Package bibliothek.gui.dock.common.perspective

Source Code of bibliothek.gui.dock.common.perspective.CPerspective$ElementIterator

/*
* 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
* benjamin_sigg@gmx.ch
* 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.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}.<br>
* When using a {@link CPerspective} clients have to be aware of:
* <ul>
*   <li>Neither single- nor multiple-dockables need to be registered.</li>
<li>Any root-{@link CStation} used by a {@link CControl} needs to be registered using {@link #addRoot(CStationPerspective)}</li>
* </ul>
* @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<String, CStationPerspective> stations = new HashMap<String, CStationPerspective>();
 
  /** All the dockables known to this perspective, only updated on a call to {@link #storeLocations()} */
  private Map<String, CDockablePerspective> dockables = new HashMap<String, CDockablePerspective>();
 
  /** 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 <code>null</code>
   */
  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<PerspectiveElement> 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 <code>dockable</code> 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.<br>
   * 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 <code>null</code> if the location of
   * <code>dockable</code> 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 <code>id</code> is
   * already registered, then this station gets replaced.
   * @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 <code>id</code>.
   * @param id some unique identifier
   * @return the station associated with <code>id</code>, can be <code>null</code>
   */
  public CStationPerspective getStation( String id ){
    return stations.get( id );
  }
 
  /**
   * Searches for the {@link SingleCDockablePerspective} or {@link MultipleCDockablePerspective} whose
   * unique identifier is <code>id</code>. 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, <code>null</code> if <code>id</code> 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 <code>key</code> 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 <code>dockable</code> 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 <code>null</code>
   */
  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 <code>null</code>
   */
  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 <code>id</code>. 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 <code>getRoot( CControl.EXTERNALIZED_STATION_ID )</code>.<br>
   * @return the station or <code>null</code> 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<ShrinkablePerspectiveStation> elements = new ArrayList<ShrinkablePerspectiveStation>();
    Iterator<PerspectiveElement> 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<PerspectiveElement> 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<PerspectiveElement>{
    private LinkedList<ElementFrame> stack = new LinkedList<ElementFrame>();
   
    public ElementIterator(){
      List<PerspectiveElement> items = new ArrayList<PerspectiveElement>();
      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();
    }
  }
}
TOP

Related Classes of bibliothek.gui.dock.common.perspective.CPerspective$ElementIterator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.