JDock 1.4

http://www.swingall.com
(c) 2005-2006 JAPISoft


JDock is a swing framework for managing, moving and resizing inner windows. JDock works with standard layouts like BorderLayout or GridBagLayout.

JDock is a container for inner windows. Inner windows have two layouts :
The user can resize any inner windows. However he can only drag and drop inner windows with a title bar.

I. Anonymous inner windows

Using anonymous inner windows is a way for maintaining your look-and-feel inside your interface but adding a resizing facility for each
part.

JDock is the main container for your components. By default this container works with a BorderLayout but it is possible to use another one
calling setLayout. As JDock is not a swing component, the user must include it in a user interface calling getView. Adding anonymous inner windows
is available with the addInnerWindow method or the add method matching the similar method of the swing Container class. The last method
is a facility for converting your code to a JDock usage.

JDock includes various facilities. For handling an inner window, JDock requires an ID which is the name of the component (property getName/setName) for the anonymous cases (and the id for the other cases).

Note that when stopping definitly using JDock you recommand you to call the dispose method freeing inner references except if you terminate your application.

Sample with a BorderLayout :

// Main panel
JDock pane = new JDock();

// The default layout is already a borderLayout
// pane.setLayout( new BorderLayout() );
       
pane.addInnerWindow( new JScrollPane( new JTree() ), BorderLayout.WEST );
pane.addInnerWindow( new JTextArea(), BorderLayout.CENTER );
pane.addInnerWindow( new JTextField( "SOUTH" ), BorderLayout.SOUTH );
       
JTextField tf;
       
pane.addInnerWindow( tf = new JTextField( "NORTH" ), BorderLayout.NORTH );
       
// We define as sample an initial size
tf.setPreferredSize( new Dimension( 100, 50 ) );
       
pane.addInnerWindow( new JScrollPane( new JTree() ), BorderLayout.EAST );
       
JFrame frame = new JFrame();
frame.getContentPane().add( pane.getView() );
frame.setSize( 600, 500 );
frame.setVisible( true );

In this sample we add 5 anonymous inner windows.  Note that you needn't to call setLayout( new BorderLayout() ) because this is managed
by JDock if no layout is provided. The user can initialize an inner window size calling setPreferredSize on the bound component, in our sample
this is the case for a textField tf.

Sample with a GridBagLayout :

public class SimpleGridBagLayout extends JFrame {
      JScrollPane spTree = new JScrollPane();
      JScrollPane spList = new JScrollPane();
      JScrollPane spList2 = new JScrollPane();
      JList downList = new JList();
      JScrollPane spText = new JScrollPane();
      JTextArea textArea = new JTextArea();
      GridBagLayout gridBagLayout1 = new GridBagLayout();
      JTree tree = new JTree();
      JList listRightDown = new JList();
      JList listRightTop = new JList();

      public SimpleGridBagLayout() {
          initUI();
      }
     
      private void initUI() {
         
        JDock dock = new JDock();

        dock.setLayout(gridBagLayout1);
        textArea.setText("jTextArea1");
        dock.add(spTree,  new GridBagConstraints(0, 0, 1, 2, 1.0, 1.0
                ,GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(2, 4, 0, 0), 138, 364));
        dock.add(spList,  new GridBagConstraints(2, 0, 1, 1, 1.0, 1.0
                ,GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(2, 0, 0, 3), 116, 240));
        dock.add(spList2,  new GridBagConstraints(2, 1, 1, 1, 1.0, 1.0
                ,GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 3), 116, 118));
        dock.add(downList,  new GridBagConstraints(0, 2, 3, 1, 1.0, 1.0
                ,GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 4, 5, 3), 527, 114));
        dock.add(spText,  new GridBagConstraints(1, 0, 1, 2, 1.0, 1.0
                ,GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(2, 0, 0, 0), 184, 346));
        spText.getViewport().add(textArea, null);
        spTree.getViewport().add(tree, null);
        spList2.getViewport().add(listRightDown, null);
        spList.getViewport().add(listRightTop, null);
       
        getContentPane().add( dock.getView() );
      }

      public static void main( String[] args ) {
        SimpleGridBagLayout frame = new SimpleGridBagLayout();
        frame.setBounds( 0, 0, 600, 500 );
        frame.setVisible( true );
      }
    }


In this sample we use anonymous inner windows with a GridBagLayout. Note that the add method is similar to the swing add method
from the Container class.

II. Title bar inner windows

When an inner window is not anonymous, it has a title bar. This title bar has various functions :
Each inner window with a title bar must have an unique ID. This ID is used for managing the inner window. We describe below the available actions :
Note that the user interface behavior of the hidding/showing actions will depend on your current layout. On some layouts, the fact of removing/hidding some components can create a wrong screen result like an empty part. This is often the case of layout with a cells system like the GridBagLayout, if you have added a component at a cell 0,0 and at cell 2,2, if you remove the component at a cell 1,1 an empty part will appear because the layout will always consider the 1,1 location as a valid one.

Sample with a BorderLayout :

public class InnerWindowBorderLayout {

    public static void main( String[] args ) {

        // Main panel
        JDock pane = new JDock();

        // Action for removing the default shadow
        // pane.setShadowMode( false );

        // The default JDock layout is a BorderLayout

        pane.addInnerWindow( new InnerWindowProperties( "T1", "Tree", new JScrollPane( new JTree() ) ), BorderLayout.WEST );
        pane.addInnerWindow( new InnerWindowProperties( "TA", "Text Area", new JTextArea() ), BorderLayout.CENTER );
        pane.addInnerWindow( new JTextField( "SOUTH" ), BorderLayout.SOUTH );
               
        pane.addInnerWindow( new JTextField( "NORTH" ), BorderLayout.NORTH );
       
        JTree t = null;
       
        pane.addInnerWindow( new InnerWindowProperties( "T2", "Tree 2", t = new JTree() ), BorderLayout.EAST );
       
        // We set an initial size as sample
       
        t.setPreferredSize( new Dimension( 200, 50 ) );    
       
        JFrame frame = new JFrame();
        frame.getContentPane().add( pane.getView() );
        frame.setSize( 600, 500 );
        frame.setVisible( true );

    }
   

In this sample, we have by default a BorderLayout. We add several inner windows having a title bar like "T1" which contains a tree.  Note that
each component can have a preferredSize for initializing its size.

Sample with a GridBagLayout :

public class InnerWindowGridBagLayout extends JFrame {
      JScrollPane spTree = new JScrollPane();
      JScrollPane spList = new JScrollPane();
      JScrollPane spList2 = new JScrollPane();
      JList downList = new JList();
      JScrollPane spText = new JScrollPane();
      JTextArea textArea = new JTextArea();
      GridBagLayout gridBagLayout1 = new GridBagLayout();
      JTree tree = new JTree();
      JList listRightDown = new JList();
      JList listRightTop = new JList();

      public InnerWindowGridBagLayout() {
          jbInit();
      }

      private void jbInit() {
         
        JDock dock = new JDock();

        dock.setLayout(gridBagLayout1);
        textArea.setText("jTextArea1");
        dock.addInnerWindow( new InnerWindowProperties( "T1", "Tree", spTree ),  new GridBagConstraints(0, 0, 1, 2, 1.0, 1.0
                ,GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(2, 4, 0, 0), 138, 364));
        dock.addInnerWindow( new InnerWindowProperties( "SP1", "List 1", spList ),  new GridBagConstraints(2, 0, 1, 1, 1.0, 1.0
                ,GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(2, 0, 0, 3), 116, 240));
        dock.addInnerWindow( new InnerWindowProperties( "SP2", "List 2", spList2 ),  new GridBagConstraints(2, 1, 1, 1, 1.0, 1.0
                ,GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 3), 116, 118));
        dock.addInnerWindow( new InnerWindowProperties( "LST", "List 3", downList ),  new GridBagConstraints(0, 2, 3, 1, 1.0, 1.0
                ,GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 4, 5, 3), 527, 114));
        dock.addInnerWindow( new InnerWindowProperties( "TA1", "Text", spText ),  new GridBagConstraints(1, 0, 1, 2, 1.0, 1.0
                ,GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(2, 0, 0, 0), 184, 346));
        spText.getViewport().add(textArea, null);
        spTree.getViewport().add(tree, null);
        spList2.getViewport().add(listRightDown, null);
        spList.getViewport().add(listRightTop, null);

        getContentPane().add( dock.getView() );
      }

      public static void main( String[] args ) {
        InnerWindowGridBagLayout frame = new InnerWindowGridBagLayout();
        frame.setBounds( 0, 0, 600, 500 );
        frame.setVisible( true );
      }

    }

This sample is very similar to the previous one except we specify to JDock a GridBagLayout calling setLayout and we
use required constraints.

III. Using custom actions

When using inner windows with a title bar, the user can have actions. We have two categories of actions :
The user can modify the common ones using the CommonActionManager. For updating these actions, it is required to
handle a class rather than an instance because each inner window will receive a new instance. By default there are the
ExtractAction and the MaxMinAction classes respectively for extracting the inner window to an external frame and to
maximize and minimize the inner window. Note that for adding a new common action, the user must implement the
CommonAction interface and the DockableAction interface. The first one notifies to the title bar that this action has
no usage when extracting the inner window toolbar to an external frame toolbar, the second one gives access to the current
inner window component.

For managing customs actions, the user has an ActionModel. This ActionModel is a collection of javax.swing.Action.
A facility is available for creating a new one with the BasicActionModel class. There's several solutions for specifying
an action model, the first one is by calling the addInnerWindow method from the JDock class and the second one is by calling getInnerWindowActionsForId.

For adding a Separator between several actions, the user must add this action ActionModel.SEPARATOR.

Sample for using custom actions :

public class Actions {

    public static void main( String[] args ) {

        // We add everywhere the Extract action
       
        CommonActionManager.addCommonAction( ExtractAction.class );
       
        // We remove everywhere the maximize/minimize action

        CommonActionManager.removeCommonAction( MaxMinAction.class );
       
        // Main panel
        JDock pane = new JDock();

        // Action for removing the default shadow
        // pane.setShadowMode( false );

        // The default JDock layout is a BorderLayout

        JTextArea textArea = new JTextArea();
       
        Action[] actions =
            new Action[] {
                new CopyAction( textArea ),
                new CutAction( textArea ),
                new PasteAction( textArea ),
                ActionModel.SEPARATOR,   // Separator sample
                new ExtractAction()    // This is a default action
        };

        JScrollPane sp = null;

        pane.addInnerWindow( new InnerWindowProperties( "T1", "Tree", sp = new JScrollPane( new JTree() ) ), BorderLayout.WEST );

        // We give a preferred size for this tree

        sp.setPreferredSize( new Dimension( 150, 100 ) );
       
        pane.addInnerWindow( new InnerWindowProperties( "TA", "Text Area", new BasicActionModel( actions ), textArea ), BorderLayout.CENTER );

        JTextField tf = new JTextField( "SOUTH" );
        tf.setPreferredSize( new Dimension( 100, 150 ) );
       
        pane.addInnerWindow( new InnerWindowProperties( "TE1", "Text1", tf ), BorderLayout.SOUTH );
       
               
        pane.addInnerWindow( new InnerWindowProperties( "TE2", "Text2", new JTextField( "NORTH" ) ), BorderLayout.NORTH );
       
        // We want no title for this inner window
       
        pane.addInnerWindow( new InnerWindowProperties( "T2", null, new JScrollPane( new JTree() ) ), BorderLayout.EAST );

        // We remove the extract action from the T1 inner frame and the TE1 inner frame

        ActionModel model1 = pane.getInnerWindowActionsForId( "T1" );
        Action a1 = model1.getActionByClass( ExtractAction.class );
        model1.removeAction( a1 );

        ActionModel model2 = pane.getInnerWindowActionsForId( "TE1" );
        Action a2 = model2.getActionByClass( ExtractAction.class );
        model2.removeAction( a2 );
       
        // We show the jdock content
       
        JFrame frame = new JFrame();
        frame.getContentPane().add( pane.getView() );
        frame.setSize( 600, 500 );
        frame.setVisible( true );

    }

    // Sample of actions
   
    // Copy the text selection
   
    static class CopyAction extends AbstractAction {
       
        private JTextComponent text;

