001: /*
002: * Jacareto Copyright (c) 2002-2005
003: * Applied Computer Science Research Group, Darmstadt University of
004: * Technology, Institute of Mathematics & Computer Science,
005: * Ludwigsburg University of Education, and Computer Based
006: * Learning Research Group, Aachen University. All rights reserved.
007: *
008: * Jacareto is free software; you can redistribute it and/or
009: * modify it under the terms of the GNU General Public
010: * License as published by the Free Software Foundation; either
011: * version 2 of the License, or (at your option) any later version.
012: *
013: * Jacareto is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
016: * General Public License for more details.
017: *
018: * You should have received a copy of the GNU General Public
019: * License along with Jacareto; if not, write to the Free
020: * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
021: *
022: */
023:
024: package jacareto.cleverphl.gui;
025:
026: import jacareto.cleverphl.CleverPHL;
027: import jacareto.cleverphl.menu.CleverPHLAction;
028: import jacareto.cleverphl.session.SessionType;
029: import jacareto.system.Customization;
030: import jacareto.system.Language;
031: import jacareto.toolkit.EnhancedHashtable;
032: import jacareto.toolkit.HashtableException;
033:
034: import org.apache.log4j.Logger;
035:
036: import java.lang.reflect.Constructor;
037: import java.lang.reflect.InvocationTargetException;
038:
039: import java.util.Collection;
040: import java.util.Enumeration;
041: import java.util.Hashtable;
042:
043: import javax.swing.AbstractButton;
044: import javax.swing.Action;
045: import javax.swing.ButtonGroup;
046: import javax.swing.JCheckBoxMenuItem;
047: import javax.swing.JComponent;
048: import javax.swing.JMenu;
049: import javax.swing.JMenuBar;
050: import javax.swing.JMenuItem;
051: import javax.swing.JPopupMenu;
052: import javax.swing.JRadioButtonMenuItem;
053: import javax.swing.KeyStroke;
054:
055: /**
056: * The menu bar of the main frame of CleverPHL.
057: *
058: * @author <a href="mailto:cspannagel@web.de">Christian Spannagel</a>
059: * @version 1.0
060: */
061: public class CleverPHLMenuBar extends JMenuBar {
062: /** The cleverphl instance. */
063: private CleverPHL cleverPHL;
064:
065: /** The frame this menu bar belongs to. */
066: private CleverPHLFrame frame;
067:
068: /** The customization. */
069: private Customization customization;
070:
071: /** The customization key this menu bar is built from. */
072: private String customizationKey;
073:
074: /** Hashtable of all loaded actions. */
075: private Hashtable actions;
076:
077: /** The language. */
078: private Language language;
079:
080: /** Maps customization keys to menu items. */
081: private Hashtable menuItems;
082:
083: /** Maps customization keys to popup menus. */
084: private Hashtable popupMenus;
085:
086: /** Hashtable of the old menu items. */
087: private Hashtable oldMenuItems;
088:
089: /** Hashtable of button groups. */
090: private Hashtable buttonGroups;
091:
092: /**
093: * Creates a new menu bar.
094: *
095: * @param cleverPHL the CleverPHL instance
096: * @param frame DOCUMENT ME!
097: */
098: public CleverPHLMenuBar(CleverPHL cleverPHL, CleverPHLFrame frame) {
099: super ();
100: this .cleverPHL = cleverPHL;
101: this .customization = cleverPHL.getCustomization();
102: this .language = cleverPHL.getLanguage();
103: this .frame = frame;
104: menuItems = new Hashtable();
105: buttonGroups = new Hashtable();
106: actions = new Hashtable();
107: popupMenus = new Hashtable();
108: }
109:
110: /**
111: * Creates the menu bar from the customization with the specified key and no session type. This
112: * can be used if no session is opened. Otherwise {@link #create (String, SessionType)} should
113: * be used.
114: *
115: * @param customizationKey DOCUMENT ME!
116: */
117: public void create(String customizationKey) {
118: create(customizationKey, null);
119: }
120:
121: /**
122: * Creates the menu bar from the customization with the specified key.
123: *
124: * @param customizationKey DOCUMENT ME!
125: * @param sessionType DOCUMENT ME!
126: */
127: public void create(String customizationKey, SessionType sessionType) {
128: try {
129: oldMenuItems = menuItems;
130: menuItems = new Hashtable();
131:
132: this .customizationKey = customizationKey;
133:
134: EnhancedHashtable h = customization
135: .getMap(customizationKey);
136: JMenuItem menuItem = null;
137:
138: for (int i = 0; i < h.size(); i++) {
139: try {
140: menuItem = (JMenuItem) getMenuComponentFromCustomization(
141: h.getString("" + i), sessionType);
142: } catch (HashtableException he) {
143: cleverPHL
144: .getLogger()
145: .fatal(
146: language
147: .getString("CleverPHL.Frame.Error.MissingMenuPosition"));
148: System.exit(-1);
149: }
150:
151: if (menuItem != null) {
152: add(menuItem);
153: }
154: }
155:
156: oldMenuItems = null;
157: } catch (HashtableException he2) {
158: cleverPHL
159: .getLogger()
160: .fatal(
161: language
162: .getString("CleverPHL.Frame.Error.NoMenuCustomization")
163: + " " + customizationKey);
164: System.exit(-1);
165: }
166:
167: // At the start of CleverPHL, no session is opened.
168: // Then just show the session menu
169: if (sessionType == null) {
170: adaptToNoSession();
171: }
172:
173: validate();
174: repaint();
175: }
176:
177: /**
178: * Rebuilds the menu.
179: *
180: * @param sessionType DOCUMENT ME!
181: */
182: public void rebuild(SessionType sessionType) {
183: removeAll();
184: create(customizationKey, sessionType);
185:
186: Enumeration keys = popupMenus.keys();
187:
188: while (keys.hasMoreElements()) {
189: String customizationName = (String) keys.nextElement();
190: JPopupMenu popupMenu = (JPopupMenu) popupMenus
191: .get(customizationName);
192: popupMenu.removeAll();
193:
194: if (customization.containsKey(customizationName
195: + ".SubItems")) {
196: EnhancedHashtable h = customization.getMap(
197: customizationName + ".SubItems",
198: new EnhancedHashtable());
199:
200: for (int i = 0; i < h.size(); i++) {
201: try {
202: String menuItemString = h.getString("" + i);
203:
204: JMenuItem menuItem;
205:
206: if (menuItemString.equals("Separator")) {
207: popupMenu.addSeparator();
208: menuItem = null;
209: } else {
210: menuItem = (JMenuItem) getMenuComponentFromCustomization(
211: menuItemString, sessionType);
212: }
213:
214: if (menuItem != null) {
215: popupMenu.add(menuItem);
216: }
217: } catch (HashtableException he) {
218: cleverPHL
219: .getLogger()
220: .fatal(
221: language
222: .getString("CleverPHL.Frame.Error.MissingMenuPosition"));
223: System.exit(-1);
224: }
225: }
226: }
227:
228: //create (customizationName, sessionType);
229: }
230: }
231:
232: /**
233: * Displays the menu to be showed when no session is opened.
234: */
235: public void adaptToNoSession() {
236: if (frame instanceof CleverPHLMainFrame) {
237: JMenu sessionMenu = getMenu(0);
238: removeAll();
239: add(sessionMenu);
240: validate();
241: repaint();
242: }
243: }
244:
245: /**
246: * Creates a menu component and its sub items from the customization.
247: *
248: * @param customizationName the name of the element in the customization
249: *
250: * @return the resulting JMenuComponent (JMenu, JMenuItem or JPopupMenu)
251: */
252: public JComponent getMenuComponentFromCustomization(
253: String customizationName) {
254: return getMenuComponentFromCustomization(customizationName,
255: null);
256: }
257:
258: /**
259: * Creates a menu component and its sub items from the customization.
260: *
261: * @param customizationName the name of the element in the customization
262: * @param sessionType the actual session type
263: *
264: * @return the resulting JMenuComponent (JMenu, JMenuItem or JPopupMenu)
265: */
266: public JComponent getMenuComponentFromCustomization(
267: String customizationName, SessionType sessionType) {
268: JComponent result = null;
269:
270: Customization customization = cleverPHL.getCustomization();
271: Language language = cleverPHL.getLanguage();
272: CleverPHLAction action = getCleverPHLAction(customization
273: .getString(customizationName + ".Class", null));
274:
275: if (action != null) {
276: if (customization.containsKey(customizationName
277: + ".SubItems")) {
278: if (result == null) {
279: if (customization.containsKey(customizationName
280: + ".Type")
281: && customization.getString(
282: customizationName + ".Type",
283: "Default").equals("Popup")) {
284: String actionName = (String) action
285: .getValue(Action.NAME);
286:
287: if ((actionName != null)
288: && !actionName.equals("")) {
289: result = new JPopupMenu(actionName);
290: } else {
291: result = new JPopupMenu();
292: }
293: } else {
294: result = new JMenu(action);
295: }
296: }
297:
298: EnhancedHashtable h = customization.getMap(
299: customizationName + ".SubItems",
300: new EnhancedHashtable());
301: JMenuItem menuItem = null;
302:
303: for (int i = 0; i < h.size(); i++) {
304: try {
305: String menuItemString = h.getString("" + i);
306:
307: if (menuItemString.equals("Separator")) {
308: if (result instanceof JMenu) {
309: ((JMenu) result).addSeparator();
310: } else {
311: ((JPopupMenu) result).addSeparator();
312: }
313:
314: menuItem = null;
315: } else {
316: menuItem = (JMenuItem) getMenuComponentFromCustomization(
317: menuItemString, sessionType);
318: }
319: } catch (HashtableException he) {
320: cleverPHL
321: .getLogger()
322: .fatal(
323: language
324: .getString("CleverPHL.Frame.Error.MissingMenuPosition"));
325: System.exit(-1);
326: }
327:
328: if (menuItem != null) {
329: if (result instanceof JMenu) {
330: ((JMenu) result).add(menuItem);
331: addMenuItem(customizationName, result);
332: } else {
333: ((JPopupMenu) result).add(menuItem);
334: }
335: }
336: }
337: } else {
338: if (result == null) {
339: if (customization.containsKey(customizationName
340: + ".Type")) {
341: try {
342: if (customization.getString(
343: customizationName + ".Type")
344: .equals("CheckBox")) {
345: result = new JCheckBoxMenuItem(action);
346:
347: if (oldMenuItems
348: .containsKey(customizationName)) {
349: ((JCheckBoxMenuItem) result)
350: .setSelected(((JCheckBoxMenuItem) oldMenuItems
351: .get(customizationName))
352: .isSelected());
353: }
354: } else if (customization.getString(
355: customizationName + ".Type")
356: .equals("RadioButton")) {
357: result = new JRadioButtonMenuItem(
358: action);
359:
360: if (customization
361: .containsKey(customizationName
362: + ".ButtonGroup")) {
363: String buttonGroupName = customization
364: .getString(
365: customizationName
366: + ".ButtonGroup",
367: "Default");
368:
369: if (!buttonGroups
370: .containsKey(buttonGroupName)) {
371: buttonGroups.put(
372: buttonGroupName,
373: new ButtonGroup());
374: }
375:
376: ((ButtonGroup) buttonGroups
377: .get(buttonGroupName))
378: .add((JMenuItem) result);
379: }
380: } else {
381: result = new JMenuItem(action);
382: }
383: } catch (HashtableException h) {
384: result = new JMenuItem(action);
385: }
386: } else {
387: result = new JMenuItem(action);
388: }
389: }
390:
391: addMenuItem(customizationName, result);
392: }
393: }
394:
395: if ((result != null) && result instanceof AbstractButton) {
396: ((AbstractButton) result).setIcon(null);
397: }
398:
399: if ((result != null) && result instanceof JPopupMenu) {
400: popupMenus.put(customizationName, result);
401: }
402:
403: // Look for the session type
404: if (sessionType != null) {
405: if (customization.containsKey(customizationName
406: + ".SessionType")) {
407: if ((customization.getInt(customizationName
408: + ".SessionType", -1) & sessionType.getID()) == 0) {
409: result = null;
410: }
411: }
412: }
413:
414: return result;
415: }
416:
417: /**
418: * Stores a menu item to an internal hashtable. If a name occurs more than just once, the items
419: * will be added as _name, __name, ___name and so on.
420: *
421: * @param customizationName DOCUMENT ME!
422: * @param item DOCUMENT ME!
423: */
424: private void addMenuItem(String customizationName, JComponent item) {
425: if (!menuItems.containsKey(customizationName)) {
426: menuItems.put(customizationName, item);
427: } else if (menuItems.get(customizationName) != item) {
428: do {
429: customizationName = "_" + customizationName;
430:
431: if (menuItems.containsKey(customizationName)
432: && (menuItems.get(customizationName) == item)) {
433: break;
434: }
435: } while (menuItems.containsKey(customizationName));
436:
437: if (!menuItems.containsKey(customizationName)) {
438: menuItems.put(customizationName, item);
439: }
440: }
441: }
442:
443: /**
444: * En- and disables all menu items with the given customization name.
445: *
446: * @param customizationName DOCUMENT ME!
447: * @param isEnabled DOCUMENT ME!
448: */
449: public void setMenuItemEnabled(String customizationName,
450: boolean isEnabled) {
451: while (menuItems.containsKey(customizationName)) {
452: JComponent menuComponent = ((JComponent) menuItems
453: .get(customizationName));
454:
455: if (menuComponent != null) {
456: menuComponent.setEnabled(isEnabled);
457: customizationName = "_" + customizationName;
458: }
459: }
460: }
461:
462: /**
463: * Sets the accelerator key for a menu item with the given customization string.
464: *
465: * @param customizationKey the customization key
466: * @param keyStroke the accelerator key stroke
467: */
468: public void setAccelerator(String customizationKey,
469: KeyStroke keyStroke) {
470: ((JMenuItem) menuItems.get(customizationKey))
471: .setAccelerator(keyStroke);
472: }
473:
474: /**
475: * Returns a instance of a given class which extends {@link
476: * jacareto.cleverphl.menu.CleverPHLAction}.
477: *
478: * @param className classname of the subclass of{@link jacareto.cleverphl.menu.CleverPHLAction}
479: *
480: * @return DOCUMENT ME!
481: */
482: private CleverPHLAction getCleverPHLAction(String className) {
483: Logger logger = cleverPHL.getLogger();
484: Language language = cleverPHL.getLanguage();
485: Customization customization = cleverPHL.getCustomization();
486:
487: if (className != null) {
488: if (actions.containsKey(className)) {
489: return (CleverPHLAction) actions.get(className);
490: } else {
491: try {
492: // some reflection instances
493: String customizationActionClassName = customization
494: .getString("CleverPHL.Action.Class", "");
495: Class cleverPHLActionClass = Class
496: .forName(customizationActionClassName);
497: Class actionClass = Class.forName(className);
498: Class[] parameterTypes = new Class[1];
499: parameterTypes[0] = cleverPHL.getClass();
500:
501: Object[] parameters = new Object[1];
502: parameters[0] = cleverPHL;
503:
504: Constructor actionConstructor = actionClass
505: .getConstructor(parameterTypes);
506:
507: if (cleverPHLActionClass
508: .isAssignableFrom(actionClass)) {
509: try {
510: CleverPHLAction action = (CleverPHLAction) actionConstructor
511: .newInstance(parameters);
512: actions.put(className, action);
513:
514: return action;
515: } catch (InstantiationException inst) {
516: logger
517: .error(
518: language
519: .getString("CleverPHL.Frame.Error.Construction")
520: + " ["
521: + className
522: + "]", inst);
523: System.exit(1);
524: } catch (IllegalAccessException ill) {
525: logger
526: .error(
527: language
528: .getString("CleverPHL.Frame.Error.Construction")
529: + " ["
530: + className
531: + "]", ill);
532: System.exit(1);
533: } catch (IllegalArgumentException ila) {
534: logger
535: .error(
536: language
537: .getString("CleverPHL.Frame.Error.Construction")
538: + " ["
539: + className
540: + "]", ila);
541: System.exit(1);
542: } catch (InvocationTargetException inv) {
543: logger
544: .error(
545: language
546: .getString("CleverPHL.Frame.Error.Construction")
547: + " ["
548: + className
549: + "]", inv);
550: System.exit(1);
551: }
552: } else {
553: logger
554: .warn(language
555: .getString("CleverPHL.Frame.Msg.NotSubclass")
556: + ": " + className);
557: System.exit(1);
558: }
559: } catch (ClassNotFoundException c) {
560: logger
561: .error(
562: language
563: .getString("CleverPHL.Frame.Error.MissingClass"),
564: c);
565: System.exit(1);
566: } catch (NoSuchMethodException n) {
567: logger
568: .error(
569: language
570: .getString("CleverPHL.Frame.Error.MissingConstructor"),
571: n);
572: System.exit(1);
573: }
574: }
575: }
576:
577: return null;
578: }
579:
580: /**
581: * Returns a menu item.
582: *
583: * @param customizationKey the customization key of the menu item
584: *
585: * @return the menu item, or <code>null</code> if the key is not known
586: */
587: public JMenuItem getMenuItem(String customizationKey) {
588: JMenuItem result = null;
589:
590: try {
591: if (menuItems.containsKey(customizationKey)) {
592: result = (JMenuItem) menuItems.get(customizationKey);
593: } else {
594: result = (JMenuItem) getMenuComponentFromCustomization(
595: customizationKey, null);
596: }
597: } catch (Exception e) {
598: result = null;
599: }
600:
601: return result;
602: }
603:
604: /**
605: * Returns all menu items als enumeration.
606: *
607: * @return DOCUMENT ME!
608: */
609: public Enumeration getMenuItems() {
610: return menuItems.elements();
611: }
612:
613: /**
614: * Returns the action belonging to a customization key.
615: *
616: * @param customizationKey the customization key of the action
617: *
618: * @return the action, or <code>null</code> if the key is not known
619: */
620: public Action getAction(String customizationKey) {
621: try {
622: String actionString = customization.getString(
623: customizationKey + ".Class", null);
624:
625: if (actions.containsKey(actionString)) {
626: return (Action) actions.get(actionString);
627: }
628:
629: return getMenuItem(customizationKey).getAction();
630: } catch (Exception e) {
631: return null;
632: }
633: }
634:
635: /**
636: * Returns all actions.
637: *
638: * @return DOCUMENT ME!
639: */
640: public Collection getActions() {
641: return actions.values();
642: }
643: }
|