Package bibliothek.gui.dock.facile.mode

Source Code of bibliothek.gui.dock.facile.mode.LocationModeManager$HierarchyListener

/*
* 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) 2009 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.facile.mode;

import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;

import bibliothek.gui.DockController;
import bibliothek.gui.DockStation;
import bibliothek.gui.Dockable;
import bibliothek.gui.dock.DockElement;
import bibliothek.gui.dock.action.DockActionSource;
import bibliothek.gui.dock.action.MultiDockActionSource;
import bibliothek.gui.dock.common.CControl;
import bibliothek.gui.dock.common.group.CGroupBehavior;
import bibliothek.gui.dock.common.group.CGroupBehaviorCallback;
import bibliothek.gui.dock.common.group.CGroupMovement;
import bibliothek.gui.dock.common.group.StackGroupBehavior;
import bibliothek.gui.dock.common.mode.ExtendedMode;
import bibliothek.gui.dock.control.DockRegister;
import bibliothek.gui.dock.control.focus.DefaultFocusRequest;
import bibliothek.gui.dock.control.relocator.DockRelocatorEvent;
import bibliothek.gui.dock.control.relocator.VetoableDockRelocatorAdapter;
import bibliothek.gui.dock.event.DockHierarchyEvent;
import bibliothek.gui.dock.event.DockHierarchyListener;
import bibliothek.gui.dock.event.DockRegisterAdapter;
import bibliothek.gui.dock.event.DoubleClickListener;
import bibliothek.gui.dock.facile.mode.status.DefaultExtendedModeEnablement;
import bibliothek.gui.dock.facile.mode.status.ExtendedModeEnablement;
import bibliothek.gui.dock.facile.mode.status.ExtendedModeEnablementFactory;
import bibliothek.gui.dock.facile.mode.status.ExtendedModeEnablementListener;
import bibliothek.gui.dock.layout.location.AsideRequest;
import bibliothek.gui.dock.layout.location.AsideRequestFactory;
import bibliothek.gui.dock.support.mode.AffectedSet;
import bibliothek.gui.dock.support.mode.AffectingRunnable;
import bibliothek.gui.dock.support.mode.ModeManager;
import bibliothek.gui.dock.support.mode.ModeManagerListener;
import bibliothek.gui.dock.util.DockProperties;
import bibliothek.gui.dock.util.IconManager;
import bibliothek.gui.dock.util.PropertyKey;
import bibliothek.gui.dock.util.PropertyValue;
import bibliothek.gui.dock.util.property.ConstantPropertyFactory;
import bibliothek.util.Path;

/**
* {@link ModeManager} for the location of a {@link Dockable}. This manager is able to
* work together with {@link CControl} or together with {@link DockController}. Clients
* using it together with a {@link DockController} need to set icons for the
* modes manually, they can use the {@link IconManager} and the keys provided in
* each mode (e.g. {@link NormalMode#ICON_IDENTIFIER}).
* @author Benjamin Sigg
* @param <M> the kind of mode this manager handles
*/
public class LocationModeManager<M extends LocationMode> extends ModeManager<Location, M>{
    /**
   * {@link PropertyKey} for the {@link ExtendedModeEnablement} that should be used
   * by a {@link LocationModeManager} to activate and deactivate the modes.
   */
  public static final PropertyKey<ExtendedModeEnablementFactory> MODE_ENABLEMENT =
    new PropertyKey<ExtendedModeEnablementFactory>( "locationmodemanager.mode_enablement",
        new ConstantPropertyFactory<ExtendedModeEnablementFactory>( DefaultExtendedModeEnablement.FACTORY ), true  );
 
  /**
   * {@link PropertyKey} for the {@link DoubleClickLocationStrategy} that should be used
   * to change the {@link ExtendedMode} of an element which has been double-clicked.
   */
  public static final PropertyKey<DoubleClickLocationStrategy> DOUBLE_CLICK_STRATEGY =
    new PropertyKey<DoubleClickLocationStrategy>( "locationmodemanager.double_click_strategy",
        new ConstantPropertyFactory<DoubleClickLocationStrategy>( DoubleClickLocationStrategy.DEFAULT ), true );
 
  /** a set of listeners that will be automatically added or removed from a {@link LocationMode} */
  private Map<Path, List<LocationModeListener>> listeners = new HashMap<Path, List<LocationModeListener>>();
 
  /** registers new dockables */
  private RegisterListener registerListener = new RegisterListener();
 
  /** registers when dockables change their position */
  private HierarchyListener hierarchyListener = new HierarchyListener();
 
  /** registers dragged and dropped dockables */
  private RelocatorListener relocatorListener = new RelocatorListener();
 
  /** how to group dockables */
  private CGroupBehavior behavior = new StackGroupBehavior();
 
  /** the action that is currently executing */
  private List<CGroupMovement> currentAction = new ArrayList<CGroupMovement>();
 
  /** the list of {@link Dockable}s for which {@link #refresh(Dockable, boolean)} has to be called */
  private LinkedHashSet<Dockable> pendingRefreshs = new LinkedHashSet<Dockable>();
 
  /** the current {@link ExtendedModeEnablementFactory} */
  private PropertyValue<ExtendedModeEnablementFactory> extendedModeFactory = new PropertyValue<ExtendedModeEnablementFactory>( MODE_ENABLEMENT ) {
    @Override
    protected void valueChanged( ExtendedModeEnablementFactory oldValue, ExtendedModeEnablementFactory newValue ){
      updateEnablement();
    }
  };
 
  /** the current {@link DoubleClickLocationStrategy} */
  private PropertyValue<DoubleClickLocationStrategy> doubleClickStrategy = new PropertyValue<DoubleClickLocationStrategy>( DOUBLE_CLICK_STRATEGY ) {
    @Override
    protected void valueChanged( DoubleClickLocationStrategy oldValue, DoubleClickLocationStrategy newValue ){
      // ignore
    }
  };
 
  /** a listener added to the current {@link #enablement} */
  private ExtendedModeEnablementListener enablementListener = new ExtendedModeEnablementListener() {
    public void availabilityChanged( Dockable dockable, ExtendedMode mode, boolean available ){
      refresh( dockable, true );
    }
  };
 
  /** detects double-click events and changes the mode of the clicked element */
  private DoubleClickListener doubleClickListener = new DoubleClickListener() {
    public DockElement getTreeLocation(){
      return null;
    }
   
    public boolean process( Dockable dockable, MouseEvent event ){
      if( event.isConsumed() )
        return false;
     
      dockable = getDoubleClickTarget( dockable );
      if( dockable != null ){
        M current = getCurrentMode( dockable );
        ExtendedMode next = getDoubleClickStrategy().handleDoubleClick( dockable, current == null ? null : current.getExtendedMode(), enablement );
        if( next != null && isModeAvailable( dockable, next )){
          setMode( dockable, next );
          ensureValidLocation( dockable );
          return true;
        }
      }
      return false;
    }
  };
 
  /** tells which modes are available for which element */
  private ExtendedModeEnablement enablement;

  /**
   * if > 0 then the layout-mode is active. In this mode this manager does not react on some
   * events to not intervene layouting
   */
  private int layoutMode = 0;
 
  /**
   * Creates a new manager.
   * @param controller the controller in whose realm this manager will work
   */
  public LocationModeManager( DockController controller ){
    super( controller );
    registerListener.connect( controller );
    controller.getRelocator().addVetoableDockRelocatorListener( relocatorListener );
   
    updateEnablement();
    extendedModeFactory.setProperties( controller );
   
    addModeManagerListener( new LocationModeListenerAdapter() );
   
    controller.getDoubleClickController().addListener( doubleClickListener );
  }
 
  public void destroy(){
    registerListener.connect( null );
    DockController controller = getController();
    controller.getRelocator().removeVetoableDockRelocatorListener( relocatorListener );
    controller.getDoubleClickController().removeListener( doubleClickListener );
   
    for( LocationMode mode : this.modes() ){
      mode.setController( null );
    }
   
    super.destroy();
    extendedModeFactory.setProperties( (DockProperties)null );
  }
 
  /**
   * Updates the current {@link ExtendedModeEnablement} using the factory
   * provided by {@link #MODE_ENABLEMENT}.
   */
  protected void updateEnablement(){
    if( enablement != null ){
      enablement.removeListener( enablementListener );
      enablement.destroy();
      enablement = null;
    }
    if( getController() != null ){
      enablement = extendedModeFactory.getValue().create( this );
      enablement.addListener( enablementListener );
    }
    rebuildAll();
  }
 
  /**
   * Sets the group behavior. The group behavior is applied if {@link #setMode(Dockable, ExtendedMode)} is called and
   * modifies the call such that another {@link Dockable} receives the event. Any call directly to any of
   * the <code>apply</code> methods will not be modified by the group behavior.
   * @param behavior the new behavior, not <code>null</code>
   */
  public void setGroupBehavior( CGroupBehavior behavior ){
    if( behavior == null ){
      throw new IllegalArgumentException( "the group behavior must not be null" );
    }
    this.behavior = behavior;
  }
 
  /**
   * Gets the current group behavior.
   * @return the current behavior, not <code>null</code>
   * @see #setGroupBehavior(CGroupBehavior)
   */
  public CGroupBehavior getGroupBehavior(){
    return behavior;
  }
 
  /**
   * Sets the current mode of <code>dockable</code>.
   * @param dockable the dockable whose mode is to be set
   * @param extendedMode the mode
   * @throws IllegalArgumentException if <code>extendedMode</code> is unknown
   */
  public void setMode( final Dockable dockable, final ExtendedMode extendedMode ){
    M mode = getMode( extendedMode.getModeIdentifier() );
    if( mode == null ){
      throw new IllegalArgumentException( "No mode '" + extendedMode.getModeIdentifier() + "' available" );
    }
 
    runTransaction( new Runnable(){
      public void run(){
        CGroupMovement action = behavior.prepare( LocationModeManager.this, dockable, extendedMode );
        if( action == null ){
          return;
        }
       
        apply( dockable, extendedMode, action );   
      }
    });
  }
 
  /**
   * Gets the action that is currently carried out.
   * @return the current action, can be <code>null</code>
   */
  public CGroupMovement getCurrentAction(){
    if( currentAction.isEmpty() ){
      return null;
    }
    return currentAction.get( currentAction.size()-1 );
  }
 
  /**
   * Executes <code>action</code> in a transaction assuming that the result of this action will lead to
   * <code>dockable</code> having the new mode <code>extendedMode</code>.
   * @param dockable the primary {@link Dockable}, this item may very well be the new focus owner
   * @param extendedMode the expected mode <code>dockable</code> will have after <code>action</code> completed
   * @param action the action to execute
   */
  public void apply( final Dockable dockable, final ExtendedMode extendedMode, final CGroupMovement action ){
    runTransaction( new AffectingRunnable(){
      public void run( final AffectedSet set ){
        try{
          getController().getFocusController().freezeFocus();
          currentAction.add( action );
          action.apply( new CGroupBehaviorCallback(){
            public void setMode( Dockable element, ExtendedMode mode ){
              apply( element, mode.getModeIdentifier(), false );
            }
           
            public void setLocation( Dockable element, Location location ){
              apply( element, location.getMode(), location, set );
            }
           
            public LocationModeManager<? extends LocationMode> getManager(){
              return LocationModeManager.this;
            }
           
            public Location getLocation( Dockable dockable ){
              M mode = getCurrentMode( dockable );
              if( mode == null ){
                return null;
              }
              return mode.current( dockable );
            }
          });
        }
        finally{
          currentAction.remove( action );
          getController().getFocusController().meltFocus();
        }
       
        LocationMode mode = getMode( extendedMode.getModeIdentifier() );
        if( mode != null ){
          if( mode.shouldAutoFocus() ){
            getController().setFocusedDockable( new DefaultFocusRequest( dockable, null, true, true, false ));
          }
          else{
            getController().setFocusedDockable( new DefaultFocusRequest( null, null, true ));
          }
        } 
      }
    });
  }
 
  /**
   * Gets the current mode of <code>dockable</code>.
   * @param dockable the element whose mode is searched
   * @return the mode or <code>null</code> if not found
   */
  public ExtendedMode getMode( Dockable dockable ){
    LocationMode mode = getCurrentMode( dockable );
    if( mode == null )
      return null;
    return mode.getExtendedMode();
  }
 
