From: <dal...@us...> - 2008-01-26 17:25:00
|
Revision: 11637 http://jedit.svn.sourceforge.net/jedit/?rev=11637&view=rev Author: daleanson Date: 2008-01-26 09:24:55 -0800 (Sat, 26 Jan 2008) Log Message: ----------- added calendar popup to revision selection panel Modified Paths: -------------- plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/RevisionSelectionPanel.java plugins/SVNPlugin/trunk/src/ise/plugin/svn/library/GUIUtils.java Added Paths: ----------- plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/dateselector/ plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/dateselector/Colors.java plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/dateselector/DateSelector.java plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/dateselector/DateSelectorDialog.java plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/dateselector/DateSelectorPanel.java plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/dateselector/NavigableDateSelector.java plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/dateselector/PopupDialog.java plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/dateselector/TitledDateSelector.java plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/dateselector/images/ plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/dateselector/images/10px.calendar.icon.gif plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/dateselector/images/10px.red.arrow.left.double.gif plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/dateselector/images/10px.red.arrow.left.gif plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/dateselector/images/10px.red.arrow.right.double.gif plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/dateselector/images/10px.red.arrow.right.gif plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/dateselector/images/8px.red.X.gif Modified: plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/RevisionSelectionPanel.java =================================================================== --- plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/RevisionSelectionPanel.java 2008-01-26 06:37:58 UTC (rev 11636) +++ plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/RevisionSelectionPanel.java 2008-01-26 17:24:55 UTC (rev 11637) @@ -29,7 +29,7 @@ package ise.plugin.svn.gui; -import java.awt.Dimension; +import java.awt.*; import java.awt.event.*; import java.util.*; import javax.swing.*; @@ -37,6 +37,8 @@ import javax.swing.event.*; import ise.java.awt.KappaLayout; +import ise.plugin.svn.gui.dateselector.*; +import ise.plugin.svn.library.GUIUtils; import org.tmatesoft.svn.core.wc.SVNRevision; @@ -55,6 +57,7 @@ private JSpinner revision_number = null; private JRadioButton date_rb = new JRadioButton( "Date:" ); private JSpinner date_spinner = null; + private JButton date_popup = null; private String title; @@ -85,7 +88,7 @@ init(); } - public RevisionSelectionPanel(String title, int direction, boolean showHead, boolean showBase, boolean showNumber, boolean showDate, boolean showWorking ) { + public RevisionSelectionPanel( String title, int direction, boolean showHead, boolean showBase, boolean showNumber, boolean showDate, boolean showWorking ) { this.title = title; this.direction = direction; this.showHead = showHead; @@ -137,6 +140,7 @@ public void actionPerformed( ActionEvent ae ) { revision_number.setEnabled ( RevisionSelectionPanel.this.revision_number_rb.isSelected() ); date_spinner.setEnabled ( RevisionSelectionPanel.this.date_rb.isSelected() ); + date_popup.setEnabled( RevisionSelectionPanel.this.date_rb.isSelected() ); } }; @@ -161,6 +165,7 @@ date_rb.addActionListener( new ActionListener() { public void actionPerformed( ActionEvent ae ) { RevisionSelectionPanel.this.date_spinner.setEnabled( RevisionSelectionPanel.this.date_rb.isSelected() ); + RevisionSelectionPanel.this.date_popup.setEnabled( RevisionSelectionPanel.this.date_rb.isSelected() ); if ( RevisionSelectionPanel.this.date_spinner.isEnabled() ) { Date date = ( Date ) date_spinner.getValue(); RevisionSelectionPanel.this.setRevision( SVNRevision.create( date ) ); @@ -189,8 +194,32 @@ ); } + date_popup = new JButton( new ImageIcon( RevisionSelectionPanel.class.getClassLoader().getResource( "ise/plugin/svn/gui/dateselector/images/10px.calendar.icon.gif" ) ) ); + date_popup.setMargin( new Insets( 1, 1, 1, 1 ) ); + date_popup.addActionListener( + new ActionListener() { + public void actionPerformed( ActionEvent ae ) { + Dialog parent = GUIUtils.getParentDialog( RevisionSelectionPanel.this ); + final DateSelectorDialog dsd = new DateSelectorDialog( parent ); + dsd.setLocation( new Point(parent.getLocation().x + date_popup.getLocation().x, parent.getLocation().y + date_popup.getLocation().y )); + dsd.addActionListener( + new ActionListener() { + public void actionPerformed( ActionEvent ae ) { + Date date = dsd.getSelectedDate(); + if ( date != null ) { + date_spinner.getModel().setValue( date ); + } + } + } + ); + dsd.setVisible( true ); + } + } + ); + revision_number.setEnabled( false ); date_spinner.setEnabled( false ); + date_popup.setEnabled( false ); if ( direction == SwingConstants.HORIZONTAL ) { add( "0, 0, 1, 1, 0, , 0", KappaLayout.createVerticalStrut( 6, true ) ); @@ -211,6 +240,7 @@ if ( showDate ) { add( "2, 2, 1, 1, W, , 3", date_rb ); add( "3, 2, 1, 1, W, , 3", getDateChooser() ); + add( "4, 2, 1, 1, , , 3", date_popup ); } } else { @@ -231,6 +261,7 @@ if ( showDate ) { add( "0, 5, 1, 1, W, , 3", date_rb ); add( "1, 5, 1, 1, W, , 3", getDateChooser() ); + add( "2, 5, 1, 1, , , 3", date_popup ); } } } @@ -281,10 +312,10 @@ public void setRevision( SVNRevision revision ) { this.revision = revision; if ( revision.getNumber() != -1 ) { - revision_number.getModel().setValue(revision.getNumber()); + revision_number.getModel().setValue( revision.getNumber() ); } else if ( revision.getDate() != null ) { - date_spinner.getModel().setValue(revision.getDate()); + date_spinner.getModel().setValue( revision.getDate() ); } } @@ -302,13 +333,14 @@ working_rb.setEnabled( b ); revision_number.setEnabled( revision_number_rb.isSelected() ); date_spinner.setEnabled( date_rb.isSelected() ); + date_popup.setEnabled( date_rb.isSelected() ); } // for testing public static void main ( String[] args ) { RevisionSelectionPanel panel = new RevisionSelectionPanel( "some title" ); - panel.setEnabled(false); - JFrame frame = new JFrame(); + panel.setEnabled( true ); + JDialog frame = new JDialog(); frame.setContentPane( panel ); frame.pack(); frame.setVisible( true ); Added: plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/dateselector/Colors.java =================================================================== --- plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/dateselector/Colors.java (rev 0) +++ plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/dateselector/Colors.java 2008-01-26 17:24:55 UTC (rev 11637) @@ -0,0 +1,91 @@ +package ise.plugin.svn.gui.dateselector; + +import java.awt.*; + +/** Provides symbolic definitions for various colors not defined in the {@link Colors} class. + *<p> + *<table> + * <tr><td>Color </td><td> Sample </td><td> R </td><td> G </td><td> B </td></tr> + * <tr><td>DARK_RED </td><td bgcolor=#990000> </td><td> 99 </td><td> 00 </td><td> 00 </td></tr> + * <tr><td>MEDIUM_RED </td><td bgcolor=#cc0000> </td><td> cc </td><td> 00 </td><td> 00 </td></tr> + * <tr><td>LIGHT_RED </td><td bgcolor=#ff0000> </td><td> ff </td><td> 00 </td><td> 00 </td></tr> + * + * <tr><td>DARK_ORANGE </td><td bgcolor=#ff6600> </td><td> ff </td><td> 66 </td><td> 00 </td></tr> + * <tr><td>MEDIUM_ORANGE </td><td bgcolor=#ff9900> </td><td> ff </td><td> 99 </td><td> 00 </td></tr> + * <tr><td>LIGHT_ORANGE </td><td bgcolor=#ffcc00> </td><td> ff </td><td> cc </td><td> 00 </td></tr> + * <tr><td>ORANGE </td><td bgcolor=#ff9900> </td><td> ff </td><td> 99 </td><td> 00 </td></tr> + * + * <tr><td>OCHRE </td><td bgcolor=#cc9900> </td><td> cc </td><td> 99 </td><td> 00 </td></tr> + * <tr><td>DARK_YELLOW </td><td bgcolor=#ffff00> </td><td> ff </td><td> ff </td><td> 00 </td></tr> + * <tr><td>MEDIUM_YELLOW </td><td bgcolor=#ffff99> </td><td> ff </td><td> ff </td><td> 99 </td></tr> + * <tr><td>LIGHT_YELLOW </td><td bgcolor=#ffffdd> </td><td> ff </td><td> ff </td><td> dd </td></tr> + * + * <tr><td>DARK_GREEN </td><td bgcolor=#006600> </td><td> 00 </td><td> 66 </td><td> 00 </td></tr> + * <tr><td>MEDIUM_GREEN </td><td bgcolor=#009900> </td><td> 00 </td><td> 99 </td><td> 00 </td></tr> + * <tr><td>LIGHT_GREEN </td><td bgcolor=#00ff00> </td><td> 00 </td><td> ff </td><td> 00 </td></tr> + * <tr><td>GREEN </td><td bgcolor=#009900> </td><td> 00 </td><td> 99 </td><td> 00 </td></tr> + * + * <tr><td>DARK_BLUE </td><td bgcolor=#000099> </td><td> 00 </td><td> 00 </td><td> 99 </td></tr> + * <tr><td>MEDIUM_BLUE </td><td bgcolor=#0000cc> </td><td> 00 </td><td> 00 </td><td> cc </td></tr> + * <tr><td>LIGHT_BLUE </td><td bgcolor=#0000ff> </td><td> 00 </td><td> 00 </td><td> ff </td></tr> + * + * <tr><td>DARK_PURPLE </td><td bgcolor=#990099> </td><td> 99 </td><td> 00 </td><td> 99 </td></tr> + * <tr><td>MEDIUM_PURPLE </td><td bgcolor=#cc00ff> </td><td> cc </td><td> 00 </td><td> ff </td></tr> + * <tr><td>LIGHT_PURPLE </td><td bgcolor=#cc99ff> </td><td> cc </td><td> 99 </td><td> ff </td></tr> + * <tr><td>PURPLE </td><td bgcolor=#cc00ff> </td><td> cc </td><td> 00 </td><td> ff </td></tr> + *</table> + * + * @see java.awt.Color + */ + +public interface Colors { + /** RGB=(0x99, 0x00, 0x00); <span style="background-color:#990000;"> </span> */ + static final Color DARK_RED = new Color( 0x99, 0x00, 0x00 ); + /** RGB=(0xcc, 0x00, 0x00); <span style="background-color:#cc0000;"> </span> */ + static final Color MEDIUM_RED = new Color( 0xcc, 0x00, 0x00 ); + /** RGB=(0xff, 0x00, 0x00); <span style="background-color:#ff0000;"> </span> */ + static final Color LIGHT_RED = new Color( 0xff, 0x00, 0x00 ); + + /** RGB=(0xff, 0x66, 0x00); <span style="background-color:#ff6600;"> </span> */ + static final Color DARK_ORANGE = new Color( 0xff, 0x66, 0x00 ); + /** RGB=(0xff, 0x99, 0x00); <span style="background-color:#ff9900;"> </span> */ + static final Color MEDIUM_ORANGE = new Color( 0xff, 0x99, 0x00 ); + /** RGB=(0xff, 0xcc, 0x00); <span style="background-color:#ffcc00;"> </span> */ + static final Color LIGHT_ORANGE = new Color( 0xff, 0xcc, 0x00 ); + /** RGB=(0xff, 0x99, 0x00); <span style="background-color:#ff9900;"> </span> */ + static final Color ORANGE = new Color( 0xff, 0x99, 0x00 ); + + /** RGB=(0xcc, 0x99, 0x00); <span style="background-color:#cc9900;"> </span> */ + static final Color OCHRE = new Color( 0xcc, 0x99, 0x00 ); + /** RGB=(0xff, 0xff, 0x00); <span style="background-color:#ffff00;"> </span> */ + static final Color DARK_YELLOW = new Color( 0xff, 0xff, 0x00 ); + /** RGB=(0xff, 0xff, 0x99); <span style="background-color:#ffff99;"> </span> */ + static final Color MEDIUM_YELLOW = new Color( 0xff, 0xff, 0x99 ); + /** RGB=(0xff, 0xff, 0xdd); <span style="background-color:#ffffdd;"> </span> */ + static final Color LIGHT_YELLOW = new Color( 0xff, 0xff, 0xdd ); + + /** RGB=(0x00, 0x66, 0x00); <span style="background-color:#006600;"> </span> */ + static final Color DARK_GREEN = new Color( 0x00, 0x66, 0x00 ); + /** RGB=(0x00, 0x99, 0x00); <span style="background-color:#009900;"> </span> */ + static final Color MEDIUM_GREEN = new Color( 0x00, 0x99, 0x00 ); + /** RGB=(0x00, 0xff, 0x00); <span style="background-color:#00ff00;"> </span> */ + static final Color LIGHT_GREEN = new Color( 0x00, 0xff, 0x00 ); + /** RGB=(0x00, 0x99, 0x00); <span style="background-color:#009900;"> </span> */ + static final Color GREEN = MEDIUM_GREEN; + + /** RGB=(0x00, 0x00, 0x99); <span style="background-color:#000099;"> </span> */ + static final Color DARK_BLUE = new Color( 0x00, 0x00, 0x99 ); + /** RGB=(0x00, 0x00, 0xcc); <span style="background-color:#0000cc;"> </span> */ + static final Color MEDIUM_BLUE = new Color( 0x00, 0x00, 0xcc ); + /** RGB=(0x00, 0x00, 0xff); <span style="background-color:#0000ff;"> </span> */ + static final Color LIGHT_BLUE = new Color( 0x00, 0x00, 0xff ); + + /** RGB=(0x99, 0x00, 0x99); <span style="background-color:#990099;"> </span> */ + static final Color DARK_PURPLE = new Color( 0x99, 0x00, 0x99 ); + /** RGB=(0xcc, 0x00, 0xff); <span style="background-color:#cc00ff;"> </span> */ + static final Color MEDIUM_PURPLE = new Color( 0xcc, 0x00, 0xff ); + /** RGB=(0xcc, 0x99, 0xff); <span style="background-color:#cc99ff;"> </span> */ + static final Color LIGHT_PURPLE = new Color( 0xcc, 0x99, 0xff ); + /** RGB=(0xcc, 0x00, 0xff); <span style="background-color:#cc00ff;"> </span> */ + static final Color PURPLE = MEDIUM_PURPLE; +} Added: plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/dateselector/DateSelector.java =================================================================== --- plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/dateselector/DateSelector.java (rev 0) +++ plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/dateselector/DateSelector.java 2008-01-26 17:24:55 UTC (rev 11637) @@ -0,0 +1,100 @@ +package ise.plugin.svn.gui.dateselector; + + +import java.awt.*; +import java.awt.event.*; +import java.util.Date; +import java.util.Calendar; // makes javadoc happy + +/** An interface for Date selection. + * + * See {@link DateSelectorPanel} for a discussion of how date selectors + * look and work. This interface defines the public methods of that + * class to allow for the use of a Gang-of-Four Decorator to add + * optional labels. + * <p> + * Most of the interface methods have to do with action-listeners support. + * The listeners are notified in two situations, which can be + * distinguished from one another by calling + * {@link ActionEvent#getID}: + * <table border=1 cellspacing=0 cellpadding=2> + * <tr><td><b><code>getID()</code> Returns:</b></td><td><b>Description:</b></td></tr> + * <tr> <td>{@link #CHANGE_ACTION}</td> + * <td> + * This event is sent when the calendar panel changes the displayed month or + * year (tyically because some sort of navigator bar asked it to). + * Call <code>event</code>.{@link ActionEvent#getActionCommand getActionCommand()} + * to get a string holding the current (after the scroll) month and year. + * You can also call {@link #getCurrentDate()} to get + * get the date the user selected. + * </td> + * </tr> + * <tr><td>{@link #SELECT_ACTION}</td> + * <td> + * Sent every time the user clicks on a date. + * Call <code>event</code>.{@link ActionEvent#getActionCommand getActionCommand()} + * to get a string + * representing the selected date. (This string takes the same + * form as the one returned by {@link Date#toString}.) + * You can also call {@link #getSelectedDate()} to get + * get the date the user selected. + * </td> + * </tr> + * <tr><td></td><td></td></tr> + * </table> + * The following example demonstrates how to create a single JPanel + * that contains a title displaying the name of the current month and + * year as well as a calendar for that date. The ActionListener automatically + * updates the label every time the user navigates to another month. + * (You will rarely have to do this, since the + * {@link TitledDateSelector} class will handle exactly + * that problem for you, but the example demonstrates the technique.) + * <pre> +private static JPanel create_calendar_pane(DateSelector s) +{ + JPanel panel = new JPanel(); + panel.setLayout( new BorderLayout() ); + + final JLabel month = new JLabel("MMM YYYY"); + s.addActionListener + ( new ActionListener() + { public void actionPerformed( ActionEvent e ) + { if( e.getID() == DateSelector.CHANGE_ACTION ) + month.setText( e.getActionCommand() ); + else + System.out.println( e.getActionCommand() ); + } + } + ); + panel.add( month, BorderLayout.NORTH ); + panel.add( s, BorderLayout.CENTER ); + return panel; +} + * </pre> + * <p> + * Classes that implement this interface must also + * <code>extend Container</code> or some <code>Container</code> + * derivative. (You can't mandate this in the compiler because + * Container is not an interface, so can't be a base class + * of DateSelector.) + * + * @see DateSelectorPanel + * @see DateSelectorDialog + */ + +public interface DateSelector { + public static final int CHANGE_ACTION = 0; + public static final int SELECT_ACTION = 1; + + public void addActionListener( ActionListener l ); + public void removeActionListener( ActionListener l ); + + public Date getSelectedDate(); + public Date getCurrentDate(); + + /** Must work just like {@link Calendar#roll(int,boolean)} */ + public void roll( int flag, boolean up ); + + /** Must work just like {@link Calendar#get(int)} */ + public int get( int flag ); +} Added: plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/dateselector/DateSelectorDialog.java =================================================================== --- plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/dateselector/DateSelectorDialog.java (rev 0) +++ plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/dateselector/DateSelectorDialog.java 2008-01-26 17:24:55 UTC (rev 11637) @@ -0,0 +1,194 @@ +package ise.plugin.svn.gui.dateselector; + + +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; +import java.util.Date; + +/** + * The DateSelectorDialog, shown below, + * combines a {@link DateSelector} and + * a {@link PopupDialog} to provide a standalone, popup dialog + * for choosing dates. + * <blockquote> + * <img style="border_style:none" src="../../../images/DateSelectorDialog.gif"> + * </blockquote> + * The dialog is a free-floating top-level window. You can drag it around by the + * title bar and close it by clicking on the "close" icon. + * <p> + * The class does implement the {@link DateSelector} interface, but + * bear in mind that the window closes when the user selects a date. + * Unlike the {@link TitledDateSelector} wrapper class, + * both of the action events are sent to listeners, however. + * Create one the hard way like this: + * <pre> +DateSelector calendar = new DateSelectorPanel( selector ); +calendar = new NavigableDateSelector( calendar ); // add navigation +DateSelectorDialog chooser = new DateSelectorDialog(parent_frame, calendar); +//... +Date d = chooser.select(); // Pops up chooser; returns selected Date. + </pre> + * You can leave out the navigation bar by omitting the second line of the + * previous example. The following convenience constructor has exactly + * the same effect as the earlier code: + * <pre> +DateSelectorDialog chooser = new DateSelectorDialog(parent_frame); + * <pre> + * You can also pop up the dialog like this: + * <pre> +chooser.setVisible(true); // blocks until dialog closed +Date d = chooser.getSelectedDate(); + * </pre> + * This class is a stand-alone dialog. For a version + * that you can embed into another window, see {@link DateSelectorPanel}. + * + * @see DateSelector + * @see DateSelectorPanel + * @see NavigableDateSelector + * @see TitledDateSelector + * @see PopupDialog + */ + +public class DateSelectorDialog extends PopupDialog implements DateSelector { + private DateSelector selector = new DateSelectorPanel(); + + /** Creates a dialog box with the indicated parent that holds + * a standard {@link DateSelectorPanel DateSelectorPanel} + * (as created using the no-arg constructor). + */ + public DateSelectorDialog( Frame parent ) { + super( parent ); + selector = new NavigableDateSelector( new DateSelectorPanel() ); + init(); + } + + /* Like {@link #DateSelectorDialog(Frame), + * but for a {@link Dialog} parent. + */ + public DateSelectorDialog( Dialog parent ) { + super( parent ); + selector = new NavigableDateSelector( new DateSelectorPanel() ); + init(); + } + + /** Creates a dialog box with the indicated parent that holds + * the indicated DateSelector. + * Note that the current month and year is displayed in the + * dialog-box title bar, so there's no need to display it in + * the selector too. + */ + public DateSelectorDialog( Frame parent, DateSelector to_wrap ) { + super( parent ); + selector = to_wrap; + init(); + } + + /* Like {@link #DateSelectorDialog(Frame,DateSelector), + * but for a {@link Dialog} parent. + */ + + public DateSelectorDialog( Dialog parent, DateSelector to_wrap ) { + super( parent ); + selector = to_wrap; + init(); + } + + /** Code comon to all constructors + */ + private void init() { + getContentPane().add( ( Container ) selector, BorderLayout.CENTER ); + selector.addActionListener + ( new ActionListener() { + public void actionPerformed( ActionEvent event ) { + if ( event.getID() == DateSelector.CHANGE_ACTION ) { + setTitle( event.getActionCommand() ); + } + else { + setVisible( false ); + dispose(); + } + } + } + ); + ( ( Container ) selector ).setVisible( true ); + pack(); + } + + /** For use when you pop up a dialog using + * <code>setVisible(true)</code> rather than {@link #select}. + * @return the selected date or null if the dialog was closed + * without selecting anything. + */ + public Date getSelectedDate() { + return selector.getSelectedDate(); + } + + /** Get the current date. The dialog stays in existance + * until the user closes it or selects a date, so this + * method can be used to see what month the user has + * scrolled to. + * @return the date currently displayed on the calendar. + */ + public Date getCurrentDate() { + return selector.getCurrentDate(); + } + + /** Add an action listner for both + * {@link DateSelector#CHANGE_ACTION} and + * {@link DateSelector#SELECT_ACTION} action events. + */ + public void addActionListener( ActionListener l ) { + selector.addActionListener( l ); + } + + /** Remove a previously-added listener */ + public void removeActionListener( ActionListener l ) { + selector.removeActionListener( l ); + } + + /** Pops up the chooser and blocks until the user selects + * a date. + * @return the selected date or null if the dialog was closed + * without selecting anything. + */ + public Date select() { + setVisible( true ); + return selector.getSelectedDate(); + } + + public void roll( int f, boolean up ) { + selector.roll( f, up ); + } + public int get( int f ) { + return selector.get( f ); + } + + //---------------------------------------------------------------------- + private static class Test { + public static void main( String[] args ) throws Exception { + final JFrame frame = new JFrame(); + frame.getContentPane().add( new JLabel( "Main Frame" ) ); + frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); + frame.pack(); + frame.setVisible(true); + + DateSelectorDialog chooser = new DateSelectorDialog( frame ); + chooser.setLocation( 10, 10 ); + System.out.println( "Displaying Selector" ); + + System.out.println( chooser.select() ); + + // No navigation bar + chooser = new DateSelectorDialog( frame, + new DateSelectorPanel( 1900, 1, 2 ) ); + + chooser.setLocation( 10, 10 ); + System.out.println( "Displaying Selector" ); + + System.out.println( chooser.select() ); + + System.exit( -1 ); + } + } +} Added: plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/dateselector/DateSelectorPanel.java =================================================================== --- plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/dateselector/DateSelectorPanel.java (rev 0) +++ plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/dateselector/DateSelectorPanel.java 2008-01-26 17:24:55 UTC (rev 11637) @@ -0,0 +1,466 @@ +package ise.plugin.svn.gui.dateselector; + + +import javax.swing.*; +import javax.swing.border.*; +import java.awt.event.*; +import java.awt.*; +import java.util.Date; +import java.util.Calendar; +import java.net.URL; + +/** A calendar-dispaly/date-selection widget. + * Here's what it looks like: + * <blockquote> + * <img src="../../../images/DateSelector.gif"> + * </blockquote> + * "Today" is highlighted. + * Select a date by clicking on it. + * The background is transparant by default — it's grey here because + * the underlying window is grey. + * <p> + <img src="../../../images/NavigableDateSelector.gif"> + * This "raw" date selector can be "decorated" in several + * ways to make it more useful. + * First, you can add a navigation bar to the bottom + * to advances the + * calandar by one month (single arrow) or one year (double arrow) + * forwards (right-pointing arrow) or backwards (left-pointing arrow). + * "Today" is highlighted. + * Navigation bars are specified using a Gang-of-Four "Decorator" + * object that wraps the raw <code>DateSelectorPanel</code> + * Both the wrapper and the underlying panel implement the + * <code>DateSelectory</code> interface, so can be use + * used interchangably. The following code creates the + * date selector at right. + * <pre> + * DateSelector selector = new DateSelectorPanel(); + * selector = new NavigableDateSelector( selector ); + * </pre> + * The same thing can be accomplished with a convenience constuctor that + * creates the wrapped DateSelectorPanel for you: + * <pre> + * DateSelector selector = new NavigableDateSelector(); + * </pre> + * <p> + * <img src="../../../images/Titled_navigable_date_selector.gif"> + * The other augmentation of interest is a title that shows the + * month name and year that's displayed. (there's an example at right). + * Use the same decoration strategy as before to add the title: + * <pre> + * DateSelector selector = new DateSelectorPanel(); + * selector = new NavigableDateSelector( selector ); + * selector = new TitledDateSelector ( selector ); + * </pre> + * You can leave out the navigation bar by ommiting the + * second line of the foregoing code. + * Again, a convenience constructor is provided to create a + * titled date selector (without the navigation bar) as follows: + * <pre> + * DateSelector selector = new TitledDateSelector(); + * </pre> + * <p> + * <img src="../../../images/DateSelectorDialog.gif"> + * The final variant is the lightweight popup dialog shown at right. + * It can be dragged around by the title bar (though dragging can + * be disabled) and closed by clicking on the "close" icon on the + * upper right. As before, use a decorator to manufacture a dialog: + * <pre> + * DateSelector selector = new DateSelectorPanel(); + * selector = new NavigableDateSelector( selector ); // add navigation + * selector = new DateSelectorDialog ( selector ); + * </pre> + * Note that you don't need a title because one is supplied for you + * in the dialog-box title bar. Also as before, a convenience + * constructor to create a navigable dialog box like the one at + * right: + * <pre> + * DateSelector = new Date_selectcor_dialog(); + * <pre> + * All the earlier examples create a claendar for the current + * month. Several methods are provided, below, to change the date + * in your program. For the most part, they work like simliar + * methods of the {@link Calendar} class. + * <DL> + * <DT><b>Known Problems</b> + * <DD> + * The month names are hard coded (in English). Future versions + * will load these strings from a resource bundle. The week layout + * (S M T W Th F Sa Su) is the default layout for the underlying + * {@link Calendar}, which should change with Locale as appropriate. + * This feature has not been tested, however. + * </DD> + * </DL> + * + * @see ise.plugin.svn.gui.dateselector.DateSelector + * @see ise.plugin.svn.gui.dateselector.DateSelectorDialog + * @see ise.plugin.svn.gui.dateselector.NavigableDateSelector + * @see ise.plugin.svn.gui.dateselector.TitledDateSelector + */ + +public class DateSelectorPanel extends JPanel implements DateSelector { + //TODO: These strings should be in a resource bundle so they + // can be internationalized. + // + private String[] months = + { "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }; + + private static final int DAYS_IN_WEEK = 7; // days in a week + private static final int MAX_WEEKS = 6; // maximum weeks in any month + + private Date selected = null; + + private Calendar calendar = Calendar.getInstance(); + { + calendar.set( Calendar.HOUR, 0 ); + calendar.set( Calendar.MINUTE, 0 ); + calendar.set( Calendar.SECOND, 0 ); + } + + // The calendar that's displayed on the screen + + private final Calendar today = Calendar.getInstance(); + + // An ActionListener that fields all events coming in from the + // calendar + // + private final Button_handler day_listener = new Button_handler(); + + // "days" is not a two-dimensional array. I drop buttons into + // a gridLayout and let the layout manager worry about + // what goes where. The first buttion is the first day of the + // first week on the grid, the 8th button is the first day of the + // second week of the grid, and so forth. + + private JButton[] days = new JButton[ DAYS_IN_WEEK * MAX_WEEKS ]; + { + for ( int i = 0; i < days.length; i++ ) { + JButton day = new JButton( "--" ); + days[ i ] = day; + day.setBorder ( new EmptyBorder( 1, 2, 1, 2 ) ); + day.setFocusPainted ( false ); + day.setActionCommand ( "D" ); + day.addActionListener ( day_listener ); + day.setOpaque ( false ); + } + } + + /** Create a DateSelector representing the current date. + */ + public DateSelectorPanel() { + JPanel calendar_display = new JPanel(); + calendar_display.setOpaque( false ); + calendar_display.setBorder( BorderFactory.createEmptyBorder( 5, 3, 0, 1 ) ); + calendar_display.setLayout( new GridLayout( MAX_WEEKS /*rows*/, DAYS_IN_WEEK /*columns*/ ) ); + + for ( int i = 0; i < days.length; ++i ) + calendar_display.add( days[ i ] ); + + setOpaque( false ); + setLayout( new BorderLayout() ); + add( calendar_display, BorderLayout.CENTER ); + updateCalendarDisplay(); + } + + /** Create a DateSelectorPanel for an arbitrary date. + * @param initial_date Calendar will display this date. The specified + * date is highlighted as "today". + * @see #DateSelectorPanel(int,int,int) + */ + + public DateSelectorPanel( Date initial_date ) { + this(); + calendar.setTime( initial_date ); + today. setTime( initial_date ); + updateCalendarDisplay(); + } + + /** Create a DateSelectorPanel for an arbitrary date. + * @param year the full year (e.g. 2003) + * @param month the month id (0=january, 1=feb, etc. [this is the + * convention supported by the other date classes]) + * @param day the day of the month. This day will be highlighted + * as "today" on the displayed calendar. Use 0 to suppress + * the highlighting. + * @see #DateSelectorPanel(Date) + */ + + public DateSelectorPanel( int year, int month, int day ) { + this(); + calendar.set( year, month, day ); + if ( day != 0 ) + today.set( year, month, day ); + updateCalendarDisplay(); + } + + /************************************************************************ + * List of observers. + */ + + private ActionListener subscribers = null; + + /** Add a listener that's notified when the user scrolls the + * selector or picks a date. + * @see DateSelector + */ + public synchronized void addActionListener( ActionListener l ) { + subscribers = AWTEventMulticaster.add( subscribers, l ); + } + + /** Remove a listener. + * @see DateSelector + */ + public synchronized void removeActionListener( ActionListener l ) { + subscribers = AWTEventMulticaster.remove( subscribers, l ); + } + + /** Notify the listeners of a scroll or select + */ + private void fireActionEvent( int id, String command ) { + if ( subscribers != null ) + subscribers.actionPerformed( new ActionEvent( this, id, command ) ); + } + + /*********************************************************************** + * Handle clicks from the buttons that represent calendar days. + */ + private class Button_handler implements ActionListener { + public void actionPerformed( ActionEvent e ) { + if ( e.getActionCommand().equals( "D" ) ) { + String text = ( ( JButton ) e.getSource() ).getText(); + + if ( text.length() > 0 ) // <=0 means click on blank square. Ignore. + { calendar.set + ( calendar.get( Calendar.YEAR ), // Reset the calendar + calendar.get( Calendar.MONTH ), // to be the choosen + Integer.parseInt( text ) // date. + ); + selected = calendar.getTime(); + fireActionEvent( SELECT_ACTION, selected.toString() ); + } + } + } + } + + //---------------------------------------------------------------------- + + private JButton highlighted = null; + + private void clearHighlight() { + if ( highlighted != null ) { + highlighted.setBackground( Color.WHITE ); + highlighted.setForeground( Color.BLACK ); + highlighted.setOpaque( false ); + highlighted = null; + } + } + + private void highlight( JButton cell ) { + highlighted = cell; + cell.setBackground( ise.plugin.svn.gui.dateselector.Colors.DARK_RED ); + cell.setForeground( Color.WHITE ); + cell.setOpaque( true ); + } + //---------------------------------------------------------------------- + + /** Redraw the buttons that comprise the calandar to display the current month */ + + private void updateCalendarDisplay() { + try { + setVisible( false ); // improves paint speed & reduces flicker + + clearHighlight(); + + // The buttons that comprise the calendar are in a single + // dimentioned array that was added to a 6x7 grid layout in + // order. Because of the linear structure, it's easy to + // lay out the calendar just by changing the labels on + // the buttons. Here's the algorithm used below + // + // 1) find out the offset to the first day of the month. + // 2) clear everything up to that offset + // 3) add the days of the month + // 4) clear everything else + + int month = calendar.get( Calendar.MONTH ); + int year = calendar.get( Calendar.YEAR ); + + fireActionEvent( CHANGE_ACTION, months[ month ] + " " + year ); + + calendar.set( year, month, 1 ); // first day of the current month. + + int first_day_offset = calendar.get( Calendar.DAY_OF_WEEK ); /* 1 */ + + assert Calendar.SUNDAY == 0; + assert first_day_offset < days.length; + + int i = 0; + while ( i < first_day_offset - 1 ) /* 2 */ + days[ i++ ].setText( "" ); + + int day_of_month = 1; + for ( ; i < days.length; ++i ) /* 3 */ + { + // Can't get calendar.equals(today) to work, so do it manually + + if ( calendar.get( Calendar.MONTH ) == today.get( Calendar.MONTH ) + && calendar.get( Calendar.YEAR ) == today.get( Calendar.YEAR ) + && calendar.get( Calendar.DATE ) == today.get( Calendar.DATE ) ) { + highlight( days[ i ] ); + } + + days[ i ].setText( String.valueOf( day_of_month ) ); + + calendar.roll( Calendar.DATE, /*up=*/ true ); // forward one day + + day_of_month = calendar.get( Calendar.DATE ); + if ( day_of_month == 1 ) + break; + } + + // Note that we break out of the previous loop with i positioned + // at the last day we added, thus the following ++ *must* be a + // preincrement becasue we want to start clearing at the cell + // after that. + + while ( ++i < days.length ) /* 4 */ + days[ i ].setText( "" ); + + setVisible( true ); + } + catch(Exception e) { + e.printStackTrace(); + } + } + + /** Create a naviagion button with an image appropriate to the caption. + * The <code>caption</code> argument is used as the button's "action command." + * This method is public only because it has to be. (It overrides a public + * method.) Pretend it's not here. + */ + + public void addNotify() { + super.addNotify(); + int month = calendar.get( Calendar.MONTH ); + int year = calendar.get( Calendar.YEAR ); + fireActionEvent( CHANGE_ACTION, months[ month ] + " " + year ); + } + + /** Returns the {@link Date Date} selected by the user or null if + * the window was closed without selecting a date. The returned + * Date has hours, minutes, and seconds values of 0. + */ + + public Date getSelectedDate() { + return selected; + } + + /** Returns the currently displayed {@link Date Date}. */ + public Date getCurrentDate() { + return calendar.getTime(); + } + + /** Works just like {@link Calendar#roll(int,boolean)}. */ + public void roll( int field, boolean up ) { + calendar.roll( field, up ); + updateCalendarDisplay(); + } + + /** Works just like {@link Calendar#roll(int,int)}. */ + public void roll( int field, int amount ) { + calendar.roll( field, amount ); + updateCalendarDisplay(); + } + + /** Works just like {@link Calendar#set(int,int,int)} + * Sets "today" (which is higlighted) to the indicated day. + */ + public void set( int year, int month, int date ) { + calendar.set( year, month, date ); + today.set( year, month, date ); + updateCalendarDisplay(); + } + + /** Works just like {@link Calendar#get(int)} */ + public int get( int field ) { + return calendar.get( field ); + } + + /** Works just like {@link Calendar#setTime(Date)}, + * Sets "today" (which is higlighted) to the indicated day. + */ + public void setTime( Date d ) { + calendar.setTime( d ); + today.setTime( d ); + updateCalendarDisplay(); + } + + /** Works just like {@link Calendar#getTime} */ + public Date getTime( ) { + return calendar.getTime(); + } + + /** Return a Calendar object that represents the currently-displayed + * month and year. Modifying this object will not affect the + * current panel. + * @return a Calendar representing the panel's state. + */ + + public Calendar getCalendar() { + Calendar c = Calendar.getInstance(); + c.setTime( calendar.getTime() ); + return c; + } + + /** Change the display to match the indicated calendar. This Calendar + * argument is used only to provide the new date/time information. + * Modifying it after a call to the current method will not affect + * the DateSelectorPanel at all. + * Sets "today" (which is higlighted) to the indicated day. + * @param calendar A calendar positioned t the date to display. + */ + + public void setFromCalendar( Calendar calendar ) { + this.calendar.setTime( calendar.getTime() ); + today.setTime( calendar.getTime() ); + updateCalendarDisplay(); + } + //---------------------------------------------------------------------- + private static class Test { + public static void main( String[] args ) { + JFrame frame = new JFrame(); + frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); + frame.getContentPane().setLayout( new FlowLayout() ); + + DateSelector left = new TitledDateSelector( new NavigableDateSelector() ); + DateSelector center = new NavigableDateSelector(); + DateSelector right = new DateSelectorPanel( 1900, 1, 2 ); + + ( ( NavigableDateSelector ) center ).changeNavigationBarColor( null ); // transparent + + ActionListener l = + new ActionListener() { + public void actionPerformed( ActionEvent e ) { + System.out.println( e.getActionCommand() ); + } + }; + + left.addActionListener ( l ); + center.addActionListener( l ); + right.addActionListener ( l ); + + JPanel white = new JPanel(); // proove that it's transparent. + white.setBackground( Color.WHITE ); + white.add( ( JPanel ) center ); + + frame.getContentPane().add( ( JPanel ) left ); // I hate these casts, but they're + frame.getContentPane().add( white ); // mandated by the fact that + frame.getContentPane().add( ( JPanel ) right ); // Component is not an interface. + + frame.pack(); + frame.setVisible( true ); + } + } +} Added: plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/dateselector/NavigableDateSelector.java =================================================================== --- plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/dateselector/NavigableDateSelector.java (rev 0) +++ plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/dateselector/NavigableDateSelector.java 2008-01-26 17:24:55 UTC (rev 11637) @@ -0,0 +1,189 @@ +package ise.plugin.svn.gui.dateselector; + + +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 ise.plugin.svn.gui.dateselector.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> + * @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 = "ise/plugin/svn/gui/dateselector/images/10px.red.arrow.right.double.gif"; + private static final String NEXT_MONTH = "ise/plugin/svn/gui/dateselector/images/10px.red.arrow.right.gif"; + private static final String PREVIOUS_YEAR = "ise/plugin/svn/gui/dateselector/images/10px.red.arrow.left.double.gif"; + private static final String PREVIOUS_MONTH = "ise/plugin/svn/gui/dateselector/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 + // immage file can't be located. + + private static final String FORWARD_MONTH = ">" ; + private static final String FORWARD_YEAR = ">>" ; + private static final String BACK_MONTH = "<" ; + private static final String 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 ); + + navigation = new JPanel(); + navigation.setLayout( new FlowLayout() ); + navigation.setBorder( null ); + navigation.setBackground( ise.plugin.svn.gui.dateselector.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 background_color the background color of the navigation + * bar (or null for transparent). The default color is + * {@link ise.plugin.svn.gui.dateselector.Colors#LIGHT_YELLOW}. + * @see #setBackground + */ + + public NavigableDateSelector( DateSelector selector, Color background_color ) { + this( selector ); + navigation.setBackground( background_color ); + } + + /** Convenience constructor. Creates the wrapped DateSelector + * for you. (It creates a {@link DateSelectorPanel} using + * the no-arg constructor. + */ + + public NavigableDateSelector() { + this( new DateSelectorPanel() ); + } + + public void changeNavigationBarColor( Color background_color ) { + if ( background_color != null ) + navigation.setBackground( background_color ); + else + navigation.setOpaque( false ); + } + + private final NavigationHandler navigation_listener = 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 ) { + ClassLoader loader = getClass().getClassLoader(); + URL image = + ( caption == FORWARD_YEAR ) ? loader.getResource( NEXT_YEAR ) : + ( caption == BACK_YEAR ) ? loader.getResource( PREVIOUS_YEAR ) : + ( caption == FORWARD_MONTH ) ? loader.getResource( NEXT_MONTH ) : + loader.getResource( PREVIOUS_MONTH ) ; + + 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( navigation_listener ); + b.setOpaque( false ); + return b; + } + + public synchronized void addActionListener( ActionListener l ) { + selector.addActionListener( l ); + } + public synchronized void removeActionListener( ActionListener l ) { + selector.removeActionListener( l ); + } + public Date getSelectedDate() { + return selector.getSelectedDate(); + } + public Date getCurrentDate() { + return selector.getCurrentDate(); + } + public void roll( int f, boolean up ) { + selector.roll( f, up ); + } + public int get( int f ) { + return selector.get( f ); + } +} Added: plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/dateselector/PopupDialog.java =================================================================== --- plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/dateselector/PopupDialog.java (rev 0) +++ plugins/SVNPlugin/trunk/src/ise/plugin/svn/gui/dateselector/PopupDialog.java 2008-01-26 17:24:55 UTC (rev 11637) @@ -0,0 +1,241 @@ +package ise.plugin.svn.gui.dateselector; + + +import javax.swing.*; +import javax.swing.border.*; +import java.awt.*; +import java.awt.event.*; +import java.awt.image.BufferedImage; +import java.awt.geom.Line2D; +import java.net.URL; + +// Test this class by instantiating DateSelector +// TODO: Draw the close box in a paint() override using lines so that +// the dependancy on the image file goes away and so that +// it can change colors to match the foreground color. + +/** A PopupDialog is a clean, lightweight, "modal" window intended for + * simple pop-up user-interface widgets. The frame, as shown at right, + * <img src="../../../images/PopupDialog.gif" align=right> + * is a single-pixel-wide + * line; the title bar holds only + * the title text and a small "close-window" icon. + * The dialog + * box can be dragged around on the screen by grabbing the title + * bar (and closed by clicking on the icon), but the user can't + * resize it, minimize it, etc. (Your program can do so, of course). + * <p> + * The "close" icon in the current implementation is an image + * loaded as a "resource" from the CLASSPATH. The file must be + * located at + * <blockquote> + * $CLASSPATH/images/8px.red.X.gif + * </blockquote> + * where <em>$CLASSPATH</em> is any directory on your CLASSPATH. + * If the class can't find the image file, it uses the character + * "X" instead. + * The main problem with this approach is that you can't change + * the color of the close icon to math the title-bar colors. + * Future versions of this class will fix the problem by rendering + * the image internally. + */ + +public class PopupDialog extends JDialog { + private Color TITLE_BAR_COLOR = ise.plugin.svn.gui.dateselector.Colors.LIGHT_YELLOW; + private Color CLOSE_BOX_COLOR = ise.plugin.svn.gui.dateselector.Colors.DARK_RED; + + private JLabel title = new JLabel( "xxxxxxxxxxxxxx" ); + { + title.setHorizontalAlignment( SwingConstants.CENTER ); + title.setOpaque( false ); + title.setFont( title.getFont().deriveFont( Font.BOLD ) ); + } + + private JPanel header = new JPanel(); + { + header.setBackground( TITLE_BAR_COLOR ); + header.setLayout( new BorderLayout() ); + header.setBorder( BorderFactory.createEmptyBorder( 2, 2, 2, 2 ) ); + header.add( title , BorderLayout.CENTER ); + header.add( create_close_button() , BorderLayout.EAST ); + } + + private JPanel content_pane = new JPanel(); + { + content_pane.setLayout( new BorderLayout() ); + } + + public PopupDialog( Frame owner ) { + super( owner ); + setModal( true ); + } + public PopupDialog( Dialog owner ) { + super( owner ); + setModal( true ); + } + + /* code common to all constructors */ + { + init_dragable(); + + setUndecorated( true ); + JPanel contents = new JPanel(); + contents.setBorder( BorderFactory.createLineBorder( Color.BLACK, 1 ) ); + contents.setLayout( new BorderLayout() ); + contents.add( header, BorderLayout.NORTH ); + contents.add( content_pane, BorderLayout.CENTER ); + contents.setBackground( Color.WHITE ); + + setContentPane( contents ); // , BorderLayout.CENTER ); + setLocation( 100, 100 ); + } + + private JButton create_close_button() { + URL image = getClass().getClassLoader().getResource( + "ise/plugin/svn/gui/dateselector/images/8px.red.X.gif" ); + + JButton b = ( image != null ) ? new JButton( new ImageIcon( image ) ) + : new JButton( " X " ) + ; + + Border outer = BorderFactory.createLineBorder( CLOSE_BOX_COLOR, 1 ); + Border inner = BorderFactory.createEmptyBorder( 2, 2, 2, 2 ); + + b.setBorder( BorderFactory.createCompoundBorder( outer, inner ) ); + + b.setOpaque( false ); + b.addActionListener + ( new ActionListener() { + public void actionPerformed( ActionEvent e ) { + PopupDialog.this.setVisible( false ); + PopupDialog.this.dispose(); + } + } + ); + + b.setFocusable( false ); + return b; + } + + /** Set the dialog title to the indicated text */ + public void setTitle( String text ) { + title.setText( text ); + } + + //---------------------------------------------------------------------- + // Drag support. + // + private Point reference_position = new Point( 0, 0 ); + private MouseMotionListener movement_handler; + private MouseListener click_handler; + + private void init_dragable() { + movement_handler = + new MouseMotionAdapter() { + public void mouseDragged( MouseEvent e ) { // The reference posistion is the (window relative) + // cursor postion when the click occured. The + // current_mouse-position is mouse position + // now, and the deltas represent the disance + // moved. + + Point current_mouse_position = e.getPoint(); + Point current_window_location = getLocation(); + + int delta_x = current_mouse_position.x - reference_position.x; + int delta_y = current_mouse_position.y - reference_position.y; + + // Move the window over by the computed delta. This move + // effectivly shifts the window-relative current-mouse + // position back to the original reference position. + + current_window_location.translate( delta_x, delta_y ); + setLocation( current_window_location ); + } + }; + + click_handler = + new MouseAdapter() { + public void mousePressed( MouseEvent e ) { + reference_position = e.getPoint(); // start of the drag + } + }; + + setDragable( true ); + } + + /** Turn dragability on or off. + */ + public void setDragable( boolean on ) { + if ( on ) { + title.addMouseMotionListener ( movement_handler ); + title.addMouseListener ( click_handler ); + } + else { + title.removeMouseMotionListener ( movement_handler ); + title.removeMouseListener ( click_handler ); + } + } + + /** Add your widgets to the window returned by this method, in + * a manner similar to a JFrame. Do not modify the Poup_dialog + * itself. The returned container is a {@link JPanel JPanel} + * with a preinstalled {@link BorderLayout}. + * By default, it's colored colored dialog-box gray. + * @return the content pane. + */ + public Container getContentPane() { + return content_pane; + } + + /** Change the color of the text and background in the title bar. + * The "close" icon is always + * {@linkplain ise.plugin.svn.gui.dateselector.Colors#DARK_RED dark red} + * so it will be hard to see if the background color is also + * a dark red). + * @param foreground the text color + * @param background the background color + */ + public void change_titlebar_colors( Color foreground, Color background ) { + title.setForeground ( foreground ); + header.setBackground( background ); + } + + //---------------------------------------------------------------------- + private static class Test { + public static void main( String[] args ) { + final JFrame main = new JFrame( "Hello" ); + final JDialog dialog = new PopupDialog( main ); + final JButton b = new JButton( "close" ); + + b.addActionListener + ( new ActionListener() { + public void actionPerformed( ActionEvent e ) { + dialog.setVisible( false ); + dialog.dispose(); + } + } + ); + main.getContentPane().add( new JLabel( "Main window" ) ); + main.pack(); + main.setVisible(true); + + ... [truncated message content] |