All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jdesktop.swingx.plaf.basic.CalendarHeaderHandler Maven / Gradle / Ivy

There is a newer version: 1.7.2
Show newest version
/*
 * $Id: CalendarHeaderHandler.java 3927 2011-02-22 16:34:11Z kleopatra $
 *
 * Copyright 2007 Sun Microsystems, Inc., 4150 Network Circle,
 * Santa Clara, California 95054, U.S.A. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */
package org.jdesktop.swingx.plaf.basic;

import org.jdesktop.swingx.JXMonthView;
import org.jdesktop.swingx.action.AbstractActionExt;

import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.UIManager;
import javax.swing.plaf.UIResource;
import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeListener;

/**
 * Provides and wires a component appropriate as a calendar navigation header.
 * The design idea is to support a pluggable header for a zoomable (PENDING JW:
 * naming!) JXMonthView. Then custom implementations can be tailored to exactly
 * fit their needs.
 * 

*

* To install a custom implementation, register the class name of the custom * header handler with the key CalendarHeaderHandler.uiControllerID * , example: * *

 * 
 *  UIManager.put(CalendarHeaderHandler.uiControllerID, "com.foo.bar.MagicHeaderHandler")
 * 
 * 
*

* Basic navigation action should (will) be defined by the ui delegate itself (PENDING * JW: still incomplete in BasicMonthViewUI). This handler can modify/enhance * them as appropriate for its context. *

*

* PENDING JW: those icons ... who's responsible? Shouldn't we use any of the * default arrows as defined in the laf anyway (are there any?) *

* * Note: this is work-in-progress, be prepared to change if subclassing * for custom requirements! * * @author Jeanette Winzenburg */ public abstract class CalendarHeaderHandler { public static final String uiControllerID = "CalendarHeaderHandler"; protected JXMonthView monthView; private JComponent calendarHeader; protected Icon monthDownImage; protected Icon monthUpImage; private PropertyChangeListener monthViewPropertyChangeListener; /** * Installs this handler to the given month view. * * @param monthView the target month view to install to. */ public void install(JXMonthView monthView) { this.monthView = monthView; // PENDING JW: remove here if rendererHandler takes over control // completely // as is, some properties are duplicated monthDownImage = UIManager.getIcon("JXMonthView.monthDownFileName"); monthUpImage = UIManager.getIcon("JXMonthView.monthUpFileName"); installNavigationActions(); installListeners(); componentOrientationChanged(); monthStringBackgroundChanged(); fontChanged(); } /** * Uninstalls this handler from the given target month view. * * @param monthView the target month view to install from. */ public void uninstall(JXMonthView monthView) { this.monthView.remove(getHeaderComponent()); uninstallListeners(); this.monthView = null; } /** * Returns a component to be used as header in a zoomable month view, * guaranteed to be not null. * * @return a component to be used as header in a zoomable JXMonthView */ public JComponent getHeaderComponent() { if (calendarHeader == null) { calendarHeader = createCalendarHeader(); } return calendarHeader; } /** * Creates and registered listeners on the monthView as appropriate. This * implementation registers a PropertyChangeListener which synchronizes * internal state on changes of componentOrientation, font and * monthStringBackground. */ protected void installListeners() { monthView.addPropertyChangeListener(getMonthViewPropertyChangeListener()); } /** * Unregisters listeners which had been installed to the monthView. */ protected void uninstallListeners() { monthView.removePropertyChangeListener(monthViewPropertyChangeListener); } /** * Returns the propertyChangelistener for the monthView. Lazily created. * * @return the propertyChangeListener for the monthView. */ private PropertyChangeListener getMonthViewPropertyChangeListener() { if (monthViewPropertyChangeListener == null) { monthViewPropertyChangeListener = evt -> { if ("componentOrientation".equals(evt.getPropertyName())) { componentOrientationChanged(); } else if ("font".equals(evt.getPropertyName())) { fontChanged(); } else if ("monthStringBackground".equals(evt.getPropertyName())) { monthStringBackgroundChanged(); } }; } return monthViewPropertyChangeListener; } /** * Synchronizes internal state which depends on the month view's * monthStringBackground. */ protected void monthStringBackgroundChanged() { getHeaderComponent().setBackground(getAsNotUIResource(monthView.getMonthStringBackground())); } /** * Synchronizes internal state which depends on the month view's font. */ protected void fontChanged() { getHeaderComponent().setFont(getAsNotUIResource(createDerivedFont())); monthView.revalidate(); } /** * Synchronizes internal state which depends on the month view's * componentOrientation. *

* This implementation updates the month navigation icons and the header * component's orientation. */ protected void componentOrientationChanged() { getHeaderComponent().applyComponentOrientation(monthView.getComponentOrientation()); if (monthView.getComponentOrientation().isLeftToRight()) { updateMonthNavigationIcons(monthDownImage, monthUpImage); } else { updateMonthNavigationIcons(monthUpImage, monthDownImage); } } /** * @param previous the icon to use in the previousMonth action * @param next the icon to use on the nextMonth action */ private void updateMonthNavigationIcons(Icon previous, Icon next) { updateActionIcon("previousMonth", previous); updateActionIcon("nextMonth", next); } /** * @param previousKey * @param previous */ private void updateActionIcon(String previousKey, Icon previous) { Action action = monthView.getActionMap().get(previousKey); if (action != null) { action.putValue(Action.SMALL_ICON, previous); } } /** * Creates and returns the component used as header in a zoomable monthView. * * @return the component used as header in a zoomable monthView, guaranteed * to be not null. */ protected abstract JComponent createCalendarHeader(); /** * Installs and configures navigational actions. *

*

* This implementation creates and installs wrappers around the * scrollToPrevious/-NextMonth actions installed by the ui and configures * them with the appropriate next/previous icons. */ protected void installNavigationActions() { installWrapper( "scrollToPreviousMonth", "previousMonth", monthView.getComponentOrientation().isLeftToRight() ? monthDownImage : monthUpImage ); installWrapper( "scrollToNextMonth", "nextMonth", monthView.getComponentOrientation().isLeftToRight() ? monthUpImage : monthDownImage ); } /** * Creates an life action wrapper around the action registered with * actionKey, sets its SMALL_ICON property to the given icon and installs * itself with the newActionKey. * * @param actionKey the key of the action to wrap around * @param newActionKey the key of the wrapper action * @param icon the icon to use in the wrapper action */ private void installWrapper(String actionKey, String newActionKey, Icon icon) { AbstractActionExt wrapper = new AbstractActionExt(null, icon) { @Override public void actionPerformed(ActionEvent e) { Action action = monthView.getActionMap().get(actionKey); if (action != null) { action.actionPerformed(e); } } }; monthView.getActionMap().put(newActionKey, wrapper); } /** * Returns a Font based on the param which is not of type UIResource. * * @param font the base font * @return a font not of type UIResource, may be null. */ private static Font getAsNotUIResource(Font font) { if (!(font instanceof UIResource)) return font; // PENDING JW: correct way to create another font instance? return font.deriveFont(font.getAttributes()); } /** * Returns a Color based on the param which is not of type UIResource. * * @param color the base color * @return a color not of type UIResource, may be null. */ private static Color getAsNotUIResource(Color color) { if (!(color instanceof UIResource)) return color; // PENDING JW: correct way to create another color instance? float[] rgb = color.getRGBComponents(null); return new Color(rgb[0], rgb[1], rgb[2], rgb[3]); } /** * Create a derived font used to when painting various pieces of the month * view component. This method will be called whenever the font on the * component is set so a new derived font can be created. */ protected Font createDerivedFont() { return monthView.getFont().deriveFont(Font.BOLD); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy