📄 defaultdockingstrategy.java
字号:
/**
* Returns a new {@code DefaultDockingPort} with characteristics similar to
* the specified base {@code DockingPort}. If the base {@code DockingPort}
* is a {@code DefaultDockingPort}, then the returned {@code DockingPort}
* will share the base {@code DockingPort's} border manager and tabbed
* drag-source flag. The returned {@code DockingPort's} {@code isRoot()}
* method will return {@code false}.
*
* @param base
* the {@code DockingPort} off of which to base the returned
* {@code DockingPort}
* @return a new {@code DefaultDockingPort} with characteristics similar to
* the specified base {@code DockingPort}.
* @see DefaultDockingPort#getBorderManager()
* @see DefaultDockingPort#setBorderManager(BorderManager)
* @see DefaultDockingPort#isTabsAsDragSource()
* @see DefaultDockingPort#setTabsAsDragSource(boolean)
* @see DefaultDockingPort#setRoot(boolean)
*/
public DockingPort createDockingPort(DockingPort base) {
DockingPort port = createDockingPortImpl(base);
if (port instanceof DefaultDockingPort
&& base instanceof DefaultDockingPort) {
DefaultDockingPort newPort = (DefaultDockingPort) port;
DefaultDockingPort ddp = (DefaultDockingPort) base;
newPort.setBorderManager(ddp.getBorderManager());
newPort.setTabsAsDragSource(ddp.isTabsAsDragSource());
newPort.setRoot(false);
}
return port;
}
protected DockingPort createDockingPortImpl(DockingPort base) {
return new DefaultDockingPort();
}
/**
* Returns a new {@code DockingSplitPane} based on the specified
* {@code DockingPort}. and region. Creation of the
* {@code DockingSplitPane} is deferred to an internal protected method to
* allow for overriding by subclasses. A client property is set on the
* returned split pane with the key DockingConstants.REGION to indicate the
* creation region of the split pane for non-{@code DockingSplitPanes}
* returned by overriding subclasses.
* <p>
* This method determines the "elder" component of the split pane by
* checking whether the new creation region is in the TOP or LEFT
* (NORTH_REGION or WEST_REGION). If the creation region, representing where
* the new {@code Dockable} will be docked, is <b>not</b> in the top or
* left, then the elder {@code Component} in the split pane must be. This
* information is used to initialize the resize weight of the split pane,
* setting resize weight to {@code 1} if the elder is in the top or left of
* the split pane and {@code 0} if not. This gives the elder
* {@code Component} in the resulting split pane priority in the layout with
* resizing the split pane.
* <p>
* If the creation region is {@code NORTH_REGION} or {@code SOUTH_REGION},
* the returned split pane is initialized with a {@code VERTICAL_SPLIT}
* orientation; otherwise a {@code HORIZONTAL_SPLIT} orientation is used.
* <p>
* Before returning, the border is removed from the split pane, its divider
* size is set to 3, and if possible the border is removed from the split
* pane divider. This is to avoid an excessive compound border effect for
* embedded {@code Components} within the split pane that may have their own
* borders.
*
* @param base
* the {@code DockingPort} off of which the returned
* {@code JSplitPane} will be based.
* @param region
* the region within the base {@code DockingPort} used to
* determine the orientation of the returned {@code JSplitPane}.
* @return a new {@code DockingSplitPane} based on the specified
* {@code DockingPort}. and region.
* @see DockingSplitPane#DockingSplitPane(DockingPort, String)
* @see #createSplitPaneImpl(DockingPort, String)
* @see JSplitPane#setResizeWeight(double)
*/
public JSplitPane createSplitPane(DockingPort base, String region) {
JSplitPane split = createSplitPaneImpl(base, region);
// mark the creation region on the split pane
SwingUtility.putClientProperty(split, DockingConstants.REGION, region);
// the creation region represents the "new" region, not the elder
// region.
// so if the creation region is NOT in the top left, then the elder
// region is.
boolean elderInTopLeft = !DockingUtility.isRegionTopLeft(region);
int resizeWeight = elderInTopLeft ? 1 : 0;
// set the resize weight based on the location of the elder component
split.setResizeWeight(resizeWeight);
// determine the orientation
int orientation = JSplitPane.HORIZONTAL_SPLIT;
if (NORTH_REGION.equals(region) || SOUTH_REGION.equals(region))
orientation = JSplitPane.VERTICAL_SPLIT;
split.setOrientation(orientation);
// remove the border from the split pane
split.setBorder(null);
// set the divider size for a more reasonable, less bulky look
split.setDividerSize(3);
split.setOneTouchExpandable(false); //zw
// check the UI. If we can't work with the UI any further, then
// exit here.
if (!(split.getUI() instanceof BasicSplitPaneUI))
return split;
// grab the divider from the UI and remove the border from it
final BasicSplitPaneDivider divider = ((BasicSplitPaneUI) split.getUI())
.getDivider();
if (divider != null) {
divider.setBorder(null);
divider.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (SwingUtilities.isLeftMouseButton(e)
&& e.getClickCount() == 2) {
// TODO should be not override, but placed logic here
((JSplitPane) divider.getParent())
.resetToPreferredSizes();
}
}
});
}
return split;
}
protected JSplitPane createSplitPaneImpl(DockingPort base, String region) {
return new DockingSplitPane(base, region);
}
/**
* Returns the initial divider location to be used by the specified
* {@code JSplitPane} when it is embedded within the specified
* {@code DockingPort}. It is assumed that the {@code JSplitPane} parameter
* is embedded within the specified {@code DockingPort}, is validated,
* visible, and its dimensions are non-zero.
* <p>
* This method gets the "size" of the specified {@code DockingPort} based on
* the orientation of the split pane (<i>width</i> for horizontal split,
* <i>height</i> for vertical split) minus the {@code DockingPort's}
* insets. It then dispatches to
* {@code getDividerProportion(DockingPort port, JSplitPane splitPane)} to
* determine the preferred proportion of the split pane divider. The
* returned value for this method is the product of the {@code DockingPort}
* size and the split proportion.
* <p>
* If either {@code port} or {@code splitPane} parameters are {@code null},
* then this method returns {@code 0}.
*
* @param port
* the {@code DockingPort} that contains the specified
* {@code JSplitPane}.
* @param splitPane
* the {@code JSplitPane} whose initial divider location is to be
* determined.
* @return the desired divider location of the supplied {@code JSplitPane}.
* @see DockingStrategy#getInitialDividerLocation(DockingPort, JSplitPane)
* @see #getDividerProportion(DockingPort, JSplitPane)
*/
public int getInitialDividerLocation(DockingPort port, JSplitPane splitPane) {
if (port == null || splitPane == null)
return 0;
Container dockingPort = (Container) port;
Insets in = dockingPort.getInsets();
boolean vert = splitPane.getOrientation() == JSplitPane.VERTICAL_SPLIT;
int inset = vert ? in.top + in.bottom : in.left + in.right;
// get the dimensions of the DockingPort, minus the insets
int portSize = vert ? dockingPort.getHeight() : dockingPort.getWidth();
portSize -= inset;
// get the divider proportion for the split pane and multiply by the
// port size
double proportion = getDividerProportion(port, splitPane);
if (proportion < 0 || proportion > 1)
proportion = 0.5d;
return (int) (portSize * proportion);
}
/**
* Returns the desired divider proportion of the specified
* {@code JSplitPane} after rendering. This method assumes that the
* {@code JSplitPane} parameter is, or will be embedded within the specified
* {@code DockingPort}. This method does <b>not</b> assume that the
* {@code JSplitPane} has been validated and that it's current dimensions
* are non-zero.
* <p>
* If either {@code port} or {@code splitPane} parameters are {@code null},
* then this method returns the default value of
* {@code RegionChecker.DEFAULT_SIBLING_SIZE}. Otherwise the "elder"
* component within the {@code JSplitPane} is determined to see if it is
* contained within a sub-{@code DockingPort}. If the "elder"
* {@code Component} cannot be determined, or it is not contained within a
* sub-{@code DockingPort}, then the default value of
* {@code RegionChecker.DEFAULT_SIBLING_SIZE} is returned.
* <p>
* If the "elder" {@code Component} is successfully resolved inside a sub-{@code DockingPort},
* then a check is done on the sub-port for the client property
* {@code DefaultDockingStrategy.PREFERRED_PROPORTION}. If this value is
* found, then the primitive float version of it is returned.
* <p>
* Failing these checks, the {@code Dockable} is resolved for the "elder"
* {@code Component} in the specified {@code JSplitPane} via
* {@code DockingManager.getDockable(Component comp)}. If no
* {@code Dockable} can be found, then
* {@code RegionChecker.DEFAULT_SIBLING_SIZE} is returned.
* <p>
* Otherwise, the {@code DockingPortPropertySet} is retrieved from the
* specified {@code DockingPort} and its {@code getRegionChecker()} method
* is called. {@code getSiblingSize(Component c, String region)} is invoked
* on the returned {@code RegionChecker} passing the "elder"
* {@code Component} in the split pane and the creation region resolved for
* the specified {@code JSplitPane}. This resolves the preferred sibling
* size for the elder {@code Dockable} component. If the elder
* {@code Component} is in the top/left of the split pane, then
* {@code 1F-prefSize} is returned. Otherwise, the preferred sibling size is
* returned.
*
* @param port
* the {@code DockingPort} that contains, or will contain the
* specified {@code JSplitPane}.
* @param splitPane
* the {@code JSplitPane} whose initial divider location is to be
* determined.
* @return the desired divider proportion of the supplied {@code JSplitPane}.
* @see RegionChecker#DEFAULT_SIBLING_SIZE
* @see #PREFERRED_PROPORTION
* @see DockingManager#getDockable(Component)
* @see RegionChecker#getSiblingSize(Component, String)
*/
public double getDividerProportion(DockingPort port, JSplitPane splitPane) {
if (port == null || splitPane == null)
return DockingManager.getDefaultSiblingSize();
Component elder = getElderComponent(splitPane);
if (elder == null)
return DockingManager.getDefaultSiblingSize();
Float prefProp = getPreferredProportion(splitPane, elder);
if (prefProp != null)
return prefProp.doubleValue();
if (elder instanceof DockingSplitPane) {
elder = ((DockingSplitPane) elder).getElderComponent();
}
Dockable dockable = DockingManager.getDockable(elder);
if (dockable != null) {
// DockingSplitPane splitter = (DockingSplitPane)splitPane;
RegionChecker rc = port.getDockingProperties().getRegionChecker();
float prefSize = rc.getSiblingSize(dockable.getComponent(),
getCreationRegion(splitPane));
return isElderTopLeft(splitPane) ? 1f - prefSize : prefSize;
// return prefSize;
}
return DockingManager.getDefaultSiblingSize();
}
protected String getCreationRegion(JSplitPane splitPane) {
if (splitPane instanceof DockingSplitPane)
return ((DockingSplitPane) splitPane).getRegion();
return (String) SwingUtility.getClientProperty(splitPane,
DockingConstants.REGION);
}
protected boolean isElderTopLeft(JSplitPane splitPane) {
if (splitPane instanceof DockingSplitPane)
return ((DockingSplitPane) splitPane).isElderTopLeft();
String region = getCreationRegion(splitPane);
// creation region represents the "new" region, not the "elder" region.
// so if the "new" region is NOT the topLeft, then the "elder" is.
return !DockingUtility.isRegionTopLeft(region);
}
protected Float getPreferredProportion(JSplitPane splitPane,
Component controller) {
// 'controller' is inside a dockingPort. re-reference to the parent
// dockingPort.
Container controllerPort = controller.getParent();
return getPreferredProportion(controllerPort);
}
protected Component getElderComponent(JSplitPane splitPane) {
if (splitPane instanceof DockingSplitPane)
return ((DockingSplitPane) splitPane).getElderComponent();
boolean inTopLeft = isElderTopLeft(splitPane);
Component comp = inTopLeft ? splitPane.getLeftComponent() : splitPane
.getRightComponent();
if (comp instanceof DockingPort)
comp = ((DockingPort) comp).getDockedComponent();
return comp;
}
protected static Float getPreferredProportion(Component c) {
return c == null ? null : (Float) SwingUtility.getClientProperty(c,
PREFERRED_PROPORTION);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -