/* Spatial Operations & Editing Tools for uDig * * Axios Engineering under a funding contract with: * Diputación Foral de Gipuzkoa, Ordenación Territorial * * http://b5m.gipuzkoa.net * http://www.axios.es * * (C) 2006, Diputación Foral de Gipuzkoa, Ordenación Territorial (DFG-OT). * DFG-OT agrees to license under Lesser General Public License (LGPL). * * 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; version 2.1 of the License. * * 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. */ package es.axios.udig.ui.editingtools.parallel; import net.refractions.udig.project.IBlackboard; import net.refractions.udig.project.IMap; import net.refractions.udig.project.ui.ApplicationGIS; import net.refractions.udig.project.ui.tool.IToolContext; import net.refractions.udig.tools.edit.Activator; import net.refractions.udig.tools.edit.EditToolHandler; import org.eclipse.jface.action.IAction; import org.eclipse.jface.viewers.ISelection; import org.eclipse.swt.graphics.Cursor; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.ToolItem; import org.eclipse.swt.widgets.Widget; import org.eclipse.ui.IActionDelegate; import org.eclipse.ui.IActionDelegate2; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.IWorkbenchWindowActionDelegate; import es.axios.udig.ui.editingtools.internal.commons.behaviour.DefaultEditPointProvider; import es.axios.udig.ui.editingtools.internal.commons.behaviour.IEditPointProvider; /** * Base class for actions triggered by an edit tool constraint, providing template and helper * methods to ease the task of adding behaviours or taking comlpete control of the currently active * edit tool. * <p> * Actionset actions configured to for the toolbarPath * <code>"net.refractions.udig.tool.edit.behaviour"</code> will be grouped together and should * extend this base class minimally by implementing {@link #activate(EditToolHandler)}. * </p> * * @author Aritz Davila (www.axios.es) * @author Mauricio Pazos (www.axios.es) * @since 0.2.0 */ public abstract class AbstractEditModifierActionDelegate implements IWorkbenchWindowActionDelegate, IActionDelegate2 { private EditToolContributorsActivator editToolContributorsActivator; /** * The edit tool handler active when this mode is activated. {@link #activate()} implementors * are free to modify its state. The original state will be restored on {@link #deactivate()} */ private EditToolHandler currentHandler; /** * @see IWorkbenchWindowActionDelegate#dispose() */ public final void dispose() { } /** * @see IActionDelegate2#init(IAction) */ public final void init( IAction action ) { } /** * @see IWorkbenchWindowActionDelegate#init(IWorkbenchWindow) */ public final void init( IWorkbenchWindow window ) { } /** * Shouldn't be called by the RCP, but {@link #runWithEvent(IAction, Event)} instead * * @see IActionDelegate#run(IAction) */ public final void run( IAction action ) { throw new UnsupportedOperationException("shouldn't be called. runWithEvent " + "should be called instead"); } /** * @see IActionDelegate#selectionChanged(IAction, ISelection) */ public final void selectionChanged( final IAction action, final ISelection selection ) { } public final void runWithEvent( final IAction action, final Event event ) { final IMap activeMap = ApplicationGIS.getActiveMap(); if (activeMap == null) { return; } final Widget widget = event.widget; final ToolItem toolItem = (ToolItem) widget; final boolean enabled = toolItem.getSelection(); final IBlackboard mapBlackBoard = activeMap.getBlackboard(); currentHandler = getEditToolHandler(mapBlackBoard); if (enabled) { editToolContributorsActivator = new EditToolContributorsActivator(); editToolContributorsActivator.activate(currentHandler); activate(); currentHandler.getActivators().add(editToolContributorsActivator); } else { deactivate(); } } /** * Obtains the currently being used edit tool handler (i.e. the {@link EditToolHandler} held in * the provided blackboard) * * @param blackboard the {@link IBlackboard map blackboard} from where to obtain the current * {@link EditToolHandler} * @return the {@link EditToolHandler} stored in the <code>blackboard</code> * @throws IllegalStateException if <code>blackboard</code> does not contains the * {@link EditToolHandler} */ private EditToolHandler getEditToolHandler( IBlackboard blackboard ) { final String key = EditToolHandler.class.getName(); final EditToolHandler currentHandler = (EditToolHandler) blackboard.get(key); if (currentHandler == null) { throw new IllegalStateException("the provided blackboard does not " + "holds the EditToolHandler"); } return currentHandler; } protected EditToolHandler getHandler() { return currentHandler; } /** * When called, it is granted that <code>currentHandler</code> is not null, and that * {@link #eventBehaviours} contains the current {@link EditToolHandler}'s event behaviours, * and modifying that list produces an immediate effect. * <p> * Implementations are allowed to modify the contents of the protected lists of behaviours * directly or to reconfigure <code>currentHandler</code> as they want. * </p> */ protected abstract void activate(); /** * Called when the modifier needs to be disabled because the user selected another modifier or * explicitly disabled the running one. * <p> * Restores the current {@link EditToolHandler}'s lists of behaviours to its original state. * </p> */ private final void deactivate() { editToolContributorsActivator.deactivate(currentHandler); } /** * Utility method for subclasses to temporally set a new {@link IEditPointProvider}. * <p> * The provider will last until another one is set or until the mode is deactivated. * </p> * * @param provider */ protected void setEditPointProvider( IEditPointProvider provider ) { editToolContributorsActivator.setEditPointProvider(currentHandler, provider); } /** * Adds and activates an Activator to the EditToolHandler's activators list * * @param handler * @param activator */ protected void addActivator( Activator activator ) { currentHandler.getActivators().add(activator); activator.activate(currentHandler); } /** * Restores and re-activates the orgiginal activators */ // protected void restoreOriginalActivators() { // editToolContributorsActivator.restoreOriginalActivators(currentHandler); // } /** * Removes and deactivates the currently running activators. The firs time called, it means the * current edit tool original ones, but nothing stops a subclass from calling this method more * than once. */ protected void removeRunningActivators() { editToolContributorsActivator.removeRunningActivators(currentHandler); } private static class EditToolContributorsActivator implements Activator { /** * Backup of the original edit point provider so it can be restored at deactivation time */ private IEditPointProvider originalEditPointProvider; /** * Internal handler used to backup the original activators and behaviours comming from the * handler in use so they can be restored at mode deactivation time and free subclasses to * extend or override the list of activators and handlers while they're active. */ private EditToolHandler backup; /** * Called when the mode using this instance has to be activated. */ public void activate( final EditToolHandler handler ) { final String key = IEditPointProvider.BLACKBOARD_KEY; final IBlackboard mapBlackBoard = getMapBlackboard(handler); originalEditPointProvider = (IEditPointProvider) mapBlackBoard.get(key); if (null == originalEditPointProvider) { originalEditPointProvider = new DefaultEditPointProvider(); setEditPointProvider(handler, originalEditPointProvider); } backup = new EditToolHandler((Cursor) null, (Cursor) null); backup.getActivators().addAll(handler.getActivators()); backup.getAcceptBehaviours().addAll(handler.getAcceptBehaviours()); backup.getBehaviours().addAll(handler.getBehaviours()); backup.getCancelBehaviours().addAll(handler.getCancelBehaviours()); } /** * Called when the current edit tool is deactivated (as a consecuence of this being an * {@link Activator}, or when the mode this instance is working on is deactivated (because * another one was selected). */ public void deactivate( EditToolHandler handler ) { removeRunningActivators(handler); restoreOriginalActivators(handler); handler.getActivators().clear(); handler.getAcceptBehaviours().clear(); handler.getBehaviours().clear(); handler.getCancelBehaviours().clear(); handler.getActivators().addAll(backup.getActivators()); handler.getAcceptBehaviours().addAll(backup.getAcceptBehaviours()); handler.getBehaviours().addAll(backup.getBehaviours()); handler.getCancelBehaviours().addAll(backup.getCancelBehaviours()); setEditPointProvider(handler, originalEditPointProvider); originalEditPointProvider = null; } public void setEditPointProvider( EditToolHandler handler, final IEditPointProvider provider ) { final IBlackboard mapBlackboard = getMapBlackboard(handler); mapBlackboard.put(IEditPointProvider.BLACKBOARD_KEY, provider); } private void restoreOriginalActivators( EditToolHandler currentHandler ) { for( Activator runnable : backup.getActivators() ) { try { currentHandler.getActivators().add(runnable); runnable.activate(currentHandler); } catch (Throwable error) { runnable.handleActivateError(currentHandler, error); } } } public void removeRunningActivators( EditToolHandler handler ) { for( Activator runnable : handler.getActivators() ) { if (runnable != this) { try { runnable.deactivate(handler); } catch (Throwable error) { runnable.handleDeactivateError(handler, error); } } } handler.getActivators().clear(); } private IBlackboard getMapBlackboard( final EditToolHandler handler ) { final IToolContext context = handler.getContext(); final IMap map = context.getMap(); final IBlackboard mapBlackboard = map.getBlackboard(); return mapBlackboard; } public void handleActivateError( EditToolHandler handler, Throwable error ) { // TODO: handle error.printStackTrace(); } public void handleDeactivateError( EditToolHandler handler, Throwable error ) { // TODO: handle error.printStackTrace(); } } }