// (c) 2003 Allen I Holub. All rights reserved.
package com.holub.ui;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import java.util.Date;
import java.util.Calendar;
import java.net.URL;
import com.holub.ui.DateSelector;
/***
* This class is wrapper for a {@link DateSelector} that adds a
* navigation bar to manipulate the wrapped selector.
* See {@link DateSelectorPanel} for a description and picture
* of date selectors.
* <DL>
* <DT><b>Images</b>
* <DD>
* <P>
* The navigation-bar arrows in the current implementation are images
* loaded as a "resource" from the CLASSPATH. Four files are used:
* <blockquote>
* $CLASSPATH/images/10px.red.arrow.right.double.gif<br>
* $CLASSPATH/images/10px.red.arrow.left.double.gif<br>
* $CLASSPATH/images/10px.red.arrow.right.gif<br>
* $CLASSPATH/images/10px.red.arrow.left.gif
* </blockquote>
* where <em>$CLASSPATH</em> is any directory on your CLASSPATH.
* If the <code>DateSelectorPanel</code>
* can't find the image file, it uses character representations
* (<code>">"</code>, <code>">>"</code>,
* <code>"<"</code>, <code>"<<"</code>).
* The main problem with this approach is that you can't change
* the color of the arrows without changing the image files. On
* the plus side, arbitrary images can be used for the movement
* icons.
* Future versions of this class will provide some way for you
* to specify that the arrows be rendered internally in colors
* that you specify at run time.
* </DD>
* </DL>
*
* <!-- ====================== distribution terms ===================== -->
* <p><blockquote
* style="border-style: solid; border-width:thin; padding: 1em 1em 1em 1em;">
* <center>
* Copyright © 2003, Allen I. Holub. All rights reserved.
* </center>
* <br>
* <br>
* This code is distributed under the terms of the
* <a href="http://www.gnu.org/licenses/gpl.html"
* >GNU Public License</a> (GPL)
* with the following ammendment to section 2.c:
* <p>
* As a requirement for distributing this code, your splash screen,
* about box, or equivalent must include an my name, copyright,
* <em>and URL</em>. An acceptable message would be:
* <center>
* This program contains Allen Holub's <em>XXX</em> utility.<br>
* (c) 2003 Allen I. Holub. All Rights Reserved.<br>
* http://www.holub.com<br>
* </center>
* If your progam does not run interactively, then the foregoing
* notice must appear in your documentation.
* </blockquote>
* <!-- =============================================================== -->
* @author Allen I. Holub
* @see DateSelector
* @see DateSelectorPanel
* @see DateSelectorDialog
* @see TitledDateSelector
*/
public class NavigableDateSelector extends JPanel implements DateSelector
{ private DateSelector selector;
// Names of images files used for the navigator bar.
private static final String
NEXT_YEAR_IMAGE = "images/10px.red.arrow.right.double.gif", //{=NavigableDateSelector.NEXT_YEAR}
NEXT_MONTH_IMAGE = "images/10px.red.arrow.right.gif",
PREVIOUS_YEAR_IMAGE = "images/10px.red.arrow.left.double.gif",
PREVIOUS_MONTH_IMAGE = "images/10px.red.arrow.left.gif";
// These constants are used both to identify the button, and
// as the button caption in the event that the appropriate
// image file can't be located.
private static final String FORWARD_MONTH = ">" ,
FORWARD_YEAR = ">>" ,
BACK_MONTH = "<" ,
BACK_YEAR = "<<" ;
private JPanel navigation = null;
/** Wrap an existing DateSelector to add a a navigation bar
* modifies the wrapped DateSelector.
*/
public NavigableDateSelector( DateSelector selector )
{ this.selector = selector;
setBorder( null );
setOpaque( false );
setLayout( new BorderLayout() );
add( (JPanel)selector, BorderLayout.CENTER );
// Create the actual navigation bar: a JPanel that holds
// four buttons whose labels are immages of arrows.
navigation = new JPanel();
navigation.setLayout(new FlowLayout());
navigation.setBorder( null );
navigation.setBackground( com.holub.ui.Colors.LIGHT_YELLOW );
navigation.add( makeNavigationButton(BACK_YEAR ) );
navigation.add( makeNavigationButton(BACK_MONTH ) );
navigation.add( makeNavigationButton(FORWARD_MONTH) );
navigation.add( makeNavigationButton(FORWARD_YEAR ) );
add(navigation, BorderLayout.SOUTH);
}
/**
* Create a navigable date selector by wrapping the indicated one.
* @param selector the raw date selector to wrap;
* @param backgroundColor the background color of the navigation
* bar (or null for transparent). The default color is
* {@link com.holub.ui.Colors#LIGHT_YELLOW}.
* @see #setBackground
*/
public NavigableDateSelector( DateSelector selector, Color backgroundColor )
{ this(selector);
navigation.setBackground( backgroundColor );
}
/** Convenience constructor. Creates the wrapped DateSelector
* for you. (It creates a {@link DateSelectorPanel} using
* the no-arg constructor.
*/
public NavigableDateSelector()
{ this( new DateSelectorPanel() );
}
/** Change the Navigation-Bar Color. Colors.TRANSPARENT is
* recognized as a legitimate background color.
*/
public void changeNavigationBarColor( Color backgroundColor )
{ if( backgroundColor != null )
navigation.setBackground( backgroundColor );
else
navigation.setOpaque(false);
}
private final NavigationHandler navigationListener
= new NavigationHandler();
/** Handle clicks from the navigation-bar buttons. */
private class NavigationHandler implements ActionListener
{ public void actionPerformed(ActionEvent e)
{ String direction = e.getActionCommand();
if (direction==FORWARD_YEAR )selector.roll(Calendar.YEAR,true);
else if(direction==BACK_YEAR )selector.roll(Calendar.YEAR,false);
else if(direction==FORWARD_MONTH)
{
selector.roll(Calendar.MONTH,true);
if( selector.get(Calendar.MONTH) == Calendar.JANUARY )
selector.roll(Calendar.YEAR,true);
}
else if (direction==BACK_MONTH )
{
selector.roll(Calendar.MONTH,false);
if( selector.get(Calendar.MONTH) == Calendar.DECEMBER )
selector.roll(Calendar.YEAR,false);
}
else
{ // assert false: "Unexpected direction";
}
}
}
private JButton makeNavigationButton(String caption)
{
// Get the resource from the class loader, which will search
// using the same algorithm that it uses to get .class files.
// As long as the indicated images files are on the CLASSPATH
// (or if the program is running from a .jar file, are
// in the jar), then we'll find them.
ClassLoader loader = getClass().getClassLoader();
URL image =
(caption==FORWARD_YEAR )? loader.getResource(NEXT_YEAR_IMAGE):
(caption==BACK_YEAR )? loader.getResource(PREVIOUS_YEAR_IMAGE):
(caption==FORWARD_MONTH )? loader.getResource(NEXT_MONTH_IMAGE):
loader.getResource(PREVIOUS_MONTH_IMAGE) ;
JButton b = (image!=null) ? new JButton( new ImageIcon(image) )
: new JButton(caption)
;
b.setBorder(new EmptyBorder(0,4,0,4));
b.setFocusPainted(false);
b.setActionCommand(caption);
b.addActionListener( navigationListener );
b.setOpaque( false );
return b;
}
public synchronized void addActionListener(ActionListener l)
{ selector.addActionListener(l);
}
public synchronized void removeActionListener(ActionListener l)
{ selector.removeActionListener(l);
}
public Calendar getCalendarRepresentation(){return selector.getCalendarRepresentation(); }
public Date getDateRepresentation() {return selector.getDateRepresentation(); }
public void displayDate( Calendar c){ selector.displayDate(c); }
public void displayDate( Date d){ selector.displayDate(d); }
public void roll(int f, boolean up) { selector.roll(f,up); }
public int get(int f) {return selector.get(f); }
}