001/*
002 * $Id: BasicCalendarHeaderHandler.java 3927 2011-02-22 16:34:11Z kleopatra $
003 *
004 * Copyright 2007 Sun Microsystems, Inc., 4150 Network Circle,
005 * Santa Clara, California 95054, U.S.A. All rights reserved.
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 * 
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015 * Lesser General Public License for more details.
016 * 
017 * You should have received a copy of the GNU Lesser General Public
018 * License along with this library; if not, write to the Free Software
019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
020 *
021 */
022package org.jdesktop.swingx.plaf.basic;
023
024import java.awt.Color;
025import java.awt.Font;
026import java.awt.event.ActionEvent;
027import java.beans.PropertyChangeEvent;
028import java.beans.PropertyChangeListener;
029import java.text.DateFormatSymbols;
030import java.util.Calendar;
031import java.util.Locale;
032
033import javax.swing.AbstractButton;
034import javax.swing.Action;
035import javax.swing.BorderFactory;
036import javax.swing.Box;
037import javax.swing.BoxLayout;
038
039import org.jdesktop.swingx.JXHyperlink;
040import org.jdesktop.swingx.JXMonthView;
041import org.jdesktop.swingx.JXPanel;
042import org.jdesktop.swingx.hyperlink.AbstractHyperlinkAction;
043import org.jdesktop.swingx.renderer.StringValue;
044import org.jdesktop.swingx.renderer.StringValues;
045
046
047/**
048 * Custom implementation of a CalendarHeaderHandler in preparation of a vista-style 
049 * calendar. Does nothing yet.
050 * 
051 * @author Jeanette Winzenburg
052 */
053public class BasicCalendarHeaderHandler extends CalendarHeaderHandler {
054    
055    
056    @Override
057    public void install(JXMonthView monthView) {
058        super.install(monthView);
059        getHeaderComponent().setActions(monthView.getActionMap().get("previousMonth"),
060                monthView.getActionMap().get("nextMonth"),
061                monthView.getActionMap().get("zoomOut"));
062
063    }
064
065    
066    
067    @Override
068    protected void installNavigationActions() {
069        // TODO Auto-generated method stub
070        super.installNavigationActions();
071        ZoomOutAction zoomOutAction = new ZoomOutAction();
072        zoomOutAction.setTarget(monthView);
073        monthView.getActionMap().put("zoomOut", zoomOutAction);
074    }
075
076
077
078    @Override
079    public void uninstall(JXMonthView monthView) {
080        getHeaderComponent().setActions(null, null, null);
081        super.uninstall(monthView);
082    }
083
084
085    @Override
086    public BasicCalendarHeader getHeaderComponent() {
087        // TODO Auto-generated method stub
088        return (BasicCalendarHeader) super.getHeaderComponent();
089    }
090
091    @Override
092    protected BasicCalendarHeader createCalendarHeader() {
093        return new BasicCalendarHeader();
094    }
095
096    /**
097     * Quick fix for Issue #1046-swingx: header text not updated if zoomable.
098     * 
099     */
100    protected static class ZoomOutAction extends AbstractHyperlinkAction<JXMonthView> {
101
102        private PropertyChangeListener linkListener;
103        // Formatters/state used by Providers. 
104        /** Localized month strings used in title. */
105        private String[] monthNames;
106        private StringValue tsv ;
107
108        public ZoomOutAction() {
109            super();
110            tsv = new StringValue() {
111                
112                @Override
113                public String getString(Object value) {
114                    if (value instanceof Calendar) {
115                        String month = monthNames[((Calendar) value)
116                                                  .get(Calendar.MONTH)];
117                        return month + " "
118                        + ((Calendar) value).get(Calendar.YEAR); 
119                    }
120                    return StringValues.TO_STRING.getString(value);
121                }
122                
123            };
124        }
125        
126        @Override
127        public void actionPerformed(ActionEvent e) {
128            // TODO Auto-generated method stub
129            
130        }
131
132        
133        /**
134         * installs a propertyChangeListener on the target and
135         * updates the visual properties from the target.
136         */
137        @Override
138        protected void installTarget() {
139            if (getTarget() != null) {
140                getTarget().addPropertyChangeListener(getTargetListener());
141            }
142            updateLocale();
143            updateFromTarget();
144        }
145
146        /**
147         * 
148         */
149        private void updateLocale() {
150            Locale current = getTarget() != null ? getTarget().getLocale() : Locale.getDefault();
151            monthNames = DateFormatSymbols.getInstance(current).getMonths();
152        }
153
154        /**
155         * removes the propertyChangeListener. <p>
156         * 
157         * Implementation NOTE: this does not clean-up internal state! There is
158         * no need to because updateFromTarget handles both null and not-null
159         * targets. Hmm...
160         * 
161         */
162        @Override
163        protected void uninstallTarget() {
164            if (getTarget() == null) return;
165            getTarget().removePropertyChangeListener(getTargetListener());
166        }
167
168        protected void updateFromTarget() {
169            // this happens on construction with null target
170            if (tsv == null) return;
171            Calendar calendar = getTarget() != null ? getTarget().getCalendar() : null;
172            setName(tsv.getString(calendar));
173        }
174
175        private PropertyChangeListener getTargetListener() {
176            if (linkListener == null) {
177             linkListener = new PropertyChangeListener() {
178
179                @Override
180                public void propertyChange(PropertyChangeEvent evt) {
181                    if ("firstDisplayedDay".equals(evt.getPropertyName())) {
182                        updateFromTarget();
183                    } else if ("locale".equals(evt.getPropertyName())) {
184                        updateLocale();
185                        updateFromTarget();
186                    }
187                }
188                
189            };
190            }
191            return linkListener;
192        }
193
194        
195    }
196
197    
198    /**
199     * Active header for a JXMonthView in zoomable mode.<p>
200     * 
201     *  PENDING JW: very much work-in-progress.
202     */
203    static class BasicCalendarHeader extends JXPanel {
204
205        protected AbstractButton prevButton;
206        protected AbstractButton nextButton;
207        protected JXHyperlink zoomOutLink;
208
209        public BasicCalendarHeader() {
210            setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
211            prevButton = createNavigationButton();
212            nextButton = createNavigationButton();
213            zoomOutLink = createZoomLink();
214            add(prevButton);
215            add(Box.createHorizontalGlue());
216            add(zoomOutLink);
217            add(Box.createHorizontalGlue());
218            add(nextButton);
219            setBorder(BorderFactory.createEmptyBorder(2, 4, 2, 4));
220        }
221
222        /**
223         * Sets the actions for backward, forward and zoom out navigation.
224         * 
225         * @param prev
226         * @param next
227         * @param zoomOut
228         */
229        public void setActions(Action prev, Action next, Action zoomOut) {
230            prevButton.setAction(prev);
231            nextButton.setAction(next);
232            zoomOutLink.setAction(zoomOut);
233        }
234        
235        
236        /**
237         * {@inheritDoc} <p>
238         * 
239         * Overridden to set the font of the zoom hyperlink.
240         */
241        @Override
242        public void setFont(Font font) {
243            super.setFont(font);
244            if (zoomOutLink != null)
245                zoomOutLink.setFont(font);
246        }
247
248        private JXHyperlink createZoomLink() {
249            JXHyperlink zoomOutLink = new JXHyperlink();
250            Color textColor = new Color(16, 66, 104);
251            zoomOutLink.setUnclickedColor(textColor);
252            zoomOutLink.setClickedColor(textColor);
253            zoomOutLink.setFocusable(false);
254            return zoomOutLink;
255        }
256
257        private AbstractButton createNavigationButton() {
258            JXHyperlink b = new JXHyperlink();
259            b.setContentAreaFilled(false);
260            b.setBorder(BorderFactory.createEmptyBorder());
261            b.setRolloverEnabled(true);
262            b.setFocusable(false);
263            return b;
264        }
265    }
266
267}
268