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

📄 defaultdockingport.java

📁 定要上载质量高而定要上载质量高而定要上载质量高而定要上载质量高而定要上载质量高而
💻 JAVA
📖 第 1 页 / 共 5 页
字号:
/*
 * Copyright (c) 2004 Christopher M Butler
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package org.flexdock.docking.defaults;

import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.LayoutManager2;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.WeakHashMap;

import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;

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.activation.ActiveDockableTracker;
import org.flexdock.docking.event.DockingEvent;
import org.flexdock.docking.event.DockingListener;
import org.flexdock.docking.event.DockingMonitor;
import org.flexdock.docking.event.TabbedDragListener;
import org.flexdock.docking.event.hierarchy.DockingPortTracker;
import org.flexdock.docking.props.DockingPortPropertySet;
import org.flexdock.docking.props.PropertyChangeListenerFactory;
import org.flexdock.docking.props.PropertyManager;
import org.flexdock.docking.state.LayoutNode;
import org.flexdock.docking.state.tree.DockableNode;
import org.flexdock.docking.state.tree.DockingPortNode;
import org.flexdock.docking.state.tree.SplitNode;
import org.flexdock.util.DockingUtility;
import org.flexdock.util.LookAndFeelSettings;
import org.flexdock.util.SwingUtility;
import org.flexdock.util.UUID;
import org.flexdock.util.Utilities;

/**
 * This is a {@code Container} that implements the {@code DockingPort}
 * interface. It provides a default implementation of {@code DockingPort} to
 * allow ease of development within docking-enabled applications.
 * <p>
 * The {@code DefaultDockingPort} handles docking in one of three ways. If the
 * port is empty, then all incoming {@code Dockables} are docked to the CENTER
 * region. If the port is not empty, then all incoming {@code Dockables} docked
 * to the CENTER region are embedded within a {@code JTabbedPane}. All incoming
 * {@code Dockables} docked to an outer region (NORTH, SOUTH, EAST, and WEST) of
 * a non-empty port are placed into a split layout using a {@code JSplitPane}.
 * <p>
 * For centrally docked {@code Components}, the immediate child of the
 * {@code DefaultDockingPort} may or may not be a {@code JTabbedPane}. If
 * {@code isSingleTabAllowed()} returns {@code true} for the current
 * {@code DefaultDockingPort}, then the immediate child returned by
 * {@code getDockedComponent()} will return a {@code JTabbedPane} instance even
 * if there is only one {@code Dockable} embedded within the port. If there is a
 * single {@code Dockable} in the port, but {@code isSingleTabAllowed()} returns
 * {@code false}, then {@code getDockedComponent()} will return the
 * {@code Component} that backs the currently docked {@code Dockable}, returned
 * by the {@code Dockable's} {@code getComponent()} method.
 * {@code isSingleTabAllowed()} is a scoped property that may apply to this
 * port, all ports across the JVM, or all ports within a user defined scope.
 * {@code getDockedComponent()} will return a {@code JTabbedPane} at all times
 * if there is more than one centrally docked {@code Dockable} within the port,
 * and all docked {@code Components} will reside within the tabbed pane.
 * <p>
 * Components that are docked in the NORTH, SOUTH, EAST, or WEST regions are
 * placed in a {@code JSplitPane} splitting the layout of the
 * {@code DockingPort} between child components. Each region of the
 * {@code JSplitPane} contains a new {@code DefaultDockingPort}, which, in
 * turn, contains the docked components. In this situation,
 * {@code getDockedComponent()} will return a {@code JSplitPane} reference.
 * <p>
 * A key concept that drives the {@code DefaultDockingPort}, then, is the
 * notion that this {@code DockingPort} implementation may only ever have one
 * single child component, which may or may not be a wrapper for other child
 * components. Because {@code JSplitPane} contains child
 * {@code DefaultDockingPorts}, each of those {@code DefaultDockingPorts} is
 * available for further sub-docking operations.
 * <p>
 * Since a {@code DefaultDockingPort} may only contain one child component,
 * there is a container hierarchy to manage tabbed interfaces, split layouts,
 * and sub-docking. As components are removed from this hierarchy, the hierarchy
 * itself must be reevaluated. Removing a component from a child
 * {@code DefaultDockingPort} within a {@code JSplitPane} renders the child
 * {@code DefaultDockingPort} unnecessary, which, in turn, renders the notion of
 * splitting the layout with a {@code JSplitPane} unnecessary (since there are
 * no longer two components to split the layout between). Likewise, removing a
 * child component from a {@code JTabbedPane} such that there is only one child
 * left within the {@code JTabbedPane} removes the need for a tabbed interface
 * to begin with.
 * <p>
 * When the {@code DockingManager} removes a component from a
 * {@code DockingPort} via {@code DockingManager.undock(Dockable dockable)} it
 * uses a call to {@code undock()} on the current {@code DockingPort}.
 * {@code undock()} automatically handles the reevaluation of the container
 * hierarchy to keep wrapper-container usage at a minimum. Since
 * {@code DockingManager} makes this callback automatic, developers normally
 * will not need to call this method explicitly. However, when removing a
 * component from a {@code DefaultDockingPort} using application code,
 * developers should keep in mind to use {@code undock()} instead of
 * {@code remove()}.
 * 
 * Border management after docking and undocking operations are accomplished
 * using a {@code BorderManager}. {@code setBorderManager()} may be used to set
 * the border manager instance and customize border management.
 * 
 * @author Christopher Butler
 * 
 */