  /**
   * Checks all {@link LocationMode}s of this manager and returns all
   * {@link DockStation}s that were registered with the given id. The same
   * station or the same id might be used for different modes.
   * @param id the id of some station
   * @return each mode-area pair where the area is not <code>null</code>, can be empty
   */
  public Map<ExtendedMode, DockStation> getRepresentations( String id ){
    if( id == null )
      throw new IllegalArgumentException( "id must not be null" );
    Map<ExtendedMode, DockStation> result = new HashMap<ExtendedMode, DockStation>();
    for( LocationMode mode : modes() ){
      DockStation station = mode.getRepresentation( id );
      if( station != null ){
        result.put( mode.getExtendedMode(), station );
      }
    }
    return result;
  }
 
  /**
   * Ignores the call, the position of {@link Dockable}s is set elsewhere.
   */
  @Override
  protected void applyDuringRead( String key, Path old, Path current, Dockable dockable ){
    // ignore
  }
 
  /**
   * Using the current {@link ExtendedModeEnablement} this method tells whether
   * mode <code>mode</code> can be applied to <code>dockable</code>.
   * @param dockable some element, not <code>null</code>
   * @param mode some mode, not <code>null</code>
   * @return the result of {@link ExtendedModeEnablement#isAvailable(Dockable, ExtendedMode)}
   */
  public boolean isModeAvailable( Dockable dockable, ExtendedMode mode ){
    if( enablement == null )
      return false;
   
    return enablement.isAvailable( dockable, mode ).isAvailable();
  }
 
  /**
   * Using the current {@link ExtendedModeEnablement} this method tells whether
   * mode <code>mode</code> is hidden from the user when looking at <code>dockable</code>. A hidden
   * mode
   * @param dockable some element, not <code>null</code>
   * @param mode some mode, not <code>null</code>
   * @return the result of {@link ExtendedModeEnablement#isAvailable(Dockable, ExtendedMode)}
   */
  public boolean isModeHidden( Dockable dockable, ExtendedMode mode ){
    if( enablement == null )
      return false;
   
    return enablement.isHidden( dockable, mode ).isHidden();
  }
 
  /**
   * Adds a listener to the mode with unique identifier <code>identifier</code>. If the
   * mode is exchanged then this listener is automatically removed and may be re-added
   * to the new mode.
   * @param identifier the identifier of some mode (not necessarily registered yet).
   * @param listener the new listener, not <code>null</code>
   */
  public void addListener( Path identifier, LocationModeListener listener ){
    if( listener == null )
      throw new IllegalArgumentException( "listener must not be null" );
   
    List<LocationModeListener> list = listeners.get( identifier );
    if( list == null ){
      list = new ArrayList<LocationModeListener>();
      listeners.put( identifier, list );
    }
    list.add( listener );
   
    LocationMode mode = getMode( identifier );
    if( mode != null ){
      mode.addLocationModeListener( listener );
    }
  }
 
  /**
   * Removes a listener from the mode <code>identifier</code>.
   * @param identifier the name of a mode
   * @param listener the listener to remove
   */
  public void removeListener( Path identifier, LocationModeListener listener ){
    List<LocationModeListener> list = listeners.get( identifier );
    if( list == null )
      return;
   
    list.remove( listener );
    if( list.isEmpty() )
      listeners.remove( identifier );
   
    LocationMode mode = getMode( identifier );
    if( mode != null ){
      mode.removeLocationModeListener( listener );
    }
  }
 
  @Override
  public M getCurrentMode( Dockable dockable ){
    while( dockable != null ){
      for( M mode : modes() ){
        if( mode.isCurrentMode( dockable ))
          return mode;
      }
      DockStation station = dockable.getDockParent();
      dockable = station == null ? null : station.asDockable();
    }
   
    return null;
  }
 
  /**
   * Gets the current strategy for handing double-clicks.
   * @return the strategy, never <code>null</code>
   * @see #setDoubleClickStrategy(DoubleClickLocationStrategy)
   */
  public DoubleClickLocationStrategy getDoubleClickStrategy(){
    return doubleClickStrategy.getValue();
  }
 
  /**
   * Sets the current strategy for handling double-clicks on {@link Dockable}s. This
   * strategy will be asked what mode to assign to an element that has been double-clicked.
   * Results that are not allowed by the current {@link ExtendedModeEnablement} are ignored.
   * @param strategy the new strategy, can be <code>null</code> to set the default strategy
   */
  public void setDoubleClickStrategy( DoubleClickLocationStrategy strategy ){
    doubleClickStrategy.setValue( strategy );
  }
 
  /**
   * Tells whether this mode is currently in layouting mode. Some
   * methods of this manager do not react while in layouting mode.
   * @return <code>true</code> if layouting mode is active
   */
  public boolean isLayouting(){
    return layoutMode > 0;
  }
 
  /**
   * Activates the {@link #isLayouting() layout mode} while <code>run</code>
   * is running.
   * @param run some code to execute
   */
  public void runLayoutTransaction( Runnable run ){
    try{
      layoutMode++;
      runTransaction( run, true );
    }
    finally{
      layoutMode--;
    }
  }
 
    /**
     * Ensures that <code>dockable</code> is not hidden behind another
     * {@link Dockable}. That does not mean that <code>dockable</code> becomes
     * visible, just that it is easier reachable without the need to change
     * modes of any <code>Dockable</code>s.<br>
     * This method returns immediatelly if in {@link #isLayouting() layouting mode}
     * @param dockable the element which should not be hidden
     */
    public void ensureNotHidden( final Dockable dockable ){
      if( isLayouting() )
        return;
     
      runTransaction( new Runnable() {
      public void run(){
          for( LocationMode mode : modes() ){
            mode.ensureNotHidden( dockable );
         
      }
    });
    }
   
    /**
     * Empty method evaluating the correct location of a {@link Dockable}. To be
     * overridden by subclasses to handle elements which have additional restrictions.
     * @param dockable the element to check
     */
    public void ensureValidLocation( Dockable dockable ){
      // nothing
    }
   
    /**
     * Iterates through all the {@link LocationMode}s for which <code>aside</code> has stored locations,
     * and sets <code>dockable</code> as neighbor. This method does not change the actual location of <code>dockable</code>,
     * rather a call to <code>apply</code> would be necessary to update the location.<br>
     * It is the responsibility of the caller to ensure that <code>dockable</code> can actually be placed at any
     * location where <code>aside</code> ever was.
     * @param dockable the item whose location should change
     * @param aside the item whose neighbor is set
     */
    public void setLocationAside( Dockable dockable, Dockable aside ){
      M current = getCurrentMode( aside );
      List<M> history = getModeHistory( aside );
     
      for( M mode : history ){
        Location location;
        if( mode == current ){
          location = mode.current( aside );
        }
        else{
          location = getHistory( aside, mode.getUniqueIdentifier() );
        }
        if( location != null ){
          AsideRequestFactory factory = getController().getProperties().get( AsideRequest.REQUEST_FACTORY );
          AsideRequest request = factory.createAsideRequest( location.getLocation(), dockable );
         
          Location result = mode.aside( request, location );
          if( result != null ){
            addToModeHistory( dockable, mode, result );
          }
         
        }
      }
    }
   
    @Override
    public DockActionSource getSharedActions( DockStation station ){
      Dockable selected = station.getFrontDockable();
      if( selected == null ){
        return null;
      }
     
      LocationMode mode = getCurrentMode( selected );
      if( mode == null ){
        return null;
      }
     
      MultiDockActionSource result = new MultiDockActionSource();
     
      for( LocationMode other : modes() ){
        if( behavior.shouldForwardActions( this, station, selected, other.getExtendedMode() ) ){
          DockActionSource source = other.getActionsFor( selected, mode );
          if( source != null ){
            result.add( source );
          }
        }
      }
     
      return result;
    }
 
  /**
   * Adds and removes listeners from {@link LocationMode}s according to the map
   * {@link LocationModeManager#listeners}.
   * @author Benjamin Sigg
   */
  private class LocationModeListenerAdapter implements ModeManagerListener<Location, LocationMode>{
    public void modeAddedModeManager<? extends Location, ? extends LocationMode> manager, LocationMode mode ){
      mode.setManager( LocationModeManager.this );
      mode.setController( getController() );
     
      List<LocationModeListener> list = listeners.get( mode.getUniqueIdentifier() );
      if( list != null ){
        for( LocationModeListener listener : list ){
          mode.addLocationModeListener( listener );
        }
      }
    }
   
    public void modeRemoved( ModeManager<? extends Location, ? extends LocationMode> manager, LocationMode mode ){
      mode.setManager( null );
      mode.setController( null );
     
      List<LocationModeListener> list = listeners.get( mode.getUniqueIdentifier() );
      if( list != null ){
        for( LocationModeListener listener : list ){
          mode.removeLocationModeListener( listener );
        }
      }
    }
   
    public void dockableAdded( ModeManager<? extends Location, ? extends LocationMode> manager, Dockable dockable ){
      // ignore
    }

    public void dockableRemoved( ModeManager<? extends Location, ? extends LocationMode> manager, Dockable dockable ){
      // ignore
    }

    public void modeChanged( ModeManager<? extends Location, ? extends LocationMode> manager, Dockable dockable, LocationMode oldMode, LocationMode newMode ){
      // ignore 
    }   
  }

