Source code: com/virtuosotechnologies/asaph/maingui/PaneManagerImpl.java
1 /*
2 ================================================================================
3
4 FILE: PaneManagerImpl.java
5
6 PROJECT:
7
8 Asaph
9
10 CONTENTS:
11
12 Implementation of the pane manager
13
14 PROGRAMMERS:
15
16 Daniel Azuma (DA) <dazuma@kagi.com>
17
18 COPYRIGHT:
19
20 Copyright (C) 2003 Daniel Azuma (dazuma@kagi.com)
21
22 This program is free software; you can redistribute it and/or
23 modify it under the terms of the GNU General Public License as
24 published by the Free Software Foundation; either version 2
25 of the License, or (at your option) any later version.
26
27 This program is distributed in the hope that it will be useful,
28 but WITHOUT ANY WARRANTY; without even the implied warranty of
29 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 GNU General Public License for more details.
31
32 You should have received a copy of the GNU General Public
33 License along with this program; if not, write to
34 Free Software Foundation, Inc.
35 59 Temple Place, Suite 330
36 Boston, MA 02111-1307 USA
37
38 ================================================================================
39 */
40
41
42 package com.virtuosotechnologies.asaph.maingui;
43
44
45 import java.beans.PropertyVetoException;
46 import java.util.Set;
47 import java.util.HashSet;
48 import java.awt.Dimension;
49 import javax.swing.JDesktopPane;
50 import javax.swing.JComponent;
51 import javax.swing.JInternalFrame;
52 import javax.swing.WindowConstants;
53 import javax.swing.event.InternalFrameAdapter;
54 import javax.swing.event.InternalFrameEvent;
55
56 import com.virtuosotechnologies.lib.base.ConstrainedKey;
57 import com.virtuosotechnologies.lib.command.CommandNode;
58 import com.virtuosotechnologies.lib.command.CommandEvent;
59 import com.virtuosotechnologies.lib.basiccommand.BasicCommandNode;
60 import com.virtuosotechnologies.lib.basiccommand.BasicItemCommandNode;
61 import com.virtuosotechnologies.lib.basiccommand.BasicContainerCommandNode;
62 import com.virtuosotechnologies.lib.basiccommand.swing.CommandNodeMenuBar;
63 import com.virtuosotechnologies.lib.propertyset.PropertySet;
64 import com.virtuosotechnologies.lib.propertyset.PropertySetListener;
65 import com.virtuosotechnologies.lib.propertyset.PropertySetEvent;
66 import com.virtuosotechnologies.lib.propertyset.BasicPropertySet;
67
68
69 /**
70 * Implementation of the pane manager
71 */
72 /*package*/ class PaneManagerImpl
73 implements PaneManager
74 {
75 private JDesktopPane desktop_;
76 private int lastPaneX_;
77 private int lastPaneY_;
78 private Set openPanes_;
79 private BasicCommandNode windowsMenuNode_;
80 private ListsImpl listsImpl_;
81
82
83 /*package*/ PaneManagerImpl(
84 ListsImpl listsImpl)
85 {
86 desktop_ = new JDesktopPane();
87 openPanes_ = new HashSet();
88 lastPaneX_ = 1000000;
89 lastPaneY_ = 1000000;
90 listsImpl_ = listsImpl;
91 }
92
93
94 /*package*/ void setCommandManager(
95 CommandManagerImpl commandManager)
96 {
97 windowsMenuNode_ = commandManager.getWindowsMenuNode();
98 }
99
100
101 /*package*/ JComponent getJComponent()
102 {
103 return desktop_;
104 }
105
106
107 /**
108 * Open a pane in the main gui. Depending on how the main gui is
109 * implemented, this pane may show up as a tab in a tabbed pane, or an
110 * internal frame, or in some other similar fashion.
111 *
112 * @param component Component representing the pane
113 * @param title initial title for the pane
114 * @param commands CommandNode for creating a menu bar, or null for no menu bar
115 * @param handler a PaneHandler for handling pane events
116 * @return A PaneController that will manipulate this pane
117 */
118 public PaneController createPane(
119 JComponent component,
120 String title,
121 CommandNode commands,
122 final PaneHandler handler)
123 {
124 final JInternalFrame frame = new JInternalFrame(title, true, true, true, true);
125 frame.setContentPane(component);
126
127 if (commands != null)
128 {
129 BasicCommandNode container = new BasicContainerCommandNode();
130 container.addChild(commands);
131 CommandNodeMenuBar menuBar = new CommandNodeMenuBar(container);
132 frame.setJMenuBar(menuBar);
133 }
134
135 // Setup controller
136 final PaneControllerImpl controller = new PaneControllerImpl(
137 frame, handler);
138 openPanes_.add(controller);
139
140 // Setup menu
141 PaneCommandNode node = new PaneCommandNode(controller);
142 windowsMenuNode_.addChild(node);
143 controller.setCommandNode(node);
144
145 // What to do on close
146 frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
147 frame.addInternalFrameListener(
148 new InternalFrameAdapter()
149 {
150 public void internalFrameClosing(
151 InternalFrameEvent ev)
152 {
153 if (handler.handlePaneClosing())
154 {
155 controller.close();
156 }
157 }
158 });
159
160 // Add to desktop
161 desktop_.add(frame);
162 frame.pack();
163 int desktopWidth = desktop_.getWidth();
164 int desktopHeight = desktop_.getHeight();
165 Dimension dim = frame.getSize();
166 dim.width += 10;
167 dim.width = Math.min(dim.width, desktopWidth-25);
168 dim.height = Math.min(dim.height, desktopHeight-25);
169 frame.setSize(dim);
170 int x = lastPaneX_+20;
171 int y = lastPaneY_+20;
172 if (x+dim.width > desktopWidth) x = 2;
173 if (y+dim.height > desktopHeight) y = 2;
174 frame.setLocation(x, y);
175 lastPaneX_ = x;
176 lastPaneY_ = y;
177 frame.setVisible(true);
178
179 return controller;
180 }
181
182
183 /*package*/ boolean shutDown()
184 {
185 while (!openPanes_.isEmpty())
186 {
187 PaneControllerImpl controller = (PaneControllerImpl)openPanes_.iterator().next();
188 if (!controller.getHandler().handlePaneClosing())
189 {
190 return false;
191 }
192 controller.close();
193 }
194 return true;
195 }
196
197
198 private class PaneCommandNode
199 extends BasicItemCommandNode
200 {
201 private PaneControllerImpl controller_;
202
203 /*package*/ PaneCommandNode(
204 PaneControllerImpl controller)
205 {
206 controller_ = controller;
207 setNameProperty((String)controller_.getValue(PaneController.TITLE_KEY));
208 }
209
210 public void commandInvoked(
211 CommandEvent ev)
212 {
213 controller_.grabFocus();
214 }
215 }
216
217
218 private class PaneControllerImpl
219 extends BasicPropertySet
220 implements
221 PaneController,
222 PropertySetListener
223 {
224 private JInternalFrame frame_;
225 private PaneHandler handler_;
226 private boolean isOpen_ = true;
227 private BasicCommandNode paneCommandNode_;
228
229
230 /*package*/ PaneControllerImpl(
231 JInternalFrame frame,
232 PaneHandler handler)
233 {
234 frame_ = frame;
235 putValue(TITLE_KEY, frame_.getTitle());
236 putValue(WINDOW_MODIFIED_KEY, Boolean.FALSE);
237 handler_ = handler;
238 addPropertySetListener(this);
239 }
240
241
242 /*package*/ PaneHandler getHandler()
243 {
244 return handler_;
245 }
246
247
248 /*package*/ void setCommandNode(
249 BasicCommandNode node)
250 {
251 paneCommandNode_ = node;
252 }
253
254
255 /**
256 * Returns true if the pane is still open. That is, if it hasn't had its
257 * close() method called yet. If this returns false, this PaneController is
258 * defunct and cannot have any other methods invoked.
259 *
260 * @return true if the pane is still open.
261 */
262 public boolean isOpen()
263 {
264 return isOpen_;
265 }
266
267
268 /**
269 * Close the pane in the main gui. Once the pane is closed, this handle
270 * will go defunct and cannot be used again, except to query isOpen().
271 *
272 * @exception IllegalStateException pane already closed.
273 */
274 public void close()
275 {
276 if (!isOpen_)
277 {
278 throw new IllegalStateException();
279 }
280 openPanes_.remove(this);
281 isOpen_ = false;
282 frame_.dispose();
283 desktop_.remove(frame_);
284 for (int i=windowsMenuNode_.getNumChildren()-1; i>=0; --i)
285 {
286 if (windowsMenuNode_.getNthChild(i) == paneCommandNode_)
287 {
288 windowsMenuNode_.removeNthChild(i);
289 break;
290 }
291 }
292 listsImpl_.requestFocus();
293 }
294
295
296 /**
297 * Returns true if this pane has focus. Focus means the internal frame
298 * or tab is in front and has keyboard focus.
299 *
300 * @return true if the pane has focus.
301 * @exception IllegalStateException pane is closed.
302 */
303 public boolean isFocused()
304 {
305 if (!isOpen_)
306 {
307 throw new IllegalStateException();
308 }
309 return frame_.isSelected();
310 }
311
312
313 /**
314 * Cause this pane to grab focus. Focus means the internal frame or tab
315 * is in front and has keyboard focus.
316 *
317 * @exception IllegalStateException pane is closed.
318 */
319 public void grabFocus()
320 {
321 if (!isOpen_)
322 {
323 throw new IllegalStateException();
324 }
325 try
326 {
327 frame_.setSelected(true);
328 }
329 catch (PropertyVetoException ex)
330 {
331 }
332 }
333
334
335 public void propertySetChanged(
336 PropertySetEvent ev)
337 {
338 ConstrainedKey key = ev.getKey();
339 if (key == TITLE_KEY)
340 {
341 String title = (String)ev.getNewValue();
342 frame_.setTitle(title);
343 paneCommandNode_.setNameProperty(title);
344 }
345 else if (key == WINDOW_MODIFIED_KEY)
346 {
347 frame_.putClientProperty("windowModified", ev.getNewValue());
348 }
349 }
350 }
351 }