Codebase list libmicroba-java / upstream/latest
[svn-upgrade] Integrating new upstream version, libmicroba-java (0.4.4.3) gregor herrmann 15 years ago
71 changed file(s) with 9037 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 Manifest-Version: 1.0
1 Ant-Version: Apache Ant 1.7.0
2 Created-By: 10.0-b22 (Sun Microsystems Inc.)
3
0 <project name="microba" default="mix_release">
1
2
3 <property name="version" value="0.4.4.3" />
4 <property name="src-pack" value="microba-${version}-sources.jar" />
5 <property name="bin-pack" value="microba-${version}.jar" />
6 <property name="doc-pack" value="microba-${version}-javadoc.jar" />
7 <property name="all-pack" value="microba-${version}-full.zip" />
8 <property name="maven-pack" value="microba-${version}-maven.jar" />
9
10 <path id="compile-classpath">
11 <pathelement location="lib-compiletime/jgraph.jar" />
12 </path>
13
14 <target name="src_release">
15 <mkdir dir="redist" />
16
17 <jar destfile="redist\${src-pack}">
18 <fileset dir="." includes="src/**/*.*" />
19 <fileset dir="." includes="lib-compiletime/**/*.txt" />
20 <fileset dir="." includes="license.txt" />
21 <fileset dir="." includes="readme.txt" />
22 <fileset dir="." includes="change.log.txt" />
23 <fileset dir="." includes="build.xml" />
24 </jar>
25 </target>
26
27 <target name="bin_release">
28 <condition property="javamail.complete">
29 <and>
30 <available classname="javax.activation.DataHandler" />
31 <available classname="javax.mail.Transport" />
32 </and>
33 </condition>
34
35
36 <mkdir dir="compile" />
37 <mkdir dir="redist" />
38
39 <echo>IMPORTANT: Assuming libraries in lib-compiletime directory. </echo>
40 <javac srcdir="src" debug="true" destdir="compile" target="1.4" source="1.4" classpathref="compile-classpath">
41 <exclude name="**/demo/**/*.*" />
42 </javac>
43
44 <jar destfile="redist\${bin-pack}">
45 <fileset dir="compile" includes="**/*.*" />
46 <fileset dir="src/main/java">
47 <include name="**/*.png" />
48 <include name="**/*.properties" />
49 </fileset>
50 <fileset dir="." includes="license.txt" />
51 <manifest>
52 <section name="common">
53 <attribute name="Specification-Title" value="Microba" />
54 <attribute name="Specification-Version" value="${version}" />
55 <attribute name="Specification-Vendor" value="Michael Baranov" />
56 <attribute name="Implementation-Title" value="Microba" />
57 <attribute name="Implementation-Version" value="${version}" />
58 <attribute name="Implementation-Vendor" value="Michael Baranov" />
59 <attribute name="Author" value="Michael Baranov" />
60 </section>
61 <section name="com/michaelbaranov/microba/calendar/CalendarPane.class">
62 <attribute name="Java-Bean" value="True" />
63 </section>
64 <section name="com/michaelbaranov/microba/calendar/DatePicker.class">
65 <attribute name="Java-Bean" value="True" />
66 </section>
67 <section name="com/michaelbaranov/microba/gradient/GradientBar.class">
68 <attribute name="Java-Bean" value="True" />
69 </section>
70 <section name="com/michaelbaranov/microba/gradienteditor/GradientEditor.class">
71 <attribute name="Java-Bean" value="True" />
72 </section>
73 <section name="com/michaelbaranov/microba/marker/MarkerBar.class">
74 <attribute name="Java-Bean" value="True" />
75 </section>
76 <section name="com/michaelbaranov/microba/jgrpah/birdview/Birdview.class">
77 <attribute name="Java-Bean" value="True" />
78 </section>
79
80 </manifest>
81 </jar>
82
83 <delete dir="compile" />
84 </target>
85
86 <target name="doc_release">
87 <mkdir dir="javadoc" />
88 <mkdir dir="redist" />
89
90 <javadoc access="public" author="yes" destdir="javadoc">
91 <fileset dir="src">
92 <include name="**/*.java" />
93 <exclude name="**/demo/**/*.java" />
94 </fileset>
95 </javadoc>
96
97 <jar destfile="redist\${doc-pack}">
98 <fileset dir="javadoc" includes="**/*.*" />
99 </jar>
100
101 <delete dir="javadoc" />
102 </target>
103
104 <target name="mix_release">
105 <antcall target="bin_release" />
106 <antcall target="src_release" />
107 <antcall target="doc_release" />
108
109 <zip destfile="redist\${all-pack}">
110 <fileset dir="redist">
111 <include name="${bin-pack}" />
112 <include name="${doc-pack}" />
113 <include name="${src-pack}" />
114 </fileset>
115 </zip>
116
117 <jar destfile="redist\${maven-pack}">
118 <fileset dir="redist">
119 <include name="${bin-pack}" />
120 <include name="${doc-pack}" />
121 <include name="${src-pack}" />
122 </fileset>
123 <fileset dir=".">
124 <include name="pom.xml"/>
125 </fileset>
126 </jar>
127 </target>
128
129
130
131 </project>
0 v.0.4.4.3
1 * Added: CalendarPane.observeMonth(int, int);
2 * Added: Slovak and Czech translation (thanks to Lubomir Grajciar)
3 * Added: Hebrew translation (thanks to Moshe Elisha)
4 * Added: Turkish translation (thanks to Emre Yazici)
5 * Added: Hungarian translation (thanks to Zoltan Kuroli)
6
7 v.0.4.4.2
8 * changed misspelled package name 'jgrpah' to 'jgraph'
9 * fixed build script to correctly package resources (thanks to Velimir Gasparovic)
10
11 v.0.4.4.1
12 * Change: changed project directory structure according to Maven guidelines.
13 * Fixed: DatePicker popup did not close when clicked on already selecteed date.
14 * CalendarPane.fireCommitEvent(boolean) made public
15 * CalendarPane.fireActionEvent() made public
16
17 v.0.4.4
18 * Added: DatePicker.dropdownFocusable property
19 * Added: MicrobaComponent.colorOverrideMap property
20 * Added: Microba.setColorOverrideMap method
21 These two improvements allow to override colors on per-instance and per-L&F basis.
22 Currenty CalendarPane and DatePicker support some color overriding.
23 * Fixed: CalendarPane ignores enabled property
24
25 v.0.4.3.4 (21 nov 2006)
26 * Fixed: Microba works with NetBeans Matisse GUI editor.
27 Thanks to Witold Szczerba for testing the fix.
28 * Fixed: manifest now specifies javabeans
29 * Refactored: common superclass extracted: MicrobaComponent
30
31 v.0.4.3.3
32 * Fixed: DatePicker ignores locale passed in constructor
33
34 v.0.4.3.2
35 * Fixed: DatePicker ignores showWeekNumber
36 * Fixed: DatePicker may return wrong date via getDate() in some cases
37 * Fixed: Portuguese translation corrected by Roger Araújo
38
39 v.0.4.3.1
40 * Fixed: DatePicker displays no tooltip string
41 * Fixed: DatePicker goes to infinite loop if keepTime is true, and date format has no time fields.
42 Thanks to Wolfgang Fietzke for his excellent bug report!
43
44 v0.4.3
45 * Added: Birdview component for JGraph library
46 * Added: Swedish translation for DatePicker
47 * Added: CalendarPane.stripDate ( and DatePicker.stripDate ) property (optional time stripping)
48 * Added: DatePicker.keepTime property (improved time field handling)
49 * Added: DatePicker.pickerStyle property (controls visual style of the picker itself)
50 * Added: DatePicker.showButtonOnly() shortcut method
51 * Added: static CalendarPane.stripDate(...) utility method
52 * Fixed: DatePicker.setDateFormat(...) never fired a PropertyChangeEvent
53 * Changed: picker-16.png ico for DatePicker changed
54
55 v.0.4.2 (31 jul 2006)
56 * Refactored: dateStyle property of DatePicker was dropped in favour of dateFormat property. However,
57 old constructors preserved.
58 * Fixed: OutOfMemory exception bug fixed. The bug prevented components to be garbage collected because
59 references were held by Timer tasks. Regression: CalendarPane will update 'today' date only
60 on creation.
61
62 v.0.4.1 (18 jun 2006)
63 * Added: ability to show number of weeks for DatePicker and CalendarPane.
64 * Fixed: Applet refresh problem: see readme.txt, see Microba.init()
65 * Fixed: Polish translation (thanks to Gregory Kaczmarczyk)
66
67 v.0.4 (29 mar 2006)
68 * Refactored: com.michaelbaranov.microba.common package introduced
69 * Refactored: class HollidayPolicy renamed to HolidayPolicy
70 * Refactored: properties named 'hollidayPolicy' renamed to 'holidayPolicy' in all classes
71 * Refactored: renamed recources in com.michaelbaranov.microba.calendar.resource:
72 16.png -> picker-16.png
73 l.png -> back-16.png
74 ll.png -> back-fast-16.png
75 r.png -> forward-16.png
76 rr.png -> forward-fast-16.png
77 * Added: MarkerBar, GradientBar, GradientEditor controls
78 * Added: multiple translations for CalendarPane UI
79 * Added: enabled/disabled state for DatePicker and CalendarPane
80 * Fixed: DatePickerCellEditor not respected focus lost behavior of the DatePicker.
81 Now it is possible to commit cell edit when cell edit stops (e.g. tab out).
82
83
84
85 v.0.3 (15 dec 2005)
86 * First public release
87
88
0 Copyright (c) 2005-2006, Michael Baranov
1 All rights reserved.
2
3 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
4
5 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
6 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
7 * Neither the name of the MICROBA, MICHAELBARANOV.COM, MICHAEL BARANOV nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
8
9 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
microba-0.4.4.2-javadoc.jar less more
Binary diff not shown
microba-0.4.4.2-sources.jar less more
Binary diff not shown
microba-0.4.4.2.jar less more
Binary diff not shown
0 TIPS & TRICKS:
1 1. In Applet#init(), call Microba.init() to handle browser refresh button correctly.
2
3 CONTRIBUTORS:
4 (random order)
5 * Alessandro Falappa: Italian translation
6 * Frido van Orden, Henk van Voorthuijsen: Dutch translation
7 * Gustavo Santucho: Spanish translation
8 * Gregory Kaczmarczyk: Polish translation
9 * Philipp Meier: German translation
10 * Claus Nielsen: Danish translation
11 * Felix Bordea: Romanian translation
12 * David Ekholm: Swedish translation
13
14 TRANSLATION:
15 For the list of supported language translations, look into
16 com\michaelbaranov\microba\calendar\DefaultCalendarResources.properties
17
18 Help translating needed! Please contribute!
19 Send the translations to: michael[.]baranov[@]gmail[.]com
20
21 KNOWN PROBLEMS:
22
23 1. DatePicker: while editing the field, enter arbitrary string after the last formatted character,
24 position cursor anywhere past the last formatted character, press up or down key -> exception is
25 raised:
26
27 java.lang.IllegalArgumentException: Invalid index
28 ...
29
30 Reason: a bug in Sun's javax.swing.text.InternationalFormatter.
31
32 2. DatePicker: set the style to STYLE_MODERN, open dropdown, click month combo box -> dropdown
33 is hidden OR can not close dropdown anymore OR exception (depends on JRE version).
34
35 Reason: a bug in Sun's javax.swing.JPopupMenu, when using "popup in popup".
36
37 3. DatePicker: if a heavy-weight popup is used to display dropdown (for ex. it goes outside a JFrame),
38 dropdown does not receive keyboard focus anymore.
39
40 Reason: a bug in Sun's focus handling routines.
0 import java.awt.FlowLayout;
1 import java.awt.event.ActionEvent;
2 import java.awt.event.ActionListener;
3 import java.beans.PropertyVetoException;
4
5 import javax.swing.JButton;
6 import javax.swing.JFrame;
7
8 import com.michaelbaranov.microba.calendar.DatePicker;
9
10 public class Snippet {
11
12 public static void main(String[] args) {
13 JFrame frame = new JFrame();
14 frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
15 frame.setLayout(new FlowLayout());
16
17 final DatePicker picker = new DatePicker();
18 picker.addActionListener(new ActionListener() {
19 public void actionPerformed(ActionEvent e) {
20 System.out.println(picker.getDate());
21 }
22 });
23
24 JButton btn = new JButton("NULL");
25 btn.addActionListener(new ActionListener() {
26 public void actionPerformed(ActionEvent e) {
27 try {
28 picker.setDate(null);
29 } catch (PropertyVetoException e1) {
30 System.out.println("Could not set null date.");
31 e1.printStackTrace();
32 }
33 picker.setEnabled(false);
34 }
35 });
36 frame.add(picker);
37 frame.add(btn);
38 frame.setSize(640, 480);
39 frame.setVisible(true);
40 }
41 }
0 package com.michaelbaranov.microba;
1
2 import java.applet.Applet;
3 import java.awt.Color;
4 import java.beans.PropertyChangeEvent;
5 import java.beans.PropertyChangeListener;
6 import java.util.HashMap;
7 import java.util.Map;
8
9 import javax.swing.LookAndFeel;
10 import javax.swing.UIManager;
11
12 import com.michaelbaranov.microba.common.MicrobaComponent;
13
14 /**
15 * This class is used to initialize Microba library.
16 *
17 * @author Michael Baranov
18 *
19 */
20 public class Microba {
21
22 private static UIChangeListener changeListener = new UIChangeListener();
23
24 /**
25 * Initializes the library: installs L&F properties, sets up a L&F change
26 * listener.
27 * <p>
28 * No need to call this method explicitly for desktop applications. You
29 * should only call it in {@link Applet#init()}. This will handle browser
30 * refresh button correctly.
31 *
32 */
33 public static synchronized void init() {
34 setLookAndFeelProperties(UIManager.getLookAndFeel());
35
36 UIManager.removePropertyChangeListener(changeListener);
37 UIManager.addPropertyChangeListener(changeListener);
38 }
39
40 private static synchronized void setLookAndFeelProperties(
41 LookAndFeel lookAndFeel) {
42 if (lookAndFeel == null)
43 return;
44
45 String packagePrefix = "com.michaelbaranov.microba.";
46
47 // all L&F
48 UIManager.put("microba.CalendarPaneUI", packagePrefix
49 + "calendar.ui.basic.BasicCalendarPaneUI");
50 UIManager.put("microba.DatePickerUI", packagePrefix
51 + "calendar.ui.basic.BasicDatePickerUI");
52 UIManager.put("microba.GradientUI", packagePrefix
53 + "gradient.ui.basic.BasicGradientUI");
54 UIManager.put("microba.GradientEditorUI", packagePrefix
55 + "gradienteditor.ui.basic.BasicGradientEditorUI");
56 UIManager.put("microba.MarkerBarUI", packagePrefix
57 + "marker.ui.basic.BasicMarkerBarUI");
58
59 // particular L&F
60 if (lookAndFeel.getID().equals("Windows")) {
61 UIManager.put("microba.MarkerBarUI", packagePrefix
62 + "marker.ui.windows.WindowsMarkerBarUI");
63 } else if (lookAndFeel.getID().equals("Metal")) {
64 UIManager.put("microba.MarkerBarUI", packagePrefix
65 + "marker.ui.metal.MetalMarkerBarUI");
66 } else if (lookAndFeel.getID().equals("Motif")) {
67 UIManager.put("microba.MarkerBarUI", packagePrefix
68 + "marker.ui.motif.MotifMarkerBarUI");
69 }
70
71 }
72
73 private static final class UIChangeListener implements
74 PropertyChangeListener {
75 public void propertyChange(PropertyChangeEvent event) {
76 if ("lookAndFeel".equals(event.getPropertyName())) {
77 setLookAndFeelProperties((LookAndFeel) event.getNewValue());
78 }
79 }
80 }
81
82 private static Map lookAndFeelToOverride = new HashMap();
83
84 /**
85 * Sets per-Lokk&Feel map of color overrides.
86 *
87 *
88 * @param lookAndFeel
89 * look&feel ID
90 * @param overrides
91 * keys in the map are {@link String} constants, valuse are of
92 * type {@link Color} or of type {@link String} (in this case,
93 * {@link Color} values are obtained via
94 * {@link UIManager#getColor(Object)}). May be <code>null</code>.
95 */
96 public static void setColorOverrideMap(String lookAndFeel, Map overrides) {
97 lookAndFeelToOverride.put(lookAndFeel, overrides);
98 // TODO: refresh ui delegates
99 }
100
101 /**
102 * Returns overriden color for given component in current Look&Feel. The
103 * algorithms is:
104 * <ul>
105 * <li>If the component overrides the constant (per-instance override),
106 * then it is returned.
107 * <li>If the library overrides the constant (per-Look&Feel override), then
108 * it is returned.
109 * <li>Else <code>null</code> is returned.
110 * </ul>
111 * This method is actually intended to be used by UI delegates of the
112 * library.
113 *
114 * @param colorConstant
115 * color constant
116 * @param component
117 * component of the library
118 * @return overriden color or <code>null</code> if not overriden
119 */
120 public static synchronized Color getOverridenColor(String colorConstant,
121 MicrobaComponent component) {
122
123 Map componentOverrideMap = component.getColorOverrideMap();
124 if (componentOverrideMap != null) {
125 if (componentOverrideMap.containsKey(colorConstant)) {
126 Object val = componentOverrideMap.get(colorConstant);
127 if (val instanceof Color)
128 return (Color) val;
129 else
130 return UIManager.getColor(val);
131 }
132 }
133
134 String currentLookAndFeel = UIManager.getLookAndFeel().getID();
135 Map overrides = (Map) lookAndFeelToOverride.get(currentLookAndFeel);
136 if (overrides != null) {
137 if (overrides.containsKey(colorConstant)) {
138 Object val = overrides.get(colorConstant);
139 if (val instanceof Color)
140 return (Color) val;
141 else
142 return UIManager.getColor(val);
143
144 }
145 }
146
147 return null;
148 }
149
150 /**
151 * Returns overriden color for given component in current Look&Feel or a
152 * default value. The algorithms is:
153 * <ul>
154 * <li>If the component overrides the constant (per-instance override),
155 * then it is returned.
156 * <li>If the library overrides the constant (per-Look&Feel override), then
157 * it is returned.
158 * <li>Else defaultColor is returned.
159 * </ul>
160 * This method is actually intended to be used by UI delegates of the
161 * library.
162 *
163 * @param colorConstant
164 * color constant
165 * @param component
166 * component of the library
167 * @param defaultColor
168 * @return overriden color or defaultColor if not overriden
169 */
170 public static synchronized Color getOverridenColor(String colorConstant,
171 MicrobaComponent component, Color defaultColor) {
172 Color overriden = getOverridenColor(colorConstant, component);
173 if (overriden != null)
174 return overriden;
175 else
176 return defaultColor;
177 }
178
179 }
0 package com.michaelbaranov.microba.calendar;
1
2 public interface CalendarColors {
3
4 // *** Header
5
6 public static final String COLOR_CALENDAR_HEADER_FOREGROUND_ENABLED = "calendar.header.foreground.enabled";
7
8 public static final String COLOR_CALENDAR_HEADER_FOREGROUND_DISABLED = "calendar.header.foreground.disabled";
9
10 public static final String COLOR_CALENDAR_HEADER_BACKGROUND_ENABLED = "calendar.header.background.enabled";
11
12 public static final String COLOR_CALENDAR_HEADER_BACKGROUND_DISABLED = "calendar.header.background.disabled";
13
14 public static final String COLOR_CALENDAR_HEADER_FOREGROUND_WEEKEND_ENABLED = "calendar.header.foreground.weekend.enabled";
15
16 public static final String COLOR_CALENDAR_HEADER_FOREGROUND_WEEKEND_DISABLED = "calendar.header.foreground.weekend.disabled";
17
18 // *** Dates grid
19 public static final String COLOR_CALENDAR_GRID_FOCUS = "calendar.grid.focus";
20
21 public static final String COLOR_CALENDAR_GRID_RESTRICTED = "calendar.grid.banned";
22
23 //
24 public static final String COLOR_CALENDAR_GRID_BACKGROUND_ENABLED = "calendar.grid.background.enabled";
25
26 public static final String COLOR_CALENDAR_GRID_BACKGROUND_DISABLED = "calendar.grid.background.disabled";
27
28 public static final String COLOR_CALENDAR_GRID_FOREGROUND_ENABLED = "calendar.grid.foreground.enabled";
29
30 public static final String COLOR_CALENDAR_GRID_FOREGROUND_DISABLED = "calendar.grid.foreground.disabled";
31
32 //
33 public static final String COLOR_CALENDAR_GRID_SELECTION_BACKGROUND_ENABLED = "calendar.grid.selection.background.enabled";
34
35 public static final String COLOR_CALENDAR_GRID_SELECTION_BACKGROUND_DISABLED = "calendar.grid.selection.background.disabled";
36
37 public static final String COLOR_CALENDAR_GRID_WEEKEND_FOREGROUND_ENABLED = "calendar.grid.weekend.foreground.enabled";
38
39 public static final String COLOR_CALENDAR_GRID_WEEKEND_FOREGROUND_DISABLED = "calendar.grid.weekend.foreground.disabled";
40
41 public static final String COLOR_CALENDAR_GRID_HOLIDAY_FOREGROUND_ENABLED = "calendar.grid.holiday.foreground.enabled";
42
43 public static final String COLOR_CALENDAR_GRID_HOLIDAY_FOREGROUND_DISABLED = "calendar.grid.holiday.foreground.disabled";
44
45 }
0 package com.michaelbaranov.microba.calendar;
1
2 import java.awt.event.ActionEvent;
3 import java.awt.event.ActionListener;
4 import java.beans.PropertyChangeEvent;
5 import java.beans.PropertyChangeListener;
6 import java.beans.PropertyVetoException;
7 import java.util.Calendar;
8 import java.util.Date;
9 import java.util.Locale;
10 import java.util.TimeZone;
11
12 import javax.swing.JFormattedTextField;
13 import javax.swing.event.EventListenerList;
14
15 import com.michaelbaranov.microba.calendar.ui.CalendarPaneUI;
16 import com.michaelbaranov.microba.common.CommitEvent;
17 import com.michaelbaranov.microba.common.CommitListener;
18 import com.michaelbaranov.microba.common.MicrobaComponent;
19
20 /**
21 * A concrete implementation of JComponent. Capable of displaying and selecting
22 * dates, much like a real-world calendar.
23 *
24 * @author Michael Baranov
25 */
26 public class CalendarPane extends MicrobaComponent implements CalendarColors {
27
28 /**
29 * The name of a "date" property.
30 */
31 public static final String PROPERTY_NAME_DATE = "date";
32
33 /**
34 * The name of a "locale" property.
35 */
36 public static final String PROPERTY_NAME_LOCALE = "locale";
37
38 /**
39 * The name of a "zone" property.
40 */
41 public static final String PROPERTY_NAME_ZONE = "zone";
42
43 /**
44 * The name of a "style" property.
45 */
46 public static final String PROPERTY_NAME_STYLE = "style";
47
48 /**
49 * The name of a "showTodayButton" property.
50 */
51 public static final String PROPERTY_NAME_SHOW_TODAY_BTN = "showTodayButton";
52
53 /**
54 * The name of a "showNoneButton" property.
55 */
56 public static final String PROPERTY_NAME_SHOW_NONE_BTN = "showNoneButton";
57
58 /**
59 * The name of a "focusLocatBehavior" property.
60 */
61 public static final String PROPERTY_NAME_FOCUS_LOST_BEHAVIOR = "focusLostBehavior";
62
63 /**
64 * The name of a "vetoPolicy" property.
65 */
66 public static final String PROPERTY_NAME_VETO_POLICY = "vetoPlicy";
67
68 /**
69 * The name of a "holidayPolicy" property.
70 */
71 public static final String PROPERTY_NAME_HOLIDAY_POLICY = "holidayPolicy";
72
73 /**
74 * The name of a "resources" property.
75 */
76 public static final String PROPERTY_NAME_RESOURCES = "resources";
77
78 /**
79 * The name of a "resources" property.
80 */
81 public static final String PROPERTY_NAME_SHOW_NUMBER_WEEK = "showNumberOfWeek";
82
83 /**
84 * The name of a "stripTime" property.
85 */
86 public static final String PROPERTY_NAME_STRIP_TIME = "stripTime";
87
88 /**
89 * A constant for the "style" property.
90 */
91 public static final int STYLE_MODERN = 0x10;
92
93 /**
94 * A constant for the "style" property.
95 */
96 public static final int STYLE_CLASSIC = 0x20;
97
98 private static final String uiClassID = "microba.CalendarPaneUI";
99
100 private EventListenerList commitListenerList = new EventListenerList();
101
102 private EventListenerList actionListenerList = new EventListenerList();
103
104 private Date date;
105
106 private TimeZone zone;
107
108 private Locale locale;
109
110 private VetoPolicy vetoPolicy;
111
112 private HolidayPolicy holidayPolicy;
113
114 private CalendarResources resources;
115
116 private int style;
117
118 private boolean showTodayButton;
119
120 private boolean showNoneButton;
121
122 private int focusLostBehavior;
123
124 private boolean showNumberOfWeek;
125
126 private boolean stripTime;
127
128 public String getUIClassID() {
129 return uiClassID;
130 }
131
132 /**
133 * Constructor.
134 */
135 public CalendarPane() {
136 this(null, 0, Locale.getDefault(), TimeZone.getDefault());
137 }
138
139 /**
140 * Constructor.
141 */
142 public CalendarPane(int style) {
143 this(null, style, Locale.getDefault(), TimeZone.getDefault());
144 }
145
146 /**
147 * Constructor.
148 */
149 public CalendarPane(Date initialDate) {
150 this(initialDate, 0, Locale.getDefault(), TimeZone.getDefault());
151 }
152
153 /**
154 * Constructor.
155 */
156 public CalendarPane(Date initialDate, int style) {
157 this(initialDate, style, Locale.getDefault(), TimeZone.getDefault());
158 }
159
160 /**
161 * Constructor.
162 */
163 public CalendarPane(Date initialDate, int style, Locale locale) {
164 this(initialDate, style, locale, TimeZone.getDefault());
165 }
166
167 /**
168 * Constructor.
169 */
170 public CalendarPane(Date initialDate, int style, Locale locale,
171 TimeZone zone) {
172 checkStyle(style);
173 checkLocale(locale);
174 checkTimeZone(zone);
175 this.style = style;
176 this.date = initialDate;
177 this.locale = locale;
178 this.zone = zone;
179 this.focusLostBehavior = JFormattedTextField.COMMIT_OR_REVERT;
180 this.showTodayButton = true;
181 this.showNoneButton = true;
182 this.vetoPolicy = null;
183 this.resources = new DefaultCalendarResources();
184 this.stripTime = true;
185
186 // forward date property change to action event
187 addPropertyChangeListener(PROPERTY_NAME_DATE,
188 new PropertyChangeListener() {
189 public void propertyChange(PropertyChangeEvent evt) {
190 fireActionEvent();
191 }
192 });
193
194 updateUI();
195 }
196
197 /**
198 * Returns currently selected date in the control.
199 * <p>
200 * The returned date is guaranteed to pass the restriction check by the
201 * current {@link VetoPolicy}. Based on the value of {@link #stripTime}
202 * property, the returned date may be automatically stripped.
203 *
204 * @return currently selected date
205 * @see #stripTime
206 * @see #stripTime(Date, TimeZone, Locale)
207 */
208 public Date getDate() {
209 if (this.stripTime)
210 return stripTime(date, getZone(), getLocale());
211 else
212 return date;
213 }
214
215 /**
216 * Sets currently selected date to the control.
217 * <p>
218 * The given date is checked against the current {@link VetoPolicy}. If the
219 * check is passed, the date is transferred to the control and the control
220 * is updated to display the date.
221 * <p>
222 * A {@link PropertyChangeEvent} may be fired, an {@link ActionEvent} may be
223 * fired.
224 *
225 * @param date
226 * the date to set
227 * @throws PropertyVetoException
228 * if the date is restricted by the current {@link VetoPolicy}.
229 * @see #getVetoPolicy()
230 * @see #setVetoPolicy(VetoPolicy)
231 * @see #addActionListener(ActionListener)
232 */
233 public void setDate(Date date) throws PropertyVetoException {
234 if (!checkDate(date)) {
235 PropertyChangeEvent propertyChangeEvent = new PropertyChangeEvent(
236 this, PROPERTY_NAME_DATE, this.date, date);
237 throw new PropertyVetoException(
238 "Value vetoed by current vetoPolicy", propertyChangeEvent);
239 }
240 Date old = this.date;
241 this.date = date;
242 if (old != null || date != null) {
243 firePropertyChange(PROPERTY_NAME_DATE, old, date);
244 }
245 }
246
247 /**
248 * Returns current locale.
249 *
250 * @return current locale
251 */
252 public Locale getLocale() {
253 return locale;
254 }
255
256 /**
257 * Sets current locale.
258 * <p>
259 * The locale is used to construct internal {@link Calendar} instances and
260 * affects visual representation of the control.
261 *
262 * @param locale
263 * the locale to set
264 */
265 public void setLocale(Locale locale) {
266 Locale old = getLocale();
267 this.locale = locale;
268 firePropertyChange(PROPERTY_NAME_LOCALE, old, getLocale());
269 }
270
271 /**
272 * Returns current time zone.
273 *
274 * @return current time zone
275 */
276 public TimeZone getZone() {
277 return zone;
278 }
279
280 /**
281 * Sets current time zone.
282 * <p>
283 * The time zone is used to construct internal {@link Calendar} instances
284 * and affects visual representation of the control. The dates returned by
285 * {@link #getDate() } will have all time components set to zero considering
286 * the current locale.
287 *
288 * @param zone
289 * the time zone to set
290 */
291 public void setZone(TimeZone zone) {
292 TimeZone old = getZone();
293 this.zone = zone;
294 firePropertyChange(PROPERTY_NAME_ZONE, old, getZone());
295 }
296
297 /**
298 * Returns current visual style of the control.
299 *
300 * @return current visual style constant.
301 */
302 public int getStyle() {
303 return style;
304 }
305
306 /**
307 * Sets the current visual style of the control.
308 * <p>
309 * The control is then updated to reflect the new style.
310 *
311 * @param style
312 * the style to set
313 * @see #STYLE_CLASSIC
314 * @see #STYLE_MODERN
315 */
316 public void setStyle(int style) {
317 style = checkStyle(style);
318 int old = this.style;
319 this.style = style;
320 firePropertyChange(PROPERTY_NAME_STYLE, old, style);
321 }
322
323 /**
324 * Is today button visible?
325 * <p>
326 * The today button allows the user to quickly select current date.
327 *
328 * @return <code>true</code> if the today button is visible,
329 * <code>false</code> otherwise
330 */
331 public boolean isShowTodayButton() {
332 return showTodayButton;
333 }
334
335 /**
336 * Shows or hides the today-button.
337 * <p>
338 * The today-button allows the user to quickly select current date.
339 *
340 * @param visible
341 * <code>true</code> to show the today-button <code>false</code>
342 * to hide
343 */
344 public void setShowTodayButton(boolean visible) {
345 Boolean old = new Boolean(this.showTodayButton);
346 this.showTodayButton = visible;
347 firePropertyChange(PROPERTY_NAME_SHOW_TODAY_BTN, old, new Boolean(
348 visible));
349 }
350
351 /**
352 * Is the none-button visible?
353 * <p>
354 * The none-button allows the user to select empty date (null-date, no
355 * date).
356 *
357 * @return <code>true</code> if the none-button is visible,
358 * <code>false</code> otherwise
359 */
360 public boolean isShowNoneButton() {
361 return showNoneButton;
362 }
363
364 /**
365 * Shows or hides the none-button.
366 * <p>
367 * The none-button allows the user to select empty date (null-date, no
368 * date).
369 *
370 * @param visible
371 * <code>true</code> to show the none-button <code>false</code>
372 * to hide
373 */
374 public void setShowNoneButton(boolean visible) {
375 Boolean old = new Boolean(this.showNoneButton);
376 this.showNoneButton = visible;
377 firePropertyChange(PROPERTY_NAME_SHOW_NONE_BTN, old, new Boolean(
378 visible));
379 }
380
381 /**
382 * Returns the focus lost behavior. Possible values are:
383 *
384 * <ul>
385 * <li><code> {@link JFormattedTextField#COMMIT}</code> <li><code>
386 * {@link JFormattedTextField#COMMIT_OR_REVERT}</code> <li><code>
387 * {@link JFormattedTextField#REVERT}</code> <li><code>
388 * {@link JFormattedTextField#PERSIST}</code>
389 * </ul>
390 * Original meaning preserved.
391 *
392 * @return the focus lost behavior constant
393 * @see JFormattedTextField
394 */
395 public int getFocusLostBehavior() {
396 return focusLostBehavior;
397 }
398
399 /**
400 * Sets the focus lost behaviour. Possible values are:
401 *
402 * <ul>
403 * <li><code> {@link JFormattedTextField#COMMIT}</code> <li><code>
404 * {@link JFormattedTextField#COMMIT_OR_REVERT}</code> <li><code>
405 * {@link JFormattedTextField#REVERT}</code> <li><code>
406 * {@link JFormattedTextField#PERSIST}</code>
407 * </ul>
408 * Original meaning preserved.
409 *
410 * @param behavior
411 * the focus lost behavior constant
412 * @see JFormattedTextField
413 */
414 public void setFocusLostBehavior(int behavior) {
415 behavior = checkFocusLostbehavior(behavior);
416 int old = this.focusLostBehavior;
417 this.focusLostBehavior = behavior;
418 firePropertyChange(PROPERTY_NAME_FOCUS_LOST_BEHAVIOR, old, behavior);
419 }
420
421 /**
422 * Resurns current calendar resources model.
423 * <p>
424 * The model is used to query localized resources for the control.
425 *
426 * @return current calendar resources model
427 * @see CalendarResources
428 */
429 public CalendarResources getResources() {
430 return resources;
431 }
432
433 /**
434 * Sets current calendar resources model.
435 * <p>
436 * The model is used to query localized resources for the control.
437 *
438 * @param resources
439 * a calendar resources model to set. Should not be
440 * <code>null</code>
441 * @see CalendarResources
442 */
443 public void setResources(CalendarResources resources) {
444 CalendarResources old = this.resources;
445 this.resources = resources;
446 firePropertyChange(PROPERTY_NAME_RESOURCES, old, resources);
447 }
448
449 /**
450 * Returns current holliday policy (model).
451 * <p>
452 * The policy is used to query holliday dates and holliday descriptions.
453 *
454 * @return current holliday policy or <code>null</code> if none set
455 * @see HolidayPolicy
456 */
457 public HolidayPolicy getHolidayPolicy() {
458 return holidayPolicy;
459 }
460
461 /**
462 * Sets current holliday policy (model) then updates the control to reflect
463 * the policy set.
464 * <p>
465 * The policy is used to query holliday dates and holiday descriptions.
466 *
467 * @param holidayPolicy
468 * a holliday policy to set. May be <code>null</code>
469 * @see VetoPolicy
470 */
471 public void setHolidayPolicy(HolidayPolicy holidayPolicy) {
472 HolidayPolicy old = this.holidayPolicy;
473 this.holidayPolicy = holidayPolicy;
474 firePropertyChange(PROPERTY_NAME_HOLIDAY_POLICY, old, holidayPolicy);
475 }
476
477 /**
478 * Returns the current veto policy (model).
479 * <p>
480 * The policy is used to veto dates in the control.
481 *
482 * @return current veto policy or <code>null</code> if none set
483 * @see VetoPolicy
484 */
485 public VetoPolicy getVetoPolicy() {
486 return vetoPolicy;
487 }
488
489 /**
490 * Sets the current veto policy (model).
491 * <p>
492 * The policy is used to veto dates in the control.
493 *
494 * @param vetoModel
495 * a veto policy to set. May be <code>null</code>
496 */
497 public void setVetoPolicy(VetoPolicy vetoModel) {
498 VetoPolicy old = this.vetoPolicy;
499 this.vetoPolicy = vetoModel;
500 firePropertyChange(PROPERTY_NAME_VETO_POLICY, old, vetoModel);
501 }
502
503 /**
504 * Is the number of every week visible?
505 *
506 * @return <code>true</code> if the number of every week is visible,
507 * <code>false</code> otherwise
508 */
509 public boolean isShowNumberOfWeek() {
510 return showNumberOfWeek;
511 }
512
513 /**
514 * Is time protion of the date automatically striped, based on current
515 * locale and ime zone?
516 *
517 * @return <code>true</code> if {@link #getDate()} returns a stripped date,
518 * <code>false</code> otherwise
519 * @see #setStripTime(boolean)
520 * @see #stripTime(Date, TimeZone, Locale)
521 */
522 public boolean isStripTime() {
523 return stripTime;
524 }
525
526 /**
527 * Makes {@link #getDate()} either strip the time portion of the date, or
528 * keep it.
529 *
530 * @param stripTime
531 * <code>true</code> to strip time, <code>false</code> to keep
532 * time
533 */
534 public void setStripTime(boolean stripTime) {
535 this.stripTime = stripTime;
536 }
537
538 /**
539 * Shows or hides the the number of every week.
540 * <p>
541 * The number of week is based on the current locale for the component.
542 *
543 * @param visible
544 * <code>true</code> to show the the number of every week
545 * <code>false</code> to hide
546 */
547 public void setShowNumberOfWeek(boolean visible) {
548 boolean old = this.showNumberOfWeek;
549 this.showNumberOfWeek = visible;
550 firePropertyChange(PROPERTY_NAME_SHOW_NUMBER_WEEK, old, visible);
551 }
552
553 /**
554 * Adds an {@link ActionListener} listener.
555 *
556 * @param listener
557 * a listener to add
558 * @see ActionListener
559 */
560 public void addActionListener(ActionListener listener) {
561 actionListenerList.add(ActionListener.class, listener);
562 }
563
564 /**
565 * Removes an {@link ActionListener} listener.
566 *
567 * @param listener
568 * a listener to remove
569 * @see ActionListener
570 */
571 public void removeActionListener(ActionListener listener) {
572 actionListenerList.remove(ActionListener.class, listener);
573
574 }
575
576 /**
577 * Adds an {@link CommitListener} listener.
578 *
579 * @param listener
580 * a listener to add
581 * @see CommitListener
582 */
583 public void addCommitListener(CommitListener listener) {
584 commitListenerList.add(CommitListener.class, listener);
585 }
586
587 /**
588 * Removes an {@link CommitListener} listener.
589 *
590 * @param listener
591 * a listener to remove
592 * @see CommitListener
593 */
594 public void removeCommitListener(CommitListener listener) {
595 commitListenerList.remove(CommitListener.class, listener);
596 }
597
598 /**
599 * Forces the control to commit current user's edit. The opertaion may fail
600 * because the date in the control may be restricted by current veto policy.
601 * If successfull, the current date of the control may change, a
602 * {@link CommitEvent} is fired.
603 *
604 * @return <code>true</code> if successful, <code>false</code> otherwise
605 * @see #revertEdit()
606 * @see #getFocusLostBehavior()
607 * @see #setFocusLostBehavior(int)
608 */
609 public boolean commitEdit() {
610 try {
611 ((CalendarPaneUI) getUI()).commit();
612 fireCommitEvent(true);
613 return true;
614 } catch (Exception e) {
615 return false;
616 }
617 }
618
619 /**
620 * Forces the control to revert current user's edit to reflect current
621 * control's date. The current date of the control may change, a
622 * {@link CommitEvent} is fired.
623 *
624 * @see #revertEdit()
625 * @see #getFocusLostBehavior()
626 * @see #setFocusLostBehavior(int)
627 */
628 public void revertEdit() {
629 ((CalendarPaneUI) getUI()).revert();
630 fireCommitEvent(false);
631 }
632
633 /**
634 * Forces the control to commit or revert user's edit depending on the
635 * current focus lost behavior as if the focus would be lost.
636 *
637 * @see #commitEdit()
638 * @see #revertEdit()
639 * @see #getFocusLostBehavior()
640 * @see #setFocusLostBehavior(int)
641 */
642 public void commitOrRevert() {
643 switch (focusLostBehavior) {
644 case JFormattedTextField.REVERT:
645 revertEdit();
646 break;
647 case JFormattedTextField.COMMIT:
648 commitEdit();
649 break;
650 case JFormattedTextField.COMMIT_OR_REVERT:
651 if (!commitEdit())
652 revertEdit();
653 break;
654 case JFormattedTextField.PERSIST:
655 // do nothing
656 break;
657 }
658 }
659
660 /**
661 * Fires a {@link CommitEvent} to all registered listeners.
662 *
663 * @param commit
664 * <code>true</code> to indicate commit, <code>false</code> to
665 * indicate revert
666 * @see CommitEvent
667 * @see CommitListener
668 */
669 public void fireCommitEvent(boolean commit) {
670 Object[] listeners = commitListenerList.getListenerList();
671
672 for (int i = listeners.length - 2; i >= 0; i -= 2)
673 if (listeners[i] == CommitListener.class)
674 ((CommitListener) listeners[i + 1]).commit(new CommitEvent(
675 this, commit));
676 }
677
678 /**
679 * Fires a {@link ActionEvent} to all registered listeners.
680 *
681 * @see ActionEvent
682 * @see ActionListener
683 */
684 public void fireActionEvent() {
685 Object[] listeners = actionListenerList.getListenerList();
686
687 for (int i = listeners.length - 2; i >= 0; i -= 2)
688 if (listeners[i] == ActionListener.class)
689 ((ActionListener) listeners[i + 1])
690 .actionPerformed(new ActionEvent(this, 0, "value"));
691 }
692
693 private void checkTimeZone(TimeZone zone) {
694 if (zone == null)
695 throw new IllegalArgumentException("'zone' can not be null.");
696
697 }
698
699 private void checkLocale(Locale locale) {
700 if (locale == null)
701 throw new IllegalArgumentException("'locale' can not be null.");
702
703 }
704
705 private int checkFocusLostbehavior(int behavior) {
706 if (behavior != JFormattedTextField.COMMIT
707 && behavior != JFormattedTextField.COMMIT_OR_REVERT
708 && behavior != JFormattedTextField.REVERT
709 && behavior != JFormattedTextField.PERSIST)
710 throw new IllegalArgumentException(
711 PROPERTY_NAME_FOCUS_LOST_BEHAVIOR
712 + ": unrecognized behavior");
713 return behavior;
714 }
715
716 private boolean checkDate(Date date) {
717 if (vetoPolicy != null) {
718 if (date == null)
719 return !vetoPolicy.isRestrictNull(this);
720 return !vetoPolicy.isRestricted(this, makeCurrentCalendar(date));
721 } else
722 return true;
723 }
724
725 private int checkStyle(int style) {
726 if (style == 0)
727 style = STYLE_CLASSIC;
728 if (style != STYLE_CLASSIC && style != STYLE_MODERN)
729 throw new IllegalArgumentException(PROPERTY_NAME_STYLE
730 + ": unrecognized style");
731 return style;
732 }
733
734 private Calendar makeCurrentCalendar(Date date) {
735 Calendar c = Calendar.getInstance(zone, locale);
736 c.setTime(date);
737 return c;
738 }
739
740 /**
741 * Returns same date as given, but time portion (hours, minutes, seconds,
742 * fraction of second) set to zero, based on given locale and time zone.
743 * Utility method.
744 * <p>
745 * Examle:<br>
746 * Fri Sep 29 15:57:23 EEST 2006 -> Fri Sep 29 00:00:00 EEST 2006
747 *
748 * @param date
749 * date to strip time from
750 * @param zone
751 * time zone to get zero fields in
752 * @param locale
753 * locale to base the calendar on
754 * @return stripped date
755 */
756 public static Date stripTime(Date date, TimeZone zone, Locale locale) {
757 if (date == null)
758 return null;
759 Calendar tmpCalendar = Calendar.getInstance(zone, locale);
760 tmpCalendar.setTime(date);
761 tmpCalendar.set(Calendar.HOUR_OF_DAY, tmpCalendar
762 .getMinimum(Calendar.HOUR_OF_DAY));
763 tmpCalendar.set(Calendar.MINUTE, tmpCalendar
764 .getMinimum(Calendar.MINUTE));
765 tmpCalendar.set(Calendar.SECOND, tmpCalendar
766 .getMinimum(Calendar.SECOND));
767 tmpCalendar.set(Calendar.MILLISECOND, tmpCalendar
768 .getMinimum(Calendar.MILLISECOND));
769 return tmpCalendar.getTime();
770 }
771
772 /**
773 * Makes the widget display given month within given year without actually
774 * changing selected date.
775 *
776 * @param year
777 * year to show
778 * @param month
779 * month within the year to show
780 */
781 public void observeMonth(int year, int month) {
782 ((CalendarPaneUI) getUI()).observeMonth(year, month);
783 }
784
785 }
0 package com.michaelbaranov.microba.calendar;
1
2 import java.util.Locale;
3
4 /**
5 * An interface is used to provide localized string resources for
6 * {@link CalendarPane} and {@link DatePicker} classes.
7 *
8 * @author Michael Baranov
9 *
10 */
11 public interface CalendarResources {
12
13 /**
14 * A key for "today" word
15 */
16 public static final String KEY_TODAY = "key.today";
17
18 /**
19 * A key for "none" word
20 */
21 public static final String KEY_NONE = "key.none";
22
23 /**
24 * This method is used to query tring resources for {@link CalendarPane} and
25 * {@link DatePicker} classes. Should not return <code>null</code>.
26 *
27 * @param key
28 * one of the keys defined by {@link CalendarResources}
29 * @param locale
30 * a {@link Locale}
31 * @return localized string resource for a given key
32 */
33 public String getResource(String key, Locale locale);
34 }
0 package com.michaelbaranov.microba.calendar;
1
2 import java.text.DateFormat;
3 import java.util.Date;
4 import java.util.Locale;
5 import java.util.Map;
6 import java.util.TimeZone;
7
8 import com.michaelbaranov.microba.calendar.ui.DatePickerUI;
9
10 /**
11 * A concrete implementation of JComponent. Capable of displaying and selecting
12 * dates, much like an editable combo-box with a calendar dropdown.
13 * <p>
14 * This implementatin allows for specifying time component along with the date.
15 * Make sure that: 1) keepTime property is true; 2) stripTime is false; 3)
16 * dateFormat has time fields;
17 *
18 * @author Michael Baranov
19 */
20 public class DatePicker extends CalendarPane {
21
22 /**
23 * The name of a "dateFormat" property.
24 */
25 public static final String PROPERTY_NAME_DATE_FORMAT = "dateFormat";
26
27 /**
28 * The name of a "fieldEditable" property.
29 */
30 public static final String PROPERTY_NAME_FIELD_EDITABLE = "fieldEditable";
31
32 /**
33 * The name of a "keepTime" property.
34 */
35 public static final String PROPERTY_NAME_KEEP_TIME = "keepTime";
36
37 /**
38 * The name of a "pickerStyle" property.
39 */
40 public static final String PROPERTY_NAME_PICKER_STYLE = "pickerStyle";
41
42 /**
43 * The name of a "popupFocusable" property.
44 */
45 public static final String PROPERTY_NAME_DROPDOWN_FOCUSABLE = "dropdownFocusable";
46
47 /**
48 * A constant for the "pickerStyle" property.
49 */
50 public static final int PICKER_STYLE_FIELD_AND_BUTTON = 0x110;
51
52 /**
53 * A constant for the "pickerStyle" property.
54 */
55 public static final int PICKER_STYLE_BUTTON = 0x120;
56
57 private static final String uiClassID = "microba.DatePickerUI";
58
59 private DateFormat dateFormat;
60
61 private boolean fieldEditable;
62
63 private boolean keepTime;
64
65 private int pickerStyle;
66
67 private boolean dropdownFocusable;
68
69 /**
70 * Constructor.
71 */
72 public DatePicker() {
73 this(new Date(), DateFormat.MEDIUM, Locale.getDefault(), TimeZone
74 .getDefault());
75 }
76
77 /**
78 * Constructor.
79 */
80 public DatePicker(Date initialDate) {
81 this(initialDate, DateFormat.MEDIUM, Locale.getDefault(), TimeZone
82 .getDefault());
83 }
84
85 /**
86 * Constructor.
87 */
88 public DatePicker(Date initialDate, int dateStyle) {
89 this(initialDate, dateStyle, Locale.getDefault(), TimeZone.getDefault());
90 }
91
92 /**
93 * Constructor.
94 */
95 public DatePicker(Date initialDate, DateFormat dateFormat) {
96 this(initialDate, dateFormat, Locale.getDefault(), TimeZone
97 .getDefault());
98 }
99
100 /**
101 * Constructor.
102 */
103 public DatePicker(Date initialDate, int dateStyle, Locale locale) {
104 this(initialDate, dateStyle, locale, TimeZone.getDefault());
105 }
106
107 /**
108 * Constructor.
109 */
110 public DatePicker(Date initialDate, DateFormat dateFormat, Locale locale) {
111 this(initialDate, dateFormat, locale, TimeZone.getDefault());
112 }
113
114 /**
115 * Constructor.
116 */
117 public DatePicker(Date initialDate, int dateStyle, Locale locale,
118 TimeZone zone) {
119 super(initialDate, CalendarPane.STYLE_CLASSIC, locale, zone);
120 checkDateStyle(dateStyle);
121 this.dateFormat = dateFormatFromStyle(dateStyle);
122 this.fieldEditable = true;
123 this.keepTime = true;
124 this.pickerStyle = PICKER_STYLE_FIELD_AND_BUTTON;
125 this.setStripTime(false);
126 this.dropdownFocusable = true;
127 updateUI();
128 }
129
130 /**
131 * Constructor.
132 */
133 public DatePicker(Date initialDate, DateFormat dateFormat, Locale locale,
134 TimeZone zone) {
135 super(initialDate, CalendarPane.STYLE_CLASSIC, locale, zone);
136 checkDateFormat(dateFormat);
137 this.dateFormat = dateFormat;
138 this.fieldEditable = true;
139 this.keepTime = true;
140 this.pickerStyle = PICKER_STYLE_FIELD_AND_BUTTON;
141 this.setStripTime(false);
142 this.dropdownFocusable = true;
143 updateUI();
144 }
145
146 public String getUIClassID() {
147 return uiClassID;
148 }
149
150 /**
151 * Returns the date format.
152 * <p>
153 *
154 * @return current date format
155 * @see #setDateFormat(DateFormat)
156 */
157 public DateFormat getDateFormat() {
158 return dateFormat;
159 }
160
161 /**
162 * Sets the date format constant defined by {@link DateFormat} and updates
163 * the control to reflect new date style.
164 * <p>
165 *
166 * @param dateFormat
167 * the date format constant to set
168 * @see #getDateFormat()
169 * @see DateFormat
170 */
171 public void setDateFormat(DateFormat dateFormat) {
172 checkDateFormat(dateFormat);
173 Object oldValue = this.dateFormat;
174 this.dateFormat = dateFormat;
175 firePropertyChange(PROPERTY_NAME_DATE_FORMAT, oldValue, dateFormat);
176 }
177
178 /**
179 * Is the edit field of the control editable by the user?
180 * <p>
181 * If not editable, the user can not type in the date and can only use
182 * calendar drop-down to select dates.
183 *
184 * @return <code>true</code> if the edit field is editable,
185 * <code>false</code> otherwise
186 *
187 * @see #setFieldEditable(boolean)
188 */
189 public boolean isFieldEditable() {
190 return fieldEditable;
191 }
192
193 /**
194 * Enables or disables editing of the edit field by the user.
195 * <p>
196 * If not editable, the user can not type in the date and can only use
197 * calendar drop-down to select dates.
198 *
199 * @param fieldEditable
200 * the editable value to set
201 *
202 * @see #isFieldEditable()
203 */
204 public void setFieldEditable(boolean fieldEditable) {
205 boolean old = this.fieldEditable;
206 this.fieldEditable = fieldEditable;
207 firePropertyChange(PROPERTY_NAME_FIELD_EDITABLE, old, fieldEditable);
208 }
209
210 /**
211 * Is the dropdown focusable?
212 * <p>
213 * If not focusable, the dropdown calendar will lack some keyboard input
214 * capabilities.
215 *
216 * @return <code>true</code> if the dropdown is focusable,
217 * <code>false</code> otherwise
218 *
219 * @see #setDropdownFocusable(boolean)
220 */
221 public boolean isDropdownFocusable() {
222 return dropdownFocusable;
223 }
224
225 /**
226 * Enables or disables focusability of the dropdown calendar.
227 * <p>
228 * If not focusable, the dropdown calendar will lack some keyboard input
229 * capabilities.
230 *
231 * @param popupFocusable
232 * the focusable value to set
233 *
234 * @see #isDropdownFocusable()
235 */
236 public void setDropdownFocusable(boolean popupFocusable) {
237 boolean old = this.dropdownFocusable;
238 this.dropdownFocusable = popupFocusable;
239 firePropertyChange(PROPERTY_NAME_DROPDOWN_FOCUSABLE, old,
240 popupFocusable);
241 }
242
243 /**
244 * Does UI try to preserve time components entered in the edit field?
245 * <p>
246 * If <code>true</code> and if the date format has some time fields
247 * (hours, minutes, seconds, fraction of second), the UI tries to respect
248 * the time fields' values entered by user as much as possible.
249 * <p>
250 * Note: to be able to receive time portion of the date, make sure
251 * {@link #isStripTime()} is <code>false</code> (the dafualt).
252 *
253 * @return <code>true</code> if the UI respects time fields,
254 * <code>false</code> otherwise
255 * @see #setKeepTime(boolean)
256 * @see #setStripTime(boolean)
257 * @see #isStripTime()
258 *
259 */
260 public boolean isKeepTime() {
261 return keepTime;
262 }
263
264 /**
265 * Determines if the UI should try to preserve time components entered in
266 * the edit field.
267 * <p>
268 * If <code>true</code> and if the date format has some time fields
269 * (hours, minutes, seconds, fraction of second), the UI tries to respect
270 * the time fields' values entered by user as much as possible.
271 * <p>
272 * Note: to be able to receive time portion of the date, make sure
273 * {@link #isStripTime()} is <code>false</code> (the dafualt).
274 *
275 * @param keepTime
276 * <code>true</code> to make the UI respects time fields,
277 * <code>false</code> otherwise
278 * @see #isKeepTime()
279 * @see #setStripTime(boolean)
280 * @see #isStripTime()
281 */
282 public void setKeepTime(boolean keepTime) {
283 boolean old = this.keepTime;
284 this.keepTime = keepTime;
285 firePropertyChange(PROPERTY_NAME_KEEP_TIME, old, keepTime);
286 }
287
288 /**
289 * Returns current visual style of the picker control.
290 * <p>
291 * NOTE: do not confuse with {@link #getStyle()}.
292 *
293 * @return current visual style constant.
294 */
295 public int getPickerStyle() {
296 return pickerStyle;
297 }
298
299 /**
300 * Sets the current visual style of the picker control.
301 * <p>
302 * The control is then updated to reflect the new style.
303 * <p>
304 * NOTE: do not confuse with {@link #getStyle()}.
305 *
306 * @param pickerStyle
307 * the style to set
308 * @see #PICKER_STYLE_BUTTON
309 * @see #PICKER_STYLE_FIELD_AND_BUTTON
310 */
311 public void setPickerStyle(int pickerStyle) {
312 pickerStyle = checkPickerStyle(pickerStyle);
313 int oldValue = this.pickerStyle;
314 this.pickerStyle = pickerStyle;
315 firePropertyChange(PROPERTY_NAME_PICKER_STYLE, oldValue, pickerStyle);
316 }
317
318 /**
319 * A shortucut method to switch picker style between
320 * {@link #PICKER_STYLE_FIELD_AND_BUTTON} and {@link #PICKER_STYLE_BUTTON}
321 *
322 * @param buttonOnly
323 * <code>true</code> to set {@link #PICKER_STYLE_BUTTON},
324 * <code>false</code> to set
325 * {@link #PICKER_STYLE_FIELD_AND_BUTTON}
326 */
327 public void showButtonOnly(boolean buttonOnly) {
328 if (buttonOnly)
329 setPickerStyle(PICKER_STYLE_BUTTON);
330 else
331 setPickerStyle(PICKER_STYLE_FIELD_AND_BUTTON);
332 }
333
334 /**
335 * Displays the calendar dropdown.
336 */
337 public void showPopup() {
338 ((DatePickerUI) getUI()).showPopup(true);
339 }
340
341 /**
342 * Hides the calendar dropdown without selecting a date.
343 */
344 public void hidePopup() {
345 ((DatePickerUI) getUI()).showPopup(false);
346 }
347
348 public boolean commitEdit() {
349 try {
350 ((DatePickerUI) getUI()).commit();
351 fireCommitEvent(true);
352 return true;
353 } catch (Exception e) {
354 return false;
355 }
356 }
357
358 public void revertEdit() {
359 ((DatePickerUI) getUI()).revert();
360 fireCommitEvent(false);
361 }
362
363 private void checkDateStyle(int style) {
364 if (style != DateFormat.SHORT && style != DateFormat.MEDIUM
365 && style != DateFormat.LONG)
366 throw new IllegalArgumentException("dateStyle: unrecognized style");
367 }
368
369 private int checkPickerStyle(int style) {
370 if (style == 0)
371 style = PICKER_STYLE_FIELD_AND_BUTTON;
372 if (style != PICKER_STYLE_FIELD_AND_BUTTON
373 && style != PICKER_STYLE_BUTTON)
374 throw new IllegalArgumentException(PROPERTY_NAME_PICKER_STYLE
375 + ": unrecognized style");
376 return style;
377 }
378
379 private void checkDateFormat(DateFormat dateFormat) {
380 if (dateFormat == null)
381 throw new IllegalArgumentException("dateFormat: null value");
382 }
383
384 private DateFormat dateFormatFromStyle(int dateStyle) {
385 DateFormat df = DateFormat.getDateInstance(dateStyle, this.getLocale());
386 df.setTimeZone(this.getZone());
387 return df;
388 }
389
390 }
0 package com.michaelbaranov.microba.calendar;
1
2 import java.beans.PropertyVetoException;
3 import java.util.Date;
4
5 import javax.swing.DefaultCellEditor;
6 import javax.swing.JCheckBox;
7 import javax.swing.table.TableCellEditor;
8 import javax.swing.tree.TreeCellEditor;
9
10 import com.michaelbaranov.microba.calendar.ui.DatePickerUI;
11
12 /**
13 * This class in a concrete implementation of {@link TableCellEditor} and
14 * {@link TreeCellEditor} interfaces. Uses {@link DatePicker} control as en
15 * editor. Subclass to extend functionality. *
16 * <p>
17 * Note: you probably will want to set the property of the {@link DatePicker}
18 * {@value DatePicker#PROPERTY_NAME_DROPDOWN_FOCUSABLE} to <code>false</code>
19 * before using it to construct {@link DatePickerCellEditor}.
20 *
21 * @see DefaultCellEditor
22 *
23 * @author Michael Baranov
24 *
25 */
26 public class DatePickerCellEditor extends DefaultCellEditor {
27
28 /**
29 * Constructor.
30 * <p>
31 * Note: you probably will want to set the property of the
32 * {@link DatePicker} {@value DatePicker#PROPERTY_NAME_DROPDOWN_FOCUSABLE}
33 * to <code>false</code> before using it to construct
34 * {@link DatePickerCellEditor}.
35 *
36 * @param datePicker
37 * the editor component
38 */
39 public DatePickerCellEditor(final DatePicker datePicker) {
40 // trick: supply a dummy JCheckBox
41 super(new JCheckBox());
42 // get back the dummy JCheckBox
43 JCheckBox checkBox = (JCheckBox) this.editorComponent;
44 // remove listeners installed by super()
45 checkBox.removeActionListener(this.delegate);
46 // replace editor component with own
47 this.editorComponent = datePicker;
48
49 // set simple look
50 ((DatePickerUI) datePicker.getUI()).setSimpeLook(true);
51
52 // replace delegate with own
53 this.delegate = new EditorDelegate() {
54 public void setValue(Object value) {
55 try {
56 ((DatePicker) editorComponent).setDate((Date) value);
57 } catch (PropertyVetoException e) {
58 }
59 }
60
61 public Object getCellEditorValue() {
62 return ((DatePicker) editorComponent).getDate();
63 }
64
65 public void cancelCellEditing() {
66 ((DatePicker) editorComponent).commitOrRevert();
67 super.cancelCellEditing();
68 }
69
70 public boolean stopCellEditing() {
71 ((DatePicker) editorComponent).commitOrRevert();
72 return super.stopCellEditing();
73 }
74
75 };
76 // install listeners
77 datePicker.addActionListener(delegate);
78 // do not set it to 1
79 setClickCountToStart(2);
80 }
81
82 }
0 package com.michaelbaranov.microba.calendar;
1
2 import java.io.IOException;
3 import java.util.Locale;
4 import java.util.Properties;
5
6 /**
7 * A very basic implementation of {@link CalendarResources}. Used by default by
8 * {@link CalendarPane} and {@link DatePicker} classes. The resources are loaded
9 * from 'DefaultCalendarResources.properties' file.
10 *
11 * @author Michael Baranov
12 *
13 */
14 public class DefaultCalendarResources implements CalendarResources {
15
16 private static final String RESOURCE_FILE = "DefaultCalendarResources.properties";
17
18 private static final String DEFAULT_LANGUAGE = "en";
19
20 private Properties strings = new Properties();
21
22 /**
23 * Constructor.
24 */
25 public DefaultCalendarResources() {
26 try {
27 strings.load(DefaultCalendarResources.class
28 .getResourceAsStream(RESOURCE_FILE));
29 } catch (IOException e) {
30 e.printStackTrace();
31 }
32 }
33
34 public String getResource(String key, Locale locale) {
35 String language = locale.getLanguage();
36 String word = (String) strings.get(language + "." + key);
37 if (word == null)
38 word = (String) strings.get(DEFAULT_LANGUAGE + "." + key);
39 return word;
40 }
41
42 }
0 en.key.none=none
1 en.key.today=today
2 de.key.none=kein
3 de.key.today=heute
4 fr.key.none=non
5 fr.key.today=aujourd'hui
6 pt.key.none=limpar
7 pt.key.today=hoje
8 ru.key.none=\u043D\u0435\u0442
9 ru.key.today=\u0441\u0435\u0433\u043E\u0434\u043D\u044F
10 it.key.none=nessuno
11 it.key.today=oggi
12 nl.key.none=geen
13 nl.key.today=vandaag
14 es.key.none=ninguna
15 es.key.today=hoy
16 pl.key.none=\u017Caden
17 pl.key.today=dzisiaj
18 by.key.none=\u043Di\u0447\u043E\u0433\u0430
19 by.key.today=\u0441\u0451\u043D\u043D\u044F
20 da.key.none=ingen
21 da.key.today=i dag
22 ro.key.none=sterge
23 ro.key.today=azi
24 sv.key.none=inget
25 sv.key.today=idag
26 sk.key.none=\u017eiadny
27 sk.key.today=dnes
28 cs.key.none=\u017e\u00e1dn\u00fd
29 cs.key.today=dnes
30 he.key.none=\u05E0\u05E7\u05D4
31 he.key.today=\u05D4\u05D9\u05D5\u05DD
32 tr.key.none=bug\u00FCn
33 tr.key.today=hi\u00E7biri
34 hu.key.none=ma
35 hu.key.today=semmi
0 package com.michaelbaranov.microba.calendar;
1
2 import java.util.Calendar;
3
4 import com.michaelbaranov.microba.common.Policy;
5
6 /**
7 * This interface is used by {@link CalendarPane} and {@link DatePicker} to
8 * provide means to define hollidays and optionally provide descriptions to
9 * them.
10 *
11 * @author Michael Baranov
12 *
13 */
14 public interface HolidayPolicy extends Policy {
15 /**
16 * This method is used to check if a date is a holliday. Holliday dates are
17 * displayed by contols in a special way.
18 *
19 * @param source
20 * a control calling this method
21 * @param date
22 * a date to check
23 * @return <code>true</code> if given <code>date</code> is a holliday
24 * <code>false</code> otherwise
25 */
26 public boolean isHolliday(Object source, Calendar date);
27
28 /**
29 * This method is used to check if a date is a weekend date. Implementation
30 * should only check day of week component of the date.
31 *
32 * @param source
33 * a control calling this method
34 * @param date
35 * a date to check
36 * @return <code>true</code> if given <code>date</code> is weekend date
37 * <code>false</code> otherwise
38 */
39 public boolean isWeekend(Object source, Calendar date);
40
41 /**
42 * This method is used to query a description for a holliday date. Note,
43 * that implementation may return localized results based on the locale
44 * passed with the date.
45 *
46 * @param source
47 * a control calling this method
48 * @param date
49 * a holliday date to get the description for
50 * @return a localized name (a description) for a holliday
51 */
52 public String getHollidayName(Object source, Calendar date);
53
54 }
0 package com.michaelbaranov.microba.calendar;
1
2 import java.util.Calendar;
3
4 import com.michaelbaranov.microba.common.Policy;
5
6 /**
7 * This interface is used by {@link CalendarPane} and {@link DatePicker} to
8 * provide means to restrict dates in a control.
9 *
10 * @author Michael Baranov
11 *
12 */
13 public interface VetoPolicy extends Policy {
14
15 /**
16 * This method is used to check if a date is restricted. Restricted dates
17 * can not be selected by users in a control.
18 *
19 * @param source
20 * a control calling this method
21 * @param date
22 * a date to check. Is never <code>null</code>
23 * @return <code>true</code> if given <code>date</code> is restricted
24 * <code>false</code> otherwise
25 */
26 public boolean isRestricted(Object source, Calendar date);
27
28 /**
29 * This method is used to check if no-date (<code>null</code> date) is
30 * restricted. Restricted dates can not be selected by users in a control.
31 *
32 * @param source
33 * a control calling this method
34 * @return <code>false</code> to allow no-date, <code>true</code>
35 * otherwise
36 */
37 public boolean isRestrictNull(Object source);
38
39 }
0 package com.michaelbaranov.microba.calendar.resource;
1
2 public class Resource {
3
4 }
0 package com.michaelbaranov.microba.calendar.ui;
1
2 import java.beans.PropertyVetoException;
3 import java.text.ParseException;
4
5 import javax.swing.plaf.ComponentUI;
6
7 public abstract class CalendarPaneUI extends ComponentUI {
8
9 public abstract void commit() throws PropertyVetoException, ParseException;
10
11 public abstract void revert();
12
13 public abstract void observeMonth(int year, int month);
14
15 }
0 package com.michaelbaranov.microba.calendar.ui;
1
2 public abstract class DatePickerUI extends CalendarPaneUI {
3
4 public abstract void showPopup(boolean visible);
5
6 public abstract void setSimpeLook(boolean b);
7
8 }
0 package com.michaelbaranov.microba.calendar.ui.basic;
1
2 import java.awt.GridBagConstraints;
3 import java.awt.GridBagLayout;
4 import java.awt.Insets;
5 import java.awt.event.ActionEvent;
6 import java.awt.event.ActionListener;
7 import java.beans.PropertyChangeEvent;
8 import java.beans.PropertyChangeListener;
9 import java.text.DateFormat;
10 import java.util.Calendar;
11 import java.util.Collection;
12 import java.util.Date;
13 import java.util.HashSet;
14 import java.util.Locale;
15 import java.util.Set;
16 import java.util.TimeZone;
17
18 import javax.swing.JButton;
19 import javax.swing.JPanel;
20
21 import com.michaelbaranov.microba.calendar.CalendarResources;
22 import com.michaelbaranov.microba.calendar.VetoPolicy;
23 import com.michaelbaranov.microba.common.PolicyEvent;
24 import com.michaelbaranov.microba.common.PolicyListener;
25
26 class AuxPanel extends JPanel implements PropertyChangeListener, PolicyListener {
27
28 public static final String PROPERTY_NAME_LOCALE = "locale";
29
30 public static final String PROPERTY_NAME_DATE = "date";
31
32 public static final String PROPERTY_NAME_ZONE = "zone";
33
34 public static final String PROPERTY_NAME_RESOURCES = "resources";
35
36 public static final String PROPERTY_NAME_VETO_MODEL = "vetoModel";
37
38 private Locale locale;
39
40 private TimeZone zone;
41
42 private JButton todayButton;
43
44 private JButton noneButton;
45
46 private DateFormat fullDateFormat;
47
48 private Date currentDate;
49
50 private Set focusableComponents = new HashSet();
51
52 private VetoPolicy vetoModel;
53
54 private boolean showTodayBtn;
55
56 private CalendarResources resources;
57
58 private boolean showNoneButton;
59
60 public AuxPanel(Locale locale, TimeZone zone, VetoPolicy vetoModel,
61 boolean showTodayBtn, boolean showNoneButton,
62 CalendarResources resources) {
63 this.locale = locale;
64 this.zone = zone;
65 this.vetoModel = vetoModel;
66 this.showTodayBtn = showTodayBtn;
67 this.showNoneButton = showNoneButton;
68 this.resources = resources;
69 if (vetoModel != null)
70 vetoModel.addVetoPolicyListener(this);
71
72 setLayout(new GridBagLayout());
73
74 todayButton = new JButton();
75 todayButton.setBorderPainted(false);
76 todayButton.setContentAreaFilled(false);
77 todayButton.setVisible(showTodayBtn);
78
79 noneButton = new JButton();
80 noneButton.setBorderPainted(false);
81 noneButton.setContentAreaFilled(false);
82 noneButton.setVisible(showNoneButton);
83
84 add(todayButton, new GridBagConstraints(0, 0, 1, 1, 1.0, 0.0,
85 GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0,
86 0, 0, 0), 0, 0));
87 add(noneButton, new GridBagConstraints(1, 0, 1, 1, 1.0, 0.0,
88 GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0,
89 0, 0, 0), 0, 0));
90
91 currentDate = new Date();
92 validateAgainstVeto();
93 createLocaleAndZoneSensitive();
94 reflectData();
95
96 todayButton.addActionListener(new ActionListener() {
97
98 public void actionPerformed(ActionEvent e) {
99 currentDate = new Date();
100 firePropertyChange(PROPERTY_NAME_DATE, null, currentDate);
101 }
102 });
103 noneButton.addActionListener(new ActionListener() {
104
105 public void actionPerformed(ActionEvent e) {
106 firePropertyChange(PROPERTY_NAME_DATE, null, null);
107 }
108 });
109
110 focusableComponents.add(todayButton);
111 this.addPropertyChangeListener(this);
112
113 // Timer timer = new Timer(true);
114 // timer.schedule(new TimerTask() {
115 //
116 // public void run() {
117 // currentDate = new Date();
118 // validateAgainstVeto();
119 // }
120 // }, 0, 60000);
121
122 }
123
124 public void propertyChange(PropertyChangeEvent evt) {
125 if (evt.getPropertyName().equals("focusable")) {
126 Boolean value = (Boolean) evt.getNewValue();
127 todayButton.setFocusable(value.booleanValue());
128 noneButton.setFocusable(value.booleanValue());
129 }
130 if (evt.getPropertyName().equals("enabled")) {
131 Boolean value = (Boolean) evt.getNewValue();
132 todayButton.setEnabled(value.booleanValue());
133 noneButton.setEnabled(value.booleanValue());
134 }
135 if (evt.getPropertyName().equals(PROPERTY_NAME_VETO_MODEL)) {
136 VetoPolicy oldValue = (VetoPolicy) evt.getOldValue();
137 VetoPolicy newValue = (VetoPolicy) evt.getOldValue();
138 if (oldValue != null)
139 oldValue.removeVetoPolicyListener(this);
140 if (newValue != null)
141 newValue.addVetoPolicyListener(this);
142 validateAgainstVeto();
143 }
144
145 }
146
147 private void createLocaleAndZoneSensitive() {
148 fullDateFormat = DateFormat.getDateInstance(DateFormat.MEDIUM, locale);
149 fullDateFormat.setTimeZone(zone);
150 }
151
152 private void reflectData() {
153 String today = resources.getResource(CalendarResources.KEY_TODAY,
154 locale);
155 String none = resources.getResource(CalendarResources.KEY_NONE, locale);
156 todayButton.setText(today + ": " + fullDateFormat.format(currentDate));
157 noneButton.setText(none);
158
159 }
160
161 public Locale getLocale() {
162 return locale;
163 }
164
165 public void setLocale(Locale locale) {
166 Locale old = this.locale;
167 this.locale = locale;
168 firePropertyChange(PROPERTY_NAME_LOCALE, old, locale);
169 createLocaleAndZoneSensitive();
170 reflectData();
171 }
172
173 public Collection getFocusableComponents() {
174 return focusableComponents;
175 }
176
177 public TimeZone getZone() {
178 return zone;
179 }
180
181 public void setZone(TimeZone zone) {
182 this.zone = zone;
183 createLocaleAndZoneSensitive();
184 reflectData();
185 }
186
187 public Date getDate() {
188 return currentDate;
189 }
190
191 public VetoPolicy getVetoModel() {
192 return vetoModel;
193 }
194
195 public void setVetoModel(VetoPolicy vetoModel) {
196 VetoPolicy old = this.vetoModel;
197 this.vetoModel = vetoModel;
198 firePropertyChange(PROPERTY_NAME_VETO_MODEL, old, vetoModel);
199 }
200
201 public void policyChanged(PolicyEvent event) {
202 validateAgainstVeto();
203 }
204
205 private void validateAgainstVeto() {
206 Calendar c = Calendar.getInstance(zone, locale);
207 c.setTime(currentDate);
208 if (vetoModel != null) {
209 todayButton.setEnabled(!vetoModel.isRestricted(this, c));
210 noneButton.setEnabled(!vetoModel.isRestrictNull(this));
211 } else {
212 todayButton.setEnabled(this.isEnabled());
213 noneButton.setEnabled(this.isEnabled());
214 }
215
216 }
217
218 public void setShowTodayBtn(boolean value) {
219 showTodayBtn = value;
220 todayButton.setVisible(showTodayBtn);
221 }
222
223 public void setResources(CalendarResources resources) {
224 CalendarResources old = this.resources;
225 this.resources = resources;
226 firePropertyChange(PROPERTY_NAME_RESOURCES, old, resources);
227 reflectData();
228 }
229
230 public void setShowNoneButton(boolean value) {
231 showNoneButton = value;
232 noneButton.setVisible(showNoneButton);
233 }
234
235 }
0 package com.michaelbaranov.microba.calendar.ui.basic;
1
2 import java.awt.GridBagConstraints;
3 import java.awt.GridBagLayout;
4 import java.awt.Insets;
5 import java.awt.event.ActionEvent;
6 import java.awt.event.FocusEvent;
7 import java.awt.event.FocusListener;
8 import java.awt.event.KeyEvent;
9 import java.beans.PropertyChangeEvent;
10 import java.beans.PropertyChangeListener;
11 import java.beans.PropertyVetoException;
12 import java.util.Date;
13 import java.util.HashSet;
14 import java.util.Locale;
15 import java.util.Set;
16 import java.util.TimeZone;
17
18 import javax.swing.AbstractAction;
19 import javax.swing.ActionMap;
20 import javax.swing.InputMap;
21 import javax.swing.JComponent;
22 import javax.swing.KeyStroke;
23 import javax.swing.SwingUtilities;
24 import javax.swing.plaf.ComponentUI;
25
26 import com.michaelbaranov.microba.calendar.CalendarPane;
27 import com.michaelbaranov.microba.calendar.DatePicker;
28 import com.michaelbaranov.microba.calendar.HolidayPolicy;
29 import com.michaelbaranov.microba.calendar.VetoPolicy;
30 import com.michaelbaranov.microba.calendar.ui.CalendarPaneUI;
31
32 public class BasicCalendarPaneUI extends CalendarPaneUI implements
33 PropertyChangeListener, FocusListener {
34
35 protected static final String ESCAPE_KEY = "##CalendarPaneUI.escape##";
36
37 protected static final String ENTER_KEY = "##CalendarPaneUI.enter##";
38
39 protected CalendarPane peer;
40
41 protected ClassicCalendarPanel classicPanel;
42
43 protected ModernCalendarPanel modernPanel;
44
45 protected AuxPanel auxPanel;
46
47 protected CalendarGridPanel gridPanel;
48
49 protected CalendarNumberOfWeekPanel numberOfWeekPanel;
50
51 protected CalendarHeader headerPanel;
52
53 protected Set focusableComponents = new HashSet();
54
55 protected ComponentListener componentListener;
56
57 public static ComponentUI createUI(JComponent c) {
58 return new BasicCalendarPaneUI();
59 }
60
61 public void installUI(JComponent component) {
62 peer = (CalendarPane) component;
63 createNestedComponents();
64 addNestedComponents();
65 installListeners();
66 installKeyboardActions();
67 }
68
69 public void uninstallUI(JComponent component) {
70 uninstallKeyboardActions();
71 uninstallListeners();
72 removeNestedComponents();
73 destroyNestedComponents();
74 peer = null;
75 }
76
77 protected void uninstallKeyboardActions() {
78 InputMap input = peer
79 .getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
80 ActionMap action = peer.getActionMap();
81
82 input.remove(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0));
83 input.remove(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0));
84
85 action.remove(ENTER_KEY);
86 action.remove(ESCAPE_KEY);
87
88 }
89
90 protected void installKeyboardActions() {
91 InputMap input = peer
92 .getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
93 ActionMap action = peer.getActionMap();
94
95 input.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), ENTER_KEY);
96 input.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), ESCAPE_KEY);
97 input.put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0), "pgupkey");
98 input
99 .put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0),
100 "pgdownkey");
101
102 action.put(ENTER_KEY, new AbstractAction() {
103
104 public void actionPerformed(ActionEvent e) {
105 peer.commitEdit();
106 }
107 });
108 action.put(ESCAPE_KEY, new AbstractAction() {
109
110 public void actionPerformed(ActionEvent e) {
111 peer.revertEdit();
112 }
113 });
114 action.put("pgupkey", new AbstractAction() {
115
116 public void actionPerformed(ActionEvent e) {
117 classicPanel.addMonth(1);
118 }
119 });
120 action.put("pgdownkey", new AbstractAction() {
121
122 public void actionPerformed(ActionEvent e) {
123 classicPanel.addMonth(-1);
124 }
125 });
126 }
127
128 protected void uninstallListeners() {
129 peer.removePropertyChangeListener(this);
130 peer.removeFocusListener(this);
131 }
132
133 protected void installListeners() {
134 peer.addPropertyChangeListener(this);
135 peer.addFocusListener(this);
136 }
137
138 protected void createNestedComponents() {
139 Date baseDate = peer.getDate() == null ? new Date() : peer.getDate();
140
141 classicPanel = new ClassicCalendarPanel(baseDate, peer.getLocale(),
142 peer.getZone());
143 modernPanel = new ModernCalendarPanel(baseDate, peer.getLocale(), peer
144 .getZone());
145 headerPanel = new CalendarHeader(peer, baseDate, peer.getLocale(), peer
146 .getZone(), peer.getHolidayPolicy());
147
148 auxPanel = new AuxPanel(peer.getLocale(), peer.getZone(), peer
149 .getVetoPolicy(), peer.isShowTodayButton(), peer
150 .isShowNoneButton(), peer.getResources());
151
152 gridPanel = new CalendarGridPanel(peer, peer.getDate(), peer
153 .getLocale(), peer.getZone(), peer.getVetoPolicy(), peer
154 .getHolidayPolicy());
155
156 numberOfWeekPanel = new CalendarNumberOfWeekPanel(peer.getDate(), peer
157 .getLocale(), peer.getZone());
158
159 focusableComponents.addAll(classicPanel.getFocusableComponents());
160 focusableComponents.addAll(modernPanel.getFocusableComponents());
161 focusableComponents.addAll(auxPanel.getFocusableComponents());
162 focusableComponents.addAll(gridPanel.getFocusableComponents());
163 focusableComponents.addAll(auxPanel.getFocusableComponents());
164
165 componentListener = new ComponentListener();
166 for (int i = 0; i < focusableComponents.size(); i++)
167 ((JComponent) focusableComponents.toArray()[i])
168 .addFocusListener(componentListener);
169
170 gridPanel.addPropertyChangeListener(componentListener);
171 modernPanel.addPropertyChangeListener(componentListener);
172 classicPanel.addPropertyChangeListener(componentListener);
173 auxPanel.addPropertyChangeListener(componentListener);
174
175 classicPanel.setEnabled(peer.isEnabled());
176 modernPanel.setEnabled(peer.isEnabled());
177 headerPanel.setEnabled(peer.isEnabled());
178 auxPanel.setEnabled(peer.isEnabled());
179 numberOfWeekPanel.setEnabled(peer.isEnabled());
180 gridPanel.setEnabled(peer.isEnabled());
181
182 }
183
184 protected void destroyNestedComponents() {
185 gridPanel.removePropertyChangeListener(componentListener);
186 modernPanel.removePropertyChangeListener(componentListener);
187 classicPanel.removePropertyChangeListener(componentListener);
188 auxPanel.removePropertyChangeListener(componentListener);
189 componentListener = null;
190
191 for (int i = 0; i < focusableComponents.size(); i++)
192 ((JComponent) focusableComponents.toArray()[i])
193 .removeFocusListener(componentListener);
194 focusableComponents.clear();
195
196 classicPanel = null;
197 modernPanel = null;
198 headerPanel = null;
199 auxPanel = null;
200 gridPanel = null;
201 numberOfWeekPanel = null;
202
203 }
204
205 protected void addNestedComponents() {
206
207 peer.removeAll();
208 peer.setLayout(new GridBagLayout());
209 if ((peer.getStyle() & CalendarPane.STYLE_CLASSIC) > 0) {
210 peer.add(classicPanel, new GridBagConstraints(0, 0, 2, 1, 1, 0,
211 GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
212 new Insets(0, 0, 0, 0), 0, 0));
213 } else {
214 peer.add(modernPanel, new GridBagConstraints(0, 0, 2, 1, 1, 0,
215 GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
216 new Insets(0, 0, 0, 0), 0, 0));
217 }
218 peer.add(headerPanel, new GridBagConstraints(1, 1, 1, 1, 1, 0,
219 GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
220 new Insets(0, 0, 0, 0), 0, 0));
221 if (peer.isShowNumberOfWeek()) {
222 peer.add(numberOfWeekPanel, new GridBagConstraints(0, 2, 1, 1, 0,
223 1, GridBagConstraints.CENTER, GridBagConstraints.VERTICAL,
224 new Insets(0, 0, 0, 0), 0, 0));
225 }
226 peer.add(gridPanel, new GridBagConstraints(1, 2, 1, 1, 1, 1,
227 GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(
228 0, 0, 0, 0), 0, 0));
229 if (peer.isShowTodayButton()) {
230 peer.add(auxPanel, new GridBagConstraints(0, 3, 2, 1, 1, 0,
231 GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
232 new Insets(0, 0, 0, 0), 0, 0));
233 }
234 if (peer.isShowNumberOfWeek()) {
235 // TODO:
236 }
237 peer.revalidate();
238 peer.repaint();
239
240 }
241
242 protected void removeNestedComponents() {
243 peer.removeAll();
244 }
245
246 protected void widgetDateChanged(Date date) {
247 Date baseDate = date == null ? new Date() : date;
248
249 headerPanel.setDate(baseDate);
250 classicPanel.setDate(baseDate);
251 modernPanel.setDate(baseDate);
252
253 gridPanel.setBaseDate(baseDate);
254 gridPanel.setDate(date);
255 numberOfWeekPanel.setBaseDate(baseDate);
256 }
257
258 protected void widgetLocaleChanged(Locale newValue) {
259 classicPanel.setLocale(newValue);
260 modernPanel.setLocale(newValue);
261 gridPanel.setLocale(newValue);
262 headerPanel.setLocale(newValue);
263 auxPanel.setLocale(newValue);
264 numberOfWeekPanel.setLocale(newValue);
265 }
266
267 protected void widgetZoneChanged(TimeZone zone) {
268 classicPanel.setZone(zone);
269 modernPanel.setZone(zone);
270 gridPanel.setZone(zone);
271 headerPanel.setZone(zone);
272 auxPanel.setZone(zone);
273 numberOfWeekPanel.setZone(zone);
274 }
275
276 protected void widgetResourceChanged() {
277 auxPanel.setResources(peer.getResources());
278 }
279
280 public void commit() throws PropertyVetoException {
281 peer.setDate(gridPanel.getDateToCommit());
282 }
283
284 public void revert() {
285 widgetDateChanged(peer.getDate());
286 }
287
288 public void focusGained(FocusEvent e) {
289 gridPanel.requestFocus(true);
290 }
291
292 public void focusLost(FocusEvent e) {
293 }
294
295 public void propertyChange(PropertyChangeEvent evt) {
296 if (evt.getPropertyName().equals(CalendarPane.PROPERTY_NAME_DATE)) {
297 widgetDateChanged((Date) evt.getNewValue());
298 } else if (evt.getPropertyName().equals(
299 CalendarPane.PROPERTY_NAME_LOCALE)) {
300 widgetLocaleChanged((Locale) evt.getNewValue());
301 } else if (evt.getPropertyName()
302 .equals(CalendarPane.PROPERTY_NAME_ZONE)) {
303 widgetZoneChanged((TimeZone) evt.getNewValue());
304 } else if (evt.getPropertyName().equals(
305 CalendarPane.PROPERTY_NAME_VETO_POLICY)) {
306 gridPanel.setVetoPolicy((VetoPolicy) evt.getNewValue());
307 auxPanel.setVetoModel((VetoPolicy) evt.getNewValue());
308 } else if (evt.getPropertyName().equals(
309 CalendarPane.PROPERTY_NAME_HOLIDAY_POLICY)) {
310 gridPanel.setHolidayPolicy((HolidayPolicy) evt.getNewValue());
311 headerPanel.setHolidayPolicy((HolidayPolicy) evt.getNewValue());
312 } else if (evt.getPropertyName().equals("enabled")) {
313 boolean value = ((Boolean) evt.getNewValue()).booleanValue();
314 classicPanel.setEnabled(value);
315 modernPanel.setEnabled(value);
316 headerPanel.setEnabled(value);
317 auxPanel.setEnabled(value);
318 numberOfWeekPanel.setEnabled(value);
319 gridPanel.setEnabled(value);
320 } else if (evt.getPropertyName().equals(
321 CalendarPane.PROPERTY_NAME_STYLE)) {
322 addNestedComponents();
323 } else if (evt.getPropertyName().equals(
324 CalendarPane.PROPERTY_NAME_SHOW_TODAY_BTN)) {
325 Boolean value = (Boolean) evt.getNewValue();
326 auxPanel.setShowTodayBtn(value.booleanValue());
327 } else if (evt.getPropertyName().equals(
328 DatePicker.PROPERTY_NAME_SHOW_NONE_BTN)) {
329 boolean value = ((Boolean) evt.getNewValue()).booleanValue();
330 auxPanel.setShowNoneButton(value);
331 } else if (evt.getPropertyName().equals(
332 DatePicker.PROPERTY_NAME_SHOW_NUMBER_WEEK)) {
333 addNestedComponents();
334 } else if (evt.getPropertyName().equals("focusable")) {
335 Boolean value = (Boolean) evt.getNewValue();
336 classicPanel.setFocusable(value.booleanValue());
337 modernPanel.setFocusable(value.booleanValue());
338 gridPanel.setFocusable(value.booleanValue());
339 auxPanel.setFocusable(value.booleanValue());
340 } else if (evt.getPropertyName().equals(
341 CalendarPane.PROPERTY_NAME_RESOURCES)) {
342 widgetResourceChanged();
343 } else if (evt.getPropertyName().equals("enabled"/*
344 * CalendarPane.PROPERTY_NAME_ENABLED
345 */)) {
346 Boolean value = (Boolean) evt.getNewValue();
347 classicPanel.setEnabled(value.booleanValue());
348 modernPanel.setEnabled(value.booleanValue());
349 gridPanel.setEnabled(value.booleanValue());
350 auxPanel.setEnabled(value.booleanValue());
351 }
352
353 }
354
355 protected class ComponentListener implements FocusListener,
356 PropertyChangeListener {
357 public void focusGained(FocusEvent e) {
358 }
359
360 public void focusLost(FocusEvent e) {
361 boolean isFocusableComponent = focusableComponents.contains(e
362 .getSource());
363 boolean isNonEmptyOpposite = e.getOppositeComponent() != null;
364 if (isFocusableComponent
365 && isNonEmptyOpposite
366 && !SwingUtilities.isDescendingFrom(e
367 .getOppositeComponent(), peer)) {
368 peer.commitOrRevert();
369 }
370 }
371
372 public void propertyChange(PropertyChangeEvent evt) {
373 if (evt.getSource() == gridPanel
374 && evt.getPropertyName().equals(
375 CalendarGridPanel.PROPERTY_NAME_DATE)) {
376 Date newValue = (Date) evt.getNewValue();
377 try {
378 peer.setDate(newValue);
379 } catch (PropertyVetoException e) {
380 // Ignore. Just can not happen, beacause CalendarGridPanel
381 // already checked the date against current peer's
382 // vetoPolicy.
383 }
384 }
385 if (evt.getSource() == gridPanel
386 && evt
387 .getPropertyName()
388 .equals(
389 CalendarGridPanel.PROPERTY_NAME_NOTIFY_SELECTED_DATE_CLICKED)) {
390 peer.fireActionEvent();
391 }
392 if (evt.getSource() == gridPanel
393 && evt.getPropertyName().equals(
394 CalendarGridPanel.PROPERTY_NAME_BASE_DATE)) {
395 Date newValue = (Date) evt.getNewValue();
396 modernPanel.setDate(newValue);
397 classicPanel.setDate(newValue);
398 }
399 if (evt.getSource() == modernPanel
400 && evt.getPropertyName().equals(
401 ModernCalendarPanel.PROPERTY_NAME_DATE)) {
402 Date newValue = (Date) evt.getNewValue();
403
404 gridPanel.setBaseDate(newValue);
405 classicPanel.setDate(newValue);
406 numberOfWeekPanel.setBaseDate(newValue);
407
408 }
409 if (evt.getSource() == classicPanel
410 && evt.getPropertyName().equals(
411 ModernCalendarPanel.PROPERTY_NAME_DATE)) {
412 Date newValue = (Date) evt.getNewValue();
413
414 gridPanel.setBaseDate(newValue);
415 modernPanel.setDate(newValue);
416 numberOfWeekPanel.setBaseDate(newValue);
417
418 }
419 if (evt.getSource() == auxPanel
420 && evt.getPropertyName()
421 .equals(AuxPanel.PROPERTY_NAME_DATE)) {
422 Date date = (Date) evt.getNewValue();
423
424 gridPanel.setDate(date);
425 peer.commitEdit();
426 }
427
428 }
429 }
430
431 public void observeMonth(int year, int month) {
432 modernPanel.goToMonth(year, month);
433 }
434
435 }
0 package com.michaelbaranov.microba.calendar.ui.basic;
1
2 import java.awt.BorderLayout;
3 import java.awt.Insets;
4 import java.awt.event.ActionEvent;
5 import java.awt.event.ActionListener;
6 import java.awt.event.InputEvent;
7 import java.awt.event.KeyEvent;
8 import java.beans.PropertyChangeEvent;
9 import java.beans.PropertyChangeListener;
10 import java.beans.PropertyVetoException;
11 import java.text.ParseException;
12 import java.util.Calendar;
13 import java.util.Date;
14 import java.util.TimeZone;
15
16 import javax.swing.AbstractAction;
17 import javax.swing.BorderFactory;
18 import javax.swing.ImageIcon;
19 import javax.swing.InputMap;
20 import javax.swing.JButton;
21 import javax.swing.JComponent;
22 import javax.swing.JFormattedTextField;
23 import javax.swing.JPopupMenu;
24 import javax.swing.JTextField;
25 import javax.swing.KeyStroke;
26 import javax.swing.JFormattedTextField.AbstractFormatter;
27 import javax.swing.plaf.ComponentUI;
28 import javax.swing.text.DateFormatter;
29 import javax.swing.text.DefaultFormatterFactory;
30
31 import com.michaelbaranov.microba.calendar.CalendarPane;
32 import com.michaelbaranov.microba.calendar.CalendarResources;
33 import com.michaelbaranov.microba.calendar.DatePicker;
34 import com.michaelbaranov.microba.calendar.HolidayPolicy;
35 import com.michaelbaranov.microba.calendar.VetoPolicy;
36 import com.michaelbaranov.microba.calendar.resource.Resource;
37 import com.michaelbaranov.microba.calendar.ui.CalendarPaneUI;
38 import com.michaelbaranov.microba.calendar.ui.DatePickerUI;
39 import com.michaelbaranov.microba.common.CommitEvent;
40 import com.michaelbaranov.microba.common.CommitListener;
41
42 public class BasicDatePickerUI extends DatePickerUI implements
43 PropertyChangeListener {
44
45 protected static final String POPUP_KEY = "##BasicVetoDatePickerUI.popup##";
46
47 protected DatePicker peer;
48
49 protected CalendarPane calendarPane;
50
51 protected JButton button;
52
53 protected JPopupMenu popup;
54
55 protected JFormattedTextField field;
56
57 protected ComponentListener componentListener;
58
59 public static ComponentUI createUI(JComponent c) {
60 return new BasicDatePickerUI();
61 }
62
63 public void installUI(JComponent c) {
64 peer = (DatePicker) c;
65 installComponents();
66 istallListeners();
67 installKeyboardActions();
68 }
69
70 public void uninstallUI(JComponent c) {
71 uninstallKeyboardActions();
72 uninstallListeners();
73 uninstallComponents();
74 peer = null;
75 }
76
77 protected void installKeyboardActions() {
78 InputMap input = peer
79 .getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
80 input.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.ALT_MASK),
81 POPUP_KEY);
82 input.put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0), POPUP_KEY);
83
84 peer.getActionMap().put(POPUP_KEY, new AbstractAction() {
85
86 public void actionPerformed(ActionEvent e) {
87 showPopup(true);
88 }
89 });
90
91 }
92
93 protected void uninstallKeyboardActions() {
94 InputMap input = peer
95 .getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
96 input
97 .remove(KeyStroke.getKeyStroke(KeyEvent.VK_C,
98 InputEvent.ALT_MASK));
99 input.remove(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0));
100
101 peer.getActionMap().remove(POPUP_KEY);
102 }
103
104 protected void istallListeners() {
105 peer.addPropertyChangeListener(this);
106 }
107
108 protected void uninstallListeners() {
109 peer.removePropertyChangeListener(this);
110 }
111
112 protected void uninstallComponents() {
113 button.removeActionListener(componentListener);
114 field.removePropertyChangeListener(componentListener);
115
116 calendarPane.removePropertyChangeListener(componentListener);
117 calendarPane.removeCommitListener(componentListener);
118 calendarPane.removeActionListener(componentListener);
119
120 peer.remove(field);
121 peer.remove(button);
122 popup = null;
123 calendarPane = null;
124 button = null;
125 field = null;
126
127 }
128
129 protected void installComponents() {
130 field = new JFormattedTextField(createFormatterFactory());
131 field.setValue(peer.getDate());
132 field.setFocusLostBehavior(peer.getFocusLostBehavior());
133 field.setEditable(peer.isFieldEditable());
134 field.setToolTipText(peer.getToolTipText());
135 // button
136 button = new JButton();
137 button.setFocusable(false);
138 button.setMargin(new Insets(0, 0, 0, 0));
139 button.setToolTipText(peer.getToolTipText());
140
141 setSimpeLook(false);
142 // calendar
143 calendarPane = new CalendarPane(peer.getStyle());
144 calendarPane.setShowTodayButton(peer.isShowTodayButton());
145 calendarPane.setFocusLostBehavior(JFormattedTextField.REVERT);
146 calendarPane.setFocusCycleRoot(true);
147 calendarPane.setBorder(BorderFactory.createEmptyBorder(1, 3, 0, 3));
148 calendarPane.setStripTime(false);
149 calendarPane.setLocale(peer.getLocale());
150 calendarPane.setZone(peer.getZone());
151 calendarPane.setFocusable(peer.isDropdownFocusable());
152 calendarPane.setColorOverrideMap(peer.getColorOverrideMap());
153 // popup
154 popup = new JPopupMenu();
155 popup.setLayout(new BorderLayout());
156 popup.add(calendarPane, BorderLayout.CENTER);
157 popup.setLightWeightPopupEnabled(true);
158 // add
159 peer.setLayout(new BorderLayout());
160
161 switch (peer.getPickerStyle()) {
162 case DatePicker.PICKER_STYLE_FIELD_AND_BUTTON:
163 peer.add(field, BorderLayout.CENTER);
164 peer.add(button, BorderLayout.EAST);
165 break;
166 case DatePicker.PICKER_STYLE_BUTTON:
167 peer.add(button, BorderLayout.EAST);
168 break;
169 }
170
171 peer.revalidate();
172 peer.repaint();
173
174 componentListener = new ComponentListener();
175
176 button.addActionListener(componentListener);
177 field.addPropertyChangeListener(componentListener);
178
179 calendarPane.addPropertyChangeListener(componentListener);
180 calendarPane.addCommitListener(componentListener);
181 calendarPane.addActionListener(componentListener);
182
183 peerDateChanged(peer.getDate());
184 }
185
186 public void setSimpeLook(boolean b) {
187 if (b) {
188 field.setBorder(BorderFactory.createEmptyBorder());
189 button.setText("...");
190 button.setIcon(null);
191 } else {
192 field.setBorder(new JTextField().getBorder());
193 button.setText("");
194 button.setIcon(new ImageIcon(Resource.class
195 .getResource("picker-16.png")));
196 }
197
198 }
199
200 public void showPopup(boolean visible) {
201 if (visible) {
202
203 // try to apply date to calendar pane popup, but not cause commit
204 if (peer.isKeepTime())
205 try {
206 AbstractFormatter formatter = field.getFormatter();
207 Date value = (Date) formatter
208 .stringToValue(field.getText());
209 calendarPane
210 .removePropertyChangeListener(componentListener);
211 calendarPane.setDate(value);
212 calendarPane.addPropertyChangeListener(componentListener);
213
214 } catch (ParseException e) {
215 // ignore
216 } catch (PropertyVetoException e) {
217 // can not happen
218 }
219
220 popup.show(peer, 0, peer.getHeight());
221 calendarPane.requestFocus(false);
222 } else {
223 popup.setVisible(false);
224 }
225 }
226
227 public void propertyChange(PropertyChangeEvent evt) {
228 if (JComponent.TOOL_TIP_TEXT_KEY.equals(evt.getPropertyName())) {
229 field.setToolTipText((String) evt.getNewValue());
230 button.setToolTipText((String) evt.getNewValue());
231 } else if (evt.getPropertyName().equals(DatePicker.PROPERTY_NAME_DATE)) {
232 Date newValue = (Date) evt.getNewValue();
233 peerDateChanged(newValue);
234 } else if (evt.getPropertyName().equals(
235 DatePicker.PROPERTY_NAME_FIELD_EDITABLE)) {
236 field.setEditable(peer.isFieldEditable());
237 } else if (evt.getPropertyName().equals(
238 DatePicker.PROPERTY_NAME_FOCUS_LOST_BEHAVIOR)) {
239 field.setFocusLostBehavior(peer.getFocusLostBehavior());
240 } else if (evt.getPropertyName()
241 .equals(DatePicker.PROPERTY_NAME_LOCALE)) {
242 field.setFormatterFactory(createFormatterFactory());
243 calendarPane.setLocale(peer.getLocale());
244 } else if (evt.getPropertyName().equals(
245 DatePicker.PROPERTY_NAME_DATE_FORMAT)) {
246 field.setFormatterFactory(createFormatterFactory());
247 } else if (evt.getPropertyName().equals(DatePicker.PROPERTY_NAME_ZONE)) {
248 field.setFormatterFactory(createFormatterFactory());
249 calendarPane.setZone((TimeZone) evt.getNewValue());
250 } else if (evt.getPropertyName().equals(
251 DatePicker.PROPERTY_NAME_SHOW_TODAY_BTN)) {
252 boolean value = ((Boolean) evt.getNewValue()).booleanValue();
253 calendarPane.setShowTodayButton(value);
254 } else if (evt.getPropertyName().equals(
255 DatePicker.PROPERTY_NAME_SHOW_NONE_BTN)) {
256 boolean value = ((Boolean) evt.getNewValue()).booleanValue();
257 calendarPane.setShowNoneButton(value);
258 } else if (evt.getPropertyName().equals(
259 DatePicker.PROPERTY_NAME_SHOW_NUMBER_WEEK)) {
260 boolean value = ((Boolean) evt.getNewValue()).booleanValue();
261 calendarPane.setShowNumberOfWeek(value);
262 } else if (evt.getPropertyName().equals(DatePicker.PROPERTY_NAME_STYLE)) {
263 int value = ((Integer) evt.getNewValue()).intValue();
264 calendarPane.setStyle(value);
265 } else if (evt.getPropertyName().equals(
266 DatePicker.PROPERTY_NAME_VETO_POLICY)) {
267 calendarPane.setVetoPolicy((VetoPolicy) evt.getNewValue());
268 } else if (evt.getPropertyName().equals(
269 DatePicker.PROPERTY_NAME_HOLIDAY_POLICY)) {
270 calendarPane.setHolidayPolicy((HolidayPolicy) evt.getNewValue());
271 } else if (evt.getPropertyName().equals("focusable")) {
272 boolean value = ((Boolean) evt.getNewValue()).booleanValue();
273 field.setFocusable(value);
274 } else if (evt.getPropertyName().equals(
275 DatePicker.PROPERTY_NAME_RESOURCES)) {
276 CalendarResources resources = (CalendarResources) evt.getNewValue();
277 calendarPane.setResources(resources);
278 } else if (evt.getPropertyName().equals("enabled"/*
279 * DatePicker.PROPERTY_NAME_ENABLED
280 */)) {
281 boolean value = ((Boolean) evt.getNewValue()).booleanValue();
282 field.setEnabled(value);
283 button.setEnabled(value);
284 } else if (evt.getPropertyName().equals(
285 DatePicker.PROPERTY_NAME_PICKER_STYLE)) {
286 peer.updateUI();
287 } else if (evt.getPropertyName().equals(
288 DatePicker.PROPERTY_NAME_DROPDOWN_FOCUSABLE)) {
289 calendarPane.setFocusable(peer.isDropdownFocusable());
290 }
291 }
292
293 private void peerDateChanged(Date newValue) {
294 try {
295 calendarPane.removePropertyChangeListener(componentListener);
296 calendarPane.setDate(newValue);
297 calendarPane.addPropertyChangeListener(componentListener);
298 } catch (PropertyVetoException e) {
299 // Ignore. CalendarPane has no VetoModel here.
300 }
301 field.removePropertyChangeListener(componentListener);
302 field.setValue(newValue);
303 field.addPropertyChangeListener(componentListener);
304 }
305
306 private DefaultFormatterFactory createFormatterFactory() {
307 return new DefaultFormatterFactory(new DateFormatter(peer
308 .getDateFormat()));
309 }
310
311 protected class ComponentListener implements ActionListener,
312 PropertyChangeListener, CommitListener {
313 public void actionPerformed(ActionEvent e) {
314
315 if (e.getSource() != calendarPane)
316 showPopup(true);
317 else
318 showPopup(false);
319
320 }
321
322 public void propertyChange(PropertyChangeEvent evt) {
323 if (evt.getSource() == calendarPane) {
324 if (CalendarPane.PROPERTY_NAME_DATE.equals(evt
325 .getPropertyName())) {
326 showPopup(false);
327
328 Date fieldValue = null;
329 try {
330 AbstractFormatter formatter = field.getFormatter();
331 fieldValue = (Date) formatter.stringToValue(field
332 .getText());
333
334 } catch (ParseException e) {
335 fieldValue = (Date) field.getValue();
336 }
337
338 if (fieldValue != null || evt.getNewValue() != null) {
339
340 if (peer.isKeepTime() && fieldValue != null
341 && evt.getNewValue() != null) {
342
343 Calendar fieldCal = Calendar.getInstance(peer
344 .getZone(), peer.getLocale());
345 fieldCal.setTime(fieldValue);
346
347 Calendar valueCal = Calendar.getInstance(peer
348 .getZone(), peer.getLocale());
349 valueCal.setTime((Date) evt.getNewValue());
350
351 // era
352 fieldCal.set(Calendar.ERA, valueCal
353 .get(Calendar.ERA));
354 // year
355 fieldCal.set(Calendar.YEAR, valueCal
356 .get(Calendar.YEAR));
357 // month
358 fieldCal.set(Calendar.MONTH, valueCal
359 .get(Calendar.MONTH));
360 // date
361 fieldCal.set(Calendar.DAY_OF_MONTH, valueCal
362 .get(Calendar.DAY_OF_MONTH));
363 field.setValue(fieldCal.getTime());
364 } else
365 field.setValue((Date) evt.getNewValue());
366
367 }
368 }
369 }
370 if (evt.getSource() == field) {
371 if ("value".equals(evt.getPropertyName())) {
372 Date value = (Date) field.getValue();
373
374 try {
375 peer.setDate(value);
376 } catch (PropertyVetoException e) {
377 field.setValue(peer.getDate());
378 }
379 }
380 }
381
382 }
383
384 public void commit(CommitEvent action) {
385 showPopup(false);
386 if (field.getValue() != null || calendarPane.getDate() != null)
387 field.setValue(calendarPane.getDate());
388 }
389
390 public void revert(CommitEvent action) {
391 showPopup(false);
392
393 }
394 }
395
396 public void commit() throws PropertyVetoException, ParseException {
397 field.commitEdit();
398 }
399
400 public void revert() {
401 peerDateChanged(peer.getDate());
402 }
403
404 public void observeMonth(int year, int month) {
405 CalendarPaneUI ui = (CalendarPaneUI) calendarPane.getUI();
406 ui.observeMonth(year, month);
407 }
408
409 }
0 package com.michaelbaranov.microba.calendar.ui.basic;
1
2 import java.awt.Color;
3 import java.awt.Graphics;
4 import java.awt.GridLayout;
5 import java.awt.event.ActionEvent;
6 import java.awt.event.FocusEvent;
7 import java.awt.event.FocusListener;
8 import java.awt.event.KeyEvent;
9 import java.awt.event.KeyListener;
10 import java.awt.event.MouseEvent;
11 import java.awt.event.MouseListener;
12 import java.beans.PropertyChangeEvent;
13 import java.beans.PropertyChangeListener;
14 import java.util.Calendar;
15 import java.util.Collection;
16 import java.util.Date;
17 import java.util.HashSet;
18 import java.util.Locale;
19 import java.util.Set;
20 import java.util.TimeZone;
21
22 import javax.swing.AbstractAction;
23 import javax.swing.BorderFactory;
24 import javax.swing.InputMap;
25 import javax.swing.JComponent;
26 import javax.swing.JLabel;
27 import javax.swing.JPanel;
28 import javax.swing.KeyStroke;
29 import javax.swing.SwingConstants;
30 import javax.swing.UIManager;
31
32 import com.michaelbaranov.microba.Microba;
33 import com.michaelbaranov.microba.calendar.CalendarColors;
34 import com.michaelbaranov.microba.calendar.CalendarPane;
35 import com.michaelbaranov.microba.calendar.HolidayPolicy;
36 import com.michaelbaranov.microba.calendar.VetoPolicy;
37 import com.michaelbaranov.microba.common.PolicyEvent;
38 import com.michaelbaranov.microba.common.PolicyListener;
39
40 class CalendarGridPanel extends JPanel implements FocusListener,
41 PolicyListener, PropertyChangeListener, MouseListener, KeyListener {
42
43 public static final String PROPERTY_NAME_DATE = "date";
44
45 public static final String PROPERTY_NAME_BASE_DATE = "baseDate";
46
47 public static final String PROPERTY_NAME_LOCALE = "locale";
48
49 public static final String PROPERTY_NAME_ZONE = "zone";
50
51 public static final String PROPERTY_NAME_VETO_POLICY = "vetoPolicy";
52
53 private static final String PROPERTY_NAME_HOLIDAY_POLICY = "holidayPolicy";
54
55 // Not a rela property, ad-hoc approach to notify about clicking selected
56 // date lable
57 public static final String PROPERTY_NAME_NOTIFY_SELECTED_DATE_CLICKED = "##same date clicked##";
58
59 private CalendarPane peer;
60
61 private Date date;
62
63 private Date baseDate;
64
65 private Date focusDate;
66
67 private Locale locale;
68
69 private TimeZone zone;
70
71 private VetoPolicy vetoPolicy;
72
73 private DateLabel labels[] = new DateLabel[42];
74
75 private Set focusableComponents = new HashSet();
76
77 private boolean explicitDateSetToNullFlag;
78
79 private HolidayPolicy holidayPolicy;
80
81 private Color focusColor;
82
83 private Color restrictedColor;
84
85 private Color gridBgEn;
86
87 private Color gridBgDis;
88
89 private Color gridFgEn;
90
91 private Color gridFgDis;
92
93 private Color selBgEn;
94
95 private Color selBgDis;
96
97 private Color wkFgEn;
98
99 private Color wkFgDis;
100
101 private Color holFgEn;
102
103 private Color holFgDis;
104
105 public CalendarGridPanel(CalendarPane peer, Date date, Locale locale,
106 TimeZone zone, VetoPolicy vetoDateModel, HolidayPolicy holidayPolicy) {
107
108 this.peer = peer;
109
110 focusColor = Microba.getOverridenColor(
111 CalendarColors.COLOR_CALENDAR_GRID_FOCUS, peer, UIManager
112 .getColor("TabbedPane.focus"));
113 restrictedColor = Microba.getOverridenColor(
114 CalendarColors.COLOR_CALENDAR_GRID_RESTRICTED, peer, Color.RED);
115 gridBgEn = Microba.getOverridenColor(
116 CalendarColors.COLOR_CALENDAR_GRID_BACKGROUND_ENABLED, peer,
117 UIManager.getColor("TextField.background"));
118
119 gridBgDis = Microba.getOverridenColor(
120 CalendarColors.COLOR_CALENDAR_GRID_BACKGROUND_DISABLED, peer,
121 UIManager.getColor("TextField.background"));
122
123 gridFgEn = Microba.getOverridenColor(
124 CalendarColors.COLOR_CALENDAR_GRID_FOREGROUND_ENABLED, peer,
125 UIManager.getColor("TextField.foreground"));
126
127 gridFgDis = Microba.getOverridenColor(
128 CalendarColors.COLOR_CALENDAR_GRID_FOREGROUND_DISABLED, peer,
129 UIManager.getColor("controlText"));
130
131 selBgEn = Microba
132 .getOverridenColor(
133 CalendarColors.COLOR_CALENDAR_GRID_SELECTION_BACKGROUND_ENABLED,
134 peer, UIManager
135 .getColor("ComboBox.selectionBackground"));
136 selBgDis = Microba
137 .getOverridenColor(
138 CalendarColors.COLOR_CALENDAR_GRID_SELECTION_BACKGROUND_DISABLED,
139 peer, UIManager
140 .getColor("ComboBox.selectionBackground"));
141
142 wkFgDis = Microba.getOverridenColor(
143 CalendarColors.COLOR_CALENDAR_GRID_WEEKEND_FOREGROUND_DISABLED,
144 peer, gridFgDis);
145 wkFgEn = Microba.getOverridenColor(
146 CalendarColors.COLOR_CALENDAR_GRID_WEEKEND_FOREGROUND_ENABLED,
147 peer, Color.RED);
148 holFgDis = Microba.getOverridenColor(
149 CalendarColors.COLOR_CALENDAR_GRID_HOLIDAY_FOREGROUND_DISABLED,
150 peer, gridFgDis);
151 holFgEn = Microba.getOverridenColor(
152 CalendarColors.COLOR_CALENDAR_GRID_HOLIDAY_FOREGROUND_ENABLED,
153 peer, Color.RED);
154
155 this.locale = locale;
156 this.zone = zone;
157 this.date = date;
158 this.baseDate = date == null ? new Date() : date;
159 this.explicitDateSetToNullFlag = date == null ? true : false;
160 this.focusDate = getFocusDateForDate(date);
161 this.vetoPolicy = vetoDateModel;
162 this.holidayPolicy = holidayPolicy;
163 if (this.vetoPolicy != null)
164 this.vetoPolicy.addVetoPolicyListener(this);
165 if (this.holidayPolicy != null)
166 this.holidayPolicy.addVetoPolicyListener(this);
167 this.addPropertyChangeListener(this);
168
169 setLayout(new GridLayout(6, 7, 2, 2));
170
171 for (int i = 0; i < 42; i++) {
172 DateLabel l = new DateLabel(i);
173 labels[i] = l;
174 l.setText(String.valueOf(i));
175 l.addMouseListener(this);
176 add(l);
177 }
178 focusableComponents.add(this);
179 addKeyListener(this);
180 setFocusable(true);
181
182 // TODO: move the following to key listeners?
183 InputMap input = this.getInputMap(JComponent.WHEN_FOCUSED);
184 input.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0),
185 "##microba.commit##");
186 input.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0),
187 "##microba.commit##");
188
189 this.getActionMap().put("##microba.commit##", new AbstractAction() {
190
191 public void actionPerformed(ActionEvent e) {
192 Calendar c = getCalendar(focusDate);
193 if (vetoPolicy == null || !vetoPolicy.isRestricted(this, c)) {
194 setDate(focusDate);
195 }
196
197 }
198 });
199 addFocusListener(this);
200 // addMouseListener(this);
201 setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
202 reflectData();
203 }
204
205 public void focusGained(FocusEvent e) {
206 setBorder(BorderFactory.createLineBorder(focusColor));
207 reflectFocusedDate();
208 }
209
210 public void focusLost(FocusEvent e) {
211 setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
212 reflectFocusedDate();
213
214 }
215
216 private void setSelectedByIndex(int i) {
217 DateLabel label = labels[i];
218 if (label.isVisible()) {
219 int day = Integer.parseInt(label.getText());
220 Calendar c = getCalendar(baseDate);
221 c.set(Calendar.DAY_OF_MONTH, day);
222 setDate(c.getTime());
223 }
224 }
225
226 private Calendar getCalendar(Date date) {
227 Calendar c = Calendar.getInstance(zone, locale);
228 c.setTime(date);
229 return c;
230 }
231
232 private int getSelectedIndex() {
233 if (date == null)
234 return -1;
235 Calendar bc = getCalendar(baseDate);
236 Calendar sc = getCalendar(date);
237 // selectd date visible in base month
238 if (bc.get(Calendar.ERA) == sc.get(Calendar.ERA)
239 && bc.get(Calendar.YEAR) == sc.get(Calendar.YEAR)
240 && bc.get(Calendar.MONTH) == sc.get(Calendar.MONTH)) {
241 bc.set(Calendar.DAY_OF_MONTH, 1);
242 int skipBefore = bc.get(Calendar.DAY_OF_WEEK)
243 - bc.getFirstDayOfWeek();
244 if (skipBefore < 0)
245 skipBefore = 7 + skipBefore;
246 int selDay = sc.get(Calendar.DAY_OF_MONTH);
247 return skipBefore + selDay - 1;
248 } else
249 return -1;
250 }
251
252 private void setFocusedByIndex(int i) {
253 DateLabel label = labels[i];
254 if (label.isVisible()) {
255 int day = Integer.parseInt(label.getText());
256 Calendar c = getCalendar(baseDate);
257 c.set(Calendar.DAY_OF_MONTH, day);
258 setFocusDate(c.getTime());
259 }
260 }
261
262 private int getFocusedIndex() {
263 Calendar bc = getCalendar(baseDate);
264 Calendar fc = getCalendar(focusDate);
265 bc.set(Calendar.DAY_OF_MONTH, 1);
266 int skipBefore = bc.get(Calendar.DAY_OF_WEEK) - bc.getFirstDayOfWeek();
267 if (skipBefore < 0)
268 skipBefore = 7 + skipBefore;
269 int selDay = fc.get(Calendar.DAY_OF_MONTH);
270 int maxDay = bc.getActualMaximum(Calendar.DAY_OF_MONTH);
271 if (selDay > maxDay)
272 selDay = maxDay;
273 return skipBefore + selDay - 1;
274 }
275
276 private void reflectData() {
277 setBackground(isEnabled() ? gridBgEn : gridBgDis);
278
279 reflectBaseDate();
280 reflectSelectedDate();
281 reflectFocusedDate();
282 }
283
284 private void reflectFocusedDate() {
285 int focusedIndex = getFocusedIndex();
286 DateLabel l = labels[focusedIndex];
287 l.setFocused(isFocusOwner());
288 }
289
290 private void reflectSelectedDate() {
291 int selIndex = getSelectedIndex();
292 if (selIndex > -1) {
293 DateLabel l = labels[selIndex];
294 l.setSelected(true);
295 }
296 }
297
298 private void reflectBaseDate() {
299 Calendar calendar = getCalendar(baseDate);
300 calendar.set(Calendar.DAY_OF_MONTH, 1);
301
302 int skipBefore = calendar.get(Calendar.DAY_OF_WEEK)
303 - calendar.getFirstDayOfWeek();
304 if (skipBefore < 0)
305 skipBefore = 7 + skipBefore;
306
307 int activeDays = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
308
309 int day = 1;
310 calendar.setTime(baseDate);
311 calendar.set(Calendar.DAY_OF_MONTH, 1);
312
313 for (int i = 0; i < 42; i++) {
314 DateLabel l = labels[i];
315 l.setBackground(isEnabled() ? selBgEn : selBgDis);
316 l.setSelected(false);
317 l.setFocused(false);
318 l.setEnabled(isEnabled());
319
320 if (i < skipBefore) {
321 l.setText("");
322 l.setVisible(false);
323 }
324 if (i >= skipBefore && i < skipBefore + activeDays) {
325 l.setVisible(true);
326 l.setText(String.valueOf(day));
327 if (vetoPolicy != null)
328 l.setBanned(vetoPolicy.isRestricted(this.peer, calendar));
329 else
330 l.setBanned(false);
331
332 if (holidayPolicy != null) {
333 l.setDate(calendar.getTime());
334 l
335 .setHolliday(holidayPolicy.isHolliday(this.peer,
336 calendar));
337 l.setWeekend(holidayPolicy.isWeekend(this.peer, calendar));
338 } else {
339 l.setHolliday(false);
340 l.setWeekend(false);
341 }
342 day++;
343 calendar.add(Calendar.DAY_OF_MONTH, 1);
344 }
345 if (i >= skipBefore + activeDays) {
346 l.setText("");
347 l.setVisible(false);
348 }
349
350 }
351 }
352
353 public Date getDate() {
354 return date;
355 }
356
357 public void setDate(Date date) {
358 Date old = this.date;
359 this.date = date;
360 this.explicitDateSetToNullFlag = date == null ? true : false;
361 this.focusDate = getFocusDateForDate(date);
362 if (old != null || date != null)
363 firePropertyChange(PROPERTY_NAME_DATE, old, date);
364 reflectData();
365 }
366
367 private Date getFocusDateForDate(Date date) {
368 if (date == null) {
369 Calendar c = getCalendar(baseDate);
370 c.set(Calendar.DAY_OF_MONTH, 1);
371 return c.getTime();
372 }
373 return date;
374 }
375
376 public Locale getLocale() {
377 return locale;
378 }
379
380 public void setLocale(Locale locale) {
381 Locale old = this.locale;
382 this.locale = locale;
383 firePropertyChange(PROPERTY_NAME_LOCALE, old, locale);
384 reflectData();
385 }
386
387 public VetoPolicy getVetoPolicy() {
388 return vetoPolicy;
389 }
390
391 public void setVetoPolicy(VetoPolicy vetoModel) {
392 VetoPolicy old = this.getVetoPolicy();
393 this.vetoPolicy = vetoModel;
394 firePropertyChange(PROPERTY_NAME_VETO_POLICY, old, vetoModel);
395 reflectData();
396 }
397
398 public HolidayPolicy getHolidayPolicy() {
399 return holidayPolicy;
400 }
401
402 public void setHolidayPolicy(HolidayPolicy holidayPolicy) {
403 HolidayPolicy old = this.getHolidayPolicy();
404 this.holidayPolicy = holidayPolicy;
405 firePropertyChange(PROPERTY_NAME_HOLIDAY_POLICY, old, holidayPolicy);
406 reflectData();
407 }
408
409 public TimeZone getZone() {
410 return zone;
411 }
412
413 public void setZone(TimeZone zone) {
414 TimeZone old = this.zone;
415 this.zone = zone;
416 firePropertyChange(PROPERTY_NAME_ZONE, old, zone);
417 reflectData();
418 }
419
420 public Collection getFocusableComponents() {
421 return focusableComponents;
422 }
423
424 class DateLabel extends JLabel {
425
426 private Date date;
427
428 private int id;
429
430 private boolean focused;
431
432 private boolean selected;
433
434 private boolean weekend;
435
436 private boolean banned;
437
438 private boolean holliday;
439
440 public DateLabel(int id) {
441 super();
442 this.id = id;
443 setHorizontalAlignment(SwingConstants.CENTER);
444
445 setFocused(false);
446 setSelected(false);
447 setWeekend(false);
448 setBanned(false);
449 setHolliday(false);
450 }
451
452 public void setHolliday(boolean b) {
453 holliday = b;
454 update();
455 repaint();
456 }
457
458 public int getId() {
459 return id;
460 }
461
462 public boolean isFocused() {
463 return focused;
464 }
465
466 public void setFocused(boolean focused) {
467 this.focused = focused;
468
469 update();
470 repaint();
471 }
472
473 public boolean isSelected() {
474 return selected;
475 }
476
477 public void setSelected(boolean selected) {
478 this.selected = selected;
479 update();
480 repaint();
481 }
482
483 private void update() {
484 // background is determined by selected state
485 // foreground by the rest
486 updateBg();
487 updateFg();
488 udapteBorder();
489 // Tooltip:
490 updateTooltip();
491 }
492
493 private void updateTooltip() {
494 if (holidayPolicy != null && holliday) {
495 Calendar c = Calendar.getInstance(zone, locale);
496 c.setTime(date);
497 setToolTipText(holidayPolicy.getHollidayName(this, c));
498 } else
499 setToolTipText(null);
500 }
501
502 private void udapteBorder() {
503 if (isFocused() && isEnabled()) {
504 setBorder(BorderFactory
505 .createLineBorder(banned ? restrictedColor : focusColor));
506
507 } else
508 setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
509 }
510
511 private void updateFg() {
512 if (isHolliday()) {
513 setForeground(isEnabled() ? holFgEn : holFgDis);
514 } else {
515 if (isWeekend()) {
516 setForeground(isEnabled() ? wkFgEn : wkFgDis);
517 } else {
518 setForeground(isEnabled() ? gridFgEn : gridFgDis);
519 }
520 }
521
522 }
523
524 private void updateBg() {
525 if (isSelected()) {
526 setOpaque(true);
527 setBackground(isEnabled() ? selBgEn : selBgDis);
528 } else
529 setOpaque(false);
530 }
531
532 public boolean isWeekend() {
533 return weekend;
534 }
535
536 public void setWeekend(boolean weekend) {
537 this.weekend = weekend;
538 }
539
540 public boolean isBanned() {
541 return banned;
542 }
543
544 public void setBanned(boolean banned) {
545 this.banned = banned;
546 update();
547 repaint();
548 }
549
550 public void paint(Graphics g) {
551
552 if (isBanned()) {
553 g.setColor(restrictedColor);
554
555 // variant 1: full size cross
556 g.drawLine(2, 2, getWidth() - 4, getHeight() - 4);
557 g.drawLine(2, getHeight() - 4, getWidth() - 4, 2);
558
559 // variant 2: smaller cross (left upper corner)
560 // g.drawLine(1, 1, 8, 8);
561 // g.drawLine(1, 8, 8, 1);
562
563 }
564 super.paint(g);
565 }
566
567 public boolean isHolliday() {
568 return holliday;
569 }
570
571 public Date getDate() {
572 return date;
573 }
574
575 public void setDate(Date date) {
576 this.date = date;
577 }
578
579 }
580
581 public void policyChanged(PolicyEvent event) {
582 reflectData();
583 }
584
585 public void propertyChange(PropertyChangeEvent evt) {
586 if (evt.getPropertyName().equals(PROPERTY_NAME_VETO_POLICY)) {
587 VetoPolicy oldValue = (VetoPolicy) evt.getOldValue();
588 VetoPolicy newValue = (VetoPolicy) evt.getOldValue();
589 if (oldValue != null)
590 oldValue.removeVetoPolicyListener(this);
591 if (newValue != null)
592 newValue.addVetoPolicyListener(this);
593 reflectData();
594 }
595 }
596
597 public Date getBaseDate() {
598 return baseDate;
599 }
600
601 public void setBaseDate(Date baseDate) {
602 // TODO: throw away the following 2 lines?
603 // if (baseDate == null)
604 // baseDate = new Date();
605 Date old = this.baseDate;
606 this.baseDate = baseDate;
607 firePropertyChange(PROPERTY_NAME_BASE_DATE, old, baseDate);
608
609 // update focus date
610 Calendar bc = getCalendar(baseDate);
611 Calendar fc = getCalendar(focusDate);
612 int focDate = fc.get(Calendar.DAY_OF_MONTH);
613 int maxDay = bc.getActualMaximum(Calendar.DAY_OF_MONTH);
614 if (focDate > maxDay)
615 focDate = maxDay;
616 bc.set(Calendar.DAY_OF_MONTH, focDate);
617 focusDate = bc.getTime();
618
619 reflectData();
620 }
621
622 private Date getFocusDate() {
623 return focusDate;
624 }
625
626 private void setFocusDate(Date focusDate) {
627 this.focusDate = focusDate;
628 explicitDateSetToNullFlag = false;
629 reflectData();
630 }
631
632 public void mouseClicked(MouseEvent e) {
633 if (!isEnabled())
634 return;
635 requestFocusInWindow();
636 DateLabel l = (DateLabel) e.getSource();
637 if (l.isVisible()) {
638 int id = Integer.parseInt(l.getText());
639 Calendar c = getCalendar(baseDate);
640 c.set(Calendar.DAY_OF_MONTH, id);
641 if (vetoPolicy == null || !vetoPolicy.isRestricted(this, c)) {
642 boolean selected = l.isSelected();
643 setDate(c.getTime());
644 if (selected)
645 firePropertyChange(
646 PROPERTY_NAME_NOTIFY_SELECTED_DATE_CLICKED, null,
647 new Integer(id));
648 }
649 }
650 }
651
652 public void mousePressed(MouseEvent e) {
653
654 }
655
656 public void mouseReleased(MouseEvent e) {
657 }
658
659 public void mouseEntered(MouseEvent e) {
660 }
661
662 public void mouseExited(MouseEvent e) {
663 }
664
665 public void keyTyped(KeyEvent e) {
666
667 }
668
669 public void keyPressed(KeyEvent e) {
670 if (!isEnabled())
671 return;
672 int id = getFocusedIndex();
673 int row = id / 7;
674 int col = id % 7;
675 if (e.getKeyCode() == KeyEvent.VK_DOWN) {
676 row++;
677 if (row < 6) {
678 setFocusedByIndex(row * 7 + col);
679 }
680 }
681 if (e.getKeyCode() == KeyEvent.VK_UP) {
682 row--;
683 if (row >= 0) {
684 setFocusedByIndex(row * 7 + col);
685 }
686 }
687 if (e.getKeyCode() == KeyEvent.VK_LEFT) {
688 col--;
689 if (col >= 0) {
690 setFocusedByIndex(row * 7 + col);
691 }
692 }
693 if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
694 col++;
695 if (col < 7) {
696 setFocusedByIndex(row * 7 + col);
697 }
698 }
699 }
700
701 public void keyReleased(KeyEvent e) {
702 }
703
704 public Date getDateToCommit() {
705 Calendar c = getCalendar(focusDate);
706 if (explicitDateSetToNullFlag
707 || (vetoPolicy != null && vetoPolicy.isRestricted(this, c)))
708 return date;
709 return focusDate;
710 }
711
712 public void setEnabled(boolean enabled) {
713 super.setEnabled(enabled);
714 reflectData();
715 }
716
717 }
0 package com.michaelbaranov.microba.calendar.ui.basic;
1
2 import java.awt.Color;
3 import java.awt.Font;
4 import java.awt.GridLayout;
5 import java.text.SimpleDateFormat;
6 import java.util.Calendar;
7 import java.util.Date;
8 import java.util.Locale;
9 import java.util.TimeZone;
10
11 import javax.swing.BorderFactory;
12 import javax.swing.JLabel;
13 import javax.swing.JPanel;
14 import javax.swing.SwingConstants;
15 import javax.swing.UIManager;
16
17 import com.michaelbaranov.microba.Microba;
18 import com.michaelbaranov.microba.calendar.CalendarPane;
19 import com.michaelbaranov.microba.calendar.HolidayPolicy;
20
21 class CalendarHeader extends JPanel {
22
23 private Locale locale;
24
25 private TimeZone zone;
26
27 private Date date;
28
29 private HolidayPolicy holidayPolicy;
30
31 private Color backgroundColorActive;
32
33 private Color backgroundColorInactive;
34
35 private Color foregroundColorActive;
36
37 private Color foregroundColorInactive;
38
39 private Color foregroundColorWeekendEnabled;
40
41 private Color foregroundColorWeekendDisabled;
42
43 public CalendarHeader(CalendarPane peer, Date date, Locale locale,
44 TimeZone zone, HolidayPolicy holidayPolicy) {
45 super();
46
47 backgroundColorActive = Microba.getOverridenColor(
48 CalendarPane.COLOR_CALENDAR_HEADER_BACKGROUND_ENABLED, peer,
49 UIManager.getColor("activeCaption"));
50 backgroundColorInactive = Microba.getOverridenColor(
51 CalendarPane.COLOR_CALENDAR_HEADER_BACKGROUND_DISABLED, peer,
52 UIManager.getColor("inactiveCaption"));
53 foregroundColorActive = Microba.getOverridenColor(
54 CalendarPane.COLOR_CALENDAR_HEADER_FOREGROUND_ENABLED, peer,
55 UIManager.getColor("controlText"));
56 foregroundColorInactive = Microba.getOverridenColor(
57 CalendarPane.COLOR_CALENDAR_HEADER_FOREGROUND_DISABLED, peer,
58 UIManager.getColor("textInactiveText"));
59 foregroundColorWeekendEnabled = Microba.getOverridenColor(
60 CalendarPane.COLOR_CALENDAR_HEADER_FOREGROUND_WEEKEND_ENABLED,
61 peer, Color.RED);
62 foregroundColorWeekendDisabled = Microba.getOverridenColor(
63 CalendarPane.COLOR_CALENDAR_HEADER_FOREGROUND_WEEKEND_DISABLED,
64 peer, foregroundColorInactive);
65
66 this.locale = locale;
67 this.zone = zone;
68 this.date = date;
69 this.holidayPolicy = holidayPolicy;
70 reflectData();
71 }
72
73 private void reflectData() {
74
75 Calendar cal = Calendar.getInstance(zone, locale);
76 cal.setTime(date == null ? new Date() : date);
77
78 SimpleDateFormat fmt = new SimpleDateFormat("E", locale);
79 fmt.setTimeZone(zone);
80
81 int numDaysInWeek = cal.getActualMaximum(Calendar.DAY_OF_WEEK)
82 - cal.getActualMinimum(Calendar.DAY_OF_WEEK) + 1;
83 int firstDayOfWeek = cal.getFirstDayOfWeek();
84
85 cal.set(Calendar.DAY_OF_WEEK, firstDayOfWeek);
86
87 removeAll();
88 setLayout(new GridLayout(1, numDaysInWeek, 2, 2));
89
90 setBackground(isEnabled() ? backgroundColorActive
91 : backgroundColorInactive);
92
93 for (int i = 0; i < numDaysInWeek; i++) {
94 JLabel label = new JLabel();
95 // TODO: add option to control limit length:
96 label.setText(fmt.format(cal.getTime())/* .substring(0,1) */);
97 label.setForeground(isEnabled() ? foregroundColorActive
98 : foregroundColorInactive);
99 label.setHorizontalAlignment(SwingConstants.CENTER);
100 label.setBorder(BorderFactory.createEmptyBorder(3, 0, 3, 0));
101 Font boldFont = label.getFont().deriveFont(Font.BOLD);
102 label.setFont(boldFont);
103 add(label);
104
105 boolean isHolliday = false;
106 if (holidayPolicy != null) {
107 isHolliday = holidayPolicy.isWeekend(this, cal);
108 }
109
110 if (isHolliday)
111 label.setForeground(isEnabled() ? foregroundColorWeekendEnabled
112 : foregroundColorWeekendDisabled);
113
114 cal.add(Calendar.DAY_OF_WEEK, 1);
115 }
116 setBorder(BorderFactory.createEmptyBorder(0, 1, 0, 1));
117 revalidate();
118 repaint();
119
120 }
121
122 public void setLocale(Locale locale) {
123 this.locale = locale;
124 reflectData();
125 }
126
127 public void setDate(Date date) {
128 this.date = date;
129 reflectData();
130 }
131
132 public TimeZone getZone() {
133 return zone;
134 }
135
136 public void setZone(TimeZone zone) {
137 this.zone = zone;
138 reflectData();
139 }
140
141 public void setHolidayPolicy(HolidayPolicy holidayPolicy) {
142 this.holidayPolicy = holidayPolicy;
143 reflectData();
144
145 }
146
147 public void setEnabled(boolean enabled) {
148 super.setEnabled(enabled);
149 reflectData();
150 }
151
152 }
0 package com.michaelbaranov.microba.calendar.ui.basic;
1
2 import java.awt.Color;
3 import java.awt.Dimension;
4 import java.awt.FontMetrics;
5 import java.awt.Graphics;
6 import java.awt.GridLayout;
7 import java.util.Calendar;
8 import java.util.Date;
9 import java.util.Locale;
10 import java.util.TimeZone;
11
12 import javax.swing.BorderFactory;
13 import javax.swing.JLabel;
14 import javax.swing.JPanel;
15 import javax.swing.UIManager;
16
17 public class CalendarNumberOfWeekPanel extends JPanel /*
18 * implements
19 * PropertyChangeListener
20 */{
21
22 public static final String PROPERTY_NAME_BASE_DATE = "baseDate";
23
24 public static final String PROPERTY_NAME_LOCALE = "locale";
25
26 public static final String PROPERTY_NAME_ZONE = "zone";
27
28 private Color backgroundColorActive = UIManager.getColor("activeCaption");
29
30 private Color backgroundColorInactive = UIManager
31 .getColor("inactiveCaption");
32
33 private Date baseDate;
34
35 private Locale locale;
36
37 private TimeZone zone;
38
39 private JLabel[] labels = new JLabel[6];
40
41 public CalendarNumberOfWeekPanel(Date baseDate, Locale locale,
42 TimeZone timeZone) {
43 super();
44 this.baseDate = baseDate == null ? new Date() : baseDate;
45 this.locale = locale;
46 this.zone = timeZone;
47
48 setLayout(new GridLayout(6, 1, 2, 2));
49
50 for (int i = 0; i < 6; i++) {
51 JLabel l = new JLabel();
52 labels[i] = l;
53
54 add(l);
55 }
56
57 setBorder(BorderFactory.createEmptyBorder(1, 4, 1, 4));
58
59 reflectBaseDate();
60 }
61
62 public void setBaseDate(Date baseDate) {
63 this.baseDate = baseDate;
64 reflectBaseDate();
65 }
66
67 private void reflectBaseDate() {
68 Calendar calendar = getCalendar(baseDate);
69 calendar.set(Calendar.DAY_OF_MONTH, 1);
70
71 int skipBefore = calendar.get(Calendar.DAY_OF_WEEK)
72 - calendar.getFirstDayOfWeek();
73 if (skipBefore < 0)
74 skipBefore = 7 + skipBefore;
75
76 int activeDays = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
77
78 int numActiveWeeks = (activeDays + skipBefore) / 7;
79 if ((activeDays + skipBefore) % 7 > 0)
80 numActiveWeeks++;
81
82 int startWeek = calendar.get(Calendar.WEEK_OF_YEAR);
83
84 for (int i = 0; i < 6; i++) {
85 labels[i].setText(startWeek > 0 && numActiveWeeks > 0 ? String
86 .valueOf(startWeek) : "");
87
88 labels[i].setForeground(isEnabled() ? UIManager
89 .getColor("controlText") : UIManager
90 .getColor("textInactiveText"));
91
92 startWeek++;
93 numActiveWeeks--;
94 }
95
96 setBackground(isEnabled() ? backgroundColorActive
97 : backgroundColorInactive);
98 }
99
100 private Calendar getCalendar(Date date) {
101 Calendar c = Calendar.getInstance(zone, locale);
102 c.setTime(date);
103 return c;
104 }
105
106 public void setLocale(Locale locale) {
107 this.locale = locale;
108 reflectBaseDate();
109 }
110
111 public void setZone(TimeZone zone) {
112 this.zone = zone;
113 reflectBaseDate();
114 }
115
116 public void paint(Graphics g) {
117 FontMetrics fm = g.getFontMetrics(labels[0].getFont());
118 Dimension dimension = new Dimension(fm.stringWidth("00") + 8, 1);
119 setMinimumSize(dimension);
120 setPreferredSize(dimension);
121 super.paint(g);
122 }
123
124 public void setEnabled(boolean enabled) {
125 super.setEnabled(enabled);
126 reflectBaseDate();
127 }
128
129 }
0 package com.michaelbaranov.microba.calendar.ui.basic;
1
2 import java.awt.Dimension;
3 import java.awt.Font;
4 import java.awt.GridBagConstraints;
5 import java.awt.GridBagLayout;
6 import java.awt.Insets;
7 import java.awt.event.ActionEvent;
8 import java.awt.event.ActionListener;
9 import java.beans.PropertyChangeEvent;
10 import java.beans.PropertyChangeListener;
11 import java.text.DateFormat;
12 import java.text.SimpleDateFormat;
13 import java.util.Calendar;
14 import java.util.Collection;
15 import java.util.Date;
16 import java.util.HashSet;
17 import java.util.Locale;
18 import java.util.Set;
19 import java.util.TimeZone;
20
21 import javax.swing.ImageIcon;
22 import javax.swing.JButton;
23 import javax.swing.JLabel;
24 import javax.swing.JPanel;
25 import javax.swing.SwingConstants;
26
27 import com.michaelbaranov.microba.calendar.resource.Resource;
28
29 class ClassicCalendarPanel extends JPanel implements
30 PropertyChangeListener {
31
32 public static final String PROPERTY_NAME_DATE = "date";
33
34 public static final String PROPERTY_NAME_LOCALE = "locale";
35
36 public static final String PROPERTY_NAME_ZONE = "zone";
37
38 private Locale locale;
39
40 private TimeZone zone;
41
42 private Calendar calendar;
43
44 private JButton prevButton;
45
46 private JButton nextButton;
47
48 private JLabel selectedDateLabel;
49
50 private DateFormat format;
51
52 private Set focusableComponents = new HashSet();
53
54 private JButton fastPrevButton;
55
56 private JButton fastNextButton;
57
58 public ClassicCalendarPanel(Date aDate, Locale aLocale, TimeZone zone) {
59 this.locale = aLocale;
60 this.zone = zone;
61
62 prevButton = new JButton();
63 nextButton = new JButton();
64
65 fastPrevButton = new JButton();
66 fastNextButton = new JButton();
67
68 nextButton.setIcon(new ImageIcon(Resource.class.getResource("forward-16.png")));
69 prevButton.setIcon(new ImageIcon(Resource.class.getResource("back-16.png")));
70 fastNextButton.setIcon(new ImageIcon(Resource.class.getResource("forward-fast-16.png")));
71 fastPrevButton.setIcon(new ImageIcon(Resource.class.getResource("back-fast-16.png")));
72 prevButton.setMargin(new Insets(0, 0, 0, 0));
73 nextButton.setMargin(new Insets(0, 0, 0, 0));
74 fastPrevButton.setMargin(new Insets(0, 0, 0, 0));
75 fastNextButton.setMargin(new Insets(0, 0, 0, 0));
76
77 Dimension psz = nextButton.getPreferredSize();
78 Dimension npsz = new Dimension(psz.height, psz.height);
79
80 nextButton.setPreferredSize(npsz);
81 prevButton.setPreferredSize(npsz);
82
83 selectedDateLabel = new JLabel();
84 selectedDateLabel.setHorizontalAlignment(SwingConstants.CENTER);
85 selectedDateLabel.setFont(selectedDateLabel.getFont().deriveFont(
86 Font.BOLD));
87 setLayout(new GridBagLayout());
88 add(fastPrevButton, new GridBagConstraints(0, 0, 1, 1, 0, 0,
89 GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(
90 0, 0, 3, 0), 0, 0));
91 add(prevButton, new GridBagConstraints(1, 0, 1, 1, 0, 0,
92 GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(
93 0, 0, 3, 0), 0, 0));
94 add(selectedDateLabel, new GridBagConstraints(2, 0, 1, 1, 1.0, 0,
95 GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
96 new Insets(0, 3, 3, 3), 0, 0));
97 add(nextButton, new GridBagConstraints(3, 0, 1, 1, 0, 0,
98 GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(
99 0, 0, 3, 0), 0, 0));
100 add(fastNextButton, new GridBagConstraints(4, 0, 1, 1, 0, 0,
101 GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(
102 0, 0, 3, 0), 0, 0));
103
104 nextButton.addActionListener(new ActionListener() {
105
106 public void actionPerformed(ActionEvent e) {
107 Date old = calendar.getTime();
108 calendar.add(Calendar.MONTH, 1);
109 firePropertyChange(PROPERTY_NAME_DATE, old, getDate());
110 reflectData();
111 }
112 });
113 prevButton.addActionListener(new ActionListener() {
114
115 public void actionPerformed(ActionEvent e) {
116 Date old = calendar.getTime();
117 calendar.add(Calendar.MONTH, -1);
118 firePropertyChange(PROPERTY_NAME_DATE, old, getDate());
119 reflectData();
120 }
121 });
122 fastNextButton.addActionListener(new ActionListener() {
123
124 public void actionPerformed(ActionEvent e) {
125 Date old = calendar.getTime();
126 calendar.add(Calendar.YEAR, 1);
127 firePropertyChange(PROPERTY_NAME_DATE, old, getDate());
128 reflectData();
129 }
130 });
131 fastPrevButton.addActionListener(new ActionListener() {
132
133 public void actionPerformed(ActionEvent e) {
134 Date old = calendar.getTime();
135 calendar.add(Calendar.YEAR, -1);
136 firePropertyChange(PROPERTY_NAME_DATE, old, getDate());
137 reflectData();
138 }
139 });
140
141 this.addPropertyChangeListener(this);
142
143 focusableComponents.add(prevButton);
144 focusableComponents.add(nextButton);
145 focusableComponents.add(fastNextButton);
146 focusableComponents.add(fastPrevButton);
147
148 createLocaleAndZoneSensitive();
149 calendar.setTime(aDate);
150 reflectData();
151 }
152
153 private void createLocaleAndZoneSensitive() {
154 if (calendar != null) {
155 Date old = calendar.getTime();
156 calendar = Calendar.getInstance(zone, locale);
157 calendar.setTime(old);
158 } else
159 calendar = Calendar.getInstance(zone, locale);
160
161 format = new SimpleDateFormat("MMMMM yyyy", locale);
162 format.setTimeZone(zone);
163
164 setPreferredLabelSize();
165
166 }
167
168 private void setPreferredLabelSize() {
169 Calendar c = Calendar.getInstance(zone, locale);
170 c.setTime(getDate());
171
172 JLabel l = new JLabel();
173 l.setFont(selectedDateLabel.getFont());
174
175 int maxWidth = Integer.MIN_VALUE;
176 for (int i = 0; i <= c.getActualMaximum(Calendar.MONTH); i++) {
177 c.set(Calendar.MONTH, i);
178 String text = format.format(c.getTime());
179 l.setText(text);
180 int w = l.getPreferredSize().width;
181 if (w > maxWidth)
182 maxWidth = w;
183 }
184 Dimension d = l.getPreferredSize();
185 d.width = maxWidth + 10;
186 selectedDateLabel.setMinimumSize(d);
187 selectedDateLabel.setPreferredSize(d);
188 this.revalidate();
189 }
190
191 private void reflectData() {
192 selectedDateLabel.setText(format.format(calendar.getTime()));
193 }
194
195 public Date getDate() {
196 return calendar.getTime();
197 }
198
199 public void setDate(Date date) {
200 Date old = getDate();
201 calendar.setTime(date);
202 firePropertyChange(PROPERTY_NAME_DATE, old, date);
203 reflectData();
204 }
205
206 public Locale getLocale() {
207 return locale;
208 }
209
210 public void setLocale(Locale locale) {
211 Locale old = this.locale;
212 this.locale = locale;
213 createLocaleAndZoneSensitive();
214 firePropertyChange(PROPERTY_NAME_LOCALE, old, locale);
215 reflectData();
216 }
217
218 public TimeZone getZone() {
219 return zone;
220 }
221
222 public void setZone(TimeZone zone) {
223 TimeZone old = this.zone;
224 this.zone = zone;
225 createLocaleAndZoneSensitive();
226 firePropertyChange(PROPERTY_NAME_ZONE, old, locale);
227 reflectData();
228 }
229
230 public void propertyChange(PropertyChangeEvent evt) {
231 if (evt.getPropertyName().equals("focusable")) {
232 Boolean value = (Boolean) evt.getNewValue();
233 prevButton.setFocusable(value.booleanValue());
234 nextButton.setFocusable(value.booleanValue());
235 fastNextButton.setFocusable(value.booleanValue());
236 fastPrevButton.setFocusable(value.booleanValue());
237 }
238 if (evt.getPropertyName().equals("enabled")) {
239 Boolean value = (Boolean) evt.getNewValue();
240 prevButton.setEnabled(value.booleanValue());
241 nextButton.setEnabled(value.booleanValue());
242 fastNextButton.setEnabled(value.booleanValue());
243 fastPrevButton.setEnabled(value.booleanValue());
244 }
245
246 }
247
248 public Collection getFocusableComponents() {
249 return focusableComponents;
250 }
251
252 public void addMonth(int m) {
253 int modM = m > 0 ? m : -m;
254 int sign = m > 0 ? 1 : -1;
255 Date old = calendar.getTime();
256 for (int i = 0; i < modM; i++) {
257 calendar.add(Calendar.MONTH, sign);
258 }
259 firePropertyChange(PROPERTY_NAME_DATE, old, getDate());
260 reflectData();
261
262 }
263
264 }
0 package com.michaelbaranov.microba.calendar.ui.basic;
1
2 import java.awt.Component;
3 import java.awt.GridBagConstraints;
4 import java.awt.GridBagLayout;
5 import java.awt.Insets;
6 import java.beans.PropertyChangeEvent;
7 import java.beans.PropertyChangeListener;
8 import java.util.Calendar;
9 import java.util.Collection;
10 import java.util.Date;
11 import java.util.HashSet;
12 import java.util.Locale;
13 import java.util.Set;
14 import java.util.TimeZone;
15
16 import javax.swing.JComboBox;
17 import javax.swing.JPanel;
18
19 class ModernCalendarPanel extends JPanel implements PropertyChangeListener {
20
21 public static final String PROPERTY_NAME_DATE = "date";
22
23 public static final String PROPERTY_NAME_LOCALE = "locale";
24
25 public static final String PROPERTY_NAME_ZONE = "zone";
26
27 private Date date;
28
29 private Locale locale;
30
31 private TimeZone zone;
32
33 private YearSpinnerModel yearSpinnerModel;
34
35 private NoGroupingSpinner yearSpinner;
36
37 private MonthComboBoxModel monthComboBoxModel;
38
39 private MonthComboBoxRenderer monthComboBoxRenderer;
40
41 private JComboBox monthCombo;
42
43 private Set focusableComponents = new HashSet();
44
45 public ModernCalendarPanel(Date aDate, Locale aLocale, TimeZone zone) {
46 this.date = aDate;
47 this.locale = aLocale;
48 this.zone = zone;
49
50 monthComboBoxModel = new MonthComboBoxModel(aDate, aLocale, zone);
51 monthComboBoxRenderer = new MonthComboBoxRenderer(aLocale, zone);
52 monthCombo = new JComboBox(monthComboBoxModel);
53
54 monthCombo.setRenderer(monthComboBoxRenderer);
55
56 yearSpinnerModel = new YearSpinnerModel(aDate, aLocale, zone);
57 yearSpinner = new NoGroupingSpinner(yearSpinnerModel);
58
59 setLayout(new GridBagLayout());
60 add(monthCombo, new GridBagConstraints(0, 0, 1, 1, 1.0, 0,
61 GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(0,
62 0, 3, 0), 0, 0));
63 add(yearSpinner, new GridBagConstraints(1, 0, 1, 1, 0, 0,
64 GridBagConstraints.EAST, GridBagConstraints.VERTICAL,
65 new Insets(0, 3, 3, 0), 0, 0));
66
67 focusableComponents.add(yearSpinner);
68 focusableComponents.add(monthCombo);
69
70 monthComboBoxModel
71 .addPropertyChangeListener(new PropertyChangeListener() {
72
73 public void propertyChange(PropertyChangeEvent evt) {
74 if (evt.getPropertyName().equals(
75 MonthComboBoxModel.PROPERTY_NAME_DATE)) {
76 Date newDate = (Date) evt.getNewValue();
77 setDate(newDate);
78 }
79 }
80 });
81 yearSpinnerModel
82 .addPropertyChangeListener(new PropertyChangeListener() {
83
84 public void propertyChange(PropertyChangeEvent evt) {
85 if (evt.getPropertyName().equals(
86 YearSpinnerModel.PROPERTY_NAME_DATE)) {
87 Date newDate = (Date) evt.getNewValue();
88 setDate(newDate);
89 }
90 }
91 });
92 this.addPropertyChangeListener(this);
93
94 }
95
96 public void setEnabled(boolean enabled) {
97 super.setEnabled(enabled);
98 monthCombo.setEnabled(enabled);
99 yearSpinner.setEnabled(enabled);
100 }
101
102 public void setFocusable(boolean focusable) {
103 super.setFocusable(focusable);
104 monthCombo.setFocusable(focusable);
105 yearSpinner.setFocusable(focusable);
106 }
107
108 public Date getDate() {
109 return date;
110 }
111
112 public void setDate(Date date) {
113 Date oldDate = this.date;
114 this.date = date;
115 firePropertyChange(PROPERTY_NAME_DATE, oldDate, date);
116 monthComboBoxModel.setDate(date);
117 yearSpinnerModel.setDate(date);
118 }
119
120 public Locale getLocale() {
121 return locale;
122 }
123
124 public void setLocale(Locale locale) {
125 Locale old = this.locale;
126 this.locale = locale;
127 monthComboBoxRenderer.setLocale(locale);
128 monthComboBoxModel.setLocale(locale);
129 yearSpinnerModel.setLocale(locale);
130 firePropertyChange(PROPERTY_NAME_LOCALE, old, locale);
131 }
132
133 public Collection getFocusableComponents() {
134 return focusableComponents;
135 }
136
137 public TimeZone getZone() {
138 return zone;
139 }
140
141 public void setZone(TimeZone zone) {
142 TimeZone old = this.zone;
143 this.zone = zone;
144 monthComboBoxRenderer.setZone(zone);
145 monthComboBoxModel.setZone(zone);
146 yearSpinnerModel.setZone(zone);
147 firePropertyChange(PROPERTY_NAME_ZONE, old, zone);
148 }
149
150 public void propertyChange(PropertyChangeEvent evt) {
151 if (evt.getPropertyName().equals("focusable")) {
152 boolean value = ((Boolean) evt.getNewValue()).booleanValue();
153 yearSpinner.setFocusable(value);
154 Component children[] = yearSpinner.getEditor().getComponents();
155 for (int i = 0; i < children.length; i++)
156 children[i].setFocusable(value);
157 monthCombo.setFocusable(value);
158 }
159 if (evt.getPropertyName().equals("enabled")) {
160 boolean value = ((Boolean) evt.getNewValue()).booleanValue();
161 yearSpinner.setEnabled(value);
162 monthCombo.setEnabled(value);
163 }
164 }
165
166 public void goToMonth(int year, int month) {
167 Date date = getDate();
168 Calendar calendar = Calendar.getInstance(zone,locale);
169 calendar.setTime(date);
170 calendar.set(Calendar.YEAR, year);
171 calendar.set(Calendar.MONTH, month);
172 setDate(calendar.getTime());
173
174 }
175
176 }
0 package com.michaelbaranov.microba.calendar.ui.basic;
1
2 import java.beans.PropertyChangeListener;
3 import java.beans.PropertyChangeSupport;
4 import java.util.Calendar;
5 import java.util.Date;
6 import java.util.Locale;
7 import java.util.TimeZone;
8
9 import javax.swing.AbstractListModel;
10 import javax.swing.ComboBoxModel;
11
12 class MonthComboBoxModel extends AbstractListModel implements
13 ComboBoxModel {
14
15 public static final String PROPERTY_NAME_LOCALE = "locale";
16
17 public static final String PROPERTY_NAME_DATE = "date";
18
19 private PropertyChangeSupport changeSupport = new PropertyChangeSupport(
20 this);
21
22 private Calendar calendar;
23
24 private Locale locale;
25
26 private TimeZone zone;
27
28 public MonthComboBoxModel(Date date, Locale locale, TimeZone zone) {
29 super();
30 this.locale = locale;
31 this.zone = zone;
32
33 createLocaleAndZoneSensitive();
34 calendar.setTime(date);
35 }
36
37 private void createLocaleAndZoneSensitive() {
38 if (calendar != null) {
39 Date old = calendar.getTime();
40 calendar = Calendar.getInstance(zone, locale);
41 calendar.setTime(old);
42 } else
43 calendar = Calendar.getInstance(zone, locale);
44 }
45
46 public Locale getLocale() {
47 return locale;
48 }
49
50 public void setLocale(Locale locale) {
51 Locale old = this.locale;
52 this.locale = locale;
53 createLocaleAndZoneSensitive();
54 changeSupport.firePropertyChange(PROPERTY_NAME_LOCALE, old, locale);
55 fireContentsChanged(this, 0, getSize() - 1);
56 }
57
58 public Date getDate() {
59 return calendar.getTime();
60 }
61
62 public void setDate(Date date) {
63 Date old = getDate();
64 calendar.setTime(date);
65 changeSupport.firePropertyChange(PROPERTY_NAME_DATE, old, date);
66 fireContentsChanged(this, 0, getSize() - 1);
67 }
68
69 public void setSelectedItem(Object anItem) {
70 Date aDate = (Date) anItem;
71 setDate(aDate);
72 }
73
74 public Object getSelectedItem() {
75 return calendar.getTime();
76 }
77
78 public int getSize() {
79 return calendar.getActualMaximum(Calendar.MONTH) + 1;
80 }
81
82 public Object getElementAt(int index) {
83 Calendar c = Calendar.getInstance(locale);
84 c.setTime(calendar.getTime());
85
86 c.set(Calendar.MONTH, 0);
87 for (int i = 0; i < index; i++)
88 c.add(Calendar.MONTH, 1);
89
90 return c.getTime();
91 }
92
93 public TimeZone getZone() {
94 return zone;
95 }
96
97 public void setZone(TimeZone zone) {
98 this.zone = zone;
99 createLocaleAndZoneSensitive();
100 fireContentsChanged(this, 0, getSize() - 1);
101 }
102
103 public void addPropertyChangeListener(PropertyChangeListener listener) {
104 changeSupport.addPropertyChangeListener(listener);
105 }
106
107 public void addPropertyChangeListener(String propertyName,
108 PropertyChangeListener listener) {
109 changeSupport.addPropertyChangeListener(propertyName, listener);
110 }
111
112 public PropertyChangeListener[] getPropertyChangeListeners() {
113 return changeSupport.getPropertyChangeListeners();
114 }
115
116 public PropertyChangeListener[] getPropertyChangeListeners(
117 String propertyName) {
118 return changeSupport.getPropertyChangeListeners(propertyName);
119 }
120
121 public boolean hasListeners(String propertyName) {
122 return changeSupport.hasListeners(propertyName);
123 }
124
125 public void removePropertyChangeListener(PropertyChangeListener listener) {
126 changeSupport.removePropertyChangeListener(listener);
127 }
128
129 public void removePropertyChangeListener(String propertyName,
130 PropertyChangeListener listener) {
131 changeSupport.removePropertyChangeListener(propertyName, listener);
132 }
133
134 }
0 package com.michaelbaranov.microba.calendar.ui.basic;
1
2 import java.awt.Component;
3 import java.text.SimpleDateFormat;
4 import java.util.Date;
5 import java.util.Locale;
6 import java.util.TimeZone;
7
8 import javax.swing.DefaultListCellRenderer;
9 import javax.swing.JList;
10
11 class MonthComboBoxRenderer extends DefaultListCellRenderer {
12
13 // private Locale locale;
14
15 private TimeZone zone;
16
17 private SimpleDateFormat dateFormat;
18
19 public MonthComboBoxRenderer(Locale locale, TimeZone zone) {
20 // this.locale = locale;
21 this.zone = zone;
22 dateFormat = new SimpleDateFormat("MMMM", locale);
23 dateFormat.setTimeZone(zone);
24 }
25
26 public Component getListCellRendererComponent(JList list, Object value,
27 int index, boolean isSelected, boolean cellHasFocus) {
28 super.getListCellRendererComponent(list, value, index, isSelected,
29 cellHasFocus);
30
31 Date date = (Date) value;
32 setText(dateFormat.format(date));
33
34 return this;
35 }
36
37 public void setLocale(Locale locale) {
38 // this.locale = locale;
39 dateFormat = new SimpleDateFormat("MMMM", locale);
40 dateFormat.setTimeZone(zone);
41 }
42
43 public void setZone(TimeZone zone) {
44 this.zone = zone;
45 dateFormat.setTimeZone(zone);
46 }
47
48 // public Locale getLocale() {
49 // return locale;
50 // }
51 //
52 // public TimeZone getZone() {
53 // return zone;
54 // }
55
56 }
0 package com.michaelbaranov.microba.calendar.ui.basic;
1
2 import java.text.NumberFormat;
3
4 import javax.swing.JComponent;
5 import javax.swing.JFormattedTextField;
6 import javax.swing.JSpinner;
7 import javax.swing.SpinnerModel;
8 import javax.swing.SpinnerNumberModel;
9 import javax.swing.text.DefaultFormatterFactory;
10 import javax.swing.text.NumberFormatter;
11
12 class NoGroupingSpinner extends JSpinner {
13
14 public static class NoGroupingNumberEditor extends NumberEditor {
15
16 public NoGroupingNumberEditor(JSpinner spinner, SpinnerModel model) {
17 super(spinner);
18 JFormattedTextField ftf = (JFormattedTextField) this
19 .getComponent(0);
20 NumberFormat fmt = NumberFormat.getIntegerInstance();
21 fmt.setGroupingUsed(false);
22 ftf.setFormatterFactory(new DefaultFormatterFactory(
23 new NumberFormatter(fmt)));
24 revalidate();
25 }
26
27 }
28
29 public NoGroupingSpinner(SpinnerModel spinnerModel) {
30 super(spinnerModel);
31 }
32
33 protected JComponent createEditor(SpinnerModel model) {
34 if (model instanceof SpinnerNumberModel)
35 return new NoGroupingNumberEditor(this, model);
36
37 return super.createEditor(model);
38 }
39
40 }
0 package com.michaelbaranov.microba.calendar.ui.basic;
1
2 import java.beans.PropertyChangeListener;
3 import java.beans.PropertyChangeSupport;
4 import java.util.Calendar;
5 import java.util.Date;
6 import java.util.Locale;
7 import java.util.TimeZone;
8
9 import javax.swing.SpinnerNumberModel;
10
11 class YearSpinnerModel extends SpinnerNumberModel {
12
13 public static final String PROPERTY_NAME_LOCALE = "locale";
14
15 public static final String PROPERTY_NAME_DATE = "date";
16
17 public static final String PROPERTY_NAME_ZONE = "zone";
18
19 private PropertyChangeSupport changeSupport = new PropertyChangeSupport(
20 this);
21
22 private Locale locale;
23
24 private TimeZone zone;
25
26 private Calendar calendar;
27
28 public YearSpinnerModel(Date date, Locale locale, TimeZone zone) {
29 this.locale = locale;
30 this.zone = zone;
31 createLocaleAndZoneSensitive();
32 calendar.setTime(date);
33 }
34
35 private void createLocaleAndZoneSensitive() {
36 if (calendar != null) {
37 Date old = calendar.getTime();
38 calendar = Calendar.getInstance(zone, locale);
39 calendar.setTime(old);
40 } else
41 calendar = Calendar.getInstance(zone, locale);
42 }
43
44 public Object getValue() {
45 return new Integer(calendar.get(Calendar.YEAR));
46 }
47
48 public void setValue(Object value) {
49 Number newVal = (Number) value;
50 Number oldVal = (Number) getValue();
51 if (oldVal.longValue() != newVal.longValue()) {
52
53 int diff = newVal.intValue() - oldVal.intValue();
54 int sign = diff > 0 ? 1 : -1;
55 if (diff < 0)
56 diff = -diff;
57 Date oldDate = calendar.getTime();
58
59 for (int i = 0; i < diff; i++)
60 calendar.add(Calendar.YEAR, sign);
61
62 changeSupport.firePropertyChange(PROPERTY_NAME_DATE, oldDate,
63 getDate());
64 fireStateChanged();
65 }
66 }
67
68 public Object getNextValue() {
69
70 Integer currVal = (Integer) getValue();
71 int newVal = currVal.intValue() + 1;
72
73 if (newVal <= calendar.getActualMaximum(Calendar.YEAR))
74 return new Integer(newVal);
75
76 return currVal;
77 }
78
79 public Object getPreviousValue() {
80 Integer currVal = (Integer) getValue();
81 int newVal = currVal.intValue() - 1;
82
83 if (newVal >= calendar.getActualMinimum(Calendar.YEAR))
84 return new Integer(newVal);
85
86 return currVal;
87 }
88
89 public Date getDate() {
90 return calendar.getTime();
91 }
92
93 public void setDate(Date date) {
94 Date old = calendar.getTime();
95 if (!old.equals(date)) {
96 calendar.setTime(date);
97 changeSupport.firePropertyChange(PROPERTY_NAME_DATE, old, date);
98 fireStateChanged();
99 }
100 }
101
102 public Locale getLocale() {
103 return locale;
104 }
105
106 public void setLocale(Locale locale) {
107 Locale old = this.locale;
108 this.locale = locale;
109 createLocaleAndZoneSensitive();
110 changeSupport.firePropertyChange(PROPERTY_NAME_LOCALE, old, locale);
111 fireStateChanged();
112 }
113
114 public TimeZone getZone() {
115 return zone;
116 }
117
118 public void setZone(TimeZone zone) {
119 TimeZone old = this.zone;
120 this.zone = zone;
121 createLocaleAndZoneSensitive();
122 changeSupport.firePropertyChange(PROPERTY_NAME_LOCALE, old, locale);
123 fireStateChanged();
124 }
125
126 public void addPropertyChangeListener(PropertyChangeListener listener) {
127 changeSupport.addPropertyChangeListener(listener);
128 }
129
130 public void addPropertyChangeListener(String propertyName,
131 PropertyChangeListener listener) {
132 changeSupport.addPropertyChangeListener(propertyName, listener);
133 }
134
135 public void removePropertyChangeListener(PropertyChangeListener listener) {
136 changeSupport.removePropertyChangeListener(listener);
137 }
138
139 public void removePropertyChangeListener(String propertyName,
140 PropertyChangeListener listener) {
141 changeSupport.removePropertyChangeListener(propertyName, listener);
142 }
143
144 public PropertyChangeListener[] getPropertyChangeListeners() {
145 return changeSupport.getPropertyChangeListeners();
146 }
147
148 public PropertyChangeListener[] getPropertyChangeListeners(
149 String propertyName) {
150 return changeSupport.getPropertyChangeListeners(propertyName);
151 }
152
153 public boolean hasListeners(String propertyName) {
154 return changeSupport.hasListeners(propertyName);
155 }
156
157 }
0 package com.michaelbaranov.microba.common;
1
2 import java.beans.PropertyChangeEvent;
3 import java.beans.PropertyChangeListener;
4 import java.beans.PropertyChangeSupport;
5
6 import javax.swing.table.AbstractTableModel;
7
8 /**
9 * A simple abstract implementation of <code>BoundedTableModel</code>. A
10 * convenience class.
11 *
12 * @author Michael Baranov
13 */
14 public abstract class AbstractBoundedTableModel extends AbstractTableModel
15 implements BoundedTableModel {
16
17 private PropertyChangeSupport propertySupport=new PropertyChangeSupport(this);
18
19 public void addPropertyChangeListener(PropertyChangeListener listener) {
20 propertySupport.addPropertyChangeListener(listener);
21 }
22
23 public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
24 propertySupport.addPropertyChangeListener(propertyName, listener);
25 }
26
27 public void firePropertyChange(PropertyChangeEvent evt) {
28 propertySupport.firePropertyChange(evt);
29 }
30
31 public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) {
32 propertySupport.firePropertyChange(propertyName, oldValue, newValue);
33 }
34
35 public void firePropertyChange(String propertyName, int oldValue, int newValue) {
36 propertySupport.firePropertyChange(propertyName, oldValue, newValue);
37 }
38
39 public void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
40 propertySupport.firePropertyChange(propertyName, oldValue, newValue);
41 }
42
43 public PropertyChangeListener[] getPropertyChangeListeners() {
44 return propertySupport.getPropertyChangeListeners();
45 }
46
47 public PropertyChangeListener[] getPropertyChangeListeners(String propertyName) {
48 return propertySupport.getPropertyChangeListeners(propertyName);
49 }
50
51 public boolean hasListeners(String propertyName) {
52 return propertySupport.hasListeners(propertyName);
53 }
54
55 public void removePropertyChangeListener(PropertyChangeListener listener) {
56 propertySupport.removePropertyChangeListener(listener);
57 }
58
59 public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
60 propertySupport.removePropertyChangeListener(propertyName, listener);
61 }
62
63 }
0 package com.michaelbaranov.microba.common;
1
2 import java.util.EventListener;
3
4 import javax.swing.DefaultListSelectionModel;
5 import javax.swing.ListSelectionModel;
6 import javax.swing.event.ListSelectionListener;
7
8 /**
9 * A simple abstract implementation of <code>BoundedTableModel</code> with
10 * implemented <code>ListSelectionModel</code> functionality. A convenience
11 * class.
12 *
13 * @author Michael Baranov
14 *
15 */
16 public abstract class AbstractBoundedTableModelWithSelection extends
17 AbstractBoundedTableModel implements ListSelectionModel {
18
19 private DefaultListSelectionModel selection = new DefaultListSelectionModel();
20
21 public AbstractBoundedTableModelWithSelection() {
22 super();
23 }
24
25 public void addListSelectionListener(ListSelectionListener l) {
26 selection.addListSelectionListener(l);
27 }
28
29 public void addSelectionInterval(int index0, int index1) {
30 selection.addSelectionInterval(index0, index1);
31 }
32
33 public void clearSelection() {
34 selection.clearSelection();
35 }
36
37 public int getAnchorSelectionIndex() {
38 return selection.getAnchorSelectionIndex();
39 }
40
41 public int getLeadSelectionIndex() {
42 return selection.getLeadSelectionIndex();
43 }
44
45 public EventListener[] getListeners(Class listenerType) {
46 return selection.getListeners(listenerType);
47 }
48
49 public ListSelectionListener[] getListSelectionListeners() {
50 return selection.getListSelectionListeners();
51 }
52
53 public int getMaxSelectionIndex() {
54 return selection.getMaxSelectionIndex();
55 }
56
57 public int getMinSelectionIndex() {
58 return selection.getMinSelectionIndex();
59 }
60
61 public int getSelectionMode() {
62 return selection.getSelectionMode();
63 }
64
65 public boolean getValueIsAdjusting() {
66 return selection.getValueIsAdjusting();
67 }
68
69 public void insertIndexInterval(int index, int length, boolean before) {
70 selection.insertIndexInterval(index, length, before);
71 }
72
73 public boolean isLeadAnchorNotificationEnabled() {
74 return selection.isLeadAnchorNotificationEnabled();
75 }
76
77 public boolean isSelectedIndex(int index) {
78 return selection.isSelectedIndex(index);
79 }
80
81 public boolean isSelectionEmpty() {
82 return selection.isSelectionEmpty();
83 }
84
85 // J2SE5
86 // ////////////////////////////////////////////////////
87 // public void moveLeadSelectionIndex(int leadIndex) {
88 // selection.moveLeadSelectionIndex(leadIndex);
89 // }
90
91 public void removeIndexInterval(int index0, int index1) {
92 selection.removeIndexInterval(index0, index1);
93 }
94
95 public void removeListSelectionListener(ListSelectionListener l) {
96 selection.removeListSelectionListener(l);
97 }
98
99 public void removeSelectionInterval(int index0, int index1) {
100 selection.removeSelectionInterval(index0, index1);
101 }
102
103 public void setAnchorSelectionIndex(int anchorIndex) {
104 selection.setAnchorSelectionIndex(anchorIndex);
105 }
106
107 public void setLeadAnchorNotificationEnabled(boolean flag) {
108 selection.setLeadAnchorNotificationEnabled(flag);
109 }
110
111 public void setLeadSelectionIndex(int leadIndex) {
112 selection.setLeadSelectionIndex(leadIndex);
113 }
114
115 public void setSelectionInterval(int index0, int index1) {
116 selection.setSelectionInterval(index0, index1);
117 }
118
119 public void setSelectionMode(int selectionMode) {
120 selection.setSelectionMode(selectionMode);
121 }
122
123 public void setValueIsAdjusting(boolean isAdjusting) {
124 selection.setValueIsAdjusting(isAdjusting);
125 }
126
127 }
0 package com.michaelbaranov.microba.common;
1
2 import javax.swing.event.EventListenerList;
3
4
5 /**
6 * This is a convenience implementation of {@link Policy}.
7 *
8 * @author Michael Baranov
9 *
10 */
11 public abstract class AbstractPolicy implements Policy {
12 private EventListenerList vetoPolicyListenerList = new EventListenerList();
13
14 public void addVetoPolicyListener(PolicyListener listener) {
15 vetoPolicyListenerList.add(PolicyListener.class, listener);
16 }
17
18 public void removeVetoPolicyListener(PolicyListener listener) {
19 vetoPolicyListenerList.remove(PolicyListener.class, listener);
20
21 }
22
23 /**
24 * Fires a {@link PolicyEvent} to all related {@link PolicyListener}s.
25 */
26 protected void fireVetoPolicyChangeAction() {
27 Object[] listeners = vetoPolicyListenerList.getListenerList();
28
29 for (int i = listeners.length - 2; i >= 0; i -= 2)
30 if (listeners[i] == PolicyListener.class)
31 ((PolicyListener) listeners[i + 1])
32 .policyChanged(new PolicyEvent(this));
33 }
34
35 }
0 package com.michaelbaranov.microba.common;
1
2 import java.beans.PropertyChangeListener;
3
4 import javax.swing.table.TableModel;
5
6 /**
7 * An extended <code>TableModel</code>.
8 * <p>
9 * The upper and lower bound values are introduced to further describe table
10 * data. For example, <code>BoundedTableModel</code> is used as a data model
11 * for <code>{@link com.michaelbaranov.microba.marker.MarkerBar}</code>,
12 * <code>{@link com.michaelbaranov.microba.gradient.GradientBar}</code>,
13 * <code>{@link com.michaelbaranov.microba.gradienteditor.GradientEditor}</code>
14 *
15 * @version 0.1 (rev. 13 Aug 2005)
16 * @author Michael Baranov <a
17 * href=http://www.michaelbaranov.com>www.michaelbaranov.com</a>
18 *
19 */
20 public interface BoundedTableModel extends TableModel {
21
22 /**
23 * The name of the bound property, that holds lower bound value.
24 */
25 public static final String PROPERTY_LOWER_BOUND = "lowerBound";
26
27 /**
28 * The name of the bound property, that holds upper bound value.
29 */
30 public static final String PROPERTY_UPPER_BOUND = "upperBound";
31
32 /**
33 * Returns some lower bound, further describing the data.
34 *
35 * @return lower bound.
36 */
37 int getLowerBound();
38
39 /**
40 * Returns some upper bound, further describing the data.
41 *
42 * @return upper bound.
43 */
44 int getUpperBound();
45
46 public void addPropertyChangeListener(PropertyChangeListener listener);
47
48 public void addPropertyChangeListener(String propertyName,
49 PropertyChangeListener listener);
50
51 public void removePropertyChangeListener(PropertyChangeListener listener);
52
53 public void removePropertyChangeListener(String propertyName,
54 PropertyChangeListener listener);
55
56 }
0 package com.michaelbaranov.microba.common;
1
2 import java.util.EventObject;
3
4 /**
5 * An event used to indicate a change to a control has been commited or reverted
6 * (rolled back).
7 *
8 * @author Michael Baranov
9 *
10 */
11 public class CommitEvent extends EventObject {
12
13 private boolean commit;
14
15 /**
16 * Constructor.
17 *
18 * @param source
19 * a control that fired the event
20 * @param commit
21 * <code>true</code> to indicate commit, <code>false</code>
22 * to indicate revert (rollback)
23 */
24 public CommitEvent(Object source, boolean commit) {
25 super(source);
26 this.commit = commit;
27 }
28
29 /**
30 * Returns the type of the event.
31 *
32 * @return <code>true</code> if a change has been commited to a control,
33 * <code>false</code> otherwise.
34 */
35 public boolean isCommit() {
36 return commit;
37 }
38
39 }
0 package com.michaelbaranov.microba.common;
1
2 import java.util.EventListener;
3
4 /**
5 * A listener that is notified of {@link CommitEvent} events.
6 *
7 * @author Michael Baranov
8 *
9 */
10 public interface CommitListener extends EventListener {
11 /**
12 * Called when a {@link CommitEvent} is fired.
13 *
14 * @param event
15 */
16 public void commit(CommitEvent event);
17
18 }
0 package com.michaelbaranov.microba.common;
1
2 import java.awt.Color;
3 import java.util.Collections;
4 import java.util.Map;
5
6 import javax.swing.JComponent;
7 import javax.swing.UIManager;
8 import javax.swing.plaf.ComponentUI;
9
10 import com.michaelbaranov.microba.Microba;
11
12 /**
13 * Superclass for all Microba GUI components.
14 *
15 * @author Michael Baranov
16 *
17 */
18 public class MicrobaComponent extends JComponent {
19
20 public static final String PROPERTY_NAME_COLOR_OVERRIDE_MAP = "colorOverrideMap";
21
22 static {
23 Microba.init();
24 }
25
26 protected Map colorOverrideMap;
27
28 public ComponentUI getUI() {
29 return ui;
30 }
31
32 /**
33 * Sets the UI delegate of this component to the corresponding UI delegate
34 * taken from UIManager.
35 * <p>
36 * This implementation has a workarount to fix the problem with non-standard
37 * class-loaders.
38 */
39 public void updateUI() {
40 UIManager.getDefaults().put(UIManager.get(this.getUIClassID()), null);
41 ComponentUI delegate = UIManager.getUI(this);
42
43 setUI(delegate);
44 invalidate();
45 }
46
47 /**
48 * Returns per-instance (only for this instance) map of color overrides. May
49 * be <code>null</code>.
50 * <p>
51 * NOTE: returned map is unmodifiable. Use {@link #setColorOverrideMap(Map)}
52 * to change the map.
53 *
54 * @return keys in the map are {@link String} constants, valuse are of type
55 * {@link Color} or of type {@link String} (in this case,
56 * {@link Color} values are obtained via
57 * {@link UIManager#getColor(Object)})
58 */
59 public Map getColorOverrideMap() {
60 if (colorOverrideMap == null)
61 return null;
62
63 return Collections.unmodifiableMap(colorOverrideMap);
64 }
65
66 /**
67 * Sets per-instance (only for this instance) map of color overrides.
68 *
69 * @param colorOverrideMap
70 * keys in the map are {@link String} constants, valuse are of
71 * type {@link Color} or of type {@link String} (in this case,
72 * {@link Color} values are obtained via
73 * {@link UIManager#getColor(Object)}). May be <code>null</code>.
74 */
75 public void setColorOverrideMap(Map colorOverrideMap) {
76 Object old = this.colorOverrideMap;
77 this.colorOverrideMap = colorOverrideMap;
78 firePropertyChange(PROPERTY_NAME_COLOR_OVERRIDE_MAP, old,
79 colorOverrideMap);
80
81 updateUI();
82 }
83
84 }
0 package com.michaelbaranov.microba.common;
1
2 public interface Policy {
3 /**
4 * Adds a {@link PolicyListener}.
5 *
6 * @param listener
7 * a {@link PolicyListener} to add
8 */
9 public void addVetoPolicyListener(PolicyListener listener);
10
11 /**
12 * Removes a {@link PolicyListener}.
13 *
14 * @param listener
15 * a {@link PolicyListener} to remove
16 */
17 public void removeVetoPolicyListener(PolicyListener listener);
18 }
0 package com.michaelbaranov.microba.common;
1
2 import java.util.EventObject;
3
4 /**
5 * An event used to indicate a policy (algorithm) has changed.
6 *
7 * @author Michael Baranov
8 *
9 */
10 public class PolicyEvent extends EventObject {
11
12 /**
13 * Constructor.
14 *
15 * @param source
16 * an object whose policy has changed
17 */
18 public PolicyEvent(Object source) {
19 super(source);
20 }
21
22 }
0 package com.michaelbaranov.microba.common;
1
2 import java.util.EventListener;
3
4 /**
5 * A listener that is notified of {@link PolicyEvent} events.
6 *
7 * @author Michael Baranov
8 *
9 */
10 public interface PolicyListener extends EventListener {
11
12 /**
13 * Called when a {@link PolicyEvent} is fired.
14 *
15 * @param event
16 */
17 public void policyChanged(PolicyEvent event);
18 }
0 package com.michaelbaranov.microba.demo;
1
2 import java.awt.BorderLayout;
3 import java.awt.Color;
4 import java.awt.GridBagConstraints;
5 import java.awt.GridBagLayout;
6 import java.awt.Insets;
7 import java.awt.event.ActionEvent;
8 import java.awt.event.ActionListener;
9 import java.awt.event.MouseAdapter;
10 import java.awt.event.MouseEvent;
11 import java.awt.event.MouseListener;
12 import java.beans.PropertyVetoException;
13 import java.text.SimpleDateFormat;
14 import java.util.Calendar;
15 import java.util.Date;
16 import java.util.HashMap;
17 import java.util.Map;
18
19 import javax.swing.JApplet;
20 import javax.swing.JColorChooser;
21 import javax.swing.JComponent;
22 import javax.swing.JFrame;
23 import javax.swing.JPanel;
24 import javax.swing.JScrollPane;
25 import javax.swing.JTabbedPane;
26 import javax.swing.JTable;
27 import javax.swing.SwingConstants;
28 import javax.swing.event.ChangeEvent;
29 import javax.swing.event.ChangeListener;
30 import javax.swing.event.ListSelectionEvent;
31 import javax.swing.event.ListSelectionListener;
32
33 import com.michaelbaranov.microba.calendar.CalendarPane;
34 import com.michaelbaranov.microba.calendar.DatePicker;
35 import com.michaelbaranov.microba.calendar.DatePickerCellEditor;
36 import com.michaelbaranov.microba.calendar.HolidayPolicy;
37 import com.michaelbaranov.microba.common.AbstractPolicy;
38 import com.michaelbaranov.microba.common.BoundedTableModel;
39 import com.michaelbaranov.microba.common.PolicyListener;
40 import com.michaelbaranov.microba.gradient.GradientBar;
41 import com.michaelbaranov.microba.gradienteditor.GradientEditor;
42 import com.michaelbaranov.microba.marker.MarkerBar;
43
44 public class Demo extends JApplet {
45
46 static MarkerBar bar;
47
48 static BoundedTableModel model;
49
50 private static JFrame frame;
51
52 private static JPanel panel;
53
54 public static void main(String[] s) {
55
56 Demo demo = new Demo();
57 demo.run();
58
59 }
60
61 private void run() {
62 frame = new JFrame();
63 frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
64 frame.getContentPane().setLayout(new BorderLayout());
65
66 JTabbedPane tabs = new JTabbedPane();
67 tabs.addTab("CalendarPane", buildCalendarPaneTab());
68 tabs.addTab("Gradient", buildGradientTab());
69 tabs.addTab("CellEditor", buildCellEditorTab());
70 tabs.addTab("DatePicker", buildDatePickerTab());
71
72 frame.getContentPane().add(tabs, BorderLayout.CENTER);
73 frame.setSize(500, 300);
74 frame.setVisible(true);
75
76 }
77
78 //
79 // public void init() {
80 // super.init();
81 // System.out.println("init");
82 // panel = new JPanel();
83 // panel.setLayout(new BorderLayout());
84 //
85 // JTabbedPane tabs = new JTabbedPane();
86 // tabs.addTab("CalendarPane", buildCalendarPaneTab());
87 // tabs.addTab("Gradient", buildGradientTab());
88 // tabs.addTab("CellEditor", buildCellEditorTab());
89 // tabs.addTab("DatePicker", buildDatePickerTab());
90 //
91 // panel.add(tabs, BorderLayout.CENTER);
92 // this.setContentPane(panel);
93 // }
94
95 public void start() {
96 System.out.println("start");
97 super.start();
98 }
99
100 public void stop() {
101 System.out.println("stop");
102 super.stop();
103 }
104
105 private class Hol extends AbstractPolicy implements HolidayPolicy {
106
107 public String getHollidayName(Object source, Calendar date) {
108 return null;
109 }
110
111 public boolean isHolliday(Object source, Calendar date) {
112 return false;
113 }
114
115 public boolean isWeekend(Object source, Calendar date) {
116 return date.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY;
117 }
118
119 }
120
121 private JComponent buildCalendarPaneTab() {
122 JPanel panel = new JPanel();
123 final CalendarPane calendarPane = new CalendarPane();
124
125 // calendarPane.setEnabled(false);
126 calendarPane.setHolidayPolicy(new Hol());
127
128 Map ov = new HashMap();
129
130 ov.put(CalendarPane.COLOR_CALENDAR_GRID_FOREGROUND_ENABLED,
131 Color.ORANGE);
132
133 calendarPane.setColorOverrideMap(ov);
134
135 try {
136 calendarPane.setDate(new Date());
137 } catch (PropertyVetoException e) {
138 // TODO Auto-generated catch block
139 e.printStackTrace();
140 }
141
142 calendarPane.addActionListener(new ActionListener() {
143
144 public void actionPerformed(ActionEvent e) {
145 System.out.println("CalendarPane:" + calendarPane.getDate());
146
147 }
148 });
149
150 panel.setLayout(new GridBagLayout());
151 panel.add(calendarPane, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0,
152 GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(
153 5, 5, 5, 5), 0, 0));
154
155 panel.addMouseListener(new MouseAdapter() {
156 public void mouseClicked(MouseEvent e) {
157 calendarPane.observeMonth(2009, 4);
158 }
159 });
160
161 return panel;
162
163 }
164
165 private JComponent buildDatePickerTab() {
166 JPanel panel = new JPanel();
167 final DatePicker datePicker = new DatePicker();
168 // datePicker.setDateFormat(new SimpleDateFormat("HH dd yyyy"));
169 datePicker.setDateFormat(SimpleDateFormat.getDateTimeInstance());
170 // datePicker.setStripTime(false);
171 datePicker.setEnabled(false);
172 datePicker.setKeepTime(true);
173 datePicker.setStripTime(false);
174 datePicker.setShowNumberOfWeek(true);
175 // datePicker.setEnabled(false);
176 // datePicker.setPickerStyle(DatePicker.PICKER_STYLE_BUTTON);
177 // datePicker.showButtonOnly(false);
178 // datePicker.setToolTipText("hello!!!!");
179 // datePicker.setShowNumberOfWeek(true);
180
181 Map ov = new HashMap();
182
183 ov.put(CalendarPane.COLOR_CALENDAR_GRID_FOREGROUND_ENABLED,
184 Color.ORANGE);
185
186 datePicker.setColorOverrideMap(ov);
187
188 panel.setLayout(new GridBagLayout());
189 panel.add(datePicker, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0,
190 GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(
191 5, 5, 5, 5), 0, 0));
192
193 datePicker.addActionListener(new ActionListener() {
194
195 public void actionPerformed(ActionEvent e) {
196 System.out.println("DatePicker:" + datePicker.getDate());
197
198 }
199 });
200
201 panel.addMouseListener(new MouseListener() {
202
203 public void mouseClicked(MouseEvent e) {
204 try {
205 datePicker.setDate(null);
206 } catch (PropertyVetoException e1) {
207 // TODO Auto-generated catch block
208 e1.printStackTrace();
209 }
210
211 }
212
213 public void mouseEntered(MouseEvent e) {
214 // TODO Auto-generated method stub
215
216 }
217
218 public void mouseExited(MouseEvent e) {
219 // TODO Auto-generated method stub
220
221 }
222
223 public void mousePressed(MouseEvent e) {
224 // TODO Auto-generated method stub
225
226 }
227
228 public void mouseReleased(MouseEvent e) {
229 // TODO Auto-generated method stub
230
231 }
232 });
233
234 return panel;
235
236 }
237
238 private JComponent buildCellEditorTab() {
239 JPanel panel = new JPanel();
240 DatePicker datePicker = new DatePicker();
241
242 datePicker.setDropdownFocusable(true);
243
244 DatePickerCellEditor cellEditor = new DatePickerCellEditor(datePicker);
245 cellEditor.setClickCountToStart(2);
246
247 JTable table = new JTable(100, 3);
248 table.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
249 JScrollPane scrollPane = new JScrollPane(table);
250
251 table.getColumnModel().getColumn(0).setCellEditor(cellEditor);
252
253 panel.setLayout(new GridBagLayout());
254 panel.add(scrollPane, new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0,
255 GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(
256 5, 5, 5, 5), 0, 0));
257 return panel;
258
259 }
260
261 private JComponent buildGradientTab() {
262 JPanel panel = new JPanel();
263 GradientBar gradient;
264
265 GradientEditor editor;
266 JColorChooser colorChooser;
267
268 colorChooser = new JColorChooser();
269 editor = new GradientEditor();
270
271 // editor.setOrientation(SwingConstants.VERTICAL);
272
273 ColorAdaptor adaptor = new ColorAdaptor(editor, colorChooser);
274
275 panel.add(editor, BorderLayout.NORTH);
276 panel.add(colorChooser, BorderLayout.CENTER);
277
278 MarkerBar bar = new MarkerBar();
279 bar.setDataModel(editor.getDataModel());
280 bar.setPositionColumn(editor.getColorPositionColumn());
281 bar.setColorColumn(editor.getColorColumn());
282 bar.setFliped(true);
283 bar.setOrientation(SwingConstants.VERTICAL);
284 panel.add(bar, BorderLayout.EAST);
285 return panel;
286 }
287
288 private static class ColorAdaptor implements ChangeListener,
289 ListSelectionListener {
290
291 private GradientEditor editor;
292
293 private JColorChooser chooser;
294
295 public ColorAdaptor(GradientEditor editor, JColorChooser chooser) {
296 super();
297 this.editor = editor;
298 this.chooser = chooser;
299
300 editor.getColorSelectionModel().addListSelectionListener(this);
301 chooser.getSelectionModel().addChangeListener(this);
302 }
303
304 public void valueChanged(ListSelectionEvent e) {
305 int index = editor.getColorSelectionModel().getLeadSelectionIndex();
306 // System.out.println(index);
307 // System.out.println(e.getFirstIndex());
308 // System.out.println(e.getLastIndex());
309 // System.out.println("-------");
310
311 Color c = (Color) editor.getDataModel().getValueAt(index,
312 editor.getColorColumn());
313 chooser.setColor(c);
314 }
315
316 public void stateChanged(ChangeEvent e) {
317
318 if (!editor.getColorSelectionModel().isSelectionEmpty()) {
319 int index = editor.getColorSelectionModel()
320 .getLeadSelectionIndex();
321
322 editor.getDataModel().setValueAt(chooser.getColor(), index,
323 editor.getColorColumn());
324 }
325
326 }
327
328 }
329
330 }
0 package com.michaelbaranov.microba.gradient;
1
2 import java.awt.Color;
3 import java.util.ArrayList;
4 import java.util.List;
5
6 import com.michaelbaranov.microba.common.AbstractBoundedTableModel;
7
8 /**
9 * A very basic implementation of {@link AbstractBoundedTableModel} used by
10 * default by {@link GradientBar}. This implementation has bounds 0 - 100 and
11 * is mutable.
12 *
13 * @author Michael Baranov
14 *
15 */
16 public class DefaultGradientModel extends AbstractBoundedTableModel {
17
18 protected static final int POSITION_COLUMN = 0;
19
20 protected static final int COLOR_COLUMN = 1;
21
22 protected List positionList = new ArrayList(32);
23
24 protected List colorList = new ArrayList(32);
25
26 /**
27 * Constructor.
28 */
29 public DefaultGradientModel() {
30 super();
31 positionList.add(new Integer(0));
32 colorList.add(Color.YELLOW);
33
34 positionList.add(new Integer(50));
35 colorList.add(Color.RED);
36
37 positionList.add(new Integer(100));
38 colorList.add(Color.GREEN);
39 }
40
41 public int getLowerBound() {
42 return 0;
43 }
44
45 public int getUpperBound() {
46 return 100;
47 }
48
49 public int getRowCount() {
50 return positionList.size();
51 }
52
53 public int getColumnCount() {
54 return 2;
55 }
56
57 public Class getColumnClass(int columnIndex) {
58 switch (columnIndex) {
59 case POSITION_COLUMN:
60 return Integer.class;
61 case COLOR_COLUMN:
62 return Color.class;
63 }
64 return super.getColumnClass(columnIndex);
65 }
66
67 public Object getValueAt(int rowIndex, int columnIndex) {
68 switch (columnIndex) {
69 case POSITION_COLUMN:
70 return positionList.get(rowIndex);
71 case COLOR_COLUMN:
72 return colorList.get(rowIndex);
73 }
74 return null;
75 }
76
77 /**
78 * Adds a color point.
79 *
80 * @param color
81 * @param position
82 */
83 public void add(Color color, int position) {
84 colorList.add(color);
85 positionList.add(new Integer(position));
86 fireTableDataChanged();
87 }
88
89 /**
90 * Removes a color point at specified index.
91 *
92 * @param index
93 */
94 public void remove(int index) {
95 colorList.remove(index);
96 positionList.remove(index);
97 fireTableDataChanged();
98 }
99
100 /**
101 * Removes all color points.
102 */
103 public void clear() {
104 colorList.clear();
105 positionList.clear();
106 fireTableDataChanged();
107 }
108
109 }
0 package com.michaelbaranov.microba.gradient;
1
2 import java.awt.Color;
3
4 import javax.swing.SwingConstants;
5
6 import com.michaelbaranov.microba.common.BoundedTableModel;
7 import com.michaelbaranov.microba.common.MicrobaComponent;
8
9 /**
10 * IMPORTANT: alpha featre not implemented. Stubs only.
11 * <p>
12 *
13 * A concrete implementation of JComponent. Displays an area filled with
14 * gradient color (palette). The color and alpha value (transparency) is
15 * linearly interpolated between key points.
16 * <p>
17 * The color key points are provided by the data model in combination with color
18 * column (index) and color position column (index). Each row in the model
19 * represents a colored key point. Color values are expected to be of type
20 * {@link Color} and position values of type {@link Number} with integer
21 * precision.
22 * <p>
23 * The alpha key points are provided by the alpha model in combination with
24 * alpha column (index) and alpha position column (index). Each row in the model
25 * represents an alpha key point. Alpha values are expected to be of type
26 * {@link Number} with floating-point precision ranging form 0.0f (transparent)
27 * to 1.0f (opaque) and position values of type {@link Number} with integer
28 * precision.
29 *
30 * Example:
31 *
32 * <pre>
33 * GradientBar bar = new GradientBar();
34 * bar.setDataModel(myColorModel);
35 * bar.setColorColumn(0);
36 * bar.setColorPositionColumn(1);
37 *
38 * bar.setAlphaModel(myAlphaModel);
39 * bar.setAlphaColumn(1);
40 * bar.setAlphaPositionColumn(0);
41 * </pre>
42 *
43 * @author Michael Baranov
44 *
45 */
46 public class GradientBar extends MicrobaComponent {
47
48 /**
49 * The name of a "dataModel" property.
50 */
51 public static final String PROPERTY_DATA_MODEL = "dataModel";
52
53 /**
54 * The name of a "alphaModel" property.
55 */
56 public static final String PROPERTY_ALPHA_MODEL = "alphaModel";
57
58 /**
59 * The name of a "colorPositionColumn" property.
60 */
61 public static final String PROPERTY_COLOR_POSITION_COLUMN = "colorPositionColumn";
62
63 /**
64 * The name of a "alphaPositionColumn" property.
65 */
66 public static final String PROPERTY_ALPHA_POSITION_COLUMN = "alphaPositionColumn";
67
68 /**
69 * The name of a "colorColumn" property.
70 */
71 public static final String PROPERTY_COLOR_COLUMN = "colorColumn";
72
73 /**
74 * The name of a "alphaColumn" property.
75 */
76 public static final String PROPERTY_ALPHA_COLUMN = "alphaColumn";
77
78 /**
79 * The name of a "orientation" property.
80 */
81 public static final String PROPERTY_ORIENTATION = "orientation";
82
83 private static final String uiClassID = "microba.GradientUI";
84
85 protected BoundedTableModel dataModel;
86
87 protected BoundedTableModel alphaModel;
88
89 protected int colorPositionColumn = 0;
90
91 protected int alphaPositionColumn = 0;
92
93 protected int colorColumn = 1;
94
95 protected int alphaColumn = 1;
96
97 protected int orientation = SwingConstants.HORIZONTAL;
98
99 public String getUIClassID() {
100 return uiClassID;
101 }
102
103 /**
104 * Constructor.
105 */
106 public GradientBar() {
107 super();
108 dataModel = new DefaultGradientModel();
109 setFocusable(false);
110 updateUI();
111 }
112
113 /**
114 * Constructor.
115 */
116 public GradientBar(BoundedTableModel model) {
117 super();
118 dataModel = model;
119 setFocusable(false);
120 updateUI();
121 }
122
123 /**
124 * Constructor.
125 */
126 public GradientBar(BoundedTableModel model, int orientation) {
127 super();
128 dataModel = model;
129 this.orientation = orientation;
130 setFocusable(false);
131 updateUI();
132 }
133
134 /**
135 * Returns the index of the color column for the data model.
136 *
137 * @return index of color column
138 * @see #setColorColumn(int)
139 */
140 public int getColorColumn() {
141 return colorColumn;
142 }
143
144 /**
145 * Sets the index of the color column for the data model.
146 *
147 * @param colorColumn
148 * index of color column
149 * @see #getColorColumn()
150 */
151 public void setColorColumn(int colorColumn) {
152 int old = this.colorColumn;
153 this.colorColumn = colorColumn;
154 firePropertyChange(PROPERTY_COLOR_COLUMN, old, colorColumn);
155 }
156
157 /**
158 * Returns the index of the alpha column for the alpha model.
159 *
160 * @return index of alpha column
161 * @see #setAlphaColumn(int)
162 */
163 public int getAlphaColumn() {
164 return alphaColumn;
165 }
166
167 /**
168 * Sets the index of the alpha column for the alpha model.
169 *
170 * @param alphaColumn
171 * index of alpha column
172 * @see #getAlphaColumn()
173 */
174 public void setAlphaColumn(int alphaColumn) {
175 int old = this.colorColumn;
176 this.alphaColumn = alphaColumn;
177 firePropertyChange(PROPERTY_ALPHA_COLUMN, old, alphaColumn);
178 }
179
180 /**
181 * Regturns the current data model. The data model provides key points for
182 * interpolation (position & color).
183 *
184 * @return current data model
185 * @see #setDataModel(BoundedTableModel)
186 * @see #getColorColumn()
187 */
188 public BoundedTableModel getDataModel() {
189 return dataModel;
190 }
191
192 /**
193 * Sets the current data model. The data model provides key points for
194 * interpolation (position & color).
195 *
196 * @param dataModel
197 * current data model
198 * @see #getDataModel()
199 * @see #getColorColumn()
200 */
201 public void setDataModel(BoundedTableModel dataModel) {
202 BoundedTableModel old = this.dataModel;
203 this.dataModel = dataModel;
204 firePropertyChange(PROPERTY_DATA_MODEL, old, dataModel);
205 }
206
207 /**
208 * Regturns the current alpha model. The data model provides alpha key
209 * points for interpolation (position & alpha).
210 *
211 * @return current alpha model
212 * @see #setAlphaModel(BoundedTableModel)
213 * @see #getAlphaColumn()
214 */
215 public BoundedTableModel getAlphaModel() {
216 return alphaModel;
217 }
218
219 /**
220 * Sets the current alpha model. The alpha model provides alpha key points
221 * for interpolation (position & alpha).
222 *
223 * @param alphaModel
224 * current alpha model
225 * @see #getAlphaModel()
226 * @see #getAlphaColumn()
227 */
228 public void setAlphaModel(BoundedTableModel alphaModel) {
229 BoundedTableModel old = this.alphaModel;
230 this.alphaModel = alphaModel;
231 firePropertyChange(PROPERTY_ALPHA_MODEL, old, alphaModel);
232 }
233
234 /**
235 * Returns current orientation of the component. Possible values are:
236 * <ul>
237 * <li>SwingConstants.HORIZONTAL
238 * <li>SwingConstants.VERTICAL
239 * </ul>
240 *
241 * @return orientation
242 * @see #setOrientation(int)
243 */
244 public int getOrientation() {
245 return orientation;
246 }
247
248 /**
249 * Sets orientation of the component. Possible values are:
250 * <ul>
251 * <li>SwingConstants.HORIZONTAL
252 * <li>SwingConstants.VERTICAL
253 * </ul>
254 *
255 * @param orientation
256 */
257 public void setOrientation(int orientation) {
258 int old = this.orientation;
259 this.orientation = orientation;
260 firePropertyChange(PROPERTY_ORIENTATION, old, orientation);
261 }
262
263 /**
264 * Returns the index of the position column for the data model.
265 *
266 * @return index of position column
267 * @see #setColorPositionColumn(int)
268 */
269 public int getColorPositionColumn() {
270 return colorPositionColumn;
271 }
272
273 /**
274 * Sets the index of the position column for the data model.
275 *
276 * @param positionColumn
277 * index of position column
278 * @see #getColorPositionColumn()
279 */
280 public void setColorPositionColumn(int positionColumn) {
281 int old = this.colorPositionColumn;
282 this.colorPositionColumn = positionColumn;
283 firePropertyChange(PROPERTY_COLOR_POSITION_COLUMN, old, positionColumn);
284 }
285
286 /**
287 * Returns the index of the position column for the alpha model.
288 *
289 * @return index of position column
290 * @see #setAlphaPositionColumn(int)
291 */
292 public int getAlphaPositionColumn() {
293 return alphaPositionColumn;
294 }
295
296 /**
297 * Sets the index of the position column for the alpha model.
298 *
299 * @param positionColumn
300 * index of position column
301 * @see #getAlphaPositionColumn()
302 */
303 public void setAlphaPositionColumn(int positionColumn) {
304 int old = this.alphaPositionColumn;
305 this.alphaPositionColumn = positionColumn;
306 firePropertyChange(PROPERTY_ALPHA_POSITION_COLUMN, old, positionColumn);
307 }
308
309 }
0 package com.michaelbaranov.microba.gradient.ui;
1
2 import java.beans.PropertyChangeEvent;
3 import java.beans.PropertyChangeListener;
4
5 import javax.swing.event.TableModelEvent;
6 import javax.swing.event.TableModelListener;
7
8 import com.michaelbaranov.microba.common.BoundedTableModel;
9 import com.michaelbaranov.microba.gradient.GradientBar;
10 import com.michaelbaranov.microba.gradient.ui.basic.BasicGradientUI;
11
12 public class GradientListener implements TableModelListener,
13 PropertyChangeListener {
14
15 private final BasicGradientUI gradientUI;
16
17 private GradientBar gradient;
18
19 public GradientListener(BasicGradientUI gradientUI, GradientBar gradient) {
20 this.gradientUI = gradientUI;
21 this.gradient = gradient;
22 }
23
24 public void propertyChange(PropertyChangeEvent evt) {
25 if (GradientBar.PROPERTY_DATA_MODEL.equals(evt.getPropertyName())) {
26 BoundedTableModel oldModel = (BoundedTableModel) evt.getOldValue();
27 BoundedTableModel newModel = (BoundedTableModel) evt.getNewValue();
28
29 if (oldModel != null)
30 oldModel.removeTableModelListener(this);
31 if (newModel != null)
32 newModel.addTableModelListener(this);
33
34 gradient.revalidate();
35 }
36
37 if (GradientBar.PROPERTY_ORIENTATION.equals(evt.getPropertyName())) {
38 gradient.revalidate();
39 }
40 if (GradientBar.PROPERTY_COLOR_POSITION_COLUMN.equals(evt.getPropertyName())) {
41 gradient.repaint();
42 }
43 if (GradientBar.PROPERTY_COLOR_COLUMN.equals(evt.getPropertyName())) {
44 gradient.repaint();
45 }
46 if ("enabled".equals(evt.getPropertyName())) {
47 gradient.repaint();
48 }
49 }
50
51 public void tableChanged(TableModelEvent e) {
52 gradient.repaint();
53
54 }
55 }
0 package com.michaelbaranov.microba.gradient.ui;
1
2 import java.awt.Color;
3 import java.awt.Insets;
4 import java.awt.Rectangle;
5 import java.util.Arrays;
6 import java.util.Comparator;
7
8 import javax.swing.plaf.ComponentUI;
9
10 import com.michaelbaranov.microba.common.BoundedTableModel;
11 import com.michaelbaranov.microba.gradient.GradientBar;
12
13 public class GradientUI extends ComponentUI {
14
15 protected static final int PREF_BAR_HEIGHT = 32;
16
17 protected static Rectangle viewRect = new Rectangle();
18
19 private PreparedColorPoint colorPoints[] = new PreparedColorPoint[0];
20
21 private PreparedAlphaPoint alphaPoints[] = new PreparedAlphaPoint[0];
22
23 protected void calculateViewRect(GradientBar gradient) {
24 Insets insets = gradient.getInsets();
25 viewRect.x = insets.left;
26 viewRect.y = insets.top;
27 viewRect.width = gradient.getWidth() - (insets.right + viewRect.x);
28 viewRect.height = gradient.getHeight() - (insets.bottom + viewRect.y);
29
30 }
31
32 protected PreparedColorPoint[] prepareColorPoints(BoundedTableModel model,
33 int positionColumn, int colorColumn) {
34
35 int numPoints = model.getRowCount();
36
37 if (numPoints > colorPoints.length) {
38 colorPoints = new PreparedColorPoint[numPoints * 2];
39 for (int i = 0; i < colorPoints.length; i++)
40 colorPoints[i] = new PreparedColorPoint();
41 }
42
43 for (int i = 0; i < numPoints; i++) {
44 PreparedColorPoint p = colorPoints[i];
45 Color c = (Color) model.getValueAt(i, colorColumn);
46 p.position = ((Number) model.getValueAt(i, positionColumn))
47 .intValue();
48 p.r = c.getRed();
49 p.g = c.getGreen();
50 p.b = c.getBlue();
51 }
52
53 Arrays.sort(colorPoints, 0, numPoints, PreparedColorPoint.comparator);
54
55 return colorPoints;
56 }
57
58 protected PreparedAlphaPoint[] prepareAlphaPoints(BoundedTableModel model,
59 int positionColumn, int alphaColumn) {
60
61 int numPoints = model.getRowCount();
62
63 if (numPoints > alphaPoints.length) {
64 alphaPoints = new PreparedAlphaPoint[numPoints * 2];
65 for (int i = 0; i < alphaPoints.length; i++)
66 alphaPoints[i] = new PreparedAlphaPoint();
67 }
68
69 for (int i = 0; i < numPoints; i++) {
70 PreparedAlphaPoint p = alphaPoints[i];
71 float f = ((Number) model.getValueAt(i, alphaColumn)).floatValue();
72 p.position = ((Number) model.getValueAt(i, positionColumn))
73 .intValue();
74 p.alpha = f;
75 }
76
77 Arrays.sort(alphaPoints, 0, numPoints, PreparedAlphaPoint.comparator);
78
79 return alphaPoints;
80 }
81
82 protected static class PreparedColorPoint {
83 public static final Comparator comparator = new PtComparator();
84
85 public int r, g, b;
86
87 public int position;
88
89 public PreparedColorPoint() {
90 }
91
92 private static class PtComparator implements Comparator {
93 public int compare(Object o1, Object o2) {
94 PreparedColorPoint cp1 = (PreparedColorPoint) o1;
95 PreparedColorPoint cp2 = (PreparedColorPoint) o2;
96 if (cp1.position < cp2.position)
97 return -1;
98 if (cp1.position > cp2.position)
99 return 1;
100 return 0;
101 }
102 }
103 }
104
105 protected static class PreparedAlphaPoint {
106 public static final Comparator comparator = new PtComparator();
107
108 public float alpha;
109
110 public int position;
111
112 public PreparedAlphaPoint() {
113 }
114
115 private static class PtComparator implements Comparator {
116 public int compare(Object o1, Object o2) {
117 PreparedColorPoint cp1 = (PreparedColorPoint) o1;
118 PreparedColorPoint cp2 = (PreparedColorPoint) o2;
119 if (cp1.position < cp2.position)
120 return -1;
121 if (cp1.position > cp2.position)
122 return 1;
123 return 0;
124 }
125 }
126 }
127
128 }
0 package com.michaelbaranov.microba.gradient.ui.basic;
1
2 import java.awt.Color;
3 import java.awt.Dimension;
4 import java.awt.Graphics;
5 import java.awt.Graphics2D;
6 import java.awt.Insets;
7 import java.beans.PropertyChangeListener;
8
9 import javax.swing.JComponent;
10 import javax.swing.SwingConstants;
11 import javax.swing.plaf.ComponentUI;
12
13 import com.michaelbaranov.microba.common.BoundedTableModel;
14 import com.michaelbaranov.microba.gradient.GradientBar;
15 import com.michaelbaranov.microba.gradient.ui.GradientListener;
16 import com.michaelbaranov.microba.gradient.ui.GradientUI;
17
18 public class BasicGradientUI extends GradientUI {
19
20 public static ComponentUI createUI(JComponent c) {
21 return new BasicGradientUI();
22 }
23
24 public void installUI(JComponent component) {
25 installListeners((GradientBar) component);
26 }
27
28 public void uninstallUI(JComponent component) {
29 uninstallListeners((GradientBar) component);
30 }
31
32 protected void installListeners(GradientBar gradient) {
33 GradientListener listener = createListener(gradient);
34
35 if (gradient.getDataModel() != null)
36 gradient.getDataModel().addTableModelListener(listener);
37 gradient.addPropertyChangeListener(listener);
38 }
39
40 protected void uninstallListeners(GradientBar gradient) {
41 GradientListener listener = lookupListsner(gradient);
42 if (listener != null) {
43 if (gradient.getDataModel() != null)
44 gradient.getDataModel().removeTableModelListener(listener);
45 gradient.removePropertyChangeListener(listener);
46 }
47
48 }
49
50 protected GradientListener lookupListsner(GradientBar gradient) {
51 PropertyChangeListener[] listeners = gradient
52 .getPropertyChangeListeners();
53
54 if (listeners != null) {
55 for (int counter = 0; counter < listeners.length; counter++) {
56 if (listeners[counter] instanceof GradientListener) {
57 return (GradientListener) listeners[counter];
58 }
59 }
60 }
61 return null;
62 }
63
64 protected GradientListener createListener(GradientBar gradient) {
65 return new GradientListener(this, gradient);
66 }
67
68 public void paint(Graphics g, JComponent c) {
69 Graphics2D g2 = (Graphics2D) g;
70
71 GradientBar gradient = (GradientBar) c;
72
73 calculateViewRect(gradient);
74
75 BoundedTableModel colorModel = gradient.getDataModel();
76 BoundedTableModel alphaModel = gradient.getAlphaModel();
77
78 if (colorModel == null)
79 return;
80
81 // TODO: alpha support
82
83 int numColorPoints = colorModel.getRowCount();
84 int numAlphaPoints = alphaModel == null ? 0 : alphaModel.getRowCount();
85
86 int colorPositionColumn = gradient.getColorPositionColumn();
87 int colorColumn = gradient.getColorColumn();
88
89 int alphaPositionColumn = gradient.getAlphaPositionColumn();
90 int alphaColumn = gradient.getAlphaColumn();
91
92 switch (numColorPoints) {
93 case 0:
94 // draw checkers?
95 // g.drawString("no data", viewRect.x, viewRect.y +
96 // viewRect.height);
97 break;
98 case 1:
99 g.setColor((Color) colorModel.getValueAt(0, colorColumn));
100 g.fillRect(viewRect.x, viewRect.y, viewRect.width, viewRect.height);
101 break;
102 default:
103 PreparedColorPoint pts[] = prepareColorPoints(colorModel,
104 colorPositionColumn, colorColumn);
105 // PreparedAlphaPoint apts[] = prepareAlphaPoints(alphaModel,
106 // colorPositionColumn, colorColumn);
107
108 int range = colorModel.getUpperBound() - colorModel.getLowerBound();
109 boolean isHorizontal = gradient.getOrientation() == SwingConstants.HORIZONTAL;
110
111 for (int i = 0; i < numColorPoints - 1; i++) {
112 PreparedColorPoint p0 = pts[i];
113 PreparedColorPoint p1 = pts[i + 1];
114
115 int pos0 = p0.position - colorModel.getLowerBound();
116 int pos1 = p1.position - colorModel.getLowerBound();
117
118 int pixPos0;
119 int pixPos1;
120 if (isHorizontal) {
121 pixPos0 = viewRect.x + viewRect.width * pos0 / range;
122 pixPos1 = viewRect.x + viewRect.width * pos1 / range;
123 } else {
124 pixPos0 = viewRect.y + viewRect.height * pos0 / range;
125 pixPos1 = viewRect.y + viewRect.height * pos1 / range;
126 }
127
128 int pixDist = pixPos1 - pixPos0;
129
130 for (int t = pixPos0; t < pixPos1; t++) {
131 Color cc = interpolate(p0, p1, pixDist, t - pixPos0);
132 g2.setColor(cc);
133 if (isHorizontal)
134 g2.drawLine(t, viewRect.y, t, viewRect.y
135 + viewRect.height);
136 else
137 g2.drawLine(viewRect.x, t, viewRect.x + viewRect.width,
138 t);
139
140 }
141
142 }
143 break;
144 }
145
146 }
147
148 private Color interpolate(PreparedColorPoint p0, PreparedColorPoint p1,
149 int pixDist, int t) {
150 int r = p0.r + (p1.r - p0.r) * t / pixDist;
151 int g = p0.g + (p1.g - p0.g) * t / pixDist;
152 int b = p0.b + (p1.b - p0.b) * t / pixDist;
153 return new Color(r, g, b);
154 }
155
156 public Dimension getMinimumSize(JComponent c) {
157 return new Dimension(1, 1);
158 }
159
160 public Dimension getPreferredSize(JComponent c) {
161
162 GradientBar gradient = (GradientBar) c;
163 BoundedTableModel dataModel = gradient.getDataModel();
164 Insets ins = gradient.getInsets();
165
166 int r;
167 if (dataModel == null)
168 r = 1;
169 else
170 r = dataModel.getUpperBound() - dataModel.getLowerBound();
171
172 if (gradient.getOrientation() == SwingConstants.HORIZONTAL)
173 return new Dimension((r) * 2 + ins.left + ins.right + 1,
174 PREF_BAR_HEIGHT + ins.top + ins.bottom + 1);
175 else
176 return new Dimension(PREF_BAR_HEIGHT + ins.top + ins.bottom + 1,
177 (r) * 2 + ins.left + ins.right + 1);
178
179 }
180
181 }
0 package com.michaelbaranov.microba.gradienteditor;
1
2 import java.awt.Color;
3 import java.util.ArrayList;
4 import java.util.List;
5
6 import javax.swing.ListSelectionModel;
7
8 import com.michaelbaranov.microba.common.AbstractBoundedTableModelWithSelection;
9 import com.michaelbaranov.microba.marker.MarkerMutationModel;
10
11 /**
12 * A basic implementation of {@link AbstractBoundedTableModelWithSelection} and
13 * {@link MarkerMutationModel}. Used by default by {@link GradientEditor} as a
14 * color model, color selection model and color mutation model.
15 *
16 * <p>
17 * This implementation is mutable.
18 *
19 * @author Michael Baranov
20 *
21 */
22 public class DefaultGradientEditorModel extends
23 AbstractBoundedTableModelWithSelection implements MarkerMutationModel {
24
25 public static final int POSITION_COLUMN = 0;
26
27 public static final int COLOR_COLUMN = 1;
28
29 protected List position = new ArrayList(32);
30
31 protected List color = new ArrayList(32);
32
33 public DefaultGradientEditorModel() {
34 super();
35 setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
36
37 position.add(new Integer(0));
38 color.add(Color.BLACK);
39
40 position.add(new Integer(255));
41 color.add(Color.WHITE);
42
43 }
44
45 public void removeMarkerAtIndex(int index) {
46 if (isSelectedIndex(index)) {
47 removeSelectionInterval(index, index);
48 }
49 position.remove(index);
50 color.remove(index);
51 fireTableRowsDeleted(index, index);
52
53 }
54
55 public int addMarkAtPosition(int pos) {
56 position.add(new Integer(pos));
57 color.add(new Color((float) Math.random(), (float) Math.random(),
58 (float) Math.random()));
59 int index = position.size() - 1;
60 fireTableRowsInserted(index, index);
61 return index;
62 }
63
64 public int getLowerBound() {
65 return 0;
66 }
67
68 public int getUpperBound() {
69 return 255;
70 }
71
72 public int getRowCount() {
73 return position.size();
74 }
75
76 public int getColumnCount() {
77 return 2;
78 }
79
80 public Class getColumnClass(int columnIndex) {
81 switch (columnIndex) {
82 case POSITION_COLUMN:
83 return Integer.class;
84 case COLOR_COLUMN:
85 return Color.class;
86 }
87 return super.getColumnClass(columnIndex);
88 }
89
90 public Object getValueAt(int rowIndex, int columnIndex) {
91 switch (columnIndex) {
92 case POSITION_COLUMN:
93 return position.get(rowIndex);
94 case COLOR_COLUMN:
95 return color.get(rowIndex);
96 }
97 return null;
98 }
99
100 public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
101 switch (columnIndex) {
102 case POSITION_COLUMN:
103
104 for (int i = 0; i < position.size(); i++)
105 if (rowIndex != i && aValue.equals(position.get(i))) {
106 return;
107 }
108
109 position.remove(rowIndex);
110 position.add(rowIndex, aValue);
111 fireTableCellUpdated(rowIndex, columnIndex);
112 break;
113
114 case COLOR_COLUMN:
115 color.remove(rowIndex);
116 color.add(rowIndex, (Color) aValue);
117 fireTableCellUpdated(rowIndex, columnIndex);
118 break;
119 }
120 }
121
122 public boolean isCellEditable(int rowIndex, int columnIndex) {
123 // protecting first 2 rows (first and last marker) from being moved
124 return !(columnIndex == POSITION_COLUMN && rowIndex < 2);
125 }
126 }
0 package com.michaelbaranov.microba.gradienteditor;
1
2 import javax.swing.JColorChooser;
3 import javax.swing.ListSelectionModel;
4
5 import com.michaelbaranov.microba.gradient.GradientBar;
6 import com.michaelbaranov.microba.marker.MarkerBar;
7 import com.michaelbaranov.microba.marker.MarkerMutationModel;
8
9 /**
10 * IMPORTANT: alpha featre not implemented. Stubs only. No alpha marker bar yet.
11 * <p>
12 *
13 * This is a component for displaying/modifying a gradient (palette).
14 *
15 * <p>
16 * Implementation details: <br>
17 * This implementation combines a {@link GradientBar} with two {@link MarkerBar}
18 * components. The marker bars are used to provide editing capabilities to the
19 * gradient bar. Note, that this component doesn't provide direct
20 * color-selecting capabilitied but relies on other external components such as
21 * {@link JColorChooser}.
22 *
23 * @author Michael Baranov
24 *
25 */
26 public class GradientEditor extends GradientBar {
27
28 /**
29 * The name of a "colorSelectionModel" property.
30 */
31 public static final String PROPERTY_COLOR_SELECTION_MODEL = "colorSelectionModel";
32
33 /**
34 * The name of a "alphaSelectionModel" property.
35 */
36 public static final String PROPERTY_ALPHA_SELECTION_MODEL = "alphaSelectionModel";
37
38 /**
39 * The name of a "colorMutationModel" property.
40 */
41 public static final String PROPERTY_COLOR_MUTATION_MODEL = "colorMutationModel";
42
43 /**
44 * The name of a "alphaMutationModel" property.
45 */
46 public static final String PROPERTY_ALPHA_MUTATION_MODEL = "alphaMutationModel";
47
48 private static final String uiClassID = "microba.GradientEditorUI";
49
50 private ListSelectionModel colorSelectionModel = null;
51
52 private ListSelectionModel alphaSelectionModel = null;
53
54 private MarkerMutationModel colorMutationModel = null;
55
56 private MarkerMutationModel alphaMutationModel = null;
57
58 /**
59 * Constructor.
60 */
61 public GradientEditor() {
62 super();
63 DefaultGradientEditorModel defaultGradientEditorModel = new DefaultGradientEditorModel();
64 dataModel = defaultGradientEditorModel;
65 colorSelectionModel = defaultGradientEditorModel;
66 colorMutationModel = defaultGradientEditorModel;
67 setFocusable(true);
68 updateUI();
69 }
70
71 public String getUIClassID() {
72 return uiClassID;
73 }
74
75 /**
76 * Regturns the current color mutation model.
77 *
78 * @return current color mutation model
79 * @see #setColorMutationModel(MarkerMutationModel)
80 * @see MarkerMutationModel
81 */
82 public MarkerMutationModel getColorMutationModel() {
83 return colorMutationModel;
84 }
85
86 /**
87 * Replaces current color mutation model with given one.
88 *
89 * @param mutationModel
90 * new mutation model. May be <code>null<code>.
91 * @see #getColorMutationModel()
92 * @see MarkerMutationModel
93 */
94 public void setColorMutationModel(MarkerMutationModel mutationModel) {
95 MarkerMutationModel oldMutationModel = this.colorMutationModel;
96 this.colorMutationModel = mutationModel;
97 firePropertyChange(PROPERTY_COLOR_MUTATION_MODEL, oldMutationModel, mutationModel);
98 }
99
100 /**
101 * Returns current color selection model.
102 *
103 * @return current color selection model.
104 * @see #setColorSelectionModel(ListSelectionModel)
105 */
106 public ListSelectionModel getColorSelectionModel() {
107 return colorSelectionModel;
108 }
109
110 /**
111 * Replaces current color selection model with given one. This
112 * implementation uses
113 * <code>{@link ListSelectionModel#getLeadSelectionIndex()}</code> to
114 * determine selected marker.
115 *
116 * @param selectionModel
117 * new selection model. May be <code>null<code>.
118 *
119 * @see #getColorSelectionModel()
120 */
121 public void setColorSelectionModel(ListSelectionModel selectionModel) {
122 ListSelectionModel oldSelectionModel = this.colorSelectionModel;
123 this.colorSelectionModel = selectionModel;
124 firePropertyChange(PROPERTY_COLOR_SELECTION_MODEL, oldSelectionModel,
125 selectionModel);
126 }
127
128 /**
129 * Returns current alpha selection model.
130 *
131 * @return current alpha selection model.
132 * @see #setAlphaSelectionModel(ListSelectionModel)
133 */
134 public ListSelectionModel getAlphaSelectionModel() {
135 return alphaSelectionModel;
136 }
137
138 /**
139 * Replaces current alpha selection model with given one. This
140 * implementation uses
141 * <code>{@link ListSelectionModel#getLeadSelectionIndex()}</code> to
142 * determine selected marker.
143 *
144 * @param selectionModel
145 * new selection model. May be <code>null<code>.
146 *
147 * @see #getAlphaSelectionModel()
148 */
149 public void setAlphaSelectionModel(ListSelectionModel selectionModel) {
150 this.alphaSelectionModel = selectionModel;
151 }
152
153 /**
154 * Regturns the current alpha mutation model.
155 *
156 * @return current alpha mutation model
157 * @see #setAlphaMutationModel(MarkerMutationModel)
158 * @see MarkerMutationModel
159 */
160 public MarkerMutationModel getAlphaMutationModel() {
161 return alphaMutationModel;
162 }
163
164 /**
165 * Replaces current alpha mutation model with given one.
166 *
167 * @param mutationModel
168 * new mutation model. May be <code>null<code>.
169 * @see #getAlphaMutationModel()
170 * @see MarkerMutationModel
171 */
172 public void setAlphaMutationModel(MarkerMutationModel mutationModel) {
173 this.alphaMutationModel = mutationModel;
174 }
175
176 }
0 package com.michaelbaranov.microba.gradienteditor.ui;
1
2 import java.awt.Component;
3 import java.awt.Container;
4 import java.awt.Dimension;
5 import java.awt.Insets;
6 import java.awt.LayoutManager;
7
8 import javax.swing.SwingConstants;
9
10 import com.michaelbaranov.microba.gradient.GradientBar;
11 import com.michaelbaranov.microba.gradienteditor.GradientEditor;
12 import com.michaelbaranov.microba.marker.MarkerBar;
13
14 public class GradientEditorLayout implements LayoutManager {
15
16 private MarkerBar bar;
17
18 private GradientBar gradient;
19
20 public GradientEditorLayout(MarkerBar bar, GradientBar gradient) {
21 this.bar = bar;
22 this.gradient = gradient;
23 }
24
25 public void addLayoutComponent(String name, Component comp) {
26 }
27
28 public void removeLayoutComponent(Component comp) {
29 }
30
31 public Dimension preferredLayoutSize(Container parent) {
32 return parent.getPreferredSize();
33 }
34
35 public Dimension minimumLayoutSize(Container parent) {
36 return parent.getMinimumSize();
37 }
38
39 public void layoutContainer(Container parent) {
40 GradientEditor e = (GradientEditor) parent;
41 Insets i = parent.getInsets();
42 int gap = bar.getMarkerSideGap();
43 if (e.getOrientation() == SwingConstants.HORIZONTAL) {
44 bar.setBounds(i.left, i.top, parent.getWidth() - i.left - i.right,
45 bar.getPreferredSize().height);
46 gradient.setBounds(i.left + gap, bar.getBounds().y
47 + bar.getBounds().height, parent.getWidth() - i.left
48 - i.right - gap - gap, parent.getHeight() - i.top
49 - i.bottom - bar.getHeight());
50 } else {
51 gradient.setBounds(i.left, i.top+gap,
52 gradient.getPreferredSize().width,parent.getHeight() - i.top - i.bottom-gap-gap);
53 bar.setBounds(gradient.getBounds().x+gradient.getBounds().width ,i.top,
54 bar.getPreferredSize().width,gradient.getBounds().height+gap+gap);
55
56 }
57 }
58
59 }
0 package com.michaelbaranov.microba.gradienteditor.ui;
1
2 import java.beans.PropertyChangeEvent;
3 import java.beans.PropertyChangeListener;
4
5 import com.michaelbaranov.microba.gradienteditor.GradientEditor;
6
7 public class GradientEditorListener implements PropertyChangeListener {
8
9 private GradientEditorUI ui;
10
11 private GradientEditor editor;
12
13 public GradientEditorListener(GradientEditor editor, GradientEditorUI ui) {
14 super();
15 this.editor = editor;
16 this.ui = ui;
17 }
18
19 public void propertyChange(PropertyChangeEvent evt) {
20 if (GradientEditor.PROPERTY_DATA_MODEL.equals(evt.getPropertyName())) {
21
22 }
23
24 }
25
26 }
0 package com.michaelbaranov.microba.gradienteditor.ui;
1
2 import javax.swing.plaf.ComponentUI;
3
4 public class GradientEditorUI extends ComponentUI{
5
6 }
0 package com.michaelbaranov.microba.gradienteditor.ui.basic;
1
2 import java.awt.Dimension;
3 import java.awt.FlowLayout;
4 import java.beans.PropertyChangeEvent;
5 import java.beans.PropertyChangeListener;
6
7 import javax.swing.JComponent;
8 import javax.swing.ListSelectionModel;
9 import javax.swing.SwingConstants;
10 import javax.swing.plaf.ComponentUI;
11
12 import com.michaelbaranov.microba.common.BoundedTableModel;
13 import com.michaelbaranov.microba.gradient.GradientBar;
14 import com.michaelbaranov.microba.gradienteditor.GradientEditor;
15 import com.michaelbaranov.microba.gradienteditor.ui.GradientEditorLayout;
16 import com.michaelbaranov.microba.gradienteditor.ui.GradientEditorUI;
17 import com.michaelbaranov.microba.marker.MarkerBar;
18 import com.michaelbaranov.microba.marker.MarkerMutationModel;
19
20 public class BasicGradientEditorUI extends GradientEditorUI {
21
22 protected GradientBar gradientBar;
23
24 protected MarkerBar colorBar;
25
26 protected MarkerBar alphaBar;
27
28 private GradientEditor gradient;
29
30 private GradientEditorListener editorListener;
31
32 public static ComponentUI createUI(JComponent c) {
33 return new BasicGradientEditorUI();
34 }
35
36 public void installUI(JComponent component) {
37 gradient = (GradientEditor) component;
38 editorListener = new GradientEditorListener();
39 createAndConfigureSubcomponents();
40 installSubcomponents();
41 installListeners();
42 gradient.revalidate();
43 }
44
45 public void uninstallUI(JComponent component) {
46 // JGradient gradient = (JGradient) component;
47 uninstallSubcomponents();
48 uninstallListeners();
49 }
50
51 protected void installSubcomponents() {
52 gradient.setLayout(new GradientEditorLayout(colorBar, gradientBar));
53 gradient.add(colorBar);
54 gradient.add(gradientBar);
55 }
56
57 protected void uninstallSubcomponents() {
58 gradient.setLayout(new FlowLayout());
59 gradient.remove(colorBar);
60 gradient.remove(gradientBar);
61 }
62
63 private void installListeners() {
64 gradient.addPropertyChangeListener(editorListener);
65 }
66
67 private void uninstallListeners() {
68 gradient.removePropertyChangeListener(editorListener);
69 }
70
71 private void createAndConfigureSubcomponents() {
72 gradientBar = new GradientBar(gradient.getDataModel());
73 gradientBar.setOrientation(gradient.getOrientation());
74 gradientBar.setColorPositionColumn(gradient.getColorPositionColumn());
75 gradientBar.setColorColumn(gradient.getColorColumn());
76
77 colorBar = new MarkerBar(gradient.getDataModel(), gradient
78 .getColorSelectionModel());
79 colorBar.setOrientation(gradient.getOrientation());
80 colorBar.setMutationModel(gradient.getColorMutationModel());
81 colorBar.setPositionColumn(gradient.getColorPositionColumn());
82 colorBar.setColorColumn(gradient.getColorColumn());
83
84 alphaBar = new MarkerBar(gradient.getDataModel(), gradient
85 .getColorSelectionModel());
86 alphaBar.setOrientation(gradient.getOrientation());
87 alphaBar.setMutationModel(gradient.getColorMutationModel());
88 alphaBar.setPositionColumn(gradient.getColorPositionColumn());
89 alphaBar.setColorColumn(gradient.getColorColumn());
90 }
91
92 class GradientEditorListener implements PropertyChangeListener {
93
94 public void propertyChange(PropertyChangeEvent evt) {
95 if (GradientEditor.PROPERTY_DATA_MODEL
96 .equals(evt.getPropertyName())) {
97 gradientBar.setDataModel((BoundedTableModel) evt.getNewValue());
98 colorBar.setDataModel((BoundedTableModel) evt.getNewValue());
99 }
100 if (GradientEditor.PROPERTY_COLOR_SELECTION_MODEL.equals(evt
101 .getPropertyName())) {
102 colorBar.setSelectionModel((ListSelectionModel) evt
103 .getNewValue());
104 }
105 if (GradientEditor.PROPERTY_COLOR_MUTATION_MODEL.equals(evt
106 .getPropertyName())) {
107 colorBar.setMutationModel((MarkerMutationModel) evt
108 .getNewValue());
109 }
110 if (GradientEditor.PROPERTY_COLOR_POSITION_COLUMN.equals(evt
111 .getPropertyName())) {
112 colorBar.setPositionColumn(((Integer) evt.getNewValue())
113 .intValue());
114 gradientBar
115 .setColorPositionColumn(((Integer) evt.getNewValue())
116 .intValue());
117 }
118 if (GradientEditor.PROPERTY_COLOR_COLUMN.equals(evt
119 .getPropertyName())) {
120 gradientBar.setColorColumn(((Integer) evt.getNewValue())
121 .intValue());
122 colorBar.setColorColumn(((Integer) evt.getNewValue())
123 .intValue());
124
125 }
126 if (GradientEditor.PROPERTY_ORIENTATION.equals(evt
127 .getPropertyName())) {
128 colorBar.setOrientation(((Integer) evt.getNewValue())
129 .intValue());
130 gradientBar.setOrientation(((Integer) evt.getNewValue())
131 .intValue());
132 }
133 if ("enabled".equals(evt.getPropertyName())) {
134 colorBar.setEnabled(((Boolean) evt.getNewValue())
135 .booleanValue());
136 gradientBar.setEnabled(((Boolean) evt.getNewValue())
137 .booleanValue());
138 }
139
140 }
141
142 }
143
144 public Dimension getMinimumSize(JComponent c) {
145 GradientBar gradient = (GradientBar) c;
146
147 Dimension minimumSize = gradientBar.getMinimumSize();
148 Dimension minimumSize2 = colorBar.getMinimumSize();
149 if (gradient.getOrientation() == SwingConstants.HORIZONTAL)
150 return new Dimension(Math
151 .max(minimumSize.width, minimumSize2.width),
152 minimumSize.height + minimumSize2.height);
153 else
154 return new Dimension(minimumSize.width + minimumSize2.width, Math
155 .max(minimumSize.height, minimumSize2.height));
156
157 }
158
159 public Dimension getPreferredSize(JComponent c) {
160 Dimension preferredSize = gradientBar.getPreferredSize();
161 Dimension preferredSize2 = colorBar.getPreferredSize();
162 if (gradient.getOrientation() == SwingConstants.HORIZONTAL)
163 return new Dimension(Math.max(preferredSize.width,
164 preferredSize2.width), preferredSize.height
165 + preferredSize2.height);
166 else
167 return new Dimension(preferredSize.width + preferredSize2.width,
168 Math.max(preferredSize.height, preferredSize2.height));
169 }
170
171 }
0 package com.michaelbaranov.microba.jgraph.birdview;
1
2 import java.awt.Color;
3 import java.awt.Dimension;
4 import java.awt.Graphics;
5 import java.awt.Graphics2D;
6 import java.awt.Point;
7 import java.awt.Rectangle;
8 import java.awt.event.AdjustmentEvent;
9 import java.awt.event.AdjustmentListener;
10 import java.awt.event.ComponentEvent;
11 import java.awt.event.ComponentListener;
12 import java.awt.event.MouseEvent;
13 import java.awt.event.MouseListener;
14 import java.awt.event.MouseMotionListener;
15 import java.awt.geom.Point2D;
16 import java.awt.geom.Rectangle2D;
17 import java.beans.PropertyChangeEvent;
18 import java.beans.PropertyChangeListener;
19
20 import javax.swing.JPanel;
21 import javax.swing.JScrollPane;
22 import javax.swing.UIManager;
23
24 import org.jgraph.JGraph;
25 import org.jgraph.event.GraphModelEvent;
26 import org.jgraph.event.GraphModelListener;
27 import org.jgraph.graph.GraphLayoutCache;
28
29 /**
30 * A JFC/Swing component that displays a bird-eyes (thumbnail) view of a
31 * {@link JGraph} in combination with {@link JScrollPane}. Also allows to pan
32 * view with the mouse.
33 *
34 *
35 * @author Michael Baranov
36 *
37 */
38 public class Birdview extends JPanel {
39
40 /**
41 * Color constant
42 */
43 public static final Color PAN_RECT_COLOR = Color.black;
44
45 /**
46 * Color constant
47 */
48 public static final Color BACKGROUND_COLOR = UIManager.getColor("Panel.background");
49
50 /**
51 * a {@link JGraph} component used as main display
52 */
53 private JGraph displayGraph;
54
55 /**
56 * a {@link JScrollPane} to track
57 */
58 private JScrollPane peerScroller;
59
60 /**
61 * a {@link JGraph} to tracl
62 */
63 private JGraph peerGraph;
64
65 /**
66 * a rect, subrect of the component area, that matches the tracked view
67 */
68 private Rectangle2D paintRect;
69
70 /**
71 * a rect, a subrect of the component area, that matches the tracked
72 * viewport
73 */
74 private Rectangle2D panRect;
75
76 /**
77 * the scale applied to {@link #displayGraph} to fit into {@link #paintRect}
78 */
79 private double scale = 1.0;
80
81 /**
82 * A listener
83 */
84 private ScrollerListener scrollerListener = new ScrollerListener();
85
86 /**
87 * A listener
88 */
89 private SelfMouseListener selfMouseListener = new SelfMouseListener();
90
91 /**
92 * A listener
93 */
94 private GraphPropertyChangeListener graphPropertyChangeListener = new GraphPropertyChangeListener();
95
96 /**
97 * Constructor.
98 *
99 * @param doc
100 * document to track. May be <code>null</code>
101 */
102 public Birdview() {
103
104 displayGraph = new JGraph();
105 displayGraph.setEnabled(false);
106 displayGraph.setAntiAliased(true);
107 displayGraph.addMouseListener(selfMouseListener);
108 displayGraph.addMouseMotionListener(selfMouseListener);
109
110 this.setLayout(null);
111 this.addComponentListener(new SelfResizeListener());
112 this.add(displayGraph);
113
114 }
115
116 /**
117 * Makes this component track the provided graph and scroller. Set
118 * parameters to <code>null</code> to unbind thie component.
119 *
120 * @param graph
121 * the graph component. May be <code>null</code>
122 * @param scroller
123 * the croller, usually the one that holds the graph. May be
124 * <code>null</code>
125 */
126 public void setTrackingFor(JGraph graph, JScrollPane scroller) {
127 if (this.peerGraph != null) {
128 this.peerGraph.getModel().removeGraphModelListener(scrollerListener);
129 this.peerGraph.removePropertyChangeListener(graphPropertyChangeListener);
130 }
131
132 this.peerGraph = graph;
133
134 if (this.peerGraph != null) {
135 this.peerGraph.getModel().addGraphModelListener(scrollerListener);
136 this.peerGraph.addPropertyChangeListener(graphPropertyChangeListener);
137
138 this.displayGraph.setGraphLayoutCache(peerGraph.getGraphLayoutCache());
139
140 } else {
141 this.displayGraph.setGraphLayoutCache(new GraphLayoutCache());
142 }
143
144 //
145 if (this.peerScroller != null) {
146 this.peerScroller.getHorizontalScrollBar().removeAdjustmentListener(
147 scrollerListener);
148 this.peerScroller.getVerticalScrollBar().removeAdjustmentListener(
149 scrollerListener);
150 }
151
152 this.peerScroller = scroller;
153
154 if (this.peerScroller != null) {
155 this.peerScroller.getHorizontalScrollBar().addAdjustmentListener(
156 scrollerListener);
157 this.peerScroller.getVerticalScrollBar().addAdjustmentListener(
158 scrollerListener);
159 }
160
161 update();
162 repaint();
163
164 }
165
166 /**
167 * Calculates {@link #paintRect}, {@link #panRect}, {@link #scale} based
168 * on observations of peerScroller.
169 *
170 */
171 private void update() {
172 if (peerScroller != null) {
173 Dimension viewSize = peerScroller.getViewport().getViewSize();
174 double viewAspect = viewSize.getHeight() / viewSize.getWidth();
175
176 Dimension panelSize = this.getSize();
177 double panelAspect = panelSize.getHeight() / panelSize.getWidth();
178
179 if (panelAspect < viewAspect) {
180 // panel is wider, height is primary
181 double desiredPanelWidth = panelSize.getHeight() / viewAspect;
182 double blankWidth = panelSize.getWidth() - desiredPanelWidth;
183 double gap = blankWidth / 2;
184 paintRect = new Rectangle2D.Double(gap, 0, desiredPanelWidth,
185 panelSize.height);
186 scale = panelSize.getHeight() / viewSize.getHeight();
187 scale *= peerGraph.getScale();
188 } else {
189 // panel is heigher, width is primary
190 double desiredPanelHeight = panelSize.getWidth() * viewAspect;
191 double blankHeight = panelSize.getHeight() - desiredPanelHeight;
192 double gap = blankHeight / 2;
193 paintRect = new Rectangle2D.Double(0, gap, panelSize.getWidth(),
194 desiredPanelHeight);
195 scale = panelSize.getWidth() / viewSize.getWidth();
196 scale *= peerGraph.getScale();
197 }
198
199 Rectangle viewRect = peerScroller.getViewport().getViewRect();
200 double shiftX = viewRect.getX() / viewSize.getWidth();
201 double shiftY = viewRect.getY() / viewSize.getHeight();
202
203 double sizeX = viewRect.getWidth() / viewSize.getWidth();
204 double sizeY = viewRect.getHeight() / viewSize.getHeight();
205
206 panRect = new Rectangle2D.Double(paintRect.getX() + paintRect.getWidth()
207 * shiftX, paintRect.getY() + paintRect.getHeight() * shiftY,
208 paintRect.getWidth() * sizeX, paintRect.getHeight() * sizeY);
209
210 } else {
211 panRect = null;
212 paintRect = null;
213 scale = 1;
214 }
215 }
216
217 /**
218 * Addjusts {@link #panRect} to be postitionsed with the centter at a given
219 * point if possible. This methods ensures that {@link #panRect} fits
220 * entirely in {@link #paintRect}.
221 *
222 * @param point
223 * the desired panRect center
224 */
225 private void panRectTo(Point point) {
226
227 Dimension viewSize = peerScroller.getViewport().getViewSize();
228 Rectangle viewRect = peerScroller.getViewport().getViewRect();
229
230 double panHalfWidth = panRect.getWidth() / 2;
231 double panHalfHeight = panRect.getHeight() / 2;
232
233 Point2D panOrigin = new Point2D.Double(point.x - panHalfWidth, point.y
234 - panHalfHeight);
235 double xk = panOrigin.getX() / paintRect.getWidth();
236 double yk = panOrigin.getY() / paintRect.getHeight();
237
238 Point viewPos = new Point((int) (viewSize.getWidth() * xk), (int) (viewSize
239 .getHeight() * yk));
240
241 // make sure we do not pan past the bounds:
242 if (viewPos.x < 0)
243 viewPos.x = 0;
244 if (viewPos.y < 0)
245 viewPos.y = 0;
246
247 int wd = (viewPos.x + viewRect.width) - viewSize.width;
248 int hd = (viewPos.y + viewRect.height) - viewSize.height;
249
250 if (wd > 0)
251 viewPos.x -= wd;
252 if (hd > 0)
253 viewPos.y -= hd;
254
255 // pan it
256 peerScroller.getViewport().setViewPosition(viewPos);
257
258 update();
259 repaint();
260 }
261
262 public void paint(Graphics g) {
263 Graphics2D g2 = (Graphics2D) g;
264
265 // fill background
266 g2.setColor(BACKGROUND_COLOR);
267 g2.fillRect(0, 0, this.getWidth(), this.getHeight());
268
269 if (peerGraph != null) {
270 // paint the graph display
271 displayGraph.setBounds(paintRect.getBounds());
272 displayGraph.setScale(scale);
273 displayGraph.setBackground(peerGraph.getBackground());
274 paintChildren(g);
275 }
276
277 if (panRect != null) {
278 // draw pan rect
279 g2.setColor(PAN_RECT_COLOR);
280 g2.draw(panRect.getBounds());
281 }
282 }
283
284 /**
285 * A listener to watch for scrollbar movement.
286 *
287 * @author Michael Baranov
288 *
289 */
290 private class ScrollerListener implements AdjustmentListener, GraphModelListener {
291
292 public void adjustmentValueChanged(AdjustmentEvent e) {
293 update();
294 repaint();
295 }
296
297 public void graphChanged(GraphModelEvent e) {
298 update();
299 repaint();
300
301 }
302
303 }
304
305 /**
306 * A listener to watch for sizing of the component itself.
307 *
308 * @author Michael Baranov
309 *
310 */
311 private class SelfResizeListener implements ComponentListener {
312
313 public void componentHidden(ComponentEvent e) {
314 }
315
316 public void componentMoved(ComponentEvent e) {
317 }
318
319 public void componentResized(ComponentEvent e) {
320 update();
321 repaint();
322 }
323
324 public void componentShown(ComponentEvent e) {
325 update();
326 repaint();
327 }
328
329 }
330
331 /**
332 * A listener to watch for mouse for the component itself.
333 *
334 * @author Michael Baranov
335 *
336 */
337 private class SelfMouseListener implements MouseListener, MouseMotionListener {
338
339 public void mouseClicked(MouseEvent e) {
340 }
341
342 public void mouseEntered(MouseEvent e) {
343 }
344
345 public void mouseExited(MouseEvent e) {
346 }
347
348 public void mousePressed(MouseEvent e) {
349
350 }
351
352 public void mouseReleased(MouseEvent e) {
353 if (paintRect != null)
354 panRectTo(e.getPoint());
355
356 }
357
358 public void mouseDragged(MouseEvent e) {
359 if (paintRect != null)
360 panRectTo(e.getPoint());
361
362 }
363
364 public void mouseMoved(MouseEvent e) {
365 }
366
367 }
368
369 /**
370 * A listener to watch for graph property change, most important "scale".
371 *
372 * @author Michael Baranov
373 *
374 */
375 private class GraphPropertyChangeListener implements PropertyChangeListener {
376
377 public void propertyChange(PropertyChangeEvent evt) {
378 if ("scale".equals(evt.getPropertyName())) {
379 update();
380 repaint();
381 }
382
383 }
384
385 }
386
387 }
0 package com.michaelbaranov.microba.marker;
1
2 import java.util.ArrayList;
3 import java.util.List;
4
5 import javax.swing.ListSelectionModel;
6
7 import com.michaelbaranov.microba.common.AbstractBoundedTableModelWithSelection;
8
9 /**
10 * A basic implementation of <code>BoundedRangeModel</code>,
11 * <code>ListSelectionModel</code> and <code>MutationModel</code> all in
12 * one. Used by default by <code>JMarkerBar</code> as data model, selection
13 * model and mutation model.
14 * <p>
15 *
16 *
17 * @author Michael Baranov
18 * @see com.michaelbaranov.microba.marker.MarkerBar
19 */
20 public class DefaultMarkerModel extends AbstractBoundedTableModelWithSelection
21 implements MarkerMutationModel {
22
23 private List data = new ArrayList(32);
24
25 private int lowerBound = 0;
26
27 private int upperBound = 100;
28
29 /**
30 * Constructs a <code>DefaultMarkerModel</code>.
31 *
32 */
33 public DefaultMarkerModel() {
34 super();
35 setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
36 }
37
38 /**
39 * Returns the count of markers. Actually returns the cound of rows in the
40 * <code>TableModel</code>.
41 *
42 * @return current marker count.
43 */
44 public int getRowCount() {
45 return data.size();
46 }
47
48 /**
49 * Returns the numbar of columns in the <code>TableModel</code>.This
50 * implementation always returns 1.
51 *
52 * @return always 1.
53 */
54 public int getColumnCount() {
55 return 1;
56 }
57
58 /**
59 * Returns the position of a marker, specified by index.
60 *
61 * @param rowIndex
62 * marker index.
63 * @param columnIndex
64 * should be 0.
65 *
66 * @return an Integer position of the marker.
67 * @see #setValueAt(Object, int, int)
68 */
69 public Object getValueAt(int rowIndex, int columnIndex) {
70 checkIndexes(rowIndex, columnIndex);
71 return data.get(rowIndex);
72 }
73
74 /**
75 * Assigns a new position to a marker, specified by index (moves the
76 * marker).
77 * <p>
78 * This implementation does not check if the specified marker position lies
79 * beyond current upper and lower bounds.
80 *
81 * @param aValue
82 * an Integer new position.
83 * @param rowIndex
84 * marker index.
85 * @param columnIndex
86 * should be 0.
87 * @see #getValueAt(int, int)
88 */
89 public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
90
91 checkIndexes(rowIndex, columnIndex);
92
93 Integer newValue = (Integer) aValue;
94 Integer oldValue = (Integer) getValueAt(rowIndex, columnIndex);
95
96 if (!newValue.equals(oldValue)) {
97 data.remove(rowIndex);
98 data.add(rowIndex, newValue);
99 fireTableCellUpdated(rowIndex, columnIndex);
100 }
101 }
102
103 /**
104 * This implementation returns <code>Integer.class</code> for
105 * columnIndex=0.
106 *
107 * @param columnIndex
108 * should be 0.
109 *
110 * @return column data class.
111 */
112 public Class getColumnClass(int columnIndex) {
113 return Integer.class;
114 }
115
116 /**
117 * This implementation returns <code>"Position"</code> for columnIndex=0.
118 *
119 * @param columnIndex
120 * should be 0.
121 * @return column name.
122 */
123 public String getColumnName(int columnIndex) {
124 return "Position";
125 }
126
127 /**
128 * This implementation always returns <code>true</code>, indicating that
129 * all markers are movable. Override to change behaviour.
130 *
131 * @return always <code>true</code>.
132 */
133 public boolean isCellEditable(int rowIndex, int columnIndex) {
134 return true;
135 }
136
137 /**
138 * Removes a marker, specified by index. Actually removes a row from the
139 * <code>TableModel</code>.
140 *
141 * @param index
142 * marker index.
143 * @see #addMarkAtPosition(int)
144 */
145 public void removeMarkerAtIndex(int index) {
146 if (isSelectedIndex(index)) {
147 removeSelectionInterval(index, index);
148 }
149 data.remove(index);
150 fireTableRowsDeleted(index, index);
151 }
152
153 /**
154 * Adds a marker with specified position. Actually appends a row to
155 * <code>TableModel</code> with specified position value. Returns the
156 * index of the added mark.
157 * <p>
158 * This implementation does not check if the specified marker position lies
159 * beyond current upper and lower bounds.
160 *
161 * @return index of added mark.
162 * @see #removeMarkerAtIndex(int)
163 */
164 public int addMarkAtPosition(int position) {
165 data.add(new Integer(position));
166 int row = data.size() - 1;
167 fireTableRowsInserted(row, row);
168
169 setSelectionInterval(row, row);
170 return row;
171 }
172
173 /**
174 * @inheritDoc
175 * @see #setLowerBound(int)
176 */
177 public int getLowerBound() {
178 return lowerBound;
179 }
180
181 /**
182 * @inheritDoc
183 * @see #setUpperBound(int)
184 */
185 public int getUpperBound() {
186 return upperBound;
187 }
188
189 /**
190 * Sets current lower bound.
191 *
192 * @param lowerBound
193 * new lower bound value.
194 * @see #setLowerBound(int)
195 */
196 public void setLowerBound(int lowerBound) {
197 if (lowerBound >= upperBound)
198 throw new IllegalArgumentException("lowerBound >= upperBound");
199
200 int old = this.lowerBound;
201 this.lowerBound = lowerBound;
202 firePropertyChange(PROPERTY_LOWER_BOUND, old, lowerBound);
203 }
204
205 /**
206 * Sets current upper bound.
207 *
208 * @param upperBound
209 * new upper bound value.
210 * @see #getUpperBound()
211 */
212 public void setUpperBound(int upperBound) {
213 int old = this.upperBound;
214 this.upperBound = upperBound;
215 firePropertyChange(PROPERTY_UPPER_BOUND, old, upperBound);
216 }
217
218 private void checkIndexes(int rowIndex, int columnIndex) {
219 if (columnIndex != 0)
220 throw new IndexOutOfBoundsException("columnIndex: " + columnIndex);
221
222 if (rowIndex < 0 || rowIndex >= data.size())
223 throw new IndexOutOfBoundsException("rowIndex: " + rowIndex);
224 }
225
226 }
0 package com.michaelbaranov.microba.marker;
1
2 import javax.swing.DefaultListSelectionModel;
3 import javax.swing.ListSelectionModel;
4 import javax.swing.SwingConstants;
5
6 import com.michaelbaranov.microba.common.BoundedTableModel;
7 import com.michaelbaranov.microba.common.MicrobaComponent;
8 import com.michaelbaranov.microba.marker.ui.MarkerBarUI;
9
10 /**
11 * A bar with multiple draggable position marks.
12 * <p>
13 * <strong>Features:</strong>
14 * <ul>
15 * <li>Single marker selection.</li>
16 * <li>Respects unmovable marks.</li>
17 * <li>Mouse marker selection & dragging.</li>
18 * <li>Hirizontal & verical orientation.</li>
19 * <li>Supported L&F: Metal, Windows, Motif, Basic for others.</li>
20 * </ul>
21 *
22 * <strong>Implementation details:</strong>
23 * <ul>
24 * <li>Data model:
25 * <code>{@link com.michaelbaranov.microba.common.BoundedTableModel}</code></li>
26 * <li>Selection model: <code>{@link javax.swing.ListSelectionModel}</code></li>
27 * <li>MutationModel model:
28 * <code>{@link com.michaelbaranov.microba.marker.MarkerMutationModel}</code></li>
29 * <li>UI delegate:
30 * <code>{@link com.michaelbaranov.microba.marker.ui.MarkerBarUI}</code></li>
31 * </ul>
32 * <p>
33 *
34 * This implementation queries marker positions from a single table column of
35 * the data model. The index defaults to 0, but you can specify it with <code>
36 * {@link #setPositionColumn(int)}</code>.
37 * A marker is considered to be unmovable, if corresponding table cell of the
38 * data model is reported to be uneditable.
39 * <p>
40 *
41 * This implementation determines the only currently selected marker with <code>
42 * {@link ListSelectionModel#getLeadSelectionIndex()}</code>
43 * of the selection model, so current selection model's selection mode has no
44 * effect.
45 *
46 * @author Michael Baranov
47 *
48 */
49 public class MarkerBar extends MicrobaComponent {
50
51 /**
52 * The name of a "dataModel" property.
53 */
54 public static final String PROPERTY_DATA_MODEL = "dataModel";
55
56 /**
57 * The name of a "selectionModel" property.
58 */
59 public static final String PROPERTY_SELECTION_MODEL = "selectionModel";
60
61 /**
62 * The name of a "mutationModel" property.
63 */
64 public static final String PROPERTY_MUTATION_MODEL = "mutationModel";
65
66 /**
67 * The name of a "orientation" property.
68 */
69 public static final String PROPERTY_ORIENTATION = "orientation";
70
71 /**
72 * The name of a "positionColumn" property.
73 */
74 public static final String PROPERTY_POSITION_COLUMN = "positionColumn";
75
76 /**
77 * The name of a "colorColumn" property.
78 */
79 public static final String PROPERTY_COLOR_COLUMN = "colorColumn";
80
81 /**
82 * The name of a "fliped" property.
83 */
84 public static final String PROPERTY_FLIP = "fliped";
85
86 private static final String uiClassID = "microba.MarkerBarUI";
87
88 private BoundedTableModel dataModel = null;
89
90 private ListSelectionModel selectionModel = null;
91
92 private MarkerMutationModel mutationModel = null;
93
94 private int positionColumn = 0;
95
96 private int colorColumn = -1;
97
98 private int orientation = SwingConstants.HORIZONTAL;
99
100 private boolean fliped = false;
101
102 /**
103 * Constructs a <code>MarkerBar</code> with all models set to a single
104 * <code>DefaultMarkerModel.</code>
105 *
106 * @see DefaultMarkerModel
107 */
108 public MarkerBar() {
109 super();
110 DefaultMarkerModel markerModel = new DefaultMarkerModel();
111 dataModel = markerModel;
112 selectionModel = markerModel;
113 mutationModel = markerModel;
114 setFocusable(true);
115 updateUI();
116 }
117
118 /**
119 * Constructs a <code>MarkerBar</code> with given orientation. All models
120 * set to a single <code>DefaultMarkerModel</code>.
121 *
122 * @param orientation
123 * initial orientation. Possible values:
124 * <code>SwingConstants.HORIZONTAL</code> or
125 * <code>SwingConstants.VERTICAL</code>
126 * @see DefaultMarkerModel
127 */
128 public MarkerBar(int orientation) {
129 super();
130 DefaultMarkerModel markerModel = new DefaultMarkerModel();
131 dataModel = markerModel;
132 selectionModel = markerModel;
133 mutationModel = markerModel;
134 this.orientation = orientation;
135 setFocusable(true);
136 updateUI();
137 }
138
139 /**
140 * Constructs a <code>MarkerBar</code> with given data model, a
141 * <code>DefaultListSelectionModel<code> as selection model and no mutation model.
142 *
143 * @param dataModel
144 * initial data model. May be <code>null<code>
145 *
146 * @see BoundedTableModel
147 */
148 public MarkerBar(BoundedTableModel dataModel) {
149 super();
150 this.dataModel = dataModel;
151 selectionModel = new DefaultListSelectionModel();
152 mutationModel = null;
153 setFocusable(true);
154 updateUI();
155 }
156
157 /**
158 * Constructs a <code>MarkerBar</code> with given data model and selection
159 * model. No mutation model.
160 *
161 * @param dataModel
162 * initial data model. May be <code>null<code>;
163 * @param selectionModel initial selection model.
164 * @see BoundedTableModel
165 */
166 public MarkerBar(BoundedTableModel dataModel, ListSelectionModel selectionModel) {
167 super();
168 this.dataModel = dataModel;
169 this.selectionModel = selectionModel;
170 mutationModel = null;
171 setFocusable(true);
172 updateUI();
173 }
174
175 /**
176 * Look&Feel UI delegate key (classID). This implementation returns:
177 * <code>"MarkerBarUI"<code>.
178 */
179 public String getUIClassID() {
180 return uiClassID;
181 }
182
183 /**
184 * Returns current data model.
185 *
186 * @return current BoundedTableModel.
187 * @see #setDataModel(BoundedTableModel)
188 * @see BoundedTableModel
189 */
190 public BoundedTableModel getDataModel() {
191 return dataModel;
192 }
193
194 /**
195 * Replaces current data model with specified one. This implementation uses
196 * current position column index to query marker positions.
197 *
198 * @param model
199 * new data model.
200 * @see #getDataModel()
201 * @see #getPositionColumn()
202 * @see BoundedTableModel
203 */
204 public void setDataModel(BoundedTableModel model) {
205 BoundedTableModel oldModel = this.dataModel;
206 this.dataModel = model;
207 firePropertyChange(PROPERTY_DATA_MODEL, oldModel, model);
208 }
209
210 /**
211 * Returns current component orientation.
212 *
213 * @return current component orientation.
214 * @see #setOrientation(int)
215 */
216 public int getOrientation() {
217 return orientation;
218 }
219
220 /**
221 * Re-orientates the component.
222 *
223 * @param orientation
224 * new orientation value. Possible values:
225 * <code>{@link SwingConstants#HORIZONTAL}</code> or
226 * <code>{@link SwingConstants#VERTICAL}</code>
227 * @see #getOrientation()
228 */
229 public void setOrientation(int orientation) {
230 int oldOrientation = this.orientation;
231 this.orientation = orientation;
232 firePropertyChange(PROPERTY_ORIENTATION, oldOrientation, orientation);
233 }
234
235 /**
236 * Returns current mutation model.
237 *
238 * @return current MutationModel.
239 * @see #setMutationModel(MarkerMutationModel)
240 * @see MarkerMutationModel
241 */
242 public MarkerMutationModel getMutationModel() {
243 return mutationModel;
244 }
245
246 /**
247 * Replaces current mutation model with given one.
248 *
249 * @param mutationModel
250 * new mutation model. May be <code>null<code>.
251 * @see #getMutationModel()
252 * @see MarkerMutationModel
253 */
254 public void setMutationModel(MarkerMutationModel mutationModel) {
255 MarkerMutationModel oldMutationModel = this.mutationModel;
256 this.mutationModel = mutationModel;
257 firePropertyChange(PROPERTY_MUTATION_MODEL, oldMutationModel, mutationModel);
258 }
259
260 /**
261 * Returns current selection model.
262 *
263 * @return current ListSelectionModel.
264 * @see #setSelectionModel(ListSelectionModel)
265 */
266 public ListSelectionModel getSelectionModel() {
267 return selectionModel;
268 }
269
270 /**
271 * Replaces current selection model with given one. This implementation uses
272 * <code>{@link ListSelectionModel#getLeadSelectionIndex()}</code> to
273 * determine selected marker.
274 *
275 * @param selectionModel
276 * new selection model. May be <code>null<code>.
277 *
278 * @see #getSelectionModel()
279 */
280 public void setSelectionModel(ListSelectionModel selectionModel) {
281 ListSelectionModel oldSelectionModel = this.selectionModel;
282 this.selectionModel = selectionModel;
283 firePropertyChange(PROPERTY_SELECTION_MODEL, oldSelectionModel, selectionModel);
284 }
285
286 /**
287 * Returns an index of currently used table column to query marker position.
288 *
289 * @return current position column index.
290 * @see #setPositionColumn(int)
291 */
292 public int getPositionColumn() {
293 return positionColumn;
294 }
295
296 /**
297 * Sets the index of the data model table column used to query marker
298 * position.
299 *
300 * @param positionColumn
301 * new position column index.
302 * @see #getPositionColumn()
303 */
304 public void setPositionColumn(int positionColumn) {
305 int oldDataColumn = this.positionColumn;
306 this.positionColumn = positionColumn;
307 firePropertyChange(PROPERTY_POSITION_COLUMN, oldDataColumn, positionColumn);
308 }
309
310 /**
311 * Returns an index of currently used table column to query marker color.
312 * Defaults to -1, which means not to query data model for color.
313 *
314 * @return current color column index.
315 * @see #setColorColumn(int)
316 */
317 public int getColorColumn() {
318 return colorColumn;
319 }
320
321 /**
322 * Sets the index of the data model table column used to query marker color.
323 * Set to -1 in order not to query data model for color data.
324 *
325 * @param colorColumn
326 * new color column index.
327 * @see #getColorColumn()
328 */
329 public void setColorColumn(int colorColumn) {
330 int old = this.colorColumn;
331 this.colorColumn = colorColumn;
332 firePropertyChange(PROPERTY_COLOR_COLUMN, old, colorColumn);
333 }
334
335 /**
336 * Returns a distance in pixeld between the edge of the component (left &
337 * right edge for horizontal orientation, top & bottom edge for vertical)
338 * and a marker beak point in outermost position. The value is actually
339 * queried from current UI delegate.
340 *
341 * @return Gap value.
342 * @see MarkerBarUI
343 */
344 public int getMarkerSideGap() {
345 return ((MarkerBarUI) getUI()).getMarkerSideGap();
346 }
347
348 /**
349 * Returns current flip flag value.
350 * <p>
351 * The flip flag defines where marker bicks are pointed:<br>
352 * <code>true</code>: down for horizontal orientation, left for vertical.<br>
353 * <code>false</code>: up for horizontal orientation, right for vertical.
354 *
355 * @return current flip value.
356 */
357 public boolean isFliped() {
358 return fliped;
359 }
360
361 /**
362 * Set flip flag value.
363 * <p>
364 * The flip flag defines where marker bicks are pointed:<br>
365 * <code>true</code>: down for horizontal orientation, left for vertical.<br>
366 * <code>false</code>: up for horizontal orientation, right for vertical.
367 *
368 * @param flip
369 * new flip flag value.
370 */
371 public void setFliped(boolean flip) {
372 boolean old = this.fliped;
373 this.fliped = flip;
374 firePropertyChange(PROPERTY_FLIP, old, flip);
375 }
376
377 }
0 package com.michaelbaranov.microba.marker;
1
2 /**
3 * A callback interface used exclusively by
4 * <code>{@link com.michaelbaranov.microba.marker.MarkerBar}</code> as a
5 * mutation model.
6 * <p>
7 * The <code>JMarkerBar</code> class notifies an implementor of the
8 * <code>MutationModel</code> about the fact, that the user is requesting a
9 * marker to be removed or added.
10 *
11 * @author Michael Baranov
12 * @see com.michaelbaranov.microba.marker.MarkerBar
13 */
14 public interface MarkerMutationModel {
15
16 /**
17 * Called when the user requests a mark to be removed from
18 * <code>JMarkerBar</code>.
19 *
20 * @param index
21 * index of the mark to be removed.
22 */
23 void removeMarkerAtIndex(int index);
24
25 /**
26 * Called when the user requests a mark to be inserted into
27 * <code>JMarkerBar</code>.
28 *
29 * @param position
30 * position at which to insert the mark.
31 * @return index of newly added mark.
32 */
33 int addMarkAtPosition(int position);
34 }
0 package com.michaelbaranov.microba.marker.ui;
1
2 import java.awt.Polygon;
3 import java.awt.event.ActionEvent;
4 import java.awt.event.ComponentEvent;
5 import java.awt.event.ComponentListener;
6 import java.awt.event.FocusEvent;
7 import java.awt.event.FocusListener;
8 import java.awt.event.KeyEvent;
9 import java.awt.event.MouseEvent;
10 import java.awt.event.MouseListener;
11 import java.awt.event.MouseMotionListener;
12 import java.beans.PropertyChangeEvent;
13 import java.beans.PropertyChangeListener;
14
15 import javax.swing.AbstractAction;
16 import javax.swing.JComponent;
17 import javax.swing.KeyStroke;
18 import javax.swing.ListSelectionModel;
19 import javax.swing.SwingConstants;
20 import javax.swing.SwingUtilities;
21 import javax.swing.event.ListSelectionEvent;
22 import javax.swing.event.ListSelectionListener;
23 import javax.swing.event.TableModelEvent;
24 import javax.swing.event.TableModelListener;
25
26 import com.michaelbaranov.microba.common.BoundedTableModel;
27 import com.michaelbaranov.microba.marker.MarkerBar;
28 import com.michaelbaranov.microba.marker.MarkerMutationModel;
29 import com.michaelbaranov.microba.marker.ui.basic.BasicMarkerBarUI;
30
31 public class MarkerBarListener implements TableModelListener, MouseListener,
32 MouseMotionListener, FocusListener, PropertyChangeListener,
33 ComponentListener, ListSelectionListener {
34
35 private static final String VK_DELETE_KEY = "##VK_DELETE##";
36
37 private static final KeyStroke DELETE_KEYSTROKE = KeyStroke.getKeyStroke(
38 KeyEvent.VK_DELETE, 0);
39
40 private final BasicMarkerBarUI barUI;
41
42 private MarkerBar bar;
43
44 private int holdingIndex = -1;
45
46 private int holdingShift;
47
48 public MarkerBarListener(BasicMarkerBarUI barUI, MarkerBar markerBar) {
49 this.barUI = barUI;
50 this.bar = markerBar;
51 }
52
53 public void mouseClicked(MouseEvent e) {
54 }
55
56 public void mousePressed(MouseEvent e) {
57
58 if (!bar.isEnabled())
59 return;
60
61 this.barUI.calculateViewRectAndBaseline(bar);
62
63 bar.requestFocusInWindow();
64
65 BoundedTableModel dataModel = bar.getDataModel();
66 ListSelectionModel selectionModel = bar.getSelectionModel();
67 int dataColumn = bar.getPositionColumn();
68
69 if (SwingUtilities.isLeftMouseButton(e) && selectionModel != null
70 && dataModel != null) {
71 handleLMBDown(e, dataModel, selectionModel, dataColumn);
72 }
73 if (SwingUtilities.isRightMouseButton(e) && dataModel != null) {
74 handleRMBDown(e, dataModel);
75 }
76
77 }
78
79 private void handleRMBDown(MouseEvent e, BoundedTableModel dataModel) {
80 int logicalOffset;
81 if (bar.getOrientation() == SwingConstants.HORIZONTAL)
82 logicalOffset = this.barUI.componentOffsetToLogicalOffset(e.getX(),
83 dataModel);
84 else
85 logicalOffset = this.barUI.componentOffsetToLogicalOffset(e.getY(),
86 dataModel);
87 int logicalPos = dataModel.getLowerBound() + logicalOffset;
88
89 if (logicalPos >= dataModel.getLowerBound()
90 && logicalPos <= dataModel.getUpperBound()) {
91
92 MarkerMutationModel mutationModel = bar.getMutationModel();
93 if (mutationModel != null)
94 mutationModel.addMarkAtPosition(logicalPos);
95
96 }
97 }
98
99 private void handleLMBDown(MouseEvent e, BoundedTableModel dataModel,
100 ListSelectionModel selectionModel, int dataColumn) {
101
102 int numAreas = dataModel.getRowCount();
103 Polygon areas[] = this.barUI.calculateMarkerAreas(bar);
104
105 // try already selected
106 for (int i = 0; i < numAreas; i++) {
107 Polygon p = areas[i];
108 if (p.contains(e.getPoint()) && selectionModel.isSelectedIndex(i)
109 && dataModel.isCellEditable(i, dataColumn)) {
110 holdingIndex = i;
111 return;
112 }
113 }
114 // try editable
115 for (int i = 0; i < numAreas; i++) {
116 Polygon p = areas[i];
117 if (p.contains(e.getPoint())
118 && dataModel.isCellEditable(i, dataColumn)) {
119 selectionModel.setSelectionInterval(i, i);
120 holdingIndex = i;
121 if (bar.getOrientation() == SwingConstants.HORIZONTAL)
122 holdingShift = e.getX() - p.xpoints[0];
123 else
124 holdingShift = e.getY() - p.ypoints[0];
125 return;
126 }
127 }
128 // try other
129 for (int i = 0; i < numAreas; i++) {
130 Polygon p = areas[i];
131 if (p.contains(e.getPoint())) {
132 selectionModel.setSelectionInterval(i, i);
133 holdingIndex = -1;
134 return;
135 }
136 }
137 selectionModel.clearSelection();
138 }
139
140 public void mouseReleased(MouseEvent e) {
141 holdingIndex = -1;
142
143 }
144
145 public void mouseEntered(MouseEvent e) {
146
147 }
148
149 public void mouseExited(MouseEvent e) {
150
151 }
152
153 public void mouseDragged(MouseEvent e) {
154
155 if (!bar.isEnabled())
156 return;
157
158 BoundedTableModel dataModel = bar.getDataModel();
159 if (holdingIndex >= 0 && dataModel != null) {
160 int componentOffset;
161 if (bar.getOrientation() == SwingConstants.HORIZONTAL)
162 componentOffset = e.getX() - holdingShift;
163 else
164 componentOffset = e.getY() - holdingShift;
165
166 int logicalOffset = this.barUI.componentOffsetToLogicalOffset(
167 componentOffset, dataModel);
168 int logicalPos = dataModel.getLowerBound() + logicalOffset;
169
170 if (logicalPos < dataModel.getLowerBound())
171 logicalPos = dataModel.getLowerBound();
172 if (logicalPos > dataModel.getUpperBound())
173 logicalPos = dataModel.getUpperBound();
174
175 dataModel.setValueAt(new Integer(logicalPos), holdingIndex, bar
176 .getPositionColumn());
177 }
178
179 }
180
181 public void mouseMoved(MouseEvent e) {
182
183 }
184
185 public void focusGained(FocusEvent e) {
186 bar.repaint();
187
188 }
189
190 public void focusLost(FocusEvent e) {
191 bar.repaint();
192
193 }
194
195 public void propertyChange(PropertyChangeEvent evt) {
196
197 if (evt.getSource() instanceof MarkerBar) {
198
199 if (MarkerBar.PROPERTY_DATA_MODEL.equals(evt.getPropertyName())) {
200 BoundedTableModel oldModel = (BoundedTableModel) evt
201 .getOldValue();
202 BoundedTableModel newModel = (BoundedTableModel) evt
203 .getNewValue();
204
205 if (oldModel != null)
206 oldModel.removeTableModelListener(this);
207 if (newModel != null)
208 newModel.addTableModelListener(this);
209
210 holdingIndex = -1;
211 bar.revalidate();
212 }
213 if (MarkerBar.PROPERTY_SELECTION_MODEL.equals(evt
214 .getPropertyName())) {
215 ListSelectionModel oldModel = (ListSelectionModel) evt
216 .getOldValue();
217 ListSelectionModel newModel = (ListSelectionModel) evt
218 .getNewValue();
219
220 if (oldModel != null)
221 oldModel.removeListSelectionListener(this);
222 if (newModel != null)
223 newModel.addListSelectionListener(this);
224
225 holdingIndex = -1;
226 bar.repaint();
227 }
228 if (MarkerBar.PROPERTY_MUTATION_MODEL
229 .equals(evt.getPropertyName())) {
230 // do not care
231 }
232 if (MarkerBar.PROPERTY_ORIENTATION.equals(evt.getPropertyName())) {
233 holdingIndex = -1;
234 bar.revalidate();
235 }
236 if (MarkerBar.PROPERTY_POSITION_COLUMN.equals(evt
237 .getPropertyName())) {
238 holdingIndex = -1;
239 bar.repaint();
240 }
241 if ("enabled".equals(evt.getPropertyName())) {
242 holdingIndex = -1;
243 bar.repaint();
244 }
245 }
246 if (evt.getSource() instanceof BoundedTableModel) {
247 bar.revalidate();
248 }
249
250 }
251
252 public void installKeyboardActions(JComponent c) {
253
254 c.getInputMap().put(DELETE_KEYSTROKE, VK_DELETE_KEY);
255 c.getActionMap().put(VK_DELETE_KEY, new AbstractAction() {
256
257 public void actionPerformed(ActionEvent e) {
258
259 BoundedTableModel dataModel = bar.getDataModel();
260 ListSelectionModel selectionModel = bar.getSelectionModel();
261 MarkerMutationModel mutationModel = bar.getMutationModel();
262
263 if (selectionModel != null && dataModel != null
264 && mutationModel != null
265 && !selectionModel.isSelectionEmpty()) {
266 int selected = selectionModel.getLeadSelectionIndex();
267 if (dataModel.isCellEditable(selected, bar
268 .getPositionColumn())) {
269 mutationModel.removeMarkerAtIndex(selected);
270 }
271 }
272 }
273 });
274 }
275
276 public void uninstallKeyboardActions(JComponent c) {
277 c.getActionMap().remove(VK_DELETE_KEY);
278 c.getInputMap().remove(DELETE_KEYSTROKE);
279 }
280
281 public void componentResized(ComponentEvent e) {
282
283 }
284
285 public void componentMoved(ComponentEvent e) {
286
287 }
288
289 public void componentShown(ComponentEvent e) {
290
291 }
292
293 public void componentHidden(ComponentEvent e) {
294
295 }
296
297 public void tableChanged(TableModelEvent e) {
298 bar.repaint();
299
300 }
301
302 public void valueChanged(ListSelectionEvent e) {
303 bar.repaint();
304
305 }
306 }
0 package com.michaelbaranov.microba.marker.ui;
1
2 import java.awt.Insets;
3 import java.awt.Polygon;
4 import java.awt.Rectangle;
5
6 import javax.swing.SwingConstants;
7 import javax.swing.plaf.ComponentUI;
8
9 import com.michaelbaranov.microba.common.BoundedTableModel;
10 import com.michaelbaranov.microba.marker.MarkerBar;
11
12 public class MarkerBarUI extends ComponentUI {
13
14 protected int MARKER_BODY_WIDTH = 12;
15
16 protected int MARKER_BODY_HEIGHT = 12;
17
18 protected int MARKER_BICK_HEIGHT = 6;
19
20 protected int baselineLeft;
21
22 protected int baselineTop;
23
24 protected int baselineLength;
25
26 protected Rectangle viewRect = new Rectangle();
27
28 protected Polygon[] polys = new Polygon[0];
29
30 protected Polygon[] calculateMarkerAreas(MarkerBar bar) {
31
32 BoundedTableModel model = bar.getDataModel();
33
34 int count = model.getRowCount();
35
36 if (polys.length < count) {
37 // grow shared polygon array
38 polys = new Polygon[count * 2];
39 for (int i = 0; i < polys.length; i++) {
40 int xx[] = new int[5];
41 int yy[] = new int[5];
42 Polygon p = new Polygon(xx, yy, 5);
43 polys[i] = p;
44 }
45 }
46
47 for (int i = 0; i < count; i++) {
48 int intValueAt = ((Integer) model.getValueAt(i, bar
49 .getPositionColumn())).intValue();
50
51 int logicalOffset = intValueAt - model.getLowerBound();
52
53 int baselineOffset = logicalOffsetToBaselineOffset(logicalOffset,
54 model);
55 int xx[] = polys[i].xpoints;
56 int yy[] = polys[i].ypoints;
57
58 if (bar.getOrientation() == SwingConstants.HORIZONTAL) {
59
60 int x = baselineLeft + baselineOffset;
61 if (bar.isFliped()) {
62 xx[0] = x;
63 yy[0] = baselineTop;
64
65 xx[1] = x + MARKER_BODY_WIDTH / 2;
66 yy[1] = baselineTop + MARKER_BICK_HEIGHT;
67
68 xx[2] = x + MARKER_BODY_WIDTH / 2;
69 yy[2] = baselineTop + MARKER_BICK_HEIGHT
70 + MARKER_BODY_HEIGHT;
71
72 xx[3] = x - MARKER_BODY_WIDTH / 2;
73 yy[3] = baselineTop + MARKER_BICK_HEIGHT
74 + MARKER_BODY_HEIGHT;
75
76 xx[4] = x - MARKER_BODY_WIDTH / 2;
77 yy[4] = baselineTop + MARKER_BICK_HEIGHT;
78
79 } else {
80
81 xx[0] = x;
82 yy[0] = baselineTop;
83
84 xx[1] = x + MARKER_BODY_WIDTH / 2;
85 yy[1] = baselineTop - MARKER_BICK_HEIGHT;
86
87 xx[2] = x + MARKER_BODY_WIDTH / 2;
88 yy[2] = baselineTop - MARKER_BICK_HEIGHT
89 - MARKER_BODY_HEIGHT;
90
91 xx[3] = x - MARKER_BODY_WIDTH / 2;
92 yy[3] = baselineTop - MARKER_BICK_HEIGHT
93 - MARKER_BODY_HEIGHT;
94
95 xx[4] = x - MARKER_BODY_WIDTH / 2;
96 yy[4] = baselineTop - MARKER_BICK_HEIGHT;
97 }
98
99 } else {
100 int y = baselineLeft + baselineOffset;
101
102 if (bar.isFliped()) {
103 xx[0] = baselineTop;
104 yy[0] = y;
105
106 yy[1] = y + MARKER_BODY_WIDTH / 2;
107 xx[1] = baselineTop - MARKER_BICK_HEIGHT;
108
109 yy[2] = y + MARKER_BODY_WIDTH / 2;
110 xx[2] = baselineTop - MARKER_BICK_HEIGHT
111 - MARKER_BODY_HEIGHT;
112
113 yy[3] = y - MARKER_BODY_WIDTH / 2;
114 xx[3] = baselineTop - MARKER_BICK_HEIGHT
115 - MARKER_BODY_HEIGHT;
116
117 yy[4] = y - MARKER_BODY_WIDTH / 2;
118 xx[4] = baselineTop - MARKER_BICK_HEIGHT;
119 } else {
120
121 xx[0] = baselineTop;
122 yy[0] = y;
123
124 yy[1] = y + MARKER_BODY_WIDTH / 2;
125 xx[1] = baselineTop + MARKER_BICK_HEIGHT;
126
127 yy[2] = y + MARKER_BODY_WIDTH / 2;
128 xx[2] = baselineTop + MARKER_BICK_HEIGHT
129 + MARKER_BODY_HEIGHT;
130
131 yy[3] = y - MARKER_BODY_WIDTH / 2;
132 xx[3] = baselineTop + MARKER_BICK_HEIGHT
133 + MARKER_BODY_HEIGHT;
134
135 yy[4] = y - MARKER_BODY_WIDTH / 2;
136 xx[4] = baselineTop + MARKER_BICK_HEIGHT;
137 }
138
139 }
140 polys[i].invalidate();
141
142 }
143 return polys;
144 }
145
146 protected int logicalOffsetToBaselineOffset(int logicalOffset,
147 BoundedTableModel model) {
148 int positionRange = model.getUpperBound() - model.getLowerBound();
149 return logicalOffset * baselineLength / positionRange;
150 }
151
152 protected int baselineOffsetToLogicalOffset(int baselineOffset,
153 BoundedTableModel model) {
154 int positionRange = model.getUpperBound() - model.getLowerBound();
155 return baselineOffset * positionRange / baselineLength;
156 }
157
158 protected int componentOffsetToLogicalOffset(int componentOffsetLeft,
159 BoundedTableModel dataModel) {
160 return baselineOffsetToLogicalOffset(
161 componentOffsetLeft - baselineLeft, dataModel);
162 }
163
164 protected void calculateViewRectAndBaseline(MarkerBar bar) {
165 Insets insets = bar.getInsets();
166 viewRect.x = insets.left;
167 viewRect.y = insets.top;
168 viewRect.width = bar.getWidth() - (insets.right + viewRect.x);
169 viewRect.height = bar.getHeight() - (insets.bottom + viewRect.y);
170
171 if (bar.getOrientation() == SwingConstants.HORIZONTAL) {
172 baselineLeft = viewRect.x + MARKER_BODY_WIDTH / 2;
173 baselineLength = viewRect.width - MARKER_BODY_WIDTH - 1;
174 if (bar.isFliped()) {
175 baselineTop = viewRect.y;
176 } else {
177 baselineTop = viewRect.y + viewRect.height - 1;
178 }
179 } else {
180 baselineLeft = viewRect.y + MARKER_BODY_WIDTH / 2;
181 baselineLength = viewRect.height - MARKER_BODY_WIDTH - 1;
182 if (bar.isFliped()) {
183 baselineTop = viewRect.x + viewRect.width - 1;
184 } else {
185 baselineTop = viewRect.x;
186 }
187 }
188 }
189
190 public int getMarkerSideGap() {
191 return MARKER_BODY_WIDTH / 2;
192 }
193
194 }
0 package com.michaelbaranov.microba.marker.ui.basic;
1
2 import java.awt.Color;
3 import java.awt.Dimension;
4 import java.awt.Graphics;
5 import java.awt.Insets;
6 import java.awt.Polygon;
7 import java.awt.Rectangle;
8 import java.awt.event.MouseMotionListener;
9
10 import javax.swing.JComponent;
11 import javax.swing.ListSelectionModel;
12 import javax.swing.LookAndFeel;
13 import javax.swing.SwingConstants;
14 import javax.swing.UIManager;
15 import javax.swing.plaf.ComponentUI;
16 import javax.swing.plaf.basic.BasicGraphicsUtils;
17
18 import com.michaelbaranov.microba.common.BoundedTableModel;
19 import com.michaelbaranov.microba.marker.MarkerBar;
20 import com.michaelbaranov.microba.marker.ui.MarkerBarListener;
21 import com.michaelbaranov.microba.marker.ui.MarkerBarUI;
22
23 public class BasicMarkerBarUI extends MarkerBarUI {
24
25 private Color selectionColor;
26
27 private Color shadowColor;
28
29 private Color focusColor;
30
31 private Color disabledColor;
32
33 private Color normalColor;
34
35 private Color textColor;
36
37 public static ComponentUI createUI(JComponent c) {
38 return new BasicMarkerBarUI();
39 }
40
41 public void installUI(JComponent component) {
42 installListeners((MarkerBar) component);
43 installKeyboardActions((MarkerBar) component);
44 installDefaults((MarkerBar) component);
45 }
46
47 public void uninstallUI(JComponent component) {
48 uninstallListeners((MarkerBar) component);
49 uninstallKeyboardActions((MarkerBar) component);
50 }
51
52 protected void installDefaults(MarkerBar bar) {
53 LookAndFeel.installBorder(bar, "Slider.border");
54 LookAndFeel.installColors(bar, "Slider.background", "Slider.foreground");
55
56 // selectedmark
57 selectionColor = UIManager.getColor("ComboBox.selectionBackground");
58 // fixed mark
59 disabledColor = UIManager.getColor("ComboBox.disabledBackground");
60 normalColor = UIManager.getColor("ComboBox.background");
61 // focus rect
62 focusColor = UIManager.getColor("Slider.focus");
63 // text & outline color
64 textColor = UIManager.getColor("textText");
65
66 }
67
68 protected void installKeyboardActions(MarkerBar bar) {
69 MarkerBarListener listener = lookupListsner(bar);
70 if (listener != null)
71 listener.installKeyboardActions(bar);
72
73 }
74
75 protected void uninstallKeyboardActions(MarkerBar bar) {
76 MarkerBarListener listener = lookupListsner(bar);
77 if (listener != null)
78 listener.uninstallKeyboardActions(bar);
79
80 }
81
82 protected void installListeners(MarkerBar markerBar) {
83 MarkerBarListener listener = createListener(markerBar);
84
85 if (markerBar.getDataModel() != null)
86 markerBar.getDataModel().addTableModelListener(listener);
87 if (markerBar.getSelectionModel() != null)
88 markerBar.getSelectionModel().addListSelectionListener(listener);
89 markerBar.addMouseListener(listener);
90 markerBar.addMouseMotionListener(listener);
91 markerBar.addFocusListener(listener);
92 markerBar.addPropertyChangeListener(listener);
93 markerBar.addComponentListener(listener);
94 }
95
96 protected void uninstallListeners(MarkerBar markerBar) {
97 MarkerBarListener listener = lookupListsner(markerBar);
98 if (listener != null) {
99 if (markerBar.getDataModel() != null)
100 markerBar.getDataModel().removeTableModelListener(listener);
101 if (markerBar.getSelectionModel() != null)
102 markerBar.getSelectionModel().removeListSelectionListener(listener);
103 markerBar.removeMouseListener(listener);
104 markerBar.removeMouseMotionListener(listener);
105 markerBar.removeFocusListener(listener);
106 markerBar.removePropertyChangeListener(listener);
107 markerBar.addComponentListener(listener);
108 }
109
110 }
111
112 protected MarkerBarListener lookupListsner(MarkerBar markerBar) {
113 MouseMotionListener[] listeners = markerBar.getMouseMotionListeners();
114
115 if (listeners != null) {
116 for (int counter = 0; counter < listeners.length; counter++) {
117 if (listeners[counter] instanceof MarkerBarListener) {
118 return (MarkerBarListener) listeners[counter];
119 }
120 }
121 }
122 return null;
123 }
124
125 protected MarkerBarListener createListener(MarkerBar markerBar) {
126 return new MarkerBarListener(this, markerBar);
127 }
128
129 public void paint(Graphics g, JComponent c) {
130
131 MarkerBar bar = (MarkerBar) c;
132
133 calculateViewRectAndBaseline(bar);
134
135 if (bar.isFocusOwner())
136 drawFocusRect(g, viewRect);
137
138 BoundedTableModel dataModel = bar.getDataModel();
139 if (dataModel == null)
140 return;
141
142 int numAreas = dataModel.getRowCount();
143 Polygon areas[] = calculateMarkerAreas(bar);
144
145 ListSelectionModel selectionModel = bar.getSelectionModel();
146
147 for (int i = 0; i < numAreas; i++) {
148 boolean isMovable = dataModel.isCellEditable(i, bar.getPositionColumn());
149 boolean isLeadSelect = (selectionModel == null || selectionModel
150 .isSelectionEmpty()) ? false
151 : selectionModel.getLeadSelectionIndex() == i;
152 if (!isLeadSelect)
153 drawMarker(g, areas[i], false, (Color) dataModel.getValueAt(i, bar
154 .getColorColumn()));
155 }
156
157 if (selectionModel != null && !selectionModel.isSelectionEmpty()) {
158 int selectedIndex = selectionModel.getLeadSelectionIndex();
159 boolean isMovable = dataModel.isCellEditable(selectedIndex, bar
160 .getPositionColumn());
161
162 if (selectedIndex < numAreas) {
163 drawMarker(g, areas[selectedIndex], /* bar.isFocusOwner() */
164 true, (Color) dataModel.getValueAt(selectedIndex, bar.getColorColumn()));
165 } else {
166 throw new IllegalStateException(
167 "Selection model inconsistent with data model: " + "element at "
168 + selectedIndex + " selected, but does not exist.");
169 }
170 }
171
172 }
173
174 protected void drawFocusRect(Graphics g, Rectangle viewRect) {
175 g.setColor(getFocusColor());
176
177 BasicGraphicsUtils.drawDashedRect(g, viewRect.x, viewRect.y, viewRect.width,
178 viewRect.height);
179 }
180
181 protected void drawMarker(Graphics g, Polygon p, boolean isSelected, Color color) {
182
183 Color innerColor = color != null ? color : getNormalColor();
184 // Color selColor = getSelectionColor();
185 Color selColor = isSelected ? getTextColor() : innerColor;
186
187 // body
188 g.setColor(innerColor);
189 g.fillPolygon(p);
190
191 // bick
192
193 if (isSelected) {
194 int xx[] = new int[3];
195 int yy[] = new int[3];
196
197 xx[0] = p.xpoints[0];
198 xx[1] = p.xpoints[1];
199 xx[2] = p.xpoints[p.npoints - 1];
200 yy[0] = p.ypoints[0];
201 yy[1] = p.ypoints[1];
202 yy[2] = p.ypoints[p.npoints - 1];
203
204 Polygon bickP = new Polygon(xx, yy, 3);
205 g.setColor(selColor);
206 g.fillPolygon(bickP);
207 g.drawPolygon(bickP);
208 }
209
210 // outline
211 g.setColor(getTextColor());
212 g.drawPolygon(p);
213
214 }
215
216 public Dimension getMinimumSize(JComponent c) {
217 MarkerBar bar = (MarkerBar) c;
218 Insets ins = bar.getInsets();
219
220 if (bar.getOrientation() == SwingConstants.HORIZONTAL)
221 return new Dimension(MARKER_BODY_WIDTH + ins.left + ins.right + 1,
222 MARKER_BODY_HEIGHT + ins.top + ins.bottom + 1);
223 else
224 return new Dimension(MARKER_BODY_HEIGHT + ins.top + ins.bottom + 1,
225 MARKER_BODY_WIDTH + ins.left + ins.right + 1);
226 }
227
228 public Dimension getPreferredSize(JComponent c) {
229
230 MarkerBar bar = (MarkerBar) c;
231 BoundedTableModel dataModel = bar.getDataModel();
232 Insets ins = bar.getInsets();
233
234 int r;
235 if (dataModel == null)
236 r = 1;
237 else
238 r = dataModel.getUpperBound() - dataModel.getLowerBound();
239
240 if (bar.getOrientation() == SwingConstants.HORIZONTAL)
241 return new Dimension((r) * 2 + MARKER_BODY_WIDTH + ins.left + ins.right + 1,
242 MARKER_BODY_HEIGHT + MARKER_BICK_HEIGHT + ins.top + ins.bottom + 1);
243 else
244 return new Dimension(MARKER_BODY_HEIGHT + MARKER_BICK_HEIGHT + ins.top
245 + ins.bottom + 1, (r) * 2 + MARKER_BODY_WIDTH + ins.left + ins.right
246 + 1);
247
248 }
249
250 public Color getFocusColor() {
251 return focusColor;
252 }
253
254 public Color getShadowColor() {
255 return shadowColor;
256 }
257
258 public Color getNormalColor() {
259 return normalColor;
260 }
261
262 public Color getSelectionColor() {
263 return selectionColor;
264 }
265
266 public Color getDisabledColor() {
267 return disabledColor;
268 }
269
270 public Color getTextColor() {
271 return textColor;
272 }
273
274 }
0 package com.michaelbaranov.microba.marker.ui.metal;
1
2 import java.awt.Graphics;
3 import java.awt.Rectangle;
4
5 import javax.swing.JComponent;
6 import javax.swing.plaf.ComponentUI;
7
8 import com.michaelbaranov.microba.marker.ui.basic.BasicMarkerBarUI;
9
10 public class MetalMarkerBarUI extends BasicMarkerBarUI {
11
12 public static ComponentUI createUI(JComponent c) {
13 return new MetalMarkerBarUI();
14 }
15
16 protected void drawFocusRect(Graphics g, Rectangle viewRect) {
17 g.setColor(getFocusColor());
18
19 g.drawRect(viewRect.x, viewRect.y, viewRect.width - 1, viewRect.height - 1);
20 }
21
22 }
0 package com.michaelbaranov.microba.marker.ui.motif;
1
2 import java.awt.Graphics;
3 import java.awt.Rectangle;
4
5 import javax.swing.JComponent;
6 import javax.swing.plaf.ComponentUI;
7
8 import com.michaelbaranov.microba.marker.ui.basic.BasicMarkerBarUI;
9
10 public class MotifMarkerBarUI extends BasicMarkerBarUI {
11
12 public static ComponentUI createUI(JComponent c) {
13 return new MotifMarkerBarUI();
14 }
15
16 protected void drawFocusRect(Graphics g, Rectangle viewRect) {
17 // focus painting is handled by the border
18 }
19
20 }
0 package com.michaelbaranov.microba.marker.ui.windows;
1
2 import java.awt.Graphics;
3 import java.awt.Rectangle;
4
5 import javax.swing.JComponent;
6 import javax.swing.UIManager;
7 import javax.swing.plaf.ComponentUI;
8 import javax.swing.plaf.basic.BasicGraphicsUtils;
9
10 import com.michaelbaranov.microba.marker.MarkerBar;
11 import com.michaelbaranov.microba.marker.ui.basic.BasicMarkerBarUI;
12
13 public class WindowsMarkerBarUI extends BasicMarkerBarUI {
14
15 private int dashedRectGapX;
16
17 private int dashedRectGapY;
18
19 private int dashedRectGapWidth;
20
21 private int dashedRectGapHeight;
22
23 private boolean defaults_initialized;
24
25 public static ComponentUI createUI(JComponent c) {
26 return new WindowsMarkerBarUI();
27 }
28
29 protected void drawFocusRect(Graphics g, Rectangle viewRect) {
30 g.setColor(getFocusColor());
31
32 g.setColor(getFocusColor());
33 // BasicGraphicsUtils.drawDashedRect(g, dashedRectGapX, dashedRectGapY,
34 // viewRect.width - dashedRectGapWidth, viewRect.height
35 // - dashedRectGapHeight);
36 BasicGraphicsUtils.drawDashedRect(g, viewRect.x, viewRect.y, viewRect.width - 1,
37 viewRect.height - 1);
38 }
39
40 protected void installDefaults(MarkerBar b) {
41 super.installDefaults(b);
42 // if(!defaults_initialized) {
43 dashedRectGapX = UIManager.getInt("Button.dashedRectGapX");
44 dashedRectGapY = UIManager.getInt("Button.dashedRectGapY");
45 dashedRectGapWidth = UIManager.getInt("Button.dashedRectGapWidth");
46 dashedRectGapHeight = UIManager.getInt("Button.dashedRectGapHeight");
47 // focusColor = UIManager.getColor(pp + "focus");
48 defaults_initialized = true;
49 }
50 }