public class DefaultDockingPort extends JPanel implements DockingPort,
        DockingConstants {
    protected class PortLayout implements LayoutManager2, Serializable {
        /**
         * Returns the amount of space the layout would like to have.
         * 
         * @param parent
         *            the Container for which this layout manager is being used
         * @return a Dimension object containing the layout's preferred size
         */
        public Dimension preferredLayoutSize(Container parent) {
            Dimension dd;
            Insets i = getInsets();

            if (dockedComponent != null) {
                dd = dockedComponent.getPreferredSize();
            } else {
                dd = parent.getSize();
            }

            return new Dimension(dd.width + i.left + i.right, dd.height + i.top
                    + i.bottom);
        }

        /**
         * Returns the minimum amount of space the layout needs.
         * 
         * @param parent
         *            the Container for which this layout manager is being used
         * @return a Dimension object containing the layout's minimum size
         */
        public Dimension minimumLayoutSize(Container parent) {
            Dimension dd;
            Insets i = getInsets();

            if (dockedComponent != null) {
                dd = dockedComponent.getMinimumSize();
            } else {
                dd = parent.getSize();
            }

            return new Dimension(dd.width + i.left + i.right, dd.height + i.top
                    + i.bottom);
        }

        /**
         * Returns the maximum amount of space the layout can use.
         * 
         * @param target
         *            the Container for which this layout manager is being used
         * @return a Dimension object containing the layout's maximum size
         */
        public Dimension maximumLayoutSize(Container target) {
            Dimension dd;
            Insets i = getInsets();

            if (dockedComponent != null) {
                dd = dockedComponent.getMaximumSize();
            } else {
                // This is silly, but should stop an overflow error
                dd = new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE - i.top
                        - i.bottom);
            }

            return new Dimension(dd.width + i.left + i.right, dd.height + i.top
                    + i.bottom);
        }

        /**
         * Instructs the layout manager to perform the layout for the specified
         * container.
         * 
         * @param parent
         *            the Container for which this layout manager is being used
         */
        public void layoutContainer(Container parent) {
            Rectangle b = getBounds();
            Insets i = getInsets();
            int w = b.width - i.right - i.left;
            int h = b.height - i.top - i.bottom;

            if (dockedComponent != null) {
                dockedComponent.setBounds(i.left, i.top, w, h);
            }
        }

        public void addLayoutComponent(String name, Component comp) {
        }

        public void removeLayoutComponent(Component comp) {
        }

        public void addLayoutComponent(Component comp, Object constraints) {
        }

        public float getLayoutAlignmentX(Container target) {
            return 0.0f;
        }

        public float getLayoutAlignmentY(Container target) {
            return 0.0f;
        }

        public void invalidateLayout(Container target) {
        }
    }

    private static final WeakHashMap COMPONENT_TITLES = new WeakHashMap();

    protected ArrayList dockingListeners;

    private Component dockedComponent;

    private BorderManager borderManager;

    private String persistentId;

    private boolean tabsAsDragSource;

    private boolean rootPort;

    private BufferedImage dragImage;

    static {
        // setup PropertyChangeListenerFactory to respond to
        // DefaultDockingPort-specific
        // events
        PropertyChangeListenerFactory
                .addFactory(new DockablePropertyChangeHandler.Factory());
    }

    /**
     * Creates a new {@code DefaultDockingPort} with a persistent ID equal to
     * the {@code String} value of this a random UUID.
     * 
     * @see org.flexdock.util.UUID
     */
    public DefaultDockingPort() {
        this(UUID.randomUUID().toString());
    }

    /**
     * Creates a new {@code DefaultDockingPort} with the specified persistent
     * ID. If {@code id} is {@code null}, then the {@code String} value of this
     * {@code Object's} hash code is used. The persistent ID will be the same
     * value returned by invoking {@code getPersistentId()} for this
     * {@code DefaultDockingPort}.
     * 
     * @param id
     *            the persistent ID for the new {@code DefaultDockingPort}
     *            instance.
     */
    public DefaultDockingPort(String id) {
        setPersistentId(id);
        dockingListeners = new ArrayList(2);
        addDockingListener(this);

⌨️ 快捷键说明

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