001: /*
002: * Copyright (c) 2004 JETA Software, Inc. All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without modification,
005: * are permitted provided that the following conditions are met:
006: *
007: * o Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: *
010: * o Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * o Neither the name of JETA Software nor the names of its contributors may
015: * be used to endorse or promote products derived from this software without
016: * specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
021: * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
022: * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
023: * INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
024: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
025: * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
026: * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
027: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028: */
029:
030: package com.jeta.open.gui.framework;
031:
032: import java.awt.Component;
033: import java.awt.Container;
034: import java.awt.LayoutManager;
035: import java.util.Collection;
036: import java.util.Iterator;
037:
038: import javax.swing.AbstractButton;
039: import javax.swing.JCheckBox;
040: import javax.swing.JComboBox;
041: import javax.swing.JComponent;
042: import javax.swing.JLabel;
043: import javax.swing.JList;
044: import javax.swing.JPanel;
045: import javax.swing.JProgressBar;
046: import javax.swing.JRadioButton;
047: import javax.swing.JSpinner;
048: import javax.swing.JTabbedPane;
049: import javax.swing.JTable;
050: import javax.swing.JTextField;
051: import javax.swing.JTree;
052: import javax.swing.text.JTextComponent;
053:
054: import com.jeta.open.registry.JETARegistry;
055: import com.jeta.open.support.ComponentFinder;
056: import com.jeta.open.support.ComponentFinderFactory;
057: import com.jeta.open.support.DefaultComponentFinder;
058: import com.jeta.open.support.SwingComponentSupport;
059:
060: /**
061: * A panel that supports locating components by name as well as supporting the
062: * JETA controller/validation framework. Before adding components to this panel,
063: * you should call {@link java.awt.Component#setName}. Components with unique
064: * names can be accessed using the component getter methods in this class.
065: * JETAPanel works with JETAController. Both classes follow the
066: * Model-View-Controller architecture where JETAPanel is the view and
067: * JETAController is the controller. Event handlers and listeners should be
068: * declared in a JETAController derived class while view and layout code should
069: * be confined to JETAPanel instances.
070: *
071: * @author Jeff Tassin
072: */
073: public class JETAPanel extends JPanel implements JETAContainer,
074: SwingComponentSupport {
075: /**
076: * Used for locating components by name in the container hierachy of this
077: * panel.
078: */
079: private ComponentFinder m_finder;
080:
081: /**
082: * The controller that handles events for this panel
083: */
084: private JETAController m_controller;
085:
086: /**
087: * we associate a director with the view the director is responsible for
088: * updating the ui components (menus/buttons/toolbars)
089: */
090: private UIDirector m_uidirector;
091:
092: /**
093: * ctor
094: */
095: public JETAPanel() {
096:
097: }
098:
099: /**
100: * ctor
101: */
102: public JETAPanel(LayoutManager layout) {
103: super (layout);
104: }
105:
106: /**
107: * ctor
108: */
109: public JETAPanel(ComponentFinder finder) {
110: m_finder = finder;
111: }
112:
113: /**
114: * Creates a component finder that is used to locate child components in
115: * this panel by name.
116: */
117: protected ComponentFinder createComponentFinder() {
118: if (m_finder == null) {
119: ComponentFinderFactory ff = (ComponentFinderFactory) JETARegistry
120: .lookup(ComponentFinderFactory.COMPONENT_ID);
121: if (ff != null)
122: m_finder = ff.createFinder(this );
123:
124: if (m_finder == null)
125: m_finder = new DefaultComponentFinder(this );
126: }
127: return m_finder;
128: }
129:
130: /**
131: * Enables/Disables the component associated with the given name.
132: *
133: * @param commandId
134: * the name of the component to enable/disable
135: * @param bEnable
136: * true/false to enable/disable
137: */
138: public void enableComponent(String commandId, boolean bEnable) {
139: Collection comps = getComponentsByName(commandId);
140: Iterator iter = comps.iterator();
141: while (iter.hasNext()) {
142: Component comp = (Component) iter.next();
143: if (comp.isEnabled() != bEnable)
144: comp.setEnabled(bEnable);
145: }
146: }
147:
148: /**
149: * Returns the selected state of the AbstractButton that has the given name.
150: * If a component is found with the given name and that component is not an
151: * AbstractButton, then false is returned.
152: *
153: * @return the selected state of the named AbstractButton.
154: */
155: public boolean getBoolean(String compName) {
156: Component comp = getComponentByName(compName);
157: if (comp instanceof AbstractButton) {
158: return ((AbstractButton) comp).isSelected();
159: } else {
160: return false;
161: }
162: }
163:
164: /**
165: * Returns the button that is contained in this panel and has the given
166: * name. If the component is not found nor is an AbstractButton, null is
167: * returned.
168: *
169: * @return the named AbstractButton
170: */
171: public AbstractButton getButton(String compName) {
172: Component comp = getComponentByName(compName);
173: if (comp instanceof AbstractButton)
174: return (AbstractButton) comp;
175: else
176: return null;
177: }
178:
179: /**
180: * Returns the JCheckBox that is contained in this panel and has the given
181: * name. If the component is not found nor is a JCheckBox, null is returned.
182: *
183: * @return the named JCheckBox
184: */
185: public JCheckBox getCheckBox(String compName) {
186: Component comp = getComponentByName(compName);
187: if (comp instanceof JCheckBox)
188: return (JCheckBox) comp;
189: else
190: return null;
191: }
192:
193: /**
194: * Returns the JComboBox that is contained in this panel and has the given
195: * name. If the component is not found nor is a JComboBox, null is returned.
196: *
197: * @return the named JComboBox
198: */
199: public JComboBox getComboBox(String compName) {
200: Component comp = getComponentByName(compName);
201: if (comp instanceof JComboBox)
202: return (JComboBox) comp;
203: else
204: return null;
205: }
206:
207: /**
208: * Locates the first component found in this container hierarchy that has
209: * the given name. This will recursively search into child containers as
210: * well. If no component is found with the given name, null is returned.
211: *
212: * @param componentName
213: * the name of the component to search for
214: * @return the named component
215: */
216: public Component getComponentByName(String componentName) {
217: Component comp = (Component) getComponentFinder()
218: .getComponentByName(componentName);
219: if (comp == null) {
220: System.err
221: .println("JETAPanel.getComponentByName failed to find component: "
222: + componentName);
223: }
224: return comp;
225: }
226:
227: /**
228: * Returns the component finder associated with this panel
229: *
230: * @return the component finder associated with this panel
231: */
232: protected ComponentFinder getComponentFinder() {
233: if (m_finder == null) {
234: m_finder = createComponentFinder();
235: }
236: return m_finder;
237: }
238:
239: /**
240: * Locates all components found in this container hierarchy that has the
241: * given name. This will recursively search into child containers as well.
242: * This method is useful for frame windows that can have multiple components
243: * with the same name. For example, a menu item and toolbar button for the
244: * same command would have the same name.
245: *
246: * @return a collection of Component objects that have the given name.
247: */
248: public Collection getComponentsByName(String compName) {
249: return getComponentFinder().getComponentsByName(compName);
250: }
251:
252: /**
253: * Recursively searches an associated parent container for all components
254: * that are named. An empty collection is returned if no names components
255: * exist.
256: *
257: * @return a collection of all named Component objects.
258: */
259: public Collection getAllNamedComponents() {
260: return getComponentFinder().getAllNamedComponents();
261: }
262:
263: /**
264: * Return the controller object that handles events for this panel. This
265: * framework assumes that all event listeners will be declared in a
266: * JETAController; however, this is not strictly required.
267: *
268: * @return the controller that will handle events for this panel
269: */
270: public JETAController getController() {
271: return m_controller;
272: }
273:
274: /**
275: * Locates the JTextField that has the given component name. The text in the
276: * field is converted to an integer and returned. If the text cannot be
277: * converted to an integer or the component is not a JTextField, the
278: * defaultValue is returned.
279: *
280: * @param compName
281: * the JTextField to find.
282: * @param defaultValue
283: * the value to return if the component is not a JTextField or
284: * the text in the field is not an integer.
285: * @return the text converted to an integer.
286: */
287: public int getInteger(String compName, int defaultValue) {
288: try {
289: Component comp = getComponentByName(compName);
290: if (comp instanceof JTextField) {
291: return Integer.parseInt(((JTextField) comp).getText());
292: }
293: } catch (Exception e) {
294: }
295: return defaultValue;
296: }
297:
298: /**
299: * Returns the JLabel that is contained in this panel and has the given
300: * name. If the component is not found nor is a JLabel, null is returned.
301: *
302: * @return the named JLabel.
303: */
304: public JLabel getLabel(String compName) {
305: Component comp = getComponentByName(compName);
306: if (comp instanceof JLabel)
307: return (JLabel) comp;
308: else
309: return null;
310: }
311:
312: /**
313: * Returns the JList that is contained in this panel and has the given name.
314: * If the component is not found nor is a JList, null is returned.
315: *
316: * @return the named JList
317: */
318: public JList getList(String compName) {
319: Component comp = getComponentByName(compName);
320: if (comp instanceof JList)
321: return (JList) comp;
322: else
323: return null;
324: }
325:
326: /**
327: * Returns the JPanel that is contained in this panel and has the given
328: * name. If the component is not found nor is a JPanel, null is returned.
329: *
330: * @return the named JPanel
331: */
332: public JPanel getPanel(String compName) {
333: Component comp = getComponentByName(compName);
334: if (comp instanceof JPanel)
335: return (JPanel) comp;
336: else
337: return null;
338: }
339:
340: /**
341: * Returns JProgressBar that is contained in this panel and has the given
342: * name. If the component is not found nor is a JProgressBar, null is
343: * returned.
344: *
345: * @return the named JProgressBar.
346: */
347: public JProgressBar getProgressBar(String compName) {
348: Component comp = getComponentByName(compName);
349: if (comp instanceof JProgressBar)
350: return (JProgressBar) comp;
351: else
352: return null;
353: }
354:
355: /**
356: * Returns the JRadioButton that is contained in this panel and has the
357: * given name. If the component is not found nor is a JRadioButton, null is
358: * returned.
359: *
360: * @return the named JRadioButton
361: */
362: public JRadioButton getRadioButton(String compName) {
363: Component comp = getComponentByName(compName);
364: if (comp instanceof JRadioButton)
365: return (JRadioButton) comp;
366: else
367: return null;
368: }
369:
370: /**
371: * Returns the selected item from the JList or JComboBox that has the given
372: * name. If a list or combo is not found with the name, null is returned.
373: *
374: * @return the selected item from the named JList or JComboBox.
375: */
376: public Object getSelectedItem(String compName) {
377: Component comp = getComponentByName(compName);
378: if (comp instanceof JList) {
379: return ((JList) comp).getSelectedValue();
380: } else if (comp instanceof JComboBox) {
381: return ((JComboBox) comp).getSelectedItem();
382: } else
383: return null;
384: }
385:
386: /**
387: * Returns JSpinner that is contained in this panel and has the given name.
388: * If the component is not found nor is a JSpinner, null is returned.
389: *
390: * @return the named JSpinner
391: */
392: public JSpinner getSpinner(String compName) {
393: Component comp = getComponentByName(compName);
394: if (comp instanceof JSpinner)
395: return (JSpinner) comp;
396: else
397: return null;
398: }
399:
400: /**
401: * Returns the JTable that is contained in this panel and has the given
402: * name. If the component is not found nor is a JTable, null is returned.
403: *
404: * @return the named JTable
405: */
406: public JTable getTable(String compName) {
407: Component comp = getComponentByName(compName);
408: if (comp instanceof JTable)
409: return (JTable) comp;
410: else
411: return null;
412: }
413:
414: /**
415: * Returns the JTabbedPane that is contained in this panel and has the given
416: * name. If the component is not found nor is a JTabbedPane, null is
417: * returned.
418: *
419: * @return the named JTabbedPane
420: */
421: public JTabbedPane getTabbedPane(String compName) {
422: Component comp = getComponentByName(compName);
423: if (comp instanceof JTabbedPane)
424: return (JTabbedPane) comp;
425: else
426: return null;
427: }
428:
429: /**
430: * Returns the JTextComponent that is contained in this panel and has the
431: * given name. If the component is not found nor is a JTextComponent, null
432: * is returned.
433: *
434: * @return the named JTextComponent
435: */
436: public JTextComponent getTextComponent(String compName) {
437: Component comp = getComponentByName(compName);
438: if (comp instanceof JTextComponent)
439: return (JTextComponent) comp;
440: else
441: return null;
442:
443: }
444:
445: /**
446: * Returns the JTextField that is contained in this panel and has the given
447: * name. If the component is not found nor is a JTextField, null is
448: * returned.
449: *
450: * @return the named JTextField
451: */
452: public JTextField getTextField(String compName) {
453: Component comp = getComponentByName(compName);
454: if (comp instanceof JTextField)
455: return (JTextField) comp;
456: else
457: return null;
458:
459: }
460:
461: /**
462: * Returns the text property from a Component. If a component is not found
463: * with the given name or a component does not have a text property, then
464: * null is returned.
465: *
466: * @return the text property.
467: */
468: public String getText(String compName) {
469: Component comp = getComponentByName(compName);
470: if (comp instanceof JTextComponent) {
471: return ((JTextComponent) comp).getText();
472: } else if (comp instanceof AbstractButton) {
473: return ((AbstractButton) comp).getText();
474: } else if (comp instanceof JLabel) {
475: return ((JLabel) comp).getText();
476: } else {
477: try {
478: if (comp != null) {
479: Class c = comp.getClass();
480: Class[] params = new Class[0];
481: Object[] values = new Object[0];
482: java.lang.reflect.Method m = c.getDeclaredMethod(
483: "getText", params);
484: Object obj = m.invoke(comp, values);
485: return obj == null ? null : obj.toString();
486: }
487: } catch (Exception e) {
488: // ignore
489: }
490: return null;
491: }
492: }
493:
494: /**
495: * Returns the JTree that is contained in this panel and has the given name.
496: * If the component is not found nor is a JTree, null is returned.
497: *
498: * @return the named JTree
499: */
500: public JTree getTree(String compName) {
501: Component comp = getComponentByName(compName);
502: if (comp instanceof JTree)
503: return (JTree) comp;
504: else
505: return null;
506:
507: }
508:
509: /**
510: * Returns the UIDirector for this container. UIDirectors are part of this
511: * framework and are responsible for enabling/disabling components based on
512: * the program state. For example, menu items and toolbar buttons must be
513: * enabled or disabled depending on the current state of the frame window.
514: * UIDirectors handle this logic.
515: *
516: * @return the UIDirector
517: */
518: public UIDirector getUIDirector() {
519: return m_uidirector;
520: }
521:
522: /**
523: * Return the selected state of the AbstractButton that has the given name.
524: * If a component is found with the given name and that component is not an
525: * AbstractButton, then false is returned.
526: *
527: * @see JETAPanel#getBoolean
528: */
529: public boolean isSelected(String compName) {
530: return getBoolean(compName);
531: }
532:
533: /**
534: * Locates the component with the given name and removes it from its parent.
535: *
536: * @param compName
537: * the name of the component to locate.
538: */
539: public void removeDescendent(String compName) {
540: Component comp = getComponentByName(compName);
541: if (comp != null) {
542: removeFromParent(comp);
543: }
544: }
545:
546: /**
547: * Helper method that removes a component from its parent container.
548: *
549: * @param comp
550: * the component to remove
551: */
552: public static void removeFromParent(Component comp) {
553: if (comp != null) {
554: Container parent = comp.getParent();
555: if (parent != null) {
556: parent.remove(comp);
557: if (parent instanceof JComponent) {
558: ((JComponent) parent).revalidate();
559: }
560: }
561: }
562: }
563:
564: public void reset() {
565: if (m_finder != null) {
566: m_finder.reset();
567: }
568: }
569:
570: /**
571: * Sets the component finder associated with this panel
572: */
573: protected void setComponentFinder(ComponentFinder finder) {
574: m_finder = finder;
575: }
576:
577: /**
578: * Sets the UIDirector for this panel.
579: */
580: public void setUIDirector(UIDirector director) {
581: m_uidirector = director;
582: }
583:
584: /**
585: * Sets the main controller that will handle events for this panel.
586: */
587: public void setController(JETAController controller) {
588: m_controller = controller;
589: }
590:
591: /**
592: * Shows/Hides the component with the given name.
593: *
594: * @param compName
595: * the name of the component to enable/disable
596: * @param bVisible
597: * show/hide the component/disable
598: */
599: public void setVisible(String compName, boolean bVisible) {
600: Component comp = getComponentByName(compName);
601: if (comp != null)
602: comp.setVisible(bVisible);
603: }
604:
605: /**
606: * Sets the selected attribute for the AbstractButton with the given name.
607: * If a component is found with the given name and that component is not an
608: * AbstractButton, this call is ignored.
609: *
610: * @param compName
611: * the name of the AbstractButton whose selected attribute to
612: * set.
613: * @param sel
614: * the selected attribute to set
615: */
616: public void setSelected(String compName, boolean sel) {
617: Component comp = getComponentByName(compName);
618: if (comp instanceof AbstractButton) {
619: ((AbstractButton) comp).setSelected(sel);
620: }
621: }
622:
623: /**
624: * Sets the selected item in a JComboBox that has the given name. If a combo
625: * is not found with the name, no action is performed.
626: */
627: public void setSelectedItem(String compName, Object value) {
628: Component comp = getComponentByName(compName);
629: if (comp instanceof JComboBox) {
630: ((JComboBox) comp).setSelectedItem(value);
631: } else if (comp instanceof JList) {
632: ((JList) comp).setSelectedValue(value, true);
633: }
634: }
635:
636: /**
637: * Sets text property for the Component with the given name. If no component
638: * is found or the Component does not have a text property, then this method
639: * is a no op.
640: *
641: * @param compName
642: * the name of the JTextComponent whose text to set
643: * @param txt
644: * the text to set
645: */
646: public void setText(String compName, String txt) {
647: Component comp = getComponentByName(compName);
648: if (comp instanceof JTextComponent) {
649: ((JTextComponent) comp).setText(txt);
650: } else if (comp instanceof JLabel) {
651: ((JLabel) comp).setText(txt);
652: } else if (comp instanceof AbstractButton) {
653: ((AbstractButton) comp).setText(txt);
654: } else {
655: try {
656: if (comp != null) {
657: Class c = comp.getClass();
658: Class[] params = new Class[] { String.class };
659: Object[] values = new Object[] { txt };
660: java.lang.reflect.Method m = c.getDeclaredMethod(
661: "setText", params);
662: m.invoke(comp, values);
663: }
664: } catch (Exception e) {
665: // ignore
666: }
667: }
668: }
669:
670: /**
671: * This is a helper method that simply forwards the call to the controller
672: * for this view (which forwards the call to the UIDirector if one exists)
673: */
674: public void updateComponents() {
675: updateComponents(null);
676: }
677:
678: /**
679: * This is a helper method that simply forwards the call to the controller
680: * for this view (which forwards the call to the UIDirector if one exists)
681: */
682: public void updateComponents(java.util.EventObject evt) {
683: if (m_controller != null)
684: m_controller.updateComponents(evt);
685: }
686: }
|