bibliothek.gui.DockStation Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of docking-frames-core Show documentation
Show all versions of docking-frames-core Show documentation
${project.name} is base or core library
/*
* 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;
import java.awt.Component;
import java.awt.Rectangle;
import javax.swing.JFrame;
import bibliothek.gui.dock.DockElement;
import bibliothek.gui.dock.DockElementRepresentative;
import bibliothek.gui.dock.DockFactory;
import bibliothek.gui.dock.accept.DockAcceptance;
import bibliothek.gui.dock.action.DockActionSource;
import bibliothek.gui.dock.event.DockStationListener;
import bibliothek.gui.dock.layout.DockableProperty;
import bibliothek.gui.dock.station.DockableDisplayer;
import bibliothek.gui.dock.station.StationPaint;
import bibliothek.gui.dock.station.support.PlaceholderList;
import bibliothek.gui.dock.station.support.PlaceholderMap;
import bibliothek.gui.dock.station.support.PlaceholderStrategy;
import bibliothek.gui.dock.title.DockTitle;
import bibliothek.gui.dock.title.DockTitleFactory;
import bibliothek.gui.dock.title.DockTitleManager;
import bibliothek.gui.dock.title.DockTitleRequest;
import bibliothek.gui.dock.title.DockTitleVersion;
/**
* A DockStation
is some area (e.g. a {@link Component}) showing
* a set of {@link Dockable}s called "children". The station is free to decide how and if to
* show its children.
* Although a station can take any form, there are some (optional) practices to follow:
*
* - Each {@link Dockable} should be child of a {@link DockableDisplayer}. The displayer will
* paint border and title of the item.
* - This station should be aware of the current {@link DockTheme} and use its factories and delegates whenever possible.
* - Drag and drop is handled by the {@link DockController}. Methods like {@link #canDrag(Dockable)}, {@link #drag(Dockable)},
* {@link #drop()} or {@link #move()} need to be implemented for this. Also {@link #accept(Dockable)}, {@link Dockable#accept(DockStation)},
* {@link Dockable#accept(DockStation, Dockable)} and the {@link DockAcceptance} of the current {@link DockController} should be checked before
* allowing a drag and drop operation.
* - For each child there should be at least one {@link DockTitle}. This station needs to derive a {@link DockTitleVersion} from
* its controller using the {@link DockController#getDockTitleManager() DockTitleManager} and its
* {@link DockTitleManager#registerDefault(String, DockTitleFactory) factory method}. With the {@link DockTitleVersion}-object one
* {@link DockTitleRequest} for each required {@link DockTitle} can be created.
* - One child can be focused. If this station changes the focus it should use {@link DockController#setAtLeastFocusedDockable(Dockable, Component)}.
* - This station should support placeholders. The current {@link PlaceholderStrategy} can be used to convert {@link Dockable}s to placeholders.
* A {@link PlaceholderList} is a good datastructure to store {@link Dockable}s and placeholders at the same time.
* - Additional points where the user can start drag and drop operations can be installed by implementing a {@link DockElementRepresentative}. It
* has to be installed using {@link DockController#addRepresentative(DockElementRepresentative)}.
* - And a new {@link DockFactory} will be required to persistently store the layout of this station.
*
* @author Benjamin Sigg
*/
public interface DockStation extends DockElement{
/**
* Sets the controller of this station. If the station wants to
* show any {@link DockTitle}, then the titles have to be replaced
* by new instances (assuming the controller is really new). The
* title has to get new {@link DockTitleVersion DockTitleVersions} through
* the {@link DockTitleManager} of controller
.
* An argument of null
means that this station is currently
* not shown.
* @param controller the owner of this station, can be null
*/
public void setController( DockController controller );
/**
* Gets the controller of this station.
* @return the controller or null
if no controller is set
* @see #setController(DockController)
*/
public DockController getController();
/**
* Updates the {@link DockTheme} of this station. The new theme
* has to be read from the {@link #getController() controller} of
* this station. If the controller is null
, this method
* should return immediately.
* You may use {@link DockUI#updateTheme(DockStation, DockFactory)}
* to implement this method.
*/
public void updateTheme();
/**
* Gets the current theme of this station. The theme can be null
,
* but that means that the station is not fully initialized, and might not
* work correct.
* @return the theme of this station or null
.
*/
public DockTheme getTheme();
/**
* Gets a list of actions which should be available for the user and
* affect the child dockable
.
* @param dockable a child of this station
* @return actions for dockable
, can be null
*/
public DockActionSource getDirectActionOffers( Dockable dockable );
/**
* Gets a list of actions which should be available for the user and
* affect dockable
. The argument dockable
* can be a child of this station, or a child of any station which is
* below this station.
* @param dockable a child of this station or a child of another station
* which is below this station
* @return actions for dockable
or null
*/
public DockActionSource getIndirectActionOffers( Dockable dockable );
/**
* Adds a listener to this station. The station has to invoke the
* methods of the listener such that its requirements are full filled.
* @param listener the listener to add
*/
public void addDockStationListener( DockStationListener listener );
/**
* Removes a listener from this station.
* @param listener the listener to remove
*/
public void removeDockStationListener( DockStationListener listener );
/**
* Tells whether the child dockable
is visible or not. Visible
* means that the {@link Dockable#getComponent() component} of dockable
* can be seen by the user. The result must be false
if
* this station is not visible.
* @param dockable the child whose visibility-state is questioned
* @return whether dockable
is visible or not
* @see #isStationVisible()
*/
public boolean isVisible( Dockable dockable );
/**
* Tells whether this station is visible or not. For example a station on
* a {@link JFrame} is not visible if the frame is minimized.
* @return whether this station is visible
*/
public boolean isStationVisible();
/**
* Gets the number of children.
* @return the number of children on this station
*/
public int getDockableCount();
/**
* Gets the index'th child of this station.
* @param index a value between 0 (incl.) and {@link #getDockableCount()}
* (excl.).
* @return a child of this station
*/
public Dockable getDockable( int index );
/**
* Gets the favorite child of this station. The favorite child is the one
* child which is specially designated for the user. An example: if the
* station behaves like a stack, and only the top child is visible, then
* the favorite child could the the top.
* A result of null
indicates that there are no children
* at all, or that there is no favorite child (all children are equal important).
* Stations should not change this property directly, they should call
* {@link DockController#setFocusedDockable(Dockable, boolean)}
* which will then call {@link #setFrontDockable(Dockable)}. Note that the
* DockController itself listens to the DockTitles, and maybe the station
* doesn't need a logic to decide which child is important.
* @return the most important child or null
*/
public Dockable getFrontDockable();
/**
* Sets the most important child. The station should ensure that this child
* is visible (assuming the station itself is visible). Read the
* comment on {@link #getFrontDockable()} how stations can change
* this property.
* @param dockable the new favorite child, can be null
* @see #getFrontDockable()
*/
public void setFrontDockable( Dockable dockable );
/**
* Gets a snapshot of all placeholders that are currently stored in this {@link DockStation}.
* A {@link DockStation} is free in the format it chooses to fill the map. The map is to be
* created with the assumptions that {@link #getDockableCount()} is 0
, meaning
* any existing {@link Dockable} gets replaced by its placeholder. The current
* {@link PlaceholderStrategy} should be used to convert {@link Dockable}s to placeholders.
* @return the map of placeholders or null
if this station does not support
* placeholders
*/
public PlaceholderMap getPlaceholders();
/**
* Sets an earlier snapshot of the placeholders of this station. This station can assume that
* it currently does not have any children (that {@link #getDockableCount()} is 0
).
* This method does nothing if it cannot handle the format or the version of placeholders
.
* @param placeholders some set of placeholders
* @throws IllegalStateException if {@link #getDockableCount()} is not equal to 0
*/
public void setPlaceholders( PlaceholderMap placeholders );
/**
* Called by the {@link DockController} of this station to indicate that
* the active-state of title
has been changed. This station
* should call the method title.{@link DockTitle#changed(bibliothek.gui.dock.event.DockTitleEvent) changed}
* with an appropriate event. The station may add some additional information
* to this call.
* @param dockable the child whose title is changed
* @param title the changed title, may not be bound
* @param active the new state of the title
*/
public void changed( Dockable dockable, DockTitle title, boolean active );
/**
* Provides a {@link DockTitle} for a child of this station. This method
* must call {@link DockTitleRequest#answer(DockTitle)} to set the result.
* Most {@link DockStation}s won't have the need to implement this method,
* leaving it empty will advice the framework to use another source for
* new {@link DockTitle}s.
* @param request the request to answer, not null
*/
public void requestChildDockTitle( DockTitleRequest request );
/**
* Tells whether this station accepts child
as a new child,
* or refuses child
. The user will not be able to drop
* a {@link Dockable} onto this station if this method returns
* false
.
* @param child a {@link Dockable} which may become a child
* @return true
if child
is accepted
*/
public boolean accept( Dockable child );
/**
* Gets precise information about the location of a child of this station.
* The result of this method could later be used to invoke
* {@link #drop(Dockable, DockableProperty)}.
* @param child a child of this station, this childs location is asked
* @param target an optional hint telling for which dockable the location information
* will be used, can be null
. This hint can be used to find a placeholder
* that should be part of the result.
* @return the location
* @see bibliothek.gui.dock.util.DockUtilities#getPropertyChain(DockStation, Dockable)
*/
public DockableProperty getDockableProperty( Dockable child, Dockable target );
/**
* Prepares this station to get the new child dockable
. The
* station has to store a possible location of the child, and should draw
* some indicators where the child will be put. The station can refuse
* dockable
, in this case nothing has to be painted and
* this method returns false
.
* There are some constraints:
*
* - The result should be
false
if this station is dockable,
* checkOverrideZone
is true
and the mouse is in
* the override-zone. of the parent. However, that condition is just "good manners" and may
* be broken.
* - This method should use {@link #accept(Dockable)} and {@link Dockable#accept(DockStation)}
* or {@link Dockable#accept(DockStation, Dockable)} to ensure that the desired
* drop-location is valid.
* - The method should use the {@link DockAcceptance} of its controller
* (see {@link DockController#getAcceptance()}) to ensure that the drop/location is valid.
*
* This method gets two points: mouseX/mouseY
is the location
* of the mouse, titleX/titleY
is the location of the dragged
* title. The second point may be interesting if the title of a dropped
* child should have the same coordinates as the image of the dragged title.
* This method is never called if dockable
is a child of this
* station. In such a case {@link #prepareMove(int, int, int, int, boolean, Dockable) prepareMove}
* is invoked.
* @param mouseX the x-coordinate of the mouse on the screen
* @param mouseY the y-coordinate of the mouse on the screen
* @param titleX the x-location of the dragged title or mouseX
if no
* title is dragged
* @param titleY the y-location of the dragged title or mouseY
if no
* title is dragged
* @param checkOverrideZone whether this station has to check if the mouse
* is in the override-zone of its parent
* @param dockable the element which will be dropped
* @return true
if dockable
can be added at the
* current location, false
otherwise.
*/
public boolean prepareDrop( int mouseX, int mouseY, int titleX, int titleY, boolean checkOverrideZone, Dockable dockable );
/**
* Adds the {@link Dockable} of the last run of
* {@link #prepareDrop(int, int, int, int, boolean, Dockable) prepareDrop} to this station.
* This method is only called if the new child and this station accepted
* each other, prepareDrop
returned true
and
* the new child is not yet a child of this station.
*/
public void drop();
/**
* Adds dockable
to this station. The station can decide
* by its own where to put dockable
.
* @param dockable a new child
*/
public void drop( Dockable dockable );
/**
* Tries to add dockable
to this station such that the location
* given by property
is matched. If property
* has a {@link DockableProperty#getSuccessor() successor} and points to
* another station, just call the drop
-method of this
* child-station. Note that property
can be of any type and
* contain invalid information.
* @param dockable the new child
* @param property the location of the child, may be invalid data
* @return true
if property
could be read
* and dockable
was dropped, false
* otherwise.
*/
public boolean drop( Dockable dockable, DockableProperty property );
/**
* Prepares the station that one of its children is moved from one
* location to another location. See {@link #prepareDrop(int, int, int, int, boolean, Dockable) prepareDrop}
* for detailed information about the behavior of this method. The only
* difference between this method and prepareDrop
is, that
* dockable
is a child of this station.
* @param mouseX the x-coordinate of the mouse on the screen
* @param mouseY the y-coordinate of the mouse on the screen
* @param titleX the x-location of the dragged title or mouseX
if no
* title is dragged
* @param titleY the y-location of the dragged title or mouseY
if no
* title is dragged
* @param checkOverrideZone whether this station has to check if the
* mouse is in the override-zone of its parent
* @param dockable the element which will be moved
* @return true
if dockable
can be added at the
* current location, false
otherwise.
*/
public boolean prepareMove( int mouseX, int mouseY, int titleX, int titleY, boolean checkOverrideZone, Dockable dockable );
/**
* Moves a child of this station to a new location according to the
* information gathered by {@link #prepareMove(int, int, int, int, boolean, Dockable) prepareMove}.
*/
public void move();
/**
* Tries to move the child dockable
in such a way, that
* {@link DockStation#getDockableProperty(Dockable, Dockable)} would return a
* {@link DockableProperty} that equals property
.
* There is no need to give a guarantee that the move successes, and clients
* should always be prepared for the possibility that this {@link DockStation}
* does nothing at all.
* @param dockable a child of this station
* @param property the preferred position of dockable
*/
public void move( Dockable dockable, DockableProperty property );
/**
* Informs this station that the information gathered by
* {@link #prepareDrop(int, int, int, int, boolean, Dockable) prepareDrop} or
* {@link #prepareMove(int, int, int, int, boolean, Dockable) prepareMove} should
* be painted somehow onto this station.
* The station should use the {@link StationPaint} of its theme
* to draw.
*/
public void draw();
/**
* Tells this station that a possible drop or move on this station
* was canceled. The station can throw away any information gathered by
* the last call {@link #prepareDrop(int, int, int, int, boolean, Dockable) prepareDrop}
* or {@link #prepareMove(int, int, int, int, boolean, Dockable) prepareMove}
* If the station is drawing some markings because of a call to
* {@link #draw()}, than the station can throw away these markings too.
*/
public void forget();
/**
* If the controller asks a station if a child could be dropped or moved,
* the controller assumes that no other station has interest in this event.
* However if this station is a dockable, and has a parent, the parent might
* be interested in the new child. This dockable station has to ask the
* parent if the current location of the mouse is in the override-zone. This
* station should not accept a child if the parent returns true
.
* On the other hand, this station could be asked by a child whether the mouse
* is in the override-zone. If the mouse hits a point of special interest,
* then the method should return true
.
* Note: if this station is asked and is a dockable station itself, then
* this method should ask the parent for his override-zone too.
* @param x the x-coordinate of the mouse on the screen
* @param y the y-coordinate of the mouse on the screen
* @param invoker a child of this station which invoked the method
* @param drop a {@link Dockable} which might become a child
* @param the type of invoker
* @return true
if the location of the mouse is of special
* interest
*/
public boolean isInOverrideZone( int x, int y, D invoker, Dockable drop );
/**
* Tells whether dockable
can be removed from this station or not.
* This method assumes that dockable
is a child of
* this station, if not, then the behavior of this method is unspecified.
* Note that the result of this method may not be respected every time,
* it's more a hint for the controller how to act.
* @param dockable a child of this station
* @return true
if dockable
can be dragged
*/
public boolean canDrag( Dockable dockable );
/**
* Removes a child from this station. This method may be called even
* if {@link #canDrag(Dockable)} returned false
.
* Note: clients may need to invoke {@link DockController#freezeLayout()}
* and {@link DockController#meltLayout()} to ensure noone else adds or
* removes Dockable
s.
* @param dockable the child to remove
*/
public void drag( Dockable dockable );
/**
* Tells whether its possible to replace the child old
* with next
where next is not a child of this station.
* @param old a child of this station
* @param next the replacement of next
.
* @return true
if the replacement is possible
* @throws IllegalArgumentException if next
is a child
* of this station
*/
public boolean canReplace( Dockable old, Dockable next );
/**
* Replaces the child old
by next
which is
* not yet a child of this station. This method should not be
* called if {@link #canReplace(Dockable, Dockable) canReplace} returned
* false
.
* @param old a child
* @param next the replacement of old
* @throws IllegalArgumentException if next
is a child of
* this station or if old
is not a child
*/
public void replace( Dockable old, Dockable next );
/**
* Replaces the child old
by next
which is
* not yet a child of this station. This method should not be
* called if {@link #canReplace(Dockable, Dockable) canReplace} returned
* false
. This method can assume that next
was
* a child of old
but no longer is.
* @param old a dockable station that is a child of this station
* @param next the replacement of old
* @throws IllegalArgumentException if next
is a child of
* this station, if old
is not a child or if old
* is not a {@link Dockable}
*/
public void replace( DockStation old, Dockable next );
/**
* Gets a rectangle in which all points of the station are. The user is
* only able to move a {@link Dockable} into this area onto this station.
* @return the bounds, relative to the screen, null
to indicate that
* this station has not any bounds
*/
public Rectangle getStationBounds();
/**
* Tells whether this station knows a rule how to compare itself with
* station
. See {@link #compare(DockStation)} for more
* details.
* @param station another station
* @return true
if a call to {@link #compare(DockStation) compare}
* will not end in an exception and return another value than 0
*/
public boolean canCompare( DockStation station );
/**
* Compares this station with station
. The comparison is needed
* if the {@link #getStationBounds() stations bounds} of the two station
* have common points. On a drag-event, the controller needs a way to
* decide which station is more important (and receives the opportunity
* to get a new child first). The controller will use the method
* compare
to do this. This method works like
* {@link Comparable#compareTo(Object)}.
* @param station another station
* @return a number less/equal/higher than zero, if this station has
* higher/equal/lesser priority than station
.
*/
public int compare( DockStation station );
}