📄 defaultdockingport.java
字号:
* If the {@code DockingPort} is <b>not</b> empty, and the specified region
* is {@code NORTH_REGION}, {@code SOUTH_REGION}, {@code EAST_REGION}, or
* {@code WEST_REGION}, then the currently docked {@code Component} is
* removed and replaced with a {@code JSplitPane}. Two new
* {@code DefaultDockingPorts} are created as sub-ports and are added to
* each side of the {@code JSplitPane}. The previously docked
* {@code Component} is docked to the CENTER_REGION of one of the sub-ports
* and the new {@code Component} is added to the other. In this case,
* subsequent calls to {@code getDockedComponent()} will return the
* {@code JSplitPane}. In this fasion, the sub-ports will now be capable of
* handling further sub-docking within the layout.
* <p>
* {@code JSplitPane} and sub-{@code DockingPort} creation are delegated to
* the {@code DockingStrategy} returned by {@code getDockingStrategy()}.
* Initial splitpane divider location is also controlled by this
* {@code DockingStrategy}.
*
* @param dockable
* the {@code Dockable} to be docked within this
* {@code DockingPort}
* @param region
* the region within this {@code DockingPort} to dock the
* specified {@code Dockable}
* @return {@code true} if the docking operation was successful,
* {@code false} otherwise.
* @see DockingPort#dock(Dockable, String)
* @see #isDockingAllowed(Component, String)
* @see #getDockedComponent()
* @see #getDockingStrategy()
* @see DockingStrategy#createDockingPort(DockingPort)
* @see DockingStrategy#createSplitPane(DockingPort, String)
* @see DockingStrategy#getInitialDividerLocation(DockingPort, JSplitPane)
* @see DockingStrategy#getDividerProportion(DockingPort, JSplitPane)
*/
public boolean dock(Dockable dockable, String region) {
if (dockable == null)
return false;
Component comp = dockable.getComponent();
if (comp == null || !isDockingAllowed(comp, region))
return false;
// can't dock the same component twice. This will also keep them from
// moving CENTER to NORTH and that sort of thing, which would just be a
// headache to manage anyway.
Component docked = getDockedComponent();
if (comp == docked)
return false;
// if there is nothing currently in the docking port, then we can only
// dock into the CENTER region.
if (docked == null)
region = CENTER_REGION;
String tabTitle = DockingUtility.getTabText(dockable);
COMPONENT_TITLES.put(comp, tabTitle);
if (!isSingleTabAllowed() && docked == null) {
setComponent(comp);
evaluateDockingBorderStatus();
return true;
}
boolean success = CENTER_REGION.equals(region) ? dockInCenterRegion(comp)
: dockInOuterRegion(comp, region);
if (success) {
evaluateDockingBorderStatus();
// if we docked in an outer region, then there is a new JSplitPane.
// We'll want to divide it in half. this is done after
// evaluateDockingBorderStatus(), so we'll know any border
// modification that took place has already happened, and we can be
// relatively safe about assumptions regarding our current insets.
if (!CENTER_REGION.equals(region))
resetSplitDividerLocation();
}
return success;
}
private void resetSplitDividerLocation() {
Component c = getDockedComponent();
if (c instanceof JSplitPane)
deferSplitDividerReset((JSplitPane) c);
}
private void deferSplitDividerReset(final JSplitPane splitPane) {
applySplitDividerLocation(splitPane);
// we don't need to defer split divider location reset until after
// a DockingSplitPane has rendered, since that class is able to figure
// out its proper divider location by itself.
if (splitPane instanceof DockingSplitPane) {
return;
}
// check to see if we've rendered
int size = SwingUtility.getSplitPaneSize(splitPane);
if (splitPane.isVisible() && size > 0 && EventQueue.isDispatchThread()) {
// if so, apply the split divider location and return
applySplitDividerLocation(splitPane);
splitPane.validate();
return;
}
// otherwise, defer applying the divider location reset until
// the split pane is rendered.
EventQueue.invokeLater(new Runnable() {
public void run() {
deferSplitDividerReset(splitPane);
}
});
}
private void applySplitDividerLocation(JSplitPane splitPane) {
DockingStrategy strategy = DockingManager.getDockingStrategy(this);
int loc = strategy.getInitialDividerLocation(this, splitPane);
splitPane.setDividerLocation(loc);
}
private boolean dockInCenterRegion(Component comp) {
Component docked = getDockedComponent();
JTabbedPane tabs = null;
if (docked instanceof JTabbedPane) {
tabs = (JTabbedPane) docked;
addTab(tabs, comp);
tabs.revalidate();
tabs.setSelectedIndex(tabs.getTabCount() - 1);
return true;
}
tabs = createTabbedPane();
// createTabbedPane() is protected and may be overridden, so we'll have
// to check for a possible null case here. Though why anyone would
// return a null, I don't know. Maybe we should throw a
// NullPointerException instead.
if (tabs == null)
return false;
// remove the currently docked component and add it to the tabbed pane
if (docked != null) {
remove(docked);
addTab(tabs, docked);
}
// add the new component to the tabbed pane
addTab(tabs, comp);
// now add the tabbed pane back to the main container
setComponent(tabs);
tabs.setSelectedIndex(tabs.getTabCount() - 1);
return true;
}
private void addTab(JTabbedPane tabs, Component comp) {
String tabText = getValidTabTitle(tabs, comp);
tabs.add(comp, tabText);
Dockable d = DockingManager.getDockable(comp);
if (d == null)
return;
Icon icon = d.getDockingProperties().getTabIcon();
int indx = tabs.getTabCount() - 1;
tabs.setIconAt(indx, icon);
}
private boolean dockInOuterRegion(Component comp, String region) {
// cache the current size and cut it in half for later in the method.
Dimension halfSize = getSize();
halfSize.width /= 2;
halfSize.height /= 2;
// remove the old docked content. we'll be adding it to another
// dockingPort.
Component docked = getDockedComponent();
remove(docked);
// add the components to their new parents.
DockingStrategy strategy = getDockingStrategy();
DockingPort oldContent = strategy.createDockingPort(this);
DockingPort newContent = strategy.createDockingPort(this);
addCmp(oldContent, docked);
dockCmp(newContent, comp);
JSplitPane newDockedContent = strategy.createSplitPane(this, region);
// put the ports in the correct order and add them to a new wrapper
// panel
DockingPort[] ports = putPortsInOrder(oldContent, newContent, region);
if (ports[0] instanceof JComponent) {
((JComponent) ports[0]).setMinimumSize(new Dimension(0, 0));
}
if (ports[1] instanceof JComponent) {
((JComponent) ports[1]).setMinimumSize(new Dimension(0, 0));
}
if (ports[0] instanceof Component)
newDockedContent.setLeftComponent((Component) ports[0]);
if (ports[1] instanceof Component)
newDockedContent.setRightComponent((Component) ports[1]);
// set the split in the middle
double ratio = .5;
if (docked instanceof Dockable
&& newDockedContent instanceof DockingSplitPane) {
Float siblingRatio = ((Dockable) docked).getDockingProperties()
.getSiblingSize(region);
if (siblingRatio != null) {
ratio = siblingRatio.doubleValue();
}
((DockingSplitPane) newDockedContent).setInitialDividerRatio(ratio);
}
newDockedContent.setDividerLocation(ratio);
// now set the wrapper panel as the currently docked component
setComponent(newDockedContent);
// if we're currently showing, then we can exit now
if (isShowing())
return true;
// otherwise, we have unrealized components whose sizes cannot be
// determined until after we're visible. cache the desired size
// values now for use later during rendering.
double proportion = strategy.getDividerProportion(this,
newDockedContent);
SwingUtility.putClientProperty((Component) oldContent,
DefaultDockingStrategy.PREFERRED_PROPORTION, new Float(
proportion));
SwingUtility.putClientProperty((Component) newContent,
DefaultDockingStrategy.PREFERRED_PROPORTION, new Float(
1f - proportion));
return true;
}
/**
* Returns the child {@code Component} currently embedded within with
* {@code DockingPort}. If the {@code DockingPort} is empty, then this
* method returns a {@code null} reference. If there is a single
* {@code Dockable} docked within it with no tabbed layout, then the
* {@code Component} for that {@code Dockable} is returned per its
* {@code getComponent()} method. If there is a tabbed layout present, then
* a {@code JTabbedPane} is returned. If there is a split layout present,
* then a {@code JSplitPane} is returned.
*
* @see DockingPort#getDockedComponent()
*/
public Component getDockedComponent() {
return dockedComponent;
}
// private JSplitPane getDockedSplitPane() {
// Component docked = getDockedComponent();
// return docked instanceof JSplitPane? (JSplitPane)docked: null;
// }
/**
* Returns a {@code String} identifier that is unique to
* {@code DockingPorts} within a JVM instance, but persistent across JVM
* instances. This is used for configuration mangement, allowing the JVM to
* recognize a {@code DockingPort} instance within an application instance,
* persist the ID, and recall it in later application instances. The ID
* should be unique within an appliation instance so that there are no
* collisions with other {@code DockingPort} instances, but it should also
* be consistent from JVM to JVM so that the association between a
* {@code DockingPort} instance and its ID can be remembered from session to
* session.
* <p>
* The value returned by this method will come from the most recent call to
* {@code setPersistentId(String id)}. If
* {@code setPersistentId(String id)} was invoked with a {@code null}
* argument, then the {@code String} verion of this {@code DockingPort's}
* hash code is used. Therefore, this method will never return a
* {@code null} reference.
*
* @return the persistent ID for this {@code DockingPort}
* @see DockingPort#getPersistentId()
* @see #setPersistentId(String)
* @see DockingManager#getDockingPort(String)
*/
public String getPersistentId() {
return persistentId;
}
/**
* Sets the persisent ID to be used for this {@code DockingPort}. If
* {@code id} is {@code null}, then the {@code String} value of this
* {@code DockingPort's} hash code is used.
* <p>
* {@code DockingPorts} are tracked by persistent ID within
* {@code DockingManager}. Whenever this method is called, the
* {@code DockingManager's} tracking mechanism is automatically upated for
* this {@code DockingPort}.
*
* @param id
* the persistent ID to be used for this {@code DockingPort}
* @see #getPersistentId()
* @see DockingManager#getDockingPort(String)
* @see DockingPortTracker#updateIndex(DockingPort)
*/
public void setPersistentId(String id) {
if (id == null) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -