View Javadoc

1   package com.melloware.jukes.gui.view.editor;
2   
3   import java.awt.Component;
4   import java.beans.PropertyChangeEvent;
5   import java.beans.PropertyChangeListener;
6   import java.util.HashMap;
7   import java.util.Iterator;
8   import java.util.LinkedList;
9   import java.util.List;
10  import java.util.Map;
11  
12  import javax.swing.JComponent;
13  import javax.swing.JPanel;
14  import javax.swing.JScrollPane;
15  import javax.swing.SwingUtilities;
16  
17  import org.apache.commons.logging.Log;
18  import org.apache.commons.logging.LogFactory;
19  
20  import com.jgoodies.uifextras.util.UIFactory;
21  import com.melloware.jukes.gui.tool.MainModule;
22  import com.melloware.jukes.gui.view.component.ComplexInternalFrame;
23  
24  /**
25   * A container that wraps <code>Editor</code> instances with a
26   * <code>JScrollPane</code>, which in turn is wrapped by
27   * a <code>SimpleInternalFrame</code>.<p>
28   *
29   * It keeps track of a collection of editors to be able to update
30   * the UIs of invisible editors when the look&amp;feel changes.
31   * <code>SwingUtilities#updateComponentTreeUI</code> updates
32   * only editors that are in the component tree. Since we have only
33   * the active editor in the component tree, we must update other
34   * editors <em>by hand</em>.
35   * An alternative implementation is to use a <code>CardPanel</code>
36   * that has all editors in the component tree, but displays one of them
37   * and hides all others.
38   * <p>
39   * Copyright (c) 1999-2007 Melloware, Inc. <http://www.melloware.com>
40   * @author Emil A. Lefkof III <info@melloware.com>
41   * @version 4.0
42   *
43   * @see MainModule
44   * @see Editor
45   * @see javax.swing.SwingUtilities#updateComponentTreeUI(java.awt.Component)
46   */
47  @SuppressWarnings("unchecked")
48  public final class EditorPanel
49      extends ComplexInternalFrame { 
50  
51      private static final Log LOG = LogFactory.getLog(EditorPanel.class);
52  
53      private JScrollPane scrollPane;
54  
55      /**
56       * Holds a list of all editors to update the UI of invisible editors
57       * in case the look&amp;feel changes. Contains some editors that
58       * are not registered with the editor registry, for example the
59       * WelcomePanel that has no associated domain class.
60       *
61       * @see #updateUI()
62       */
63      private final List editors;
64  
65      /**
66       * Maps domain classes to <code>Editor</code> instances.
67       *
68       * @see #addEditor(Editor)
69       */
70      private final Map editorRegistry;
71  
72      /**
73       * Constructs a <code>EditorPanel</code>.
74       *
75       * @param mainModule   used to observe selection changes
76       */
77      public EditorPanel(MainModule mainModule) {
78          super("Editor");
79          editorRegistry = new HashMap();
80          editors = new LinkedList();
81          setContent(buildContent());
82  
83          mainModule.addPropertyChangeListener(MainModule.PROPERTYNAME_SELECTION, new SelectionChangeHandler());
84      }
85  
86      /**
87       * Gets the editors.
88       * <p>
89       * @return Returns the editors.
90       */
91      public List getEditors() {
92          return this.editors;
93      }
94  
95      /**
96       * Shows the specified <code>Editor</code>: sets the icon,
97       * title, tool bar, and finally switches the viewport's view.
98       *
99       * @param newEditor   the editor to be set
100      */
101     public void setActiveEditor(Editor newEditor) {
102         setFrameIcon(newEditor.getIcon());
103         setTitle(newEditor.getTitle());
104         setToolBar(newEditor.getToolBar());
105         setHeaderToolBar(newEditor.getHeaderToolBar());
106         scrollPane.setViewportView((Component)newEditor);
107     }
108 
109     /**
110      * Adds a <code>Editor</code> to this <code>EditorPanel</code>.
111      *
112      * @param editor   the editor to add
113      */
114     public void addEditor(Editor editor) {
115         Class domainClass = editor.getDomainClass();
116         if (domainClass != null) {
117             registerEditor(domainClass, editor);
118         }
119 
120         editors.add(editor);
121     }
122     
123     /**
124      * Clears all editors out.
125      */
126     public void clearEditors() {
127     	editors.clear();
128     }
129 
130     /**
131      * The look&amp;feel has changed. Updates the UI.
132      * In addition to the superclass behavior, this method
133      * updates the component trees for the invisible editors.
134      */
135     public void updateUI() {
136         super.updateUI();
137         if (editors == null) {
138             return;
139         }
140 
141         for (Iterator i = editors.iterator(); i.hasNext();) {
142             JComponent viewer = (JComponent)i.next();
143 
144             // The Swing Suite provides class MySwingUtilities
145             // that fixes bugs with l&f switching at runtime.
146             SwingUtilities.updateComponentTreeUI(viewer);
147         }
148     }
149 
150     /**
151      * Returns the current <code>Editor</code>.
152      *
153      * @return the current <code>Editor</code>.
154      */
155     private Editor getActiveEditor() {
156         return (Editor)scrollPane.getViewport().getView();
157     }
158 
159     /**
160      * Builds the content, which is a panel wrapped by a stripped
161      * <code>JScrollPane</code>. The panel will be replaced later
162      * by the different viewers, where we access the viewer via
163      * the scrollpane's viewport view.
164      */
165     private JComponent buildContent() {
166         return scrollPane = UIFactory.createStrippedScrollPane(new JPanel());
167     }
168 
169     /**
170      * Returns the <code>Editor</code> that has been registered
171      * for the given domain object class, <code>null</code> if none.
172      *
173      * @param domainClass   the class associated with the editor to lookup
174      * @return the editor associated with the given domain class
175      */
176     private Editor lookupEditor(Class domainClass) {
177         return (Editor)editorRegistry.get(domainClass);
178     }
179 
180     /**
181      * Registers a <code>Editor</code> for a domain class.
182      *
183      * @param domainClass   the key used to lookup the editor later
184      * @param editor        the value stored under the given domain class
185      */
186     private void registerEditor(Class domainClass, Editor editor) {
187         Object oldValue = editorRegistry.put(domainClass, editor);
188         if (oldValue != null) {
189             LOG.debug("Duplicate editor registered for " + domainClass);
190         }
191     }
192 
193     /**
194      * Deactivates the current editor, looks up appropriate viewer for
195      * the new selection, sets the model, activates it and makes it visible.
196      *
197      * @param selection   the new domain selection
198      */
199     private void updateActiveEditor(Object selection) {
200         if (selection == null) {
201             return;
202         }
203 
204         getActiveEditor().deactivate();
205 
206         Editor editor = lookupEditor(selection.getClass());
207         if (editor != null) {
208             editor.setModel(selection);
209             editor.activate();
210             setActiveEditor(editor);
211         }
212     }
213 
214     // Listens to changes in the main module's selection and updates the editor.
215     private class SelectionChangeHandler
216         implements PropertyChangeListener {
217 
218         /**
219          * The main module's selection has changed. Look up the editor
220          * registered for the selection's domain class, deactivate the active
221          * editor, activate the new editor and set is as active editor.
222          *
223          * @param evt   describes the property change
224          */
225         public void propertyChange(PropertyChangeEvent evt) {
226             if (evt.getNewValue() == null) {
227                 // gets the first editor in the list if no event found
228                 setActiveEditor((Editor)getEditors().get(0));
229             } else {
230                 updateActiveEditor(evt.getNewValue());
231             }
232         }
233     }
234 
235 }