        public CopyAction( JTextComponent text ) {
            this.text = text;
            putValue( Action.SHORT_DESCRIPTION, "Copy action" );
            putValue( Action.SMALL_ICON, new ImageIcon( getClass().getResource( "Copy16.gif" ) ) );
        }
        public void actionPerformed( ActionEvent e ) {
            text.copy();
        }
    }

    // Cut the text selection
   
    static class CutAction extends AbstractAction {
       
        private JTextComponent text;

        public CutAction( JTextComponent text ) {
            this.text = text;
            putValue( Action.SHORT_DESCRIPTION, "Cut the selection" );
            putValue( Action.SMALL_ICON, new ImageIcon( getClass().getResource( "Cut16.gif" ) ) );
        }
        public void actionPerformed( ActionEvent e ) {
            text.cut();
        }
    }

    // Paste the text selection
   
    static class PasteAction extends AbstractAction {
       
        private JTextComponent text;

        public PasteAction( JTextComponent text ) {
            this.text = text;
            putValue( Action.SHORT_DESCRIPTION, "Paste the clipboard" );
            putValue( Action.SMALL_ICON, new ImageIcon( getClass().getResource( "Paste16.gif" ) ) );
        }
        public void actionPerformed( ActionEvent e ) {
            text.paste();
        }
    }
       
}

In this sample, we act on the common actions by removing the default MaxMinAction and by adding the
ExtractAction. We also set actions for the textField TA. Note that by customizing the ActionModel from the
addInnerWindow method, you will have to insert also the common actions like the ExtractAction.

IV. Various facilities

Many actions are avalaible for inner windows with a title bar. Here a  a set of methods of the JDock class.

Version
Method
Role
1.4
setEnabledActionPopup
By default enabled, it shows a menu popup on the window icon if actions are available in the window bar.
1.4
isEnabledActionPopup
Return true if an action popup menu is available
1.4
resize
Resize a window (width or height). This action will return false when the resize is impossible, for instance when a component size is too little after the operation.
1.1
setEnabledStatusBar
Add a status bar for hidding/showing inner windows. By default this is disabled. Note that this method must be called before using the getView method.
1.1
isEnabledStatusBar
Return true is a status bar is available.
1.1
setInnerWindowFixed
It will avoid the user to move an inner window
1.1
isInnerWindowFixed
Return true is an inner window cannot be moved
1.1
setInnerWindowIconForId
Reset the icon for this inner window (must be non anonymous)
1.1
getInnerWindowIconForId Return the icon for this inner window
1.0
extractInnerWindow
Convert the inner window to an external frame. If there are custom actions a toolbar will be added automatically.
1.0 getInnerWindowActionsForId
Return the ActionModel for this inner window ID
1.0 getInnerWindowTitleForId
Return the title for this inner window ID
1.0 getInnerWindowViewForId
Return the UI content for this inner window ID
1.0 getState
Return the current inner windows UI state. This is a serializable object the user can stored calling ObjectOutputStream.
1.0 hideInnerWindow
Hide an inner window. Note that the behavior of the other component will depend on your current layout.
1.0 isInnerWindowHidden
Return true if an inner window is hidden.
1.0 isMaximizedInnerWindow
Return true if an inner window is maximized
1.0 maximizedRestoredInnerWindow
Maximize or restore the size of an inner window
1.0 maximizeInnerWindow
Maximize an inner window
1.0 removeInnerWindow
Remove definitly an inner window
1.0 restoreInnerWindow
Restore the size of an inner window previously maximized
1.0 selectInnerWindow
Give the focus to an inner window
1.0 setInnerWindowBackgroundForId
Update the background of an inner window
1.0 setInnerWindowForegroundForId
Update the foreground of an inner window
1.0 setInnerWindowTitleForId
Update the title of an inner window
1.0 setState
Restore a UI state of the inner window
1.0 showInnerWindow
Show an inner window previously hidden

Sample for acting on inner windows from a menu :


public class InnerWindowMenu {

