Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Bibliothek - DockingFrames
* Library built on Java/Swing, allows the user to "drag and drop"
* panels containing any Swing-Component the developer likes to add.
*
* Copyright (C) 2007 Benjamin Sigg
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Benjamin Sigg
* [email protected]
* CH - Switzerland
*/
package bibliothek.gui.dock;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.PointerInfo;
import java.awt.Rectangle;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.swing.Icon;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.event.MouseInputAdapter;
import javax.swing.event.MouseInputListener;
import bibliothek.gui.DockController;
import bibliothek.gui.DockStation;
import bibliothek.gui.DockTheme;
import bibliothek.gui.DockUI;
import bibliothek.gui.Dockable;
import bibliothek.gui.dock.action.DefaultDockActionSource;
import bibliothek.gui.dock.action.DockAction;
import bibliothek.gui.dock.action.DockActionSource;
import bibliothek.gui.dock.action.HierarchyDockActionSource;
import bibliothek.gui.dock.action.ListeningDockAction;
import bibliothek.gui.dock.action.LocationHint;
import bibliothek.gui.dock.displayer.DockableDisplayerHints;
import bibliothek.gui.dock.dockable.DockHierarchyObserver;
import bibliothek.gui.dock.dockable.DockableStateListener;
import bibliothek.gui.dock.dockable.DockableStateListenerManager;
import bibliothek.gui.dock.event.DockHierarchyEvent;
import bibliothek.gui.dock.event.DockHierarchyListener;
import bibliothek.gui.dock.event.DockStationAdapter;
import bibliothek.gui.dock.event.DockStationListener;
import bibliothek.gui.dock.event.DockTitleEvent;
import bibliothek.gui.dock.event.DockableListener;
import bibliothek.gui.dock.event.DoubleClickListener;
import bibliothek.gui.dock.event.SplitDockListener;
import bibliothek.gui.dock.layout.DockableProperty;
import bibliothek.gui.dock.security.SecureContainer;
import bibliothek.gui.dock.station.Combiner;
import bibliothek.gui.dock.station.DisplayerCollection;
import bibliothek.gui.dock.station.DisplayerFactory;
import bibliothek.gui.dock.station.DockStationIcon;
import bibliothek.gui.dock.station.DockableDisplayer;
import bibliothek.gui.dock.station.DockableDisplayerListener;
import bibliothek.gui.dock.station.StationBackgroundComponent;
import bibliothek.gui.dock.station.StationChildHandle;
import bibliothek.gui.dock.station.StationPaint;
import bibliothek.gui.dock.station.split.DefaultSplitLayoutManager;
import bibliothek.gui.dock.station.split.DockableSplitDockTree;
import bibliothek.gui.dock.station.split.Leaf;
import bibliothek.gui.dock.station.split.Node;
import bibliothek.gui.dock.station.split.Placeholder;
import bibliothek.gui.dock.station.split.PutInfo;
import bibliothek.gui.dock.station.split.Root;
import bibliothek.gui.dock.station.split.SplitDockAccess;
import bibliothek.gui.dock.station.split.SplitDockCombinerSource;
import bibliothek.gui.dock.station.split.SplitDockFullScreenProperty;
import bibliothek.gui.dock.station.split.SplitDockPathProperty;
import bibliothek.gui.dock.station.split.SplitDockPlaceholderProperty;
import bibliothek.gui.dock.station.split.SplitDockProperty;
import bibliothek.gui.dock.station.split.SplitDockStationFactory;
import bibliothek.gui.dock.station.split.SplitDockTree;
import bibliothek.gui.dock.station.split.SplitDockTreeFactory;
import bibliothek.gui.dock.station.split.SplitDropTreeException;
import bibliothek.gui.dock.station.split.SplitFullScreenAction;
import bibliothek.gui.dock.station.split.SplitLayoutManager;
import bibliothek.gui.dock.station.split.SplitNode;
import bibliothek.gui.dock.station.split.SplitNodeVisitor;
import bibliothek.gui.dock.station.split.SplitPlaceholderSet;
import bibliothek.gui.dock.station.split.SplitTreeFactory;
import bibliothek.gui.dock.station.split.PutInfo.Put;
import bibliothek.gui.dock.station.support.CombinerSource;
import bibliothek.gui.dock.station.support.CombinerTarget;
import bibliothek.gui.dock.station.support.DockStationListenerManager;
import bibliothek.gui.dock.station.support.DockableVisibilityManager;
import bibliothek.gui.dock.station.support.PlaceholderMap;
import bibliothek.gui.dock.station.support.PlaceholderStrategy;
import bibliothek.gui.dock.station.support.PlaceholderStrategyListener;
import bibliothek.gui.dock.station.support.RootPlaceholderStrategy;
import bibliothek.gui.dock.themes.DefaultDisplayerFactoryValue;
import bibliothek.gui.dock.themes.DefaultStationPaintValue;
import bibliothek.gui.dock.themes.StationCombinerValue;
import bibliothek.gui.dock.themes.ThemeManager;
import bibliothek.gui.dock.title.ControllerTitleFactory;
import bibliothek.gui.dock.title.DockTitle;
import bibliothek.gui.dock.title.DockTitleFactory;
import bibliothek.gui.dock.title.DockTitleRequest;
import bibliothek.gui.dock.title.DockTitleVersion;
import bibliothek.gui.dock.util.BackgroundAlgorithm;
import bibliothek.gui.dock.util.BackgroundPanel;
import bibliothek.gui.dock.util.DockProperties;
import bibliothek.gui.dock.util.DockUtilities;
import bibliothek.gui.dock.util.PropertyKey;
import bibliothek.gui.dock.util.PropertyValue;
import bibliothek.gui.dock.util.icon.DockIcon;
import bibliothek.gui.dock.util.property.ConstantPropertyFactory;
import bibliothek.util.Path;
import bibliothek.util.Todo;
import bibliothek.util.Todo.Compatibility;
import bibliothek.util.Todo.Priority;
import bibliothek.util.Todo.Version;
/**
* This station shows all its children at once. The children are separated
* by small gaps which can be moved by the user. It is possible to set
* one child to {@link #setFullScreen(Dockable) fullscreen}, this child will
* be shown above all other children. The user can double click on the title
* of a child to change its fullscreen-mode.
* The station tries to register a {@link DockTitleFactory} with the
* ID {@link #TITLE_ID}.
* @author Benjamin Sigg
*/
public class SplitDockStation extends SecureContainer implements Dockable, DockStation {
/** The ID under which this station tries to register a {@link DockTitleFactory} */
public static final String TITLE_ID = "split";
/**
* Describes which {@link KeyEvent} will maximize/normalize the currently
* selected {@link Dockable}.
*/
public static final PropertyKey MAXIMIZE_ACCELERATOR = new PropertyKey("SplitDockStation maximize accelerator");
/**
* Defines the behavior of a {@link DockStation}, how to react on a
* drop-event, how to react on resize and other things related
* to the layout.
*/
public static final PropertyKey LAYOUT_MANAGER = new PropertyKey("SplitDockStation layout manager",
new ConstantPropertyFactory(new DefaultSplitLayoutManager()), true);
/** The parent of this station */
private DockStation parent;
/** Listener registered to the parent. When triggered it invokes other listeners */
private VisibleListener visibleListener = new VisibleListener();
/** The controller to which this station is registered */
private DockController controller;
/** The theme of this station */
private DockTheme theme;
/** Combiner to {@link #dropOver(Leaf, Dockable, CombinerSource, CombinerTarget) combine} some Dockables */
private StationCombinerValue combiner;
/** The type of titles which are used for this station */
private DockTitleVersion title;
/** A list of {@link DockableListener} which will be invoked when something noticable happens */
private List dockableListeners = new ArrayList();
/** All {@link DockableStateListener}s of this station */
private DockableStateListenerManager dockableStateListeners;
/** an observer ensuring that the {@link DockHierarchyEvent}s are sent properly */
private DockHierarchyObserver hierarchyObserver;
/** A list of {@link SplitDockListener} which will be invoked when something noticable happens */
private List splitListeners = new ArrayList();
/** The handler for events and listeners concerning the visibility of children */
private DockableVisibilityManager visibility;
/** the DockTitles which are bound to this dockable */
private List titles = new LinkedList();
/** the list of actions offered for this Dockable */
private HierarchyDockActionSource globalSource;
/**
* The list of all registered {@link DockStationListener DockStationListeners}.
* This list can be used to send events to all listeners.
*/
protected DockStationListenerManager dockStationListeners = new DockStationListenerManager(this);
/** Optional text for this station */
private PropertyValue titleText = new PropertyValue(PropertyKey.DOCK_STATION_TITLE){
@Override
protected void valueChanged( String oldValue, String newValue ){
if( oldValue == null )
oldValue = "";
if( newValue == null )
newValue = "";
for( DockableListener listener : dockableListeners.toArray(new DockableListener[dockableListeners.size()]) )
listener.titleTextChanged(SplitDockStation.this, oldValue, newValue);
}
};
/** Optional icon for this station */
private DockIcon titleIcon;
/** Optional tooltip for this station */
private PropertyValue titleToolTip = new PropertyValue(PropertyKey.DOCK_STATION_TOOLTIP){
@Override
protected void valueChanged( String oldValue, String newValue ){
for( DockableListener listener : dockableListeners.toArray(new DockableListener[dockableListeners.size()]) )
listener.titleToolTipChanged(SplitDockStation.this, oldValue, newValue);
}
};
/** the manager for detailed control of the behavior of this station */
private PropertyValue layoutManager = new PropertyValue(LAYOUT_MANAGER){
@Override
protected void valueChanged( SplitLayoutManager oldValue, SplitLayoutManager newValue ){
if( oldValue != null )
oldValue.uninstall(SplitDockStation.this);
if( newValue != null )
newValue.install(SplitDockStation.this);
}
};
private PropertyValue placeholderStrategyProperty = new PropertyValue(PlaceholderStrategy.PLACEHOLDER_STRATEGY){
@Override
protected void valueChanged( PlaceholderStrategy oldValue, PlaceholderStrategy newValue ){
placeholderStrategy.setStrategy(newValue);
}
};
/** strategy for managing placeholders */
private RootPlaceholderStrategy placeholderStrategy = new RootPlaceholderStrategy(this);
/** Whether the user can double click on a child to expand it. Default is true. */
private boolean expandOnDoubleclick = true;
/** expands a child of this station when the user clicks twice on the child */
private FullScreenListener fullScreenListener = new FullScreenListener();
/** The list of {@link Dockable Dockables} which are shown on this station */
private List dockables = new ArrayList();
/** The {@link Dockable} which has the focus */
private Dockable frontDockable;
/** The {@link Dockable} which is currently in fullscreen-mode. This value might be null */
private StationChildHandle fullScreenDockable;
/** An action that is added to all children. The action changes the fullscreen-mode of the child. Can be null */
private ListeningDockAction fullScreenAction;
/** Size of the gap between two children in pixel */
private int dividerSize = 4;
/**
* Relative size of the border where a {@link Dockable} will be placed aside
* another Dockable when dragging the new Dockable onto this station. Should
* be between 0 and 0.25f.
*/
private float sideSnapSize = 1 / 4f;
/**
* Size of the border outside this station where a {@link Dockable} will still
* be considered to be dropped onto this station. Measured in pixel.
*/
private int borderSideSnapSize = 25;
/**
* Whether the bounds of this station are slightly bigger than the station itself.
* Used together with {@link #borderSideSnapSize} to grab Dockables "out of the sky".
* The default is true.
*/
private boolean allowSideSnap = true;
/** Access to the private and protected methods for some friends of this station */
private Access access = new Access();
/** The root of the tree which determines the structure of this station */
private Root root;
/** Ensures that no placeholder is used twice on this station */
private SplitPlaceholderSet placeholderSet;
/** Whether nodes can automatically be removed from the tree or not */
private int treeLock = 0;
/** Information about the {@link Dockable} which is currently draged onto this station. */
private PutInfo putInfo;
/** A {@link StationPaint} to draw some markings onto this station */
private DefaultStationPaintValue paint;
/** A {@link DisplayerFactory} used to create {@link DockableDisplayer} for the children of this station */
private DefaultDisplayerFactoryValue displayerFactory;
/** The set of displayers currently used by this station */
private DisplayerCollection displayers;
/**
* A listener to the mouse. If triggered, the listener moves the dividers
* between the children around.
*/
private DividerListener dividerListener;
/**
* Whether the user can resize the content.
*/
private boolean resizingEnabled = true;
/** If true, the components are resized while the split is dragged */
private boolean continousDisplay = false;
/** the configurable hints for the parent of this station */
private DockableDisplayerHints hints;
/** the parent of all {@link DockableDisplayer}s */
private Content content;
/** the background algorithm of this station */
private Background background = new Background();
/**
* Constructs a new {@link SplitDockStation}.
*/
public SplitDockStation(){
this( true );
}
/**
* Creates a new {@link SplitDockStation}.
* @param createFullScreenAction whether {@link #createFullScreenAction()} should be called or not
*/
public SplitDockStation( boolean createFullScreenAction ){
content = new Content();
content.setBackground( background );
setBasePane( content );
placeholderSet = new SplitPlaceholderSet(access);
dockableStateListeners = new DockableStateListenerManager( this );
paint = new DefaultStationPaintValue( ThemeManager.STATION_PAINT + ".split", this );
combiner = new StationCombinerValue( ThemeManager.COMBINER + ".split", this );
displayerFactory = new DefaultDisplayerFactoryValue( ThemeManager.DISPLAYER_FACTORY + ".split", this );
displayers = new DisplayerCollection(this, displayerFactory);
displayers.addDockableDisplayerListener(new DockableDisplayerListener(){
public void discard( DockableDisplayer displayer ){
SplitDockStation.this.discard(displayer);
}
});
dividerListener = new DividerListener();
if( createFullScreenAction ){
fullScreenAction = createFullScreenAction();
}
visibility = new DockableVisibilityManager(dockStationListeners);
getContentPane().addMouseListener(dividerListener);
getContentPane().addMouseMotionListener(dividerListener);
hierarchyObserver = new DockHierarchyObserver(this);
globalSource = new HierarchyDockActionSource(this);
globalSource.bind();
titleIcon = new DockStationIcon( "dockStation.default", this ){
protected void changed( Icon oldValue, Icon newValue ){
for( DockableListener listener : dockableListeners.toArray( new DockableListener[ dockableListeners.size()] )){
listener.titleIconChanged( SplitDockStation.this, oldValue, newValue );
}
}
};
addDockStationListener(new DockStationAdapter(){
@Override
public void dockableAdded( DockStation station, Dockable dockable ){
updateConfigurableDisplayerHints();
}
@Override
public void dockableRemoved( DockStation station, Dockable dockable ){
updateConfigurableDisplayerHints();
}
});
placeholderStrategy.addListener(new PlaceholderStrategyListener(){
public void placeholderInvalidated( Set placeholders ){
removePlaceholders(placeholders);
}
});
addHierarchyListener( new HierarchyListener(){
public void hierarchyChanged( HierarchyEvent e ){
if( (e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0 ){
if( getDockParent() == null ){
dockableStateListeners.checkVisibility();
}
visibility.fire();
}
}
});
}
/**
* Creates a new root for this station.
* @param access access to the internals of this station
* @return the new root
*/
protected Root createRoot( SplitDockAccess access ){
return new Root(access);
}
/**
* Gets the root of this station, creates a root if necessary. This
* method cannot be overridden while {@link #getRoot()} can. This method
* just returns the value of {@link #root}, makes it a read only variable.
* @return the root
* @see #getRoot()
*/
protected final Root root(){
if( root == null ) {
root = createRoot(access);
}
return root;
}
@Override
public String toString(){
if( root == null ) {
return super.toString();
}
else {
return root.toString();
}
}
@Override
public Dimension getMinimumSize(){
Insets insets = getInsets();
Dimension base = getRoot().getMinimumSize();
if( insets != null ) {
base = new Dimension(base.width + insets.left + insets.right, base.height + insets.top + insets.bottom);
}
return base;
}
public DockTheme getTheme(){
return theme;
}
public void updateTheme(){
DockController controller = getController();
if( controller != null ) {
DockTheme newTheme = controller.getTheme();
if( newTheme != theme ) {
theme = newTheme;
try {
callDockUiUpdateTheme();
}
catch( IOException ex ) {
throw new RuntimeException(ex);
}
}
}
}
/**
* Calls the method {@link DockUI#updateTheme(DockStation, DockFactory)}
* with this as the first argument, and an appropriate factory
* as the second argument.
* @throws IOException if the DockUI throws an exception
*/
protected void callDockUiUpdateTheme() throws IOException{
DockUI.updateTheme(this, new SplitDockStationFactory());
}
/**
* Creates an {@link DockAction action} which is added to all children
* of this station. The action allows the user to expand a child to
* fullscreen. The action is also added to subchildren, but the effect
* does only affect direct children of this station.
* @return the action or null if this feature should be
* disabled, or the action is {@link #setFullScreenAction(ListeningDockAction) set later}
*/
protected ListeningDockAction createFullScreenAction(){
return new SplitFullScreenAction(this);
}
/**
* Sets an {@link DockAction action} which allows to expand children. This
* method can only be invoked if there is not already set an action. It is
* a condition that {@link #createFullScreenAction()} returns null
* @param fullScreenAction the new action
* @throws IllegalStateException if there is already an action present
*/
public void setFullScreenAction( ListeningDockAction fullScreenAction ){
if( this.fullScreenAction != null )
throw new IllegalStateException("The fullScreenAction can only be set once");
this.fullScreenAction = fullScreenAction;
}
/**
* Sets whether a double click on a child or its title can expand the child
* to fullscreen or not.
* @param expandOnDoubleclick true if the double click should
* have an effect, false if double clicks should be ignored.
*/
public void setExpandOnDoubleclick( boolean expandOnDoubleclick ){
this.expandOnDoubleclick = expandOnDoubleclick;
}
/**
* Tells whether a child expands to fullscreen when double clicked or not.
* @return true if a double click has an effect, false
* otherwise
* @see #setExpandOnDoubleclick(boolean)
*/
public boolean isExpandOnDoubleclick(){
return expandOnDoubleclick;
}
/**
* Enables the user to resize the children of this station. The default value
* of this property is true. Note that resizing is a core
* functionality of this station, disabling it should be considered
* carefully.
* @param resizingEnabled whether resizing is enabled or not
*/
public void setResizingEnabled( boolean resizingEnabled ){
this.resizingEnabled = resizingEnabled;
}
/**
* Tells whether the user can drag dividiers and resize dockables in this way.
* @return true if resizing is allowed
*/
public boolean isResizingEnabled(){
return resizingEnabled;
}
public void setDockParent( DockStation station ){
if( this.parent != null )
this.parent.removeDockStationListener(visibleListener);
parent = station;
if( station != null )
station.addDockStationListener(visibleListener);
hierarchyObserver.update();
}
public DockStation getDockParent(){
return parent;
}
public void setController( DockController controller ){
super.setController( controller );
if( this.controller != controller ) {
if( this.controller != null ){
this.controller.getDoubleClickController().removeListener(fullScreenListener);
}
for( StationChildHandle handle : dockables ) {
handle.setTitleRequest(null);
}
this.controller = controller;
getDisplayers().setController(controller);
if( fullScreenAction != null )
fullScreenAction.setController(controller);
titleIcon.setController(controller);
titleText.setProperties(controller);
layoutManager.setProperties(controller);
placeholderStrategyProperty.setProperties(controller);
paint.setController( controller );
displayerFactory.setController( controller );
combiner.setController( controller );
background.setController( controller );
if( controller != null ) {
title = controller.getDockTitleManager().getVersion(TITLE_ID, ControllerTitleFactory.INSTANCE);
controller.getDoubleClickController().addListener(fullScreenListener);
}
else
title = null;
for( StationChildHandle handle : dockables ) {
handle.setTitleRequest(title);
}
hierarchyObserver.controllerChanged(controller);
visibility.fire();
}
}
@Override
public DockController getController(){
return controller;
}
public void addDockableListener( DockableListener listener ){
dockableListeners.add(listener);
}
public void removeDockableListener( DockableListener listener ){
dockableListeners.remove(listener);
}
public void addDockHierarchyListener( DockHierarchyListener listener ){
hierarchyObserver.addDockHierarchyListener(listener);
}
public void removeDockHierarchyListener( DockHierarchyListener listener ){
hierarchyObserver.removeDockHierarchyListener(listener);
}
public void addMouseInputListener( MouseInputListener listener ){
// ignore
}
public void removeMouseInputListener( MouseInputListener listener ){
// ignore
}
public boolean accept( DockStation station ){
return true;
}
public boolean accept( DockStation base, Dockable neighbour ){
return true;
}
/**
* Tells whether next can be dropped over old.
* @param old some old dockable
* @param next some new dockable
* @return true if combining is allowed
*/
protected boolean acceptable( Dockable old, Dockable next ){
if( !old.accept( this, next )){
return false;
}
if( !next.accept( this )){
return false;
}
DockController controller = getController();
if( controller != null ){
return controller.getAcceptance().accept( this, old, next );
}
return true;
}
/**
* Tells whether next can be dropped on this station
* @param next some new dockable
* @return true if combining is allowed
*/
protected boolean acceptable( Dockable next ){
if( !accept( next )){
return false;
}
if( !next.accept( this )){
return false;
}
DockController controller = getController();
if( controller != null ){
return controller.getAcceptance().accept( this, next );
}
return true;
}
public Component getComponent(){
return this;
}
public DockElement getElement(){
return this;
}
public boolean isUsedAsTitle(){
return false;
}
public boolean shouldFocus(){
return true;
}
public boolean shouldTransfersFocus(){
return false;
}
public Point getPopupLocation( Point click, boolean popupTrigger ){
if( popupTrigger )
return click;
else
return null;
}
public String getTitleText(){
String text = titleText.getValue();
if( text == null )
return "";
else
return text;
}
/**
* Sets the text of the title of this dockable.
* @param titleText the text displayed in the title
*/
public void setTitleText( String titleText ){
this.titleText.setValue(titleText);
}
public String getTitleToolTip(){
return titleToolTip.getValue();
}
/**
* Sets the tooltip that should be shown on any title that is {@link #bind(DockTitle) bound}
* to this dockable.
* @param text the tooltip, can be null
*/
public void setTitleToolTip( String text ){
titleToolTip.setValue(text);
}
public Icon getTitleIcon(){
return titleIcon.value();
}
/**
* Sets an icon that is shown in the {@link DockTitle titles} of this {@link Dockable}.
* @param titleIcon the icon or null
*/
public void setTitleIcon( Icon titleIcon ){
this.titleIcon.setValue( titleIcon, true );
}
/**
* Resets the icon of this {@link SplitDockStation}, the default icon is shown again.
*/
public void resetTitleIcon(){
this.titleIcon.setValue( null );
}
/**
* Sets a special {@link SplitLayoutManager} which this station has to use.
* @param manager the manager or null to return to the
* manager that is specified in the {@link DockProperties} by the key
* {@link #LAYOUT_MANAGER}.
*/
public void setSplitLayoutManager( SplitLayoutManager manager ){
layoutManager.setValue(manager);
}
/**
* Gets the layout manager which was explicitly set.
* @return the manager or null
* @see #setSplitLayoutManager(SplitLayoutManager)
*/
public SplitLayoutManager getSplitLayoutManager(){
return layoutManager.getOwnValue();
}
/**
* Gets the strategy for creating and storing placeholders. Note that this is not the same
* value as was set to {@link #setPlaceholderStrategy(PlaceholderStrategy)}
* @return the strategy, never null
*/
public RootPlaceholderStrategy getPlaceholderStrategy(){
return placeholderStrategy;
}
/**
* Sets the strategy for selecting placeholders when removing {@link Dockable}s from this
* station.
* @param strategy the new strategy or null to install the default strategy
*/
public void setPlaceholderStrategy( PlaceholderStrategy strategy ){
placeholderStrategyProperty.setValue(strategy);
}
/**
* Every child has an invisible border whose size is determined by sideSnapSize.
* If another {@link Dockable} is dragged into that border, it is added as neighbor.
* Otherwise it is merged with the present child.
* @param sideSnapSize the relative size of the border, should be between
* 0 and 0.5f
* @throws IllegalArgumentException if the size is less than 0
*/
public void setSideSnapSize( float sideSnapSize ){
if( sideSnapSize < 0 )
throw new IllegalArgumentException("sideSnapSize must not be less than 0");
this.sideSnapSize = sideSnapSize;
}
/**
* Gets the relative size of the invisible border of all children.
* @return the size
* @see #setSideSnapSize(float)
*/
public float getSideSnapSize(){
return sideSnapSize;
}
/**
* There is an invisible border around the station. If a {@link Dockable} is
* dragged inside this border, its considered to be on the station, but
* will be dropped aside the station (like the whole station is a neighbor
* of the Dockable).
* @param borderSideSnapSize the size of the border in pixel
* @throws IllegalArgumentException if the size is smaller than 0
*/
public void setBorderSideSnapSize( int borderSideSnapSize ){
if( borderSideSnapSize < 0 )
throw new IllegalArgumentException("borderSideSnapeSize must not be less than 0");
this.borderSideSnapSize = borderSideSnapSize;
}
/**
* Gets the size of the border around the station.
* @return the size in pixel
* @see #setBorderSideSnapSize(int)
*/
public int getBorderSideSnapSize(){
return borderSideSnapSize;
}
/**
* Sets the size of the divider-gap between the children of this station.
* @param dividerSize the size of the gap in pixel
* @throws IllegalArgumentException if the size is less than 0.
*/
public void setDividerSize( int dividerSize ){
if( dividerSize < 0 )
throw new IllegalArgumentException("dividerSize must not be less than 0");
this.dividerSize = dividerSize;
doLayout();
}
/**
* Gets the size of the divider-gap.
* @return the size
* @see #setDividerSize(int)
*/
public int getDividerSize(){
return dividerSize;
}
/**
* Sets whether the dockables should be resized while the split
* is dragged, or not.
* @param continousDisplay true if the dockables should
* be resized
*/
public void setContinousDisplay( boolean continousDisplay ){
this.continousDisplay = continousDisplay;
}
/**
* Tells whether the dockables are resized while the split is
* dragged, or not.
* @return true if the dockables are resized
* @see #setContinousDisplay(boolean)
*/
public boolean isContinousDisplay(){
return continousDisplay;
}
/**
* Sets whether {@link Dockable Dockables} which are dragged near
* the station are captured and added to this station.
* @param allowSideSnap true if the station can
* snap Dockables which are near.
* @see #setBorderSideSnapSize(int)
*/
public void setAllowSideSnap( boolean allowSideSnap ){
this.allowSideSnap = allowSideSnap;
}
/**
* Tells whether the station can grab Dockables which are dragged
* near the station.
* @return true if grabbing is allowed
* @see #setAllowSideSnap(boolean)
*/
public boolean isAllowSideSnap(){
return allowSideSnap;
}
public void requestDockTitle( DockTitleRequest request ){
// ignore
}
public void changed( Dockable dockable, DockTitle title, boolean active ){
title.changed(new DockTitleEvent(this, dockable, active));
}
public void requestChildDockTitle( DockTitleRequest request ){
// ignore
}
public void bind( DockTitle title ){
if( titles.contains(title) )
throw new IllegalArgumentException("Title is already bound");
titles.add(title);
for( DockableListener listener : dockableListeners.toArray(new DockableListener[dockableListeners.size()]) )
listener.titleBound(this, title);
}
public void unbind( DockTitle title ){
if( !titles.contains(title) )
throw new IllegalArgumentException("Title is unknown");
titles.remove(title);
for( DockableListener listener : dockableListeners.toArray(new DockableListener[dockableListeners.size()]) )
listener.titleUnbound(this, title);
}
public DockTitle[] listBoundTitles(){
return titles.toArray(new DockTitle[titles.size()]);
}
public DockActionSource getLocalActionOffers(){
return null;
}
public DockActionSource getGlobalActionOffers(){
return globalSource;
}
public void configureDisplayerHints( DockableDisplayerHints hints ){
this.hints = hints;
updateConfigurableDisplayerHints();
}
/**
* Gets the argument that was last used for
* {@link #configureDisplayerHints(DockableDisplayerHints)}.
* @return the configurable hints or null
*/
protected DockableDisplayerHints getConfigurableDisplayerHints(){
return hints;
}
/**
* Updates the {@link #getConfigurableDisplayerHints() current hints}
* of this station.
*/
protected void updateConfigurableDisplayerHints(){
if( hints != null ) {
if( getDockableCount() == 0 )
hints.setShowBorderHint(Boolean.TRUE);
else
hints.setShowBorderHint(Boolean.FALSE);
}
}
public DockStation asDockStation(){
return this;
}
public DefaultDockActionSource getDirectActionOffers( Dockable dockable ){
if( fullScreenAction == null )
return null;
else {
DefaultDockActionSource source = new DefaultDockActionSource(new LocationHint(LocationHint.DIRECT_ACTION, LocationHint.VERY_RIGHT));
source.add(fullScreenAction);
return source;
}
}
public DockActionSource getIndirectActionOffers( Dockable dockable ){
if( fullScreenAction == null )
return null;
DockStation parent = dockable.getDockParent();
if( parent == null )
return null;
if( parent instanceof SplitDockStation )
return null;
dockable = parent.asDockable();
if( dockable == null )
return null;
parent = dockable.getDockParent();
if( parent != this )
return null;
DefaultDockActionSource source = new DefaultDockActionSource(fullScreenAction);
source.setHint(new LocationHint(LocationHint.INDIRECT_ACTION, LocationHint.VERY_RIGHT));
return source;
}
public void addDockStationListener( DockStationListener listener ){
dockStationListeners.addListener(listener);
}
public void removeDockStationListener( DockStationListener listener ){
dockStationListeners.removeListener(listener);
}
public void addDockableStateListener( DockableStateListener listener ){
dockableStateListeners.addListener( listener );
}
public void removeDockableStateListener( DockableStateListener listener ){
dockableStateListeners.removeListener( listener );
}
/**
* Adds a listener to this station. The listener is informed some
* settings only available to a {@link SplitDockStation} are changed.
* @param listener the new listener
*/
public void addSplitDockStationListener( SplitDockListener listener ){
splitListeners.add(listener);
}
/**
* Removes an earlier added listener.
* @param listener The listener to remove
*/
public void removeSplitDockStationListener( SplitDockListener listener ){
splitListeners.remove(listener);
}
public boolean isVisible( Dockable dockable ){
return isStationVisible() && (!isFullScreen() || dockable == getFullScreen());
}
public boolean isStationVisible(){
return isDockableVisible();
}
public boolean isDockableVisible(){
DockController controller = getController();
if( controller == null ){
return false;
}
DockStation parent = getDockParent();
if( parent != null ){
return parent.isVisible( this );
}
return isShowing();
}
public int getDockableCount(){
return dockables.size();
}
public Dockable getDockable( int index ){
return dockables.get(index).getDockable();
}
public DockableProperty getDockableProperty( Dockable child, Dockable target ){
DockableProperty result = getDockablePlaceholderProperty(child, target);
if( result == null ) {
result = getDockablePathProperty(child);
}
return result;
}
/**
* Creates a {@link DockableProperty} for the location of dockable.
* The location is encoded as the path through the tree to get to dockable.
* @param dockable the element whose location is searched
* @return the location
*/
public SplitDockPathProperty getDockablePathProperty( final Dockable dockable ){
final SplitDockPathProperty path = new SplitDockPathProperty();
root().submit(new SplitTreeFactory