|
|||||||||||||||||||
Source file | Conditionals | Statements | Methods | TOTAL | |||||||||||||||
DynamicResource.java | 52.6% | 68% | 76.2% | 65.4% |
|
1 |
/*
|
|
2 |
* SimplyHTML, a word processor based on Java, HTML and CSS
|
|
3 |
* Copyright (C) 2002 Ulrich Hilger
|
|
4 |
*
|
|
5 |
* This program is free software; you can redistribute it and/or
|
|
6 |
* modify it under the terms of the GNU General Public License
|
|
7 |
* as published by the Free Software Foundation; either version 2
|
|
8 |
* of the License, or (at your option) any later version.
|
|
9 |
*
|
|
10 |
* This program is distributed in the hope that it will be useful,
|
|
11 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13 |
* GNU General Public License for more details.
|
|
14 |
*
|
|
15 |
* You should have received a copy of the GNU General Public License
|
|
16 |
* along with this program; if not, write to the Free Software
|
|
17 |
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
18 |
*/
|
|
19 |
|
|
20 |
import java.awt.Component;
|
|
21 |
import java.util.ResourceBundle;
|
|
22 |
import java.util.MissingResourceException;
|
|
23 |
import java.util.Locale;
|
|
24 |
import java.util.Hashtable;
|
|
25 |
import java.util.Enumeration;
|
|
26 |
import javax.swing.event.*;
|
|
27 |
import javax.swing.*;
|
|
28 |
import java.beans.PropertyChangeListener;
|
|
29 |
import java.beans.PropertyChangeEvent;
|
|
30 |
import java.net.URL;
|
|
31 |
|
|
32 |
/**
|
|
33 |
* Provides methods to dynamically combine components and resource bundles.
|
|
34 |
*
|
|
35 |
* <p>The actions, menus and menuitems created by this object are
|
|
36 |
* stored privately inside this object. This allows for later
|
|
37 |
* access to one of the stored items through the action command name.</p>
|
|
38 |
*
|
|
39 |
* <p><b>IMPORTANT:</b> Action command names must be unique, if actions
|
|
40 |
* or menus are added to an instance of this class and if the actions or
|
|
41 |
* menus are defined in different ResourceBundles, the action names
|
|
42 |
* must be unique over all ResourceBundles involved, because the action
|
|
43 |
* names are used as identifiers for connection of actions to compnents
|
|
44 |
* such as menus and menu items.</p>
|
|
45 |
*
|
|
46 |
* <p>Component creation methods such as createMenu or createMenuItem
|
|
47 |
* expect definitions coming from a ResourceBundle, typically a
|
|
48 |
* text file ending with '.properties'.</p>
|
|
49 |
*
|
|
50 |
* <p>
|
|
51 |
* Inside the .properties file, a menu definition is looking similar to
|
|
52 |
* <pre>
|
|
53 |
* # plugin menu definition
|
|
54 |
* plugin=test1 test2 test3
|
|
55 |
* pluginLabel=Test Plug-In
|
|
56 |
*
|
|
57 |
* # plugin menu items
|
|
58 |
* test1Label=Test 1
|
|
59 |
* test1Image=images/test1.gif
|
|
60 |
* test1Tip=test menu item 1
|
|
61 |
* test2Label=Test 2
|
|
62 |
* test3Label=Test 3
|
|
63 |
* </pre>
|
|
64 |
* </p>
|
|
65 |
*
|
|
66 |
* <p>
|
|
67 |
* The calling class has to define actions named accordingly, e.g.
|
|
68 |
* <pre>
|
|
69 |
* DynamicResource dynRes = new DynamicResource("com.foo.bar.myPlugin");
|
|
70 |
* dynRes.addAction("test1", new MyAction("test1");
|
|
71 |
* dynRes.addAction("test2", new MyAction("test2");
|
|
72 |
* dynRes.addAction("test3", new MyAction("test3");
|
|
73 |
* </pre>
|
|
74 |
* </p>
|
|
75 |
*
|
|
76 |
* @author Ulrich Hilger
|
|
77 |
* @author Light Development
|
|
78 |
* @author <a href="http://www.lightdev.com">http://www.lightdev.com</a>
|
|
79 |
* @author <a href="mailto:info@lightdev.com">info@lightdev.com</a>
|
|
80 |
* @author published under the terms and conditions of the
|
|
81 |
* GNU General Public License,
|
|
82 |
* for details see file gpl.txt in the distribution
|
|
83 |
* package of this software
|
|
84 |
*
|
|
85 |
* @version stage 11, April 27, 2003
|
|
86 |
*/
|
|
87 |
|
|
88 |
public class DynamicResource { |
|
89 |
|
|
90 |
/** name constant for labels in the resource file */
|
|
91 |
private static final String labelSuffix = "Label"; |
|
92 |
|
|
93 |
/** name constant for action commands in the resource file */
|
|
94 |
private static final String actionSuffix = "Action"; |
|
95 |
|
|
96 |
/** name constant for indicating image resources in the resource file */
|
|
97 |
public static final String imageSuffix = "Image"; |
|
98 |
|
|
99 |
/** name constant for tool tip strings in the resource file */
|
|
100 |
public static final String toolTipSuffix = "Tip"; |
|
101 |
|
|
102 |
/** name constant for selected icon names in the resource file */
|
|
103 |
public static final String selectedIconSuffix = "SelectedIcon"; |
|
104 |
|
|
105 |
/** indicator for menu separators */
|
|
106 |
public static final String menuSeparatorKey = "-"; |
|
107 |
|
|
108 |
/** dynamic storage for menu items */
|
|
109 |
private Hashtable menuItems = new Hashtable(); |
|
110 |
|
|
111 |
/** dynamic storage for actions */
|
|
112 |
private Hashtable commands = new Hashtable(); |
|
113 |
|
|
114 |
/** dynamic storage for menus */
|
|
115 |
private Hashtable menus = new Hashtable(); |
|
116 |
|
|
117 |
public static final String IMAGE_EMPTY = "empty.gif"; |
|
118 |
|
|
119 |
/**
|
|
120 |
* construct a new DynamicResource.
|
|
121 |
*/
|
|
122 | 11 |
public DynamicResource() {
|
123 |
} |
|
124 |
|
|
125 |
/**
|
|
126 |
* add an action to this <code>DynamicResource</code>
|
|
127 |
*
|
|
128 |
* @param cmd the internal identifier for the action
|
|
129 |
* @param action the action to associate with actionCommand
|
|
130 |
*/
|
|
131 | 4800 |
public void addAction(String cmd, Action action) { |
132 | 4800 |
commands.put(cmd, action); |
133 |
} |
|
134 |
|
|
135 |
/**
|
|
136 |
* Create a menu bar. This reads the
|
|
137 |
* definition of the menu from the associated resource file.
|
|
138 |
*
|
|
139 |
* @param resources the ResourceBundle to get the menu definition from
|
|
140 |
* @param name name of the menu bar definition
|
|
141 |
*
|
|
142 |
* @return the created menu bar
|
|
143 |
*/
|
|
144 | 75 |
public JMenuBar createMenubar(ResourceBundle resources, String name) {
|
145 | 75 |
JMenuItem mi; |
146 | 75 |
JMenuBar mb = new JMenuBar();
|
147 | 75 |
String[] menuKeys = Util.tokenize(getResourceString(resources, name), " ");
|
148 | 75 |
for (int i = 0; i < menuKeys.length; i++) { |
149 | 600 |
JMenu m = createMenu(resources, menuKeys[i]); |
150 | 600 |
if (m != null) { |
151 | 600 |
mb.add(m); |
152 |
} |
|
153 |
} |
|
154 | 75 |
return mb;
|
155 |
} |
|
156 |
|
|
157 |
/**
|
|
158 |
* Create a menu for the app. This reads the
|
|
159 |
* definition of the menu from the associated resource file.
|
|
160 |
*
|
|
161 |
* @param resources the ResourceBundle to get the menu definition from
|
|
162 |
* @param key the key of the menu definition in the resource file
|
|
163 |
* @return the created menu
|
|
164 |
*/
|
|
165 | 600 |
public JMenu createMenu(ResourceBundle resources, String key) {
|
166 | 600 |
JMenu menu = null;
|
167 | 600 |
String def = getResourceString(resources, key); |
168 | 600 |
if(def == null) { |
169 | 0 |
def = "";
|
170 |
} |
|
171 | 600 |
String[] itemKeys = Util.tokenize(def, " ");
|
172 | 600 |
menu = new JMenu(getResourceString(resources, key + labelSuffix));
|
173 | 600 |
for (int i = 0; i < itemKeys.length; i++) { |
174 | 6075 |
if (itemKeys[i].equals(menuSeparatorKey)) {
|
175 | 2025 |
menu.addSeparator(); |
176 |
} |
|
177 |
else {
|
|
178 | 4050 |
JMenuItem mi = createMenuItem(resources, itemKeys[i]); |
179 | 4050 |
menu.add(mi); |
180 |
} |
|
181 |
} |
|
182 | 600 |
menu.addMenuListener(new DynamicMenuListener());
|
183 |
/**
|
|
184 |
* store the menu in the menus hashtable for possible later use
|
|
185 |
*/
|
|
186 | 600 |
menus.put(key, menu); |
187 | 600 |
return menu;
|
188 |
} |
|
189 |
|
|
190 | 75 |
public JMenu getMenu(String cmd) {
|
191 | 75 |
return (JMenu) menus.get(cmd);
|
192 |
} |
|
193 |
|
|
194 |
/**
|
|
195 |
* create a menu item
|
|
196 |
*
|
|
197 |
* @param resources the ResourceBundle to get the item definition from
|
|
198 |
* @param cmd the action command to be associated
|
|
199 |
* with the new menu item
|
|
200 |
* @return the created menu item
|
|
201 |
*/
|
|
202 | 4050 |
public JMenuItem createMenuItem(ResourceBundle resources, String cmd) {
|
203 |
/**
|
|
204 |
* create a new menu item with the appropriate label from the
|
|
205 |
* resource file. This label later is set from the action this
|
|
206 |
* menu item is associated to (see below).
|
|
207 |
*/
|
|
208 | 4050 |
JMenuItem mi; |
209 | 4050 |
mi = new JMenuItem(getResourceString(resources, cmd + labelSuffix));
|
210 |
|
|
211 | 4050 |
String astr = getResourceString(resources, cmd + actionSuffix); |
212 | 4050 |
if (astr == null) { |
213 | 4050 |
astr = cmd; |
214 |
} |
|
215 |
//System.out.println(astr);
|
|
216 | 4050 |
mi.setActionCommand(astr); |
217 |
|
|
218 |
/**
|
|
219 |
* connect action and menu item with appropriate listeners
|
|
220 |
*/
|
|
221 | 4050 |
Action a = getAction(astr); |
222 | 4050 |
if (a != null) { |
223 |
//System.out.println(cmd + " not null");
|
|
224 | 4050 |
Object aKey = a.getValue(AbstractAction.ACCELERATOR_KEY); |
225 | 4050 |
if(aKey != null) { |
226 | 1050 |
mi.setAccelerator((KeyStroke) aKey); |
227 |
} |
|
228 |
/**
|
|
229 |
* add Action 'a' as the listener to action events
|
|
230 |
* fired from this menu, i.e. execute action 'a' with
|
|
231 |
* menu item 'mi'
|
|
232 |
*/
|
|
233 | 4050 |
mi.addActionListener(a); |
234 |
|
|
235 |
/**
|
|
236 |
* cause an instance of inner class ActionChangeListener
|
|
237 |
* to listen to property changes of Action 'a' and to apply
|
|
238 |
* changed properties of Action 'a' to menu item 'mi'
|
|
239 |
*/
|
|
240 | 4050 |
a.addPropertyChangeListener(createActionChangeListener(mi)); |
241 |
|
|
242 |
/**
|
|
243 |
* if the action has an image,
|
|
244 |
* associate it with the menu item
|
|
245 |
*/
|
|
246 | 4050 |
Icon icon = (Icon) a.getValue(Action.SMALL_ICON); |
247 | 4050 |
if (icon != null) { |
248 | 2175 |
mi.setHorizontalTextPosition(JButton.RIGHT); |
249 | 2175 |
mi.setIcon(icon); |
250 |
} |
|
251 |
|
|
252 |
/**
|
|
253 |
* initially set the enabled state of the menu item
|
|
254 |
* according to its action's enabled state
|
|
255 |
*/
|
|
256 | 4050 |
mi.setEnabled(a.isEnabled()); |
257 |
} |
|
258 |
else {
|
|
259 | 0 |
mi.setEnabled(false);
|
260 |
} |
|
261 |
|
|
262 |
/**
|
|
263 |
* store the menu item in the menuItems hashtable for possible later use
|
|
264 |
*/
|
|
265 | 4050 |
menuItems.put(cmd, mi); |
266 |
|
|
267 | 4050 |
return mi;
|
268 |
} |
|
269 |
|
|
270 |
/**
|
|
271 |
* get a string from the resources file
|
|
272 |
*
|
|
273 |
* @param resources the ResourceBundle to get the string from
|
|
274 |
* @param nm the key of the string
|
|
275 |
* @return the string for the given key or null if not found
|
|
276 |
*/
|
|
277 | 21143 |
public String getResourceString(ResourceBundle resources, String nm) {
|
278 | 21143 |
String str = null;
|
279 | 21143 |
try {
|
280 |
//System.out.println("getResourceString nm=" + nm);
|
|
281 | 21143 |
str = resources.getString(nm); |
282 |
} |
|
283 |
catch (MissingResourceException mre) { }
|
|
284 | 21143 |
return str;
|
285 |
} |
|
286 |
|
|
287 |
/**
|
|
288 |
* listen to menu select events for proper updating of menu items
|
|
289 |
*
|
|
290 |
* whenever a menu is selected, its menu items are iterated and the
|
|
291 |
* update method of the item's action is called causing
|
|
292 |
* the menu item to reflect the correct enabled state.
|
|
293 |
*
|
|
294 |
* As each menu item is connected with a PropertyChangeListener
|
|
295 |
* listening to property changes on it'Saction, the menu item is
|
|
296 |
* updated by the PropertyChangeListener whenever the enabledState
|
|
297 |
* of the action changes.
|
|
298 |
*/
|
|
299 |
private class DynamicMenuListener implements MenuListener { |
|
300 | 600 |
public DynamicMenuListener() {
|
301 |
} |
|
302 | 0 |
public void menuSelected(MenuEvent e) { |
303 | 0 |
Component[] items = ((JMenu) e.getSource()).getMenuComponents(); |
304 | 0 |
Action action; |
305 | 0 |
for(int i = 0; i < items.length; i++) { |
306 | 0 |
if(items[i] instanceof JPopupMenu.Separator) { |
307 |
} |
|
308 | 0 |
else if(items[i] instanceof JMenuItem) { |
309 | 0 |
action = getAction(((JMenuItem) items[i]).getActionCommand()); |
310 | 0 |
if(action instanceof SHTMLAction) { |
311 | 0 |
((SHTMLAction) action).update(); |
312 |
} |
|
313 |
} |
|
314 |
} |
|
315 |
} |
|
316 | 0 |
public void menuDeselected(MenuEvent e) { |
317 |
} |
|
318 | 0 |
public void menuCanceled(MenuEvent e) { |
319 |
} |
|
320 |
} |
|
321 |
|
|
322 |
/**
|
|
323 |
* get an action from the commands table
|
|
324 |
*
|
|
325 |
* @param cmd the name of the action the get
|
|
326 |
* @return the action found for the given name
|
|
327 |
*/
|
|
328 | 5929 |
public Action getAction(String cmd) {
|
329 | 5929 |
return (Action) commands.get(cmd);
|
330 |
} |
|
331 |
|
|
332 |
/**
|
|
333 |
* get all actions registered in this <code>DynamicResource</code>
|
|
334 |
*
|
|
335 |
* @return all actions
|
|
336 |
*/
|
|
337 | 231 |
public Enumeration getActions() {
|
338 | 231 |
return commands.elements();
|
339 |
} |
|
340 |
|
|
341 |
/** create our PropertyChangeListener implementation */
|
|
342 | 4050 |
private PropertyChangeListener createActionChangeListener(JMenuItem b) {
|
343 | 4050 |
return new ActionChangedListener(b); |
344 |
} |
|
345 |
|
|
346 |
/**
|
|
347 |
* associate a menu item to an action.
|
|
348 |
*
|
|
349 |
* When registering this
|
|
350 |
* action listener with an action, it gets informed by
|
|
351 |
* property changes of that particular action.
|
|
352 |
*
|
|
353 |
* By passing a menu item to the constructor of ActionChangedListener,
|
|
354 |
* an instance of ActionChangedListener 'remembers' the menu item
|
|
355 |
* its property are associated to.
|
|
356 |
*/
|
|
357 |
private class ActionChangedListener implements PropertyChangeListener { |
|
358 |
JMenuItem menuItem; |
|
359 |
|
|
360 | 4050 |
ActionChangedListener(JMenuItem mi) { |
361 | 4050 |
super();
|
362 | 4050 |
this.menuItem = mi;
|
363 |
} |
|
364 |
|
|
365 | 4688 |
public void propertyChange(PropertyChangeEvent e) { |
366 | 4688 |
String propertyName = e.getPropertyName(); |
367 | 4688 |
if (e.getPropertyName().equals(Action.NAME)) {
|
368 | 0 |
String text = (String) e.getNewValue(); |
369 | 0 |
menuItem.setText(text); |
370 |
} |
|
371 | 4688 |
else if (propertyName.equals("enabled")) { |
372 | 4688 |
Boolean enabledState = (Boolean) e.getNewValue(); |
373 | 4688 |
menuItem.setEnabled(enabledState.booleanValue()); |
374 |
} |
|
375 |
} |
|
376 |
} |
|
377 |
|
|
378 |
/**
|
|
379 |
* get the menu item that was created for the given
|
|
380 |
* command.
|
|
381 |
*
|
|
382 |
* @param cmd name of the action.
|
|
383 |
* @return item created for the given command or null
|
|
384 |
* if one wasn't created.
|
|
385 |
*/
|
|
386 | 0 |
public JMenuItem getMenuItem(String cmd) {
|
387 | 0 |
return (JMenuItem) menuItems.get(cmd);
|
388 |
} |
|
389 |
|
|
390 |
/**
|
|
391 |
* get the icon for a given command.
|
|
392 |
*
|
|
393 |
* <p>If the resource bundle has a reference to an icon for the
|
|
394 |
* given commamd, an icon is created for the respective image resource.
|
|
395 |
* otherwise, null is returned.</p>
|
|
396 |
*
|
|
397 |
* @param resources the ResourceBundle to get the icon from
|
|
398 |
* @param cmd the command an icon is requested for
|
|
399 |
*
|
|
400 |
* @return the icon for that command or null, if none is present
|
|
401 |
* for this command
|
|
402 |
*/
|
|
403 | 4876 |
public Icon getIconForCommand(ResourceBundle resources, String cmd) {
|
404 | 4876 |
return getIconForName(resources, cmd + imageSuffix);
|
405 |
} |
|
406 |
|
|
407 | 5326 |
public Icon getIconForName(ResourceBundle resources, String name) {
|
408 | 5326 |
Icon icon = null;
|
409 | 5326 |
URL url = getResource(resources, name); |
410 |
//System.out.println("getIconForName name=" + name + ", url=" + url);
|
|
411 | 5326 |
if (url != null) { |
412 | 2925 |
icon = new ImageIcon(url);
|
413 |
} |
|
414 | 5326 |
return icon;
|
415 |
} |
|
416 |
|
|
417 |
/**
|
|
418 |
* get the location of a resource.
|
|
419 |
*
|
|
420 |
* <p>Resources such as images are delivered with the application in
|
|
421 |
* the path containing the application's classes. The resources file
|
|
422 |
* coming with SimplyHTML has a key for every resource pointing to
|
|
423 |
* the subdirectory relative to the class path.</p>
|
|
424 |
*
|
|
425 |
* @param resources the ResourceBundle to get the resource from
|
|
426 |
* @param key the key of the resource in the resource file
|
|
427 |
* @return the resource location as a URL
|
|
428 |
*/
|
|
429 | 5401 |
public URL getResource(ResourceBundle resources, String key) {
|
430 | 5401 |
String name = getResourceString(resources, key); |
431 | 5401 |
if (name != null/* && !name.endsWith(IMAGE_EMPTY)*/) { |
432 | 3000 |
URL url = this.getClass().getResource(name);
|
433 | 3000 |
return url;
|
434 |
} |
|
435 | 2401 |
return null; |
436 |
} |
|
437 |
|
|
438 |
/**
|
|
439 |
* Create a tool bar. This reads the definition of a tool bar
|
|
440 |
* from the associated resource file.
|
|
441 |
*
|
|
442 |
* @param resources the ResourceBundle to get the tool bar definition from
|
|
443 |
* @param nm the name of the tool bar definition in the resource file
|
|
444 |
*
|
|
445 |
* @return the created tool bar
|
|
446 |
*/
|
|
447 | 0 |
public JToolBar createToolBar(ResourceBundle resources, String nm) {
|
448 | 0 |
Action action; |
449 | 0 |
AbstractButton newButton; |
450 | 0 |
java.awt.Dimension buttonSize = new java.awt.Dimension(24,24);
|
451 | 0 |
java.awt.Dimension separatorSize = new java.awt.Dimension(3, 20);
|
452 | 0 |
JSeparator separator; |
453 | 0 |
String[] itemKeys = Util.tokenize(getResourceString(resources, nm), " ");
|
454 | 0 |
JToolBar toolBar = new JToolBar();
|
455 | 0 |
toolBar.putClientProperty("JToolBar.isRollover", Boolean.TRUE );
|
456 | 0 |
for (int i = 0; i < itemKeys.length; i++) { |
457 |
/** special handling for separators */
|
|
458 | 0 |
if (itemKeys[i].equals(menuSeparatorKey)) {
|
459 | 0 |
separator = new JSeparator(JSeparator.VERTICAL);
|
460 | 0 |
toolBar.add(separator); |
461 |
} |
|
462 |
else {
|
|
463 | 0 |
action = getAction(itemKeys[i]); |
464 | 0 |
newButton = toolBar.add(action); |
465 | 0 |
newButton.setMinimumSize(buttonSize); |
466 | 0 |
newButton.setPreferredSize(buttonSize); |
467 | 0 |
newButton.setMaximumSize(buttonSize); |
468 | 0 |
newButton.setFocusPainted(false);
|
469 |
} |
|
470 |
} |
|
471 | 0 |
return toolBar;
|
472 |
} |
|
473 |
} |
|