blob: 3909d15a020bcd2c6f35ead568d551708abefd24 [file] [log] [blame]
// IdentifiablePluginView.java
package org.eclipse.stem.ui.views;
/*******************************************************************************
* Copyright (c) 2006, 2008 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
*******************************************************************************/
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.Platform;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.edit.ui.dnd.LocalTransfer;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.util.LocalSelectionTransfer;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.stem.core.Constants;
import org.eclipse.stem.core.common.DublinCore;
import org.eclipse.stem.core.common.Identifiable;
import org.eclipse.stem.data.geography.GeographicNames;
import org.eclipse.stem.jobs.execution.IExecutable;
import org.eclipse.stem.ui.Activator;
import org.eclipse.stem.ui.perspectives.Simulation;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.DragSourceListener;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseTrackAdapter;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ViewPart;
/**
* This class represents an eclipse view of the {@link Identifiable} resources
* of a particular type that have been imported into eclipse as plug-ins.
*
* @see Identifiable
* @see GraphsView
* @see ModelsView
* @see ScenariosView
*/
public abstract class IdentifiablePluginView extends ViewPart {
protected TreeViewer treeViewer;
private DublinCoreToolTipHandler dcTTipHandler;
/**
* This is the selection that is in effect at the start of a drag operation
*/
protected ISelection selection;
/**
* This map keeps track of the {@link Identifiable} that we've deserialized
* so we don't need to do that more than once.
*
* @see #getIdentifiable(URI)
*/
protected Map<URI, Identifiable> deserializedIdentifiablesMap = new HashMap<URI, Identifiable>();
/**
* Constructor
*/
public IdentifiablePluginView() {
super();
}
/**
* @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
*/
@Override
public void createPartControl(final Composite parent) {
dcTTipHandler = new DublinCoreToolTipHandler(parent.getShell());
treeViewer = new TreeViewer(parent);
treeViewer
.setContentProvider(new IdentifiablePluginViewTreeContentProvider());
treeViewer
.setLabelProvider(getIdentifiablePluginViewLabelContentProvider());
treeViewer.setUseHashlookup(true);
treeViewer.setInput(getInput());
// Hook up the dublin core tool tip handler
dcTTipHandler.addDCToolTipHelp(treeViewer.getTree());
// We become a selection provider too
getSite().setSelectionProvider(treeViewer);
// Context Menu
final MenuManager contextMenuManager = new MenuManager();
// Place Holder for Menu Additions
contextMenuManager.add(new Separator("execution"));
// Set the context menu for the viewer
treeViewer.getControl().setMenu(
contextMenuManager.createContextMenu(treeViewer.getControl()));
getSite().registerContextMenu(contextMenuManager, treeViewer);
// Listen for double-clicks on Executables
treeViewer.addDoubleClickListener(new IDoubleClickListener() {
public void doubleClick(final DoubleClickEvent event) {
final IExecutable executable = (IExecutable) Platform.getAdapterManager().getAdapter(((StructuredSelection) event.getSelection()).toList().get(0), IExecutable.class);
// Were we successful in adapting?
if (executable != null) {
// Yes
executable.run();
// Only switch to the Simulation Persepctive when the executable is a standard
// run (scenario). For other executables we may want to stay in other special
// perspectives
if(executable instanceof Adapter) {
Adapter a = (Adapter) executable;
Object obj = a.getTarget();
if( obj instanceof org.eclipse.stem.core.scenario.impl.ScenarioImpl ) {
Activator.switchToPerspective(Simulation.ID_STEM_SIMULATION_PERSPECTIVE);
}
} // if adapter (usually true)
} // if
} // doubleClick
});
// Set up drag support
final int ops = DND.DROP_LINK | DND.DROP_COPY | DND.DROP_MOVE;
final Transfer[] transfers = new Transfer[] {
LocalSelectionTransfer.getTransfer(),
LocalTransfer.getInstance() };
treeViewer.addDragSupport(ops, transfers, new DragSourceListener() {
/**
* @see org.eclipse.swt.dnd.DragSourceListener#dragStart(org.eclipse.swt.dnd.DragSourceEvent)
*/
public void dragStart(final DragSourceEvent event) {
// We need to figure out when the drag can start here
// Just say "yes" right now
event.doit = true;
selection = treeViewer.getSelection();
// LocalSelectionTransfer.getTransfer().setSelection(selection);
} // dragStart
/**
* @see org.eclipse.swt.dnd.DragSourceListener#dragSetData(org.eclipse.swt.dnd.DragSourceEvent)
*/
public void dragSetData(final DragSourceEvent event) {
if (LocalSelectionTransfer.getTransfer().isSupportedType(
event.dataType)) {
// Yes
event.data = extractURIStringsFromIdentifiableDelegates((IStructuredSelection) selection);
LocalSelectionTransfer.getTransfer().setSelection(
(IStructuredSelection) event.data);
} // if
else if (LocalTransfer.getInstance().isSupportedType(
event.dataType)) {
// Yes
event.data = extractURIStringsFromIdentifiableDelegates((IStructuredSelection) selection);
} // if
} // dragSetData
private IStructuredSelection extractURIStringsFromIdentifiableDelegates(
final IStructuredSelection selectedDelegates) {
final List<String> collection = new ArrayList<String>();
for (final Iterator selectionIter = selectedDelegates
.iterator(); selectionIter.hasNext();) {
final Object element = selectionIter.next();
// Was an Identifiable Delegate selected?
if (element instanceof IdentifiableDelegate) {
// Yes
// It has a URI that specifies the serialized
// representation of the Identifiable
final String uriString = ((IdentifiableDelegate) element)
.getDublinCore().getIdentifier();
// Were we successful in getting the uri string?
if (uriString != null) {
// Yes
collection.add(uriString);
}
} // if
} // for each selection
return new IStructuredSelection() {
final List<String> list;
{
list = collection;
}
public Object getFirstElement() {
return list.get(0);
}
public Iterator<String> iterator() {
return list.iterator();
}
public int size() {
return list.size();
}
public Object[] toArray() {
return list.toArray();
}
public List<String> toList() {
return list;
}
public boolean isEmpty() {
return list.isEmpty();
}
};
} // extractURIStrings
/**
* @see org.eclipse.swt.dnd.DragSourceListener#dragFinished(org.eclipse.swt.dnd.DragSourceEvent)
*/
public void dragFinished(
@SuppressWarnings("unused") final DragSourceEvent event) {
selection = null;
LocalTransfer.getInstance().javaToNative(null, null);
} // dragFinished
});
} // createPartControl
/**
* @see org.eclipse.ui.part.WorkbenchPart#setFocus()
*/
@Override
public void setFocus() {
// Nothing
}
/**
* @return the input model specific to this view
*/
protected abstract IdentifiableViewModel getInput();
/**
* @return the {@link IdentifiablePluginViewLabelContentProvider}
* appropriate for the model
*/
protected abstract IdentifiablePluginViewLabelContentProvider getIdentifiablePluginViewLabelContentProvider();
/**
* This class represents the model of the {@link Identifiable}'s that extend
* a particular extension point.
*/
protected abstract static class IdentifiableViewModel {
// The root of the tree of categories and identifiables
private final Category root;
// Mapping between a category id and a category
private final Map<String, Category> categoryMap;
/**
* @param extensionPointID
* the identifier of the extension point that Identifiables
* use to plug-in.
*/
public IdentifiableViewModel(final String extensionPointID) {
root = new Category(Constants.IDENTIFIABLE_ROOT_CATEGORY_NAME,
Constants.IDENTIFIABLE_ROOT_CATEGORY_ID, ""); //$NON-NLS-1$
categoryMap = new HashMap<String, Category>();
categoryMap.put(root.getCategoryId(), root);
// Get the configuration elements for this extension point
final IExtensionRegistry registry = Platform.getExtensionRegistry();
final IConfigurationElement[] configElements = registry
.getConfigurationElementsFor(extensionPointID);
// Make a first pass through the elements looking for categories
for (final IConfigurationElement element : configElements) {
// Is this a Category?
if (Constants.CATEGORY_ELEMENT.equals(element.getName())) {
// Yes
if(element.getAttribute(Constants.CATEGORY_NAME_ATTRIBUTE).startsWith("%"))
continue; // Skip untranslated categories
addCategory(element);
}
} // for each configuration element
// Resolve the connections between parent and child categories
resolveCategories();
// Iterate through the elements. Processing the identifiables
for (final IConfigurationElement element : configElements) {
// Is this a Category?
if (Constants.CATEGORY_ELEMENT.equals(element.getName())) {
// Yes
continue;
}
// Is this a dublin core element?
else if (Constants.DUBLIN_CORE_ELEMENT
.equals(element.getName())) {
// Yes
// Was a category id specified in the element?
Category category = root;
final String categoryId = element
.getAttribute("category_id"); //$NON-NLS-1$
if (categoryId != null) {
// Yes
category = categoryMap.get(categoryId);
// Did we find the category?
if (category == null) {
// No
Activator.logError(MessageFormat.format(Messages
.getString("IPView.No_Category"), //$NON-NLS-1$
categoryId), null);
category = root;
}
category = category == null ? root : category;
}
addIdentifiableDelegate(category, element);
} // if dublin core
// Is it an element with a "name" attribute?
else if (element.getAttribute("name") != null) {
// Yes
addIdentifiableDelegate(root, element);
} // if
else {
Activator.logError(MessageFormat.format(Messages
.getString("IPView.Unexpected_Element"), element
.getName(), extensionPointID), null);
} // else
} // for each configuration element
} // IdentifiableViewModel
/**
* Add an {@link IdentifiableDelegate} to the model.
*
* @param category
* the {@link Category} to add the delegate to
*
* @param element
* the {@link DublinCore} element that defines the delegate
*/
private void addIdentifiableDelegate(final Category category,
final IConfigurationElement element) {
final IdentifiableDelegate identifiableDelegate = new IdentifiableDelegate(
element);
category.addIdentifiableDelegate(identifiableDelegate);
} // addIdentifiableDelegate
/**
* Add a {@link Category} to the model.
*
* @param element
* the category element that defines the category
*/
private Category addCategory(final IConfigurationElement element) {
final Category category = new Category(element);
// Does the category already exist?
Category retValue = categoryMap.get(category.getCategoryId());
if (retValue == null) {
// No
// It's new
retValue = category;
categoryMap.put(category.getCategoryId(), category);
}
return retValue;
} // addCategory
/**
* Hook up parent and child categories.
*/
private void resolveCategories() {
// Go through each of the categories hooking up parent with child
for (final Category category : categoryMap.values()) {
// Is this the root category?
if (category == root) {
// Yes
continue;
}
// Does it's parent exist?
Category parentCategory = categoryMap.get(category
.getParentId());
if (parentCategory == null) {
// No
Activator
.logInformation(
"When organizing categories, the specified parent category \"" //$NON-NLS-1$
+ category.getParentId()
+ "\" for the category \"" //$NON-NLS-1$
+ category.getCategoryId()
+ "\" could not be found. Using \"/\" instead.", //$NON-NLS-1$
null);
parentCategory = root;
} // if parent exists
category.setParent(parentCategory);
parentCategory.addChildCategory(category);
} // for each category
} // resolveCategories
/**
* @return the root
*/
protected final Category getRoot() {
return root;
}
} // IdentifiableViewModel
/**
* This class represents an element in the tree that is the model of the
* plugged in graphs.
*/
protected static class Category implements Comparable<Object> {
Category parent;
String parentId;
String categoryId;
String categoryName;
List<Category> childCategories;
List<IdentifiableDelegate> childIdentifiables;
protected Category(final String categoryName, final String categoryId,
final String parentId) {
this.categoryName = categoryName;
this.categoryId = categoryId;
this.parentId = parentId;
this.parent = null;
this.childCategories = new ArrayList<Category>();
this.childIdentifiables = new ArrayList<IdentifiableDelegate>();
}
protected Category(final IConfigurationElement element) {
this(getNLSCatagoryName(element
.getAttribute(Constants.CATEGORY_NAME_ATTRIBUTE)), element
.getAttribute(Constants.CATEGORY_ID_ATTRIBUTE), element
.getAttribute(Constants.PARENT_ID_ATTRIBUTE));
}
/**
* @param category
* a child {@link Category} to add to this parent
*/
public void addChildCategory(final Category category) {
childCategories.add(category);
}
/**
* @param identifiableDelegate
* the {@link IdentifiableDelegate} to add to the category
*/
public void addIdentifiableDelegate(
final IdentifiableDelegate identifiableDelegate) {
childIdentifiables.add(identifiableDelegate);
}
/**
* @param attribute
* the value of {@link Constants#CATEGORY_NAME_ATTRIBUTE}
* @return the NLS'd version of the category name
*/
private static String getNLSCatagoryName(final String attribute) {
final String name = GeographicNames.getName(attribute);
return name.startsWith("!") ? attribute : name;
} // getNLSCatagoryName
/**
* @return the categoryId of this {@link Category}
*/
protected final String getCategoryId() {
return categoryId;
}
/**
* @return the parentId
*/
protected final String getParentId() {
return parentId;
}
/**
* @return the parent
*/
protected final Category getParent() {
return parent;
}
/**
* @param parent
* the parent to set
*/
protected final void setParent(final Category parent) {
this.parent = parent;
}
/**
* @return the children of the {@link Category}
*/
public Object[] getChildren() {
final List<Object> kidList = new ArrayList<Object>();
Collections.sort(childCategories);
Collections.sort(childIdentifiables);
kidList.addAll(childCategories);
kidList.addAll(childIdentifiables);
return kidList.toArray();
} // getChildren
/**
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
final StringBuilder retValue = new StringBuilder(categoryName);
retValue.append(", "); //$NON-NLS-1$
retValue.append(categoryId);
retValue.append(", "); //$NON-NLS-1$
retValue.append(parentId);
return retValue.toString();
}
/**
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int PRIME = 31;
int result = 1;
result = PRIME * result
+ ((categoryId == null) ? 0 : categoryId.hashCode());
return result;
}
/**
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Category other = (Category) obj;
if (categoryId == null) {
if (other.categoryId != null) {
return false;
}
} else if (!categoryId.equals(other.categoryId)) {
return false;
}
return true;
}
/**
* @param o
* @return the value of the compare
* @see java.lang.Comparable#compareTo(java.lang.Object)
*/
public int compareTo(final Object o) {
int retValue = 0;
if (o instanceof Category) {
// Yes
final Category category = (Category) o;
retValue = categoryName.compareTo(category.categoryName);
} // if Category
else if (o instanceof IdentifiableDelegate) {
// Yes
// In a tree listing that mixes categories and
// IdentifiableDelegates we want the categories to appear first,
// so we always return the same value.
retValue = 1;
} // if IdentifiableDelegate
return retValue;
} // compareTo
} // Category
/**
* This class provides content for the tree view of the {@link Identifiable}
* s that are available as parts of plug-ins.
*/
protected static class IdentifiablePluginViewTreeContentProvider implements
ITreeContentProvider {
/**
* @see org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java.lang.Object)
*/
public Object[] getChildren(final Object parentElement) {
Object[] retValue = null;
if (parentElement instanceof Category) {
final Category category = (Category) parentElement;
final List<Object> kidList = new ArrayList<Object>();
Collections.sort(category.childCategories);
Collections.sort(category.childIdentifiables);
kidList.addAll(category.childCategories);
kidList.addAll(category.childIdentifiables);
retValue = kidList.toArray();
}
return retValue;
} // getChildren
/**
* @see org.eclipse.jface.viewers.ITreeContentProvider#getParent(java.lang.Object)
*/
public Object getParent(final Object element) {
Object retValue = null;
if (element instanceof Category) {
retValue = ((Category) element).parent;
} else {
retValue = ((IdentifiableDelegate) element).getParent();
}
return retValue;
} // getParent
/**
* @see org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java.lang.Object)
*/
public boolean hasChildren(final Object element) {
boolean retValue = false;
if (element instanceof Category) {
final Category cagatory = (Category) element;
retValue = cagatory.childCategories.size() > 0
|| cagatory.childIdentifiables.size() > 0;
}
return retValue;
} // hasChildren
/**
* @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
*/
public Object[] getElements(final Object inputElement) {
final IdentifiableViewModel model = (IdentifiableViewModel) inputElement;
// return new Object[] { model.getRoot() };
Arrays.sort(model.getRoot().getChildren());
return model.getRoot().getChildren();
} // getElements
/**
* @see org.eclipse.jface.viewers.IContentProvider#dispose()
*/
public void dispose() {
// Nothing to dispose
} // dispose
/**
* @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer,
* java.lang.Object, java.lang.Object)
*/
public void inputChanged(
@SuppressWarnings("unused") final Viewer viewer,
@SuppressWarnings("unused") final Object oldInput,
@SuppressWarnings("unused") final Object newInput) {
// Nothing to do right now
} // inputChanged
} // IdentifiablePluginViewTreeContentProvider
/**
* This class provides labels the describe the {@link Identifiable}s
* available as part of plug-ins.
*/
protected static abstract class IdentifiablePluginViewLabelContentProvider
implements ILabelProvider {
private static Image categoryIcon = null;
// If true then we've never tried to get the icon
static boolean categoryIconFirstTime = true;
private final List<ILabelProviderListener> listeners;
/**
* Constructor
*/
public IdentifiablePluginViewLabelContentProvider() {
listeners = new ArrayList<ILabelProviderListener>();
} // IdentifiablePluginViewLabelContentProvider
/**
* @see org.eclipse.jface.viewers.ILabelProvider#getImage(java.lang.Object)
*/
public Image getImage(final Object element) {
Image retValue = null;
if (element instanceof Category) {
retValue = getCategoryIcon();
}
return retValue;
} // getImage
/**
* @return the icon to be used to represent {@link Category}s, or
* <code>null</code> if it can't be loaded.
*/
protected Image getCategoryIcon() {
// Should we try to load the icon?
if (categoryIconFirstTime && categoryIcon == null) {
// Yes
categoryIconFirstTime = false;
categoryIcon = PlatformUI.getWorkbench().getSharedImages()
.getImage(ISharedImages.IMG_OBJ_FOLDER);
} // if we should load the icon
return categoryIcon;
} // getCategoryIcon
/**
* @see org.eclipse.jface.viewers.ILabelProvider#getText(java.lang.Object)
*/
public String getText(final Object element) {
String retValue = ""; //$NON-NLS-1$
if (element instanceof Category) {
final Category category = (Category) element;
retValue = category.categoryName;
} else if (element instanceof IdentifiableDelegate) {
final IdentifiableDelegate identifiableDelegate = (IdentifiableDelegate) element;
retValue = identifiableDelegate.toString();
}
return retValue;
} // getText
/**
* @see org.eclipse.jface.viewers.IBaseLabelProvider#addListener(org.eclipse.jface.viewers.ILabelProviderListener)
*/
public void addListener(final ILabelProviderListener listener) {
listeners.add(listener);
} // addListener
/**
* @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose()
*/
public void dispose() {
// Nothing to do. The images are disposed of elsewhere,
} // dispose
/**
* @see org.eclipse.jface.viewers.IBaseLabelProvider#isLabelProperty(java.lang.Object,
* java.lang.String)
*/
public boolean isLabelProperty(
@SuppressWarnings("unused") final Object element,
@SuppressWarnings("unused") final String property) {
return false;
} // isLabelProperty
/**
* @see org.eclipse.jface.viewers.IBaseLabelProvider#removeListener(org.eclipse.jface.viewers.ILabelProviderListener)
*/
public void removeListener(final ILabelProviderListener listener) {
listeners.remove(listener);
} // removeListener
} // IdentifiablePluginViewLabelContentProvider
/**
* This class displays the {@link DublinCore} metadata of
* {@link Identifiable}s when the mouse hovers over it.
*/
private static class DublinCoreToolTipHandler {
// This is the number of pixels below the current mouse position at
// which to position the dublin core
protected static final int Y_OFFSET = 16;
protected Shell dcTipShell;
Label dcDescriptionText;
Label dcCreatorText;
Label dcValidText;
Label dcSourceText;
DublinCoreToolTipHandler(final Shell parent) {
final Display display = parent.getDisplay();
dcTipShell = new Shell(parent, SWT.ON_TOP | SWT.TOOL);
final GridLayout gridLayout = new GridLayout();
gridLayout.numColumns = 1;
dcTipShell.setLayout(gridLayout);
final Color backgroundColor = display
.getSystemColor(SWT.COLOR_INFO_BACKGROUND);
final Color foregroundColor = display
.getSystemColor(SWT.COLOR_INFO_FOREGROUND);
dcTipShell.setBackground(backgroundColor);
dcDescriptionText = createDCAttributeLabel(dcTipShell,
backgroundColor, foregroundColor);
dcCreatorText = createDCAttributeLabel(dcTipShell, backgroundColor,
foregroundColor);
dcValidText = createDCAttributeLabel(dcTipShell, backgroundColor,
foregroundColor);
dcSourceText = createDCAttributeLabel(dcTipShell, backgroundColor,
foregroundColor);
dcTipShell.pack();
} // DublinCoreToolTipHandler
private Label createDCAttributeLabel(final Shell parent,
final Color backgroundColor, final Color foregroundColor) {
final Label retValue = new Label(parent, SWT.NONE);
retValue.setBackground(backgroundColor);
retValue.setForeground(foregroundColor);
retValue.setLayoutData(new GridData(GridData.FILL_HORIZONTAL
| GridData.VERTICAL_ALIGN_CENTER));
return retValue;
} // createDCAttributeLabel
/**
* Add the necessary listeners to the {@link Control} to catch the mouse
* events and pop the tool tip up.
*
* @param control
*/
public void addDCToolTipHelp(final Control control) {
// If the user clicks with the mouse we want to get rid of the
// dublin core
control.addMouseListener(new MouseAdapter() {
/**
* @see org.eclipse.swt.events.MouseAdapter#mouseDown(org.eclipse.swt.events.MouseEvent)
*/
@Override
public void mouseDown(
@SuppressWarnings("unused") final MouseEvent e) {
// Is the dublin core visible?
if (dcTipShell.isVisible()) {
// Yes
// Not any more
dcTipShell.setVisible(false);
} // if visible
} // mouseDown
});
// If the mouse hovers we want to pop up the dublin core, but if it
// exits we want to get right of it.
control.addMouseTrackListener(new MouseTrackAdapter() {
/**
* @see org.eclipse.swt.events.MouseTrackAdapter#mouseHover(org.eclipse.swt.events.MouseEvent)
*/
@Override
public void mouseHover(final MouseEvent e) {
final Point pt = new Point(e.x, e.y);
// Is the event's Widget a Tree (it should be)?
if (e.widget instanceof Tree) {
// Yes
final Tree tree = (Tree) e.widget;
final TreeItem treeItem = tree.getItem(pt);
// Are we over anything?
if (treeItem != null) {
// Yes
final Object obj = treeItem.getData();
// Does it have DC meta data?
if (obj instanceof IdentifiableDelegate) {
// Yes
final IdentifiableDelegate id = (IdentifiableDelegate) obj;
final DublinCore dc = id.getDublinCore();
final String description = dc.getDescription();
final String creator = dc.getCreator();
final String valid = dc.getValid();
final String source = dc.getSource();
// Is there a description?
if (description != null
&& !description.equals("")) {
// Yes
dcDescriptionText.setText(description);
dcDescriptionText.setVisible(true);
} // if
else {
// No
dcDescriptionText.setVisible(false);
}
// Is there a creator?
if (creator != null && !creator.equals("")) {
// Yes
dcCreatorText.setText(creator);
dcCreatorText.setVisible(true);
} // if
else {
// No
dcCreatorText.setVisible(false);
}
// Is there a valid range?
if (valid != null && !valid.equals("")) {
// Yes
dcValidText.setText(valid);
dcValidText.setVisible(true);
} // if
else {
// No
dcValidText.setVisible(false);
}
// Is there a source?
if (source != null && !source.equals("")) {
// Yes
dcSourceText.setText(source);
dcSourceText.setVisible(true);
} // if
else {
// No
dcSourceText.setVisible(false);
}
dcTipShell.pack();
// Now we need to figure out where to position
// the shell containing the dublin core tool tip
// given the size of the tool tip and the bounds
// of the Display.
dcTipShell.setBounds(computeHoverLocation(
dcTipShell, control.toDisplay(pt)));
// Make the Dublin Core tool tip visible
dcTipShell.setVisible(true);
} // if IConfigurationElement
else {
// No
dcTipShell.setVisible(false);
}
} // if display DC
else {
// No
dcTipShell.setVisible(false);
}
} // if Tree
} // mouseHover
/**
* Figure out where to position the tool tip
*
* @param dcTipShell
* the {@link Shell} that contains the dublin core
* @param mousePosition
* the current position of the Mouse relative to the
* Display
*/
private Rectangle computeHoverLocation(final Shell dcTipShell,
final Point mousePosition) {
// Get the current bounds of the toolTip
final Rectangle retValue = dcTipShell.getBounds();
final Rectangle displayBounds = dcTipShell.getDisplay()
.getBounds();
// The x position is either the current mouse position if
// the dublin core can be displayed entirely to the right of
// that, or a value to the left of that that allows it to be
// displayed, with 0 being the limit.
retValue.x = Math.max(Math.min(mousePosition.x,
displayBounds.width - retValue.width), 0);
// The y position is Y_OFFSET pixels below the current mouse
// position, or if the entire dublin core won't fit in the
// window at that position, then the lowest position above
// that where it can, with 0 (the top of the Display) being
// the limit
retValue.y = Math.max(Math.min(mousePosition.y + Y_OFFSET,
displayBounds.height - retValue.height), 0);
return retValue;
} // computeHoverLocation
/**
* @see org.eclipse.swt.events.MouseTrackAdapter#mouseExit(org.eclipse.swt.events.MouseEvent)
*/
@Override
public void mouseExit(
@SuppressWarnings("unused") final MouseEvent e) {
// Is the dublin core visible?
if (dcTipShell.isVisible()) {
// Yes
// Not any more
dcTipShell.setVisible(false);
} // if visible
} // mouseExit
});
} // addDCToolTipHelp
} // DublinCoreToolTipHandler
} // IdentifiablePluginView