Copyright © 2004 Christopher M Butler This work is licensed under a Creative Commons License.
Eleritec Docking Framework Tutorial
The BorderManager Interface The StandardBorderManager
A BorderManager Example
The provided border management example consists of three classes; BorderDemo.java, DemoBorderManager.java, and DockablePanel.java. They have been separated out into multiple classes based upon logical function to help demonstrate how custom border management might be included into a more extensive application.

BorderDemo.java is the main class responsible for constructing the application. It instantiates a JFrame, adds several DefaultDockingPorts to the content pane, and docks a series of docking-enabled panels into a preconfigured layout. The construction code in this class is very similar to that used in previous examples. The method buildDockingPort() retrieves a DefaultDockingPort from createDockingPort() and adds a DockablePanel into it.

Toggle to Hide Example Code
private DefaultDockingPort buildDockingPort(String desc) {
   // create the DockingPort
   DefaultDockingPort port = createDockingPort();

   // create the Dockable panel
   DockablePanel panel = new DockablePanel(desc);

   // dock the panel and return the DockingPort
   port.dock(panel.getDockable(), DockingPort.CENTER_REGION);

   return port;
}

private DefaultDockingPort createDockingPort() {
   DefaultDockingPort port = new DefaultDockingPort();
   port.setPreferredSize(new Dimension(100, 100));
   port.setBorderManager(new DemoBorderManager());
   port.setComponentProvider(new ComponentProvider());
   return port;
}

As shown here, the inner class ComponentProvider is used as the SubComponentProvider for the DefaultDockingPort. This inner class extends the ComponentProviderAdapter class, since only the createChildPort() and createSplitPane() methods are needed for this example. We also see references to our two other classes, DockablePanel and DemoBorderManager. DockablePanel has a getDockable() method that returns a Dockable instance responsible for delegation of its Dockable functionality. What is curiously absent here is the usual call to DockingManager.registerDockable().

Turning to DockablePanel.java, one finds that Dockable registration happens directly within the constructor. DockablePanel uses an inner class DockableImpl to handle its docking-related functionality. This is the object returned by getDockable(), and it is the object that is registered with the DockingManager at the end fo the DockablePanel constructor.

Toggle to Hide Example Code
public DockablePanel(String title) {
   super(new BorderLayout());
   dragInit = new JPanel();
   dragInit.setBackground(getBackground().darker());
   dragInit.setPreferredSize(new Dimension(10, 10));
   add(dragInit, BorderLayout.EAST);
   setBorder(new TitledBorder(title));
   setTitle(title);
   dockableImpl = new DockableImpl();
   DockingManager.registerDockable(dockableImpl);
}
.
.
Dockable getDockable() {
   return dockableImpl;
}
.
.
private class DockableImpl extends DockableAdapter {
   public Component getDockable() {
      return getThis();
   }

   public String getDockableDesc() {
      return title;
   }

   public Component getInitiator() {
      return dragInit;
   }

   public void setDockableDesc(String desc) {
      setTitle(desc);
   }
}

The DockablePanel is merely a generic JPanel with a TitledBorder, a BorderLayout, and a gray sidebar in the EAST region to act as a drag initiator. By itself, this is nothing we haven't seen before.

The DemoBorderManager class is where the real substance of the example resides. It is designed specifically to work with the DockablePanel class, so its implementation is by no means generic. The private method getDesiredBorder() is responsible for creating a border for docked components.

Toggle to Hide Example Code
private Border getDesiredBorder(Component cmp) {
	if (cmp instanceof DefaultDockingPort)
		cmp = ((DefaultDockingPort) cmp).getDockedComponent();

	if (cmp instanceof DockablePanel) {
		String title = ((DockablePanel) cmp).getDockable().getDockableDesc();
		return new TitledBorder(title);
	}
	return dummyBorder;
}

This method is able to pull out the description of a DockablePanel, if one exists, and return a TitledBorder. Otherwise, it returns a dummy TitledBorder without a caption.

The managePortNullChild() method merely assigns the dummy border to the entire DockingPort.

Toggle to Hide Example Code
public void managePortNullChild(DockingPort port) {
   setBorder(port, dummyBorder);
}

The managePortSimpleChild() method strips any border from the docked component and assigns the desired TitledBorder, complete with descriptive text, to the entire DockingPort.

Toggle to Hide Example Code
public void managePortSimpleChild(DockingPort port) {
   if (port == null || port.getDockedComponent() == null)
      return;

   Component docked = port.getDockedComponent();
   setBorder(docked, null);
   setBorder(port, getDesiredBorder(docked));
}

The managePortTabbedChild() method removes the border from the DockingPort itself and assigns a desired border to each Component within the docked JTabbedPane. Because of the way getDesiredBorder() works, each TitledBorder in the JTabbedPane will match the current tab title.

Toggle to Hide Example Code
public void managePortTabbedChild(DockingPort port) {
   setBorder(port, null);

   if (port == null || !(port.getDockedComponent() instanceof JTabbedPane))
      return;

   JTabbedPane tabs = (JTabbedPane) port.getDockedComponent();
   int tc = tabs.getTabCount();
   for (int i = 0; i < tc; i++)
      setBorder(tabs.getComponentAt(i), new TitledBorder(tabs.getTitleAt(i)));
}

The managePortSplitChild() method removes borders from the DockingPort, JSplitPane, and child DockingPorts. It then adds a desired border to each docked component in the split pane configuration.

Toggle to Hide Example Code
public void managePortSplitChild(DockingPort port) {
   if (port == null || !(port.getDockedComponent() instanceof JSplitPane))
      return;

   // clear the borders on the split pane and divider
   JSplitPane split = (JSplitPane) port.getDockedComponent();
   clearSplitPaneBorder(split);

   // determine the borders for each child component

   Component left = split.getLeftComponent();
   Component right = split.getRightComponent();
   Border leftBorder = getDesiredBorder(left);
   Border rightBorder = getDesiredBorder(right);

   // set the borders for all interested parties
   setBorder(port, null);
   setBorder(left, null);
   setBorder(right, null);
   setBorder(getDocked(left), leftBorder);
   setBorder(getDocked(right), rightBorder);
}

The BorderManager Interface The StandardBorderManager