  /**
   * If the {@link DockRegister} is currently stalled, then a call to {@link LocationModeManager#refresh(Dockable, boolean)}
   * is scheduled, otherwise the call is performed directly.
   * @param dockable the dockable which should be forwarded to {@link LocationModeManager#refresh(Dockable, boolean)}
   */
  public void delayedRefresh( Dockable dockable ){
    if( getController().getRegister().isStalled() ){
      pendingRefreshs.add( dockable );
    }
    else{
      refresh( dockable, true );
    }
  }
 
  /**
   * This listener registers when {@link Dockable}s enter and leave and adds or
   * removes a {@link DockHierarchyListener}.
   * @author Benjamin Sigg
   */
  private class RegisterListener extends DockRegisterAdapter{
    private DockController controller;
   
    public void connect( DockController controller ){
      if( this.controller != null ){
        DockRegister register = this.controller.getRegister();
        register.removeDockRegisterListener( this );
        for( Dockable dockable : register.listDockables() ){
          dockable.removeDockHierarchyListener( hierarchyListener );
          rebuild( dockable );
        }
      }
      this.controller = controller;
      if( controller != null ){
        DockRegister register = controller.getRegister();
        register.addDockRegisterListener( this );
        for( Dockable dockable : register.listDockables() ){
          dockable.addDockHierarchyListener( hierarchyListener );
        }
      }
    }
   
    @Override
    public void dockableRegistered( DockController controller, Dockable dockable ){
      dockable.addDockHierarchyListener( hierarchyListener );
      rebuild( dockable );
    }
   
    @Override
    public void dockableUnregistered( DockController controller, Dockable dockable ){
      dockable.removeDockHierarchyListener( hierarchyListener );
    }
   
    @Override
    public void registerUnstalled( DockController controller ){
      while( pendingRefreshs.size() > 0 && !controller.getRegister().isStalled() ){
        Iterator<Dockable> iter = pendingRefreshs.iterator();
        Dockable next = iter.next();
        iter.remove();
        refresh( next, true );
      }
    }
  }
 
  /**
   * Reacts on dockables that are changing their position by calling
   * {@link LocationModeManager#refresh(Dockable, boolean)}.
   * @author Benjamin Sigg
   */
  private class HierarchyListener implements DockHierarchyListener{
    public void controllerChanged( DockHierarchyEvent event ){
      // ignore
    }

    public void hierarchyChanged( DockHierarchyEvent event ){
            if( !isOnTransaction() ){
              delayedRefresh( event.getDockable() );
           
    }   
  }
 
  /**
   * Detects the drag-operation and calls {@link LocationModeManager#store(Dockable)}.
   * @author Benjamin Sigg
   */
  private class RelocatorListener extends VetoableDockRelocatorAdapter{
    @Override
    public void dragging( DockRelocatorEvent event ){
      store( event.getDockable() );
      for( Dockable dockable : event.getImplicitDockables() ){
        store( dockable );
      }
        }
  }
}
TOP

Related Classes of bibliothek.gui.dock.facile.mode.LocationModeManager$HierarchyListener

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.