    public static void main( String[] args ) {

        // Main panel
        final JDock pane = new JDock();

        pane.addInnerWindow( new InnerWindowProperties( "T1", "Tree", new JScrollPane( new JTree() ) ), BorderLayout.WEST );
        pane.addInnerWindow( new InnerWindowProperties( "TA", "Text Area", new JTextArea() ), BorderLayout.CENTER );
        pane.addInnerWindow( new InnerWindowProperties( "Text", "Text field", new JTextField( "SOUTH" ) ), BorderLayout.SOUTH );
       
        JTextField tf = new JTextField( "NORTH" );
       
        // We force an initial dimension
       
        tf.setPreferredSize( new Dimension( 100, 50 ) );
       
        pane.addInnerWindow( tf, BorderLayout.NORTH ); // "Text2", "Text field 2", tf, BorderLayout.NORTH );
        pane.addInnerWindow( new InnerWindowProperties( "T2", "Tree 2", new JScrollPane( new JTree() ) ), BorderLayout.EAST );

        JFrame frame = new JFrame();
        frame.getContentPane().add( pane.getView() );
        frame.setSize( 600, 500 );
       
        JMenuBar bar = new JMenuBar();
       
        // Menu for hidding / showing an inner window
       
        JMenu menu = new JMenu( "Hide/Show" );
        bar.add( menu );

        // Menu sample for destroying an inner window
        // Destroy means the inner window can't be used after
       
        JMenu menu2 = new JMenu( "Destroy" );
        JMenuItem item1 = menu2.add( new AbstractAction() {
            public void actionPerformed( ActionEvent e ) {
                pane.removeInnerWindow( "T1" );
            }
        });
        item1.setText( "T1" );
        bar.add( menu2 );

        // Menu sample for selecting an inner window

        JMenu menu4 = new JMenu( "Select" );
        item1 = menu4.add( new AbstractAction() {
            public void actionPerformed( ActionEvent e ) {
                pane.selectInnerWindow( "T2" );
            }
        });
        item1.setText( "Tree 2" );
        item1 = menu4.add( new AbstractAction() {
            public void actionPerformed( ActionEvent e ) {
                pane.selectInnerWindow( "TA" );
            }
        });
        item1.setText( "Text Area" );

        bar.add( menu4 );

        // Menu sample for maximizing

        JMenu menu5 = new JMenu( "Maximize" );
        item1 = menu5.add( new AbstractAction() {
            public void actionPerformed( ActionEvent e ) {
                pane.maximizedRestoredInnerWindow( "TA" );
            }
        });
        item1.setText( "Text Area" );

        bar.add( menu5 );

        // Menu sample for extracting an inner window content

        JMenu menu6 = new JMenu( "Extractor" );
        item1 = menu6.add( new AbstractAction() {
            public void actionPerformed( ActionEvent e ) {
                pane.extractInnerWindow( "TA" );
            }
        });
        item1.setText( "Text Area" );
       
        bar.add( menu6 );

        // Menu sample for showing a shadow when resizing or moving an inner window

        JMenu menu7 = new JMenu( "Shadow" );
        item1 = menu7.add( new AbstractAction() {
            public void actionPerformed( ActionEvent e ) {
                if ( pane.isEnabledResizeShasow() )
                    pane.setEnabledResizeShadow( false );
                else
                    pane.setEnabledResizeShadow( true );
            }
        });
        item1.setText( "Resize" );

        item1 = menu7.add( new AbstractAction() {
            public void actionPerformed( ActionEvent e ) {
                if ( pane.isEnabledDraggingShasow() )
                    pane.setEnabledDraggingShadow( false );
                else
                    pane.setEnabledDraggingShadow( true );
            }
        });
        item1.setText( "Dragging" );
       
        bar.add( menu7 );
       
        JMenu menu8 = new JMenu( "State" );
   
        item1 = menu8.add( new AbstractAction() {
            public void actionPerformed( ActionEvent e ) {
                state = pane.getState();
            }
        });
        item1.setText( "Save" );

        item1 = menu8.add( new AbstractAction() {
            public void actionPerformed( ActionEvent e ) {
                if ( state != null )
                    pane.setState( state );
            }
        });
        item1.setText( "Restore" );
       
        bar.add( menu8 );

        // Menu for disposing the JDock panel and terminating this
        // application
       
        JMenu menu3 = new JMenu( "Exit" );
        item1 = menu3.add( new AbstractAction() {
            public void actionPerformed( ActionEvent e ) {
                pane.dispose();
                System.exit( 0 );
            }
        });
        item1.setText( "JDock" );
        bar.add( menu3 );

        frame.setJMenuBar( bar );
       
        // Here the way for having the menu managed by JDock;
        pane.setMenuWindow( menu );

        frame.setVisible( true );
    }

