View Javadoc

1   /*
2    * $HeadURL: $
3    * $Date: $
4    * $Revision: $
5    * $Author: $
6    * 
7    * Copyright (c) 2005 MindTree Consulting Ltd. 
8    * 
9    * This file is part of Insight.
10   * 
11   * Insight is free software: you can redistribute it and/or modify it under the 
12   * terms of the GNU General Public License as published by the Free Software 
13   * Foundation, either version 3 of the License, or (at your option) any later 
14   * version.
15   * 
16   * Insight is distributed in the hope that it will be useful, but 
17   * WITHOUT ANY WARRANTY; without even the implied warranty of 
18   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General 
19   * Public License for more details.
20   * 
21   * You should have received a copy of the GNU General Public License along with 
22   * Insight.  If not, see <http://www.gnu.org/licenses/>.
23   */
24  package com.mindtree.techworks.insight.gui.preferences;
25  
26  import java.awt.Component;
27  import java.awt.Dimension;
28  import java.awt.GridBagConstraints;
29  import java.awt.GridBagLayout;
30  import java.awt.Insets;
31  import java.awt.Rectangle;
32  import java.awt.event.ActionEvent;
33  import java.awt.event.ActionListener;
34  import java.awt.event.WindowAdapter;
35  import java.awt.event.WindowEvent;
36  import java.util.HashMap;
37  import java.util.Iterator;
38  
39  import javax.swing.JButton;
40  import javax.swing.JDialog;
41  import javax.swing.JFrame;
42  import javax.swing.JLabel;
43  import javax.swing.JOptionPane;
44  import javax.swing.JSplitPane;
45  import javax.swing.JTree;
46  import javax.swing.event.TreeSelectionEvent;
47  import javax.swing.event.TreeSelectionListener;
48  import javax.swing.tree.DefaultMutableTreeNode;
49  import javax.swing.tree.DefaultTreeCellRenderer;
50  
51  import com.mindtree.techworks.insight.InsightConstants;
52  import com.mindtree.techworks.insight.ResourceManager;
53  import com.mindtree.techworks.insight.ShutdownHookManager;
54  import com.mindtree.techworks.insight.preferences.PreferenceManager;
55  import com.mindtree.techworks.insight.preferences.model.Preference;
56  import com.mindtree.techworks.insight.preferences.model.PreferenceInfo;
57  
58  /**
59   * The <code>PreferencesFrame</code> class is the GUI for maintaining Insight
60   * preferences. The preferences include both transient and persistent ones.
61   * 
62   * @see com.mindtree.techworks.insight.preferences
63   * @author Regunath B
64   * @version $Revision: 27 $ $Date: 2007-12-16 04:58:03 -0700 (Sun, 16 Dec 2007) $
65   */
66  
67  public class PreferencesFrame extends JDialog implements TreeSelectionListener {
68  
69  	/**
70  	 * 
71  	 */
72  	private static final long serialVersionUID = 6632219854510095454L;
73  
74  	/**
75  	 * Useful constants for display sizes - width
76  	 */
77  	private static final int SPLIT_PANE_WIDTH = 700;
78  
79  	/**
80  	 * Useful constants for display sizes - height
81  	 */
82  	private static final int SPLIT_PANE_HEIGHT = 450;
83  
84  	/**
85  	 * Layout definition.
86  	 */
87  	private GridBagLayout gl;
88  
89  	/**
90  	 * Layout constrains
91  	 */
92  	private GridBagConstraints gc;
93  
94  	/**
95  	 * Split pane that display the list of preferences and permits editing the
96  	 * preference attributes
97  	 */
98  	private JSplitPane splitPane;
99  
100 	/**
101 	 * JTree used for displaying the preference names
102 	 */
103 	private JTree preferencesTree;
104 
105 	/**
106 	 * Buttons in the display - save the preferences
107 	 */
108 	protected JButton saveButton;
109 
110 	/**
111 	 * Buttons in the display - cancel the changes
112 	 */
113 	private JButton cancelButton;
114 
115 	/**
116 	 * Insight for this class
117 	 */
118 	private JFrame parent;
119 
120 	/**
121 	 * Hashmap containing loaded AbstractPreferencesUIPanel instances
122 	 */
123 	protected HashMap loadedUIPanels;
124 
125 	/**
126 	 * Constructor for this class.
127 	 * 
128 	 * @param parent
129 	 *            The parent frame for this dialog for this class
130 	 */
131 	public PreferencesFrame (JFrame parent) {
132 
133 		super (JOptionPane.getFrameForComponent (parent), InsightConstants
134 				.getLiteral ("MAINTAIN_PREFERENCES"), true);
135 		this.parent = parent;
136 		initialize ();
137 	}
138 
139 	/**
140 	 * Constructs an instance of this class. This constructor is to be called
141 	 * when this window is to come up without a parent. By default, if this
142 	 * constructor is called, then a <code>System.exit(0)</code> is called
143 	 * when this window closes.
144 	 */
145 	public PreferencesFrame () {
146 
147 		setTitle (InsightConstants.getLiteral ("MAINTAIN_PREFERENCES"));
148 		JOptionPane.getFrameForComponent(this).setIconImage(
149 				ResourceManager.getInstance().loadImageIcon("INSIGHT_ICON")
150 						.getImage());
151 
152 		// This has come up on its own, so add a shutdown hook
153 		ShutdownHookManager
154 				.addShutdownAction (ShutdownHookManager.SHUTDOWN_ACTION_SAVE_PREFERENCES);
155 
156 		initialize ();
157 	}
158 
159 	/**
160 	 * Initializes the display of this dialog.
161 	 */
162 	private void initialize () {
163 
164 		loadedUIPanels = new HashMap ();
165 		gl = new GridBagLayout ();
166 		gc = new GridBagConstraints ();
167 		getContentPane ().setLayout (gl);
168 
169 		preferencesTree = new JTree (getPreferenceNames ());
170 		this.splitPane = new JSplitPane (JSplitPane.HORIZONTAL_SPLIT,
171 				preferencesTree, null);
172 
173 		// hide the root node
174 		preferencesTree.setRootVisible (false);
175 		// display the handles
176 		preferencesTree.setShowsRootHandles (true);
177 		// disable icon display
178 		DefaultTreeCellRenderer nodeRenderer = (DefaultTreeCellRenderer) preferencesTree
179 				.getCellRenderer ();
180 		nodeRenderer.setLeafIcon (null);
181 		nodeRenderer.setClosedIcon (null);
182 		nodeRenderer.setOpenIcon (null);
183 		// add this class as a TreeSelectionListener to the JTree
184 		preferencesTree.addTreeSelectionListener (this);
185 
186 		// set the preferred component and hence window size
187 		this.splitPane.setPreferredSize (new Dimension (SPLIT_PANE_WIDTH,
188 				SPLIT_PANE_HEIGHT));
189 		this.preferencesTree.setMinimumSize (new Dimension (
190 				SPLIT_PANE_WIDTH / 5, SPLIT_PANE_HEIGHT));
191 		addComponent (this.splitPane, 0, 0, 1, 1, 3, 1);
192 
193 		ButtionActionProcessor actionProcessor = new ButtionActionProcessor ();
194 		saveButton = new JButton (InsightConstants.getLiteral ("SAVE"));
195 		cancelButton = new JButton (InsightConstants.getLiteral ("CANCEL"));
196 		saveButton.addActionListener (actionProcessor);
197 		cancelButton.addActionListener (actionProcessor);
198 		addComponent (saveButton, 0, 1, 0, 0, 1, 1);
199 		addComponent (cancelButton, 1, 1, 0, 0, 1, 1);
200 
201 		// Add a window adapter to clear state when the user closes this
202 		// frame by clicking on window close
203 		this.addWindowListener (new WindowAdapter () {
204 
205 			public void windowClosing (WindowEvent event) {
206 
207 				resetWidgets ();
208 			}
209 		});
210 	}
211 
212 	/**
213 	 * Displays this frame
214 	 */
215 	public void showPreferences () {
216 
217 		// select the first node
218 		this.preferencesTree.setSelectionRow (0);
219 		this.pack ();
220 		// Center this window in Insight
221 		if (null != parent) {
222 			// Center this window relative to the parent
223 			int insightX = this.parent.getX ();
224 			int insightY = this.parent.getY ();
225 			int thisX = insightX
226 					+ ((this.parent.getWidth () - this.getWidth ()) / 2);
227 			int thisY = insightY
228 					+ ((this.parent.getHeight () - this.getHeight ()) / 2);
229 			this.setLocation (thisX, thisY);
230 		} else {
231 			// Center it on the screen
232 			Dimension dim = getToolkit ().getScreenSize ();
233 			Rectangle abounds = getBounds ();
234 			setLocation ((dim.width - abounds.width) / 2,
235 							(dim.height - abounds.height) / 2);
236 		}
237 
238 		this.show ();
239 	}
240 
241 	/**
242 	 * Hides this frame
243 	 */
244 	public void hidePreferences () {
245 
246 		if (null != parent) {
247 			// If this has a parent it can be reused!
248 			this.hide ();
249 			resetWidgets ();
250 		} else {
251 			// No parent so this will never be used again.
252 			this.dispose ();
253 			System.exit (0);
254 		}
255 	}
256 
257 	/**
258 	 * Interface implementation method
259 	 * 
260 	 * @see javax.swing.event.TreeSelectionListener#valueChanged(javax.swing.event.TreeSelectionEvent)
261 	 */
262 	public void valueChanged (TreeSelectionEvent arg0) {
263 
264 		DefaultMutableTreeNode node = (DefaultMutableTreeNode) preferencesTree
265 				.getLastSelectedPathComponent ();
266 		if (node == null) {
267 			return;
268 		}
269 		Object nodeInfo = node.getUserObject ();
270 		PreferenceInfo prefInfo = (PreferenceInfo) nodeInfo;
271 		Preference selectedPreference = PreferenceManager.getInstance ()
272 				.getPreference (prefInfo.getCompleteId ());
273 		AbstractPreferencesUIPanel uiPanel = (AbstractPreferencesUIPanel) loadedUIPanels
274 				.get (selectedPreference.getId ());
275 		if (uiPanel == null) {
276 			try {
277 				uiPanel = (AbstractPreferencesUIPanel) Class
278 						.forName (selectedPreference.getDisplayClass ())
279 						.newInstance ();
280 				loadedUIPanels.put (selectedPreference.getId (), uiPanel);
281 				uiPanel.initialize (selectedPreference, this);
282 			} catch (Exception ex) {
283 				ex.printStackTrace ();
284 				this.splitPane.setRightComponent (new JLabel (InsightConstants
285 						.getLiteral ("ERROR_PREF_UI")));
286 				return;
287 			}
288 		}
289 		this.splitPane.setRightComponent (uiPanel);
290 	}
291 
292 	/**
293 	 * Adds the specified component to this panel using the specified
294 	 * constraints.
295 	 * 
296 	 * @param c
297 	 *            The component to add
298 	 * @param gridx
299 	 *            Horizontal location on the grid
300 	 * @param gridy
301 	 *            Vertical location on the grid
302 	 * @param weightx
303 	 *            The horizontal weight
304 	 * @param weighty
305 	 *            The vertical weight
306 	 * @param width
307 	 *            The width of the component
308 	 * @param height
309 	 *            The height of the component
310 	 */
311 	private final void addComponent (Component c, int gridx, int gridy,
312 			int weightx, int weighty, int width, int height) {
313 
314 		gc.fill = GridBagConstraints.BOTH;
315 		gc.anchor = GridBagConstraints.NORTHWEST;
316 		gc.insets = new Insets (5, 5, 5, 5);
317 		gc.gridx = gridx;
318 		gc.gridy = gridy;
319 		gc.weightx = weightx;
320 		gc.weighty = weighty;
321 		gc.gridwidth = width;
322 		gc.gridheight = height;
323 		gl.setConstraints (c, gc);
324 		getContentPane ().add (c);
325 	}
326 
327 	/**
328 	 * Helper method that gets the preferences
329 	 * 
330 	 * @return The tree with all the loaded preferences.
331 	 */
332 	private DefaultMutableTreeNode getPreferenceNames () {
333 
334 		DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode ();
335 		PreferenceManager prefManager = PreferenceManager.getInstance ();
336 		for (Iterator iterator = prefManager.getAllPreferenceNames ()
337 				.iterator (); iterator.hasNext ();) {
338 			PreferenceInfo prefInfo = (PreferenceInfo) iterator.next ();
339 			addPreferenceToTree (prefInfo, rootNode);
340 		}
341 		return rootNode;
342 	}
343 
344 	/**
345 	 * Helper method that recursively adds the the specified PrefenceInfo and
346 	 * its children as leaves to the JTree using the specified tree node.
347 	 * 
348 	 * @param prefInfo
349 	 *            the PreferenceInfo containing the preference and its children
350 	 * @param parentNode
351 	 *            the DefaultMutableTreeNode to add the prefernce to
352 	 */
353 	private void addPreferenceToTree (PreferenceInfo prefInfo,
354 			DefaultMutableTreeNode parentNode) {
355 
356 		if (prefInfo.isUserModifiable () && !prefInfo.isAggregated ()) {
357 			DefaultMutableTreeNode thisNode = new DefaultMutableTreeNode (
358 					prefInfo);
359 			parentNode.add (thisNode);
360 			Iterator iterator = prefInfo.iterateChildPreferenceInfos ();
361 			while (iterator != null && iterator.hasNext ()) {
362 				addPreferenceToTree ((PreferenceInfo) iterator.next (),
363 										thisNode);
364 			}
365 		}
366 	}
367 
368 	/**
369 	 * Helper method to reset the widgets
370 	 */
371 	protected void resetWidgets () {
372 
373 		this.loadedUIPanels.clear ();
374 		// disable selected row. This is needed because
375 		// the panel contnets are loaded in valueChanged() method is fired
376 		this.preferencesTree.setSelectionRow ( -1);
377 	}
378 
379 	/**
380 	 * This class listens for events on the parent dialog.
381 	 * 
382 	 * @author <a href="mailto:regunath_b@mindtree.com">Regunath B</a>
383 	 * @version $Revision: 27 $ $Date: 2007-12-16 04:58:03 -0700 (Sun, 16 Dec 2007) $
384 	 */
385 	private final class ButtionActionProcessor implements ActionListener {
386 
387 		/**
388 		 * Interface method implementation
389 		 * 
390 		 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
391 		 */
392 		public void actionPerformed (ActionEvent e) {
393 
394 			Object source = e.getSource ();
395 			if (source == saveButton) {
396 				// inform the PreferenceManager of an intent to save
397 				// preference(s)
398 				PreferenceManager.getInstance ().startPreferencesSave ();
399 				Iterator iterator = loadedUIPanels.values ().iterator ();
400 				while (iterator.hasNext ()) {
401 					// inform the preference GUIs to update the Preference
402 					// values for persistence
403 					((AbstractPreferencesUIPanel) iterator.next ())
404 							.setPreferenceValues ();
405 				}
406 				// inform the PreferenceManager of save preference(s) completion
407 				PreferenceManager.getInstance ().endPreferencesSave ();
408 			}
409 			hidePreferences ();
410 		}
411 
412 	}
413 
414 }