/*
* 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) 2011 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
* benjamin_sigg@gmx.ch
* CH - Switzerland
*/
package bibliothek.gui.dock.common.mode;
import java.util.List;
import bibliothek.gui.DockStation;
import bibliothek.gui.Dockable;
import bibliothek.gui.dock.common.CControl;
import bibliothek.gui.dock.common.CStation;
import bibliothek.gui.dock.common.CStationContainer;
import bibliothek.gui.dock.common.intern.CDockable;
import bibliothek.gui.dock.common.intern.CommonDockable;
import bibliothek.gui.dock.common.intern.station.CommonDockStation;
import bibliothek.gui.dock.common.util.CDockUtilities;
import bibliothek.gui.dock.facile.mode.Location;
import bibliothek.gui.dock.support.mode.HistoryRewriter;
/**
* The {@link CStationContainerHistoryRewriter} tries to ensure that a {@link CDockable} stays on the
* same {@link CStationContainer} when changing the {@link ExtendedMode}.
* @author Benjamin Sigg
*/
public class CStationContainerHistoryRewriter implements HistoryRewriter<Location, CLocationMode>{
/** provides the list of {@link CStationContainer}s to check */
private CControl control;
/**
* Creates a new rewriter
* @param control provides the list of {@link CStationContainer}s to check
*/
public CStationContainerHistoryRewriter( CControl control ){
this.control = control;
}
/**
* Gets the {@link CControl} that is using this rewriter.
* @return the control
*/
public CControl getControl(){
return control;
}
/**
* Given the current location of <code>dockable</code> and the root station it is going
* to use, this method decides which {@link CStation} is actually going to be the new parent
* root station.
* @param dockable the element that is going to be moved around
* @param root the new root station
* @return a replacement for <code>root</code>, a value of <code>null</code> means that
* <code>root</code> should be used.
*/
protected CStation<?> getMatchingStation( Dockable dockable, String root ){
// search root
CStation<?> rootStation = control.getStation( root );
if( rootStation == null ){
return null;
}
CStationContainer rootContainer = getContainer( rootStation );
if( rootContainer == null ){
return rootStation;
}
// search current container
CStation<?> station = getParent( dockable );
CStationContainer container = getContainer( station );
if( container != null ){
if( rootContainer == container ){
return rootStation;
}
return container.getMatchingStation( rootContainer, rootStation );
}
else{
List<Location> history = control.getLocationManager().getPropertyHistory( dockable );
for( int i = history.size()-1; i >= 0; i-- ){
String historyRoot = history.get( i ).getRoot();
CStation<?> historyStation = control.getStation( historyRoot );
if( historyStation != null ){
container = getContainer( historyStation );
if( container != null ){
CStation<?> result = container.getMatchingStation( rootContainer, rootStation );
if( result != null ){
return result;
}
}
}
}
}
return null;
}
/**
* Searches a {@link CStation} which could be the new parent of <code>dockable</code>
* if it should be in mode <code>mode</code>.
* @param dockable the element for which a new parent is searched
* @param mode the mode <code>element</code> should be in
* @return the new parent or <code>null</code>
*/
protected CStation<?> getMatchingStation( Dockable dockable, ExtendedMode mode ){
CStation<?> station = getParent( dockable );
CStation<?> workingArea = getWorkingArea( dockable );
if( station != null && workingArea != null && !isValidParent( station, workingArea )){
return workingArea;
}
CStationContainer container = getContainer( station );
if( container != null ){
return container.getDefaultStation( mode );
}
List<Location> history = control.getLocationManager().getPropertyHistory( dockable );
for( int i = history.size()-1; i >= 0; i-- ){
String historyRoot = history.get( i ).getRoot();
CStation<?> rootStation = control.getStation( historyRoot );
if( rootStation != null ){
container = getContainer( rootStation );
if( container != null ){
CStation<?> result = container.getDefaultStation( mode );
if( result != null && isValidParent( result, workingArea )){
return result;
}
}
}
}
return null;
}
private boolean isValidParent( CStation<?> parent, CStation<?> workingArea ){
return parent != null && CDockUtilities.getFirstWorkingArea( parent ) == workingArea;
}
/**
* Gets the {@link CStation} which is set as {@link CDockable#getWorkingArea()}
* for <code>dockable</code>.
* @param dockable the element whose working area is searched
* @return the working area or <code>null</code>
*/
protected CStation<?> getWorkingArea( Dockable dockable ){
if( dockable instanceof CommonDockable ){
return ((CommonDockable)dockable).getDockable().getWorkingArea();
}
return null;
}
/**
* Gets the first parent {@link CStation} of <code>dockable</code>.
* @param dockable some dockable whose parent station is searched
* @return the parent station or <code>null</code> if not found
*/
protected CStation<?> getParent( Dockable dockable ){
DockStation dockStation = dockable.getDockParent();
while( dockStation != null ){
if( dockStation instanceof CommonDockStation<?,?>){
return ((CommonDockStation<?,?>)dockStation).getStation();
}
if( dockStation.asDockable() == null ){
dockStation = null;
}
else{
dockStation = dockStation.asDockable().getDockParent();
}
}
return null;
}
/**
* Searches the {@link CStationContainer} which is the parent of <code>child</code>.
* @param child some {@link CStation} whose parent is searched
* @return the parent of <code>child</code> or <code>null</code>
*/
protected CStationContainer getContainer( CStation<?> child ){
if( child == null ){
return null;
}
DockStation station = child.getStation();
while( station != null ){
if( station instanceof CommonDockStation<?,?>){
CStation<?> next = ((CommonDockStation<?,?>)station).getStation();
CStationContainer container = control.getRegister().getContainer( next );
if( container != null ){
return container;
}
}
Dockable dockable = station.asDockable();
if( dockable == null ){
return null;
}
station = dockable.getDockParent();
if( station == null ){
return null;
}
}
return null;
}
public Location rewrite( Dockable dockable, CLocationMode mode, Location history ){
CStation<?> replacement = null;
if( history != null ){
replacement = getMatchingStation( dockable, history.getRoot() );
}
if( replacement == null ){
replacement = getMatchingStation( dockable, mode.getExtendedMode() );
}
if( replacement == null ){
return history;
}
else{
if( history == null ){
return new Location( mode.getUniqueIdentifier(), replacement.getUniqueId(), null, false );
}
else{
return new Location( mode.getUniqueIdentifier(), replacement.getUniqueId(), history.getLocation(), history.isApplicationDefined() );
}
}
}
}