    static State state;
}

In this sample, we create a JMenu for acting on the inner window. We also let JDock managing our menu for
hidding/showing inner windows by calling setMenuWindow.

V. Look-and-feel

The user can control the look-and-feel of JDock. First of all, creating JDock with a boolean argument, it is possible to
remove the UI shadow for the inner windows. The JDock background can be updated using setBackground. Also when
moving or resizing the shadow can be removed.

The inner window title can be updated with the following UIManager properties :
For having no starting and final color, the user must set the same value for both. By default the final color is the panel
background.

For updating dynamically the title or the background (starting color) or the title color, the following methods are provided
setInnerWindowBackgroundForId, setInnerWindowForegroundForId and setInnerWindowTitleForId. It is possible
to remove a title using a null value.

Sample for changing the colors or the shadow while resizing or moving :


public class Colors {
   
    public static void main( String[] args ) {

        // Reset the starting color of the header for each non selected inner window
        UIManager.put( "jdock.innerwindow.gradient.startColor", Color.DARK_GRAY );
        // Reset the final color of the header for each non selected inner window
        UIManager.put( "jdock.innerwindow.gradient.stopColor", Color.WHITE );
        // Reset the starting color of the header for each selected inner window
        UIManager.put( "jdock.innerwindow.gradient.selectedStartColor", Color.RED.darker() );
        // Reset the final color of the header for each selected inner window       
        UIManager.put( "jdock.innerwindow.gradient.selectedStopColor", Color.WHITE );       
       
        // Main panel without shadow for the inner window
        JDock pane = new JDock( false );

        // Action for removing the default shadow
        // pane.setShadowMode( false );

        // The default JDock layout is a BorderLayout

        pane.addInnerWindow( new InnerWindowProperties( "T1", "Tree", new JScrollPane( new JTree() ) ), BorderLayout.WEST );
        pane.addInnerWindow( new InnerWindowProperties( "TA", "Text Area", new JTextArea() ), BorderLayout.CENTER );
        pane.addInnerWindow( new InnerWindowProperties( "TEXT1", "Text1", new JTextField( "SOUTH" ) ), BorderLayout.SOUTH );
       
        JTextField tf;
       
        pane.addInnerWindow( new InnerWindowProperties( "TEXTE", "Text2", tf = new JTextField( "NORTH" ) ), BorderLayout.NORTH );
       
        tf.setPreferredSize( new Dimension( 100, 50 ) );
       
        pane.addInnerWindow( new InnerWindowProperties( "T2", "Tree 2", new JTree() ), BorderLayout.EAST );
       
        // Background color for the inner panel
        pane.setBackground( Color.BLACK );
        // Color of the found window while dragging an inner window
        pane.setDraggingActiveWindow( Color.BLUE );
        // Color of the shadow while dragging an inner window
        pane.setDraggingShadowColor( Color.GREEN );
        // Color of the shadow while resizing an inner window
        pane.setResizingShadowColor( Color.GREEN );

        pane.setInnerWindowBackgroundForId( "T1", Color.GREEN.darker() );
       
        JFrame frame = new JFrame();
        frame.getContentPane().add( pane.getView() );
        frame.setSize( 600, 500 );
        frame.setVisible( true );

    }
   
}

VI. State

For saving the drag'n drop state, the inner windows size or the maximized inner window, the user can use the getState method. This method will
return a State object that implements the java.io.Serializable interface. This object can be saved or restored using a java.io.ObjectOutputStream or
java.io.ObjectInputStream. Here a sample for writting the state in a file :

JDock dock = new JDock();
...

State currentState = dock.getState();
ObjectOutputStream output = new ObjectOutputStream( new FileOutputStream( "jdoc.state" ) );
output.writeObject( currentState );
output.close();


This is similar for restoring a previous state using the java.io.ObjectInputStream and calling setState on the JDock class

VII. Listener

For receiving events about various user actions, a JDockListener is available. This listener can be added calling addJDockListener inside
the JDock container.

An event is generated for the following cases :

(c) 2004 JAPISoft