📄 dockingmanager.java
字号:
/*
* 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;
import java.awt.Component;
import java.awt.Window;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.io.IOException;
import java.util.EventListener;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.WeakHashMap;
import javax.swing.SwingUtilities;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.flexdock.docking.activation.ActiveDockableListener;
import org.flexdock.docking.adapter.AdapterFactory;
import org.flexdock.docking.adapter.DockingAdapter;
import org.flexdock.docking.defaults.DefaultDockingStrategy;
import org.flexdock.docking.defaults.DockableComponentWrapper;
import org.flexdock.docking.drag.DragManager;
import org.flexdock.docking.drag.effects.DragPreview;
import org.flexdock.docking.drag.effects.EffectsManager;
import org.flexdock.docking.drag.effects.RubberBand;
import org.flexdock.docking.event.DockingEventHandler;
import org.flexdock.docking.event.hierarchy.DockingPortTracker;
import org.flexdock.docking.event.hierarchy.RootDockingPortInfo;
import org.flexdock.docking.floating.policy.FloatPolicyManager;
import org.flexdock.docking.props.DockablePropertySet;
import org.flexdock.docking.props.PropertyManager;
import org.flexdock.docking.state.DockingState;
import org.flexdock.docking.state.FloatManager;
import org.flexdock.docking.state.LayoutManager;
import org.flexdock.docking.state.MinimizationManager;
import org.flexdock.docking.state.PersistenceException;
import org.flexdock.event.EventManager;
import org.flexdock.event.RegistrationEvent;
import org.flexdock.util.ClassMapping;
import org.flexdock.util.DockingUtility;
import org.flexdock.util.ResourceManager;
import org.flexdock.util.RootWindow;
import org.flexdock.util.SwingUtility;
import org.flexdock.util.Utilities;
/**
* This class is used as a public facade into the framework docking system. It
* provides a straightforward public API for managing and manipulating the
* various different subcomponents that make up the docking framework through a
* single class. {@code DockingManager} cannot be instantiated. Rather, its
* methods are accessed statically from within application code and it generally
* defers processing to a set of abstract handlers hidden from the application
* layer.
*
* Among {@code DockingManager's} responsibilities are as follows:
*
* <dl>
* <dt>Maintaining a component repository.</dt>
* <dd> All {@code Dockables} and {@code DockingPorts} are cached within an and
* accessible through and internal registry. </dd>
* <dt>Maintaining framework state.</dt>
* <dd>{@code DockingManager} provides APIs for managing various different
* global framework settings, including application-key, floating support,
* auto-persistence, {@code LayoutManagers}, and {@code MinimizationManagers}.
* </dd>
* <dt>Behavioral auto-configuration.</dt>
* <dd> {@code DockingManager} automatically adds and removes necessary event
* listeners to enable/disable drag-to-dock behavior as components are
* registered and unregistered. </dd>
* <dt>Programmatic access to docking operations.</dt>
* <dd> {@code DockingManager} provides public APIs for programmatically dock,
* undock, minimize, persist, and load {@code Dockables} from storage. </dd>
* </dl>
*
* @author Christopher Butler
*/
public class DockingManager implements DockingConstants {
private static Log log = LogFactory.getLog(DockingManager.class);
public static final String MINIMIZE_MANAGER = "minimize.manager";
public static final String LAYOUT_MANAGER = "layout.manager";
private static final String DEV_PROPS = "org/flexdock/util/dev-props.properties";
private static final String CONFIG_PROPS = "org/flexdock/docking/flexdock-core.properties";
private static final DockingManager SINGLETON = new DockingManager();
private static final HashMap DOCKABLES_BY_ID = new HashMap();
private static final WeakHashMap DOCKABLES_BY_COMPONENT = new WeakHashMap();
private static final ClassMapping DOCKING_STRATEGIES = new ClassMapping(
DefaultDockingStrategy.class, new DefaultDockingStrategy());
// Map(DockingPort -> MaximizedState)
private static final Map maximizedStatesByRootPort = new HashMap();
private static Object persistentIdLock = new Object();
private String defaultLayoutManagerClass;
private String defaultMinimizeManagerClass;
private DockingStrategy defaultDocker;
private LayoutManager layoutManager;
private MinimizationManager minimizeManager;
private DockableFactory dockableFactory;
private AutoPersist autoPersister;
private float defaultSiblingSize;
static {
// call this method to preload any framework resources
// we might need later
init();
}
private static class AutoPersist extends Thread {
private boolean enabled;
public void run() {
store();
}
private synchronized void store() {
try {
if (isEnabled())
storeLayoutModel();
} catch (IOException e) {
e.printStackTrace();
} catch (PersistenceException e) {
e.printStackTrace();
}
}
public synchronized boolean isEnabled() {
return enabled;
}
public synchronized void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}
private static class MaximizedState {
private final Dockable dockable;
private final DockingPort originalPort;
public MaximizedState(Dockable dockable, DockingPort originalDockingPort) {
this.dockable = dockable;
this.originalPort = originalDockingPort;
}
public Dockable getDockable() {
return dockable;
}
public DockingPort getOriginalPort() {
return originalPort;
}
}
private static void init() {
// load the dev system properties
Properties p = ResourceManager.getProperties(DEV_PROPS, true);
if (p != null)
System.getProperties().putAll(p);
// prime the drag manager for use
DragManager.prime();
// ensure our Dockable adapters have been loaded
AdapterFactory.prime();
// make sure dockingEvents are properly intercepted
EventManager.addHandler(new DockingEventHandler());
EventManager.addListener(FloatPolicyManager.getInstance());
Properties config = ResourceManager.getProperties(CONFIG_PROPS, true);
DockingManager mgr = getDockingManager();
// set the minimization manager
mgr.defaultMinimizeManagerClass = config.getProperty(MINIMIZE_MANAGER);
setMinimizeManager(mgr.defaultMinimizeManagerClass);
// set the layout manager
mgr.defaultLayoutManagerClass = config.getProperty(LAYOUT_MANAGER);
setLayoutManager(mgr.defaultLayoutManagerClass);
// setup tracking for the currently active dockable
ActiveDockableListener.prime();
// setup the default sibling size
float siblingSize = Utilities.getFloat(System
.getProperty(RegionChecker.DEFAULT_SIBLING_SIZE_KEY),
RegionChecker.DEFAULT_SIBLING_SIZE);
setDefaultSiblingSize(siblingSize);
// setup auto-persistence
Runtime.getRuntime().addShutdownHook(getDockingManager().autoPersister);
}
private DockingManager() {
defaultDocker = new DefaultDockingStrategy();
autoPersister = new AutoPersist();
}
private static DockingManager getDockingManager() {
return SINGLETON;
}
public static void addDragSource(Dockable dockable, Component dragSrc) {
List sources = dockable == null ? null : dockable.getDragSources();
if (sources == null || dragSrc == null)
return;
if (!sources.contains(dragSrc)) {
updateDragListeners(dockable);
}
}
/**
* Convenience method that removes the specified {@code Dockable} from the
* layout. If the {@code Dockable}is embedded within the main application
* frame or a floating dialog, it is removed from the container hierarchy.
* If the {@code Dockable} is presently minimized, it is removed from the
* current minimization manager. If the {@code Dockable} is already "closed"
* or is {@code null}, no operation is performed. "Closing" a
* {@code Dockable} only removes it from the visual layout. It does not
* remove it from the internal {@code Dockable} registry and all underlying
* {@code DockingState} information remains consistent so that the
* {@code Dockable} may later be restored to its original location within
* the application.
*
* @param dockable
* the {@code Dockable} to be closed.
*/
public static void close(Dockable dockable) {
if (dockable == null)
return;
if (isMaximized(dockable)) {
toggleMaximized(dockable);
}
if (isDocked(dockable)) {
undock(dockable);
} else if (DockingUtility.isMinimized(dockable)) {
getMinimizeManager().close(dockable);
}
}
/**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -