1 package com.melloware.jukes.gui.view.component;
2
3 import java.text.DateFormat;
4
5 import javax.swing.AbstractAction;
6 import javax.swing.AbstractButton;
7 import javax.swing.JFormattedTextField;
8 import javax.swing.JToggleButton;
9 import javax.swing.filechooser.FileFilter;
10 import javax.swing.text.DefaultFormatter;
11 import javax.swing.text.DefaultFormatterFactory;
12 import javax.swing.text.JTextComponent;
13
14 import com.jgoodies.binding.adapter.BasicComponentFactory;
15 import com.jgoodies.binding.adapter.Bindings;
16 import com.jgoodies.binding.value.ValueModel;
17 import com.jgoodies.uif.action.ActionManager;
18 import com.jgoodies.uif.component.ToolBarButton;
19 import com.jgoodies.validation.formatter.RelativeDateFormatter;
20 import com.melloware.jukes.gui.tool.Actions;
21 import com.melloware.jukes.gui.tool.Resources;
22
23 /**
24 * Consists only of static methods that vend formatted text fields used
25 * to edit dates that are bound to an underlying ValueModel.
26 * Extends the Binding library's BasicComponentFactory to inherit
27 * all factory metods from that class.
28 * <p>
29 * Copyright (c) 1999-2007 Melloware, Inc. <http://www.melloware.com>
30 * @author Emil A. Lefkof III <info@melloware.com>
31 * @version 4.0
32 *
33 * @see com.jgoodies.binding.adapter.BasicComponentFactory
34 * @see com.jgoodies.binding.adapter.Bindings
35 */
36 public final class ComponentFactory
37 extends BasicComponentFactory {
38
39 private ComponentFactory() {
40 // Suppresses default constructor, ensuring non-instantiability.
41 }
42
43
44
45 /**
46 * Creates and returns a formatted text field that is bound
47 * to the Date value of the given <code>ValueModel</code>.<p>
48 *
49 * The JFormattedTextField is configured with an AbstractFormatter
50 * that uses two different DateFormats to edit and display the Date.
51 * A <code>SHORT</code> DateFormat with strict checking is used to edit
52 * (parse) a date; the DateFormatter's default DateFormat is used to
53 * display (format) a date. In both cases <code>null</code> Dates are
54 * mapped to the empty String.<p>
55 *
56 * In addition to formatted Dates, the parser accepts positive and
57 * negative integers and interprets them as Dates relative to today.
58 * For example -1 is yesterday, 1 is tomorrow, and 7 is "in a week".<p>
59 *
60 * Yesterday, today, and tomorrow are displayed as these Strings,
61 * not as formatted Dates.
62 *
63 * @param valueModel the model that holds the value to be edited
64 * @return a formatted text field for Date instances that is bound
65 * @throws NullPointerException if the model is <code>null</code>
66 */
67 public static JFormattedTextField createDateField(ValueModel valueModel) {
68 return createDateField(valueModel, true);
69 }
70
71 /**
72 * Creates and returns a formatted text field that is bound
73 * to the Date value of the given <code>ValueModel</code>.<p>
74 *
75 * The JFormattedTextField is configured with an AbstractFormatter
76 * that uses two different DateFormats to edit and display the Date.
77 * A <code>SHORT</code> DateFormat with strict checking is used to edit
78 * (parse) a date; the DateFormatter's default DateFormat is used to
79 * display (format) a date. In both cases <code>null</code> Dates are
80 * mapped to the empty String.<p>
81 *
82 * In addition to formatted Dates, the parser accepts positive and
83 * negative integers and interprets them as Dates relative to today.
84 * For example -1 is yesterday, 1 is tomorrow, and 7 is "in a week".<p>
85 *
86 * If <code>enableShortcuts</code> is set to <code>true</code>,
87 * yesterday, today, and tomorrow are displayed as these Strings,
88 * not as formatted Dates.
89 *
90 * @param valueModel the model that holds the value to be edited
91 * @param enableShortcuts true to display yesterday, today, and tomorrow
92 * with natural language strings
93 * @return a formatted text field for Date instances that is bound
94 * @throws NullPointerException if the model is <code>null</code>
95 */
96 public static JFormattedTextField createDateField(ValueModel valueModel, boolean enableShortcuts) {
97 return createDateField(valueModel, enableShortcuts, false);
98 }
99
100 /**
101 * Creates and returns a formatted text field that is bound
102 * to the Date value of the given <code>ValueModel</code>.<p>
103 *
104 * The JFormattedTextField is configured with an AbstractFormatter
105 * that uses two different DateFormats to edit and display the Date.
106 * A <code>SHORT</code> DateFormat with strict checking is used to edit
107 * (parse) a date; the DateFormatter's default DateFormat is used to
108 * display (format) a date. In both cases <code>null</code> Dates are
109 * mapped to the empty String.<p>
110 *
111 * In addition to formatted Dates, the parser accepts positive and
112 * negative integers and interprets them as Dates relative to today.
113 * For example -1 is yesterday, 1 is tomorrow, and 7 is "in a week".<p>
114 *
115 * If <code>enableShortcuts</code> is set to <code>true</code>,
116 * yesterday, today, and tomorrow are displayed as these Strings,
117 * not as formatted Dates.
118 *
119 * @param valueModel the model that holds the value to be edited
120 * @param enableShortcuts true to display yesterday, today, and tomorrow
121 * with natural language strings
122 * @param commitsOnValidEdit true to commit on valid edit,
123 * false to commit on focus lost
124 * @return a formatted text field for Date instances that is bound
125 * @throws NullPointerException if the model is <code>null</code>
126 */
127 public static JFormattedTextField createDateField(ValueModel valueModel,
128 boolean enableShortcuts,
129 boolean commitsOnValidEdit) {
130 DateFormat shortFormat = DateFormat.getDateInstance(DateFormat.SHORT);
131 shortFormat.setLenient(false);
132
133 DefaultFormatter defaultFormatter = new RelativeDateFormatter(shortFormat, false, true);
134 defaultFormatter.setCommitsOnValidEdit(commitsOnValidEdit);
135
136 JFormattedTextField.AbstractFormatter displayFormatter = new RelativeDateFormatter(enableShortcuts, true);
137
138 DefaultFormatterFactory formatterFactory = new DefaultFormatterFactory(defaultFormatter, displayFormatter);
139
140 JFormattedTextField textField = new JFormattedTextField(formatterFactory);
141 Bindings.bind(textField, valueModel);
142 return textField;
143 }
144
145 /**
146 * Create a new button that is a directory chooser button and associates
147 * it with a text component to put the selected directory in.
148 * <p>
149 * @param aTextComponent the text component to title case
150 * @return an Abstract button that is the title case button
151 */
152 public static AbstractButton createDirectoryChooserButton(JTextComponent aTextComponent) {
153 final AbstractAction action = (AbstractAction)ActionManager.get(Actions.DIRECTORY_ID);
154 AbstractButton button = new ToolBarButton(action);
155 button.putClientProperty(Resources.TEXT_COMPONENT, aTextComponent);
156 button.setOpaque(false);
157 button.setVerifyInputWhenFocusTarget(true);
158 return button;
159 }
160
161 /**
162 * Create a new button that is a file chooser button and associates
163 * it with a text component to put the selected file in.
164 * <p>
165 * @param aTextComponent the text component to title case
166 * @param aTitle the title of the chooser dialog
167 * @param aFilter the file filter for the chooser
168 * @return an Abstract button that is the title case button
169 */
170 public static AbstractButton createFileChooserButton(JTextComponent aTextComponent,
171 String aTitle,
172 FileFilter aFilter) {
173 final AbstractAction action = (AbstractAction)ActionManager.get(Actions.FILE_CHOOSER_ID);
174 AbstractButton button = new ToolBarButton(action);
175 button.putClientProperty(Resources.TEXT_COMPONENT, aTextComponent);
176 button.putClientProperty(Resources.FILE_CHOOSER_FILTER, aFilter);
177 button.putClientProperty(Resources.FILE_CHOOSER_TITLE, aTitle);
178 button.setOpaque(false);
179 button.setVerifyInputWhenFocusTarget(true);
180 return button;
181 }
182
183 /**
184 * Create a new button that is a title case button and associates it with a
185 * text component to actually perform the title casing on.
186 * <p>
187 * @param aTextComponent the text component to title case
188 * @return an Abstract button that is the title case button
189 */
190 public static AbstractButton createTitleCaseButton(JTextComponent aTextComponent) {
191 final AbstractAction action = (AbstractAction)ActionManager.get(Actions.TITLECASE_ID);
192 AbstractButton button = new ToolBarButton(action);
193 button.putClientProperty(Resources.TEXT_COMPONENT, aTextComponent);
194 button.setOpaque(false);
195 button.setVerifyInputWhenFocusTarget(true);
196 return button;
197 }
198
199 /**
200 * Create a new tool bar button from an Action.
201 * <p>
202 * @param aActionId the actionId to create the button for
203 * @return an Abstract button that is the title case button
204 */
205 public static AbstractButton createToolBarButton(String aActionId) {
206 final AbstractAction action = (AbstractAction)ActionManager.get(aActionId);
207 AbstractButton button = new ToolBarButton(action);
208 button.setOpaque(false);
209 button.setVerifyInputWhenFocusTarget(true);
210 return button;
211 }
212
213 /**
214 * Create a new tool bar toggle button from an Action.
215 * <p>
216 * @param aActionId the actionId to create the button for
217 * @return an Abstract button that is the title case button
218 */
219 public static AbstractButton createToolBarToggleButton(String aActionId) {
220 final AbstractAction action = (AbstractAction)ActionManager.get(aActionId);
221 AbstractButton button = new JToggleButton(action);
222 button.setText("");
223 button.setOpaque(false);
224 button.setVerifyInputWhenFocusTarget(true);
225 return button;
226 }
227
228 }