/*=============================================================================
* Copyright Texas Instruments, Inc., 2002. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package ti.chimera.plugin;
import ti.exceptions.ProgrammingErrorException;
import ti.chimera.*;
import ti.chimera.pref.ChoiceNodeContract;
import ti.chimera.registry.*;
import ti.chimera.service.*;
import java.util.*;
import java.lang.ref.*;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
/**
* This plugin provides an implementation of the window manager mode. It
* provides an implementation of the {@link WindowMode} service for the
* window manager to use to activate/deactivate this mode. The rest of
* this plugin realizes the implementation of displaying dialogs, tool-
* bars, menubar entries, etc., on behalf of the window manager plugin.
* <p>
* This plugin is only half of the equasion as far as window management.
* The other half is the plugin that implements the "window manager"
* service, which is the "front end" that the rest of the system uses.
* <center><img src="WindowManagerArchitecture.png"></center>
* The devision is labor is that the this plugin responds to data written
* into the registry.
*
* @author Rob Clark
* @version 0.1
*/
public class DesktopModePlugin
extends AbstractModePlugin
{
/**
* The desktop containing all the dialogs
*/
private JDesktopPane desktopPane;
/**
*/
private NodeSubscriber mainWindowBoundsSubscriber = new SwingNodeSubscriber( new NodeSubscriber() {
public void publish( Node node, Object value )
{
Rectangle rv = (Rectangle)value;
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
Insets i = getScreenInsets();
if( rv.x < i.left )
rv.x = i.left;
if( rv.y < i.top )
rv.y = i.top;
if( (rv.width + rv.x) > (d.width - i.right) )
rv.width = d.width - i.right - rv.x;
if( (rv.height + rv.y) > (d.height - i.bottom) )
rv.height = d.height - i.bottom - rv.y;
getMain().debug( 1, getName() + ": mainWindow.setBounds( " + rv + " )" );
mainWindow.setBounds(rv);
}
} );
/**
*/
private NodeSubscriber dragModeSubscriber = new SwingNodeSubscriber( new NodeSubscriber() {
public void publish( Node node, Object value )
{
getMain().debug( 1, getName() + ": desktopPane.setDragMode( " + value + " )" );
desktopPane.setDragMode( ((Integer)value).intValue() );
}
} );
/*=======================================================================*/
/**
* Class Constructor.
*
* @param main the main application
*/
public DesktopModePlugin( Main main )
{
super( main, "Desktop Mode" );
try
{
registry.link(
new PersistentNode( getDefaultMainWindowBounds(),
new TypeNodeContract( Rectangle.class ),
"the bounds of the main window" ),
"/Window Manager/" + getName() + "/bounds" );
registry.link(
new PersistentNode( new Integer( JDesktopPane.LIVE_DRAG_MODE ),
new ChoiceNodeContract( new Object[] { new Integer( JDesktopPane.LIVE_DRAG_MODE ), new Integer( JDesktopPane.OUTLINE_DRAG_MODE )},
new Object[] { "opaque", "outline" } ),
"what drag mode to use?" ),
"/Preferences/Window Manager/Desktop Mode/Drag Mode" );
}
catch(RegistryException e)
{
throw new ProgrammingErrorException(e);
}
main.atExit( new Runnable() {
public void run()
{
if( mainWindow != null )
{
try
{
registry.resolve("/Window Manager/Desktop Mode/bounds").setValue( mainWindow.getBounds() );
}
catch(RegistryException e)
{
throw new ProgrammingErrorException(e);
}
}
}
} );
registerServiceFactory( new ServiceFactory() {
public Service createService()
{
return new AbstractWindowMode("desktop mode") {
/**
* Called after mainWindow is created, but before subscribes in start()
*/
protected void startHook()
{
// build the desktop pane containing all the dialogs (JInternalFrames)
desktopPane = new JDesktopPane();
registry.subscribeToValue(
"/Window Manager/Desktop Mode/bounds",
null,
mainWindowBoundsSubscriber
);
registry.subscribeToValue(
"/Preferences/Window Manager/Desktop Mode/Drag Mode",
null,
dragModeSubscriber
);
((RootPaneContainer)mainWindow).getRootPane().getContentPane().add( desktopPane, ti.swing.DockLayout.CENTER );
}
/**
* Called after unsubscribes in stop()
*/
protected void stopHook()
{
registry.unsubscribeFromValue(mainWindowBoundsSubscriber);
registry.unsubscribeFromValue(dragModeSubscriber);
desktopPane = null;
}
/**
* Called to realize a dialog
*/
protected void createDialog( String name )
{
desktopPane.add( new DesktopModeDialogImplementation(name) );
}
};
}
} );
}
/*=======================================================================*/
/**
* Get the appropriate default main-window size for this mode
*/
protected Rectangle getDefaultMainWindowBounds()
{
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
Insets i = getScreenInsets();
Rectangle r = new Rectangle();
r.x = i.left;
r.y = i.top;
r.width = d.width - i.left - i.right;
r.height = d.height - i.top - i.bottom;
getMain().debug( 1, getName() + ": getDefaultMainWindowBounds() => " + r);
return r;
}
/*=======================================================================*/
/**
* Create the main-window, in which the menubar, toolbar, etc. are
* displayed.
*
* @return the main-window
* @see #diposeMainWindow
*/
protected Component createMainWindow()
{
JFrame mainWindow = new JFrame( getAppName() ) {
public void setBounds( int x, int y, int width, int height )
{
super.setBounds( x, y, width, height );
try {
fixBounds();
} catch(NullPointerException e) {
/* XXX ignore... ugly hack to work around details of how java
* implements inner-classes... if we access dialogUtilityTable
* prior to this constructor returning, then the access method
* generated by the compiler will throw a NPE.
*/
}
}
};
mainWindow.setDefaultCloseOperation( JFrame.DO_NOTHING_ON_CLOSE );
mainWindow.addWindowListener( new WindowAdapter() {
public void windowClosing( WindowEvent evt ) { main.exit(0); }
} );
// build the menu-bar-item tree:
mainWindow.setJMenuBar( new ti.chimera.MenuBar( getMain(), "/MenuBar" ) );
return mainWindow;
}
protected void fixMainWindowBounds() {}
/*=======================================================================*/
/**
* Dispose of the main-window created by {@link #createMainWindow}.
*
* @param mainWindow the main-window to dispose
* @see #createMainWindow
*/
protected void disposeMainWindow( Component mainWindow )
{
((JFrame)mainWindow).dispose();
}
/*=======================================================================*/
/**
* The dialog implementation realizes the display of a dialog created
* by the window manager. It handles subscribing to the children of
* <code>/Dialogs/<TITLE></code> to receive state change notification
* of the dialog it is realizing. Also, it subscribes to the deletion
* of <code>/Dialogs/<TITLE></code> to detect that the dialog has
* been closed.
*/
private class DesktopModeDialogImplementation
extends JInternalFrameWrapper
implements DialogImplementation
{
private DialogUtility util;
private boolean windowVisible = false;
/**
* Class Constructor
*
* @param title the unique title of this dialog
*/
DesktopModeDialogImplementation( String title )
{
super( title, true, true, true, true );
util = new DialogUtility( this, title );
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
addInternalFrameListener( new InternalFrameAdapter() {
public void internalFrameClosing( InternalFrameEvent evt )
{
util.triggerDispose();
}
} );
}
public void setVisible( boolean b )
{
windowVisible = b;
refreshVisibility();
}
public void refreshVisibility()
{
super.setVisible( windowVisible && userInterfaceVisible );
}
public void toFront()
{
try {
setIcon(false);
} catch(java.beans.PropertyVetoException e) {}
super.toFront();
}
public void dispose()
{
try
{
util.dispose();
super.dispose();
}
catch(WindowManager.DialogNotClosableException e)
{
// ignore
}
}
public void center()
{
Rectangle mb = mainWindow.getBounds();
Rectangle tb = getBounds();
tb.x = (mb.width - tb.width) / 2;
tb.y = (mb.height - tb.height) / 2;
setBounds(tb);
}
public void setBounds( int x, int y, int width, int height )
{
// fix the bounds to not fall outside of desktop pane
if( desktopPane.isVisible() &&
(desktopPane.getWidth() > 0) &&
(desktopPane.getHeight() > 0) )
{
if( x < 0 )
x = 0;
if( y < 0 )
y = 0;
if( (x + width) > desktopPane.getWidth() )
width = desktopPane.getWidth() - x;
if( (y + height) > desktopPane.getHeight() )
height = desktopPane.getHeight() - y;
}
super.setBounds( x, y, width, height );
util.boundsUpdated();
}
public void fixBounds() { /* XXX */ }
public void addWindowListener( WindowListener l )
{
addInternalFrameListener( new WindowListenerWrapper(l) );
}
public void removeWindowListener( WindowListener l )
{
removeInternalFrameListener( new WindowListenerWrapper(l) );
}
private class WindowListenerWrapper
implements InternalFrameListener
{
private WindowListener l;
WindowListenerWrapper( WindowListener l )
{
this.l = l;
}
public void internalFrameOpened( InternalFrameEvent evt )
{
l.windowOpened( makeWindowEvent(evt) );
}
public void internalFrameClosing( InternalFrameEvent evt )
{
l.windowClosing( makeWindowEvent(evt) );
}
public void internalFrameClosed( InternalFrameEvent evt )
{
l.windowClosed( makeWindowEvent(evt) );
}
public void internalFrameIconified( InternalFrameEvent evt )
{
l.windowIconified( makeWindowEvent(evt) );
}
public void internalFrameDeiconified( InternalFrameEvent evt )
{
l.windowDeiconified( makeWindowEvent(evt) );
}
public void internalFrameActivated( InternalFrameEvent evt )
{
l.windowActivated( makeWindowEvent(evt) );
}
public void internalFrameDeactivated( InternalFrameEvent evt )
{
l.windowDeactivated( makeWindowEvent(evt) );
}
private WindowEvent makeWindowEvent( InternalFrameEvent evt )
{
return null; // XXX
}
public int hashCode()
{
return l.hashCode();
}
public boolean equals( Object obj )
{
return (obj instanceof WindowListenerWrapper) && ((WindowListenerWrapper)obj).l.equals(l);
}
}
}
}
/*
* Local Variables:
* tab-width: 2
* indent-tabs-mode: nil
* mode: java
* c-indentation-style: java
* c-basic-offset: 2
* eval: (c-set-offset 'substatement-open '0)
* eval: (c-set-offset 'case-label '+)
* eval: (c-set-offset 'inclass '+)
* eval: (c-set-offset 'inline-open '0)
* End:
*/
|