/* uDig - User Friendly Desktop Internet GIS client
* http://udig.refractions.net
* (C) 2004-2012, Refractions Research Inc.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD
* License v1.0 (http://udig.refractions.net/files/bsd3-v10.html).
*/
package org.locationtech.udig.project.ui.internal.tool.display;
import java.awt.AWTException;
import java.awt.Robot;
import java.awt.event.KeyEvent;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.locationtech.udig.catalog.IGeoResource;
import org.locationtech.udig.core.filter.AdaptingFilter;
import org.locationtech.udig.core.filter.AdaptingFilterFactory;
import org.locationtech.udig.core.internal.ExtensionPointList;
import org.locationtech.udig.internal.ui.UDIGDNDProcessor;
import org.locationtech.udig.internal.ui.UDIGDropHandler;
import org.locationtech.udig.internal.ui.UDigByteAndLocalTransfer;
import org.locationtech.udig.internal.ui.UiPlugin;
import org.locationtech.udig.internal.ui.operations.OperationCategory;
import org.locationtech.udig.internal.ui.operations.OperationMenuFactory;
import org.locationtech.udig.internal.ui.operations.RunOperationsAction;
import org.locationtech.udig.project.EditManagerEvent;
import org.locationtech.udig.project.IEditManagerListener;
import org.locationtech.udig.project.ILayer;
import org.locationtech.udig.project.IMap;
import org.locationtech.udig.project.internal.Map;
import org.locationtech.udig.project.internal.ProjectPackage;
import org.locationtech.udig.project.internal.commands.CreateMapCommand;
import org.locationtech.udig.project.ui.ApplicationGIS;
import org.locationtech.udig.project.ui.internal.ApplicationGISInternal;
import org.locationtech.udig.project.ui.internal.MapEditor;
import org.locationtech.udig.project.ui.internal.MapEditorPart;
import org.locationtech.udig.project.ui.internal.MapEditorWithPalette;
import org.locationtech.udig.project.ui.internal.MapPart;
import org.locationtech.udig.project.ui.internal.Messages;
import org.locationtech.udig.project.ui.internal.ProjectUIPlugin;
import org.locationtech.udig.project.ui.internal.actions.Delete;
import org.locationtech.udig.project.ui.internal.tool.ToolContext;
import org.locationtech.udig.project.ui.internal.tool.impl.ToolContextImpl;
import org.locationtech.udig.project.ui.tool.IContextMenuContributionTool;
import org.locationtech.udig.project.ui.tool.IToolManager;
import org.locationtech.udig.project.ui.tool.ModalTool;
import org.locationtech.udig.project.ui.tool.Tool;
import org.locationtech.udig.project.ui.tool.ToolConstants;
import org.locationtech.udig.project.ui.tool.options.PreferencesShortcutToolOptionsContributionItem;
import org.locationtech.udig.project.ui.viewers.MapEditDomain;
import org.locationtech.udig.ui.IDropAction;
import org.locationtech.udig.ui.IDropHandlerListener;
import org.locationtech.udig.ui.UDIGDragDropUtilities;
import org.locationtech.udig.ui.ViewerDropLocation;
import org.locationtech.udig.ui.operations.LazyOpFilter;
import org.locationtech.udig.ui.operations.OpAction;
import org.locationtech.udig.ui.operations.OpFilter;
import org.eclipse.core.commands.Command;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.impl.AdapterImpl;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.ContributionItem;
import org.eclipse.jface.action.GroupMarker;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.action.IMenuCreator;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.action.StatusLineManager;
import org.eclipse.jface.action.SubCoolBarManager;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.HelpListener;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.widgets.Event;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IKeyBindingService;
import org.eclipse.ui.ISelectionService;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.SubActionBars2;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction;
import org.eclipse.ui.commands.ICommandService;
import org.eclipse.ui.dialogs.PropertyDialogAction;
import org.eclipse.ui.part.EditorPart;
import org.eclipse.ui.part.ViewPart;
import org.opengis.filter.Filter;
/**
* Manages Edit tools activation and registration.
* <p>
* The tool manager is a used by the MapEditor to populate the
* menu and action bars. It is responsible for processing the tools
* extension point and making action contributions as needed.
* <p>
* New for uDig 1.1:
* <ul>
* <li>We will check for an ActionSet with the same name as the tool category,
* this will allow you to turn off actions that don't make sense for your current
* workflow (ie perspective change).
* </ul>
*
* @author Jesse Eichar (Refractions Research Inc)
* @since 0.6.0
*/
public class ToolManager implements IToolManager {
/**
* This is a list of all tool actions(buttons) that are not part of the editor toolbar. For
* example the info view may have a tool as part of its toolbar which is a proxy for the real
* tool on the editor view.
*/
Set<IAction> registeredToolActions = new HashSet<IAction>();
/**
* List of categorieIds; these may or may not be
* associated with an ActionSet.
*/
protected List<String> categoryIds = new ArrayList<String>();
/**
* These represent modal tools that complete take over the map.
*/
List<ModalToolCategory> modalCategories = new LinkedList<ModalToolCategory>();
/**
* These represent fire and forget actions like zoomIn and zoomOut.
*/
List<ActionToolCategory> actionCategories = new LinkedList<ActionToolCategory>();
/**
* These represent additions made to the menu.
*/
List<MenuToolCategory> menuCategories = new LinkedList<MenuToolCategory>();
/**
*
* I think these are the tools that lurk in the background updating state
* like the status bar.
*/
List<ToolProxy> backgroundTools = new LinkedList<ToolProxy>();
/**
* Shared images assoicated with these tools; used for everything from
* cursors to button icons.
*/
ISharedImages sharedImages = PlatformUI.getWorkbench().getSharedImages();
/**
* Cache of all configured cursors.
*/
protected java.util.Map<String, CursorProxy> cursorsCache = new HashMap<String, CursorProxy>();
/**
* Proxy for the active tool (ie statue of the editor).
* <p>
* The category of this tool will behave a little like a persepctive; since
* the nature of the editor changes complety with the current tool. As such
* the Edit menu may change what actions are available based on what subject
* matter this tool is working on.
*/
private ToolProxy activeModalToolProxy;
/**
* Current active tool; this represents the state of the editor.
* <p>
* This is considered an internal detail of ToolManager.
*/
private ModalTool activeTool;
/**
* Default modal tool. This tool is set during initialisation of
* tools by ToolProxy.DEFAULT_ID.
*/
ToolProxy defaultModalToolProxy;
Lock redoLock=new ReentrantLock();
Lock undoLock=new ReentrantLock();
Lock forwardLock=new ReentrantLock();
Lock backwardLock=new ReentrantLock();
Lock deleteLock=new ReentrantLock();
Lock enterLock=new ReentrantLock();
Lock pasteLock=new ReentrantLock();
Lock propertiesLock=new ReentrantLock();
Lock copyLock=new ReentrantLock();
Lock cutLock=new ReentrantLock();
private volatile IAction redoAction;
private volatile IAction undoAction;
private volatile IAction forwardAction;
private volatile IAction backwardAction;
private volatile IAction deleteAction;
private volatile IAction enterAction;
private volatile IAction zoomToSelectionAction;
private volatile IAction pasteAction;
private volatile IAction copyAction;
private volatile IAction cutAction;
private AdapterImpl commandListener;
private List<ContributionItem> optionsContribution = new ArrayList<ContributionItem>();
/**
* Construct <code>ToolManager</code>.
*/
public ToolManager() {
processCategories();
processTools();
removeEmptyCategories();
Collections.sort(categoryIds, new CategorySorter());
setCommandHandlers();
}
/**
* Populates the categories with their associated tools
*/
private void processTools() {
List<IConfigurationElement> extensionList = ExtensionPointList
.getExtensionPointList(Tool.EXTENSION_ID);
for( IConfigurationElement element : extensionList ) {
IExtension extension = element.getDeclaringExtension();
String type = element.getName();
if (type.equals("backgroundTool")) { //$NON-NLS-1$
ToolProxy proxy = new ToolProxy(extension, element, this);
backgroundTools.add(proxy);
} else if (type.equals("modalTool")) { //$NON-NLS-1$
String categoryId = getCategoryIdAttribute(element); //$NON-NLS-1$
ToolProxy proxy = new ToolProxy(extension, element, this);
addToModalCategory(categoryId, proxy);
} else if (type.equals("actionTool")) { //$NON-NLS-1$
String categoryId = getCategoryIdAttribute(element); //$NON-NLS-1$
ToolProxy proxy = new ToolProxy(extension, element, this);
addToActionCategory(categoryId, proxy);
addToMenuCategory(categoryId, proxy);
}else if(type.equals("toolCursor")){ //$NON-NLS-1$
CursorProxy cursorProxy = new CursorProxy(element);
cursorsCache.put(cursorProxy.getID(), cursorProxy);
}
}
if( activeModalToolProxy == null ){
activeModalToolProxy = defaultModalToolProxy;
}
}
private String getCategoryIdAttribute(IConfigurationElement element) {
String id = element.getAttribute("categoryId");
return id == null? "" : id;
}
/**
* Finds cursor proxy by ID in cache.
*/
public Cursor findToolCursor(String cursorID){
CursorProxy cursorProxy = cursorsCache.get(cursorID);
if(cursorProxy != null)
return cursorProxy.getCursor();
Cursor systemCursor = CursorProxy.getSystemCursor(cursorID);
if(systemCursor != null)
return systemCursor;
return null;
}
/**
* Find a tool with the provided ID.
* <p>
* In the current implementation finds only among modal tools.
* TODO Extend findTool to search for non modal tools
* @param toolID toolId to search for
* @return Modal tool if found, or null
*/
public Tool findTool(String toolID) {
for(ModalToolCategory category : modalCategories){
for (ModalItem item : category) {
if(toolID.equals(item.getId())){
return ((ToolProxy)item).getTool();
}
}
}
return null;
}
/**
* Find a tool proxy with the provided ID.
* <p>This searches modal tools, background tools, and
* action tools</p>
* @param toolID toolId to search for
* @return ToolProxy of tool if found or null
*/
public ToolProxy findToolProxy(String toolID) {
for(ModalToolCategory category : modalCategories){
for (ModalItem item : category) {
if(toolID.equals(item.getId())){
return (ToolProxy)item;
}
}
}
for(ActionToolCategory category : actionCategories){
for (ModalItem item : category) {
if(toolID.equals(item.getId())){
return (ToolProxy)item;
}
}
}
for(ToolProxy item : backgroundTools){
if(toolID.equals(item.getId())){
return (ToolProxy)item;
}
}
return null;
}
private void addToModalCategory( String categoryId, ToolProxy proxy ) {
if( filterTool(categoryId, proxy, ModalToolCategory.class) ){
return;
}
ModalToolCategory modalCategory = findModalCategory(categoryId);
if (modalCategory == null) {
modalCategory = findModalCategory(Messages.ToolCategory_other);
if (modalCategory == null) {
modalCategory = new ModalToolCategory(this);
modalCategories.add(modalCategory);
if (!categoryIds.contains(Messages.ToolCategory_other))
categoryIds.add(Messages.ToolCategory_other);
}
}
modalCategory.add(proxy);
}
/**
* This method is called each time an action is about to be added to a category.
* If the message returns true the tool <b>will not</b> be added.
* The default implementation always returns false.
*
* @param categoryId the id of the category that the tool will be added to, this will never be null
* @param proxy the proxy for the tool.
* @param categoryType the type of category
*
* @return true if the tool will NOT be added to the category
*/
protected boolean filterTool( String categoryId, ToolProxy proxy, Class<? extends ToolCategory> categoryType ) {
return false;
}
private void addToMenuCategory( String categoryId, ToolProxy proxy ) {
if( filterTool(categoryId, proxy, MenuToolCategory.class) ){
return;
}
MenuToolCategory category = findMenuCategory(categoryId);
if (category == null) {
category = findMenuCategory(Messages.ToolCategory_other);
if (category == null) {
category = new MenuToolCategory(this);
menuCategories.add(category);
if (!categoryIds.contains(Messages.ToolCategory_other))
categoryIds.add(Messages.ToolCategory_other);
}
}
category.add(proxy);
}
private void addToActionCategory( String categoryId, ToolProxy proxy ) {
if( filterTool(categoryId, proxy, ActionToolCategory.class) ){
return;
}
ActionToolCategory category = findActionCategory(categoryId);
if (category == null) {
category = findActionCategory(Messages.ToolCategory_other);
if (category == null) {
category = new ActionToolCategory(this);
actionCategories.add(category);
if (!categoryIds.contains(Messages.ToolCategory_other))
categoryIds.add(Messages.ToolCategory_other);
}
}
category.add(proxy);
}
/**
* Processes the extension point and creates all the categories.
*/
private void processCategories() {
List<IConfigurationElement> extension = ExtensionPointList
.getExtensionPointList(Tool.EXTENSION_ID);
for( IConfigurationElement element : extension ) {
if (!element.getName().equals("category")) //$NON-NLS-1$
continue;
ModalToolCategory modalCategory;
String id = element.getAttribute("id"); //$NON-NLS-1$
categoryIds.add(id);
modalCategory = findModalCategory(id);
if (modalCategory == null) {
modalCategory = new ModalToolCategory(element, ToolManager.this);
modalCategories.add(modalCategory);
}
ActionToolCategory actionCategory;
actionCategory = findActionCategory(id);
if (actionCategory == null) {
actionCategory = new ActionToolCategory(element, ToolManager.this);
actionCategories.add(actionCategory);
}
MenuToolCategory category;
category = findMenuCategory(id);
if (category == null) {
category = new MenuToolCategory(element, ToolManager.this);
menuCategories.add(category);
}
}
}
private void removeEmptyCategories() {
List<ToolCategory> toRemove = new ArrayList<ToolCategory>();
for( ActionToolCategory category : actionCategories ) {
if (category.items.size() == 0)
toRemove.add(category);
}
actionCategories.removeAll(toRemove);
for( ModalToolCategory category : modalCategories ) {
if (category.items.size() == 0)
toRemove.add(category);
}
modalCategories.removeAll(toRemove);
for( MenuToolCategory category : menuCategories ) {
if (category.items.size() == 0)
toRemove.add(category);
}
menuCategories.removeAll(toRemove);
}
/**
* Register commands handlers; so they can be used by the keyboard short cut system.
*/
private void setCommandHandlers() {
Set<String> ids = new HashSet<String>();
ICommandService service = (ICommandService) PlatformUI.getWorkbench().getAdapter(
ICommandService.class);
for( ModalToolCategory category : modalCategories ) {
if (!ids.contains(category.getId())) {
ids.add(category.getId());
category.setCommandHandlers(service);
}
registerCommands(ids, service, category);
}
for( ActionToolCategory category : actionCategories ) {
if (!ids.contains(category.getId())) {
ids.add(category.getId());
category.setCommandHandlers(service);
}
registerCommands(ids, service, category);
}
for( MenuToolCategory category : menuCategories ) {
if (!ids.contains(category.getId())) {
ids.add(category.getId());
category.setCommandHandlers(service);
}
registerCommands(ids, service, category);
}
}
/**
* Register commands; so they can be picked up by command handlers.
* <p>
* These command/handler system is used to hook our tools up to the keyboard
* short cut system.
* <p>
* @param ids
* @param service
* @param category
*/
private void registerCommands( Set<String> ids, ICommandService service, ToolCategory category ) {
for( ModalItem tool : category ) {
if (!ids.contains(tool.getId())) {
ids.add(category.getId());
for( String currentId : tool.getCommandIds() ) {
currentId=currentId.trim();
Command command = service.getCommand(currentId);
if (command != null)
command.setHandler(tool.getHandler(currentId));
}
}
}
}
MapPart currentEditor;
/**
* This method is called to perform tools initialisation when
* the map editor is selected.
*/
public void setCurrentEditor( MapPart editor ) {
if( editor==currentEditor ){
return;
}
currentEditor = editor;
if (editor != null) {
if (editor != null) {
setActiveTool(editor);
setEnabled(editor.getMap(), actionCategories);
setEnabled(editor.getMap(), menuCategories);
setEnabled(editor.getMap(), modalCategories);
}
} else {
disable(actionCategories);
disable(menuCategories);
disable(modalCategories);
}
}
/**
* Churn through the category disabling all tools.
*
* @param categories
*/
private void disable( List<? extends ToolCategory> categories ) {
for( ToolCategory category : categories ) {
for( ModalItem item : category ) {
OpFilter enablesFor = item.getEnablesFor();
if( enablesFor instanceof LazyOpFilter)
((LazyOpFilter)enablesFor).disable();
}
}
}
EditManagerListener selectedLayerListener;
private PropertyDialogAction propertiesAction;
/**
* Listener for EditManager.
*
* @author Vitalus
*
*/
class EditManagerListener implements IEditManagerListener{
public void setCurrentMap(IMap map){
}
public void changed( EditManagerEvent event ) {
if (selectedLayerListener != this) {
event.getSource().removeListener(this);
return;
}
if (event.getType() == EditManagerEvent.SELECTED_LAYER) {
setEnabled(event.getSource().getMap(), actionCategories);
setEnabled(event.getSource().getMap(), menuCategories);
setEnabled(event.getSource().getMap(), modalCategories);
}
}
}
/**
* Heads through the categories giving each tool a chance to enable/disable itself.
* <p>
* Specifically we grab the OpFilter and give it a chance to determine if
* the tool is enabled; currently OpFilter is focused on the selectedLayer
* but I hope to break this out to process more general "core expressions"
* in the future (but we have to wait for someone to ask first).
*
* @param map
* @param categories
*/
private void setEnabled( IMap map, Collection<? extends ToolCategory> categories) {
if(selectedLayerListener == null)
selectedLayerListener = new EditManagerListener();
selectedLayerListener.setCurrentMap(map);
//One listener is enough. Say NO to listeners hell:)
if(!map.getEditManager().containsListener(selectedLayerListener))
map.getEditManager().addListener(selectedLayerListener);
for( ToolCategory cat : categories ) {
for( ModalItem item : cat ) {
OpFilter enablesFor = item.getEnablesFor();
ILayer selectedLayer = map.getEditManager().getSelectedLayer();
// JG: I don't trust asserts in production code!
// assert enablesFor instanceof LazyOpFilter;
if( !(enablesFor instanceof LazyOpFilter) ){
enablesFor = new LazyOpFilter(item, enablesFor);
}
boolean accept = enablesFor.accept(selectedLayer);
item.setEnabled(accept);
}
}
}
/**
* Sets the context of the currently active tool and ensures that all tools are enabled.
* <p>
* This is called by the "support views" associated with the MapEditor,
* it is used so the tools can be active even when the MapEditor does not have the focus.
* Without this modification you would need to constantly select the MapEditor, change the tool
* and then get to work.
* <p>
* Aside: it would be good if selecting a tool made the MapEditor grab focus.
* <p>
* @param editor MapEditor associated with the support view (such as the Layers view)
*/
@SuppressWarnings("unchecked")
void setActiveTool( MapPart editor ) {
// ensure we are listening to this MapPart's Map
Map map = editor.getMap();
Adapter listener = getCommandListener(editor);
if (!map.eAdapters().contains(listener)){
map.eAdapters().add(listener);
}
// Define the tool context allowing tools to interact with this map
ToolContext tools = new ToolContextImpl();
tools.setMapInternal(map);
// Provide each tool with the new tool context
//
setContext(modalCategories, tools); // if active a modal tool is supposed to register listeners
setContext(actionCategories, tools);
setContext(menuCategories, tools);
for( ToolProxy tool : backgroundTools ) {
tool.setContext(tools);
}
for( IAction action : registeredToolActions){
action.setEnabled(true);
}
setCommandActions(map, editor);
// wire in the current activeModalTool
if( activeModalToolProxy != null ){
if( !activeModalToolProxy.isActive() ){
// work around to allow the 1st modal tool to be active
if( activeTool == null ){
activeTool = activeModalToolProxy.getModalTool();
// add tool options to the status area
initToolOptionsContribution(editor.getStatusLineManager(), activeModalToolProxy);
}
activeModalToolProxy.getModalTool().setActive(true);
}
editor.setSelectionProvider(activeModalToolProxy.getSelectionProvider());
if( editor instanceof MapEditorWithPalette){
// temporary cast while we sort out if MapPart can own an MapEditDomain
MapEditorWithPalette editor2 = (MapEditorWithPalette) editor;
MapEditDomain editDomain = editor2.getEditDomain();
editDomain.setActiveTool( activeModalToolProxy.getId() );
}
}
}
/**
* Go through List of ToolCategory and update each Tool with the new tool context.
* @param categories
* @param tools
*/
private void setContext( List<? extends ToolCategory> categories, ToolContext tools ) {
for( ToolCategory category : categories ) {
for(ModalItem item : category.items ) {
ToolProxy tool = (ToolProxy) item;
tool.setContext(tools);
}
}
}
/**
* Adds an Action that executes a tool to the toolbar.
*
* @param action
*/
public void addToolAction( IAction action ) {
registeredToolActions.add(action);
action.setEnabled(ApplicationGIS.getActiveMap() != ApplicationGIS.NO_MAP);
}
/**
* Creates a action that acts as a proxy for the tool in the editor toolbar.
* <p>
* The client code must set the name image descriptor etc... of the Action
* </p>
*
* @param toolID the id of the tool
* @param categoryID the category the tool is part of
* @return a proxy action that can be put in other toolbars
*/
public IAction createToolAction( final String toolID, final String categoryID ) {
final IAction toolAction = new Action(){
@Override
public void runWithEvent( Event event ) {
IAction action = getTool(toolID, categoryID);
if (action != null && action.isEnabled()) {
action.runWithEvent(event );
}
}
};
toolAction.addPropertyChangeListener(new IPropertyChangeListener(){
public void propertyChange( PropertyChangeEvent event ) {
if( event.getProperty().equals(IAction.ENABLED)){
toolAction.setEnabled((Boolean) event.getNewValue());
}
}
});
toolAction.setEnabled(getTool(toolID, categoryID).isEnabled());
addToolAction(toolAction);
return toolAction;
}
public ActionToolCategory findActionCategory( String id ) {
for( ActionToolCategory category : actionCategories ) {
if (category.getId().equals(id))
return category;
}
return null;
}
MenuToolCategory findMenuCategory( String id ) {
for( MenuToolCategory category : menuCategories ) {
if (category.getId().equals(id))
return category;
}
return null;
}
protected ModalToolCategory findModalCategory( String id ) {
for( ModalToolCategory category : modalCategories ) {
String id2 = category.getId();
if (id2.equals(id))
return category;
}
return null;
}
/**
* Used to contribute Tools to the provided menu manger.
* <p>
* The following contributions are made:
* <ul>
* <li>navigate: forward and backward buttons
* <li>map: an entry for each tool category
* </ul>
*/
public void contributeToMenu( IMenuManager manager ) {
IMenuManager navigateMenu = manager.findMenuUsingPath(IWorkbenchActionConstants.M_NAVIGATE);
if (navigateMenu == null) {
// I would like to arrange for the Navigate menu to already
// be in place before the ToolManager is kicked into action
// (this is part of the missions to have uDig plugins walk
// softly when being hosted in other RCP applications)
// See UDIGActionBarAdvisor for hosting requirements.
navigateMenu = new MenuManager(
Messages.ToolManager_menu_manager_title, IWorkbenchActionConstants.M_NAVIGATE);
IContributionItem additions = manager.find(IWorkbenchActionConstants.MB_ADDITIONS);
if( additions==null || !(additions instanceof GroupMarker) ){
manager.add(navigateMenu);
}else{
manager.appendToGroup(IWorkbenchActionConstants.MB_ADDITIONS, navigateMenu);
}
navigateMenu.add(new GroupMarker(IWorkbenchActionConstants.NAV_START));
navigateMenu.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));
navigateMenu.add(new GroupMarker(IWorkbenchActionConstants.NAV_END));
}
IWorkbench workbench = PlatformUI.getWorkbench();
IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
// we are using the global BACK and FORWARD actions here
// and will register "handlers" for these commands
navigateMenu.appendToGroup(IWorkbenchActionConstants.NAV_END,
ActionFactory.BACK.create(window));
navigateMenu.appendToGroup(IWorkbenchActionConstants.NAV_END,
ActionFactory.FORWARD.create(window));
if (!manager.isVisible()){
// since this is the top level menu bar why would it not be visible?
manager.setVisible(true);
}
IMenuManager mapMenu = manager.findMenuUsingPath("map");
if( mapMenu == null ){
// Once again the hosting RCP application should of provided
// us with a Map menu; but let's be careful and make our own here
// if needed.
// See UDIGActionBarAdvisor for hosting requirements.
mapMenu = new MenuManager(Messages.ToolManager_menu_manager_title, "map");
manager.add(mapMenu);
mapMenu.add(new GroupMarker("mapStart"));
mapMenu.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));
mapMenu.add(new GroupMarker("mapEnd"));
}
// churn through each category and add stuff as needed
// note we check with the cmdService to see what we if the actionSet
// associated with this cateogry is turned on by the
// current perspective.
for( MenuToolCategory category : menuCategories ) {
category.contribute(manager);
}
}
/** (non-Javadoc)
*
* @see org.locationtech.udig.project.ui.tool.IToolManager#contributeActiveModalTool(org.eclipse.jface.action.IMenuManager)
*/
public void contributeActiveModalTool( IMenuManager manager ) {
Tool activeTool = getActiveTool();
if(activeTool instanceof IContextMenuContributionTool){
IContextMenuContributionTool contributionTool = (IContextMenuContributionTool)activeTool;
ArrayList<IContributionItem> contributions = new ArrayList<IContributionItem>();
contributionTool.contributeContextMenu(contributions);
if(!contributions.isEmpty()){
manager.add(new Separator());
for( IContributionItem item : contributions ) {
manager.add(item);
}
}
}
}
/**
* Retrieves the redo action that is used by much of the map components such as the MapEditor
* and the LayersView. redoes the last undone command sent to the currently active map.
*/
public IAction getREDOAction() {
Map activeMap = ApplicationGISInternal.getActiveMap();
redoLock.lock();
try{
if (redoAction == null) {
redoAction = new Action(){
/**
* @see org.eclipse.jface.action.Action#run()
*/
public void run() {
Map activeMap = ApplicationGISInternal.getActiveMap();
if (activeMap != ApplicationGIS.NO_MAP)
activeMap.redo();
}
};
redoAction.setImageDescriptor(sharedImages
.getImageDescriptor(ISharedImages.IMG_TOOL_REDO));
redoAction.setText(Messages.ToolManager_redoAction);
redoAction.setActionDefinitionId("org.eclipse.ui.edit.redo"); //$NON-NLS-1$
}
if (activeMap != ApplicationGIS.NO_MAP)
redoAction.setEnabled(activeMap.getCommandStack().canRedo());
else
redoAction.setEnabled(false);
return redoAction;
}finally{
redoLock.unlock();
}
}
/**
*
*/
public void setREDOAction( IAction action, IWorkbenchPart part ) {
if( action == null )
throw new NullPointerException("action must not be null"); //$NON-NLS-1$
if( part == null )
throw new NullPointerException("part must not be null"); //$NON-NLS-1$
redoLock.lock();
try {
redoAction = action;
redoAction.setActionDefinitionId("org.eclipse.ui.edit.redo"); //$NON-NLS-1$
IKeyBindingService service = part.getSite().getKeyBindingService();
service.registerAction(redoAction);
} finally {
redoLock.unlock();
}
}
/**
* Retrieves the undo action that is used by much of the map components such as the MapEditor
* and the LayersView. Undoes the last command sent to the currently active map.
*
* @param part
*/
public IAction getUNDOAction() {
Map activeMap = ApplicationGISInternal.getActiveMap();
undoLock.lock();
try{
if (undoAction == null) {
undoAction = new Action(){
/**
* @see org.eclipse.jface.action.Action#run()
*/
public void run() {
Map activeMap = ApplicationGISInternal.getActiveMap();
if (activeMap != ApplicationGIS.NO_MAP)
activeMap.undo();
}
};
undoAction.setImageDescriptor(sharedImages
.getImageDescriptor(ISharedImages.IMG_TOOL_UNDO));
undoAction.setText(Messages.ToolManager_undoAction);
undoAction.setActionDefinitionId("org.eclipse.ui.edit.undo"); //$NON-NLS-1$
}
if (activeMap != ApplicationGIS.NO_MAP)
undoAction.setEnabled(activeMap.getCommandStack().canUndo());
else
undoAction.setEnabled(false);
return undoAction;
}finally{
undoLock.unlock();
}
}
/**
*
*/
public void setUNDOAction( IAction action, IWorkbenchPart part ) {
if( action == null )
throw new NullPointerException("action must not be null"); //$NON-NLS-1$
if( part == null )
throw new NullPointerException("part must not be null"); //$NON-NLS-1$
undoLock.lock();
try{
undoAction = action;
undoAction.setActionDefinitionId("org.eclipse.ui.edit.undo"); //$NON-NLS-1$
IKeyBindingService service = part.getSite().getKeyBindingService();
service.registerAction(undoAction);
}finally{
undoLock.unlock();
}
}
/**
* Retrieves the forward navigation action that is used by much of the map components such as
* the MapEditor and the LayersView. Executes the last undone Nav command on the current map.
*/
public IAction getFORWARD_HISTORYAction() {
Map activeMap = ApplicationGISInternal.getActiveMap();
forwardLock.lock();
try{
if (forwardAction == null) {
forwardAction = new Action(){
/**
* @see org.eclipse.jface.action.Action#run()
*/
public void run() {
Map activeMap = ApplicationGISInternal.getActiveMap();
if (activeMap != ApplicationGIS.NO_MAP)
activeMap.forwardHistory();
}
};
forwardAction.setImageDescriptor(sharedImages
.getImageDescriptor(ISharedImages.IMG_TOOL_FORWARD));
forwardAction.setText(Messages.ToolManager_forward);
forwardAction.setToolTipText(Messages.ToolManager_forward_tooltip);
forwardAction.setActionDefinitionId("org.eclipse.ui.navigate.forward"); //$NON-NLS-1$
}
if (activeMap != ApplicationGIS.NO_MAP)
forwardAction.setEnabled(activeMap.getCommandStack().canRedo());
else
forwardAction.setEnabled(false);
return forwardAction;
}finally{
forwardLock.unlock();
}
}
/**
*
*/
public void setFORWARDAction( IAction action, IWorkbenchPart part ) {
if( action == null )
throw new NullPointerException("action must not be null"); //$NON-NLS-1$
if( part == null )
throw new NullPointerException("part must not be null"); //$NON-NLS-1$
forwardLock.lock();
try{
forwardAction = action;
forwardAction.setActionDefinitionId("org.eclipse.ui.navigate.forward"); //$NON-NLS-1$
IKeyBindingService service = part.getSite().getKeyBindingService();
service.registerAction(forwardAction);
}finally{
forwardLock.unlock();
}
}
public void registerActionsWithPart( IWorkbenchPart part ) {
IKeyBindingService service = part.getSite().getKeyBindingService();
service.registerAction(getBACKWARD_HISTORYAction());
service.registerAction(getFORWARD_HISTORYAction());
service.registerAction(getCOPYAction(part));
service.registerAction(getCUTAction(part));
service.registerAction(getDELETEAction());
service.registerAction(getPASTEAction(part));
service.registerAction(getREDOAction());
service.registerAction(getUNDOAction());
addToolScope(part.getSite());
}
public void unregisterActions( IWorkbenchPart part ){
IKeyBindingService service = part.getSite().getKeyBindingService();
service.unregisterAction(getBACKWARD_HISTORYAction());
service.unregisterAction(getFORWARD_HISTORYAction());
service.unregisterAction(getCOPYAction(part));
service.unregisterAction(getCUTAction(part));
service.unregisterAction(getDELETEAction());
service.unregisterAction(getPASTEAction(part));
service.unregisterAction(getREDOAction());
service.unregisterAction(getUNDOAction());
service.setScopes(new String[0]);
}
/**
* Retrieves the backward navigation action that is used by much of the map components such as
* the MapEditor and the LayersView. Undoes the last Nav command set to the current map.
*
* @param part
*/
public IAction getBACKWARD_HISTORYAction() {
Map activeMap = ApplicationGISInternal.getActiveMap();
backwardLock.lock();
try{
if (backwardAction == null) {
backwardAction = new Action(){
/**
* @see org.eclipse.jface.action.Action#run()
*/
public void run() {
Map activeMap = ApplicationGISInternal.getActiveMap();
if (activeMap != ApplicationGIS.NO_MAP)
activeMap.backwardHistory();
}
};
backwardAction.setImageDescriptor(sharedImages
.getImageDescriptor(ISharedImages.IMG_TOOL_BACK));
backwardAction.setText(Messages.ToolManager_back);
backwardAction.setToolTipText(Messages.ToolManager_back_tooltip);
backwardAction.setActionDefinitionId("org.eclipse.ui.navigate.back"); //$NON-NLS-1$
}
if (activeMap != ApplicationGIS.NO_MAP)
backwardAction.setEnabled(activeMap.getCommandStack().canUndo());
else
backwardAction.setEnabled(false);
}finally{
backwardLock.unlock();
}
return backwardAction;
}
/**
*
*/
public void setBACKAction( IAction action, IWorkbenchPart part ) {
if( action == null )
throw new NullPointerException("action must not be null"); //$NON-NLS-1$
if( part == null )
throw new NullPointerException("part must not be null"); //$NON-NLS-1$
backwardLock.lock();
try{
backwardAction = action;
backwardAction.setActionDefinitionId("org.eclipse.ui.navigate.back"); //$NON-NLS-1$
IKeyBindingService service = part.getSite().getKeyBindingService();
service.registerAction(backwardAction);
}finally{
backwardLock.unlock();
}
}
/**
*
*/
public IAction getCUTAction( IWorkbenchPart part ) {
cutLock.lock();
try{
if( cutAction==null ){
cutAction=new Action(){
};
}
// JONES
return cutAction;
}finally{
cutLock.unlock();
}
}
public void setCUTAction( IAction action, IWorkbenchPart part ) {
if( action == null )
throw new NullPointerException("action must not be null"); //$NON-NLS-1$
if( part == null )
throw new NullPointerException("part must not be null"); //$NON-NLS-1$
cutLock.lock();
try{
cutAction = action;
cutAction.setActionDefinitionId("org.eclipse.ui.edit.cut"); //$NON-NLS-1$
IKeyBindingService service = part.getSite().getKeyBindingService();
service.registerAction(cutAction);
}finally{
cutLock.unlock();
}
}
public IAction getCOPYAction( final IWorkbenchPart part ) {
copyLock.lock();
try{
if (copyAction == null) {
copyAction = new CopyAction();
IAction template = ActionFactory.COPY.create(part.getSite().getWorkbenchWindow());
copyAction.setText(template.getText());
copyAction.setToolTipText(template.getToolTipText());
copyAction.setImageDescriptor(template.getImageDescriptor());
copyAction.setId(template.getId());
copyAction.setActionDefinitionId("org.eclipse.ui.edit.copy"); //$NON-NLS-1$
}
if (copyAction instanceof CopyAction) {
((CopyAction) copyAction).setPart(part);
}
IKeyBindingService service = part.getSite().getKeyBindingService();
service.registerAction(copyAction);
return copyAction;
}finally{
copyLock.unlock();
}
}
public void setCOPYAction( IAction action, IWorkbenchPart part ) {
if( action == null )
throw new NullPointerException("action must not be null"); //$NON-NLS-1$
if( part == null )
throw new NullPointerException("part must not be null"); //$NON-NLS-1$
copyLock.lock();
try{
copyAction = action;
copyAction.setActionDefinitionId("org.eclipse.ui.edit.copy"); //$NON-NLS-1$
IKeyBindingService service = part.getSite().getKeyBindingService();
service.registerAction(copyAction);
}finally{
copyLock.unlock();
}
}
//
public IAction getPropertiesAction( IWorkbenchPart part, ISelectionProvider selectionProvider ) {
propertiesLock.lock();
try{
if (propertiesAction == null ||
propertiesAction.getSelectionProvider() != selectionProvider ){
propertiesAction = new PropertyDialogAction( part.getSite().getWorkbenchWindow(), selectionProvider );
}
IKeyBindingService service = part.getSite().getKeyBindingService();
service.registerAction(propertiesAction);
return propertiesAction;
} finally {
propertiesLock.unlock();
}
}
public IAction getPASTEAction( IWorkbenchPart part ) {
pasteLock.lock();
try{
if (pasteAction == null) {
pasteAction = new PasteAction();
IAction template = ActionFactory.PASTE.create(part.getSite().getWorkbenchWindow());
pasteAction.setText(template.getText());
pasteAction.setToolTipText(template.getToolTipText());
pasteAction.setImageDescriptor(template.getImageDescriptor());
pasteAction.setId(template.getId());
pasteAction.setActionDefinitionId("org.eclipse.ui.edit.paste"); //$NON-NLS-1$
}
if (pasteAction instanceof PasteAction) {
((PasteAction) pasteAction).setPart(part);
}
IKeyBindingService service = part.getSite().getKeyBindingService();
service.registerAction(pasteAction);
return pasteAction;
}finally{
pasteLock.unlock();
}
}
public void setPASTEAction( IAction action, IWorkbenchPart part ) {
if( action == null )
throw new NullPointerException("action must not be null"); //$NON-NLS-1$
if( part == null )
throw new NullPointerException("part must not be null"); //$NON-NLS-1$
pasteLock.lock();
try{
pasteAction = action;
pasteAction.setActionDefinitionId("org.eclipse.ui.edit.paste"); //$NON-NLS-1$
IKeyBindingService service = part.getSite().getKeyBindingService();
service.registerAction(pasteAction);
}finally{
pasteLock.unlock();
}
}
public synchronized IAction getDELETEAction() {
deleteLock.lock();
try{
if (deleteAction == null) {
deleteAction = new Action(){
@Override
public void run() {
IWorkbenchWindow workbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
ISelectionService selectionService = workbenchWindow.getSelectionService();
ISelection selection = selectionService.getSelection();
Delete delete=new Delete( false );
delete.selectionChanged(this, selection);
delete.run(this);
}
};
deleteAction.setActionDefinitionId("org.eclipse.ui.edit.delete"); //$NON-NLS-1$
IWorkbenchAction actionTemplate = ActionFactory.DELETE.create(PlatformUI.getWorkbench().getActiveWorkbenchWindow());
deleteAction.setText(actionTemplate.getText());
deleteAction.setToolTipText(actionTemplate.getToolTipText());
deleteAction.setImageDescriptor(actionTemplate.getImageDescriptor());
deleteAction.setDescription(actionTemplate.getDescription());
deleteAction.setDisabledImageDescriptor(actionTemplate.getDisabledImageDescriptor());
}
return deleteAction;
}finally{
deleteLock.unlock();
}
}
public synchronized void setDELETEAction( IAction action, IWorkbenchPart part ) {
if( action == null )
throw new NullPointerException("action must not be null"); //$NON-NLS-1$
if( part == null )
throw new NullPointerException("part must not be null"); //$NON-NLS-1$
deleteLock.lock();
try{
deleteAction = action;
deleteAction.setActionDefinitionId("org.eclipse.ui.edit.delete"); //$NON-NLS-1$
IKeyBindingService service = part.getSite().getKeyBindingService();
service.registerAction(deleteAction);
}finally{
deleteLock.unlock();
}
}
public synchronized IAction getENTERAction() {
enterLock.lock();
try{
if (enterAction == null) {
enterAction = new Action(){
public void run() {
try {
Robot r = new Robot();
r.keyPress(KeyEvent.VK_ENTER);
r.keyRelease(KeyEvent.VK_ENTER);
} catch (AWTException e) {
e.printStackTrace();
}
}
};
enterAction.setText(Messages.ToolManager_enterAction);
enterAction.setToolTipText(Messages.ToolManager_enterActionTooltip);
enterAction.setDescription(Messages.ToolManager_enterActionTooltip);
}
return enterAction;
}finally{
enterLock.unlock();
}
}
public synchronized IAction getZOOMTOSELECTEDAction() {
enterLock.lock();
try{
if (zoomToSelectionAction == null) {
zoomToSelectionAction = getToolAction("org.locationtech.udig.tool.default.show.selection", "org.locationtech.udig.tool.category.zoom");
}
return zoomToSelectionAction;
}finally{
enterLock.unlock();
}
}
private void createModalToolToolbar( SubCoolBarManager cbmanager ) {
ToolBarManager manager = new ToolBarManager(SWT.FLAT);
for( String id : categoryIds ) {
ModalToolCategory modalCategory = findModalCategory(id);
if (modalCategory != null) {
modalCategory.contribute(manager);
}
}
if (manager != null && manager.getItems().length > 0)
cbmanager.add(manager);
}
private void createActionToolToolbar( SubCoolBarManager cbmanager ) {
ToolBarManager manager = new ToolBarManager(SWT.FLAT);
manager.add(getBACKWARD_HISTORYAction());
manager.add(getFORWARD_HISTORYAction());
for( String id : categoryIds ) {
ActionToolCategory category = findActionCategory(id);
if (category != null)
category.contribute(manager);
}
if (manager != null && manager.getItems().length > 0)
cbmanager.add(manager);
}
/**
* Adds both action tools and modal tools to the manager
*
* @deprecated
*
* @see contributeActionTools(IToolBarManager toolBarManager, IActionBars bars )
* @see contributeModalTools(IToolBarManager toolBarManager, IActionBars bars )
*
* @param cbmanager
* @param bars
* @see org.locationtech.udig.project.ui.tool.ModalTool
* @see org.locationtech.udig.project.ui.tool.ActionTool
*/
public void contributeToCoolBar( SubCoolBarManager cbmanager, IActionBars bars ) {
cbmanager.setVisible(true);
createActionToolToolbar(cbmanager);
createModalToolToolbar(cbmanager);
}
/* (non-Javadoc)
* @see org.locationtech.udig.project.ui.tool.IToolManager#contributeActionTools(org.eclipse.jface.action.IToolBarManager, org.eclipse.ui.IActionBars)
*/
public void contributeActionTools(IToolBarManager toolBarManager, IActionBars bars ) {
toolBarManager.add(getBACKWARD_HISTORYAction());
toolBarManager.add(getFORWARD_HISTORYAction());
for( String id : categoryIds ) {
ActionToolCategory category = findActionCategory(id);
if (category != null)
category.contribute(toolBarManager);
}
}
/* (non-Javadoc)
* @see org.locationtech.udig.project.ui.tool.IToolManager#contributeModalTools(org.eclipse.jface.action.IToolBarManager, org.eclipse.ui.IActionBars)
*/
public void contributeModalTools(IToolBarManager toolBarManager, IActionBars bars ) {
for( String id : categoryIds ) {
ModalToolCategory modalCategory = findModalCategory(id);
if (modalCategory != null) {
modalCategory.contribute(toolBarManager);
}
}
}
SubActionBars2 getActionBars() {
if (ApplicationGISInternal.getActiveMap() == ApplicationGIS.NO_MAP)
return null;
MapPart active = ApplicationGISInternal.getActiveEditor();
if( active instanceof MapEditorPart){
MapEditorPart editor = (MapEditorPart) active;
return (SubActionBars2) editor.getMapEditorSite().getActionBars();
}
else if( active instanceof ViewPart){
ViewPart view = (ViewPart) active;
return (SubActionBars2) view.getViewSite().getActionBars();
}
return null;
}
private IAction actionCLOSE;
private IAction actionSAVE;
private IAction actionCLOSE_ALL;
private PreferencesShortcutToolOptionsContributionItem preferencesShortcutToolOptions;
/**
* Contributes the common global actions.
* @param part WorkbenchPart such as a view or editor
* @param bars Actionbar used to register global actions
*/
public void contributeGlobalActions( IWorkbenchPart part, IActionBars bars ) {
IKeyBindingService service = part.getSite().getKeyBindingService();
bars.setGlobalActionHandler(ActionFactory.BACK.getId(), getBACKWARD_HISTORYAction());
bars.setGlobalActionHandler(ActionFactory.FORWARD.getId(), getFORWARD_HISTORYAction());
bars.setGlobalActionHandler(ActionFactory.UNDO.getId(), getUNDOAction());
bars.setGlobalActionHandler(ActionFactory.REDO.getId(), getREDOAction());
bars.setGlobalActionHandler(ActionFactory.CUT.getId(), getCUTAction(part));
bars.setGlobalActionHandler(ActionFactory.COPY.getId(), getCOPYAction(part));
bars.setGlobalActionHandler(ActionFactory.PASTE.getId(), getPASTEAction(part));
bars.setGlobalActionHandler(ActionFactory.DELETE.getId(), getDELETEAction());
ISelectionProvider selection = part.getSite().getSelectionProvider();
if( selection != null ){
bars.setGlobalActionHandler(ActionFactory.PROPERTIES.getId(), getPropertiesAction(part,selection));
}
if(actionCLOSE == null)
actionCLOSE = ActionFactory.CLOSE.create(part.getSite().getWorkbenchWindow());
service.registerAction(actionCLOSE);
bars.setGlobalActionHandler(ActionFactory.CLOSE.getId(), actionCLOSE);
if(actionSAVE == null)
actionSAVE = ActionFactory.SAVE.create(part.getSite().getWorkbenchWindow());
service.registerAction(actionSAVE);
bars.setGlobalActionHandler(ActionFactory.SAVE.getId(), actionSAVE);
if(actionCLOSE_ALL == null)
actionCLOSE_ALL = ActionFactory.CLOSE_ALL.create(part.getSite().getWorkbenchWindow());
bars.setGlobalActionHandler(ActionFactory.CLOSE_ALL.getId(), actionCLOSE_ALL);
}
void dispose() {
for( ToolCategory category : modalCategories ) {
category.dispose(ApplicationGISInternal.getActiveEditor().getMapEditorSite()
.getActionBars());
}
for( ToolCategory category : actionCategories ) {
category.dispose(ApplicationGISInternal.getActiveEditor().getMapEditorSite()
.getActionBars());
}
for( ToolCategory category : menuCategories ) {
category.dispose(ApplicationGISInternal.getActiveEditor().getMapEditorSite()
.getActionBars());
}
for( ToolProxy tool : backgroundTools ) {
tool.dispose();
}
}
Adapter getCommandListener( final MapPart editor ) {
if (commandListener == null) {
commandListener = new AdapterImpl(){
/**
* @see org.eclipse.emf.common.notify.impl.AdapterImpl#notifyChanged(org.eclipse.emf.common.notify.Notification)
*/
public void notifyChanged( Notification msg ) {
// Map map = (Map) getTarget();
/*
* While this adapter is a singlton and added to all opened maps, each time
* target variable is reset.
*/
Map map = null;
switch( msg.getFeatureID(msg.getNotifier().getClass()) ) {
case ProjectPackage.MAP__COMMAND_STACK:
map = (Map) msg.getNotifier();
setCommandActions(map, editor);
break;
case ProjectPackage.MAP__NAV_COMMAND_STACK:
map = (Map) msg.getNotifier();
setCommandActions(map, editor);
break;
}
}
};
}
return commandListener;
}
/**
* Hook up the usual actions (UNDO,REDO,BACKWARDS_HISTORY,FORWARD_HISTORY) to the provided
* editor.
*
* @param map
* @param editor
*/
void setCommandActions( Map map, MapPart editor ) {
if (map.getCommandStack().canRedo())
getREDOAction().setEnabled(true);
else
getREDOAction().setEnabled(false);
if (map.getCommandStack().canUndo())
getUNDOAction().setEnabled(true);
else
getUNDOAction().setEnabled(false);
if (map.getNavCommandStack().hasBackHistory())
getBACKWARD_HISTORYAction().setEnabled(true);
else
getBACKWARD_HISTORYAction().setEnabled(false);
if (map.getNavCommandStack().hasForwardHistory())
getFORWARD_HISTORYAction().setEnabled(true);
else
getFORWARD_HISTORYAction().setEnabled(false);
}
public IAction getTool( String toolID, String categoryID ) {
return getToolAction(toolID, categoryID);
}
public IAction getToolAction( String toolID, String categoryID ) {
final IAction tool = getToolInteral(toolID, categoryID);
if( tool == null )
return null;
return new IAction(){
IAction wrapped=tool;
public void addPropertyChangeListener( IPropertyChangeListener listener ) {
wrapped.addPropertyChangeListener(listener);
}
public int getAccelerator() {
return wrapped.getAccelerator();
}
public String getActionDefinitionId() {
return wrapped.getActionDefinitionId();
}
public String getDescription() {
return wrapped.getDescription();
}
public ImageDescriptor getDisabledImageDescriptor() {
return wrapped.getDisabledImageDescriptor();
}
public HelpListener getHelpListener() {
return wrapped.getHelpListener();
}
public ImageDescriptor getHoverImageDescriptor() {
return wrapped.getHoverImageDescriptor();
}
public String getId() {
return wrapped.getId();
}
public ImageDescriptor getImageDescriptor() {
return wrapped.getImageDescriptor();
}
public IMenuCreator getMenuCreator() {
return wrapped.getMenuCreator();
}
public int getStyle() {
return wrapped.getStyle();
}
public String getText() {
return wrapped.getText();
}
public String getToolTipText() {
return wrapped.getToolTipText();
}
public boolean isChecked() {
return wrapped.isChecked();
}
public boolean isEnabled() {
return wrapped.isEnabled();
}
public boolean isHandled() {
return wrapped.isHandled();
}
public void removePropertyChangeListener( IPropertyChangeListener listener ) {
wrapped.removePropertyChangeListener(listener);
}
public void runWithEvent( Event event ) {
wrapped.runWithEvent(event);
}
public void run() {
wrapped.run();
}
public void setAccelerator( int keycode ) {
throw new UnsupportedOperationException("This is an unmodifiable action"); //$NON-NLS-1$
}
public void setActionDefinitionId( String id ) {
throw new UnsupportedOperationException("This is an unmodifiable action"); //$NON-NLS-1$
}
public void setChecked( boolean checked ) {
throw new UnsupportedOperationException("This is an unmodifiable action"); //$NON-NLS-1$
}
public void setDescription( String text ) {
throw new UnsupportedOperationException("This is an unmodifiable action"); //$NON-NLS-1$
}
public void setDisabledImageDescriptor( ImageDescriptor newImage ) {
throw new UnsupportedOperationException("This is an unmodifiable action"); //$NON-NLS-1$
}
public void setEnabled( boolean enabled ) {
throw new UnsupportedOperationException("This is an unmodifiable action"); //$NON-NLS-1$
}
public void setHelpListener( HelpListener listener ) {
throw new UnsupportedOperationException("This is an unmodifiable action"); //$NON-NLS-1$
}
public void setHoverImageDescriptor( ImageDescriptor newImage ) {
throw new UnsupportedOperationException("This is an unmodifiable action"); //$NON-NLS-1$
}
public void setId( String id ) {
throw new UnsupportedOperationException("This is an unmodifiable action"); //$NON-NLS-1$
}
public void setImageDescriptor( ImageDescriptor newImage ) {
throw new UnsupportedOperationException("This is an unmodifiable action"); //$NON-NLS-1$
}
public void setMenuCreator( IMenuCreator creator ) {
throw new UnsupportedOperationException("This is an unmodifiable action"); //$NON-NLS-1$
}
public void setText( String text ) {
throw new UnsupportedOperationException("This is an unmodifiable action"); //$NON-NLS-1$
}
public void setToolTipText( String text ) {
throw new UnsupportedOperationException("This is an unmodifiable action"); //$NON-NLS-1$
}
};
}
/**
* returns the actual tool action.
*/
private IAction getToolInteral( String toolID, String categoryID ) {
ToolCategory category = findModalCategory(categoryID);
if (category != null) {
IAction tool = searchCategoryForTool(toolID, category);
if( tool!=null )
return tool;
}
category = findActionCategory(categoryID);
if (category != null) {
IAction tool = searchCategoryForTool(toolID, category);
if( tool!=null )
return tool;
}
category = findMenuCategory(categoryID);
if (category != null) {
IAction tool = searchCategoryForTool(toolID, category);
if( tool!=null )
return tool;
}
return null;
}
/**
*
* @param toolID
* @param category
* @return
*/
private IAction searchCategoryForTool( String toolID, ToolCategory category ) {
for( Iterator iter2 = category.iterator(); iter2.hasNext(); ) {
ToolProxy tool = (ToolProxy) iter2.next();
String id = tool.getId();
if (id.equals(toolID))
return tool.getAction();
}
return null;
}
/**
* Returns the list of categories containing modal tools.
*
* @return the list of categories containing modal tools.
*/
public List<ModalToolCategory> getModalToolCategories() {
return modalCategories;
}
//
// public Tool getActiveModalTool(){
//
// }
/**
* Returns the tool category that is currently active.
*
* @return the tool category that is currently active.
*/
public ToolCategory getActiveCategory() {
return findModalCategory(activeModalToolProxy.getCategoryId());
}
private static class CategorySorter implements Comparator<String>, Serializable {
/** long serialVersionUID field */
private static final long serialVersionUID = 1L;
private final static java.util.Map<String, Integer> values = new HashMap<String, Integer>();
static {
values.put(ToolConstants.RENDER_CA, 5);
values.put(ToolConstants.ZOOM_CA, 4);
values.put(ToolConstants.PAN_CA, 3);
values.put(ToolConstants.SELECTION_CA, 2);
values.put(ToolConstants.INFO_CA, 1);
values.put(ToolConstants.EDIT_CA, 0);
}
private static final int max = -1;
private static final int min = 1;
/**
* @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
*/
public int compare( String arg0, String arg1 ) {
Integer value0 = values.get(arg0);
Integer value1 = values.get(arg1);
if (value0 == null && value1 == null)
return 0;
if (value1 == null)
return max;
if (value0 == null )
return min;
if (value0.equals(value1))
return 0;
return value0.intValue() > value1.intValue() ? max : min;
}
}
/**
* This method enables the context that allows tool keybinding to work.
*
* @param site
*/
public void addToolScope( IWorkbenchPartSite site ) {
String[] scopes = site.getKeyBindingService().getScopes();
String[] newScopes = new String[scopes.length + 1];
System.arraycopy(scopes, 0, newScopes, 1, scopes.length);
newScopes[0] = "org.locationtech.udig.project.ui.tool"; //$NON-NLS-1$
site.getKeyBindingService().setScopes(newScopes);
}
/*
* This allows for customized operation menus that are based on the currently selected tool.
*/
public MenuManager createOperationsContextMenu(ISelection selection) {
try {
MenuManager contextManager = getOperationMenuFactory().createMenuManager();
List<OperationCategory> primaryCategories = activeModalToolProxy.getOperationCategories();
Collection<OperationCategory> secondaryCategories = getOperationMenuFactory()
.getCategories().values();
for( int i = 0; i < primaryCategories.size(); i++ ) {
OperationCategory category = primaryCategories.get(i);
// Limit the size of the context menu to 20, but don't ever display a portion of
// a category, only always the entire thing.
if (contextManager.getItems().length >= 15 && category.getActions().size() > 5) {
break;
}
MenuManager menu = category.createContextMenu();
if ((i != 0 && menu.getItems().length != 0)
&& (secondaryCategories.size() != 0 || getOperationMenuFactory()
.getActions().size() != 0)) {
contextManager.add(new Separator());
}
for( IContributionItem item : menu.getItems() ) {
contextManager.add(item);
}
}
// if primaryCategories are present, create an "Other" submenu
if (contextManager.getItems().length != 0) {
RunOperationsAction action = new RunOperationsAction();
action.setText(Messages.ToolCategory_other);
contextManager.add(new Separator());
contextManager.add(action);
} else {
Iterator iter = secondaryCategories.iterator();
while( iter.hasNext() ) {
OperationCategory category = (OperationCategory) iter.next();
for( OpAction action : category.getActions() ) {
if( selection instanceof IStructuredSelection )
action.updateEnablement((IStructuredSelection) selection, true);
if (action.isEnabled())
contextManager.add(action);
}
if (iter.hasNext())
contextManager.add(new Separator());
}
if (getOperationMenuFactory().getActions().size() != 0) {
contextManager.add(new Separator());
}
for( OpAction action : getOperationMenuFactory().getActions() ) {
if( selection instanceof IStructuredSelection )
action.updateEnablement((IStructuredSelection) selection, true);
if (action.isEnabled()) {
contextManager.add(action);
}
}
}
return contextManager;
} catch (Throwable e) {
ProjectUIPlugin.log("error creating the Operations ContextMenu", e);//$NON-NLS-1$
return new MenuManager();
}
}
private OperationMenuFactory getOperationMenuFactory() {
return UiPlugin.getDefault().getOperationMenuFactory();
}
/**
* (non-Javadoc)
* @see org.locationtech.udig.project.ui.tool.IToolManager#getActiveTool()
*/
public Tool getActiveTool() {
return activeModalToolProxy.getTool();
}
/**
* Returns active tool proxy object.
*
* @return
*/
public ToolProxy getActiveToolProxy(){
return activeModalToolProxy;
}
/**
* Sets the current active modal tool; please note that the provided
* tool must be visible / enabled and available in the user interface
* for this operation to work.
*
* @param activeModalToolProxy
*/
public void setActiveModalToolProxy(ToolProxy modalToolProxy) {
if( modalToolProxy == null ){
// we will have to use the default then
modalToolProxy = defaultModalToolProxy;
}
if(activeModalToolProxy != null && activeModalToolProxy.getId() == modalToolProxy.getId() ){
return; // no change required
}
this.activeModalToolProxy = modalToolProxy;
// connect the tools to the map area
setActiveModalTool( modalToolProxy.getModalTool() );
currentEditor.setSelectionProvider(modalToolProxy.getSelectionProvider());
// add tool options to the status area
initToolOptionsContribution(currentEditor.getStatusLineManager(), getActiveToolProxy());
}
/**
* This method goes through the steps of deactivating the current tool option contribution and
* activating the new tool option contribution.
*
* @param statusLine
* @param modalToolProxy
*/
private void initToolOptionsContribution(IStatusLineManager statusLine, ToolProxy modalToolProxy){
if(statusLine != null ){
if(preferencesShortcutToolOptions == null || preferencesShortcutToolOptions.isDisposed()){
preferencesShortcutToolOptions = new PreferencesShortcutToolOptionsContributionItem();
statusLine.appendToGroup(StatusLineManager.BEGIN_GROUP, preferencesShortcutToolOptions);
preferencesShortcutToolOptions.setVisible(true);
}
preferencesShortcutToolOptions.update(modalToolProxy);
//TODO, cache contributions instead of destroying them and recreating them
//remove old tool contribution
for(ContributionItem contribution : optionsContribution){
statusLine.remove(contribution.getId());
}
//get the new contributions
optionsContribution = modalToolProxy.getOptionsContribution();
//set all new contributions
for(ContributionItem contribution : optionsContribution){
statusLine.appendToGroup(StatusLineManager.BEGIN_GROUP, contribution);
contribution.setVisible(true);
}
statusLine.update(true);
}
}
/**
* This method goes through the steps of deactivating the current tool
* and activating the new one.
*
* @param modalTool
*/
private void setActiveModalTool( ModalTool modalTool ) {
if (modalTool == null) {
// we cannot run with out a tool; so we will sue the default!
modalTool = defaultModalToolProxy.getModalTool();
}
if (activeTool == modalTool) {
return; // no change required!
}
if (activeTool != null) {
// ask the current tool to stop listening etc...
activeTool.setActive(false);
activeTool = null;
}
if( modalTool.getContext() == null ){
// the tool cannot be activated as it has not been connected to the map yet
// Could we perform activeTool.setContext( toolContext )?
return;
}
try {
activeTool = modalTool;
activeTool.setActive(true);// this should register itself with the tool manager
// this was normally handled by the ToolProxy which we cannot get a hold of
String currentCursorID = activeTool.getCursorID();
Cursor toolCursor = findToolCursor(currentCursorID);
activeTool.getContext().getViewportPane().setCursor(toolCursor);
}
catch (Throwable eek){
System.err.println("Trouble activating "+modalTool+":"+eek);
try {
activeTool.setActive(false); // hope it does a better at cleaning up
}
catch (Throwable t){
// no it did not do a better job cleaning up
}
activeTool = defaultModalToolProxy.getModalTool();
activeTool.setActive(true);
}
}
//
// static class CopyAction extends Action {
// final Set<Transfer> transfers = UDIGDragDropUtilities.getTransfers();
// IWorkbenchPart part;
// public IWorkbenchPart getPart() {
// return part;
// }
// public void setPart( IWorkbenchPart part ) {
// this.part = part;
// }
// @Override
// public void runWithEvent( Event event ) {
// Clipboard clipBoard = new Clipboard(event.display);
// try {
// IStructuredSelection selection = (IStructuredSelection) part.getSite()
// .getSelectionProvider().getSelection();
// if (selection.isEmpty())
// return;
// List<Object> data = new ArrayList<Object>();
// List<Transfer> dataTransfers = new ArrayList<Transfer>();
// Object[] testData = new Object[1];
// Transfer[] testTransfer = new Transfer[1];
// for( Iterator iter = selection.iterator(); iter.hasNext(); ) {
// Object element = iter.next();
// for( Transfer transfer : transfers ) {
// try {
// testData[0] = element;
// testTransfer[0] = transfer;
// clipBoard.setContents(testData, testTransfer);
// } catch (Exception e) {
// continue;
// }
// data.add(element);
// dataTransfers.add(transfer);
// }
// }
// clipBoard.setContents(data.toArray(), dataTransfers
// .toArray(new Transfer[dataTransfers.size()]));
// } finally {
// clipBoard.dispose();
// }
//
// }
// }
static class CopyAction extends Action {
final Set<Transfer> transfers = UDIGDragDropUtilities.getTransfers();
IWorkbenchPart part;
public IWorkbenchPart getPart() {
return part;
}
public void setPart( IWorkbenchPart part ) {
this.part = part;
}
@Override
public void runWithEvent( Event event ) {
Clipboard clipBoard = new Clipboard(event.display);
try {
IMap map = ApplicationGIS.getActiveMap();
if( map == ApplicationGIS.NO_MAP )
return;
ILayer selectedLayer = map.getEditManager().getSelectedLayer();
if( selectedLayer == null )
return;
Filter layerFilter = selectedLayer.getFilter();
if ( layerFilter==Filter.INCLUDE || layerFilter == org.geotools.filter.Filter.ALL ){
return;
}
AdaptingFilter filter = null;
if( layerFilter instanceof AdaptingFilter){
AdaptingFilter adapting = (AdaptingFilter) layerFilter;
if( adapting.getAdapter(ILayer.class)!=null ){
filter = adapting;
}
}
if( filter == null ){
filter = AdaptingFilterFactory.createAdaptingFilter(layerFilter, selectedLayer);
}
clipBoard.setContents(new Object[]{filter},
new Transfer[]{UDigByteAndLocalTransfer.getInstance()});
}finally {
clipBoard.dispose();
}
}
}
// static class PasteAction extends Action {
// IWorkbenchPart part;
// public IWorkbenchPart getPart() {
// return part;
// }
// public void setPart( IWorkbenchPart part ) {
// this.part = part;
// }
// @Override
// public void run() {
// MapEditor activeEditor = ApplicationGISInternal.getActiveEditor();
// Object targetObject = activeEditor;
// IStructuredSelection selection = (IStructuredSelection) part.getSite()
// .getSelectionProvider().getSelection();
// if (!selection.isEmpty()) {
// targetObject = selection.iterator().next();
//
// }
// Clipboard clipboard = new Clipboard(activeEditor.getSite().getShell().getDisplay());
// Set<Transfer> transfers = UDIGDNDProcessor.getTransfers();
// Object contents = null;
// for( Transfer transfer : transfers ) {
// contents = clipboard.getContents(transfer);
// if (contents != null)
// break;
// }
// if (contents != null) {
// UDIGDropHandler dropHandler = activeEditor.getDropHandler();
// dropHandler.setTarget(targetObject);
// dropHandler.setViewerLocation(ViewerDropLocation.NONE);
// dropHandler.performDrop(contents, null);
// }
// }
// }
static class PasteAction extends Action {
IWorkbenchPart part;
public IWorkbenchPart getPart() {
return part;
}
public void setPart( IWorkbenchPart part ) {
this.part = part;
}
@Override
public void run() {
Clipboard clipboard = new Clipboard(part.getSite().getShell().getDisplay());
Set<Transfer> transfers = UDIGDNDProcessor.getTransfers();
Object contents = null;
for( Transfer transfer : transfers ) {
contents = clipboard.getContents(transfer);
if (contents != null)
break;
}
Object selection = firstSelectedElement();
if (contents != null) {
MapEditorPart activeEditor = ApplicationGISInternal.getActiveEditor();
final Map finalMap;
final UDIGDropHandler finalDropHandler;
if( selection instanceof Map){
finalMap = (Map)selection;
finalDropHandler = new UDIGDropHandler();
activeEditor=null;
} else if( activeEditor==null ){
CreateMapCommand command = new CreateMapCommand(null,Collections.<IGeoResource>emptyList(), null);
try {
command.run(new NullProgressMonitor());
} catch (Exception e) {
throw (RuntimeException) new RuntimeException( ).initCause( e );
}
finalMap = (Map) command.getCreatedMap();
finalDropHandler = new UDIGDropHandler();
} else {
finalDropHandler = activeEditor.getDropHandler();
finalMap = activeEditor.getMap();
}
final MapEditorPart finalActiveEditor = activeEditor;
ILayer selectedLayer = finalMap.getEditManager().getSelectedLayer();
if( selectedLayer==null ){
finalDropHandler.setTarget(finalMap);
}else{
finalDropHandler.setTarget(selectedLayer);
}
finalDropHandler.addListener(new IDropHandlerListener(){
public void done( IDropAction action, Throwable error ) {
if( finalActiveEditor==null && finalMap.getMapLayers().size()==0 ){
finalMap.getProjectInternal().getElementsInternal().remove(finalMap);
}
finalDropHandler.removeListener(this);
}
public void noAction( Object data ) {
if( finalActiveEditor==null && finalMap.getMapLayers().size()==0 ){
finalMap.getProjectInternal().getElementsInternal().remove(finalMap);
}
finalDropHandler.removeListener(this);
}
public void starting( IDropAction action ) {
}
});
finalDropHandler.setViewerLocation(ViewerDropLocation.ON);
finalDropHandler.performDrop(contents, null);
}
}
private Object firstSelectedElement() {
ISelection selection = part.getSite().getSelectionProvider().getSelection();
if( selection.isEmpty() || !(selection instanceof IStructuredSelection)){
return null;
}else{
return ((IStructuredSelection)selection).getFirstElement();
}
}
}
public List<ActionToolCategory> getActiveToolCategories() {
return actionCategories;
}
}