blob: 61beb808d22aed1433736ac03b41f35cf4aca782 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.gef.ui.parts;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSource;
import org.eclipse.swt.dnd.DropTarget;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.resource.LocalResourceManager;
import org.eclipse.jface.resource.ResourceManager;
import org.eclipse.jface.util.TransferDragSourceListener;
import org.eclipse.jface.util.TransferDropTargetListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.gef.AccessibleEditPart;
import org.eclipse.gef.EditDomain;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPartFactory;
import org.eclipse.gef.EditPartViewer;
import org.eclipse.gef.KeyHandler;
import org.eclipse.gef.RootEditPart;
import org.eclipse.gef.SelectionManager;
/**
* The base implementation for EditPartViewer.
*
* @author hudsonr
*/
public abstract class AbstractEditPartViewer implements EditPartViewer {
private DisposeListener disposeListener;
private SelectionManager selectionModel;
/**
* The raw list of selected editparts.
*/
protected final List selection = new ArrayList();
/**
* The unmodifiable list of selected editparts.
*/
protected final List constantSelection = Collections
.unmodifiableList(selection);
/**
* The list of selection listeners.
*
* @deprecated
*/
protected List selectionListeners = new ArrayList(1);
/**
* The editpart specifically set to have focus. Note that if this value is
* <code>null</code>, the focus editpart is still implied to be the part
* with primary selection. Subclasses should call the accessor:
* {@link #getFocusEditPart()} whenever possible.
*
* @deprecated
*/
protected EditPart focusPart;
private EditPartFactory factory;
private Map mapIDToEditPart = new HashMap();
private Map mapVisualToEditPart = new HashMap();
private Map properties;
private Control control;
private ResourceManager resources;
private EditDomain domain;
private RootEditPart rootEditPart;
private MenuManager contextMenu;
private DragSource dragSource;
private org.eclipse.gef.dnd.DelegatingDragAdapter dragAdapter = new org.eclipse.gef.dnd.DelegatingDragAdapter();
private DropTarget dropTarget;
private org.eclipse.gef.dnd.DelegatingDropAdapter dropAdapter = new org.eclipse.gef.dnd.DelegatingDropAdapter();
private KeyHandler keyHandler;
private PropertyChangeSupport changeSupport;
/**
* Constructs the viewer and calls {@link #init()}.
*/
public AbstractEditPartViewer() {
setSelectionManager(SelectionManager.createDefault());
init();
}
/**
* @see EditPartViewer#setSelectionManager(SelectionManager)
*/
public void setSelectionManager(SelectionManager model) {
Assert.isNotNull(model);
if (selectionModel != null)
selectionModel.internalUninstall();
selectionModel = model;
model.internalInitialize(this, selection, new Runnable() {
public void run() {
fireSelectionChanged();
}
});
if (getControl() != null)
model.internalHookControl(getControl());
}
/**
* @see EditPartViewer#addDragSourceListener(org.eclipse.gef.dnd.TransferDragSourceListener)
*/
public void addDragSourceListener(
org.eclipse.gef.dnd.TransferDragSourceListener listener) {
addDragSourceListener((TransferDragSourceListener) listener);
}
/**
* @see EditPartViewer#addDragSourceListener(TransferDragSourceListener)
*/
public void addDragSourceListener(TransferDragSourceListener listener) {
getDelegatingDragAdapter().addDragSourceListener(listener);
refreshDragSourceAdapter();
}
/**
* @see EditPartViewer#addDropTargetListener(org.eclipse.gef.dnd.TransferDropTargetListener)
*/
public void addDropTargetListener(
org.eclipse.gef.dnd.TransferDropTargetListener listener) {
addDropTargetListener((TransferDropTargetListener) listener);
}
/**
* @see EditPartViewer#addDropTargetListener(TransferDropTargetListener)
*/
public void addDropTargetListener(TransferDropTargetListener listener) {
getDelegatingDropAdapter().addDropTargetListener(listener);
refreshDropTargetAdapter();
}
/**
* @see EditPartViewer#addPropertyChangeListener(PropertyChangeListener)
*/
public void addPropertyChangeListener(PropertyChangeListener listener) {
if (changeSupport == null)
changeSupport = new PropertyChangeSupport(this);
changeSupport.addPropertyChangeListener(listener);
}
/**
* @see ISelectionProvider#addSelectionChangedListener(ISelectionChangedListener)
*/
public void addSelectionChangedListener(ISelectionChangedListener listener) {
selectionListeners.add(listener);
}
/**
* @see EditPartViewer#appendSelection(EditPart)
*/
public void appendSelection(EditPart editpart) {
selectionModel.appendSelection(editpart);
}
/**
* @see EditPartViewer#createControl(Composite)
*/
public abstract Control createControl(Composite parent);
/**
* @see EditPartViewer#deselect(EditPart)
*/
public void deselect(EditPart editpart) {
selectionModel.deselect(editpart);
}
/**
* @see EditPartViewer#deselectAll()
*/
public void deselectAll() {
selectionModel.deselectAll();
}
/**
* Called if and when the <code>Control</code> is disposed. Subclasses may
* extend this method to perform additional cleanup.
*
* @param e
* the disposeevent
*/
protected void handleDispose(DisposeEvent e) {
if (resources != null)
resources.dispose();
setControl(null);
}
/**
* @see EditPartViewer#findObjectAt(Point)
*/
public final EditPart findObjectAt(Point pt) {
return findObjectAtExcluding(pt, Collections.EMPTY_SET);
}
/**
* @see EditPartViewer#findObjectAtExcluding(Point, Collection)
*/
public final EditPart findObjectAtExcluding(Point pt, Collection exclude) {
return findObjectAtExcluding(pt, exclude, null);
}
/**
* Fires selection changed to the registered listeners at the time called.
*/
protected void fireSelectionChanged() {
Object listeners[] = selectionListeners.toArray();
SelectionChangedEvent event = new SelectionChangedEvent(this,
getSelection());
for (int i = 0; i < listeners.length; i++)
((ISelectionChangedListener) listeners[i]).selectionChanged(event);
}
/**
* @see EditPartViewer#flush()
*/
public void flush() {
}
/**
* @see EditPartViewer#getContextMenu()
*/
public MenuManager getContextMenu() {
return contextMenu;
}
/**
* @see EditPartViewer#getContents()
*/
public EditPart getContents() {
return getRootEditPart().getContents();
}
/**
* @see EditPartViewer#getControl()
*/
public Control getControl() {
return control;
}
/**
* Returns <code>null</code> or the DelegatingDragAdapater. The adapter is
* created automatically when
* {@link #addDragSourceListener(TransferDragSourceListener)} is called.
*
* @return <code>null</code> or the adapter
*/
protected org.eclipse.gef.dnd.DelegatingDragAdapter getDelegatingDragAdapter() {
return dragAdapter;
}
/**
* Returns <code>null</code> or the DelegatingDropAdapater. The adapter is
* created automatically when
* {@link #addDropTargetListener(TransferDropTargetListener)} is called.
*
* @return <code>null</code> or the adapter
*/
protected org.eclipse.gef.dnd.DelegatingDropAdapter getDelegatingDropAdapter() {
return dropAdapter;
}
/**
* Returns <code>null</code> or the DragSource. The drag source is created
* automatically when
* {@link #addDragSourceListener(TransferDragSourceListener)} is called.
*
* @return <code>null</code> or the drag source
*/
protected DragSource getDragSource() {
return dragSource;
}
/**
* Returns <code>null</code> or the DropTarget. The drop target is created
* automatically when
* {@link #addDropTargetListener(TransferDropTargetListener)} is called.
*
* @return <code>null</code> or the drop target
*/
protected DropTarget getDropTarget() {
return dropTarget;
}
/**
* @see EditPartViewer#getEditDomain()
*/
public EditDomain getEditDomain() {
return domain;
}
/**
* @see EditPartViewer#getEditPartFactory()
*/
public EditPartFactory getEditPartFactory() {
return factory;
}
/**
* @see EditPartViewer#getEditPartRegistry()
*/
public Map getEditPartRegistry() {
return mapIDToEditPart;
}
/**
* @see EditPartViewer#getFocusEditPart()
*/
public EditPart getFocusEditPart() {
if (focusPart != null)
return focusPart;
if (getSelectedEditParts().isEmpty()) {
if (getContents() != null)
return getContents();
else
return getRootEditPart();
}
List selection = getSelectedEditParts();
return (EditPart) selection.get(selection.size() - 1);
}
/**
* @see EditPartViewer#getKeyHandler()
*/
public KeyHandler getKeyHandler() {
return keyHandler;
}
/**
* @see EditPartViewer#getProperty(String)
*/
public Object getProperty(String key) {
if (properties != null)
return properties.get(key);
return null;
}
/**
* @see org.eclipse.gef.EditPartViewer#getResourceManager()
*/
public ResourceManager getResourceManager() {
if (resources != null)
return resources;
Assert.isNotNull(getControl());
resources = new LocalResourceManager(JFaceResources.getResources());
return resources;
}
/**
* @see EditPartViewer#getRootEditPart()
*/
public RootEditPart getRootEditPart() {
return rootEditPart;
}
/**
* @see EditPartViewer#getSelectedEditParts()
*/
public List getSelectedEditParts() {
return constantSelection;
}
/**
* Returns an ISelection containing a list of one or more EditPart. Whenever
* {@link #getSelectedEditParts()} returns an empty list, the
* <i>contents</i> editpart ({@link #getContents()}) is returned as the
* current selection.
*
* @see org.eclipse.jface.viewers.ISelectionProvider#getSelection()
*/
public ISelection getSelection() {
return selectionModel.getSelection();
}
/**
* @see EditPartViewer#getSelectionManager()
*/
public SelectionManager getSelectionManager() {
return selectionModel;
}
/**
* @see EditPartViewer#getVisualPartMap()
*/
public Map getVisualPartMap() {
return mapVisualToEditPart;
}
/**
* Called once the control has been set.
*
* @see #unhookControl()
*/
protected void hookControl() {
Control control = getControl();
Assert.isTrue(control != null);
getSelectionManager().internalHookControl(control);
control.addDisposeListener(disposeListener = new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
handleDispose(e);
}
});
if (getRootEditPart() != null)
getRootEditPart().activate();
refreshDragSourceAdapter();
refreshDropTargetAdapter();
if (contextMenu != null)
control.setMenu(contextMenu.createContextMenu(getControl()));
}
/**
* Called whenever the {@link #getDragSource() drag source} is automatically
* created.
*/
protected void hookDragSource() {
dragSource.addDragListener(getDelegatingDragAdapter());
}
/**
* Called whenever the {@link #getDropTarget() drop target} is automatically
* created.
*/
protected void hookDropTarget() {
getDropTarget().addDropListener(getDelegatingDropAdapter());
}
/**
* Called from the constructor. Subclasses may extend this method.
*/
protected void init() {
}
private void primDeselectAll() {
EditPart part;
List list = primGetSelectedEditParts();
for (int i = 0; i < list.size(); i++) {
part = (EditPart) list.get(i);
part.setSelected(EditPart.SELECTED_NONE);
}
list.clear();
}
/**
* Returns the modifiable List of selected EditParts.
*
* @return the internal list of selected editparts
*/
protected List primGetSelectedEditParts() {
return selection;
}
/**
* Creates or disposes a DragSource as needed, and sets the supported
* transfer types. Clients should not need to call or override this method.
*/
protected void refreshDragSourceAdapter() {
if (getControl() == null)
return;
if (getDelegatingDragAdapter().isEmpty())
setDragSource(null);
else {
if (getDragSource() == null)
setDragSource(new DragSource(getControl(), DND.DROP_MOVE
| DND.DROP_COPY | DND.DROP_LINK));
getDragSource().setTransfer(
getDelegatingDragAdapter().getTransfers());
}
}
/**
* Creates or disposes a DropTarget as needed, and sets the supported
* transfer types. Clients should not need to call or override this method.
*/
protected void refreshDropTargetAdapter() {
if (getControl() == null)
return;
if (getDelegatingDropAdapter().isEmpty())
setDropTarget(null);
else {
if (getDropTarget() == null)
setDropTarget(new DropTarget(getControl(), DND.DROP_MOVE
| DND.DROP_COPY | DND.DROP_LINK));
getDropTarget().setTransfer(
getDelegatingDropAdapter().getTransfers());
}
}
/**
* @see EditPartViewer#registerAccessibleEditPart(AccessibleEditPart)
*/
public void registerAccessibleEditPart(AccessibleEditPart acc) {
}
/**
* @see EditPartViewer#removeDragSourceListener(org.eclipse.gef.dnd.TransferDragSourceListener)
* @deprecated
*/
public void removeDragSourceListener(
org.eclipse.gef.dnd.TransferDragSourceListener listener) {
removeDragSourceListener((TransferDragSourceListener) listener);
}
/**
* @see EditPartViewer#removeDragSourceListener(TransferDragSourceListener)
*/
public void removeDragSourceListener(TransferDragSourceListener listener) {
getDelegatingDragAdapter().removeDragSourceListener(listener);
if (getDelegatingDragAdapter().isEmpty())
refreshDragSourceAdapter();
}
/**
* @see EditPartViewer#removeDropTargetListener(org.eclipse.gef.dnd.TransferDropTargetListener)
* @deprecated
*/
public void removeDropTargetListener(
org.eclipse.gef.dnd.TransferDropTargetListener listener) {
removeDropTargetListener((TransferDropTargetListener) listener);
}
/**
* @see EditPartViewer#removeDropTargetListener(TransferDropTargetListener)
*/
public void removeDropTargetListener(TransferDropTargetListener listener) {
getDelegatingDropAdapter().removeDropTargetListener(listener);
if (getDelegatingDropAdapter().isEmpty())
refreshDropTargetAdapter();
}
/**
* @see EditPartViewer#removePropertyChangeListener(PropertyChangeListener)
*/
public void removePropertyChangeListener(PropertyChangeListener listener) {
if (changeSupport != null) {
changeSupport.removePropertyChangeListener(listener);
if (changeSupport.getPropertyChangeListeners().length == 0)
changeSupport = null;
}
}
/**
* @see ISelectionProvider#removeSelectionChangedListener(ISelectionChangedListener)
*/
public void removeSelectionChangedListener(ISelectionChangedListener l) {
selectionListeners.remove(l);
}
/**
* @see EditPartViewer#reveal(EditPart)
*/
public void reveal(EditPart part) {
}
/**
* @see EditPartViewer#select(EditPart)
*/
public void select(EditPart editpart) {
// If selection isn't changing, do nothing.
if ((getSelectedEditParts().size() == 1)
&& (getSelectedEditParts().get(0) == editpart))
return;
primDeselectAll();
appendSelection(editpart); // fireSelectionChanged() is called here
}
/**
* @see EditPartViewer#setContextMenu(MenuManager)
*/
public void setContextMenu(MenuManager manager) {
if (contextMenu != null)
contextMenu.dispose();
contextMenu = manager;
if (getControl() != null && !getControl().isDisposed())
getControl().setMenu(contextMenu.createContextMenu(getControl()));
}
/**
* @see EditPartViewer#setContents(EditPart)
*/
public void setContents(EditPart editpart) {
getRootEditPart().setContents(editpart);
}
/**
* @see EditPartViewer#setContents(Object)
*/
public void setContents(Object contents) {
Assert.isTrue(getEditPartFactory() != null,
"An EditPartFactory is required to call setContents(Object)");//$NON-NLS-1$
setContents(getEditPartFactory().createEditPart(null, contents));
}
/**
* @see EditPartViewer#setControl(Control)
*/
public void setControl(Control control) {
if (this.control != null)
unhookControl();
this.control = control;
if (control != null)
hookControl();
}
/**
* @see EditPartViewer#setCursor(Cursor)
*/
public void setCursor(Cursor cursor) {
if (getControl() == null || getControl().isDisposed())
return;
getControl().setCursor(cursor);
}
/**
* Sets the drag source. Called from {@link #refreshDragSourceAdapter()}.
*
* @param source
* <code>null</code> or a drag source
*/
protected void setDragSource(DragSource source) {
if (dragSource != null)
dragSource.dispose();
dragSource = source;
if (dragSource != null)
hookDragSource();
}
/**
* Sets the drop target. Called from {@link #refreshDropTargetAdapter()}.
*
* @param target
* dropTarget <code>null</code> or a drop target
*/
protected void setDropTarget(DropTarget target) {
if (dropTarget != null)
dropTarget.dispose();
dropTarget = target;
if (dropTarget != null)
hookDropTarget();
}
/**
* @see EditPartViewer#setEditDomain(EditDomain)
*/
public void setEditDomain(EditDomain editdomain) {
this.domain = editdomain;
}
/**
* @see EditPartViewer#setEditPartFactory(org.eclipse.gef.EditPartFactory)
*/
public void setEditPartFactory(EditPartFactory factory) {
this.factory = factory;
}
/**
* @see EditPartViewer#setFocus(EditPart)
*/
public void setFocus(EditPart part) {
getSelectionManager().setFocus(part);
focusPart = part;
}
/**
* @see EditPartViewer#setKeyHandler(KeyHandler)
*/
public void setKeyHandler(KeyHandler handler) {
keyHandler = handler;
}
/**
* @see EditPartViewer#setProperty(String, Object)
*/
public void setProperty(String key, Object value) {
if (properties == null)
properties = new HashMap();
Object old;
if (value == null)
old = properties.remove(key);
else
old = properties.put(key, value);
if (changeSupport != null)
changeSupport.firePropertyChange(key, old, value);
}
/**
* @see EditPartViewer#setRootEditPart(RootEditPart)
*/
public void setRootEditPart(RootEditPart editpart) {
if (rootEditPart != null) {
if (rootEditPart.isActive())
rootEditPart.deactivate();
rootEditPart.setViewer(null);
}
rootEditPart = editpart;
rootEditPart.setViewer(this);
if (getControl() != null)
rootEditPart.activate();
}
/**
* @see EditPartViewer#setRouteEventsToEditDomain(boolean)
*/
public void setRouteEventsToEditDomain(boolean value) {
}
/**
* Sets the selection to the given selection and fires selection changed.
* The ISelection should be an {@link IStructuredSelection} or it will be
* ignored.
*
* @see ISelectionProvider#setSelection(ISelection)
*/
public void setSelection(ISelection newSelection) {
selectionModel.setSelection(newSelection);
}
/**
* Called when the control is being set to <code>null</code>, but before it
* is null.
*/
protected void unhookControl() {
Assert.isTrue(getControl() != null);
if (disposeListener != null) {
getControl().removeDisposeListener(disposeListener);
disposeListener = null;
}
if (getContextMenu() != null)
getContextMenu().dispose();
if (getRootEditPart() != null)
getRootEditPart().deactivate();
}
/**
* Does nothing by default. Subclasses needing to add accessibility support
* should override this method.
*
* @see EditPartViewer#unregisterAccessibleEditPart(AccessibleEditPart)
*/
public void unregisterAccessibleEditPart(AccessibleEditPart acc) {
}
}