⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 defaultdockingstrategy.java

📁 定要上载质量高而定要上载质量高而定要上载质量高而定要上载质量高而定要上载质量高而
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
/*
 * Created on Mar 14, 2005
 */
package org.flexdock.docking.defaults;

import java.awt.Component;
import java.awt.Container;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Map;

import javax.swing.JSplitPane;
import javax.swing.SwingUtilities;
import javax.swing.plaf.basic.BasicSplitPaneDivider;
import javax.swing.plaf.basic.BasicSplitPaneUI;

import org.flexdock.docking.Dockable;
import org.flexdock.docking.DockingConstants;
import org.flexdock.docking.DockingManager;
import org.flexdock.docking.DockingPort;
import org.flexdock.docking.DockingStrategy;
import org.flexdock.docking.RegionChecker;
import org.flexdock.docking.drag.DragManager;
import org.flexdock.docking.drag.DragOperation;
import org.flexdock.docking.event.DockingEvent;
import org.flexdock.docking.floating.frames.DockingFrame;
import org.flexdock.docking.floating.frames.FloatingDockingPort;
import org.flexdock.docking.props.DockablePropertySet;
import org.flexdock.docking.state.FloatManager;
import org.flexdock.event.EventManager;
import org.flexdock.util.DockingUtility;
import org.flexdock.util.RootWindow;
import org.flexdock.util.SwingUtility;

/**
 * @author Christopher Butler
 */
public class DefaultDockingStrategy implements DockingStrategy,
        DockingConstants {
    public static final String PREFERRED_PROPORTION = "DefaultDockingStrategy.PREFERRED_PROPORTION";
	
    /**
     * Returns the specified {@code Dockable's} sibling {@code Dockable} within
     * the current docking layout. This method checks the parent
     * {@code DockingPort} of a given {@code Dockable} to see if it is split
     * equally with another {@code Dockable}. If so, the immediate sibling
     * {@code Dockable} is returned. If there are more than two
     * {@code Dockables} within the split layout, then the closest sibling
     * region is determined and this method dispatches to
     * {@code getSibling(Dockable dockable, String region)}.
     * <p>
     * If the specified {@code Dockable} is {@code null}, or there are no
     * siblings available in the docking layout, then this methdo returns a
     * {@code null} reference. If the specified {@code Dockable} is not
     * currently docked within a {@code DockingPort}, then this method returns
     * a {@code null} reference.
     * 
     * @param dockable
     *            the {@code Dockable} whose sibling is to be returned
     * @return the sibling of the specified {@code Dockable} within the current
     *         docking layout.
     * @see Dockable#getDockingPort()
     * @see #getSibling(Dockable, String)
     */
    public static Dockable getSibling(Dockable dockable) {
        if (dockable == null)
            return null;

        DockingPort port = dockable.getDockingPort();
        String startRegion = findRegion(dockable.getComponent());
        String region = DockingUtility.flipRegion(startRegion);
        Dockable sibling = findDockable(port, dockable.getComponent(), region,
                startRegion);

        return sibling;
    }
	
    /**
     * Returns the sibling {@code Dockable} relative to the specified
     * {@code Dockable's} supplied region in the current docking layout. If
     * {@code dockable} is {@code null} or {@code region} is either invalid or
     * equal to {@code CENTER_REGION}, then this method returns a {@code null}
     * reference.
     * <p>
     * If the specified {@code Dockable} is in a {@code DockingPort} that
     * equally splits the layout between two {@code Dockables} in a fashion that
     * matches up with the specified region, then the immediate sibling
     * {@code Dockable} is returned. Otherwise, a fuzzy search is performed
     * throughout the docking layout for a {@code Dockable} that "looks like" it
     * is docked to the supplied region of the specified {@code Dockable} from a
     * visual standpoint.
     * <p>
     * For instance, a docking layout may consist of four quadrants <i>Dockable1</i>
     * (top-left), <i>Dockable2</i> (top-right), <i>Dockable3</i>
     * (bottom-left) and <i>Dockable4</i> (bottom-right). The layout is built
     * by docking <i>Dockable2>/i> to the {@code EAST_REGION} of <i>Dockable1</i>,
     * <i>Dockable3</i> to the {@code SOUTH_REGION} of <i>Dockable1</i>, and
     * <i>Dockable4</i> to the {@code SOUTH_REGION} of <i>Dockable2</i>.
     * Within this layout, <i>Dockable1</i> and <i>Dockable3</i> are immediate
     * siblings, as are <i>Dockable2</i> and <i>Dockable4</i>. Thus,
     * requesting sibling NORTH_REGION of <i>Dockable3</i> will easily yield
     * <i>Dockable1</i>. However, <i>Dockable3</i> has no immediate
     * {@code EAST_REGION} sibling. In this case, a fuzzy search through the
     * layout is performed to determine the visual sibling, and this method
     * returns <i>Dockable4</i>. Likewise, this method will return a
     * {@code null} reference for the {@code WEST_REGION} sibling of
     * <i>Dockable3}, since there are no {@code Dockables} in the visual layout
     * to the west of this {@code Dockable}.
     * 
     * @param dockable
     *            the {@code Dockable} whose sibling is to be returned
     * @param region
     *            the region of the specified {@code Dockable} whose visual
     *            sibling is to be returned
     * @return the {@code Dockable} in the supplied region relative to the
     *         specified {@code Dockable}
     */
    public static Dockable getSibling(Dockable dockable, String region) {
        if (dockable == null || !DockingManager.isValidDockingRegion(region)
                || CENTER_REGION.equals(region))
            return null;

        DockingPort port = dockable.getDockingPort();
        String startRegion = findRegion(dockable.getComponent());
        Dockable sibling = findDockable(port, dockable.getComponent(), region,
                startRegion);

        return sibling;
    }
	
    private static Dockable findDockable(DockingPort port, Component self,
            String region, String startRegion) {
        if (port == null)
            return null;

        Component docked = port.getDockedComponent();
        // if we're not a split port, then there is no concept of 'outer
        // regions'.
        // jump up a level to find the parent split port
        if (!(docked instanceof JSplitPane)) {
            DockingPort superPort = DockingManager
                    .getDockingPort((Component) port);
            return findDockable(superPort, self, region, startRegion);
        }

        Component sibling = port.getComponent(region);
        if (sibling == self) {
            if (!(self instanceof JSplitPane)) {
                DockingPort superPort = DockingManager
                        .getDockingPort((Component) port);
                return findDockable(superPort, self, region, startRegion);
            }
            return null;
        }

        if (sibling instanceof JSplitPane) {
            // go one level deeper
            DockingPort subPort = DockingManager.getDockingPort(sibling);
            Component other = port.getComponent(DockingUtility
                    .flipRegion(region));
            String subRegion = findSubRegion((JSplitPane) sibling, other,
                    region, startRegion);
            return findDockable(subPort, self, subRegion, startRegion);
        }

        // if we have no direct sibling in the specified region, the jump
        // up a level.
        if (sibling == null) {
            DockingPort superPort = DockingManager
                    .getDockingPort((Component) port);
            self = port.getDockedComponent();
            return findDockable(superPort, self, region, startRegion);
        }

        return DockingManager.getDockable(sibling);
    }
	
    private static String findSubRegion(JSplitPane split, Component other,
            String targetRegion, String baseRegion) {
        String region = DockingUtility.translateRegionAxis(split, targetRegion);
        if (!(other instanceof JSplitPane))
            return region;

        boolean translated = !targetRegion.equals(region);
        if (translated && !DockingUtility.isAxisEquivalent(region, baseRegion)) {
            region = DockingUtility.flipRegion(region);
        }

        return region;
    }
	
    /**
     * Returns the docking region within the current split docking layout
     * containing the specified {@code Component}. If {@code comp} is
     * {@code null}, then a {@code null} reference is returned. If {@code comp}
     * is not in a split layout, then {@code CENTER_REGION} is returned.
     * <p>
     * This method resolves the associated {@code Dockable} and
     * {@code DockingPort} for the specified {@code Component} and backtracks
     * through the docking layout to find a split layout. If a split layout is
     * found, then the region retured by this method is calculated relative to
     * its sibling in the layout.
     * 
     * @param comp
     *            the {@code Component} whose region is to be returned
     * @return the region of the current split layout containing the specified
     *         {@code Dockable}
     */
    public static String findRegion(Component comp) {
        if (comp == null)
            return null;

        DockingPort port = DockingManager.getDockingPort(comp);
        Component docked = port.getDockedComponent();

        if (!(docked instanceof JSplitPane)) {
            // we didn't find a split pane, to check the grandparent dockingport
            DockingPort superPort = DockingManager
                    .getDockingPort((Component) port);
            // if there was no grandparent DockingPort, then we're stuck with
            // the docked
            // component we already found. this can happen on the root
            // dockingport.
            docked = superPort == null ? docked : superPort
                    .getDockedComponent();
        }

        if (!(docked instanceof JSplitPane))
            return CENTER_REGION;

        JSplitPane split = (JSplitPane) docked;
        boolean horiz = split.getOrientation() == JSplitPane.HORIZONTAL_SPLIT;
        Component left = split.getLeftComponent();
        if (left == port) {
            return horiz ? WEST_REGION : NORTH_REGION;
        }
        return horiz ? EAST_REGION : SOUTH_REGION;

    }
	
    /**
     * Docks the specified {@code Dockable} into the supplied {@code region} of
     * the specified {@code DockingPort}. This method is meant for programmatic
     * docking, as opposed to realtime, event-based docking operations. As such,
     * it defers processing to
     * {@code dock(Dockable dockable, DockingPort port, String region, DragOperation token)},
     * passing a {@code null} argument for the {@code DragOperation} parameter.
     * This implies that there is no event-based drag operation currently in
     * progress to control the semantics of the docking operation, only that an
     * attempt should be made to dock the specified {@code Dockable} into the
     * specified {@code DockingPort}.
     * <p>
     * This method will return {@code false} if {@code dockable} or {@code port}
     * are {@code null}, or if {@code region} is not a valid region according
     * to the specified {@code DockingPort}. If a {@code Dockable} is currently
     * docked within the specified {@code DockingPort}, then that
     * {@code Dockable's} territorial properties are also checked and this
     * method may return {@code false} if the territory is blocked. Finally,
     * this method will return {@code false} if the specified {@code Dockable}
     * is already docked within the supplied region of the specified
     * <code.DockingPort}.
     * 
     * @param dockable
     *            the {@code Dockable} we wish to dock
     * @param port
     *            the {@code DockingPort} into which we wish to dock
     * @param region
     *            the region of the specified {@code DockingPort} into which we
     *            wish to dock.
     * @return {@code true} if the docking operation was successful,
     *         {@code false}. otherwise.
     * @see #dock(Dockable, DockingPort, String, DragOperation)
     * @see Dockable#getDockingProperties()
     * @see DockablePropertySet#isTerritoryBlocked(String)
     */
    public boolean dock(Dockable dockable, DockingPort port, String region) {
        return dock(dockable, port, region, null);
    }

    /**
     * Docks the specified {@code Dockable} into the supplied {@code region} of
     * the specified {@code DockingPort}. This method is meant for realtime,
     * event-based docking based on an in-progress drag operation. It is not
     * recommended for developers to call this method programmatically, except
     * to pass in a {@code null} {@code DragOperation} argument. *
     * <p>
     * The {@code DragOperation} parameter, if present, will control the
     * semantics of the docking operation based upon current mouse position,
     * drag threshold, and a customizable drag context {@code Map}. For
     * instance, the {@code DragOperation} may contain information regarding the
     * {@code Dockable} over which the mouse is currently hovered, whether the
     * user is attempting to drag a {@code Dockable} outside the bounds of any
     * existing windows (perhaps in an attempt to float the {@code Dockable}),
     * or whether the current distance offset from the original drag point
     * sufficiently warrants a valid docking operation.
     * <p>
     * If the {@code DragOperation} is {@code null}, then this method will
     * attempt to programmatically dock the specified {@code Dockable} into the
     * supplied {@code region} of the specified {@code DockingPort} without
     * regard to external event-based criteria. This is in accordance with the
     * behavior specified by
     * {@code dock(Dockable dockable, DockingPort port, String region)}.
     * 
     * This method will return {@code false} if {@code dockable} or {@code port}
     * are {@code null}, or if {@code region} is not a valid region according
     * to the specified {@code DockingPort}. If a {@code Dockable} is currently
     * docked within the specified {@code DockingPort}, then that
     * {@code Dockable's} territorial properties are also checked and this
     * method may return {@code false} if the territory is blocked. If a
     * {@code DragOperation} is present, then this method will return
     * {@code false} if the required drag threshold has not been exceeded.
     * Finally, this method will return {@code false} if the specified
     * {@code Dockable} is already docked within the supplied region of the
     * specified <code.DockingPort}.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -