0001: /*=============================================================================
0002: * Copyright Texas Instruments, Inc., 2002. All Rights Reserved.
0003: *
0004: * This program is free software; you can redistribute it and/or modify
0005: * it under the terms of the GNU General Public License as published by
0006: * the Free Software Foundation; either version 2 of the License, or
0007: * (at your option) any later version.
0008: *
0009: * This program is distributed in the hope that it will be useful,
0010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0012: * GNU General Public License for more details.
0013: *
0014: * You should have received a copy of the GNU General Public License
0015: * along with this program; if not, write to the Free Software
0016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0017: */
0018:
0019: package ti.chimera.plugin;
0020:
0021: import ti.exceptions.ProgrammingErrorException;
0022: import ti.chimera.*;
0023: import ti.chimera.registry.*;
0024: import ti.chimera.service.*;
0025:
0026: import java.util.*;
0027: import java.lang.ref.*;
0028: import javax.swing.*;
0029: import javax.swing.event.*;
0030: import java.awt.*;
0031: import java.awt.event.*;
0032:
0033: /**
0034: * This plugin provides an base implementation of the functionality of
0035: * the window manager mode that should be in common to all modes. It
0036: * provides an abstract base implementation of the {@link WindowMode}
0037: * service for the subclass of this class to extend.
0038: * <p>
0039: * The mode is only half of the equasion as far as window management.
0040: * The other half is the plugin that implements the "window manager"
0041: * service, which is the "front end" that the rest of the system uses.
0042: * <center><img src="WindowManagerArchitecture.png"></center>
0043: * The devision is labor is that the this plugin responds to data written
0044: * into the registry.
0045: *
0046: * @author Rob Clark
0047: * @version 0.1
0048: */
0049: public abstract class AbstractModePlugin extends Plugin {
0050: /**
0051: * For defaults and behaviors that depend on whether we are running
0052: * in a mac environment or not; this is set to <code>true</code> if
0053: * executing on a mac
0054: */
0055: protected static final boolean MRJ = System
0056: .getProperty("mrj.version") != null;
0057:
0058: /**
0059: * For defaults and behaviors that depend on whether we are running
0060: * in a JDK v1.4 or later environment, in which case it is set to
0061: * <code>true</code>.
0062: */
0063: protected static final boolean JDK14 = System.getProperty(
0064: "java.version").startsWith("1.4");
0065:
0066: /**
0067: * We use the registry a lot, so hang on to a copy for easy access...
0068: */
0069: protected Registry registry;
0070:
0071: /**
0072: * The main-window. This is the window that contains the menu-bar, the
0073: * tool-bars, and the JDesktopPane containing all the dialogs
0074: */
0075: protected Component mainWindow;
0076:
0077: /**
0078: * Is the user interface visible?
0079: */
0080: protected boolean userInterfaceVisible = false;
0081:
0082: /**
0083: * The subscriber that listens for look & feel changes
0084: */
0085: private NodeSubscriber lnfSubscriber;
0086:
0087: /**
0088: * The subscriber that listens for new dialogs, and creates a
0089: * {@link DialogImplementation} for each new dialog. The dialog
0090: * implementation itself handles listening for the removal of the
0091: * dialog, so this subscriber only needs to worry about creation.
0092: */
0093: private NodeSubscriber dialogDirectorySubscriber;
0094:
0095: /**
0096: * The subscriber that listens for new toolbars, and displays them.
0097: */
0098: private NodeSubscriber toolBarDirectorySubscriber;
0099:
0100: /**
0101: * The subscriber to the visibility of the user interface
0102: */
0103: private NodeSubscriber visibleSubscriber = new SwingNodeSubscriber(
0104: new NodeSubscriber() {
0105:
0106: public void publish(Node node, Object value) {
0107: setVisible(((Boolean) value).booleanValue());
0108: }
0109:
0110: });
0111:
0112: /**
0113: * Table of DialogUtilities... need to msg the DialogUtility when
0114: * we leave this mode, so they can unsubscribe but not run the
0115: * close-runnables when the dialog itself is dispose'd!
0116: */
0117: private WeakHashMap dialogUtilityTable = new WeakHashMap();
0118:
0119: /*=======================================================================*/
0120: /**
0121: * Class Constructor.
0122: *
0123: * @param main the main application
0124: * @param name the plugin name
0125: */
0126: public AbstractModePlugin(Main main, String name) {
0127: super (main, name);
0128: registry = main.getRegistry();
0129:
0130: try {
0131: if (!registry
0132: .exists("/Preferences/Window Manager/ToolBar Drag")) {
0133: registry
0134: .link(
0135: new Node(
0136: Boolean.FALSE,
0137: NodeContract.BOOLEAN_CONTRACT,
0138: "can a toolbar be dragged out of the toolbar area to become a free-floating window? (Note: this is currently kind of buggy, so it is disabled by default.)"),
0139: "/Preferences/Window Manager/ToolBar Drag");
0140: }
0141: } catch (RegistryException e) {
0142: throw new ProgrammingErrorException(e);
0143: }
0144: }
0145:
0146: protected Main getMain() {
0147: return main;
0148: }
0149:
0150: /*=======================================================================*/
0151: /**
0152: * Called when the visibility of the user interface changes. This should
0153: * be overriden as needed.
0154: */
0155: protected void setVisible(boolean b) {
0156: mainWindow.setVisible(b);
0157: userInterfaceVisible = b;
0158:
0159: // use toArray to avoid ConcurrentModificationException
0160: DialogUtility[] dus;
0161: synchronized (dialogUtilityTable) {
0162: dus = (DialogUtility[]) (dialogUtilityTable.keySet()
0163: .toArray(new DialogUtility[dialogUtilityTable
0164: .size()]));
0165: }
0166:
0167: for (int i = 0; i < dus.length; i++)
0168: dus[i].refreshVisibility();
0169:
0170: mainWindow.repaint();
0171: }
0172:
0173: /*=======================================================================*/
0174: /**
0175: * get the application name
0176: */
0177: protected String getAppName() {
0178: String appname = System.getProperty("ti.chimera.appname");
0179: if (appname == null)
0180: appname = "chimera";
0181: return appname;
0182: }
0183:
0184: /*=======================================================================*/
0185: /**
0186: * utility function for accessing the {@link java.awt.GraphicsEnvironment}
0187: */
0188: protected GraphicsConfiguration getGraphicsConfiguration() {
0189: if (mainWindow != null) {
0190: return mainWindow.getGraphicsConfiguration();
0191: } else {
0192: GraphicsEnvironment ge = GraphicsEnvironment
0193: .getLocalGraphicsEnvironment();
0194: GraphicsDevice[] gds = ge.getScreenDevices();
0195: for (int i = 0; i < gds.length; i++) {
0196: GraphicsConfiguration[] gcs = gds[i]
0197: .getConfigurations();
0198: if ((gcs != null) && (gcs.length > 0))
0199: return gcs[0];
0200: }
0201: return null; // hopefully we don't get here!
0202: }
0203: }
0204:
0205: /*=======================================================================*/
0206: /**
0207: */
0208: public Insets getScreenInsets() {
0209: if (JDK14)
0210: return Toolkit.getDefaultToolkit().getScreenInsets(
0211: getGraphicsConfiguration());
0212: return new Insets(MRJ ? 20 : 0, 0, 0, 0);
0213: }
0214:
0215: /*=======================================================================*/
0216: /**
0217: * fix the bounds of all dialogs
0218: */
0219: protected void fixBounds() {
0220: // use toArray to avoid ConcurrentModificationException
0221: DialogUtility[] dus;
0222: synchronized (dialogUtilityTable) {
0223: dus = (DialogUtility[]) (dialogUtilityTable.keySet()
0224: .toArray(new DialogUtility[dialogUtilityTable
0225: .size()]));
0226: }
0227:
0228: for (int i = 0; i < dus.length; i++)
0229: dus[i].fixBounds();
0230: }
0231:
0232: /*=======================================================================*/
0233: /**
0234: * fix the bounds of all dialogs
0235: */
0236: protected void fixMainWindowBounds() {
0237: boolean resize = false;
0238: Container c = ((RootPaneContainer) mainWindow).getRootPane()
0239: .getContentPane();
0240: Dimension preferredSize = mainWindow.getPreferredSize();
0241: Dimension mainWindowSize = mainWindow.getSize();
0242:
0243: // ???
0244: if ((preferredSize.height == 0) && (preferredSize.width == 0))
0245: return;
0246:
0247: // use preferred height:
0248: if (mainWindowSize.height != preferredSize.height) {
0249: mainWindowSize.height = preferredSize.height;
0250: resize = true;
0251: }
0252:
0253: // but preferred width might be 0, so only grow width:
0254: if (mainWindowSize.width < preferredSize.width) {
0255: mainWindowSize.width = preferredSize.width;
0256: resize = true;
0257: }
0258:
0259: if (resize) {
0260: mainWindow.setSize(mainWindowSize);
0261: fixBounds();
0262: }
0263: }
0264:
0265: /*=======================================================================*/
0266: /**
0267: * Create the main-window, in which the menubar, toolbar, etc. are
0268: * displayed.
0269: *
0270: * @return the main-window
0271: * @see #diposeMainWindow
0272: */
0273: protected abstract Component createMainWindow();
0274:
0275: /*=======================================================================*/
0276: /**
0277: * Dispose of the main-window created by {@link #createMainWindow}.
0278: *
0279: * @param mainWindow the main-window to dispose
0280: * @see #createMainWindow
0281: */
0282: protected abstract void disposeMainWindow(Component mainWindow);
0283:
0284: /*=======================================================================*/
0285: /**
0286: * Base class for service... makes use of startHook()/stopHook()/
0287: * createDialog() which must be implemented by derived class.
0288: */
0289: protected abstract class AbstractWindowMode extends WindowMode {
0290: protected AbstractWindowMode(String name) {
0291: super (name);
0292: }
0293:
0294: public final void start() {
0295: getMain().debug(1, getName() + ": begin start");
0296:
0297: // build the main window:
0298: mainWindow = createMainWindow();
0299: mainWindow.setVisible(false);
0300:
0301: registry.subscribeToValue("/Window Manager/visible",
0302: NodeContract.BOOLEAN_CONTRACT, visibleSubscriber);
0303:
0304: try {
0305: boolean dragOutEnabled = ((Boolean) (registry
0306: .resolve("/Preferences/Window Manager/ToolBar Drag")
0307: .getValue())).booleanValue();
0308:
0309: Container c = ((RootPaneContainer) mainWindow)
0310: .getRootPane().getContentPane();
0311: ti.swing.DockLayout dockLayout = new ti.swing.DockLayout(
0312: c, dragOutEnabled);
0313: dockLayout.setHorizontalSpacing(3);
0314: dockLayout.setVerticalSpacing(3);
0315: c.setLayout(dockLayout);
0316: } catch (RegistryException e) {
0317: throw new ProgrammingErrorException(e);
0318: }
0319:
0320: startHook();
0321:
0322: // setup subscriber to listen for L&F changes:
0323: lnfSubscriber = new SwingNodeSubscriber(
0324: new NodeSubscriber() {
0325:
0326: public void publish(Node node, Object value) {
0327: getMain()
0328: .debug(
0329: 1,
0330: getName()
0331: + ": UIManager.setLookAndFeel( "
0332: + value + " )");
0333: if (value != null) {
0334: try {
0335: UIManager
0336: .setLookAndFeel((String) value);
0337: SwingUtilities
0338: .updateComponentTreeUI(mainWindow);
0339: } catch (Throwable e) {
0340: throw new ProgrammingErrorException(
0341: e);
0342: }
0343: }
0344: }
0345:
0346: });
0347: registry.subscribeToValue(
0348: "/Preferences/Window Manager/Look And Feel",
0349: NodeContract.STRING_CONTRACT, lnfSubscriber);
0350:
0351: // setup subscriber to listen for new dialogs:
0352: dialogDirectorySubscriber = new NodeSubscriber() {
0353:
0354: private DirectoryTable lastDt;
0355:
0356: public void publish(Node node, Object value) {
0357: DirectoryTable dt = (DirectoryTable) value;
0358:
0359: for (Iterator added = dt.notIn(lastDt); added
0360: .hasNext();) {
0361: String dialogName = (String) (added.next());
0362: getMain().debug(
0363: 1,
0364: getName() + ": createDialog( "
0365: + dialogName + " )");
0366: createDialog(dialogName);
0367: }
0368:
0369: lastDt = dt;
0370: }
0371:
0372: };
0373: registry.subscribeToValue("/Dialogs", null,
0374: dialogDirectorySubscriber);
0375:
0376: // setup subscriber to listen for new toolbars:
0377: toolBarDirectorySubscriber = new NodeSubscriber() {
0378:
0379: private DirectoryTable lastDt;
0380:
0381: public void publish(Node node, Object value) {
0382: DirectoryTable dt = (DirectoryTable) value;
0383:
0384: for (Iterator added = dt.notIn(lastDt); added
0385: .hasNext();) {
0386: String basename = (String) (added.next());
0387:
0388: getMain().debug(
0389: 1,
0390: getName() + ": new tool bar: "
0391: + basename);
0392:
0393: (new NodeSubscriberAdapter(registry) {
0394:
0395: private JToolBar currentToolBar;
0396:
0397: public void publish(final Node node,
0398: final Object value) {
0399: SwingUtilities
0400: .invokeLater(new Runnable() {
0401: public void run() {
0402: synchronized (AbstractModePlugin.this ) {
0403: if (mainWindow == null)
0404: return;
0405:
0406: Container c = ((RootPaneContainer) mainWindow)
0407: .getRootPane()
0408: .getContentPane();
0409:
0410: if (currentToolBar != null)
0411: c
0412: .remove(currentToolBar);
0413:
0414: currentToolBar = (JToolBar) value;
0415: if (currentToolBar != null)
0416: c
0417: .add(
0418: currentToolBar,
0419: ti.swing.DockLayout.NORTH);
0420:
0421: // make sure main-window is big enough:
0422: fixMainWindowBounds();
0423:
0424: c.repaint();
0425: }
0426: }
0427: });
0428: }
0429:
0430: public void nodeDeleted(Node node) {
0431: unsubscribe();
0432: publish(node, null); // removes toolbar
0433: }
0434:
0435: }).subscribe("/ToolBars/" + basename, null);
0436: }
0437:
0438: lastDt = dt;
0439: }
0440:
0441: };
0442: registry.subscribeToValue("/ToolBars", null,
0443: toolBarDirectorySubscriber);
0444:
0445: getMain().debug(1, getName() + ": finish start");
0446: }
0447:
0448: public final void stop() {
0449: getMain().debug(1, getName() + ": begin stop");
0450:
0451: // use toArray to avoid ConcurrentModificationException
0452: DialogUtility[] dus;
0453: synchronized (dialogUtilityTable) {
0454: dus = (DialogUtility[]) (dialogUtilityTable.keySet()
0455: .toArray(new DialogUtility[dialogUtilityTable
0456: .size()]));
0457: }
0458:
0459: for (int i = 0; i < dus.length; i++)
0460: dus[i].stop();
0461:
0462: registry.unsubscribeFromValue(lnfSubscriber);
0463: registry.unsubscribeFromValue(dialogDirectorySubscriber);
0464: registry.unsubscribeFromValue(toolBarDirectorySubscriber);
0465:
0466: registry.unsubscribeFromValue(visibleSubscriber);
0467:
0468: stopHook();
0469:
0470: disposeMainWindow(mainWindow);
0471: synchronized (AbstractModePlugin.this ) {
0472: mainWindow = null;
0473: }
0474:
0475: getMain().debug(1, getName() + ": finish stop");
0476: }
0477:
0478: /**
0479: * Called after mainWindow is created, but before subscribes in start()
0480: */
0481: protected abstract void startHook();
0482:
0483: /**
0484: * Called after unsubscribes in stop()
0485: */
0486: protected abstract void stopHook();
0487:
0488: /**
0489: * Called to realize a dialog
0490: */
0491: protected abstract void createDialog(String name);
0492: }
0493:
0494: /*=======================================================================*/
0495: /**
0496: * Iterface used by DialogUtility to manipulate the dialog in response to
0497: * data published by registry
0498: */
0499: protected interface DialogImplementation {
0500: public void setContentPane(Container contentPane);
0501:
0502: public void setBounds(Rectangle bounds);
0503:
0504: public void fixBounds();
0505:
0506: public Rectangle getBounds();
0507:
0508: public void setVisible(boolean visible);
0509:
0510: public void refreshVisibility();
0511:
0512: public void center();
0513:
0514: public void toFront();
0515:
0516: public void pack();
0517:
0518: public void dispose();
0519:
0520: public void addWindowListener(WindowListener l);
0521:
0522: public void removeWindowListener(WindowListener l);
0523: }
0524:
0525: /*=======================================================================*/
0526: /**
0527: * Handles the interface between the registry and the dialog subscriber,
0528: * and other features in common between any dialog implementation. The
0529: * dialog implementation should call <code>dispose()</code> and
0530: * <code>boundsUpdated()</code> as needed.
0531: */
0532: protected class DialogUtility {
0533: // the dialog we are acting on behalf of:
0534: private DialogImplementation impl;
0535: private String title;
0536:
0537: // the list of runnables to run when dispose()'d:
0538: private java.util.List closeRunnableList;
0539:
0540: // list of window-listeners
0541: private java.util.List windowListenerList;
0542:
0543: // hang on to these so we can unsubscribe at the end:
0544: private java.util.List nodeSubscriberList = new LinkedList();
0545:
0546: // keep track of bounds changes that we originated, to prevent infinite loop
0547: private WeakHashMap boundsTable = new WeakHashMap();
0548:
0549: // the window listener
0550: private WindowListener windowListener = new WindowListener() {
0551:
0552: /**
0553: * Invoked the first time a window is made visible.
0554: */
0555: public void windowOpened(WindowEvent evt) {
0556: synchronized (impl) {
0557: for (Iterator itr = windowListenerList.iterator(); itr
0558: .hasNext();)
0559: ((WindowListener) (itr.next()))
0560: .windowOpened(evt);
0561: }
0562: }
0563:
0564: /**
0565: * Invoked when the user attempts to close the window
0566: * from the window's system menu. If the program does not
0567: * explicitly hide or dispose the window while processing
0568: * this event, the window close operation will be cancelled.
0569: */
0570: public void windowClosing(WindowEvent evt) {
0571: synchronized (impl) {
0572: for (Iterator itr = windowListenerList.iterator(); itr
0573: .hasNext();)
0574: ((WindowListener) (itr.next()))
0575: .windowClosing(evt);
0576: }
0577: }
0578:
0579: /**
0580: * Invoked when a window has been closed as the result
0581: * of calling dispose on the window.
0582: */
0583: public void windowClosed(WindowEvent evt) {
0584: synchronized (impl) {
0585: for (Iterator itr = windowListenerList.iterator(); itr
0586: .hasNext();)
0587: ((WindowListener) (itr.next()))
0588: .windowClosed(evt);
0589: }
0590: }
0591:
0592: /**
0593: * Invoked when a window is changed from a normal to a
0594: * minimized state. For many platforms, a minimized window
0595: * is displayed as the icon specified in the window's
0596: * iconImage property.
0597: * @see java.awt.Frame#setIconImage
0598: */
0599: public void windowIconified(WindowEvent evt) {
0600: synchronized (impl) {
0601: for (Iterator itr = windowListenerList.iterator(); itr
0602: .hasNext();)
0603: ((WindowListener) (itr.next()))
0604: .windowIconified(evt);
0605: }
0606: }
0607:
0608: /**
0609: * Invoked when a window is changed from a minimized
0610: * to a normal state.
0611: */
0612: public void windowDeiconified(WindowEvent evt) {
0613: synchronized (impl) {
0614: for (Iterator itr = windowListenerList.iterator(); itr
0615: .hasNext();)
0616: ((WindowListener) (itr.next()))
0617: .windowDeiconified(evt);
0618: }
0619: }
0620:
0621: /**
0622: * Invoked when the window is set to be the user's
0623: * active window, which means the window (or one of its
0624: * subcomponents) will receive keyboard events.
0625: */
0626: public void windowActivated(WindowEvent evt) {
0627: synchronized (impl) {
0628: for (Iterator itr = windowListenerList.iterator(); itr
0629: .hasNext();)
0630: ((WindowListener) (itr.next()))
0631: .windowActivated(evt);
0632: }
0633: }
0634:
0635: /**
0636: * Invoked when a window is no longer the user's active
0637: * window, which means that keyboard events will no longer
0638: * be delivered to the window or its subcomponents.
0639: */
0640: public void windowDeactivated(WindowEvent evt) {
0641: synchronized (impl) {
0642: for (Iterator itr = windowListenerList.iterator(); itr
0643: .hasNext();)
0644: ((WindowListener) (itr.next()))
0645: .windowDeactivated(evt);
0646: }
0647: }
0648:
0649: };
0650:
0651: /**
0652: * Class Constructor
0653: *
0654: * @param impl the dialog implementation
0655: * @param title the title of the dialog
0656: */
0657: DialogUtility(DialogImplementation impl, String title) {
0658: this .impl = impl;
0659: this .title = title;
0660: installSubscribers();
0661: synchronized (dialogUtilityTable) {
0662: dialogUtilityTable.put(this , Boolean.TRUE);
0663: }
0664: }
0665:
0666: private synchronized void installSubscribers() {
0667: getMain().debug(
0668: 0,
0669: getName() + ": " + title
0670: + ": begin installSubscribers");
0671:
0672: Object tmp;
0673:
0674: synchronized (nodeSubscriberList) {
0675: // subscribe to deletion of this dialog:
0676: registry
0677: .subscribeToDeletion(
0678: "/Dialogs/" + title,
0679: (NodeDeletionSubscriber) (tmp = new NodeDeletionSubscriber() {
0680:
0681: public void nodeDeleted(Node node) {
0682: impl.dispose();
0683: }
0684:
0685: }));
0686: nodeSubscriberList.add(tmp);
0687:
0688: // install subscribers:
0689: registry
0690: .subscribeToValue(
0691: "/Dialogs/" + title
0692: + "/closeRunnableList",
0693: null,
0694: (NodeSubscriber) (tmp = new SwingNodeSubscriber(
0695: new NodeSubscriber() {
0696:
0697: public void publish(
0698: Node node,
0699: Object value) {
0700: getMain()
0701: .debug(
0702: 0,
0703: getName()
0704: + ": "
0705: + title
0706: + ": closeRunnableList="
0707: + value);
0708: closeRunnableList = (java.util.List) value;
0709: }
0710:
0711: })));
0712: nodeSubscriberList.add(tmp);
0713:
0714: registry
0715: .subscribeToValue(
0716: "/Dialogs/" + title + "/contentPane",
0717: null,
0718: (NodeSubscriber) (tmp = new SwingNodeSubscriber(
0719: new NodeSubscriber() {
0720:
0721: public void publish(
0722: Node node,
0723: Object value) {
0724: getMain()
0725: .debug(
0726: 0,
0727: getName()
0728: + ": "
0729: + title
0730: + ": contentPane="
0731: + value);
0732: impl
0733: .setContentPane((Container) value);
0734: }
0735:
0736: })));
0737: nodeSubscriberList.add(tmp);
0738:
0739: registry
0740: .subscribeToValue(
0741: "/Dialogs/" + title
0742: + "/windowListenerList",
0743: null,
0744: (NodeSubscriber) (tmp = new SwingNodeSubscriber(
0745: new NodeSubscriber() {
0746:
0747: public void publish(
0748: Node node,
0749: Object value) {
0750: synchronized (impl) {
0751: getMain()
0752: .debug(
0753: 0,
0754: getName()
0755: + ": "
0756: + title
0757: + ": windowListenerList="
0758: + value);
0759: windowListenerList = (java.util.List) value;
0760: }
0761: }
0762:
0763: })));
0764: nodeSubscriberList.add(tmp);
0765:
0766: registry
0767: .subscribeToValue(
0768: "/Dialogs/" + title + "/visible",
0769: null,
0770: (NodeSubscriber) (tmp = new SwingNodeSubscriber(
0771: new NodeSubscriber() {
0772:
0773: public void publish(
0774: Node node,
0775: Object value) {
0776: getMain()
0777: .debug(
0778: 0,
0779: getName()
0780: + ": "
0781: + title
0782: + ": visible="
0783: + value);
0784: impl
0785: .setVisible(((Boolean) value)
0786: .booleanValue());
0787: }
0788:
0789: })));
0790: nodeSubscriberList.add(tmp);
0791:
0792: registry
0793: .subscribeToValue(
0794: "/Dialogs/" + title + "/control",
0795: null,
0796: (NodeSubscriber) (tmp = new SwingNodeSubscriber(
0797: new NodeSubscriber() {
0798:
0799: public void publish(
0800: Node node,
0801: Object value) {
0802: getMain()
0803: .debug(
0804: 0,
0805: getName()
0806: + ": "
0807: + title
0808: + ": control="
0809: + value);
0810:
0811: if (!"ready"
0812: .equals(value))
0813: node
0814: .setValue("ready");
0815:
0816: // ignore null and ready values:
0817: if ((value == null)
0818: || value
0819: .equals("ready"))
0820: return;
0821:
0822: if (value
0823: .equals("center"))
0824: impl.center();
0825: else if (value
0826: .equals("toFront"))
0827: impl.toFront();
0828: else if (value
0829: .equals("pack")) {
0830: if (!avoidPack())
0831: impl.pack();
0832: } else
0833: throw new ProgrammingErrorException(
0834: "unknown control command: "
0835: + value);
0836: }
0837:
0838: })));
0839: nodeSubscriberList.add(tmp);
0840:
0841: registry
0842: .subscribeToValue(
0843: "/Dialogs/" + title + "/bounds",
0844: null,
0845: (NodeSubscriber) (tmp = new SwingNodeSubscriber(
0846: new NodeSubscriber() {
0847:
0848: public void publish(
0849: Node node,
0850: Object value) {
0851: getMain()
0852: .debug(
0853: 0,
0854: getName()
0855: + ": "
0856: + title
0857: + ": bounds="
0858: + value);
0859: if (value != null)
0860: if (boundsTable
0861: .remove(value) == null)
0862: impl
0863: .setBounds((Rectangle) value);
0864: }
0865:
0866: })));
0867: nodeSubscriberList.add(tmp);
0868: }
0869:
0870: impl.addWindowListener(windowListener);
0871:
0872: getMain().debug(
0873: 0,
0874: getName() + ": " + title
0875: + ": finish installSubscribers");
0876: }
0877:
0878: // work-around for #362:
0879: private boolean avoidPack() {
0880: try {
0881: return oscript.fs.AbstractFileSystem.resolve(
0882: "/config/Dialogs/" + title + "/bounds.dat")
0883: .exists();
0884: } catch (java.io.IOException e) {
0885: return false;
0886: }
0887: }
0888:
0889: private void removeSubscribers() {
0890: getMain().debug(
0891: 0,
0892: getName() + ": " + title
0893: + ": begin removeSubscribers");
0894:
0895: impl.removeWindowListener(windowListener);
0896:
0897: synchronized (nodeSubscriberList) {
0898: for (Iterator itr = nodeSubscriberList.iterator(); itr
0899: .hasNext();) {
0900: Object subscriber = itr.next();
0901:
0902: if (subscriber instanceof NodeSubscriber)
0903: registry
0904: .unsubscribeFromValue((NodeSubscriber) subscriber);
0905: else if (subscriber instanceof NodeCreationSubscriber)
0906: registry
0907: .unsubscribeFromCreation((NodeCreationSubscriber) subscriber);
0908: else if (subscriber instanceof NodeDeletionSubscriber)
0909: registry
0910: .unsubscribeFromDeletion((NodeDeletionSubscriber) subscriber);
0911:
0912: itr.remove();
0913: }
0914: }
0915:
0916: getMain().debug(
0917: 0,
0918: getName() + ": " + title
0919: + ": finish removeSubscribers");
0920: }
0921:
0922: /**
0923: * Called when the window system (rather than Dialog object) triggers
0924: * disposing the dialog... rather than calling <code>dispose()</code>
0925: * directly, this removes the registry paths associates with this
0926: * dialog, which causes proper cleanup
0927: */
0928: void triggerDispose() {
0929: try {
0930: registry.unlink("/Dialogs/" + title, true);
0931: } catch (RegistryException e) {
0932: throw new ProgrammingErrorException(e);
0933: }
0934: }
0935:
0936: /**
0937: * To be called by dialog implementation when dialog is disposed
0938: */
0939: void dispose() {
0940: getMain().debug(0, getName() + ": " + title + ": dispose");
0941:
0942: if (closeRunnableList != null) {
0943: synchronized (closeRunnableList) {
0944: for (Iterator itr = closeRunnableList.iterator(); itr
0945: .hasNext();) {
0946: ((Runnable) (itr.next())).run();
0947: itr.remove();
0948: }
0949: }
0950: }
0951:
0952: removeSubscribers();
0953: }
0954:
0955: /**
0956: * Called if we are leaving the current mode... removes subscribers
0957: * but does not run the close-runnables.
0958: */
0959: void stop() {
0960: getMain().debug(0, getName() + ": " + title + ": stop");
0961: closeRunnableList = null;
0962: removeSubscribers();
0963: }
0964:
0965: /**
0966: */
0967: void fixBounds() {
0968: impl.fixBounds();
0969: }
0970:
0971: /**
0972: */
0973: void refreshVisibility() {
0974: impl.refreshVisibility();
0975: }
0976:
0977: /**
0978: * To be called by dialog implementation when bounds changes
0979: */
0980: void boundsUpdated() {
0981: try {
0982: synchronized (registry) {
0983: String path = "/Dialogs/" + title + "/bounds";
0984: if (registry.exists(path)) {
0985: Rectangle r = impl.getBounds();
0986: boundsTable.put(r, Boolean.TRUE);
0987: registry.resolve(path).setValue(r);
0988: }
0989: }
0990: } catch (RegistryException e) {
0991: throw new ProgrammingErrorException(e);
0992: }
0993: }
0994: }
0995: }
0996:
0997: /*
0998: * Local Variables:
0999: * tab-width: 2
1000: * indent-tabs-mode: nil
1001: * mode: java
1002: * c-indentation-style: java
1003: * c-basic-offset: 2
1004: * eval: (c-set-offset 'substatement-open '0)
1005: * eval: (c-set-offset 'case-label '+)
1006: * eval: (c-set-offset 'inclass '+)
1007: * eval: (c-set-offset 'inline-open '0)
1008: * End:
1009: */
|