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             // The Swing Suite provides class MySwingUtilities
144             // that fixes bugs with l&f switching at runtime.
145             SwingUtilities.updateComponentTreeUI(viewer);
146         }
147     }
148 
149     /**
150      * Returns the current <code>Editor</code>.
151      *
152      * @return the current <code>Editor</code>.
153      */
154     private Editor getActiveEditor() {
155         return (Editor)scrollPane.getViewport().getView();
156     }
157 
158     /**
159      * Builds the content, which is a panel wrapped by a stripped
160      * <code>JScrollPane</code>. The panel will be replaced later
161      * by the different viewers, where we access the viewer via
162      * the scrollpane's viewport view.
163      */
164     private JComponent buildContent() {
165         return scrollPane = UIFactory.createStrippedScrollPane(new JPanel());
166     }
167 
168     /**
169      * Returns the <code>Editor</code> that has been registered
170      * for the given domain object class, <code>null</code> if none.
171      *
172      * @param domainClass   the class associated with the editor to lookup
173      * @return the editor associated with the given domain class
174      */
175     private Editor lookupEditor(Class domainClass) {
176         return (Editor)editorRegistry.get(domainClass);
177     }
178 
179     /**
180      * Registers a <code>Editor</code> for a domain class.
181      *
182      * @param domainClass   the key used to lookup the editor later
183      * @param editor        the value stored under the given domain class
184      */
185     private void registerEditor(Class domainClass, Editor editor) {
186         Object oldValue = editorRegistry.put(domainClass, editor);
187         if (oldValue != null) {
188             LOG.debug("Duplicate editor registered for " + domainClass);
189         }
190     }
191 
192     /**
193      * Deactivates the current editor, looks up appropriate viewer for
194      * the new selection, sets the model, activates it and makes it visible.
195      *
196      * @param selection   the new domain selection
197      */
198     private void updateActiveEditor(Object selection) {
199         if (selection == null) {
200             return;
201         }
202 
203         getActiveEditor().deactivate();
204         Editor editor = lookupEditor(selection.getClass());
205         if (editor != null) {
206             editor.setModel(selection);
207             editor.activate();
208             setActiveEditor(editor);
209         }
210     }
211 
212     // Listens to changes in the main module's selection and updates the editor.
213     private class SelectionChangeHandler
214         implements PropertyChangeListener {
215 
216         /**
217          * The main module's selection has changed. Look up the editor
218          * registered for the selection's domain class, deactivate the active
219          * editor, activate the new editor and set is as active editor.
220          *
221          * @param evt   describes the property change
222          */
223         public void propertyChange(PropertyChangeEvent evt) {
224             if (evt.getNewValue() == null) {
225                 // gets the first editor in the list if no event found
226                 setActiveEditor((Editor)getEditors().get(0));
227             } else {
228                 updateActiveEditor(evt.getNewValue());
229             }
230         }
231     }
232 
233 }