001: /*=============================================================================
002: * Copyright Texas Instruments, Inc., 2002. All Rights Reserved.
003: *
004: * This program is free software; you can redistribute it and/or modify
005: * it under the terms of the GNU General Public License as published by
006: * the Free Software Foundation; either version 2 of the License, or
007: * (at your option) any later version.
008: *
009: * This program is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU General Public License for more details.
013: *
014: * You should have received a copy of the GNU General Public License
015: * along with this program; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: */
018:
019: package ti.chimera.plugin;
020:
021: import ti.exceptions.ProgrammingErrorException;
022: import ti.chimera.*;
023: import ti.chimera.pref.ChoiceNodeContract;
024: import ti.chimera.registry.*;
025: import ti.chimera.service.*;
026:
027: import java.util.*;
028: import java.lang.ref.*;
029: import javax.swing.*;
030: import javax.swing.event.*;
031: import java.awt.*;
032: import java.awt.event.*;
033:
034: /**
035: * This plugin provides an implementation of the window manager mode. It
036: * provides an implementation of the {@link WindowMode} service for the
037: * window manager to use to activate/deactivate this mode. The rest of
038: * this plugin realizes the implementation of displaying dialogs, tool-
039: * bars, menubar entries, etc., on behalf of the window manager plugin.
040: * <p>
041: * This plugin is only half of the equasion as far as window management.
042: * The other half is the plugin that implements the "window manager"
043: * service, which is the "front end" that the rest of the system uses.
044: * <center><img src="WindowManagerArchitecture.png"></center>
045: * The devision is labor is that the this plugin responds to data written
046: * into the registry.
047: *
048: * @author Rob Clark
049: * @version 0.1
050: */
051: public class DesktopModePlugin extends AbstractModePlugin {
052: /**
053: * The desktop containing all the dialogs
054: */
055: private JDesktopPane desktopPane;
056:
057: /**
058: */
059: private NodeSubscriber mainWindowBoundsSubscriber = new SwingNodeSubscriber(
060: new NodeSubscriber() {
061:
062: public void publish(Node node, Object value) {
063: Rectangle rv = (Rectangle) value;
064: Dimension d = Toolkit.getDefaultToolkit()
065: .getScreenSize();
066: Insets i = getScreenInsets();
067:
068: if (rv.x < i.left)
069: rv.x = i.left;
070:
071: if (rv.y < i.top)
072: rv.y = i.top;
073:
074: if ((rv.width + rv.x) > (d.width - i.right))
075: rv.width = d.width - i.right - rv.x;
076:
077: if ((rv.height + rv.y) > (d.height - i.bottom))
078: rv.height = d.height - i.bottom - rv.y;
079:
080: getMain().debug(
081: 1,
082: getName() + ": mainWindow.setBounds( " + rv
083: + " )");
084: mainWindow.setBounds(rv);
085: }
086:
087: });
088:
089: /**
090: */
091: private NodeSubscriber dragModeSubscriber = new SwingNodeSubscriber(
092: new NodeSubscriber() {
093:
094: public void publish(Node node, Object value) {
095: getMain().debug(
096: 1,
097: getName() + ": desktopPane.setDragMode( "
098: + value + " )");
099: desktopPane.setDragMode(((Integer) value)
100: .intValue());
101: }
102:
103: });
104:
105: /*=======================================================================*/
106: /**
107: * Class Constructor.
108: *
109: * @param main the main application
110: */
111: public DesktopModePlugin(Main main) {
112: super (main, "Desktop Mode");
113:
114: try {
115: registry.link(new PersistentNode(
116: getDefaultMainWindowBounds(), new TypeNodeContract(
117: Rectangle.class),
118: "the bounds of the main window"),
119: "/Window Manager/" + getName() + "/bounds");
120: registry
121: .link(
122: new PersistentNode(
123: new Integer(
124: JDesktopPane.LIVE_DRAG_MODE),
125: new ChoiceNodeContract(
126: new Object[] {
127: new Integer(
128: JDesktopPane.LIVE_DRAG_MODE),
129: new Integer(
130: JDesktopPane.OUTLINE_DRAG_MODE) },
131: new Object[] { "opaque",
132: "outline" }),
133: "what drag mode to use?"),
134: "/Preferences/Window Manager/Desktop Mode/Drag Mode");
135: } catch (RegistryException e) {
136: throw new ProgrammingErrorException(e);
137: }
138:
139: main.atExit(new Runnable() {
140:
141: public void run() {
142: if (mainWindow != null) {
143: try {
144: registry.resolve(
145: "/Window Manager/Desktop Mode/bounds")
146: .setValue(mainWindow.getBounds());
147: } catch (RegistryException e) {
148: throw new ProgrammingErrorException(e);
149: }
150: }
151: }
152: });
153:
154: registerServiceFactory(new ServiceFactory() {
155:
156: public Service createService() {
157: return new AbstractWindowMode("desktop mode") {
158:
159: /**
160: * Called after mainWindow is created, but before subscribes in start()
161: */
162: protected void startHook() {
163: // build the desktop pane containing all the dialogs (JInternalFrames)
164: desktopPane = new JDesktopPane();
165:
166: registry.subscribeToValue(
167: "/Window Manager/Desktop Mode/bounds",
168: null, mainWindowBoundsSubscriber);
169:
170: registry
171: .subscribeToValue(
172: "/Preferences/Window Manager/Desktop Mode/Drag Mode",
173: null, dragModeSubscriber);
174:
175: ((RootPaneContainer) mainWindow).getRootPane()
176: .getContentPane().add(desktopPane,
177: ti.swing.DockLayout.CENTER);
178: }
179:
180: /**
181: * Called after unsubscribes in stop()
182: */
183: protected void stopHook() {
184: registry
185: .unsubscribeFromValue(mainWindowBoundsSubscriber);
186: registry
187: .unsubscribeFromValue(dragModeSubscriber);
188: desktopPane = null;
189: }
190:
191: /**
192: * Called to realize a dialog
193: */
194: protected void createDialog(String name) {
195: desktopPane
196: .add(new DesktopModeDialogImplementation(
197: name));
198: }
199:
200: };
201: }
202:
203: });
204: }
205:
206: /*=======================================================================*/
207: /**
208: * Get the appropriate default main-window size for this mode
209: */
210: protected Rectangle getDefaultMainWindowBounds() {
211: Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
212: Insets i = getScreenInsets();
213: Rectangle r = new Rectangle();
214:
215: r.x = i.left;
216: r.y = i.top;
217: r.width = d.width - i.left - i.right;
218: r.height = d.height - i.top - i.bottom;
219:
220: getMain().debug(1,
221: getName() + ": getDefaultMainWindowBounds() => " + r);
222:
223: return r;
224: }
225:
226: /*=======================================================================*/
227: /**
228: * Create the main-window, in which the menubar, toolbar, etc. are
229: * displayed.
230: *
231: * @return the main-window
232: * @see #diposeMainWindow
233: */
234: protected Component createMainWindow() {
235: JFrame mainWindow = new JFrame(getAppName()) {
236: public void setBounds(int x, int y, int width, int height) {
237: super .setBounds(x, y, width, height);
238: try {
239: fixBounds();
240: } catch (NullPointerException e) {
241: /* XXX ignore... ugly hack to work around details of how java
242: * implements inner-classes... if we access dialogUtilityTable
243: * prior to this constructor returning, then the access method
244: * generated by the compiler will throw a NPE.
245: */
246: }
247: }
248: };
249:
250: mainWindow.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
251: mainWindow.addWindowListener(new WindowAdapter() {
252: public void windowClosing(WindowEvent evt) {
253: main.exit(0);
254: }
255: });
256:
257: // build the menu-bar-item tree:
258: mainWindow.setJMenuBar(new ti.chimera.MenuBar(getMain(),
259: "/MenuBar"));
260:
261: return mainWindow;
262: }
263:
264: protected void fixMainWindowBounds() {
265: }
266:
267: /*=======================================================================*/
268: /**
269: * Dispose of the main-window created by {@link #createMainWindow}.
270: *
271: * @param mainWindow the main-window to dispose
272: * @see #createMainWindow
273: */
274: protected void disposeMainWindow(Component mainWindow) {
275: ((JFrame) mainWindow).dispose();
276: }
277:
278: /*=======================================================================*/
279: /**
280: * The dialog implementation realizes the display of a dialog created
281: * by the window manager. It handles subscribing to the children of
282: * <code>/Dialogs/<TITLE></code> to receive state change notification
283: * of the dialog it is realizing. Also, it subscribes to the deletion
284: * of <code>/Dialogs/<TITLE></code> to detect that the dialog has
285: * been closed.
286: */
287: private class DesktopModeDialogImplementation extends
288: JInternalFrameWrapper implements DialogImplementation {
289: private DialogUtility util;
290: private boolean windowVisible = false;
291:
292: /**
293: * Class Constructor
294: *
295: * @param title the unique title of this dialog
296: */
297: DesktopModeDialogImplementation(String title) {
298: super (title, true, true, true, true);
299:
300: util = new DialogUtility(this , title);
301:
302: setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
303: addInternalFrameListener(new InternalFrameAdapter() {
304: public void internalFrameClosing(InternalFrameEvent evt) {
305: util.triggerDispose();
306: }
307: });
308: }
309:
310: public void setVisible(boolean b) {
311: windowVisible = b;
312: refreshVisibility();
313: }
314:
315: public void refreshVisibility() {
316: super .setVisible(windowVisible && userInterfaceVisible);
317: }
318:
319: public void toFront() {
320: try {
321: setIcon(false);
322: } catch (java.beans.PropertyVetoException e) {
323: }
324: super .toFront();
325: }
326:
327: public void dispose() {
328: try {
329: util.dispose();
330: super .dispose();
331: } catch (WindowManager.DialogNotClosableException e) {
332: // ignore
333: }
334: }
335:
336: public void center() {
337: Rectangle mb = mainWindow.getBounds();
338: Rectangle tb = getBounds();
339:
340: tb.x = (mb.width - tb.width) / 2;
341: tb.y = (mb.height - tb.height) / 2;
342:
343: setBounds(tb);
344: }
345:
346: public void setBounds(int x, int y, int width, int height) {
347: // fix the bounds to not fall outside of desktop pane
348: if (desktopPane.isVisible() && (desktopPane.getWidth() > 0)
349: && (desktopPane.getHeight() > 0)) {
350: if (x < 0)
351: x = 0;
352:
353: if (y < 0)
354: y = 0;
355:
356: if ((x + width) > desktopPane.getWidth())
357: width = desktopPane.getWidth() - x;
358:
359: if ((y + height) > desktopPane.getHeight())
360: height = desktopPane.getHeight() - y;
361: }
362:
363: super .setBounds(x, y, width, height);
364: util.boundsUpdated();
365: }
366:
367: public void fixBounds() { /* XXX */
368: }
369:
370: public void addWindowListener(WindowListener l) {
371: addInternalFrameListener(new WindowListenerWrapper(l));
372: }
373:
374: public void removeWindowListener(WindowListener l) {
375: removeInternalFrameListener(new WindowListenerWrapper(l));
376: }
377:
378: private class WindowListenerWrapper implements
379: InternalFrameListener {
380: private WindowListener l;
381:
382: WindowListenerWrapper(WindowListener l) {
383: this .l = l;
384: }
385:
386: public void internalFrameOpened(InternalFrameEvent evt) {
387: l.windowOpened(makeWindowEvent(evt));
388: }
389:
390: public void internalFrameClosing(InternalFrameEvent evt) {
391: l.windowClosing(makeWindowEvent(evt));
392: }
393:
394: public void internalFrameClosed(InternalFrameEvent evt) {
395: l.windowClosed(makeWindowEvent(evt));
396: }
397:
398: public void internalFrameIconified(InternalFrameEvent evt) {
399: l.windowIconified(makeWindowEvent(evt));
400: }
401:
402: public void internalFrameDeiconified(InternalFrameEvent evt) {
403: l.windowDeiconified(makeWindowEvent(evt));
404: }
405:
406: public void internalFrameActivated(InternalFrameEvent evt) {
407: l.windowActivated(makeWindowEvent(evt));
408: }
409:
410: public void internalFrameDeactivated(InternalFrameEvent evt) {
411: l.windowDeactivated(makeWindowEvent(evt));
412: }
413:
414: private WindowEvent makeWindowEvent(InternalFrameEvent evt) {
415: return null; // XXX
416: }
417:
418: public int hashCode() {
419: return l.hashCode();
420: }
421:
422: public boolean equals(Object obj) {
423: return (obj instanceof WindowListenerWrapper)
424: && ((WindowListenerWrapper) obj).l.equals(l);
425: }
426: }
427: }
428: }
429:
430: /*
431: * Local Variables:
432: * tab-width: 2
433: * indent-tabs-mode: nil
434: * mode: java
435: * c-indentation-style: java
436: * c-basic-offset: 2
437: * eval: (c-set-offset 'substatement-open '0)
438: * eval: (c-set-offset 'case-label '+)
439: * eval: (c-set-offset 'inclass '+)
440: * eval: (c-set-offset 'inline-open '0)
441: * End:
442: */
|