All Downloads are FREE. Search and download functionalities are using the official Maven repository.

bibliothek.gui.dock.common.perspective.CPerspective Maven / Gradle / Ivy

The newest version!
/*
 * 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) 2010 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.common.perspective;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;

import bibliothek.gui.DockStation;
import bibliothek.gui.Dockable;
import bibliothek.gui.dock.common.CContentArea;
import bibliothek.gui.dock.common.CControl;
import bibliothek.gui.dock.common.CControlRegister;
import bibliothek.gui.dock.common.CStation;
import bibliothek.gui.dock.common.SingleCDockableFactory;
import bibliothek.gui.dock.common.intern.CControlAccess;
import bibliothek.gui.dock.common.intern.CDockable;
import bibliothek.gui.dock.common.mode.CLocationMode;
import bibliothek.gui.dock.common.mode.CLocationModeManager;
import bibliothek.gui.dock.common.mode.ExtendedMode;
import bibliothek.gui.dock.common.perspective.mode.LocationModeManagerPerspective;
import bibliothek.gui.dock.common.perspective.mode.LocationModePerspective;
import bibliothek.gui.dock.facile.mode.Location;
import bibliothek.gui.dock.perspective.PerspectiveElement;
import bibliothek.gui.dock.perspective.PerspectiveStation;
import bibliothek.util.Todo;
import bibliothek.util.Todo.Compatibility;
import bibliothek.util.Todo.Priority;

/**
 * A {@link CPerspective} is a lightweight, modifiable representation of all {@link Dockable}s and {@link DockStation}s
 * handled by a {@link CControl}.
* When using a {@link CPerspective} clients have to be aware of: *
    *
  • Neither single- nor multiple-dockables need to be registered.
  • *
  • Any root-{@link CStation} used by a {@link CControl} needs to be registered using {@link #addRoot(CStationPerspective)}
  • *
* @author Benjamin Sigg */ @Todo( compatibility=Compatibility.COMPATIBLE, priority=Priority.MAJOR, description="remove the warning about modes without perspective" ) public class CPerspective { /** All the stations of this perspective */ private Map stations = new HashMap(); /** All the dockables known to this perspective, only updated on a call to {@link #storeLocations()} */ private Map dockables = new HashMap(); /** a manager for finding the location of {@link CDockablePerspective}s */ private LocationModeManagerPerspective locationModeManager; /** information about the {@link CControl} in whose realm this perspective is used */ private CControlAccess control; /** * Creates a new perspective * @param control the owner of this perspective */ public CPerspective( CControlAccess control ){ this.control = control; initLocations(); } private void initLocations(){ locationModeManager = new LocationModeManagerPerspective( this, control ); CLocationModeManager manager = control.getLocationManager(); for( CLocationMode mode : manager.modes() ){ LocationModePerspective perspective = mode.createPerspective(); if( perspective != null ){ locationModeManager.addMode( perspective ); } else{ System.err.println( "warning: mode " + mode.getClass() + " does not provide perspective" ); } } } /** * Gets the representation of the {@link CLocationModeManager}, the representation * is responsible for finding out what {@link ExtendedMode} and location a * {@link CDockablePerspective} has. * @return the location manager, not null */ public LocationModeManagerPerspective getLocationManager(){ return locationModeManager; } /** * Stores the current location of all {@link CDockablePerspective}s currently known to this * {@link CPerspective}. The location is stored in the {@link LocationHistory} of each * dockable. */ public void storeLocations(){ Iterator elements = elements(); while( elements.hasNext() ){ PerspectiveElement dockable = elements.next(); if( dockable instanceof CommonElementPerspective ){ CDockablePerspective cdockable = ((CommonElementPerspective)dockable).getElement().asDockable(); if( cdockable != null ){ storeLocation( cdockable ); } } } } /** * Determines the current location of dockable and stores that location * in a map using the {@link ExtendedMode} of the {@link Location} as key. If the * user later clicks on one of the buttons like "minimize" or "externalize" this * location information is read and applied.
* Also stores the dockables itself, if they are removed from their parents the perspective * still knows of their existence * @param dockable the element whose location should be stored * @return the location that was stored or null if the location of * dockable could not be determined */ public Location storeLocation( CDockablePerspective dockable ){ Location location = getLocationManager().getLocation( dockable ); if( location != null ){ dockable.getLocationHistory().add( getLocationManager().getMode( location.getMode() ), location ); String id = getId( dockable ); if( id != null ){ dockables.put( id, dockable ); } } return location; } private String getId( CDockablePerspective dockable ){ String id = null; if( dockable instanceof SingleCDockablePerspective ){ id = ((SingleCDockablePerspective)dockable).getUniqueId(); if( id != null ){ id = control.getRegister().toSingleId( id ); } } else if( dockable instanceof MultipleCDockablePerspective ){ id = ((MultipleCDockablePerspective)dockable).getUniqueId(); if( id != null ){ id = control.getRegister().toMultiId( id ); } } return id; } /** * Adds a new station to this perspective. If a station with name id is * already registered, then this station gets replaced.
* WARNING: the framework will not automatically create a {@link CStation}. The client needs * to register a {@link SingleCDockableFactory} in order to create the station when it is missing. * @param station the new station */ public void addStation( CStationPerspective station ){ if( station == null ){ throw new IllegalArgumentException( "station must not be null" ); } stations.put( station.getUniqueId(), station ); station.setPerspective( this ); } /** * Gets the station which was registered with the unique identifier id. * @param id some unique identifier * @return the station associated with id, can be null */ public CStationPerspective getStation( String id ){ return stations.get( id ); } /** * Searches for the {@link SingleCDockablePerspective} or {@link MultipleCDockablePerspective} whose * unique identifier is id. This method requires a call to {@link #storeLocations()} * before it will return any results. * @param id the unique identifier of a dockable, after {@link CControlRegister#toSingleId(String)} * or {@link CControlRegister#toMultiId(String)} has been applied. * @return the stored dockable, null if id is unknown or if * {@link #storeLocations()} was not executed */ public CDockablePerspective getDockable( String id ){ return dockables.get( id ); } /** * Gets all the unique keys for {@link SingleCDockablePerspective}s and {@link MultipleCDockablePerspective}s. * For this method to return the correct keys, {@link #storeLocations()} must have been executed. * @return the keys of all the dockables that are currently known */ public String[] getDockableKeys(){ return dockables.keySet().toArray( new String[ dockables.size() ] ); } /** * Removes the dockable with unique key key from the list of known dockables. If the * dockable is still part of the tree, and {@link #storeLocations()} is called, then the dockable * is reinserted into the list. * @param key the unique identifier of the element to remove * @return the element that was removed */ public CDockablePerspective removeDockable( String key ){ return dockables.remove( key ); } /** * Stores dockable in the list of known dockables. This allows * clients to add "invisible" dockables: {@link CDockable}s which are not yet visible * but which already have some location information stored. * @param dockable the new element, not null */ public void putDockable( CDockablePerspective dockable ){ if( dockable == null ){ throw new IllegalArgumentException( "dockable must not be null" ); } String id = getId( dockable ); if( id != null ){ dockables.put( id, dockable ); } } /** * Gets the names of all the stations that were registered * @return the names, not null */ public String[] getStationKeys(){ return stations.keySet().toArray( new String[ stations.size() ] ); } /** * Gets a representation of the default {@link CContentArea}. If there are no * stations for the perspective, then the missing stations are automatically * added to this perspective. * @return the area */ public CContentPerspective getContentArea(){ return getContentArea( CControl.CONTENT_AREA_STATIONS_ID ); } /** * Gets a representation of the {@link CContentArea} with identifier id. If there are no * stations for the perspective, then the missing stations are automatically * added to this perspective. * @param id the unique identifier of the area * @return the area */ public CContentPerspective getContentArea( String id ){ return new CContentPerspective( this, id ); } /** * Gets the {@link CStationPerspective} for the station that represents free floating dockables. This * is equivalent of calling getRoot( CControl.EXTERNALIZED_STATION_ID ).
* @return the station or null if there is no station registered with key * {@link CControl#EXTERNALIZED_STATION_ID} * @throws ClassCastException if the station named {@link CControl#EXTERNALIZED_STATION_ID} is not * of type {@link CExternalizePerspective} */ public CExternalizePerspective getScreenStation(){ return (CExternalizePerspective) getStation( CControl.EXTERNALIZED_STATION_ID ); } /** * Searches all occurances of a {@link ShrinkablePerspectiveStation} and calls * {@link ShrinkablePerspectiveStation#shrink() shrink} on them. */ public void shrink(){ List elements = new ArrayList(); Iterator iter = elements(); while( iter.hasNext() ){ PerspectiveElement next = iter.next(); if( next instanceof ShrinkablePerspectiveStation ){ elements.add( (ShrinkablePerspectiveStation)next ); } } for( ShrinkablePerspectiveStation station : elements ){ station.shrink(); } } /** * Gets an iterator that will visit all the {@link PerspectiveElement}s of this {@link CPerspective}. The * iterator does not check whether this perspective is modified while it is in use. * @return the iterator over all elements */ public Iterator elements(){ return new ElementIterator(); } private static class ElementFrame{ public PerspectiveElement[] items; public int offset; public ElementFrame( PerspectiveElement[] items ){ this.items = items; } } /** * An iterator over all the {@link PerspectiveElement}s that are currently stored in this * perspective. * @author Benjamin Sigg */ private class ElementIterator implements Iterator{ private LinkedList stack = new LinkedList(); public ElementIterator(){ List items = new ArrayList(); for( CStationPerspective station : stations.values() ){ if( station.asDockable() == null || station.asDockable().getParent() == null ){ items.add( station.intern() ); } } stack.addFirst( new ElementFrame( items.toArray( new PerspectiveElement[ items.size() ] ) ) ); } public boolean hasNext(){ for( ElementFrame frame : stack ){ if( frame.offset < frame.items.length ){ return true; } } return false; } public PerspectiveElement next(){ while( stack.size() > 0 ){ ElementFrame top = stack.peek(); if( top.offset < top.items.length ){ PerspectiveElement result = top.items[top.offset++]; PerspectiveStation station = result.asStation(); if( station != null ){ PerspectiveElement[] children = new PerspectiveElement[ station.getDockableCount() ]; for( int i = 0; i < children.length; i++ ){ children[ i ] = station.getDockable( i ); } stack.addFirst( new ElementFrame( children ) ); } return result; } stack.poll(); } throw new NoSuchElementException(); } public void remove(){ throw new UnsupportedOperationException(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy