diff options
Diffstat (limited to 'plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui')
38 files changed, 6769 insertions, 0 deletions
diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/business/api/helper/TreeUIHelper.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/business/api/helper/TreeUIHelper.java new file mode 100644 index 0000000000..e1c77d4b2e --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/business/api/helper/TreeUIHelper.java @@ -0,0 +1,113 @@ +/******************************************************************************* + * Copyright (c) 2011 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.business.api.helper; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.emf.common.util.EList; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.swt.widgets.TreeItem; + +import org.eclipse.sirius.tree.DTreeItem; + +/** + * Utility methods to handle Tree models. + * + * @author jdupont + */ +public final class TreeUIHelper { + + private TreeUIHelper() { + + } + + /** + * Add elements to a tree descriptor. + * + * @param expected + * tree descriptor to update. + * @param str + * data to add. + */ + public static void addLineToTree(final List<String> expected, final String str) { + expected.add(str); + } + + /** + * Export the given tree to HTML format. + * + * @param tree + * tree to export. + * @return a string with the HTML tree. + */ + public static String toContentHTMl(final Tree tree) { + return TreeUIHelper.toHTML(TreeUIHelper.toTreeDescriptor(tree)); + } + + /** + * Transform a graphical tree to a tree descriptor. + * + * @param tree + * tree to transform. + * @return a list of element representing the tree. + */ + public static List<String> toTreeDescriptor(final Tree tree) { + final List<String> expected = new ArrayList<String>(); + for (final TreeItem treeItem : tree.getItems()) { + expected.add(treeItem.getText()); + if (treeItem.getData() instanceof DTreeItem) { + for (String str : TreeUIHelper.addLineToDescriptor(((DTreeItem) treeItem.getData()).getOwnedTreeItems())) { + expected.add(str); + } + } + } + return expected; + } + + private static List<String> addLineToDescriptor(EList<DTreeItem> treeItemSpecs) { + final List<String> expected = new ArrayList<String>(); + for (final DTreeItem dTreeItem : treeItemSpecs) { + expected.add(dTreeItem.getName()); + if (!dTreeItem.getOwnedTreeItems().isEmpty()) { + for (String str : TreeUIHelper.addLineToDescriptor(dTreeItem.getOwnedTreeItems())) { + expected.add(str); + } + // addLineToDescriptor(dTreeItem.getOwnedTreeItems()); + } + } + return expected; + + } + + /** + * Transform a tree descriptor to an HTML representation. + * + * @param descriptor + * the tree descriptor. + * @return an HTML tree. + */ + public static String toHTML(final List<String> descriptor) { + final StringBuffer result = new StringBuffer(); + result.append("<table>\n"); + for (String line : descriptor) { + result.append("<tr>"); + result.append("<td>"); + result.append(line); + result.append("</td>"); + result.append("</tr>\n"); + + } + result.append("</table>"); + return result.toString(); + } + +} diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/business/internal/dialect/HierarchyLabelTreeProvider.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/business/internal/dialect/HierarchyLabelTreeProvider.java new file mode 100644 index 0000000000..953cc87452 --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/business/internal/dialect/HierarchyLabelTreeProvider.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * Copyright (c) 2009 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.business.internal.dialect; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.jface.viewers.ILabelProvider; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.swt.graphics.Image; + +import org.eclipse.sirius.business.api.query.IdentifiedElementQuery; +import org.eclipse.sirius.description.AbstractNodeMapping; +import org.eclipse.sirius.description.Group; +import org.eclipse.sirius.description.IdentifiedElement; +import org.eclipse.sirius.tree.description.TreeDescription; +import org.eclipse.sirius.tree.description.TreeMapping; +import org.eclipse.sirius.tree.description.TreeNavigationDescription; + +/** + * A label provider for mappings to display their hierarchy. + * + * @author jdupont + */ +public class HierarchyLabelTreeProvider extends LabelProvider { + + private static final String DELIMITER = " > "; + + private ILabelProvider wrappedProvider; + + /** + * Create a new instance without existing providers. + */ + public HierarchyLabelTreeProvider() { + } + + /** + * Create a new instance with wrapped label provider as base type. + * + * @param wrappedLabelProvider + * the wrapped label provider + */ + public HierarchyLabelTreeProvider(final ILabelProvider wrappedLabelProvider) { + this.wrappedProvider = wrappedLabelProvider; + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.jface.viewers.LabelProvider#getImage(java.lang.Object) + */ + @Override + public Image getImage(final Object element) { + return wrappedProvider != null ? wrappedProvider.getImage(element) : super.getImage(element); + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.jface.viewers.LabelProvider#getText(java.lang.Object) + */ + @Override + public String getText(final Object element) { + if (element instanceof TreeMapping || element instanceof TreeDescription || element instanceof TreeNavigationDescription) { + final IdentifiedElement mapping = (IdentifiedElement) element; + String text = mapping.getName(); + EObject container = mapping.eContainer(); + while (container != null && !(container instanceof Group)) { + text = getLabel(container) + DELIMITER + text; + container = container.eContainer(); + } + return text; + } + return wrappedProvider != null ? wrappedProvider.getText(element) : super.getText(element); + } + + private String getLabel(final EObject eObject) { + + String label = null; + + if (eObject instanceof IdentifiedElement) { + label = new IdentifiedElementQuery((IdentifiedElement) eObject).getLabel(); + } else if (eObject instanceof AbstractNodeMapping) { + label = ((AbstractNodeMapping) eObject).getName(); + } + return label != null ? label : "Element whithout name"; + } + +} diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/business/internal/dialect/TreeDialectUI.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/business/internal/dialect/TreeDialectUI.java new file mode 100644 index 0000000000..e9a2851571 --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/business/internal/dialect/TreeDialectUI.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2010 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.business.internal.dialect; + +import org.eclipse.sirius.ui.business.api.dialect.DialectUI; +import org.eclipse.sirius.ui.business.api.dialect.DialectUIServices; + +/** + * The UI part of the tree dialect. + * + * @author pcdavid + */ +public class TreeDialectUI implements DialectUI { + /** + * {@inheritDoc} + */ + public String getName() { + return "tree"; + } + + /** + * {@inheritDoc} + */ + public DialectUIServices getServices() { + return new TreeDialectUIServices(); + } +} diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/business/internal/dialect/TreeDialectUIServices.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/business/internal/dialect/TreeDialectUIServices.java new file mode 100644 index 0000000000..39f7b39e79 --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/business/internal/dialect/TreeDialectUIServices.java @@ -0,0 +1,325 @@ +/******************************************************************************* + * Copyright (c) 2010 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.business.internal.dialect; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.emf.common.notify.AdapterFactory; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.util.EcoreUtil; +import org.eclipse.emf.edit.command.CommandParameter; +import org.eclipse.emf.edit.provider.ComposedAdapterFactory; +import org.eclipse.emf.transaction.RunnableWithResult; +import org.eclipse.jface.viewers.ILabelProvider; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PlatformUI; + +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; + +import org.eclipse.sirius.common.tools.DslCommonPlugin; +import org.eclipse.sirius.common.tools.api.util.StringUtil; +import org.eclipse.sirius.DRepresentation; +import org.eclipse.sirius.DRepresentationElement; +import org.eclipse.sirius.DSemanticDecorator; +import org.eclipse.sirius.business.api.session.Session; +import org.eclipse.sirius.description.DescriptionPackage; +import org.eclipse.sirius.description.RepresentationDescription; +import org.eclipse.sirius.tools.api.profiler.SiriusTasksKey; +import org.eclipse.sirius.tree.DTree; +import org.eclipse.sirius.tree.DTreeItem; +import org.eclipse.sirius.tree.business.internal.metamodel.TreeToolVariables; +import org.eclipse.sirius.tree.description.DescriptionFactory; +import org.eclipse.sirius.tree.description.TreeCreationDescription; +import org.eclipse.sirius.tree.description.TreeDescription; +import org.eclipse.sirius.tree.description.TreeNavigationDescription; +import org.eclipse.sirius.tree.provider.TreeItemProviderAdapterFactory; +import org.eclipse.sirius.tree.ui.tools.internal.editor.DTreeEditor; +import org.eclipse.sirius.ui.business.api.dialect.DialectEditor; +import org.eclipse.sirius.ui.business.api.dialect.DialectUIServices; +import org.eclipse.sirius.ui.business.api.dialect.ExportFormat; +import org.eclipse.sirius.ui.business.api.session.SessionEditorInput; + +/** + * Implementation of the UI services for the tree dialect. + * + * @author pcdavid + */ +public class TreeDialectUIServices implements DialectUIServices { + + /** + * {@inheritDoc} + * + * @see org.eclipse.sirius.ui.business.api.dialect.DialectUIServices#canHandle(org.eclipse.sirius.DRepresentation) + */ + public boolean canHandle(DRepresentation representation) { + return representation instanceof DTree; + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.sirius.ui.business.api.dialect.DialectUIServices#canHandleEditor(org.eclipse.ui.IEditorPart) + */ + public boolean canHandleEditor(IEditorPart editorPart) { + return editorPart instanceof DTreeEditor; + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.sirius.ui.business.api.dialect.DialectUIServices#openEditor(org.eclipse.sirius.business.api.session.Session, + * org.eclipse.sirius.DRepresentation) + */ + public IEditorPart openEditor(Session session, DRepresentation representation) { + return openEditor(session, representation, new NullProgressMonitor()); + } + + /** + * {@inheritDoc} + */ + public IEditorPart openEditor(Session session, DRepresentation dRepresentation, IProgressMonitor monitor) { + IEditorPart editorPart = null; + try { + monitor.beginTask("tree opening", 10); + if (dRepresentation instanceof DTree) { + DslCommonPlugin.PROFILER.startWork(SiriusTasksKey.OPEN_TREE_KEY); + URI uri = EcoreUtil.getURI(dRepresentation); + final IEditorInput editorInput = new SessionEditorInput(uri, getEditorName(dRepresentation), session); + monitor.worked(2); + monitor.subTask("tree opening : " + dRepresentation.getName()); + RunnableWithResult<IEditorPart> runnable = new RunnableWithResult.Impl<IEditorPart>() { + public void run() { + final IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); + try { + setResult(page.openEditor(editorInput, DTreeEditor.ID)); + } catch (final PartInitException e) { + // silent catch + } + } + }; + PlatformUI.getWorkbench().getDisplay().syncExec(runnable); + monitor.worked(8); + IEditorPart result = runnable.getResult(); + if (canHandleEditor(result)) { + DslCommonPlugin.PROFILER.stopWork(SiriusTasksKey.OPEN_TREE_KEY); + editorPart = result; + } + } + } finally { + monitor.done(); + } + return editorPart; + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.sirius.ui.business.api.dialect.DialectUIServices#getEditorName(org.eclipse.sirius.DRepresentation) + */ + public String getEditorName(DRepresentation representation) { + String editorName = representation.getName(); + if (StringUtil.isEmpty(editorName)) { + editorName = "New Tree"; + } + return editorName; + } + + /** + * {@inheritDoc} + */ + public boolean closeEditor(IEditorPart editorPart, boolean save) { + boolean result = false; + if (canHandleEditor(editorPart)) { + try { + ((DTreeEditor) editorPart).close(save); + } catch (NullPointerException e) { + // we might have an exception closing an editor which is + // already in trouble + } + // We suppose it is closed. + result = true; + } + return result; + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.sirius.ui.business.api.dialect.DialectUIServices#isRepresentationManagedByEditor(org.eclipse.sirius.DRepresentation, + * org.eclipse.ui.IEditorPart) + */ + public boolean isRepresentationManagedByEditor(DRepresentation representation, IEditorPart editorPart) { + boolean isRepresentationManagedByEditor = false; + if (canHandleEditor(editorPart)) { + DTreeEditor dTreeEditor = (DTreeEditor) editorPart; + isRepresentationManagedByEditor = dTreeEditor.getRepresentation() != null && dTreeEditor.getRepresentation().equals(representation); + } + return isRepresentationManagedByEditor; + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.sirius.ui.business.api.dialect.DialectUIServices#isRepresentationDescriptionManagedByEditor(org.eclipse.sirius.description.RepresentationDescription, + * org.eclipse.ui.IEditorPart) + */ + public boolean isRepresentationDescriptionManagedByEditor(RepresentationDescription representationDescription, IEditorPart editorPart) { + if (canHandleEditor(editorPart)) { + DTreeEditor dtreeEditor = (DTreeEditor) editorPart; + return EcoreUtil.equals(dtreeEditor.getTreeModel().getDescription(), representationDescription); + } else { + return false; + } + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.sirius.ui.business.api.dialect.DialectUIServices#createAdapterFactory() + */ + public AdapterFactory createAdapterFactory() { + final ComposedAdapterFactory factory = new ComposedAdapterFactory(); + factory.addAdapterFactory(new org.eclipse.sirius.tree.description.provider.DescriptionItemProviderAdapterFactory()); + factory.addAdapterFactory(new TreeItemProviderAdapterFactory()); + return factory; + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.sirius.ui.business.api.dialect.DialectUIServices#canExport(org.eclipse.sirius.ui.business.api.dialect.ExportFormat) + */ + public boolean canExport(ExportFormat format) { + return false; + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.sirius.ui.business.api.dialect.DialectUIServices#export(org.eclipse.sirius.DRepresentation, + * org.eclipse.sirius.business.api.session.Session, + * org.eclipse.core.runtime.IPath, + * org.eclipse.sirius.ui.business.api.dialect.ExportFormat, + * org.eclipse.core.runtime.IProgressMonitor) + */ + public void export(DRepresentation representation, Session session, IPath path, ExportFormat format, IProgressMonitor monitor) { + // Nothing to do for trees. + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.sirius.ui.business.api.dialect.DialectUIServices#provideNewChildDescriptors() + */ + public Collection<CommandParameter> provideNewChildDescriptors() { + Collection<CommandParameter> newChilds = Lists.newArrayList(); + TreeDescription treeDescription = org.eclipse.sirius.tree.description.DescriptionFactory.eINSTANCE.createTreeDescription(); + newChilds.add(new CommandParameter(null, DescriptionPackage.Literals.VIEWPOINT__OWNED_REPRESENTATIONS, treeDescription)); + return newChilds; + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.sirius.ui.business.api.dialect.DialectUIServices#provideRepresentationCreationToolDescriptors(java.lang.Object) + */ + public Collection<CommandParameter> provideRepresentationCreationToolDescriptors(Object feature) { + Collection<CommandParameter> newChilds = Lists.newArrayList(); + TreeCreationDescription treeCreationDescription = DescriptionFactory.eINSTANCE.createTreeCreationDescription(); + new TreeToolVariables().doSwitch(treeCreationDescription); + newChilds.add(new CommandParameter(null, feature, treeCreationDescription)); + return newChilds; + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.sirius.ui.business.api.dialect.DialectUIServices#provideRepresentationNavigationToolDescriptors(java.lang.Object) + */ + public Collection<CommandParameter> provideRepresentationNavigationToolDescriptors(Object feature) { + Collection<CommandParameter> newChilds = Lists.newArrayList(); + TreeNavigationDescription treeNavigationDescription = DescriptionFactory.eINSTANCE.createTreeNavigationDescription(); + new TreeToolVariables().doSwitch(treeNavigationDescription); + newChilds.add(new CommandParameter(null, feature, treeNavigationDescription)); + return newChilds; + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.sirius.ui.business.api.dialect.DialectUIServices#provideTools(org.eclipse.emf.ecore.EObject) + */ + public Collection<CommandParameter> provideTools(EObject object) { + return Collections.emptyList(); + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.sirius.ui.business.api.dialect.DialectUIServices#provideAdditionalMappings(org.eclipse.emf.ecore.EObject) + */ + public Collection<CommandParameter> provideAdditionalMappings(EObject object) { + return Collections.emptyList(); + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.sirius.ui.business.api.dialect.DialectUIServices#getHierarchyLabelProvider(ILabelProvider) + */ + public ILabelProvider getHierarchyLabelProvider(ILabelProvider currentLabelProvider) { + return new HierarchyLabelTreeProvider(currentLabelProvider); + } + + /** + * {@inheritDoc} + */ + public void setSelection(DialectEditor dialectEditor, List<DRepresentationElement> selection) { + if (dialectEditor instanceof DTreeEditor) { + Viewer viewer = ((DTreeEditor) dialectEditor).getViewer(); + Iterable<DTreeItem> items = Iterables.filter(selection, DTreeItem.class); + viewer.setSelection(new StructuredSelection(Lists.newArrayList(items))); + } + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.sirius.ui.business.api.dialect.DialectUIServices#getSelection(org.eclipse.sirius.ui.business.api.dialect.DialectEditor) + */ + public Collection<DSemanticDecorator> getSelection(DialectEditor editor) { + Collection<DSemanticDecorator> selection = Sets.newLinkedHashSet(); + if (editor instanceof DTreeEditor) { + DTreeEditor dEditor = (DTreeEditor) editor; + ISelection sel = dEditor.getSite().getSelectionProvider().getSelection(); + + if (sel instanceof IStructuredSelection) { + Iterables.addAll(selection, Iterables.filter(((IStructuredSelection) sel).toList(), DSemanticDecorator.class)); + } + } + return selection; + } +} diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/properties/propertysource/TreeCompositeEObjectPropertySource.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/properties/propertysource/TreeCompositeEObjectPropertySource.java new file mode 100644 index 0000000000..3aedc1c1f3 --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/properties/propertysource/TreeCompositeEObjectPropertySource.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2013 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.properties.propertysource; + +import org.eclipse.emf.common.notify.AdapterFactory; +import org.eclipse.ui.IEditorPart; + +import org.eclipse.sirius.common.ui.tools.api.util.EclipseUIUtil; +import org.eclipse.sirius.tree.ui.provider.TreeUIPlugin; +import org.eclipse.sirius.tree.ui.tools.internal.editor.DTreeEditor; +import org.eclipse.sirius.ui.tools.api.properties.AbstractEObjectPropertySource; + +public class TreeCompositeEObjectPropertySource extends AbstractEObjectPropertySource { + + /** + * {@inheritDoc} + * + * @see org.eclipse.sirius.ui.tools.api.properties.AbstractEObjectPropertySource#getItemProvidersAdapterFactory() + */ + @Override + protected AdapterFactory getItemProvidersAdapterFactory() { + AdapterFactory adapterFactory = null; + final IEditorPart part = EclipseUIUtil.getActiveEditor(); + if (part instanceof DTreeEditor) { + adapterFactory = ((DTreeEditor) part).getAdapterFactory(); + } else { + adapterFactory = TreeUIPlugin.getPlugin().getItemProvidersAdapterFactory(); + } + return adapterFactory; + } + +} diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/properties/section/common/AbstractDTreePropertySection.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/properties/section/common/AbstractDTreePropertySection.java new file mode 100644 index 0000000000..c96f289d7c --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/properties/section/common/AbstractDTreePropertySection.java @@ -0,0 +1,383 @@ +/******************************************************************************* + * Copyright (c) 2010 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.properties.section.common; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.commands.operations.OperationHistoryFactory; +import org.eclipse.emf.common.notify.AdapterFactory; +import org.eclipse.emf.common.notify.Notification; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.edit.domain.EditingDomain; +import org.eclipse.emf.edit.domain.IEditingDomainProvider; +import org.eclipse.emf.edit.provider.ComposedAdapterFactory; +import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider; +import org.eclipse.emf.transaction.DemultiplexingListener; +import org.eclipse.emf.transaction.NotificationFilter; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.swt.layout.FormAttachment; +import org.eclipse.swt.layout.FormData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.views.properties.IPropertySourceProvider; +import org.eclipse.ui.views.properties.PropertySheetPage; +import org.eclipse.ui.views.properties.tabbed.AbstractPropertySection; +import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage; + +import org.eclipse.sirius.common.tools.DslCommonPlugin; +import org.eclipse.sirius.tools.api.profiler.SiriusTasksKey; +import org.eclipse.sirius.tree.ui.provider.TreeUIPlugin; +import org.eclipse.sirius.tree.ui.tools.internal.editor.DTreeEditor; +import org.eclipse.sirius.ui.tools.api.properties.DTablePropertySheetpage; +import org.eclipse.sirius.ui.tools.api.properties.UndoableModelPropertySheetEntry; +import org.eclipse.sirius.ui.tools.internal.editor.AbstractDTreeEditor; + +/** + * An abstract implementation of a property tab section for the property sheet.<BR> + * This implementation uses a {@link PropertySheetPage} in the section to manage + * {@link org.eclipse.ui.views.properties.PropertySheetEntry} and + * {@link org.eclipse.emf.edit.ui.provider.PropertySource} + * + * @author <a href="mailto:nathalie.lepine@obeo.fr">Nathalie Lepine</a> + * + */ +public abstract class AbstractDTreePropertySection extends AbstractPropertySection implements IPropertySourceProvider { + + /** The parent property sheet page for this section. */ + protected DTablePropertySheetpage parentPropertySheetPage; + + /** + * the content property sheet page witch manages SheetEntry for this + * section. + */ + protected PropertySheetPage contentPage; + + /** + * Current selected object or first object in the selection when multiple + * objects are selected. + */ + protected EObject eObject; + + /** The list of currently selected objects. */ + protected List<Object> eObjectList; + + /** + * Plugin's + * {@link org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider + * AdapterFactoryLabelProvider}. + */ + protected AdapterFactoryLabelProvider adapterFactoryLabelProvider; + + /** + * Model event listener.<BR> + * Listen the editing domain + */ + protected DemultiplexingListener eventListener = new DemultiplexingListener(getFilter()) { + + @Override + protected void handleNotification(final TransactionalEditingDomain domain, final Notification notification) { + update(domain, notification); + } + }; + + /** + * The editing domain of the corresponding {@link AbstractDTableEditor + * editor} + */ + private TransactionalEditingDomain editingDomain; + + /** + * {@inheritDoc} + * + * @see org.eclipse.ui.views.properties.tabbed.ISection#createControls(org.eclipse.swt.widgets.Composite, + * org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage) + */ + @Override + public void createControls(final Composite parent, final TabbedPropertySheetPage aTabbedPropertySheetPage) { + super.createControls(parent, aTabbedPropertySheetPage); + if (aTabbedPropertySheetPage instanceof DTablePropertySheetpage) { + this.parentPropertySheetPage = (DTablePropertySheetpage) aTabbedPropertySheetPage; + } + + final Composite composite = getWidgetFactory().createFlatFormComposite(parent); + + // + // remove the other page. + contentPage = new PropertySheetPage(); + final UndoableModelPropertySheetEntry root = new UndoableModelPropertySheetEntry(OperationHistoryFactory.getOperationHistory()); + + root.setPropertySourceProvider(getPropertySourceProvider()); + contentPage.setRootEntry(root); + + contentPage.createControl(composite); + final FormData data = new FormData(); + data.left = new FormAttachment(0, 0); + data.right = new FormAttachment(100, 0); + data.top = new FormAttachment(0, 0); + data.bottom = new FormAttachment(100, 0); + data.height = 100; + data.width = 100; + contentPage.getControl().setLayoutData(data); + // setActionBars(aTabbedPropertySheetPage.getSite().getActionBars()); + // ((SortedPropertySheetPage) page).setSorter(new AirPropertySorter()); + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.ui.views.properties.tabbed.ISection#setInput(org.eclipse.ui.IWorkbenchPart, + * org.eclipse.jface.viewers.ISelection) + */ + @Override + public void setInput(final IWorkbenchPart part, final ISelection selection) { + super.setInput(part, selection); + if (!(selection instanceof IStructuredSelection)) { + if (selection instanceof EObject) { + eObject = (EObject) selection; + } + } else if (((IStructuredSelection) selection).getFirstElement() instanceof EObject) { + eObject = (EObject) ((IStructuredSelection) selection).getFirstElement(); + eObjectList = ((IStructuredSelection) selection).toList(); + } + // get the editing domain of the IWorkbenchPart + final IEditingDomainProvider provider = (IEditingDomainProvider) part.getAdapter(IEditingDomainProvider.class); + if (provider != null) { + final EditingDomain theEditingDomain = provider.getEditingDomain(); + if (theEditingDomain instanceof TransactionalEditingDomain) { + setEditingDomain((TransactionalEditingDomain) theEditingDomain); + } + } + + contentPage.selectionChanged(part, selection); + } + + /** + * Fetches the + * {@link org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider + * AdapterFactoryLabelProvider} adapted to the given object. + * + * @param eObj + * The object + * @return The plugin's + * {@link org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider + * AdapterFactoryLabelProvider} . + */ + protected AdapterFactoryLabelProvider getAdapterFactoryLabelProvider(final EObject eObj) { + if (adapterFactoryLabelProvider == null) { + if (getPart() instanceof AbstractDTreeEditor) { + adapterFactoryLabelProvider = new AdapterFactoryLabelProvider(((AbstractDTreeEditor) getPart()).getAdapterFactory()); + } else { + return new AdapterFactoryLabelProvider(rescueAdapterFactory()); + } + } + return adapterFactoryLabelProvider; + } + + /** + * Return a default AdapterFactory. + * + * @return a default AdapterFactory + */ + protected AdapterFactory rescueAdapterFactory() { + final List<ComposedAdapterFactory> factories = new ArrayList<ComposedAdapterFactory>(); + factories.add(new ComposedAdapterFactory(ComposedAdapterFactory.Descriptor.Registry.INSTANCE)); + return new ComposedAdapterFactory(factories); + } + + /** + * Fetches the plugin's + * {@link org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider + * AdapterFactoryLabelProvider}. + * + * @return The plugin's + * {@link org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider + * AdapterFactoryLabelProvider} . + */ + protected AdapterFactoryLabelProvider getAdapterFactoryLabelProvider() { + return getAdapterFactoryLabelProvider(null); + } + + /** + * Returns the PropertySource provider. + * + * @return The PropertySource provider + */ + protected IPropertySourceProvider getPropertySourceProvider() { + return this; + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.ui.views.properties.tabbed.AbstractPropertySection#dispose() + */ + @Override + public void dispose() { + super.dispose(); + + if (contentPage != null) { + contentPage.dispose(); + contentPage = null; + } + if (eObjectList != null) { + try { + eObjectList.clear(); + } catch (final UnsupportedOperationException e) { + // Do nothing + } + } + eObject = null; + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.ui.views.properties.tabbed.AbstractPropertySection#refresh() + */ + @Override + public void refresh() { + DslCommonPlugin.PROFILER.startWork(SiriusTasksKey.REFRESH_PROPERTIES_VIEW_SECTION_KEY); + contentPage.refresh(); + DslCommonPlugin.PROFILER.stopWork(SiriusTasksKey.REFRESH_PROPERTIES_VIEW_SECTION_KEY); + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.ui.views.properties.tabbed.AbstractPropertySection#aboutToBeHidden() + */ + @Override + public void aboutToBeHidden() { + super.aboutToBeHidden(); + + final TransactionalEditingDomain theEditingDomain = getEditingDomain(); + if (theEditingDomain != null) { + theEditingDomain.removeResourceSetListener(getEventListener()); + } + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.ui.views.properties.tabbed.AbstractPropertySection#aboutToBeShown() + */ + @Override + public void aboutToBeShown() { + super.aboutToBeShown(); + + final TransactionalEditingDomain theEditingDomain = getEditingDomain(); + if (theEditingDomain != null) { + theEditingDomain.addResourceSetListener(getEventListener()); + } + } + + /** + * Return the model event listener. + * + * @return Returns the eventListener. + */ + protected DemultiplexingListener getEventListener() { + return eventListener; + } + + /** + * Subclasses overriding this method should remember to override + * {@link #update(TransactionalEditingDomain, Notification)} as required. + * The default implementation of + * {@link #update(TransactionalEditingDomain, Notification)} will only + * update if the notifier is an <code>EObject</code>. + * + * @return the filter for events used by my <code>eventListener</code>. + */ + public NotificationFilter getFilter() { + return NotificationFilter.createEventTypeFilter(Notification.SET).or(NotificationFilter.createEventTypeFilter(Notification.UNSET)) + .and(NotificationFilter.createNotifierTypeFilter(EObject.class)); + } + + /** + * Updates me if the notifier is an <code>EObject</code> by calling + * {@link #update(Notification, EObject)}. Does nothing otherwise. + * Subclasses should override this method if they need to update based on + * non-EObject notifiers. + * + * @param domain + * the editing domain + * @param notification + * the event notification + */ + protected void update(final TransactionalEditingDomain domain, final Notification notification) { + if (parentPropertySheetPage.isUpdateEnabled()) { + Object notifier = notification.getNotifier(); + if (notifier instanceof EObject && contentPage != null && contentPage.getControl() != null) { + final Control control = contentPage.getControl(); + control.getDisplay().syncExec(new Runnable() { + public void run() { + if (!control.isDisposed() && control.isVisible()) { + refresh(); + } + } + }); + } + } + } + + /** + * Gets the editing domain from my EObject input. + * + * @return my editing domain + */ + protected TransactionalEditingDomain getEditingDomain() { + return editingDomain; + } + + /** + * Sets the editingDomain. + * + * @param editingDomain + * The editingDomain to set. + */ + protected void setEditingDomain(final TransactionalEditingDomain editingDomain) { + this.editingDomain = editingDomain; + } + + /** + * Override to use all vertical space.<BR> {@inheritDoc} + * + * @see org.eclipse.ui.views.properties.tabbed.AbstractPropertySection#shouldUseExtraSpace() + */ + @Override + public boolean shouldUseExtraSpace() { + return true; + } + + /** + * Get the adapter factory. + * + * @param object + * the object + * @return the retrieved adapter factory + */ + protected AdapterFactory getAdapterFactory(final Object object) { + AdapterFactory adapterFactory = null; + if (object != null) { + if (getPart() instanceof DTreeEditor) { + adapterFactory = ((DTreeEditor) getPart()).getAdapterFactory(); + } else { + adapterFactory = TreeUIPlugin.getPlugin().getItemProvidersAdapterFactory(); + } + } + return adapterFactory; + } +} diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/properties/section/core/CorePropertySection.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/properties/section/core/CorePropertySection.java new file mode 100644 index 0000000000..8d77ec292f --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/properties/section/core/CorePropertySection.java @@ -0,0 +1,80 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008, 2009 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.properties.section.core; + +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.emf.common.notify.AdapterFactory; +import org.eclipse.emf.edit.provider.IItemPropertySource; +import org.eclipse.emf.edit.ui.provider.PropertySource; +import org.eclipse.ui.views.properties.IPropertySource; + +import org.eclipse.sirius.tree.DTreeItem; +import org.eclipse.sirius.tree.ui.properties.propertysource.TreeCompositeEObjectPropertySource; +import org.eclipse.sirius.tree.ui.properties.section.common.AbstractDTreePropertySection; +import org.eclipse.sirius.ui.tools.api.properties.AbstractEObjectPropertySource; + +/** + * Properties for the semantic model. + * + * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a> + */ +public class CorePropertySection extends AbstractDTreePropertySection { + + /** + * {@inheritDoc} + * + * @see org.eclipse.ui.views.properties.IPropertySourceProvider#getPropertySource(java.lang.Object) + */ + public IPropertySource getPropertySource(final Object object) { + IPropertySource propSrc = null; + + if (object instanceof IPropertySource) { + propSrc = (IPropertySource) object; + } else if (object instanceof DTreeItem) { + final DTreeItem line = (DTreeItem) object; + propSrc = getPropertySource(line); + } else { + final AdapterFactory af = getAdapterFactory(object); + if (af != null) { + final IItemPropertySource ips = (IItemPropertySource) af.adapt(object, IItemPropertySource.class); + if (ips != null) { + return new PropertySource(object, ips); + } + } + if (object instanceof IAdaptable) { + propSrc = (IPropertySource) ((IAdaptable) object).getAdapter(IPropertySource.class); + } + } + return propSrc; + } + + /** + * Returns a property source for the given {@link DLine line}. + * + * @param line + * the line + * @return the property source for the line passed in (maybe + * <code>null</code>) + */ + protected AbstractEObjectPropertySource getPropertySource(final DTreeItem line) { + final AbstractEObjectPropertySource propertySource = new TreeCompositeEObjectPropertySource(); + final AdapterFactory af = getAdapterFactory(line); + if (af != null) { + final IItemPropertySource ips = (IItemPropertySource) af.adapt(line, IItemPropertySource.class); + if (ips != null) { + final IPropertySource targetPropertySource = new PropertySource(line, ips); + propertySource.addPropertySource(line, targetPropertySource); + } + } + return propertySource; + } + +} diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/properties/section/semantic/SemanticPropertySection.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/properties/section/semantic/SemanticPropertySection.java new file mode 100644 index 0000000000..a303274bc0 --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/properties/section/semantic/SemanticPropertySection.java @@ -0,0 +1,130 @@ +/******************************************************************************* + * Copyright (c) 2007, 2009 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.properties.section.semantic; + +import java.util.Collection; +import java.util.Iterator; + +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.emf.common.notify.AdapterFactory; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.edit.provider.IItemPropertySource; +import org.eclipse.emf.edit.ui.provider.PropertySource; +import org.eclipse.ui.views.properties.IPropertySource; + +import org.eclipse.sirius.DSemanticDecorator; +import org.eclipse.sirius.SiriusPlugin; +import org.eclipse.sirius.tree.DTreeItem; +import org.eclipse.sirius.tree.ui.properties.propertysource.TreeCompositeEObjectPropertySource; +import org.eclipse.sirius.tree.ui.properties.section.common.AbstractDTreePropertySection; +import org.eclipse.sirius.ui.tools.api.properties.AbstractCompositeEObjectPropertySource; +import org.eclipse.sirius.ui.tools.api.properties.AbstractEObjectPropertySource; +import org.eclipse.sirius.ecore.extender.business.api.accessor.ModelAccessor; + +/** + * Properties for the semantic model. + * + * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a> + */ +public class SemanticPropertySection extends AbstractDTreePropertySection { + + /** + * {@inheritDoc} + * + * @see org.eclipse.ui.views.properties.IPropertySourceProvider#getPropertySource(java.lang.Object) + */ + public IPropertySource getPropertySource(final Object object) { + IPropertySource propSrc = null; + + if (object instanceof IPropertySource) { + propSrc = (IPropertySource) object; + } else if (object instanceof DSemanticDecorator) { + final DSemanticDecorator semanticDecorator = (DSemanticDecorator) object; + propSrc = getPropertySource(semanticDecorator); + } else { + final AdapterFactory af = getAdapterFactory(object); + if (af != null) { + final IItemPropertySource ips = (IItemPropertySource) af.adapt(object, IItemPropertySource.class); + if (ips != null) { + return new PropertySource(object, ips); + } + } + if (object instanceof IAdaptable) { + propSrc = (IPropertySource) ((IAdaptable) object).getAdapter(IPropertySource.class); + } + } + return propSrc; + } + + /** + * Returns a property source for the given {@link DTableElement table + * element}. + * + * @param tableElement + * the table element + * @return the property source for the cell passed in (maybe + * <code>null</code>) + */ + protected IPropertySource getPropertySource(final DTreeItem tableElement) { + final ModelAccessor accessor = SiriusPlugin.getDefault().getModelAccessorRegistry().getModelAccessor(tableElement); + return getPropertySource(accessor, tableElement.getSemanticElements()); + } + + /** + * Returns a property source for the given {@link DCell cell}. + * + * @param accessor + * the model accessor + * @param eObjects + * collection of object + * @return the property source for the cell passed in (maybe + * <code>null</code>) + */ + protected IPropertySource getPropertySource(final ModelAccessor accessor, final Collection<EObject> eObjects) { + final Iterator<EObject> iterElements = eObjects.iterator(); + final AbstractEObjectPropertySource propertySource = new TreeCompositeEObjectPropertySource(); + while (iterElements.hasNext()) { + final EObject semanticElement = iterElements.next(); + fillPropertySource(accessor, semanticElement, propertySource); + } + return propertySource; + } + + /** + * Returns a property source for the given {@link DSemanticDecorator + * semanticDecorator}. + * + * @param semanticDecorator + * the semanticDecorator + * @return the property source for the semanticDecorator passed in (maybe + * <code>null</code>) + */ + protected IPropertySource getPropertySource(final DSemanticDecorator semanticDecorator) { + final AbstractEObjectPropertySource propertySource = new TreeCompositeEObjectPropertySource(); + final ModelAccessor accessor = SiriusPlugin.getDefault().getModelAccessorRegistry().getModelAccessor(semanticDecorator); + final EObject semanticElement = semanticDecorator.getTarget(); + fillPropertySource(accessor, semanticElement, propertySource); + return propertySource; + } + + private void fillPropertySource(final ModelAccessor accessor, final EObject semanticElement, final AbstractCompositeEObjectPropertySource propertySource) { + if (!(accessor.isExtension(semanticElement))) { + final AdapterFactory af = getAdapterFactory(semanticElement); + if (af != null) { + final IItemPropertySource ips = (IItemPropertySource) af.adapt(semanticElement, IItemPropertySource.class); + if (ips != null) { + final IPropertySource targetPropertySource = new PropertySource(semanticElement, ips); + propertySource.addPropertySource(semanticElement, targetPropertySource); + } + } + } + } +} diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/api/editor/DTreeEditor.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/api/editor/DTreeEditor.java new file mode 100644 index 0000000000..0f31286e44 --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/api/editor/DTreeEditor.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2011 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.tools.api.editor; + +import org.eclipse.emf.common.notify.AdapterFactory; +import org.eclipse.swt.widgets.Control; + +import org.eclipse.sirius.ui.business.api.dialect.DialectEditor; + +/** + * {@link DialectEditor} for TreeDialect. + * + * @author <a href="mailto:mariot.chauvin@obeo.fr">Mariot Chauvin</a> + */ +public interface DTreeEditor extends DialectEditor { + + /** + * Get the associated SWT control. + * + * @return the associated control + */ + Control getControl(); + + /** + * Return the adapter factory used for providing views of the model of this + * editor. + * + * @return the adapter factory used for providing views of the model of this + * editor. + */ + AdapterFactory getAdapterFactory(); + +} diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/command/CreateLineCommandFromToolRecordingCommand.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/command/CreateLineCommandFromToolRecordingCommand.java new file mode 100644 index 0000000000..04f2aa3288 --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/command/CreateLineCommandFromToolRecordingCommand.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2010 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.tools.internal.command; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.transaction.RecordingCommand; +import org.eclipse.emf.transaction.TransactionalEditingDomain; + +import org.eclipse.sirius.tree.DTree; +import org.eclipse.sirius.tree.DTreeItem; +import org.eclipse.sirius.tree.DTreeItemContainer; +import org.eclipse.sirius.tree.business.api.command.ITreeCommandFactory; +import org.eclipse.sirius.tree.description.TreeItemCreationTool; + +/** + * A Recording Command to call + * tableCommandFactory.buildCreateLineCommandFromTool. + * + * @author smonnier + */ +public class CreateLineCommandFromToolRecordingCommand extends RecordingCommand { + + /** + * The line concerned with this action + */ + private DTreeItem line; + + private DTree tree; + + private ITreeCommandFactory treeCommandFactory; + + private TreeItemCreationTool tool; + + /** + * Constructor. + * + * @param domain + * the editing domain. + * @param label + * the name of the command. + * @param line + * the line in which to create the new line. + * @param tree + * the tree in which to create the line. + * @param treeCommandFactory + * the factory to use to build commands. + * @param tool + * the line creation tool. + */ + public CreateLineCommandFromToolRecordingCommand(TransactionalEditingDomain domain, String label, DTreeItem line, DTree tree, ITreeCommandFactory treeCommandFactory, TreeItemCreationTool tool) { + super(domain, label); + this.line = line; + this.tree = tree; + this.treeCommandFactory = treeCommandFactory; + this.tool = tool; + } + + /** + * {@inheritDoc} + */ + @Override + protected void doExecute() { + // The CreateLineAction can be launch from the table + EObject target; + DTreeItemContainer lineContainer; + if (line != null) { + target = line.getTarget(); + lineContainer = (DTreeItemContainer) line.eContainer(); + } else { + target = tree.getTarget(); + lineContainer = tree; + } + treeCommandFactory.buildCreateLineCommandFromTool(lineContainer, target, tool).execute(); + } + +} diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/command/EMFCommandFactoryUI.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/command/EMFCommandFactoryUI.java new file mode 100644 index 0000000000..56784273cd --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/command/EMFCommandFactoryUI.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2013 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.tools.internal.command; + +import org.eclipse.sirius.tree.tools.api.interpreter.IInterpreterSiriusTreeVariables; +import org.eclipse.sirius.ui.tools.api.command.AbstractSWTCallback; + +/** + * Implementation of the + * {@link org.eclipse.sirius.tools.api.command.ui.UICallBack} interface using + * SWT. + * + * @author nlepine + */ +public class EMFCommandFactoryUI extends AbstractSWTCallback { + /** + * {@inheritDoc} + */ + @Override + protected String getVariableNameForRepresentation() { + return IInterpreterSiriusTreeVariables.TREE; + } +} diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/DTreeActionBarContributor.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/DTreeActionBarContributor.java new file mode 100644 index 0000000000..e344ed1504 --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/DTreeActionBarContributor.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2010, 2012 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.tools.internal.editor; + +import org.eclipse.emf.edit.ui.action.EditingDomainActionBarContributor; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.ui.IWorkbenchActionConstants; + +import org.eclipse.sirius.tree.ui.tools.internal.editor.actions.EditorCreateTreeItemMenuAction; + +/** + * This is a contributor for a DTree editor. + * + * @author cbrun + */ +public class DTreeActionBarContributor extends EditingDomainActionBarContributor { + + /** + * Constructor. + */ + public DTreeActionBarContributor() { + + } + + /** + * Add the create tree item menu to the toolbar. + * + * @param editorCreateLineMenuAction + * the menu to add + */ + public void addCreateTreeItemMenu(final EditorCreateTreeItemMenuAction editorCreateLineMenuAction) { + final IToolBarManager toolBarManager = getActionBars().getToolBarManager(); + toolBarManager.remove(EditorCreateTreeItemMenuAction.ID); + toolBarManager.appendToGroup(IWorkbenchActionConstants.MB_ADDITIONS, editorCreateLineMenuAction); //$NON-NLS-1$ + toolBarManager.update(true); + } + +} diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/DTreeEditor.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/DTreeEditor.java new file mode 100644 index 0000000000..7c50845945 --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/DTreeEditor.java @@ -0,0 +1,666 @@ +/******************************************************************************* + * Copyright (c) 2010, 2012 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.tools.internal.editor; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener; +import org.eclipse.core.runtime.preferences.InstanceScope; +import org.eclipse.emf.common.notify.AdapterFactory; +import org.eclipse.emf.common.ui.URIEditorInput; +import org.eclipse.emf.common.util.TreeIterator; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.edit.provider.ComposedAdapterFactory; +import org.eclipse.emf.edit.provider.ComposedImage; +import org.eclipse.emf.edit.provider.IDisposable; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.TreePath; +import org.eclipse.jface.viewers.TreeSelection; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.window.Window; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Image; +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.TreeItem; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorMatchingStrategy; +import org.eclipse.ui.IEditorReference; +import org.eclipse.ui.IEditorSite; +import org.eclipse.ui.IFileEditorInput; +import org.eclipse.ui.IPartListener; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.contexts.IContextService; +import org.eclipse.ui.dialogs.SaveAsDialog; +import org.eclipse.ui.part.FileEditorInput; + +import org.eclipse.sirius.common.tools.api.interpreter.IInterpreter; +import org.eclipse.sirius.DRepresentation; +import org.eclipse.sirius.DSemanticDecorator; +import org.eclipse.sirius.SiriusPlugin; +import org.eclipse.sirius.business.api.dialect.DialectManager; +import org.eclipse.sirius.business.api.dialect.command.RefreshRepresentationsCommand; +import org.eclipse.sirius.business.api.session.Session; +import org.eclipse.sirius.business.api.session.SessionManager; +import org.eclipse.sirius.provider.SiriusEditPlugin; +import org.eclipse.sirius.tools.api.interpreter.InterpreterRegistry; +import org.eclipse.sirius.tree.DTree; +import org.eclipse.sirius.tree.DTreeElementSynchronizer; +import org.eclipse.sirius.tree.business.api.command.ITreeCommandFactory; +import org.eclipse.sirius.tree.business.api.command.TreeCommandFactoryService; +import org.eclipse.sirius.tree.business.internal.helper.TreeHelper; +import org.eclipse.sirius.tree.business.internal.refresh.DTreeElementSynchronizerSpec; +import org.eclipse.sirius.tree.ui.provider.TreeUIPlugin; +import org.eclipse.sirius.tree.ui.tools.internal.command.EMFCommandFactoryUI; +import org.eclipse.sirius.tree.ui.tools.internal.editor.preferences.SiriusPreferenceChangeListener; +import org.eclipse.sirius.ui.business.api.descriptor.ComposedImageDescriptor; +import org.eclipse.sirius.ui.business.api.dialect.marker.TraceabilityMarkerNavigationProvider; +import org.eclipse.sirius.ui.business.api.session.IEditingSession; +import org.eclipse.sirius.ui.business.api.session.SessionEditorInput; +import org.eclipse.sirius.ui.business.api.session.SessionUIManager; +import org.eclipse.sirius.ui.tools.internal.editor.AbstractDTreeEditor; +import org.eclipse.sirius.ecore.extender.business.api.accessor.ModelAccessor; + +/** + * Editor for tree representations. + * + * @author nlepine + * + */ +public class DTreeEditor extends AbstractDTreeEditor implements org.eclipse.sirius.tree.ui.tools.api.editor.DTreeEditor { + + /** + * The DTreeEditor ID. + */ + public static final String ID = "org.eclipse.sirius.tree.ui.EditorID"; + + /** The context ID. */ + private static final String CONTEXT_ID = ID + ".treeContext"; + + /** Initial title image descriptor **/ + private static final ImageDescriptor INITIAL_TITLE_IMAGE_DESCRIPTOR = TreeUIPlugin.getBundledImageDescriptor("icons/full/obj16/TreeDescription.gif"); + + private IPartListener refreshAtOpeningActivator; + + private DTree treeModel; + + private IPreferenceChangeListener viewPointPreferenceChangeListener; + + /** + * Creates a new Editor for tree representations. + * + */ + public DTreeEditor() { + super(); + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.sirius.ui.tools.internal.editor.AbstractDTreeEditor#getInitialImage() + */ + public Image getInitialImage() { + if (initialTitleImage == null || initialTitleImage.isDisposed()) { + initialTitleImage = SiriusEditPlugin.getPlugin().getImage(INITIAL_TITLE_IMAGE_DESCRIPTOR); + } + return initialTitleImage; + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.sirius.ui.tools.internal.editor.AbstractDTreeEditor#getFrozenRepresentationImage() + */ + @Override + public Image getFrozenRepresentationImage() { + if (frozenRepresentationImage == null || frozenRepresentationImage.isDisposed()) { + Image refreshImage = TreeUIPlugin.getImage(TreeUIPlugin.getBundledImageDescriptor("icons/" + DTreeViewerManager.REFRESH_IMG + ".gif")); + List<Object> images = new ArrayList<Object>(2); + images.add(refreshImage); + Image lockByOtherOverlayImage = SiriusEditPlugin.getPlugin() + .getImage(SiriusEditPlugin.Implementation.getBundledImageDescriptor("icons/full/decorator/permission_denied_overlay.gif")); + images.add(lockByOtherOverlayImage); + ImageDescriptor composedImageDescriptor = new ComposedImageDescriptor(new ComposedImage(images)); + frozenRepresentationImage = SiriusEditPlugin.getPlugin().getImage(composedImageDescriptor); + } + return frozenRepresentationImage; + } + + /** + * We have to take care of the case when Eclipse starts up with a session + * and diagram already open. + * + * {@inheritDoc} + */ + @Override + public void init(final IEditorSite site, final IEditorInput input) throws PartInitException { + setSite(site); + + final Collection<Session> sessions = SessionManager.INSTANCE.getSessions(); + + /* + * we are during eclipse boot, we are not trying to close the editor + */ + if (sessions.isEmpty() && (!isClosing)) { + SessionManager.INSTANCE.addSessionsListener(sessionManagerListener); + } + isClosing = false; + + if (input instanceof SessionEditorInput) { + final URI uri = ((SessionEditorInput) input).getURI(); + this.session = ((SessionEditorInput) input).getSession(); + setTreeModel(getDTree(uri, false)); + } else if (input instanceof URIEditorInput) { + /* This happens when Eclipse is launched with an open tree editor */ + final URI uri = ((URIEditorInput) input).getURI(); + final DTree rootElement = getDTree(uri, true); + if (rootElement != null) { + setTreeModel(rootElement); + } + } + + setInput(input); + + if (session != null) { + session.addListener(this); + } + + initCommandFactoryProviders(); + + adapterFactory = new ComposedAdapterFactory(TreeUIPlugin.getPlugin().getItemProvidersAdapterFactory()); + + final IEditingSession uiSession = SessionUIManager.INSTANCE.getOrCreateUISession(this.session); + uiSession.open(); + uiSession.attachEditor(this); + setAccessor(SiriusPlugin.getDefault().getModelAccessorRegistry().getModelAccessor(getTreeModel())); + + if (getTreeModel() != null) { + /* + * let's activate the model listening + */ + final DTreeElementSynchronizer sync = new DTreeElementSynchronizerSpec(getInterpreter(), getAccessor()); + getTreeModel().activate(sync); + + /* Update title. Semantic tree could have been renamed */ + notify(PROP_TITLE); + + /* handle preferences */ + new InstanceScope().getNode(SiriusPlugin.ID).addPreferenceChangeListener(viewPointPreferenceChangeListener); + + // Launch the refresh if needed + if (DialectManager.INSTANCE.isRefreshActivatedOnRepresentationOpening()) { + launchRefresh(true); + } + + initCollaborativeIPermissionAuthority(getTreeModel()); + } + } + + /** + * Creates the SWT controls for this workbench part. + * <p> + * Subclasses must implement this method. For a detailed description of the + * requirements see <code>IWorkbenchPart</code> + * </p> + * + * @param parent + * the parent control + * @see org.eclipse.ui.IWorkbenchPart + */ + @Override + public void createPartControl(final Composite parent) { + super.createPartControl(parent); + + // DslCommonPlugin.PROFILER.startWork(SiriusTasks.CREATE_TREE); + if (getTreeModel() == null) { + /* eclipse was closed with an editor opened and not saved */ + final Label errorLabel = new Label(parent, SWT.CENTER); + errorLabel.setText("This tree was not saved. You can close the editor"); + return; + } + treeViewerManager = new DTreeViewerManager(parent, getTreeModel(), getEditingDomain(), accessor, emfCommandFactory, this); + // DslCommonPlugin.PROFILER.stopWork(SiriusTasks.CREATE_TREE); + getSite().setSelectionProvider(treeViewerManager.getTreeViewer()); + + /* initialize Java Service. */ + EObject semantic = null; + if (treeModel != null) { + semantic = treeModel.getTarget(); + } + if (semantic == null) { + final TreeIterator<?> allContents = this.getEditingDomain().getResourceSet().getAllContents(); + while (allContents.hasNext() && semantic == null) { + final Object next = allContents.next(); + if (next instanceof DSemanticDecorator) { + semantic = ((DSemanticDecorator) next).getTarget(); + } + } + } + EObject anyEObject = semantic; + final Iterator<Resource> iterResources = this.getEditingDomain().getResourceSet().getResources().iterator(); + while (iterResources.hasNext() && anyEObject == null) { + final Resource res = iterResources.next(); + if (!res.getContents().isEmpty()) { + anyEObject = res.getContents().get(0); + } + } + if (anyEObject.eResource().getResourceSet() != getEditingDomain().getResourceSet()) { + anyEObject.eResource().unload(); + } + if (anyEObject != null) { + final IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(anyEObject); + InterpreterRegistry.prepareImportsFromSession(interpreter, SessionManager.INSTANCE.getSession(anyEObject)); + } + // add a listener to selection + getSite().getPage().addSelectionListener(this); + // Add the CreateTreeItem menu of the toolbar + ((DTreeActionBarContributor) getEditorSite().getActionBarContributor()).addCreateTreeItemMenu(((DTreeViewerManager) this.getTableViewer()).getCreateTreeItemMenu()); + + refreshAtOpeningActivator = new RefreshAtOpeningActivator(this); + getSite().getPage().addPartListener(refreshAtOpeningActivator); + + // Activate context + IContextService contextService = (IContextService) getSite().getService(IContextService.class); + contextService.activateContext(CONTEXT_ID); + } + + /** + * Overridden to update the UI part when the {@link DTree} model is changed + * outside of a EMF Command (which notify DTreeContentAdapter) in case of + * collab model. + * + * {@inheritDoc} + */ + @Override + public void setInput(IEditorInput input) { + super.setInput(input); + + // Expands the TreeItem according to the model + Viewer viewer = getViewer(); + if (viewer instanceof TreeViewer) { + TreeViewer treeViewer = (TreeViewer) viewer; + treeViewer.setExpandedElements(TreeHelper.getExpandedItems(getTreeModel()).toArray()); + } + } + + private DTree getDTree(final URI uri, final boolean loadOnDemand) { + DTree result = null; + final Resource resource = getEditingDomain().getResourceSet().getResource(uri.trimFragment(), loadOnDemand); + if (resource != null && resource.isLoaded()) { + if (uri.fragment() != null) { + final EObject rootElement = resource.getEObject(uri.fragment()); + if (rootElement instanceof DTree) { + result = (DTree) rootElement; + } + } + } + return result; + } + + private void initCommandFactoryProviders() { + /* get IEMFCommandFactories */ + emfCommandFactory = TreeCommandFactoryService.getInstance().getNewProvider().getCommandFactory(getEditingDomain()); + // Set the automatic refresh according to the preference + ((ITreeCommandFactory) emfCommandFactory).setAutoRefreshDTree(isAutoRefresh()); + /* + * We add a callback for UI stuffs + */ + emfCommandFactory.setUserInterfaceCallBack(new EMFCommandFactoryUI()); + + /* Set viewpoint preference change listener */ + viewPointPreferenceChangeListener = new SiriusPreferenceChangeListener((ITreeCommandFactory) emfCommandFactory); + + } + + private IInterpreter getInterpreter() { + return SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(getTreeModel().getTarget()); + } + + /** + * @param accessor + * the accessor to set + */ + private void setAccessor(final ModelAccessor accessor) { + this.accessor = accessor; + ((ITreeCommandFactory) emfCommandFactory).setModelAccessor(this.accessor); + } + + /** + * {@inheritDoc} + * */ + protected void launchRefresh(boolean loading) { + getEditingDomain().getCommandStack().execute(new RefreshRepresentationsCommand(getEditingDomain(), getTreeModel())); + if (!loading) { + getViewer().refresh(); + } + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.sirius.ui.tools.internal.editor.AbstractDTreeEditor#launchRefresh() + */ + @Override + protected void launchRefresh() { + launchRefresh(false); + } + + private void setTreeModel(final DTree rootElement) { + this.treeModel = rootElement; + + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.sirius.ui.business.api.dialect.DialectEditor#validateRepresentation() + */ + public void validateRepresentation() { + // TODO Auto-generated method stub + + } + + /** + * Closes this DTreeEditor. + * + * @param save + * indicates whether the modifications should save or not + */ + public void close(final boolean save) { + Display display = getSite().getShell().getDisplay(); + display.asyncExec(new Runnable() { + public void run() { + if (treeViewerManager != null) { + getSite().getPage().closeEditor(DTreeEditor.this, save); + } + } + }); + + } + + public DTree getTreeModel() { + return this.treeModel; + } + + /** + * {@inheritDoc} + */ + public DRepresentation getRepresentation() { + return getTreeModel(); + } + + public String getContributorId() { + return ID; + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.ui.part.EditorPart#doSave(org.eclipse.core.runtime.IProgressMonitor) + */ + @Override + public void doSave(final IProgressMonitor progressMonitor) { + + if (isDeleted(getEditorInput())) { + + if (isSaveAsAllowed()) { + + /* + * 1GEUSSR: ITPUI:ALL - User should never loose changes made in + * the editors. Changed Behavior to make sure that if called + * inside a regular save (because of deletion of input element) + * there is a way to report back to the caller. + */ + performSaveAs(progressMonitor); + + } else { + + // final Shell shell = getSite().getShell(); + // final String title = + // Messages.dTableEditor_ErrorSaveDeletedTitle; + // final String msg = + // Messages.dTableEditor_ErrorSaveDeletedMessage; + // MessageDialog.openError(shell, title, msg); + } + + } else { + // Update the readonly state + // updateState(getEditorInput()); + // Valide the state + // validateState(getEditorInput()); + performSave(false, progressMonitor); + } + // Indicates that the editor is saved + } + + /** + * Perform the saveAs action. + * + * @param progressMonitor + * The progress monitor + */ + private void performSaveAs(final IProgressMonitor progressMonitor) { + final Shell shell = getSite().getShell(); + final IEditorInput input = getEditorInput(); + final SaveAsDialog dialog = new SaveAsDialog(shell); + final IFile original = input instanceof IFileEditorInput ? ((IFileEditorInput) input).getFile() : null; + if (original != null) { + dialog.setOriginalFile(original); + } + dialog.create(); + // if (isDeleted(input) && original != null) { + // final String message = + // NLS.bind(Messages.dTableEditor_SavingDeletedFile, + // original.getName()); + // dialog.setErrorMessage(null); + // dialog.setMessage(message, IMessageProvider.WARNING); + // } + if (dialog.open() == Window.CANCEL) { + if (progressMonitor != null) { + progressMonitor.setCanceled(true); + } + } else { + final IPath filePath = dialog.getResult(); + if (filePath == null) { + if (progressMonitor != null) { + progressMonitor.setCanceled(true); + } + return; + } + final IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); + final IFile file = workspaceRoot.getFile(filePath); + final IEditorInput newInput = new FileEditorInput(file); + // Check if the editor is already open + final IEditorMatchingStrategy matchingStrategy = getEditorDescriptor().getEditorMatchingStrategy(); + final IEditorReference[] editorRefs = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getEditorReferences(); + for (IEditorReference editorRef : editorRefs) { + if (matchingStrategy.matches(editorRef, newInput)) { + // MessageDialog.openWarning(shell, + // Messages.dTableEditor_SaveAsErrorTitle, + // Messages.dTableEditor_SaveAsErrorMessage); + return; + } + } + final boolean success = false; + // try { + // provider.aboutToChange(newInput); + // getDocumentProvider(newInput).saveDocument(progressMonitor, + // newInput, + // getDocumentProvider().getDocument(getEditorInput()), true); + // success = true; + // } catch (final CoreException x) { + // final IStatus status = x.getStatus(); + // if (status == null || status.getSeverity() != IStatus.CANCEL) { + // ErrorDialog.openError(shell, Messages.dTableEditorSaveErrorTitle, + // Messages.dTableEditorSaveErrorMessage, x.getStatus()); + // } + // } finally { + // provider.changed(newInput); + // if (success) { + // setInput(newInput); + // } + // } + if (progressMonitor != null) { + progressMonitor.setCanceled(!success); + } + } + } + + /** + * + * {@inheritDoc} + */ + @Override + public void doSaveAs() { + if (isSaveAsAllowed()) { + performSaveAs(new NullProgressMonitor()); + } + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.ui.ide.IGotoMarker#gotoMarker(org.eclipse.core.resources.IMarker) + */ + public void gotoMarker(IMarker marker) { + if (TraceabilityMarkerNavigationProvider.isTraceabilityMarker(marker)) { + new TraceabilityMarkerNavigationProvider(this).gotoMarker(marker); + } else { + doGoToMarker(marker); + } + } + + /** + * Sets the cursor and selection state for an editor to reveal the position + * of the given marker. + * + * @param marker + * the marker to go to + */ + // TODO for now on, this implementation only allow to handle Traceability + // markers + protected void doGoToMarker(IMarker marker) { + final String treeURI = marker.getAttribute(TraceabilityMarkerNavigationProvider.REPRESENTATION_URI, null); + final String elementId = marker.getAttribute(TraceabilityMarkerNavigationProvider.REPRESENTATION_ELEMENT_ID, null); + + if (treeURI == null || elementId == null) { + return; + } + + final URI markerTreeURI = URI.createURI(treeURI); + final DTree markerTree = (DTree) this.getTreeModel().eResource().getEObject(markerTreeURI.fragment()); + + if (markerTree != null) { + EObject searchedElement = markerTree.eResource().getEObject(elementId); + TreeViewer viewer = this.treeViewerManager.getTreeViewer(); + + // FIXME : contrary to tables, getItems() of the Tree returns only + // expanded elements. So we expand it manually + Object[] expandedElements = viewer.getExpandedElements(); + ((TreeViewer) this.getViewer()).expandAll(); + TreeItem contains = contains(viewer.getTree().getItems(), searchedElement); + ((TreeViewer) this.getViewer()).setExpandedElements(expandedElements); + + if (contains != null) { + ISelection selection = new TreeSelection(getTreePathFromItem(contains)); + ((TreeViewer) this.getViewer()).setSelection(selection, true); + } + + } + } + + /** + * Returns the tree path for the given item. + * + * @param item + * the item from which obtain the path + * @return {@link TreePath} + * + * @since 3.2 + */ + protected TreePath getTreePathFromItem(TreeItem item) { + LinkedList<Object> segments = new LinkedList<Object>(); + TreeItem myItem = item; + while (myItem != null) { + Object segment = item.getData(); + Assert.isNotNull(segment); + segments.addFirst(segment); + myItem = myItem.getParentItem(); + } + return new TreePath(segments.toArray()); + } + + /** + * Return the adapter factory used for providing views of the model of this + * editor. + * + * @return the adapter factory used for providing views of the model of this + * editor. + */ + public AdapterFactory getAdapterFactory() { + if (adapterFactory == null) { + // Create an adapter factory that yields item providers. + adapterFactory = TreeUIPlugin.getPlugin().createAdapterFactory(); + } + return adapterFactory; + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.sirius.ui.tools.internal.editor.AbstractDTreeEditor#dispose() + */ + @Override + public void dispose() { + if (refreshAtOpeningActivator != null) { + getSite().getPage().removePartListener(refreshAtOpeningActivator); + } + refreshAtOpeningActivator = null; + super.dispose(); + if (getAdapterFactory() instanceof IDisposable) { + ((IDisposable) getAdapterFactory()).dispose(); + } + + new InstanceScope().getNode(SiriusPlugin.ID).removePreferenceChangeListener(viewPointPreferenceChangeListener); + viewPointPreferenceChangeListener = null; + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.sirius.tree.ui.tools.api.editor.DTreeEditor#getControl() + */ + public Control getControl() { + TreeViewer treeViewer = this.getTableViewer().getTreeViewer(); + return treeViewer.getTree(); + } + +} diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/DTreeMenuListener.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/DTreeMenuListener.java new file mode 100644 index 0000000000..a94644c167 --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/DTreeMenuListener.java @@ -0,0 +1,426 @@ +/******************************************************************************* + * Copyright (c) 2010, 2012 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.tools.internal.editor; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.eclipse.emf.common.notify.AdapterFactory; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.edit.provider.IItemLabelProvider; +import org.eclipse.emf.edit.ui.provider.ExtendedImageRegistry; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.action.IMenuListener; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.action.Separator; +import org.eclipse.jface.action.SubContributionItem; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.ui.IWorkbenchActionConstants; + +import org.eclipse.sirius.common.tools.api.interpreter.EvaluationException; +import org.eclipse.sirius.common.tools.api.interpreter.IInterpreter; +import org.eclipse.sirius.common.tools.api.util.StringUtil; +import org.eclipse.sirius.DDiagram; +import org.eclipse.sirius.DRepresentation; +import org.eclipse.sirius.DRepresentationElement; +import org.eclipse.sirius.DSemanticDecorator; +import org.eclipse.sirius.SiriusPlugin; +import org.eclipse.sirius.business.api.dialect.DialectManager; +import org.eclipse.sirius.business.api.helper.task.InitInterpreterVariablesTask; +import org.eclipse.sirius.business.api.logger.RuntimeLoggerInterpreter; +import org.eclipse.sirius.business.api.logger.RuntimeLoggerManager; +import org.eclipse.sirius.business.api.query.IdentifiedElementQuery; +import org.eclipse.sirius.business.api.session.Session; +import org.eclipse.sirius.business.api.session.SessionManager; +import org.eclipse.sirius.description.tool.AbstractVariable; +import org.eclipse.sirius.description.tool.RepresentationCreationDescription; +import org.eclipse.sirius.description.tool.RepresentationNavigationDescription; +import org.eclipse.sirius.description.tool.ToolPackage; +import org.eclipse.sirius.tree.DTree; +import org.eclipse.sirius.tree.DTreeItem; +import org.eclipse.sirius.tree.description.TreeMapping; +import org.eclipse.sirius.tree.ui.tools.internal.command.EMFCommandFactoryUI; +import org.eclipse.sirius.tree.ui.tools.internal.editor.actions.AbstractToolAction; +import org.eclipse.sirius.tree.ui.tools.internal.editor.actions.AbstractToolItemAction; +import org.eclipse.sirius.tree.ui.tools.internal.editor.actions.CreateRepresentationFromRepresentationCreationDescription; +import org.eclipse.sirius.tree.ui.tools.internal.editor.actions.CreateToolItemAction; +import org.eclipse.sirius.tree.ui.tools.internal.editor.actions.DeleteTreeItemsAction; +import org.eclipse.sirius.tree.ui.tools.internal.editor.actions.OpenRepresentationAction; +import org.eclipse.sirius.tree.ui.tools.internal.editor.actions.RefreshAction; +import org.eclipse.sirius.tree.ui.tools.internal.editor.provider.TreePopupMenuContributionSupport; +import org.eclipse.sirius.ui.business.api.dialect.DialectUIManager; + +/** + * A menu listener which show or hide the menu according to : + * <UL> + * <LI>the current selection</LI> + * <LI>and the tool precondition. + * </UL> + * + * @author <a href="mailto:nathalie.lepine@obeo.fr">Nathalie Lepine</a> + * + */ +public class DTreeMenuListener implements IMenuListener { + + private static final String MENU_NAVIGATE_ID = "popup.navigate"; + + private static final String NEW_REPRESENTATION_GROUP_SEPARATOR = "newRepresentation"; + + private static final String EXISTING_REPRESENTATION_GROUP_SEPARATOR = "existingRepresentation"; + + private static final String NAVIGATE_REPRESENTATION_GROUP_SEPARATOR = "navigateRepresentationGroup"; + + private static final String PROPERTIES_SEPARATOR = "properties"; + + private static final String LOCK_SEPARATOR = "lockGroup"; + + private final AdapterFactory adapterFactory; + + private final DTree dTree; + + private final DTreeViewerManager treeViewManager; + + private RefreshAction refreshAction; + + private final DeleteTreeItemsAction deleteItemsAction; + + private Map<TreeMapping, List<AbstractToolAction>> mappingToCreateActions; + + private List<AbstractToolAction> createActionsForTree; + + /** + * The support to use for handling contextual menu contributions. + */ + private TreePopupMenuContributionSupport treePopupMenuContributionHandler; + + /** + * Default constructor. + * + * @param tree + * The tree associates with this menu + * @param treeViewManager + * The manager of the TreeView + * @param mappingToCreateActions + * A map which associates {@link TreeMapping} with the + * corresponding list of {@link AbstractToolAction} ( + * {@link org.eclipse.sirius.tree.ui.tools.internal.editor.action.CreateLineAction} + * or + * {@link org.eclipse.sirius.tree.ui.tools.internal.editor.action.CreateTargetColumnAction} + * ) + * @param createActionsForTree + * A list of the actions for create lines under the tree. + */ + public DTreeMenuListener(final DTree tree, final DTreeViewerManager treeViewManager, final Map<TreeMapping, List<AbstractToolAction>> mappingToCreateActions, + final List<AbstractToolAction> createActionsForTree) { + super(); + adapterFactory = DialectUIManager.INSTANCE.createAdapterFactory(); + this.dTree = tree; + this.treeViewManager = treeViewManager; + this.treePopupMenuContributionHandler = new TreePopupMenuContributionSupport(this.treeViewManager.getEditingDomain(), this.treeViewManager.getTreeCommandFactory()); + this.deleteItemsAction = new DeleteTreeItemsAction(treeViewManager.getEditingDomain(), treeViewManager.getTreeCommandFactory()); + + setMappingToCreateActions(mappingToCreateActions); + setCreateActionsForTree(createActionsForTree); + refreshAction = new RefreshAction((DTreeEditor) treeViewManager.getEditor()); + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.jface.action.IMenuListener#menuAboutToShow(org.eclipse.jface.action.IMenuManager) + */ + public void menuAboutToShow(final IMenuManager manager) { + // Refresh the cached actions if needed + treeViewManager.fillMenu(); + // Add line menus + addTreeItemMenus(manager); + // Add navigate menus + addNavigateMenu(manager); + manager.add(new Separator()); + // Add viewpoint menus + addRefreshMenu(manager); + manager.add(new Separator()); + manager.add(new Separator(DTreeMenuListener.LOCK_SEPARATOR)); + addTreeMenus(manager); + // Add show properties view + manager.add(new Separator(DTreeMenuListener.PROPERTIES_SEPARATOR)); + manager.add(new Separator()); + manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); + } + + /** + * Add the tree menus if any line is selected.<BR> + * + * @param manager + * the menu manager + */ + private void addTreeMenus(final IMenuManager manager) { + final Collection<DTreeItem> selectedItems = treeViewManager.getSelectedItems(); + if (selectedItems != null && !selectedItems.isEmpty()) { + for (final AbstractToolAction abstractToolAction : getCreateActionsForTree()) { + if (abstractToolAction instanceof CreateToolItemAction) { + final CreateToolItemAction createLineAction = (CreateToolItemAction) abstractToolAction; + if (createLineAction.canExecute()) { + manager.add(createLineAction); + } + + } + } + manager.add(new Separator()); + } + } + + /** + * Add the navigate sub menu and its actions if needed. + * + * @param manager + * The menu manager + */ + private void addNavigateMenu(final IMenuManager manager) { + // Create a new sub-menu manager + final MenuManager navigateMenuManager = new MenuManager("Navigate", DTreeMenuListener.MENU_NAVIGATE_ID); + // Create the item to add to the main manager + final SubContributionItem navigateMenuItem = new SubContributionItem(navigateMenuManager); + manager.add(navigateMenuItem); + // Add menus to navigate through existing representations (created by + // RepresentationCreationDescription) + final Separator existingGroup = new Separator(DTreeMenuListener.EXISTING_REPRESENTATION_GROUP_SEPARATOR); + navigateMenuManager.add(existingGroup); + // Add menus to navigate through existing representations (corresponding + // to the RepresentationNavigationDescription) + final Separator navigateRepresentationGroup = new Separator(NAVIGATE_REPRESENTATION_GROUP_SEPARATOR); + navigateMenuManager.add(navigateRepresentationGroup); + // Add menus to navigate through new representations (corresponding to + // the RepresentationCreationDescription) + final Separator createGroup = new Separator(DTreeMenuListener.NEW_REPRESENTATION_GROUP_SEPARATOR); + navigateMenuManager.add(createGroup); + final Collection<DTreeItem> currentTreeElements = treeViewManager.getSelectedItems(); + if (currentTreeElements != null && currentTreeElements.size() == 1) { + DTreeItem currentTreeElement = currentTreeElements.iterator().next(); + // Add actions to navigate to existing representation + createNavigationAction(navigateMenuItem, currentTreeElement); + // Add actions to navigate to new representation + if (currentTreeElement instanceof DTreeItem) { + createDetailsActions((DTreeItem) currentTreeElement, navigateMenuItem); + } + } else { + // Add actions to navigate to existing representation + createNavigationAction(navigateMenuItem, dTree); + } + } + + /** + * @param navigateMenuItem + * @param semanticElement + */ + private void createNavigationAction(final SubContributionItem navigate, final DSemanticDecorator decorator) { + final EObject semanticElement = decorator.getTarget(); + final Session session = SessionManager.INSTANCE.getSession(semanticElement); + if (session != null) { + final Collection<DRepresentation> otherRepresentations = DialectManager.INSTANCE.getRepresentations(semanticElement, session); + for (final DRepresentation representation : otherRepresentations) { + navigate.setVisible(true); + ((IMenuManager) navigate.getInnerItem()).appendToGroup(EXISTING_REPRESENTATION_GROUP_SEPARATOR, buildOpenRepresentationAction(session, representation)); + } + if (decorator instanceof DRepresentationElement) { + if (buildNavigableRepresentationsMenu((IMenuManager) navigate.getInnerItem(), decorator, session)) { + // if at least one navigable representation menu + // has been created, we have to make the navigate menu + // visible + navigate.setVisible(true); + } + } + } + } + + private boolean buildNavigableRepresentationsMenu(final IMenuManager navigate, final EObject designerObj, final Session session) { + final DRepresentationElement element = (DRepresentationElement) designerObj; + if (element.getMapping() != null) { + + for (final RepresentationNavigationDescription navDesc : element.getMapping().getNavigationDescriptions()) { + final IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(element.getTarget()); + + final Map<AbstractVariable, Object> variables = new HashMap<AbstractVariable, Object>(); + variables.put(navDesc.getContainerVariable(), element.getTarget()); + variables.put(navDesc.getContainerViewVariable(), element); + + final InitInterpreterVariablesTask init = new InitInterpreterVariablesTask(variables, interpreter, new EMFCommandFactoryUI()); + init.execute(); + + boolean precondition = true; + if (!StringUtil.isEmpty(navDesc.getPrecondition())) { + try { + precondition = interpreter.evaluateBoolean(element.getTarget(), navDesc.getPrecondition()); + } catch (final EvaluationException e) { + RuntimeLoggerManager.INSTANCE.error(navDesc, ToolPackage.eINSTANCE.getAbstractToolDescription_Precondition(), e); + } + } + + if (precondition) { + // VP-2659 : we return true if at least one action has been + // added in the menu to make it visible + return buildOpenRepresentationActions(navigate, interpreter, navDesc, element, session); + } + } + } + return false; + } + + private boolean buildOpenRepresentationActions(final IMenuManager navigate, final IInterpreter interpreter, final RepresentationNavigationDescription navDesc, + final DRepresentationElement element, final Session session) { + boolean atLeastOneRepresentationActionsWasCreated = false; + Collection<EObject> candidates; + if (!StringUtil.isEmpty(navDesc.getBrowseExpression())) { + final RuntimeLoggerInterpreter safeInterpreter = RuntimeLoggerManager.INSTANCE.decorate(interpreter); + candidates = safeInterpreter.evaluateCollection(element.getTarget(), navDesc, ToolPackage.eINSTANCE.getRepresentationNavigationDescription_BrowseExpression()); + } else { + candidates = new ArrayList<EObject>(); + final Iterator<EObject> it = SiriusPlugin.getDefault().getModelAccessorRegistry().getModelAccessor(element.getTarget()).eAllContents(element.getTarget()); + while (it.hasNext()) { + candidates.add(it.next()); + } + } + final Collection<DRepresentation> representations = DialectManager.INSTANCE.getRepresentations(navDesc.getRepresentationDescription(), session); + for (final DRepresentation representation : representations) { + if (representation instanceof DSemanticDecorator && candidates.contains(((DSemanticDecorator) representation).getTarget())) { + interpreter.setVariable(navDesc.getRepresentationNameVariable().getName(), representation.getName()); + String label = new StringBuffer("Open ").append(navDesc.getName()).append(" : ").append(representation.getName()).toString(); + if (!StringUtil.isEmpty(navDesc.getNavigationNameExpression())) { + try { + label = interpreter.evaluateString(element.getTarget(), navDesc.getNavigationNameExpression()); + } catch (final EvaluationException e) { + RuntimeLoggerManager.INSTANCE.error(navDesc, ToolPackage.eINSTANCE.getRepresentationNavigationDescription_NavigationNameExpression(), e); + } + } + navigate.appendToGroup(NAVIGATE_REPRESENTATION_GROUP_SEPARATOR, buildOpenRepresentationAction(session, representation, label)); + atLeastOneRepresentationActionsWasCreated = true; + } + } + return atLeastOneRepresentationActionsWasCreated; + } + + private IAction buildOpenRepresentationAction(final Session session, final DRepresentation representation) { + String representationName = representation.getName(); + if (StringUtil.isEmpty(representationName)) { + representationName = "(unnamed)"; + if (representation instanceof DDiagram) { + representationName += " " + new IdentifiedElementQuery(((DDiagram) representation).getDescription()).getLabel(); + } + } + return buildOpenRepresentationAction(session, representation, "Open " + representationName); + } + + private IAction buildOpenRepresentationAction(final Session session, final DRepresentation representation, final String label) { + + ImageDescriptor imageDescriptor = null; + final IItemLabelProvider labelProvider = (IItemLabelProvider) adapterFactory.adapt(representation, IItemLabelProvider.class); + if (labelProvider != null) { + imageDescriptor = ExtendedImageRegistry.getInstance().getImageDescriptor(labelProvider.getImage(representation)); + } + return new OpenRepresentationAction(label, imageDescriptor, representation, session); + + } + + private void addRefreshMenu(final IMenuManager manager) { + manager.add(refreshAction); + } + + private void addTreeItemMenus(final IMenuManager manager) { + final Collection<DTreeItem> selectedItems = treeViewManager.getSelectedItems(); + if (selectedItems != null && !selectedItems.isEmpty()) { + manager.add(new Separator()); + + // Expose popup menus if there is only one selected line. + if (selectedItems.size() == 1) { + DTreeItem firstSelectedItem = selectedItems.iterator().next(); + // VP-915 : handling users contributing throw PopupMenus tools + treePopupMenuContributionHandler.contributeToPopupMenu(manager, firstSelectedItem); + } + + addDeleteItemsAction(manager, selectedItems); + + // Expose create actions if there is only one selected line. + if (selectedItems.size() == 1) { + DTreeItem firstSelectedItem = selectedItems.iterator().next(); + addCreateActions(manager, firstSelectedItem); + } + + } + } + + private void addCreateActions(IMenuManager manager, DTreeItem singleSelectedItem) { + if (singleSelectedItem.getActualMapping() != null) { + final List<AbstractToolAction> createActions = getMappingToCreateActions().get(singleSelectedItem.getActualMapping()); + if (createActions != null && !createActions.isEmpty()) { + for (final AbstractToolAction createAction : createActions) { + ((AbstractToolItemAction) createAction).setLine(singleSelectedItem); + if (createAction.canExecute()) { + manager.add(createAction); + } + } + } + } + + } + + private void addDeleteItemsAction(IMenuManager manager, Collection<DTreeItem> selectedItems) { + deleteItemsAction.setItems(selectedItems); + if (deleteItemsAction.canExecute()) { + manager.add(deleteItemsAction); + } + } + + private void createDetailsActions(final DTreeItem currentElement, final SubContributionItem navigate) { + if (currentElement.getActualMapping() != null) { + final Iterator<RepresentationCreationDescription> it = currentElement.getActualMapping().getDetailDescriptions().iterator(); + while (it.hasNext()) { + final RepresentationCreationDescription desc = it.next(); + final String precondition = desc.getPrecondition(); + boolean append = true; + if (precondition != null && !StringUtil.isEmpty(precondition.trim())) { + append = false; + final IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(currentElement.getTarget()); + try { + append = interpreter.evaluateBoolean(currentElement.getTarget(), precondition); + } catch (final EvaluationException e) { + // do nothing + } + } + if (append) { + navigate.setVisible(true); + ((IMenuManager) navigate.getInnerItem()).appendToGroup(NEW_REPRESENTATION_GROUP_SEPARATOR, new CreateRepresentationFromRepresentationCreationDescription(desc, currentElement, + treeViewManager.getEditingDomain(), treeViewManager.getTreeCommandFactory())); + } + } + } + } + + protected Map<TreeMapping, List<AbstractToolAction>> getMappingToCreateActions() { + return mappingToCreateActions; + } + + public void setMappingToCreateActions(final Map<TreeMapping, List<AbstractToolAction>> mappingToCreateActions) { + this.mappingToCreateActions = mappingToCreateActions; + } + + protected List<AbstractToolAction> getCreateActionsForTree() { + return createActionsForTree; + } + + public void setCreateActionsForTree(final List<AbstractToolAction> createActionsForTable) { + this.createActionsForTree = createActionsForTable; + } +} diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/DTreeViewer.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/DTreeViewer.java new file mode 100644 index 0000000000..0274b98e3d --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/DTreeViewer.java @@ -0,0 +1,111 @@ +/******************************************************************************* + * Copyright (c) 2011 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.tools.internal.editor; + +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.TreeItem; + +import org.eclipse.sirius.business.api.session.Session; +import org.eclipse.sirius.tree.ui.tools.internal.editor.listeners.DTreeItemExpansionChecker; +import org.eclipse.sirius.ui.tools.internal.editor.AbstractDTreeViewer; + +/** + * Sirius {@link AbstractDTreeViewer} for DTree model. + * + * @author <a href="mailto:esteban.dugueperoux@obeo.fr">Esteban Dugueperoux</a> + */ +public class DTreeViewer extends AbstractDTreeViewer { + + private DTreeItemExpansionChecker dTreeItemExpansionChecker; + + /** + * Creates a tree viewer on the given tree control. The viewer has no input, + * no content provider, a default label provider, no sorter, and no filters. + * + * @param parent + * the parent control + * @param style + * the SWT style bits used to create the tree. + * @param session + * the {@link Session} used by the underlying model + */ + public DTreeViewer(final Composite parent, final int style, final Session session) { + super(parent, style); + this.dTreeItemExpansionChecker.setPermissionAuthority(session.getModelAccessor().getPermissionAuthority()); + } + + /** + * Overridden to add the {@link DTreeItemExpansionChecker}. + * + * {@inheritDoc} + */ + @Override + protected void hookControl(Control control) { + dTreeItemExpansionChecker = new DTreeItemExpansionChecker(control); + super.hookControl(control); + } + + /** + * Overridden to fix a behavior difference. + * + * {@inheritDoc} + */ + @Override + public void expandToLevel(Object elementOrTreePath, int level) { + int newLevel = level; + if (level == ALL_LEVELS) { + /* + * here we're making sure we'll have the same behavior as in Linux + * even on other platforms. We don't want the user to ends up in an + * infinite loop because he stroke the "*" key on windows and this + * tree is infinite. + */ + newLevel = getCurrentExpandedLevel() + 1; + } + super.expandToLevel(elementOrTreePath, newLevel); + } + + private int getCurrentExpandedLevel() { + int maxLevel = 0; + for (TreeItem child : getTree().getItems()) { + int childValue = doBrowse(child, 1); + if (childValue > maxLevel) { + maxLevel = childValue; + } + } + return maxLevel; + }; + + private int doBrowse(TreeItem cur, int currentLevel) { + int maxLevel = currentLevel; + for (TreeItem child : cur.getItems()) { + int childValue = doBrowse(child, currentLevel + 1); + if (childValue > maxLevel) { + maxLevel = childValue; + } + } + return maxLevel; + } + + /** + * Overridden to remove the {@link DTreeItemExpansionChecker}. + * + * {@inheritDoc} + */ + @Override + protected void handleDispose(DisposeEvent event) { + dTreeItemExpansionChecker.dispose(); + super.handleDispose(event); + } + +} diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/DTreeViewerManager.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/DTreeViewerManager.java new file mode 100644 index 0000000000..4ebe75c9d2 --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/DTreeViewerManager.java @@ -0,0 +1,493 @@ +/******************************************************************************* + * Copyright (c) 2010 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.tools.internal.editor; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.emf.common.notify.AdapterFactory; +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.jface.layout.TreeColumnLayout; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.resource.ImageRegistry; +import org.eclipse.jface.viewers.ColumnViewer; +import org.eclipse.jface.viewers.ColumnViewerEditor; +import org.eclipse.jface.viewers.FocusCellOwnerDrawHighlighter; +import org.eclipse.jface.viewers.ILabelDecorator; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.ITreeViewerListener; +import org.eclipse.jface.viewers.TreeViewerEditor; +import org.eclipse.jface.viewers.TreeViewerFocusCellManager; +import org.eclipse.jface.viewers.ViewerColumn; +import org.eclipse.swt.SWT; +import org.eclipse.swt.dnd.ByteArrayTransfer; +import org.eclipse.swt.dnd.DND; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.KeyListener; +import org.eclipse.swt.events.MouseAdapter; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.TreeItem; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.views.navigator.LocalSelectionTransfer; + +import com.google.common.collect.Lists; + +import org.eclipse.sirius.common.tools.DslCommonPlugin; +import org.eclipse.sirius.common.tools.api.util.Option; +import org.eclipse.sirius.common.tools.api.util.Options; +import org.eclipse.sirius.business.api.session.Session; +import org.eclipse.sirius.business.api.session.SessionManager; +import org.eclipse.sirius.tools.api.command.ICommandFactory; +import org.eclipse.sirius.tools.api.profiler.SiriusTasksKey; +import org.eclipse.sirius.tree.DTree; +import org.eclipse.sirius.tree.DTreeItem; +import org.eclipse.sirius.tree.business.api.command.ITreeCommandFactory; +import org.eclipse.sirius.tree.business.internal.helper.TreeHelper; +import org.eclipse.sirius.tree.description.TreeDescription; +import org.eclipse.sirius.tree.description.TreeItemCreationTool; +import org.eclipse.sirius.tree.description.TreeItemMapping; +import org.eclipse.sirius.tree.description.TreeMapping; +import org.eclipse.sirius.tree.ui.provider.TreeUIPlugin; +import org.eclipse.sirius.tree.ui.tools.internal.editor.actions.AbstractToolAction; +import org.eclipse.sirius.tree.ui.tools.internal.editor.actions.CreateToolItemAction; +import org.eclipse.sirius.tree.ui.tools.internal.editor.actions.DeleteTreeItemsAction; +import org.eclipse.sirius.tree.ui.tools.internal.editor.actions.EditorCreateTreeItemMenuAction; +import org.eclipse.sirius.tree.ui.tools.internal.editor.listeners.DTreeViewerListener; +import org.eclipse.sirius.tree.ui.tools.internal.editor.provider.DTreeContentProvider; +import org.eclipse.sirius.tree.ui.tools.internal.editor.provider.DTreeDecoratingLabelProvider; +import org.eclipse.sirius.tree.ui.tools.internal.editor.provider.DTreeItemDropListener; +import org.eclipse.sirius.tree.ui.tools.internal.editor.provider.DTreeItemEditingSupport; +import org.eclipse.sirius.ui.tools.internal.editor.AbstractDTableViewerManager; +import org.eclipse.sirius.ui.tools.internal.editor.AbstractDTreeEditor; +import org.eclipse.sirius.ui.tools.internal.editor.DTableColumnViewerEditorActivationStrategy; +import org.eclipse.sirius.ui.tools.internal.editor.DTableTreeFocusListener; +import org.eclipse.sirius.ui.tools.internal.views.sessionview.ModelDragTargetAdapter; +import org.eclipse.sirius.ecore.extender.business.api.accessor.ModelAccessor; + +/** + * This class manages the tree viewer for display the DTree. + * + * @author nlepine + */ +public class DTreeViewerManager extends AbstractDTableViewerManager { + + /** The key for the image which represents a delete action. */ + public static final String REFRESH_IMG = "tree/refresh"; + + /** The key for the image which represents a delete action. */ + public static final String DELETE_IMG = "tree/delete"; + + /** The key for the image which represents a delete action. */ + public static final String CREATE_TREE_ITEM_IMG = "tree/newTreeItem"; + + static { + imageRegistry.put(REFRESH_IMG, ImageDescriptor.createFromURL((URL) TreeUIPlugin.INSTANCE.getImage(REFRESH_IMG))); + imageRegistry.put(DELETE_IMG, ImageDescriptor.createFromURL((URL) TreeUIPlugin.INSTANCE.getImage(DELETE_IMG))); + imageRegistry.put(CREATE_TREE_ITEM_IMG, ImageDescriptor.createFromURL((URL) TreeUIPlugin.INSTANCE.getImage(CREATE_TREE_ITEM_IMG))); + } + + private ITreeViewerListener treeViewerListener; + + private final ITreeCommandFactory treeCommandFactory; + + private DTreeContentProvider dTreeContentProvider; + + private DTreeMenuListener actualMenuListener; + + private AdapterFactory adapterFactory; + + private final EditorCreateTreeItemMenuAction createTreeItemMenu = new EditorCreateTreeItemMenuAction(); + + /** + * The constructor. + * + * @param parent + * The parent composite + * @param input + * The input DTable + * @param editingDomain + * The transactional editing domain of this viewer + * @param accessor + * The accessor for the model + * @param tableCommandFactory + * The EMF command factory + * @param treeEditor + * The associated editor + */ + public DTreeViewerManager(final Composite parent, final DTree input, final TransactionalEditingDomain editingDomain, final ModelAccessor accessor, final ICommandFactory tableCommandFactory, + final AbstractDTreeEditor treeEditor) { + super(parent, input, editingDomain, accessor, tableCommandFactory, treeEditor); + this.treeCommandFactory = (ITreeCommandFactory) tableCommandFactory; + adapterFactory = TreeUIPlugin.getPlugin().getItemProvidersAdapterFactory(); + this.createTreeViewer(parent); + } + + public static ImageRegistry getImageRegistry() { + return imageRegistry; + } + + /** + * Creates the TreeViewer. + * + * Problem for action on column header + * + * @param composite + * the Container of the TreeViewer to create + */ + @Override + protected void createTreeViewer(final Composite composite) { + // Create a composite to hold the children + final GridData gridData = new GridData(GridData.FILL_BOTH); + composite.setLayoutData(gridData); + + final TreeColumnLayout treeLayout = new TreeColumnLayout(); + composite.setLayout(treeLayout); + + // Create and setup the TreeViewer + final int style = SWT.H_SCROLL | SWT.V_SCROLL | SWT.MULTI; + + treeViewer = new DTreeViewer(composite, style, getSession()); + + // Add a focus listener to deactivate the EMF actions on the Tree + treeViewer.getTree().addFocusListener(new DTableTreeFocusListener(tableEditor, treeViewer.getTree())); + treeViewer.setUseHashlookup(true); + + // tableViewer.setSorter(new + // ExampleTaskSorter(ExampleTaskSorter.DESCRIPTION)); + + dTreeContentProvider = new DTreeContentProvider(getSession(), this); + treeViewer.setContentProvider(dTreeContentProvider); + + // Wrap the LabelProvider in a DecoratingLabelProvider + ILabelDecorator decorator = PlatformUI.getWorkbench().getDecoratorManager().getLabelDecorator(); + treeViewer.setLabelProvider(new DTreeDecoratingLabelProvider(adapterFactory, decorator)); + + fillMenu(); + triggerColumnSelectedColumn(); + initializeEditingSupport(); + initializeDragAndDropSupport(); + initializeKeyBindingSupport(); + + treeViewerListener = new DTreeViewerListener(getSession()); + treeViewer.addTreeListener(treeViewerListener); + + // Manage height of the lines, selected colors, + triggerCustomDrawingTreeItems(); + + // Create a new CellFocusManager + final TreeViewerFocusCellManager focusCellManager = new TreeViewerFocusCellManager(treeViewer, new FocusCellOwnerDrawHighlighter(treeViewer)); + // Create a TreeViewerEditor with focusable cell + TreeViewerEditor.create(treeViewer, focusCellManager, new DTableColumnViewerEditorActivationStrategy(treeViewer), ColumnViewerEditor.TABBING_HORIZONTAL + | ColumnViewerEditor.TABBING_MOVE_TO_ROW_NEIGHBOR | ColumnViewerEditor.TABBING_VERTICAL | ColumnViewerEditor.KEYBOARD_ACTIVATION); + + // The input for the table viewer is the instance of DTable + treeViewer.setInput(dRepresentation); + + // Expands the line according to the model + treeViewer.setExpandedElements(TreeHelper.getExpandedItems((DTree) dRepresentation).toArray()); + } + + private void initializeKeyBindingSupport() { + treeViewer.getTree().addKeyListener(new KeyListener() { + public void keyPressed(final KeyEvent e) { + if (e.keyCode == SWT.DEL) { + DeleteTreeItemsAction deleteItemsAction = new DeleteTreeItemsAction(getEditingDomain(), getTreeCommandFactory()); + deleteItemsAction.setItems(getSelectedItems()); + if (deleteItemsAction.canExecute()) { + deleteItemsAction.run(); + } + } + } + public void keyReleased(final KeyEvent e) { + }; + }); + } + + private Session getSession() { + return SessionManager.INSTANCE.getSession(((DTree) dRepresentation).getTarget()); + } + + /** + * Initializes the Editing Support (allowing direct Edit) to associate to + * the current Tree. + */ + protected void initializeEditingSupport() { + + // Step 1 : get the TreeViewerColumn corresponding to this Tree + DslCommonPlugin.PROFILER.startWork(SiriusTasksKey.ADD_SWT_COLUMN_KEY); + + Option<ViewerColumn> optionViewerColumn = getViewerColumn(); + if (optionViewerColumn.some()) { + ViewerColumn treeColumn = optionViewerColumn.get(); + + // Step 2 : set the Editing support + treeColumn.setEditingSupport(new DTreeItemEditingSupport(treeViewer, getEditingDomain(), getAccessor(), getTreeCommandFactory(), this.getEditor())); + } + DslCommonPlugin.PROFILER.stopWork(SiriusTasksKey.ADD_SWT_COLUMN_KEY); + } + + /** + * Initializes Drag and Drop support for the current DTree. + */ + protected void initializeDragAndDropSupport() { + // If copy/paste operations should be supported, may add + // " | DND.DROP_COPY" to the supported operations. + int supportedOperations = DND.DROP_MOVE | DND.DROP_LINK; + + ISelectionProvider selectionProvider = this.treeViewer; + this.treeViewer.addDragSupport(supportedOperations, new ByteArrayTransfer[] { LocalSelectionTransfer.getInstance() }, new ModelDragTargetAdapter(selectionProvider)); + this.treeViewer.addDropSupport(supportedOperations, new ByteArrayTransfer[] { LocalSelectionTransfer.getInstance() }, new DTreeItemDropListener(this.treeViewer, this.editingDomain, + this.treeCommandFactory, this.accessor)); + } + + /** + * Returns the viewer column associated to the treeViewer. + * + * @return the viewer column of the treeViewer, or Options.newNone() if to + * viewer column found. + */ + private Option<ViewerColumn> getViewerColumn() { + Option<ViewerColumn> viewerColumn = Options.newNone(); + + // We use reflection to access to the ColumnViewer.getViewerColumn(int) + // method (package visibility) + Class<?> columnViewerClass = ColumnViewer.class; + Method method; + try { + method = columnViewerClass.getDeclaredMethod("getViewerColumn", Integer.TYPE); + method.setAccessible(true); + Object invoke = method.invoke(treeViewer, 0); + if (invoke instanceof ViewerColumn) { + viewerColumn = Options.newSome((ViewerColumn) invoke); + } + } catch (SecurityException e) { + // Nothing to do, method will return Options.NONE + } catch (NoSuchMethodException e) { + // Nothing to do, method will return Options.NONE + } catch (IllegalArgumentException e) { + // Nothing to do, method will return Options.NONE + } catch (InvocationTargetException e) { + // Nothing to do, method will return Options.NONE + } catch (IllegalAccessException e) { + // Nothing to do, method will return Options.NONE + } + + return viewerColumn; + } + + /** + * Initialize a cache and add, if needed, the contextual menu for the table. <BR> + * Cached the actions of creation and deletion in order to increase + * performance and not calculate it on each contextual menu.<BR> + */ + @Override + public void fillMenu() { + if (descriptionFileChanged) { + descriptionFileChanged = false; + final Map<TreeMapping, List<AbstractToolAction>> mappingToCreateActions = new HashMap<TreeMapping, List<AbstractToolAction>>(); + final List<AbstractToolAction> createActionsForTree = new ArrayList<AbstractToolAction>(); + + calculateAvailableMenus(mappingToCreateActions, createActionsForTree); + mgr.setRemoveAllWhenShown(true); + if (actualMenuListener != null) { + mgr.removeAll(); + actualMenuListener.setMappingToCreateActions(mappingToCreateActions); + actualMenuListener.setCreateActionsForTree(createActionsForTree); + } else { + actualMenuListener = new DTreeMenuListener((DTree) dRepresentation, this, mappingToCreateActions, createActionsForTree); + mgr.addMenuListener(actualMenuListener); + // + final Menu menu = mgr.createContextMenu(treeViewer.getControl()); + treeViewer.getControl().setMenu(menu); + // // Add this line to have others contextual menus + tableEditor.getSite().registerContextMenu(mgr, treeViewer); + } + getCreateTreeItemMenu().update(createActionsForTree); + } + } + + /** + * Get the selected {@link DTreeItem item}. + * + * @return the selected tree items or an empty collection + */ + public Collection<DTreeItem> getSelectedItems() { + Collection<DTreeItem> result = Lists.newArrayList(); + if (treeViewer.getTree().getSelectionCount() > 0) { + for (TreeItem item : treeViewer.getTree().getSelection()) { + Object data = item.getData(); + if (data instanceof DTreeItem) { + result.add((DTreeItem) data); + } + } + } + return result; + } + + /** + * Create the menus according to the {@link TreeMapping} and the associated + * {@link CreateTool} and {@link DeleteTool}. + * + */ + private void calculateAvailableMenus(final Map<TreeMapping, List<AbstractToolAction>> mappingToCreateActions, final List<AbstractToolAction> createActionsForTree) { + + final TreeDescription treeDescription = ((DTree) dRepresentation).getDescription(); + + if (treeDescription != null) { + // Actions on lines + calculateAvailableMenusForLine(treeDescription.getSubItemMappings(), mappingToCreateActions, new ArrayList<TreeItemMapping>()); + + // Actions on table + final EList<? extends TreeItemCreationTool> createLineTools = treeDescription.getCreateTreeItem(); + for (final TreeItemCreationTool createTool : createLineTools) { + final CreateToolItemAction createLineAction = new CreateToolItemAction(createTool, getEditingDomain(), getTreeCommandFactory()); + createLineAction.setTable((DTree) dRepresentation); + createActionsForTree.add(createLineAction); + } + } + + } + + /** + * Create the menus according to the {@link LineMapping} and the associated + * {@link CreateTool} and {@link DeleteTool}. + * + * @param lineMappings + * List of {@link LineMapping} + * @param mappingToCreateActions + * A map which associates {@link TreeMapping} with the + * corresponding list of {@link AbstractToolAction} ( + * {@link CreateLineAction} or {@link CreateTargetColumnAction}) + */ + private void calculateAvailableMenusForLine(final EList<TreeItemMapping> lineMappings, final Map<TreeMapping, List<AbstractToolAction>> mappingToCreateActions, + final List<TreeItemMapping> processedLineMappings) { + for (final TreeItemMapping treeItemMapping : lineMappings) { + if (treeItemMapping != null && !mappingToCreateActions.keySet().contains(treeItemMapping)) { + final EList<? extends TreeItemCreationTool> createTools = treeItemMapping.getCreate(); + List<AbstractToolAction> existingCreateTools = mappingToCreateActions.get(treeItemMapping); + if (existingCreateTools == null) { + existingCreateTools = new ArrayList<AbstractToolAction>(); + } + for (final TreeItemCreationTool createTool : createTools) { + existingCreateTools.add(new CreateToolItemAction(createTool, getEditingDomain(), getTreeCommandFactory())); + } + mappingToCreateActions.put(treeItemMapping, existingCreateTools); + } + if (treeItemMapping != null && !processedLineMappings.contains(treeItemMapping)) { + processedLineMappings.add(treeItemMapping); + calculateAvailableMenusForLine(treeItemMapping.getAllSubMappings(), mappingToCreateActions, processedLineMappings); + } + } + } + + /** + * Add a listener on the tree to listen the mouseDouwn or the key left-right + * arrows and store the activeColumn + */ + private void triggerColumnSelectedColumn() { + treeViewer.getTree().addMouseListener(new MouseAdapter() { + + @Override + public void mouseDown(final MouseEvent event) { + int x = 0; + for (int i = 0; i < treeViewer.getTree().getColumnCount(); i++) { + x += treeViewer.getTree().getColumn(i).getWidth(); + if (event.x <= x) { + activeColumn = i; + break; + } + } + } + + }); + treeViewer.getTree().addKeyListener(new KeyListener() { + public void keyPressed(final KeyEvent e) { + if (e.keyCode == SWT.ARROW_LEFT && activeColumn != 0) { + activeColumn--; + treeViewer.getTree().showColumn(treeViewer.getTree().getColumn(activeColumn)); + } else if (e.keyCode == SWT.ARROW_RIGHT && activeColumn != treeViewer.getTree().getColumnCount() - 1) { + activeColumn++; + treeViewer.getTree().showColumn(treeViewer.getTree().getColumn(activeColumn)); + } + } + + public void keyReleased(final KeyEvent e) { + }; + }); + + } + + /** + * Return the TableCommandFactory. + * + * @return the TableCommandFactory + */ + public ITreeCommandFactory getTreeCommandFactory() { + return treeCommandFactory; + } + + /** + * Check the tree. + * + * @param tree + * the tree to test + * @return true if the tree is equals to the dTree of this manager, false + * otherwise + */ + public boolean isSameTree(final DTree tree) { + return ((DTree) dRepresentation).equals(tree); + } + + /** + * Changed descriptionFileChanged state. + * + * @param modified + * Indicates whether the odesign file has changed since the last + * load menus + */ + @Override + public void setDescriptionFileChanged(final boolean modified) { + descriptionFileChanged = modified; + } + + /** + * Return the menu which is display in the toolBar. + * + * @return the menu for create lines on the root + */ + public EditorCreateTreeItemMenuAction getCreateTreeItemMenu() { + return createTreeItemMenu; + } + + /** + * Release resources. + */ + @Override + public void dispose() { + treeViewer.removeTreeListener(treeViewerListener); + treeViewerListener = null; + dTreeContentProvider.dispose(); + dTreeContentProvider = null; + super.dispose(); + createTreeItemMenu.dispose(); + } + +} diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/RefreshAtOpeningActivator.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/RefreshAtOpeningActivator.java new file mode 100644 index 0000000000..94265e0853 --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/RefreshAtOpeningActivator.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright (c) 2013 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.tools.internal.editor; + +import org.eclipse.ui.IPartListener; +import org.eclipse.ui.IWorkbenchPart; + +/** + * IPartListener to allows update of the DTree model after tree dialect editor + * opening. Done here because it is call even with IMemento. + * + * @author <a href="mailto:esteban.dugueperoux@obeo.fr">Esteban Dugueperoux</a> + */ +public class RefreshAtOpeningActivator implements IPartListener { + + private DTreeEditor dTreeEditor; + + /** + * Default constructor. + * + * @param dTreeEditor + * the {@link DTreeEditor} + */ + public RefreshAtOpeningActivator(DTreeEditor dTreeEditor) { + this.dTreeEditor = dTreeEditor; + } + + /** + * {@inheritDoc} + * + * @see IPartListener#partActivated(IWorkbenchPart) + */ + public void partActivated(IWorkbenchPart part) { + + } + + /** + * {@inheritDoc} + * + * @see IPartListener#partBroughtToTop(IWorkbenchPart) + */ + public void partBroughtToTop(IWorkbenchPart part) { + + } + + /** + * {@inheritDoc} + * + * @see IPartListener#partClosed(IWorkbenchPart) + */ + public void partClosed(IWorkbenchPart part) { + + } + + /** + * {@inheritDoc} + * + * @see IPartListener#partDeactivated(IWorkbenchPart) + */ + public void partDeactivated(IWorkbenchPart part) { + + } + + /** + * {@inheritDoc} + * + * @see IPartListener#partOpened(IWorkbenchPart) + */ + public void partOpened(IWorkbenchPart part) { + // Activation of the refresh of the DTree property page + dTreeEditor.enablePropertiesUpdate(true); + dTreeEditor.forceRefreshProperties(); + } + +} diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/actions/AbstractToolAction.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/actions/AbstractToolAction.java new file mode 100644 index 0000000000..e398e7bba3 --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/actions/AbstractToolAction.java @@ -0,0 +1,107 @@ +/******************************************************************************* + * Copyright (c) 2010 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.tools.internal.editor.actions; + +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.jface.action.Action; +import org.eclipse.jface.resource.ImageDescriptor; + +import org.eclipse.sirius.tree.business.api.command.ITreeCommandFactory; +import org.eclipse.sirius.tree.description.TreeItemTool; + +/** + * An abstract class for all actions which launch tool (DeleteTool, CreateTool). + * + * @author nlepine + */ +public class AbstractToolAction extends Action { + TransactionalEditingDomain editingDomain; + + ITreeCommandFactory treeCommandFactory; + + /** + * The tool corresponding to this action. + */ + TreeItemTool tool; + + /** + * Creates a new action with the given text. + * + * @param text + * the action's text, or <code>null</code> if there is no text + * @param editingDomain + * The transactional editing domain + * @param treeCommandFactory + * The EMF command factory + * @param treeTool + * The tool corresponding to this action + * + */ + public AbstractToolAction(final String text, final TransactionalEditingDomain editingDomain, final ITreeCommandFactory treeCommandFactory, final TreeItemTool treeTool) { + super(text); + this.editingDomain = editingDomain; + this.treeCommandFactory = treeCommandFactory; + this.tool = treeTool; + } + + /** + * Creates a new action with the given text and style. + * + * @param text + * the action's text, or <code>null</code> if there is no text + * @param image + * the action's image, or <code>null</code> if there is no image + * @param editingDomain + * The transactional editing domain + * @param treeCommandFactory + * The EMF command factory + * @param treeTool + * The tool corresponding to this action + */ + public AbstractToolAction(final String text, final ImageDescriptor image, final TransactionalEditingDomain editingDomain, final ITreeCommandFactory treeCommandFactory, final TreeItemTool treeTool) { + super(text, image); + this.editingDomain = editingDomain; + this.treeCommandFactory = treeCommandFactory; + this.tool = treeTool; + } + + /** + * return The transactional editing domain. + * + * @return the editingDomain + */ + protected TransactionalEditingDomain getEditingDomain() { + return editingDomain; + } + + /** + * Return the EMF command factory. + * + * @return the treeCommandFactory + */ + protected ITreeCommandFactory getITreeCommandFactory() { + return treeCommandFactory; + } + + /** + * The default implementation of this <code>AbstractToolAction</code> method + * return false. Subclasses should override this method. + * + * @return true if this action can be execute, false otherwise + */ + public boolean canExecute() { + return false; + } + + protected TreeItemTool getTool() { + return tool; + } +} diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/actions/AbstractToolItemAction.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/actions/AbstractToolItemAction.java new file mode 100644 index 0000000000..7756248363 --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/actions/AbstractToolItemAction.java @@ -0,0 +1,85 @@ +/******************************************************************************* + * Copyright (c) 2010 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.tools.internal.editor.actions; + +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.jface.resource.ImageDescriptor; + +import org.eclipse.sirius.tree.DTreeItem; +import org.eclipse.sirius.tree.business.api.command.ITreeCommandFactory; +import org.eclipse.sirius.tree.description.TreeItemTool; + +/** + * An abstract class for all actions on {@link DLine}. + * + * @author nlepine + */ +public abstract class AbstractToolItemAction extends AbstractToolAction { + + /** + * The line concerned with this action + */ + private DTreeItem line; + + /** + * Creates a new action with the given text and the given line. + * + * @param text + * the action's text, or <code>null</code> if there is no text + * @param editingDomain + * The transactional editing domain + * @param treeCommandFactory + * The EMF command factory + * @param treeTool + * The tool corresponding to this action + */ + public AbstractToolItemAction(final String text, final TransactionalEditingDomain editingDomain, final ITreeCommandFactory treeCommandFactory, final TreeItemTool treeTool) { + super(text, editingDomain, treeCommandFactory, treeTool); + } + + /** + * Creates a new action with the given text and style. + * + * @param text + * the action's text, or <code>null</code> if there is no text + * @param image + * the action's image, or <code>null</code> if there is no image + * @param editingDomain + * The transactional editing domain + * @param treeCommandFactory + * The EMF command factory + * @param treeTool + * The tool corresponding to this action + */ + public AbstractToolItemAction(final String text, final ImageDescriptor image, final TransactionalEditingDomain editingDomain, final ITreeCommandFactory treeCommandFactory, + final TreeItemTool treeTool) { + super(text, image, editingDomain, treeCommandFactory, treeTool); + } + + /** + * Return the line. + * + * @return the line + */ + public DTreeItem getTreeItem() { + return line; + } + + /** + * Set the line on which the tool of this action applied. + * + * @param line + * the line to set + */ + public void setLine(final DTreeItem line) { + this.line = line; + } +} diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/actions/CreateRepresentationFromRepresentationCreationDescription.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/actions/CreateRepresentationFromRepresentationCreationDescription.java new file mode 100644 index 0000000000..c8979d7c80 --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/actions/CreateRepresentationFromRepresentationCreationDescription.java @@ -0,0 +1,143 @@ +/******************************************************************************* + * Copyright (c) 2010 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.tools.internal.editor.actions; + +import org.eclipse.emf.common.command.Command; +import org.eclipse.emf.common.command.CompoundCommand; +import org.eclipse.emf.common.notify.AdapterFactory; +import org.eclipse.emf.edit.provider.IItemLabelProvider; +import org.eclipse.emf.edit.ui.provider.ExtendedImageRegistry; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.jface.action.Action; +import org.eclipse.jface.resource.ImageDescriptor; + +import org.eclipse.sirius.common.tools.api.interpreter.EvaluationException; +import org.eclipse.sirius.common.tools.api.interpreter.IInterpreter; +import org.eclipse.sirius.common.tools.api.util.StringUtil; +import org.eclipse.sirius.common.ui.SiriusTransPlugin; +import org.eclipse.sirius.DRepresentationElement; +import org.eclipse.sirius.business.api.dialect.command.CreateRepresentationCommand; +import org.eclipse.sirius.business.api.logger.RuntimeLoggerManager; +import org.eclipse.sirius.business.api.session.Session; +import org.eclipse.sirius.business.api.session.SessionManager; +import org.eclipse.sirius.description.DescriptionPackage; +import org.eclipse.sirius.description.RepresentationDescription; +import org.eclipse.sirius.description.tool.RepresentationCreationDescription; +import org.eclipse.sirius.description.tool.ToolPackage; +import org.eclipse.sirius.tools.api.interpreter.InterpreterUtil; +import org.eclipse.sirius.tree.business.api.command.ITreeCommandFactory; +import org.eclipse.sirius.ui.business.api.dialect.DialectUIManager; +import org.eclipse.sirius.ui.tools.api.image.ImagesPath; + +/** + * Create a new Representation from a {@link RepresentationCreationDescription}. + * + * @author <a href="mailto:nathalie.lepine@obeo.fr">Nathalie Lepine</a> + */ +public class CreateRepresentationFromRepresentationCreationDescription extends Action { + + private static final AdapterFactory ADAPTER_FACTORY = DialectUIManager.INSTANCE.createAdapterFactory(); + + private final RepresentationCreationDescription desc; + + private final DRepresentationElement target; + + private final TransactionalEditingDomain editingDomain; + + private final ITreeCommandFactory treeCommandFactory; + + /** + * Build the action. + * + * @param desc + * {@link RepresentationCreationDescription} to use. + * @param target + * element on which the user requested the creation of a new + * representation. + * @param editingDomain + * current {@link org.eclipse.emf.edit.domain.EditingDomain}. + * @param tableCommandFactory + * The {@link ITableCommandFactory}. + */ + public CreateRepresentationFromRepresentationCreationDescription(final RepresentationCreationDescription desc, final DRepresentationElement target, final TransactionalEditingDomain editingDomain, + final ITreeCommandFactory tableCommandFactory) { + this.desc = desc; + this.target = target; + this.editingDomain = editingDomain; + ImageDescriptor imageDescriptor = null; + RepresentationDescription representationDescription = desc.getRepresentationDescription(); + if (representationDescription != null) { + // Search the icon for this representation description + final IItemLabelProvider labelProvider = (IItemLabelProvider) CreateRepresentationFromRepresentationCreationDescription.ADAPTER_FACTORY.adapt(representationDescription, + IItemLabelProvider.class); + if (labelProvider != null) { + imageDescriptor = ExtendedImageRegistry.getInstance().getImageDescriptor(labelProvider.getImage(representationDescription)); + } + } + if (imageDescriptor != null) { + setImageDescriptor(imageDescriptor); + } else { + setImageDescriptor(SiriusTransPlugin.getBundledImageDescriptor(ImagesPath.CREATE_VIEW_ICON)); + } + this.treeCommandFactory = tableCommandFactory; + } + + @Override + public String getText() { + return new StringBuffer("New detail : ").append(desc.getName()).toString(); + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.jface.action.Action#run() + */ + @Override + public void run() { + final CompoundCommand compoundCommand = new CompoundCommand(); + + final IInterpreter interpreter = InterpreterUtil.getInterpreter(target.getTarget()); + // default name + String name = "new " + desc.getName(); + if (!StringUtil.isEmpty(desc.getTitleExpression())) { + try { + name = interpreter.evaluateString(target.getTarget(), desc.getTitleExpression()); + } catch (final EvaluationException e) { + RuntimeLoggerManager.INSTANCE.error(desc, ToolPackage.eINSTANCE.getRepresentationCreationDescription_TitleExpression(), e); + } + } else if (desc.getRepresentationDescription() != null && !StringUtil.isEmpty(desc.getRepresentationDescription().getTitleExpression())) { + try { + name = interpreter.evaluateString(target.getTarget(), desc.getRepresentationDescription().getTitleExpression()); + } catch (final EvaluationException e) { + RuntimeLoggerManager.INSTANCE.error(desc.getRepresentationDescription(), DescriptionPackage.eINSTANCE.getRepresentationDescription_TitleExpression(), e); + } + } + + try { + name = treeCommandFactory.getUserInterfaceCallBack().askForDetailName(name, desc.getRepresentationDescription().getEndUserDocumentation()); + + if (desc.getInitialOperation() != null && desc.getInitialOperation().getFirstModelOperations() != null) { + final Command emfCommandTool = treeCommandFactory.buildDoExecuteDetailsOperation(target, desc, name); + compoundCommand.append(emfCommandTool); + } + final CreateRepresentationCommand command = treeCommandFactory.buildCreateRepresentationFromDescription(desc, target, name); + compoundCommand.append(command); + editingDomain.getCommandStack().execute(compoundCommand); + + final Session session = SessionManager.INSTANCE.getSession(target.getTarget()); + + DialectUIManager.INSTANCE.openEditor(session, command.getCreatedRepresentation()); + } catch (final InterruptedException e) { + // the user pressed "cancel", let's do nothing + } + + } +} diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/actions/CreateToolItemAction.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/actions/CreateToolItemAction.java new file mode 100644 index 0000000000..27ffc00f74 --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/actions/CreateToolItemAction.java @@ -0,0 +1,193 @@ +/******************************************************************************* + * Copyright (c) 2010 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.tools.internal.editor.actions; + +import java.util.Iterator; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.edit.provider.IItemLabelProvider; +import org.eclipse.emf.edit.ui.provider.ExtendedImageRegistry; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.jface.resource.ImageDescriptor; + +import com.google.common.collect.Iterators; + +import org.eclipse.sirius.common.tools.api.interpreter.EvaluationException; +import org.eclipse.sirius.common.tools.api.interpreter.IInterpreter; +import org.eclipse.sirius.common.tools.api.interpreter.IInterpreterSiriusVariables; +import org.eclipse.sirius.common.tools.api.util.StringUtil; +import org.eclipse.sirius.SiriusPlugin; +import org.eclipse.sirius.business.api.logger.RuntimeLoggerManager; +import org.eclipse.sirius.business.api.query.IdentifiedElementQuery; +import org.eclipse.sirius.description.tool.CreateInstance; +import org.eclipse.sirius.description.tool.ToolPackage; +import org.eclipse.sirius.tools.api.interpreter.InterpreterUtil; +import org.eclipse.sirius.tree.DTree; +import org.eclipse.sirius.tree.DTreeItemContainer; +import org.eclipse.sirius.tree.business.api.command.ITreeCommandFactory; +import org.eclipse.sirius.tree.business.internal.helper.TreeHelper; +import org.eclipse.sirius.tree.description.TreeItemCreationTool; +import org.eclipse.sirius.tree.description.TreeItemMapping; +import org.eclipse.sirius.tree.description.TreeItemTool; +import org.eclipse.sirius.tree.ui.provider.TreeUIPlugin; +import org.eclipse.sirius.tree.ui.tools.internal.command.CreateLineCommandFromToolRecordingCommand; +import org.eclipse.sirius.tree.ui.tools.internal.editor.DTreeViewerManager; +import org.eclipse.sirius.ecore.extender.business.api.accessor.exception.MetaClassNotFoundException; + +/** + * Action to launch the createTool of the treeItemContainer (tree or tree item). + * + * @author nlepine + */ +public class CreateToolItemAction extends AbstractToolItemAction { + DTree tree; + + /** + * Constructor. + * + * @param createTool + * The tool to do some other actions + * @param editingDomain + * The transactional editing domain + * @param tableCommandFactory + * The EMF command factory + */ + public CreateToolItemAction(final TreeItemCreationTool createTool, final TransactionalEditingDomain editingDomain, final ITreeCommandFactory tableCommandFactory) { + super(new IdentifiedElementQuery(createTool).getLabel(), CreateToolItemAction.findImageDescriptor(createTool), editingDomain, tableCommandFactory, createTool); + } + + private static ImageDescriptor findImageDescriptor(TreeItemCreationTool createTool) { + + ImageDescriptor descriptor = DTreeViewerManager.getImageRegistry().getDescriptor(DTreeViewerManager.CREATE_TREE_ITEM_IMG); + EObject created = null; + + Iterator<CreateInstance> createInstances = Iterators.filter(createTool.eAllContents(), CreateInstance.class); + while (created == null && createInstances.hasNext()) { + CreateInstance map = createInstances.next(); + created = CreateToolItemAction.tryToInstanciateType(createTool, created, map.getTypeName()); + } + + Iterator<TreeItemMapping> it = createTool.getMapping().iterator(); + while (created == null && it.hasNext()) { + TreeItemMapping map = it.next(); + created = CreateToolItemAction.tryToInstanciateType(createTool, created, map.getDomainClass()); + } + + if (created != null) { + final IItemLabelProvider labelProvider = (IItemLabelProvider) TreeUIPlugin.getPlugin().getItemProvidersAdapterFactory().adapt(created, IItemLabelProvider.class); + if (labelProvider != null) { + ImageDescriptor semanticDescriptor = ExtendedImageRegistry.getInstance().getImageDescriptor(labelProvider.getImage(created)); + if (semanticDescriptor != null) { + descriptor = semanticDescriptor; + } + + } + } + + return descriptor; + } + + private static EObject tryToInstanciateType(TreeItemCreationTool createTool, EObject created, String map) { + EObject result = created; + if (!StringUtil.isEmpty(map)) { + try { + final EObject anInstance = SiriusPlugin.getDefault().getModelAccessorRegistry().getModelAccessor(createTool).createInstance(map); + result = anInstance; + } catch (final MetaClassNotFoundException e) { + /* + * silent catch, it's just a bit more magic, if we're able to + * retrieve the right type then we'll do. + */ + } + + } + return result; + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.jface.action.Action#run() + */ + @Override + public void run() { + super.run(); + getEditingDomain().getCommandStack().execute(new CreateLineCommandFromToolRecordingCommand(getEditingDomain(), getText(), getTreeItem(), tree, treeCommandFactory, getCreationTool())); + } + + private TreeItemCreationTool getCreationTool() { + TreeItemCreationTool tool = null; + final TreeItemTool tableTool = getTool(); + if (tableTool instanceof TreeItemCreationTool) { + tool = (TreeItemCreationTool) tableTool; + } + return tool; + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.sirius.table.ui.tools.internal.editor.action.AbstractToolAction#canExecute() + */ + @Override + public boolean canExecute() { + boolean canExecute = true; + if (getCreationTool() != null) { + if (getCreationTool().getFirstModelOperation() == null) { + canExecute = false; + } else { + if (getCreationTool().getPrecondition() != null && !StringUtil.isEmpty(getCreationTool().getPrecondition().trim())) { + IInterpreter interpreter = null; + try { + if (getTreeItem() != null) { + interpreter = InterpreterUtil.getInterpreter(getTreeItem().getTarget()); + interpreter.setVariable(IInterpreterSiriusVariables.ROOT, TreeHelper.getTree(getTreeItem()).getTarget()); + interpreter.setVariable(IInterpreterSiriusVariables.ELEMENT, getTreeItem().getTarget()); + interpreter.setVariable(IInterpreterSiriusVariables.CONTAINER, ((DTreeItemContainer) getTreeItem().eContainer()).getTarget()); + canExecute = interpreter.evaluateBoolean(getTreeItem().getTarget(), getCreationTool().getPrecondition()); + } else { + interpreter = InterpreterUtil.getInterpreter(getTable().getTarget()); + interpreter.setVariable(IInterpreterSiriusVariables.ROOT, getTable().getTarget()); + interpreter.setVariable(IInterpreterSiriusVariables.ELEMENT, getTable().getTarget()); + interpreter.setVariable(IInterpreterSiriusVariables.CONTAINER, null); + canExecute = interpreter.evaluateBoolean(getTable().getTarget(), getCreationTool().getPrecondition()); + } + } catch (final EvaluationException e) { + RuntimeLoggerManager.INSTANCE.error(getCreationTool(), ToolPackage.eINSTANCE.getAbstractToolDescription_Precondition(), e); + } + interpreter.unSetVariable(IInterpreterSiriusVariables.ROOT); + interpreter.unSetVariable(IInterpreterSiriusVariables.ELEMENT); + interpreter.unSetVariable(IInterpreterSiriusVariables.CONTAINER); + } + } + } + return canExecute; + } + + /** + * Return the table. + * + * @return the table + */ + public DTree getTable() { + return tree; + } + + /** + * Set the table on which the tool of this action applied. + * + * @param table + * the table to set + */ + public void setTable(final DTree table) { + this.tree = table; + } +} diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/actions/DeleteTreeItemsAction.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/actions/DeleteTreeItemsAction.java new file mode 100644 index 0000000000..be36baf71f --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/actions/DeleteTreeItemsAction.java @@ -0,0 +1,158 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.tools.internal.editor.actions; + +import java.util.Collection; + +import org.eclipse.emf.common.command.CompoundCommand; +import org.eclipse.emf.transaction.RecordingCommand; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.jface.action.Action; + +import com.google.common.collect.Lists; + +import org.eclipse.sirius.business.api.query.IdentifiedElementQuery; +import org.eclipse.sirius.tree.DTreeItem; +import org.eclipse.sirius.tree.business.api.command.ITreeCommandFactory; +import org.eclipse.sirius.tree.business.internal.metamodel.query.DTreeItemInternalQuery; +import org.eclipse.sirius.tree.description.TreeItemDeletionTool; +import org.eclipse.sirius.tree.ui.tools.internal.editor.DTreeViewerManager; + +/** + * This action delete the line (the corresponding semantic element). + * + * @author nlepine + */ +public class DeleteTreeItemsAction extends Action { + private static final String DELETE_ITEM = "Delete tree item"; + + private static final String DELETE_ITEMS = DELETE_ITEM + "s"; + + private static final String TOOLTIP_ITEM = "Delete the target semantic element"; + + private static final String TOOLTIP_ITEMS = TOOLTIP_ITEM + "s"; + + private final ITreeCommandFactory treeCommandFactory; + + private final TransactionalEditingDomain editingDomain; + + private final Collection<DTreeItem> items = Lists.newArrayList(); + + /** + * Constructor. The deleteTool can be null if there is nothing specific to + * do (only the delete of the line). <BR> + * When a {@link DeleteTool} is specified the normal delete is not done. + * + * @param editingDomain + * The transactional editing domain + * @param treeCommandFactory + * The EMF command factory + * + */ + public DeleteTreeItemsAction(final TransactionalEditingDomain editingDomain, final ITreeCommandFactory treeCommandFactory) { + super(DELETE_ITEM, DTreeViewerManager.getImageRegistry().getDescriptor(DTreeViewerManager.DELETE_IMG)); + this.editingDomain = editingDomain; + this.treeCommandFactory = treeCommandFactory; + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.jface.action.Action#run() + */ + @Override + public void run() { + super.run(); + + CompoundCommand cc = new CompoundCommand(); + for (DTreeItem item : items) { + cc.append(new DeleteTreeElementRecordingCommand(getEditingDomain(), getText(), item)); + } + + getEditingDomain().getCommandStack().execute(cc); + + items.clear(); + } + + private TransactionalEditingDomain getEditingDomain() { + return editingDomain; + } + + private TreeItemDeletionTool getDeleteTool(DTreeItem treeItem) { + TreeItemDeletionTool tool = null; + if (treeItem != null && treeItem.getActualMapping() != null) { + tool = treeItem.getActualMapping().getDelete(); + } + return tool; + } + + /** + * Set the tree items to delete. + * + * @param itemsToDelete + * the items to delete. + */ + public void setItems(Collection<DTreeItem> itemsToDelete) { + items.clear(); + if (itemsToDelete != null) { + items.addAll(itemsToDelete); + } + + if (items.size() == 1) { + setText(DELETE_ITEM); + setToolTipText(TOOLTIP_ITEM); + + TreeItemDeletionTool deleteTool = getDeleteTool(items.iterator().next()); + if (deleteTool != null) { + setText(new IdentifiedElementQuery(deleteTool).getLabel()); + setToolTipText(deleteTool.getDocumentation()); + } + } else if (items.size() > 1) { + setText(DELETE_ITEMS); + setToolTipText(TOOLTIP_ITEMS); + } + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.sirius.tree.ui.tools.internal.editor.action.AbstractToolAction#canExecute() + */ + public boolean canExecute() { + boolean canExecute = !items.isEmpty(); + + for (DTreeItem itemToDelete : items) { + canExecute = canExecute && new DTreeItemInternalQuery(itemToDelete).canBeDeleted(); + + if (!canExecute) { + break; + } + } + + return canExecute; + } + + private class DeleteTreeElementRecordingCommand extends RecordingCommand { + + private final DTreeItem item; + + public DeleteTreeElementRecordingCommand(TransactionalEditingDomain domain, String label, DTreeItem item) { + super(domain, label); + this.item = item; + } + + @Override + protected void doExecute() { + treeCommandFactory.buildDeleteTreeElement(item).execute(); + } + + } +} diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/actions/EditorCreateTreeItemMenuAction.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/actions/EditorCreateTreeItemMenuAction.java new file mode 100644 index 0000000000..9117a825de --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/actions/EditorCreateTreeItemMenuAction.java @@ -0,0 +1,189 @@ +/******************************************************************************* + * Copyright (c) 2010 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.tools.internal.editor.actions; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.ActionContributionItem; +import org.eclipse.jface.action.IMenuCreator; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.MenuItem; + +import org.eclipse.sirius.tree.ui.tools.internal.editor.DTreeViewerManager; + +/** + * This implementation is used to create the structure viewer's + * "Create Tree Item" action. + * + * @author <a href="mailto:nathalie.lepine@obeo.fr">Nathalie Lepine</a> + */ +public class EditorCreateTreeItemMenuAction extends Action implements IMenuCreator { + /** The Id of this action. */ + public static final String ID = "CreateTreeItemMenu"; + + /** Menu manager for this action. */ + private final MenuManager menuManager = new MenuManager(); + + /** The last action launch from this menu. */ + private Action lastCreateTreeItemAction; + + /** List of the current available actions for this menu. */ + private final List<CreateToolItemAction> createTreeItemActionsForTree = new ArrayList<CreateToolItemAction>(); + + // menu item selection listener: listens to selection events + private final Listener menuItemListener = new Listener() { + public void handleEvent(final Event event) { + if (SWT.Selection == event.type && !event.widget.isDisposed()) { + final ActionContributionItem item = (ActionContributionItem) event.widget.getData(); + setLastAction((CreateToolItemAction) item.getAction()); + } + } + }; + + /** + * This default constructor will instantiate an action given the + * {@link #BUNDLE bundle} resources prefixed by "action.save". + */ + public EditorCreateTreeItemMenuAction() { + super("Create root tree items", DTreeViewerManager.getImageRegistry().getDescriptor(DTreeViewerManager.CREATE_TREE_ITEM_IMG)); + setId(ID); + setMenuCreator(this); + setEnabled(false); + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.jface.action.Action#run() + */ + @Override + public void run() { + if (lastCreateTreeItemAction != null && lastCreateTreeItemAction.isEnabled()) { + lastCreateTreeItemAction.run(); + } + } + + /** + * This will add the given action to this action's menu. + * + * @param action + * {@link Action} to add to this action's menu. + */ + public void addActionToMenu(final Action action) { + final ActionContributionItem contribution = new ActionContributionItem(action); + menuManager.add(contribution); + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.jface.action.IMenuCreator#dispose() + */ + public void dispose() { + if (menuManager.getMenu() != null) { + final MenuItem[] menuItems = menuManager.getMenu().getItems(); + for (MenuItem menuItem : menuItems) { + if (menuItem.getStyle() == SWT.SEPARATOR) { + continue; + } + menuItem.removeListener(SWT.Selection, menuItemListener); + } + menuManager.getMenu().dispose(); + } + menuManager.dispose(); + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.jface.action.IMenuCreator#getMenu(org.eclipse.swt.widgets.Control) + */ + public Menu getMenu(final Control parent) { + // Creates the menu if needed, or removes all elements except for the + // save action + if (menuManager.getMenu() == null) { + menuManager.createContextMenu(parent); + update(); + } + + final MenuItem[] menuItems = menuManager.getMenu().getItems(); + for (MenuItem menuItem : menuItems) { + if (menuItem.getStyle() == SWT.SEPARATOR) { + continue; + } + menuItem.addListener(SWT.Selection, menuItemListener); + } + + return menuManager.getMenu(); + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.jface.action.IMenuCreator#getMenu(org.eclipse.swt.widgets.Menu) + */ + public Menu getMenu(final Menu parent) { + return null; + } + + /** + * The change is applied on the next getMenu. + * + * @param createActionsForTable + * List of <{@link AbstractToolAction} + */ + public void update(final List<AbstractToolAction> createActionsForTable) { + getCreateTreeItemActionsForTree().clear(); + menuManager.removeAll(); + // Add all create line tool + for (final AbstractToolAction toolAction : createActionsForTable) { + if (toolAction instanceof CreateToolItemAction) { + getCreateTreeItemActionsForTree().add((CreateToolItemAction) toolAction); + } + } + update(); + } + + /** + * The change is applied on the next getMenu. + */ + protected void update() { + setEnabled(!getCreateTreeItemActionsForTree().isEmpty()); + + menuManager.removeAll(); + // Add all create line tool on the table + for (final CreateToolItemAction createLineAction : getCreateTreeItemActionsForTree()) { + if (createLineAction.canExecute()) { + menuManager.add(createLineAction); + } + } + } + + public void setLastAction(final CreateToolItemAction createLineAction) { + lastCreateTreeItemAction = createLineAction; + } + + /** + * Return the available createTreeItem actions. + * + * @return the createTreeItemActionsForTable + */ + protected List<CreateToolItemAction> getCreateTreeItemActionsForTree() { + return createTreeItemActionsForTree; + } +} diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/actions/EditorRefreshAction.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/actions/EditorRefreshAction.java new file mode 100644 index 0000000000..000678f4f0 --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/actions/EditorRefreshAction.java @@ -0,0 +1,100 @@ +/******************************************************************************* + * Copyright (c) 2010 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.tools.internal.editor.actions; + +import java.lang.reflect.InvocationTargetException; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.dialogs.ProgressMonitorDialog; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IEditorActionDelegate; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IWorkbenchPart; + +import org.eclipse.sirius.SiriusPlugin; +import org.eclipse.sirius.business.api.dialect.command.RefreshRepresentationsCommand; +import org.eclipse.sirius.tree.ui.tools.internal.editor.DTreeEditor; +import org.eclipse.sirius.ui.business.api.action.RefreshActionListenerRegistry; + +/** + * This action refresh the content of the tree. + * + * @author nlepine + */ +public class EditorRefreshAction implements IEditorActionDelegate { + /** + * This records the editor or view with which the action is currently + * associated. + */ + protected IWorkbenchPart workbenchPart; + + /** + * {@inheritDoc} + * + * @see org.eclipse.ui.IEditorActionDelegate#setActiveEditor(org.eclipse.jface.action.IAction, + * org.eclipse.ui.IEditorPart) + */ + public void setActiveEditor(final IAction action, final IEditorPart targetEditor) { + setActiveWorkbenchPart(targetEditor); + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction) + */ + public void run(final IAction action) { + if (workbenchPart instanceof DTreeEditor) { + final IRunnableWithProgress op = new IRunnableWithProgress() { + public void run(final IProgressMonitor monitor) { + final DTreeEditor treeEditor = (DTreeEditor) workbenchPart; + treeEditor.enablePropertiesUpdate(false); + RefreshActionListenerRegistry.INSTANCE.notifyRepresentationIsAboutToBeRefreshed(treeEditor.getTreeModel()); + treeEditor.getEditingDomain().getCommandStack().execute(new RefreshRepresentationsCommand(treeEditor.getEditingDomain(), monitor, treeEditor.getTreeModel())); + treeEditor.enablePropertiesUpdate(true); + } + }; + final Shell activeShell = workbenchPart.getSite().getShell(); + final ProgressMonitorDialog monitorDialog = new ProgressMonitorDialog(activeShell); + try { + monitorDialog.run(false, false, op); + } catch (final InvocationTargetException e) { + MessageDialog.openError(activeShell, "Error", e.getTargetException().getMessage()); + SiriusPlugin.getDefault().error("Error while refreshing tree", e); + } catch (final InterruptedException e) { + MessageDialog.openInformation(activeShell, "Cancelled", e.getMessage()); + } + } + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.ui.IActionDelegate#selectionChanged(org.eclipse.jface.action.IAction, + * org.eclipse.jface.viewers.ISelection) + */ + public void selectionChanged(final IAction action, final ISelection selection) { + } + + /** + * Set the workbench part. + * + * @param aWorkbenchPart + * the new workbench part + */ + public void setActiveWorkbenchPart(final IWorkbenchPart aWorkbenchPart) { + this.workbenchPart = aWorkbenchPart; + } +} diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/actions/OpenRepresentationAction.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/actions/OpenRepresentationAction.java new file mode 100644 index 0000000000..77404b6636 --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/actions/OpenRepresentationAction.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2013 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.tools.internal.editor.actions; + +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.emf.transaction.RecordingCommand; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.jface.action.Action; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.ui.IEditorPart; + +import org.eclipse.sirius.DRepresentation; +import org.eclipse.sirius.business.api.dialect.DialectManager; +import org.eclipse.sirius.business.api.session.Session; +import org.eclipse.sirius.ui.business.api.dialect.DialectEditor; +import org.eclipse.sirius.ui.business.api.dialect.DialectUIManager; +import org.eclipse.sirius.ui.business.api.session.IEditingSession; +import org.eclipse.sirius.ui.business.api.session.SessionUIManager; + +public final class OpenRepresentationAction extends Action { + + private final DRepresentation representation; + + private final Session session; + + private TransactionalEditingDomain editingDomain; + + /** + * Constructor. + * + * @param text + * the action's text, or <code>null</code> if there is no text + * @param image + * the action's image, or <code>null</code> if there is no image + * @param representation + * the representation to open. + * @param session + * the session in which to open it. + */ + public OpenRepresentationAction(String text, ImageDescriptor image, DRepresentation representation, Session session) { + super(text, image); + this.representation = representation; + this.session = session; + this.editingDomain = session.getTransactionalEditingDomain(); + } + + /** + * Constructor. + * + * @param representation + * the representation to open. + * @param session + * the session in which to open it. + */ + public OpenRepresentationAction(DRepresentation representation, Session session) { + super(); + this.representation = representation; + this.session = session; + this.editingDomain = session.getTransactionalEditingDomain(); + } + + /** + * {@inheritDoc} + */ + @Override + public void run() { + super.run(); + editingDomain.getCommandStack().execute(new AttachEditorRecordingCommand(editingDomain)); + } + + private class AttachEditorRecordingCommand extends RecordingCommand { + + public AttachEditorRecordingCommand(TransactionalEditingDomain domain) { + super(domain); + } + + @Override + protected void doExecute() { + final IEditingSession ui = SessionUIManager.INSTANCE.getUISession(session); + DialectManager.INSTANCE.refresh(representation, new NullProgressMonitor()); + final IEditorPart part = DialectUIManager.INSTANCE.openEditor(session, representation); + if (part != null && ui != null) { + ui.attachEditor((DialectEditor) part); + } + } + + } +} diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/actions/RefreshAction.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/actions/RefreshAction.java new file mode 100644 index 0000000000..43bd7fc6c0 --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/actions/RefreshAction.java @@ -0,0 +1,140 @@ +/******************************************************************************* + * Copyright (c) 2010 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.tools.internal.editor.actions; + +import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; +import java.util.LinkedList; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.dialogs.ProgressMonitorDialog; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IObjectActionDelegate; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.PlatformUI; + +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; + +import org.eclipse.sirius.SiriusPlugin; +import org.eclipse.sirius.business.api.dialect.command.RefreshRepresentationsCommand; +import org.eclipse.sirius.tools.api.command.SiriusCommand; +import org.eclipse.sirius.tree.DTreeElement; +import org.eclipse.sirius.tree.business.internal.helper.RefreshTreeElementTask; +import org.eclipse.sirius.tree.ui.tools.internal.editor.DTreeEditor; +import org.eclipse.sirius.tree.ui.tools.internal.editor.DTreeViewerManager; +import org.eclipse.sirius.ui.business.api.action.RefreshActionListenerRegistry; + +/** + * This action refresh the entire tree or the tree items elements selected. + * + * @author nlepine + */ +public class RefreshAction extends Action implements IObjectActionDelegate { + private static final String DEFAULT_NAME = "Refresh Tree Element"; + + DTreeEditor treeEditor; + + private ISelection selection; + + private LinkedList<Object> minimizedSelection; + + /** + * Default constructor. + * + * @param treeEditor + * the tree editor + */ + public RefreshAction(final DTreeEditor treeEditor) { + super(DEFAULT_NAME, DTreeViewerManager.getImageRegistry().getDescriptor(DTreeViewerManager.REFRESH_IMG)); + this.treeEditor = treeEditor; + minimizedSelection = new LinkedList<Object>(); + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.jface.action.Action#run() + */ + @Override + public void run() { + this.selection = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getSelection(); + if (this.selection instanceof IStructuredSelection) { + final IStructuredSelection structuredSelection = (IStructuredSelection) this.selection; + minimizedSelection = new LinkedList<Object>(Arrays.asList(structuredSelection.toArray())); + + } + final IRunnableWithProgress op = new IRunnableWithProgress() { + public void run(final IProgressMonitor monitor) { + final SiriusCommand result = new SiriusCommand(treeEditor.getEditingDomain()); + Iterable<DTreeElement> elements = Iterables.filter(minimizedSelection, DTreeElement.class); + result.getTasks().add(new RefreshTreeElementTask(Lists.newArrayList(elements), treeEditor.getEditingDomain(), monitor)); + treeEditor.getEditingDomain().getCommandStack().execute(result); + } + }; + run(op); + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.ui.IObjectActionDelegate#setActivePart(org.eclipse.jface.action.IAction, + * org.eclipse.ui.IWorkbenchPart) + */ + public void setActivePart(IAction action, IWorkbenchPart targetPart) { + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction) + */ + public void run(IAction action) { + IRunnableWithProgress op = new IRunnableWithProgress() { + public void run(final IProgressMonitor monitor) { + TransactionalEditingDomain domain = treeEditor.getEditingDomain(); + domain.getCommandStack().execute(new RefreshRepresentationsCommand(domain, monitor, treeEditor.getTreeModel())); + } + }; + RefreshActionListenerRegistry.INSTANCE.notifyRepresentationIsAboutToBeRefreshed(treeEditor.getTreeModel()); + run(op); + } + + private void run(final IRunnableWithProgress op) { + final Shell activeShell = treeEditor.getSite().getShell(); + final ProgressMonitorDialog monitorDialog = new ProgressMonitorDialog(activeShell); + try { + treeEditor.enablePropertiesUpdate(false); + monitorDialog.run(true, false, op); + } catch (final InvocationTargetException e) { + MessageDialog.openError(activeShell, "Error", e.getTargetException().getMessage()); + SiriusPlugin.getDefault().error("Error while refreshing tree", e); + } catch (final InterruptedException e) { + MessageDialog.openInformation(activeShell, "Cancelled", e.getMessage()); + } finally { + treeEditor.enablePropertiesUpdate(true); + } + } + + /** + * {@inheritDoc} + */ + public void selectionChanged(IAction action, ISelection sel) { + this.selection = sel; + } +} diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/listeners/DTreeItemExpansionChecker.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/listeners/DTreeItemExpansionChecker.java new file mode 100644 index 0000000000..cbea6d8362 --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/listeners/DTreeItemExpansionChecker.java @@ -0,0 +1,142 @@ +/******************************************************************************* + * Copyright (c) 2011 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.tools.internal.editor.listeners; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.TreeItem; + +import org.eclipse.sirius.tree.DTreeItem; +import org.eclipse.sirius.tree.TreePackage; +import org.eclipse.sirius.ecore.extender.business.api.permission.IPermissionAuthority; + +/** + * {@link Listener} to prevents expansion/collapse {@link Event} while + * {@link IPermissionAuthority} disallow + * {@link TreePackage#DTREE_ITEM__EXPANDED} change. + * + * @author <a href="mailto:esteban.dugueperoux@obeo.fr">Esteban Dugueperoux</a> + */ +public class DTreeItemExpansionChecker implements Listener { + + private IPermissionAuthority permissionAuthority; + + private Control control; + + /** + * Default constructor. + * + * @param control + * the {@link Control} to listen + */ + public DTreeItemExpansionChecker(Control control) { + this.control = control; + control.getDisplay().addFilter(SWT.Expand, this); + control.getDisplay().addFilter(SWT.Collapse, this); + } + + public void setPermissionAuthority(IPermissionAuthority permissionAuthority) { + this.permissionAuthority = permissionAuthority; + } + + /** + * Overridden to handle {@link SWT#Collapse} and {@link SWT#Expand} events. + * + * {@inheritDoc} + */ + public void handleEvent(Event event) { + switch (event.type) { + case SWT.Collapse: + handleTreeCollapse(event); + break; + case SWT.Expand: + handleTreeExpand(event); + break; + default: + break; + } + + } + + /** + * Handle the undo of the swt TreeItem collapse if the current + * {@link IPermissionAuthority} disallow it. + */ + private void handleTreeCollapse(Event event) { + if (!isEventForDTreeItemExpandable(event)) { + event.type = SWT.None; + final TreeItem treeItem = (TreeItem) event.item; + Display.getDefault().asyncExec(new Runnable() { + + public void run() { + treeItem.setExpanded(true); + } + + }); + + } + } + + /** + * Handle the undo the swt TreeItem expansion if the current + * {@link IPermissionAuthority} disallow it. + */ + private void handleTreeExpand(Event event) { + if (!isEventForDTreeItemExpandable(event)) { + event.type = SWT.None; + final TreeItem treeItem = (TreeItem) event.item; + Display.getDefault().asyncExec(new Runnable() { + + public void run() { + treeItem.setExpanded(false); + } + + }); + } + } + + /** + * Tells if the specified {@link Event} is a event of a {@link TreeItem} + * collapse/expansion which should be allowed by the current + * {@link IPermissionAuthority}. + * + * @param event + * the specified {@link Event} + * @return true if the specified {@link Event} is allowed by the current + * {@link IPermissionAuthority}, false else + */ + private boolean isEventForDTreeItemExpandable(Event event) { + boolean isEventForDTreeItemExpandable = true; + if (event.item instanceof TreeItem) { + TreeItem treeItem = (TreeItem) event.item; + Object data = treeItem.getData(); + if (data instanceof DTreeItem) { + DTreeItem dTreeItem = (DTreeItem) data; + boolean canEditFeature = permissionAuthority != null && permissionAuthority.canEditFeature(dTreeItem, TreePackage.Literals.DTREE_ITEM__EXPANDED.getName()); + isEventForDTreeItemExpandable = canEditFeature; + } + } + return isEventForDTreeItemExpandable; + } + + /** + * remove THis {@link DTreeItemExpansionChecker} as {@link Listener} of the + * Tree. + */ + public void dispose() { + control.getDisplay().removeFilter(SWT.Expand, this); + control.getDisplay().removeFilter(SWT.Collapse, this); + } + +} diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/listeners/DTreeViewerListener.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/listeners/DTreeViewerListener.java new file mode 100644 index 0000000000..8e7cf8a1fb --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/listeners/DTreeViewerListener.java @@ -0,0 +1,115 @@ +/******************************************************************************* + * Copyright (c) 2011 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.tools.internal.editor.listeners; + +import org.eclipse.emf.common.command.CommandStack; +import org.eclipse.emf.common.command.CompoundCommand; +import org.eclipse.emf.transaction.RecordingCommand; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.jface.viewers.ITreeViewerListener; +import org.eclipse.jface.viewers.TreeExpansionEvent; + +import org.eclipse.sirius.business.api.session.Session; +import org.eclipse.sirius.tools.api.command.SiriusCommand; +import org.eclipse.sirius.tree.DTreeItem; +import org.eclipse.sirius.tree.business.api.interaction.DTreeItemUserInteraction; +import org.eclipse.sirius.tree.business.internal.dialect.common.viewpoint.GlobalContext; +import org.eclipse.sirius.tree.business.internal.helper.RefreshTreeElementTask; + +/** + * A {@link ITreeViewerListener} to update the DTree model when a SWT TreeItem + * is collapsed/expanded. + * + * @author <a href="mailto:esteban.dugueperoux@obeo.fr">Esteban Dugueperoux</a> + */ +public class DTreeViewerListener implements ITreeViewerListener { + + private Session session; + + private TransactionalEditingDomain domain; + + /** + * Default constructor. + * + * @param session + * {@link Session} + */ + public DTreeViewerListener(Session session) { + this.session = session; + this.domain = session.getTransactionalEditingDomain(); + } + + /** + * {@inheritDoc} + */ + public void treeExpanded(final TreeExpansionEvent event) { + if (event.getElement() instanceof DTreeItem) { + DTreeItem dTreeItem = (DTreeItem) event.getElement(); + if (!dTreeItem.isExpanded()) { + CommandStack commandStack = domain.getCommandStack(); + CompoundCommand expandDTreeItemCmd = new CompoundCommand("Expand " + dTreeItem.getName() + " tree item"); + expandDTreeItemCmd.append(new TreeFoldingRecordingCommand(session, event, true)); + final SiriusCommand result = new SiriusCommand(domain); + result.getTasks().add(new RefreshTreeElementTask((DTreeItem) event.getElement(), domain)); + expandDTreeItemCmd.append(result); + commandStack.execute(expandDTreeItemCmd); + } + } + } + + /** + * {@inheritDoc} + */ + public void treeCollapsed(final TreeExpansionEvent event) { + if (event.getElement() instanceof DTreeItem) { + DTreeItem dTreeItem = (DTreeItem) event.getElement(); + if (dTreeItem.isExpanded()) { + CommandStack commandStack = domain.getCommandStack(); + CompoundCommand expandDTreeItemCmd = new CompoundCommand("Collapse " + dTreeItem.getName() + " tree item"); + expandDTreeItemCmd.append(new TreeFoldingRecordingCommand(session, event, false)); + commandStack.execute(expandDTreeItemCmd); + } + } + } + + /** + * EMF Command to synchronize the DTree according to a + * {@link TreeExpansionEvent}. + * + * @author <a href="mailto:esteban.dugueperoux@obeo.fr">Esteban + * Dugueperoux</a> + */ + class TreeFoldingRecordingCommand extends RecordingCommand { + + private Session session; + + private TreeExpansionEvent event; + + private boolean expand; + + public TreeFoldingRecordingCommand(Session session, TreeExpansionEvent event, boolean expand) { + super(session.getTransactionalEditingDomain()); + this.session = session; + this.event = event; + this.expand = expand; + } + + @Override + protected void doExecute() { + GlobalContext ctx = new GlobalContext(session.getModelAccessor(), session); + if (expand) { + new DTreeItemUserInteraction((DTreeItem) event.getElement(), ctx).expand(); + } else { + new DTreeItemUserInteraction((DTreeItem) event.getElement(), ctx).collapse(); + } + } + } +} diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/preferences/SiriusPreferenceChangeListener.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/preferences/SiriusPreferenceChangeListener.java new file mode 100644 index 0000000000..e26183771d --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/preferences/SiriusPreferenceChangeListener.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2012 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.tools.internal.editor.preferences; + +import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener; +import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent; + +import org.eclipse.sirius.business.api.preferences.DesignerPreferencesKeys; +import org.eclipse.sirius.tree.business.api.command.ITreeCommandFactory; + +/** + * Listener of the + * {@link org.eclipse.sirius.table.ui.tools.internal.editor.AbstractDTableEditor} + * preferences. + * + * @author mporhel + * + */ +public class SiriusPreferenceChangeListener implements IPreferenceChangeListener { + + ITreeCommandFactory factory; + + /** + * Build a new listener. + * + * @param factory + * editor's command factory. + */ + public SiriusPreferenceChangeListener(final ITreeCommandFactory factory) { + this.factory = factory; + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.core.runtime.Preferences.IPreferenceChangeListener#propertyChange(org.eclipse.core.runtime.Preferences.PreferenceChangeEvent) + */ + public void preferenceChange(PreferenceChangeEvent event) { + if (DesignerPreferencesKeys.PREF_AUTO_REFRESH.name().equals(event.getKey()) && event.getNewValue() instanceof String && !event.getNewValue().equals(event.getOldValue())) { + factory.setAutoRefreshDTree(Boolean.parseBoolean((String) event.getNewValue())); + } + } +} diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/provider/DTreeColumnLabelProvider.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/provider/DTreeColumnLabelProvider.java new file mode 100644 index 0000000000..37670a2901 --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/provider/DTreeColumnLabelProvider.java @@ -0,0 +1,176 @@ +/******************************************************************************* + * Copyright (c) 2010 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.tools.internal.editor.provider; + +import java.io.File; +import java.net.MalformedURLException; + +import org.eclipse.core.runtime.Path; +import org.eclipse.emf.common.notify.AdapterFactory; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.Image; + +import org.eclipse.sirius.common.tools.api.resource.FileProvider; +import org.eclipse.sirius.common.tools.api.util.StringUtil; +import org.eclipse.sirius.BasicLabelStyle; +import org.eclipse.sirius.FontFormat; +import org.eclipse.sirius.RGBValues; +import org.eclipse.sirius.SiriusPlugin; +import org.eclipse.sirius.tree.DTreeItem; +import org.eclipse.sirius.tree.ui.provider.TreeUIPlugin; +import org.eclipse.sirius.ui.tools.api.color.VisualBindingManager; +import org.eclipse.sirius.ui.tools.api.provider.DSemanticTargetBasedLabelProvider; + +/** + * Label provider for all the tree item. + * + * @author <a href="mailto:nathalie.lepine@obeo.fr">Nathalie Lepine</a> + */ +public class DTreeColumnLabelProvider extends DSemanticTargetBasedLabelProvider { + + /** + * Default constructor. + * + * @param adapterFactoryLabelProvider + * Provider which to delegate label and image resolution. + */ + public DTreeColumnLabelProvider(final AdapterFactory adapterFactoryLabelProvider) { + super(adapterFactoryLabelProvider); + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.jface.viewers.ColumnLabelProvider#getBackground(java.lang.Object) + */ + @Override + public Color getBackground(final Object element) { + Color result = null; + if (element instanceof DTreeItem) { + final DTreeItem item = (DTreeItem) element; + if (item.getOwnedStyle() != null) { + final RGBValues rgb = item.getOwnedStyle().getBackgroundColor(); + if (rgb != null) { + result = VisualBindingManager.getDefault().getColorFromRGBValues(rgb); + } + } + } + return result; + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.jface.viewers.ColumnLabelProvider#getFont(java.lang.Object) + */ + @Override + public Font getFont(final Object element) { + if (element instanceof DTreeItem) { + final DTreeItem item = (DTreeItem) element; + if (item.getOwnedStyle() != null) { + final int size = item.getOwnedStyle().getLabelSize(); + FontFormat labelFormat = null; + if (item.getOwnedStyle().getLabelFormat() != null) { + labelFormat = item.getOwnedStyle().getLabelFormat(); + } else { + labelFormat = FontFormat.NORMAL_LITERAL; + } + return VisualBindingManager.getDefault().getFontFromLabelFormatAndSize(labelFormat, size); + } + } + return null; + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.jface.viewers.ColumnLabelProvider#getForeground(java.lang.Object) + */ + @Override + public Color getForeground(final Object element) { + if (element instanceof DTreeItem) { + final DTreeItem item = (DTreeItem) element; + if (item.getOwnedStyle() != null && item.getOwnedStyle().getLabelColor() != null) { + final RGBValues rgb = item.getOwnedStyle().getLabelColor(); + if (rgb != null) { + return VisualBindingManager.getDefault().getLabelColorFromRGBValues(rgb); + } + } + } + return null; + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.jface.viewers.ColumnLabelProvider#getImage(java.lang.Object) + */ + @Override + public Image getImage(final Object element) { + if (element instanceof DTreeItem) { + final DTreeItem item = (DTreeItem) element; + if (item.getOwnedStyle() != null && item.getOwnedStyle().isShowIcon()) { + Image labelImage = null; + + if (StringUtil.isEmpty(item.getOwnedStyle().getIconPath())) { + labelImage = super.getImage(element); + } else { + labelImage = getCustomImage(item.getOwnedStyle()); + } + return labelImage; + } + } + return null; + } + + private Image getCustomImage(BasicLabelStyle bls) { + Image customImage = null; + if (bls != null && !StringUtil.isEmpty(bls.getIconPath())) { + ImageDescriptor descriptor = null; + String iconPath = bls.getIconPath(); + final File imageFile = FileProvider.getDefault().getFile(new Path(iconPath)); + if (imageFile != null && imageFile.exists() && imageFile.canRead()) { + try { + descriptor = ImageDescriptor.createFromURL(imageFile.toURI().toURL()); + } catch (MalformedURLException e) { + // log a waring later. + } + } + + if (descriptor == null) { + SiriusPlugin.getDefault().warning("Icon file \"" + iconPath + "\" not found", null); + descriptor = ImageDescriptor.getMissingImageDescriptor(); + } + + customImage = TreeUIPlugin.getImage(descriptor); + } + return customImage; + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.jface.viewers.ColumnLabelProvider#getText(java.lang.Object) + */ + @Override + public String getText(final Object element) { + String result = StringUtil.EMPTY_STRING; + if (element instanceof DTreeItem) { + final DTreeItem item = (DTreeItem) element; + if (item != null) { + result = item.getName(); + } + } + return result; + } +} diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/provider/DTreeContentAdapter.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/provider/DTreeContentAdapter.java new file mode 100644 index 0000000000..c4e6585b7c --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/provider/DTreeContentAdapter.java @@ -0,0 +1,290 @@ +/******************************************************************************* + * Copyright (c) 2010, 2012 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.tools.internal.editor.provider; + +import org.eclipse.emf.common.notify.Notification; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.transaction.ResourceSetChangeEvent; +import org.eclipse.emf.transaction.ResourceSetListenerImpl; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.emf.transaction.util.TransactionUtil; +import org.eclipse.ui.PlatformUI; + +import com.google.common.collect.Iterables; + +import org.eclipse.sirius.common.tools.DslCommonPlugin; +import org.eclipse.sirius.RGBValues; +import org.eclipse.sirius.SiriusPackage; +import org.eclipse.sirius.business.api.helper.SiriusUtil; +import org.eclipse.sirius.tools.api.profiler.SiriusTasksKey; +import org.eclipse.sirius.tree.DTree; +import org.eclipse.sirius.tree.DTreeItem; +import org.eclipse.sirius.tree.TreeItemStyle; +import org.eclipse.sirius.tree.TreePackage; +import org.eclipse.sirius.tree.ui.tools.internal.editor.DTreeViewer; +import org.eclipse.sirius.tree.ui.tools.internal.editor.DTreeViewerManager; + +/** + * This class is an EMF Adapter which listen change in the model to update a + * {@link org.eclipse.sirius.tree.ui.tools.internal.editor.DTreeViewer}. + * + * @author nlepine + * + */ +public class DTreeContentAdapter extends ResourceSetListenerImpl { + + private DTreeViewerManager dTreeViewerManager; + + /** The structured viewer to update. */ + private DTreeViewer dTreeViewer; + + /** + * Creates a new tree content adapter with the given session. + * + * @param dTreeViewerManager + * the structured viewer to update + */ + public DTreeContentAdapter(DTreeViewerManager dTreeViewerManager) { + this.dTreeViewerManager = dTreeViewerManager; + this.dTreeViewer = (DTreeViewer) dTreeViewerManager.getTreeViewer(); + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.emf.transaction.ResourceSetListenerImpl#isPostcommitOnly() + */ + @Override + public boolean isPostcommitOnly() { + return true; + } + + private boolean isCustom(Notification notif) { + return notif.getEventType() == -1; + } + + private void notifyChanged(final Notification notification) { + if (dTreeViewer == null || dTreeViewer.getControl() == null || dTreeViewer.getControl().isDisposed()) { + if (notification.getNotifier() instanceof EObject) { + final TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(notification.getNotifier()); + if (domain != null) { + domain.removeResourceSetListener(this); + } + } + return; + } + + final Object notifier = notification.getNotifier(); + + if (notifier instanceof Resource) { + final Resource resource = (Resource) notifier; + + // Indicates that at least one description file has changed or was + // reloaded + if (SiriusUtil.DESCRIPTION_MODEL_EXTENSION.equals(resource.getURI().fileExtension())) { + if (notification.getFeatureID(Resource.class) == Resource.RESOURCE__IS_MODIFIED || notification.getFeatureID(Resource.class) == Resource.RESOURCE__IS_LOADED) { + dTreeViewerManager.setDescriptionFileChanged(true); + } + } + } + + if (isChangeAboutDTreeModel(notification)) { + if (notifier instanceof DTree) { + handleDTreeNotification(notification, (DTree) notifier); + } else if (notifier instanceof DTreeItem) { + handleDTreeItemNotification(notification, (DTreeItem) notifier); + } else if (notifier instanceof TreeItemStyle) { + handleDTreeItemNotification(notification, (TreeItemStyle) notifier); + } else if (notifier instanceof RGBValues) { + handleDTreItemNotification(notification, (RGBValues) notifier); + } + } + } + + /** + * Checks if the specified {@link Notification} is about a change a a + * {@link DTree}. + * + * @param notification + * the specified {@link Notification} + * @return true if the specified {@link Notification} is about a change a a + * {@link DTree}, false else + */ + private boolean isChangeAboutDTreeModel(final Notification notification) { + boolean isImpactingNotification = false; + Object notifier = notification.getNotifier(); + if (notifier instanceof EObject) { + EObject eObject = (EObject) notifier; + while (eObject != null && !isImpactingNotification) { + if (eObject instanceof DTree) { + isImpactingNotification = true; + } else { + eObject = eObject.eContainer(); + } + } + } + return isImpactingNotification; + } + + /** + * @param n + * @param notifier + */ + private void handleDTreeNotification(final Notification n, final DTree tree) { + final int featureID = n.getFeatureID(DTree.class); + + switch (featureID) { + case TreePackage.DTREE__OWNED_TREE_ITEMS: + case TreePackage.DTREE__TARGET: + DslCommonPlugin.PROFILER.startWork(SiriusTasksKey.REFRESH_SWT_TABLE_KEY); + refreshViewer(tree); + DslCommonPlugin.PROFILER.stopWork(SiriusTasksKey.REFRESH_SWT_TABLE_KEY); + break; + default: + break; + } + } + + /** + * @param n + * @param notifier + */ + private void handleDTreeItemNotification(final Notification n, final DTreeItem dTreeItem) { + final int featureID = n.getFeatureID(DTreeItem.class); + + switch (featureID) { + case TreePackage.DTREE_ITEM__NAME: + case TreePackage.DTREE_ITEM__OWNED_STYLE: + DslCommonPlugin.PROFILER.startWork(SiriusTasksKey.UPDATE_SWT_LINE_KEY); + updateViewer(dTreeItem); + DslCommonPlugin.PROFILER.stopWork(SiriusTasksKey.UPDATE_SWT_LINE_KEY); + break; + case TreePackage.DTREE_ITEM__OWNED_TREE_ITEMS: + DslCommonPlugin.PROFILER.startWork(SiriusTasksKey.REFRESH_SWT_LINE_KEY); + refreshViewer(dTreeItem); + // The refresh doesn't update swt TreeItem expansion then we must do + // it + PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() { + public void run() { + if (dTreeViewer != null && dTreeViewer.getControl() != null && !dTreeViewer.getControl().isDisposed()) { + dTreeViewer.setExpandedState(dTreeItem, dTreeItem.isExpanded()); + } + } + }); + DslCommonPlugin.PROFILER.stopWork(SiriusTasksKey.REFRESH_SWT_LINE_KEY); + break; + case TreePackage.DTREE_ITEM__EXPANDED: + if (n.getNewValue() instanceof Boolean) { + DslCommonPlugin.PROFILER.startWork(SiriusTasksKey.CHANGE_SWT_LINE_COLAPSE_STATE_KEY); + final boolean expanded = n.getNewBooleanValue(); + PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() { + public void run() { + if (dTreeViewer != null && dTreeViewer.getControl() != null && !dTreeViewer.getControl().isDisposed()) { + dTreeViewer.setExpandedState(dTreeItem, expanded); + } + } + }); + DslCommonPlugin.PROFILER.stopWork(SiriusTasksKey.CHANGE_SWT_LINE_COLAPSE_STATE_KEY); + } + break; + default: + break; + } + } + + /** + * @param n + * @param notifier + */ + private void handleDTreeItemNotification(final Notification n, final TreeItemStyle notifier) { + final int featureID = n.getFeatureID(TreeItemStyle.class); + + switch (featureID) { + case TreePackage.TREE_ITEM_STYLE__BACKGROUND_COLOR: + case TreePackage.TREE_ITEM_STYLE__LABEL_COLOR: + case TreePackage.TREE_ITEM_STYLE__LABEL_FORMAT: + case TreePackage.TREE_ITEM_STYLE__LABEL_SIZE: + case TreePackage.TREE_ITEM_STYLE__SHOW_ICON: + final DTreeItem treeItem = (DTreeItem) notifier.eContainer(); + if (treeItem != null) { + DslCommonPlugin.PROFILER.startWork(SiriusTasksKey.UPDATE_SWT_LINE_KEY); + updateViewer(treeItem); + DslCommonPlugin.PROFILER.stopWork(SiriusTasksKey.UPDATE_SWT_LINE_KEY); + } + break; + default: + break; + } + } + + private void handleDTreItemNotification(Notification notification, RGBValues notifier) { + final int featureID = notification.getFeatureID(TreeItemStyle.class); + + switch (featureID) { + case SiriusPackage.RGB_VALUES__BLUE: + case SiriusPackage.RGB_VALUES__GREEN: + case SiriusPackage.RGB_VALUES__RED: + EObject notifierContainer = notifier.eContainer(); + if (notifierContainer instanceof TreeItemStyle) { + TreeItemStyle treeItemStyle = (TreeItemStyle) notifierContainer; + EObject treeitemStyleContainer = treeItemStyle.eContainer(); + if (treeitemStyleContainer != null) { + DslCommonPlugin.PROFILER.startWork(SiriusTasksKey.UPDATE_SWT_LINE_KEY); + updateViewer(treeitemStyleContainer); + DslCommonPlugin.PROFILER.stopWork(SiriusTasksKey.UPDATE_SWT_LINE_KEY); + } + } + break; + default: + break; + } + } + + private void refreshViewer(final Object object) { + if (object != null) { + PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() { + public void run() { + if (dTreeViewer != null && dTreeViewer.getControl() != null && !dTreeViewer.getControl().isDisposed()) { + dTreeViewer.refresh(object, true); + } + } + }); + } + } + + private void updateViewer(final Object object) { + if (object != null) { + PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() { + public void run() { + if (dTreeViewer != null && dTreeViewer.getControl() != null && !dTreeViewer.getControl().isDisposed()) { + dTreeViewer.update(object, null); + } + } + }); + } + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.emf.transaction.ResourceSetListenerImpl#resourceSetChanged(org.eclipse.emf.transaction.ResourceSetChangeEvent) + */ + @Override + public void resourceSetChanged(ResourceSetChangeEvent event) { + super.resourceSetChanged(event); + for (Notification notif : Iterables.filter(event.getNotifications(), Notification.class)) { + if (!isCustom(notif)) { + notifyChanged(notif); + } + } + } +} diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/provider/DTreeContentProvider.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/provider/DTreeContentProvider.java new file mode 100644 index 0000000000..85c14beafc --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/provider/DTreeContentProvider.java @@ -0,0 +1,139 @@ +/******************************************************************************* + * Copyright (c) 2010 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.tools.internal.editor.provider; + +import java.util.List; + +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.Viewer; + +import org.eclipse.sirius.business.api.session.Session; +import org.eclipse.sirius.tree.DTree; +import org.eclipse.sirius.tree.DTreeItem; +import org.eclipse.sirius.tree.DTreeItemContainer; +import org.eclipse.sirius.tree.ui.tools.internal.editor.DTreeViewerManager; + +/** + * The provider for the content of the tree. + * + * @author nlepine + */ +public class DTreeContentProvider implements ITreeContentProvider { + + private Session session; + + /** The EMF adapter */ + private DTreeContentAdapter dTreeContentAdapter; + + /** + * Creates a tree with the given session. + * + * @param session + * the session. + * @param dTreeViewerManager + * the manager of the structured viewer to update + */ + public DTreeContentProvider(final Session session, DTreeViewerManager dTreeViewerManager) { + this.session = session; + this.dTreeContentAdapter = new DTreeContentAdapter(dTreeViewerManager); + this.session.getTransactionalEditingDomain().addResourceSetListener(dTreeContentAdapter); + } + + /** + * Returns the elements to display in the viewer (only the visible one). + * + * @param inputElement + * the input element + * @return the array of elements to display in the viewer + * + * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object) + */ + public Object[] getElements(final Object inputElement) { + if (inputElement instanceof DTree) { + final List<DTreeItem> visibleLines = getVisibleLines((DTree) inputElement); + return visibleLines.toArray(); + } + return null; + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.jface.viewers.IStructuredContentProvider#inputChanged(Viewer, + * Object, Object) + */ + public void inputChanged(final Viewer viewer, final Object oldInput, final Object newInput) { + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java.lang.Object) + */ + public Object[] getChildren(final Object parentElement) { + Object[] result = null; + if (parentElement instanceof DTree) { + final List<DTreeItem> visibleLines = getVisibleLines((DTree) parentElement); + result = visibleLines.toArray(); + } else if (parentElement instanceof DTreeItem) { + final List<DTreeItem> visibleLines = getVisibleLines((DTreeItem) parentElement); + result = visibleLines.toArray(); + } + return result; + } + + /** + * Returns the visible items of the given <@link DTreeItemContainer + * lineContainer>. + * <p> + * + * @param treeItemContainer + * the line container + * @return a list of visible lines + */ + private List<DTreeItem> getVisibleLines(final DTreeItemContainer treeItemContainer) { + return treeItemContainer.getOwnedTreeItems(); + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.jface.viewers.ITreeContentProvider#getParent(java.lang.Object) + */ + public Object getParent(final Object element) { + if (element instanceof DTreeItem) { + final DTreeItem line = (DTreeItem) element; + return line.eContainer(); + } + return null; + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java.lang.Object) + */ + public boolean hasChildren(final Object element) { + final Object[] children = getChildren(element); + return children != null && children.length > 0; + } + + /** + * Disposes of this content provider. + * + * @see org.eclipse.jface.viewers.IContentProvider#dispose() + */ + public void dispose() { + session.getTransactionalEditingDomain().removeResourceSetListener(dTreeContentAdapter); + dTreeContentAdapter = null; + } + +} diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/provider/DTreeDecoratingLabelProvider.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/provider/DTreeDecoratingLabelProvider.java new file mode 100644 index 0000000000..b259c4d684 --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/provider/DTreeDecoratingLabelProvider.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2011 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.tools.internal.editor.provider; + +import org.eclipse.emf.common.notify.AdapterFactory; +import org.eclipse.jface.viewers.ILabelDecorator; +import org.eclipse.swt.graphics.Image; + +/** + * Inherits {@link DTreeColumnLabelProvider} to decorate DTreeItem. + * + * @author edugueperoux + */ +public class DTreeDecoratingLabelProvider extends DTreeColumnLabelProvider { + + private ILabelDecorator decorator; + + /** + * Default constructor. + * + * @param adapterFactoryLabelProvider + * Provider which to delegate label and image resolution + * @param decorator + * {@link ILabelDecorator} to decorate the {@link Image} returned + * by {@link DTreeDecoratingLabelProvider#getImage(Object)} + */ + public DTreeDecoratingLabelProvider(AdapterFactory adapterFactoryLabelProvider, ILabelDecorator decorator) { + super(adapterFactoryLabelProvider); + this.decorator = decorator; + } + + /** + * Overridden to decorate with a image to notify the user of lock status. + * + * {@inheritDoc} + */ + public Image getImage(Object element) { + Image image = super.getImage(element); + if (decorator != null) { + Image decorated = decorator.decorateImage(image, element); + if (decorated != null) { + return decorated; + } + } + return image; + } + +} diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/provider/DTreeItemDragListener.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/provider/DTreeItemDragListener.java new file mode 100644 index 0000000000..2f72800227 --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/provider/DTreeItemDragListener.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright (c) 2009, 2011 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.tools.internal.editor.provider; + +import java.util.Iterator; +import java.util.Set; + +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.swt.dnd.DragSourceAdapter; +import org.eclipse.swt.dnd.DragSourceEvent; +import org.eclipse.swt.dnd.DragSourceListener; +import org.eclipse.ui.views.navigator.LocalSelectionTransfer; + +import com.google.common.collect.Sets; + +import org.eclipse.sirius.tree.DTreeItem; + +//FIXME Alex Lagarde +/** + * . + * + * @author alagarde + */ +public class DTreeItemDragListener extends DragSourceAdapter implements DragSourceListener { + + private ISelectionProvider selectionProvider; + + /** + * Construct a new instance. + * + * @param selectionProvider + * the selection provider + */ + public DTreeItemDragListener(ISelectionProvider selectionProvider) { + this.selectionProvider = selectionProvider; + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.swt.dnd.DragSourceAdapter#dragFinished(org.eclipse.swt.dnd.DragSourceEvent) + */ + @Override + public void dragFinished(DragSourceEvent event) { + + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.swt.dnd.DragSourceAdapter#dragSetData(org.eclipse.swt.dnd.DragSourceEvent) + */ + @SuppressWarnings("unchecked") + @Override + public void dragSetData(DragSourceEvent event) { + // We set the data of the drag to all selected DTreeItem (if any) + ISelection selection = this.selectionProvider.getSelection(); + if (selection instanceof IStructuredSelection) { + Set<DTreeItem> dragData = Sets.newLinkedHashSet(); + Iterator<Object> selectionIterator = ((IStructuredSelection) selection).iterator(); + while (selectionIterator.hasNext()) { + Object selectedElement = selectionIterator.next(); + if (selectedElement instanceof DTreeItem) { + dragData.add((DTreeItem) selectedElement); + } + } + LocalSelectionTransfer.getInstance().setSelection(this.selectionProvider.getSelection()); + event.data = dragData; + } + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.swt.dnd.DragSourceAdapter#dragStart(org.eclipse.swt.dnd.DragSourceEvent) + */ + @Override + public void dragStart(DragSourceEvent event) { + event.doit = !this.selectionProvider.getSelection().isEmpty(); + } + +} diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/provider/DTreeItemDropListener.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/provider/DTreeItemDropListener.java new file mode 100644 index 0000000000..2fa20cd287 --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/provider/DTreeItemDropListener.java @@ -0,0 +1,518 @@ +/******************************************************************************* + * Copyright (c) 2009, 2010 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.tools.internal.editor.provider; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.eclipse.emf.common.command.Command; +import org.eclipse.emf.common.command.CompoundCommand; +import org.eclipse.emf.common.command.UnexecutableCommand; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerDropAdapter; +import org.eclipse.swt.dnd.DropTargetListener; +import org.eclipse.swt.dnd.TransferData; +import org.eclipse.ui.views.navigator.LocalSelectionTransfer; + +import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; + +import org.eclipse.sirius.common.tools.api.interpreter.IInterpreter; +import org.eclipse.sirius.common.tools.api.interpreter.IInterpreterSiriusVariables; +import org.eclipse.sirius.common.tools.api.util.Option; +import org.eclipse.sirius.common.tools.api.util.Options; +import org.eclipse.sirius.common.tools.api.util.StringUtil; +import org.eclipse.sirius.DSemanticDecorator; +import org.eclipse.sirius.SiriusPlugin; +import org.eclipse.sirius.business.api.logger.RuntimeLoggerInterpreter; +import org.eclipse.sirius.business.api.logger.RuntimeLoggerManager; +import org.eclipse.sirius.description.tool.ToolPackage; +import org.eclipse.sirius.tree.DTree; +import org.eclipse.sirius.tree.DTreeItem; +import org.eclipse.sirius.tree.DTreeItemContainer; +import org.eclipse.sirius.tree.business.api.command.ITreeCommandFactory; +import org.eclipse.sirius.tree.description.TreeDragSource; +import org.eclipse.sirius.tree.description.TreeItemContainerDropTool; +import org.eclipse.sirius.ecore.extender.business.api.accessor.ModelAccessor; +import org.eclipse.sirius.ecore.extender.business.api.permission.IPermissionAuthority; + +/** + * Drop Listener used to validate and perform Drag and Drop operations on + * DTreeItems. + * + * @author <a href="mailto:alex.lagarde@obeo.fr">Alex Lagarde</a> + */ +public class DTreeItemDropListener extends ViewerDropAdapter implements DropTargetListener { + /** + * Start of the error message when more than one drop description + * corresponds to a drop element. + */ + private static final String MORE_THAN_ONE_DROP_DESCRIPTION_ERROR_MSG = "There are more than one drop description that match the dropped element"; + + private TransactionalEditingDomain domain; + + private ModelAccessor accessor; + + private ITreeCommandFactory commandFactory; + + /** + * A cache memorizing the sources of the current dragAndDrop. + */ + private final Set<DSemanticDecorator> droppedData = Sets.newLinkedHashSet(); + + /** + * A cache memorizing the semantic sources of the current dragAndDrop. + */ + private final Map<EObject, TreeItemContainerDropTool> semanticDroppedData = Maps.newLinkedHashMap(); + + /** + * The cache value of the DnD target. + */ + private DTreeItemContainer dropTarget; + + /** + * The preceding siblings of the current DnD operation. + */ + private final Collection<DTreeItem> precedingSiblings = Lists.newArrayList(); + + /** + * Creates a new DTreeItemDropListener. + * + * @param viewer + * the viewer on which this ViewerDropListener will be installed + * @param domain + * the Editing domain in which execute the DnD actions + * @param treeCommandFactory + * the Tree command factory to use + * @param accessor + * the model accessor to use + */ + public DTreeItemDropListener(Viewer viewer, TransactionalEditingDomain domain, ITreeCommandFactory treeCommandFactory, ModelAccessor accessor) { + super(viewer); + this.domain = domain; + this.commandFactory = treeCommandFactory; + this.accessor = accessor; + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.jface.viewers.ViewerDropAdapter#validateDrop(java.lang.Object, + * int, org.eclipse.swt.dnd.TransferData) + */ + @Override + public boolean validateDrop(Object target, int operation, TransferData transferType) { + resetContext(); + computeContext(target, operation, transferType); + + boolean valid = validateContext(); + + if (!valid) { + resetContext(); + } + + return valid; + } + + private void resetContext() { + dropTarget = null; + precedingSiblings.clear(); + droppedData.clear(); + semanticDroppedData.clear(); + } + + private void computeContext(Object target, int operation, TransferData transferType) { + // Result are stored to avoid unnecessary computation of + // the TreeItems when performing drag + + // Step A : get the correct target and preceding siblings + computeDropTargetAndPrecedingSiblings(target); + + // Step B : get the sources of the drop by checking + // the local selection transfer + computeDraggedDataFromLocalSelectionTransfer(); + + } + + /** + * Computes the actual Target of the DnD and the preceding siblings + * variables , according to the current Location value : + * <ul> + * <li>if the currentLocation is LOCATION_BEFORE : then the target of the + * DnD is the container of the default target. Preceding siblings will be + * all TreeItems contained by this container and located before the current + * target.</li> + * <li>if the currentLocation is LOCATION_AFTER : then the target of the DnD + * is the container of the default target. Preceding siblings will be all + * TreeItems contained by this container and located before the current + * target, including the current target.</li> + * <li>for all other values of currentLocation, then the target of the DnD + * is the current target, and the precedingSiblings will be all TreeItmes + * contained in the current target.</li> + * <li>if the target of the DnD is null, then the real container is the tree + * itself.</li> + * </ul> + * + * @param target + * the current DnD target (calculated by SWT) + * @return the actual Target of the DnD + */ + private void computeDropTargetAndPrecedingSiblings(Object target) { + int currentLocation = getCurrentLocation(); + + Object mouseTarget = target; + if (mouseTarget == null) { + // receiver is tree + mouseTarget = getViewer().getInput(); + currentLocation = LOCATION_ON; + } + + if (mouseTarget instanceof DTreeItem) { + DTreeItem itemMouseTarget = (DTreeItem) mouseTarget; + + // If the cursor is between 2 treeItems, + // the dropTarget should be the container + if ((currentLocation == LOCATION_BEFORE) || (currentLocation == LOCATION_AFTER)) { + if (itemMouseTarget.eContainer() instanceof DTreeItemContainer) { + dropTarget = (DTreeItemContainer) itemMouseTarget.eContainer(); + } + } else { + dropTarget = (DTreeItem) mouseTarget; + } + } else if (mouseTarget instanceof DTree) { + dropTarget = (DTree) mouseTarget; + } + + precedingSiblings.clear(); + if (dropTarget != null) { + List<DTreeItem> ownedTreeItems = dropTarget.getOwnedTreeItems(); + + // The preceding sliblings are all TreeItems contained + // before the current dropTarget. + if ((currentLocation == LOCATION_BEFORE) || (currentLocation == LOCATION_AFTER)) { + if (mouseTarget instanceof DTreeItem) { + DTreeItem ticMouseTarget = (DTreeItem) mouseTarget; + int dropTargetIndex = ownedTreeItems.indexOf(ticMouseTarget); + if (dropTargetIndex > 0) { + precedingSiblings.addAll(ownedTreeItems.subList(0, dropTargetIndex)); + } + + // If the items are dropped after the dropTarget + if (currentLocation == LOCATION_AFTER) { + // Then the current drop Target must be considered as a + // preceding slibling + precedingSiblings.add(ticMouseTarget); + } + } + } else { + // If the sources are dropped directly on a tree item container + // the we consider that all children of the drop target are + // preceding siblings of this target. + precedingSiblings.addAll(dropTarget.getOwnedTreeItems()); + } + } + } + + /** + * Compute the sources of the drag and drop from the local selection + * transfer's selection (for example the Model Explorer View). + * + */ + private void computeDraggedDataFromLocalSelectionTransfer() { + ISelection selection = LocalSelectionTransfer.getInstance().getSelection(); + + droppedData.clear(); + semanticDroppedData.clear(); + + if (selection instanceof IStructuredSelection) { + IStructuredSelection sel = (IStructuredSelection) selection; + + Iterable<DSemanticDecorator> dSelection = Iterables.filter(sel.toList(), DSemanticDecorator.class); + if (!Iterables.isEmpty(dSelection)) { + for (DSemanticDecorator semDec : dSelection) { + droppedData.add(semDec); + semanticDroppedData.put(semDec.getTarget(), null); + } + } else { + for (EObject eobject : Iterables.filter(sel.toList(), EObject.class)) { + semanticDroppedData.put(eobject, null); + } + } + } + } + + private boolean validateContext() { + boolean valid = false; + + // Check 1 : Graphical considerations + // Check 1.1 : the target must be a treeItem and the selection not empty + if (dropTarget != null && !semanticDroppedData.isEmpty()) { + // Look for a tool for each dropped semantic element + + // Check 1.2 : the sources must no contain the target + valid = !sourceIsTargetContainer(); + if (valid) { + // Check 2 : ensure that the target of the DnD can be edited + valid = canEditSemanticDecorator(dropTarget); + + // Check 3 : For each source of the DnD + // a DnD tool must be defined and applicable + if (!droppedData.isEmpty()) { + // Check 3.1 : dropping viewpoint elements : more variables + // and tool BOTH or TREE + for (DSemanticDecorator dSem : droppedData) { + valid = valid && canEditSemanticDecorator(dSem); + + EObject oldContainer = null; + if (dSem.eContainer() instanceof DSemanticDecorator) { + oldContainer = ((DSemanticDecorator) dSem.eContainer()).getTarget(); + } + Option<TreeItemContainerDropTool> dropTool = getBestDropDescription(dSem.getTarget(), oldContainer, TreeDragSource.TREE, dSem); + if (dropTool.some()) { + semanticDroppedData.put(dSem.getTarget(), dropTool.get()); + } else { + valid = false; + } + + if (!valid) { + break; + } + } + } else { + // Check 3.2 : dropping semantic elements : variables and + // tool BOTH or PROJECT_EXPLORER + for (EObject droppedElement : Lists.newArrayList(semanticDroppedData.keySet())) { + valid = valid && canEditEObject(droppedElement); + + Option<TreeItemContainerDropTool> dropTool = getBestDropDescription(droppedElement, null, TreeDragSource.PROJECT_EXPLORER, null); + + if (dropTool.some()) { + semanticDroppedData.put(droppedElement, dropTool.get()); + } else { + valid = false; + } + + if (!valid) { + break; + } + } + } + } + } + return valid; + } + + /** + * Indicates if one of the dragged sources is a container of the target. + * + * @param dragSources + * the dragged element + * @param dropTarget + * the drop target + * @return true if one of the dragged sources is a container of the target, + * false otherwise + */ + private boolean sourceIsTargetContainer() { + Object targetContainer = dropTarget; + while (targetContainer instanceof DTreeItem) { + if (droppedData.contains(targetContainer)) { + return true; + } + targetContainer = ((DTreeItem) targetContainer).getContainer(); + } + return false; + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.jface.viewers.ViewerDropAdapter#performDrop(java.lang.Object) + */ + @Override + public boolean performDrop(Object data) { + boolean dropped = false; + if (dropTarget != null) { + // Step 1 : create a command containing all semantic + // instructions + // associated to the DnD tools + Command dndCommand = buildCommand(); + + // Step 2 : execute the created command + if (dndCommand.canExecute()) { + domain.getCommandStack().execute(dndCommand); + dropped = true; + } + } + resetContext(); + return dropped; + + } + + private CompoundCommand buildCommand() { + CompoundCommand dndCommand = new CompoundCommand("Drag And Drop"); + if (!droppedData.isEmpty()) { + for (DSemanticDecorator semDec : droppedData) { + EObject droppedElement = semDec.getTarget(); + TreeItemContainerDropTool tool = semanticDroppedData.get(droppedElement); + if (tool == null) { + dndCommand.append(UnexecutableCommand.INSTANCE); + } + dndCommand.append(commandFactory.buildDropItemFromTool(semDec, dropTarget, precedingSiblings, tool)); + } + } else { + for (Entry<EObject, TreeItemContainerDropTool> entry : semanticDroppedData.entrySet()) { + if (entry.getValue() == null) { + dndCommand.append(UnexecutableCommand.INSTANCE); + } + dndCommand.append(commandFactory.buildDropItemFromTool(entry.getKey(), dropTarget, precedingSiblings, entry.getValue())); + } + } + return dndCommand; + } + + /** + * Indicates whether the given DSemanticDecorator (TreeItem or DTree) can be + * edited or not, using the Permission Authority and the CanEdit feature. + * + * @param decorator + * the item to determine if it is editable or not + * @return true if the given DSemanticDecorator and its target can be + * edited, false otherwise + */ + protected boolean canEditSemanticDecorator(DSemanticDecorator decorator) { + // Permission Authority must allow edition of the DTreeItem and its + // semantic target + + IPermissionAuthority authority = accessor != null ? accessor.getPermissionAuthority() : null; + boolean canEdit = authority != null && authority.canEditInstance(decorator.getTarget()); + canEdit = canEdit && authority.canEditInstance(decorator); + + return canEdit; + } + + /** + * Indicates whether the given object can be edited or not, using the + * Permission Authority and the CanEdit feature. + * + * @param obj + * the item to determine if it is editable or not + * @return true if the given object can be edited, false otherwise + */ + protected boolean canEditEObject(EObject obj) { + // Permission Authority must allow edition of the DTreeItem and its + // semantic target + + IPermissionAuthority authority = accessor != null ? accessor.getPermissionAuthority() : null; + boolean canEdit = authority != null && authority.canEditInstance(obj); + + return canEdit; + } + + /** + * Return the best drop description. + * + * @param description + * . + * @param droppedElement + * The semantic dropped element + * @param oldContainer + * The old semantic container, can be null (for instance if drop + * comes from project explorer) + * @param newContainer + * The new semantic container + * @param newViewContainer + * The new view container + * @param dragSource + * the drag source. + * @param droppedSemanticDecorator + * The graphical dropped element (Optional). + * @return he best drop description + */ + private Option<TreeItemContainerDropTool> getBestDropDescription(final EObject droppedElement, final EObject oldContainer, final TreeDragSource dragSource, + final DSemanticDecorator droppedSemanticDecorator) { + + final IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(droppedElement); + if (oldContainer != null) { + interpreter.setVariable(IInterpreterSiriusVariables.CONTAINER_OLD, oldContainer); + } + interpreter.setVariable(IInterpreterSiriusVariables.CONTAINER_NEW, dropTarget.getTarget()); + interpreter.setVariable(IInterpreterSiriusVariables.CONTAINER_VIEW_NEW, dropTarget); + interpreter.setVariable(IInterpreterSiriusVariables.ELEMENT, droppedElement); + if (droppedSemanticDecorator != null) { + interpreter.setVariable(IInterpreterSiriusVariables.VIEW, droppedSemanticDecorator); + } + RuntimeLoggerInterpreter safeInterpreter = RuntimeLoggerManager.INSTANCE.decorate(interpreter); + + TreeItemContainerDropTool bestDropDescription = null; + + /* find valid candidates */ + for (TreeItemContainerDropTool dropTool : getDropTools(dragSource)) { + if (checkPrecondition(dropTool, safeInterpreter, droppedElement)) { + if (bestDropDescription == null) { + bestDropDescription = dropTool; + } else { + SiriusPlugin.getDefault().warning( + MORE_THAN_ONE_DROP_DESCRIPTION_ERROR_MSG + " : " + droppedElement + " (" + bestDropDescription.getName() + " and " + dropTool.getName() + ").", new RuntimeException()); + break; + } + } + } + + // Clean variables + if (oldContainer != null) { + interpreter.unSetVariable(IInterpreterSiriusVariables.CONTAINER_OLD); + } + interpreter.unSetVariable(IInterpreterSiriusVariables.CONTAINER_NEW); + interpreter.unSetVariable(IInterpreterSiriusVariables.CONTAINER_VIEW_NEW); + interpreter.unSetVariable(IInterpreterSiriusVariables.ELEMENT); + if (droppedSemanticDecorator != null) { + interpreter.unSetVariable(IInterpreterSiriusVariables.VIEW); + } + + return Options.newSome(bestDropDescription); + } + + private boolean checkPrecondition(TreeItemContainerDropTool dropTool, RuntimeLoggerInterpreter safeInterpreter, EObject droppedElement) { + final String precondition = dropTool.getPrecondition(); + if (precondition != null && !StringUtil.isEmpty(precondition.trim())) { + return safeInterpreter.evaluateBoolean(droppedElement, dropTool, ToolPackage.eINSTANCE.getAbstractToolDescription_Precondition()); + } + return true; + } + + private Iterable<TreeItemContainerDropTool> getDropTools(final TreeDragSource dragSource) { + Predicate<TreeItemContainerDropTool> checkedDragSource = new Predicate<TreeItemContainerDropTool>() { + public boolean apply(TreeItemContainerDropTool input) { + return input.getDragSource() == TreeDragSource.BOTH || input.getDragSource() == dragSource; + } + }; + + Collection<TreeItemContainerDropTool> availableTools = Lists.newArrayList(); + if (dropTarget instanceof DTree) { + availableTools.addAll(((DTree) dropTarget).getDescription().getDropTools()); + } else if (dropTarget instanceof DTreeItem) { + availableTools.addAll(((DTreeItem) dropTarget).getActualMapping().getDropTools()); + } + + return Iterables.filter(availableTools, checkedDragSource); + } + +} diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/provider/DTreeItemEditingSupport.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/provider/DTreeItemEditingSupport.java new file mode 100644 index 0000000000..ef51bdb06d --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/provider/DTreeItemEditingSupport.java @@ -0,0 +1,298 @@ +/******************************************************************************* + * Copyright (c) 2009, 2010 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.tools.internal.editor.provider; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.transaction.RecordingCommand; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.jface.viewers.CellEditor; +import org.eclipse.jface.viewers.EditingSupport; +import org.eclipse.jface.viewers.TextCellEditor; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.swt.widgets.Tree; + +import org.eclipse.sirius.common.tools.api.interpreter.EvaluationException; +import org.eclipse.sirius.common.tools.api.interpreter.IInterpreter; +import org.eclipse.sirius.common.tools.api.util.StringUtil; +import org.eclipse.sirius.business.api.logger.RuntimeLoggerManager; +import org.eclipse.sirius.tools.api.interpreter.InterpreterUtil; +import org.eclipse.sirius.tree.DTreeItem; +import org.eclipse.sirius.tree.business.api.command.ITreeCommandFactory; +import org.eclipse.sirius.tree.description.TreeItemEditionTool; +import org.eclipse.sirius.ui.tools.internal.editor.AbstractDTreeEditor; +import org.eclipse.sirius.ecore.extender.business.api.accessor.ModelAccessor; +import org.eclipse.sirius.ecore.extender.business.api.permission.IPermissionAuthority; + +/** + * Support for editing DTreeItems of a DTree. + * + * @author <a href="mailto:alex.lagarde@obeo.fr">Alex Lagarde</a> + */ +public class DTreeItemEditingSupport extends EditingSupport { + + /** + * The transactional editing domain of this viewer. + */ + private final TransactionalEditingDomain editingDomain; + + /** + * The model accessor to use for get and modify model elements. + */ + private final ModelAccessor accessor; + + /** + * The command Factory to use for building tools commands. + */ + private final ITreeCommandFactory treeCommandFactory; + + /** + * The managed TreeEditor. + */ + private final AbstractDTreeEditor treeEditor; + + /** + * Creates a new editing support for editing DTreeItems of a DTree. + * + * @param viewer + * The treeViewer for this editingSupport + * @param editingDomain + * The transactional editing domain of this viewer + * @param accessor + * The accessor for the model + * @param treeCommandFactory + * the command Factory to use for building tools commands + * @param abstractDTreeEditor + * The associated editor + */ + public DTreeItemEditingSupport(final TreeViewer viewer, final TransactionalEditingDomain editingDomain, final ModelAccessor accessor, final ITreeCommandFactory treeCommandFactory, + final AbstractDTreeEditor abstractDTreeEditor) { + super(viewer); + this.editingDomain = editingDomain; + this.accessor = accessor; + this.treeCommandFactory = treeCommandFactory; + this.treeEditor = abstractDTreeEditor; + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.jface.viewers.EditingSupport#canEdit(java.lang.Object) + */ + @Override + protected boolean canEdit(final Object element) { + + if (element instanceof DTreeItem) { + final DTreeItem item = (DTreeItem) element; + boolean canEdit = false; + IInterpreter interpreter = null; + // If the DTreeItem to edit is associated to a canEdit expression + // if (item.getUpdater() != null && item.getUpdater().getCanEdit() + // != null && item.getUpdater().getCanEdit().length() > 0) { + // interpreter = InterpreterUtil.getInterpreter(item.getTarget()); + // try { + // // The evaluation of this expression must return true + // canEdit = interpreter.evaluateBoolean(item.getTarget(), + // item.getUpdater().getCanEdit()); + // } catch (final EvaluationException e) { + // RuntimeLoggerManager.INSTANCE.error(item.getUpdater(), + // DescriptionPackage.eINSTANCE.getTreeItemUpdater_CanEdit(), e); + // } + // } + // If the Edition tool has a precondition + if (item.getUpdater() != null && item.getUpdater().getDirectEdit() != null) { + canEdit = true; + if (!StringUtil.isEmpty(item.getUpdater().getDirectEdit().getPrecondition())) { + if (interpreter == null) { + interpreter = InterpreterUtil.getInterpreter(item.getTarget()); + } + String precondition = item.getUpdater().getDirectEdit().getPrecondition(); + try { + canEdit = interpreter.evaluateBoolean(item.getTarget(), precondition); + } catch (final EvaluationException e) { + RuntimeLoggerManager.INSTANCE.error(item.getUpdater().getDirectEdit(), org.eclipse.sirius.description.tool.ToolPackage.eINSTANCE.getAbstractToolDescription_Precondition(), + e); + } + + } + } + + // DTreeItem also must be editable + return canEdit && getAuthority().canEditInstance(item); + } + return false; + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.jface.viewers.EditingSupport#getCellEditor(java.lang.Object) + */ + @Override + protected CellEditor getCellEditor(final Object element) { + if (element instanceof DTreeItem) { + DTreeItem editedItem = (DTreeItem) element; + final boolean directEdit = editedItem.getUpdater() != null && editedItem.getUpdater().getDirectEdit() != null; + return getBestCellEditor(editedItem.getTarget(), directEdit); + } + return null; + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.jface.viewers.EditingSupport#getValue(java.lang.Object) + */ + @Override + protected Object getValue(final Object element) { + Object result = null; + if (element instanceof DTreeItem) { + result = ((DTreeItem) element).getName(); + } + return result; + } + + /** + * {@inheritDoc} + * + * @see org.eclipse.jface.viewers.EditingSupport#setValue(java.lang.Object, + * java.lang.Object) + */ + @Override + protected void setValue(final Object element, final Object value) { + if (element instanceof DTreeItem) { + final DTreeItem treeItem = (DTreeItem) element; + + if (value != null) { + final Object finalValue = value; + if (treeItem.getUpdater() != null && treeItem.getUpdater().getDirectEdit() != null) { + // Specific set : we use the DirectEditTool defined on this + // DTreeItem to modify semantic elements + specificSetValue(treeItem, finalValue); + } else { + // Normal set : we only change the DTreeItem name + standardSetValue(treeItem, finalValue); + } + } + + } + } + + /** + * Only changes the name of the given DTreeItem. + * + * @param itemToSet + * the edited DTreeItem + * @param value + * the new value for this DTreeItem + */ + private void standardSetValue(final DTreeItem itemToSet, final Object value) { + // We simply change the name of the given itemToSet + final DTreeItem treeItem = itemToSet; + if (value instanceof String) { + getEditingDomain().getCommandStack().execute(new StandardSetValueRecordingCommand(getEditingDomain(), "Direct Edit on " + itemToSet.getName(), treeItem, value)); + } + } + + /** + * Set the value by calling the defined Edition Tool. + * + * @param editedTreeItem + * The DTreeItem to set + * @param value + * the new value + * + */ + private void specificSetValue(final DTreeItem editedTreeItem, final Object value) { + treeEditor.enablePropertiesUpdate(false); + // We use the command Factory to create the command corresponding to the + // Editing Tool + final TreeItemEditionTool editTool = editedTreeItem.getUpdater().getDirectEdit(); + if (editTool.getFirstModelOperation() != null) { + getEditingDomain().getCommandStack().execute(treeCommandFactory.buildDirectEditLabelFromTool(editedTreeItem, editTool, (String) value)); + } + // We allow properties update so that the treeItem is correctly + // refreshed + treeEditor.enablePropertiesUpdate(true); + treeEditor.forceRefreshProperties(); + } + + /** + * Chooses the best CellEditor depending on the type of value to edit + * + * @param element + * The current edited element + * @param directEdit + * true if this cell has a direct edit tool, false otherwise + * @return An adapted cell Editor + */ + private CellEditor getBestCellEditor(final EObject element, final boolean directEdit) { + final Tree tree = ((TreeViewer) getViewer()).getTree(); + final TextCellEditor textEditor = new TextCellEditor(tree) { + /** + * {@inheritDoc} We override the doSetFocus for clearing the + * selection for the direct edition of the cell. + * + * @see org.eclipse.jface.viewers.TextCellEditor#doSetFocus() + */ + @Override + protected void doSetFocus() { + super.doSetFocus(); + if (text != null) { + text.clearSelection(); + } + } + }; + textEditor.getControl().addFocusListener(new DTreeItemEditorFocusListener(this.treeEditor, textEditor)); + return textEditor; + } + + /** + * Return the transactional editing domain. + * + * @return the transactional editing domain + */ + public TransactionalEditingDomain getEditingDomain() { + return editingDomain; + } + + /** + * @return The permission authority + */ + private IPermissionAuthority getAuthority() { + return getAccessor().getPermissionAuthority(); + } + + /** + * @return the accessor + */ + private ModelAccessor getAccessor() { + return accessor; + } + + private class StandardSetValueRecordingCommand extends RecordingCommand { + + private DTreeItem treeItem; + + private Object value; + + public StandardSetValueRecordingCommand(TransactionalEditingDomain domain, String label, DTreeItem treeItem, Object value) { + super(domain, label); + this.treeItem = treeItem; + this.value = value; + } + + @Override + protected void doExecute() { + treeItem.setName((String) value); + } + + } +} diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/provider/DTreeItemEditorFocusListener.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/provider/DTreeItemEditorFocusListener.java new file mode 100644 index 0000000000..2b31f59359 --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/provider/DTreeItemEditorFocusListener.java @@ -0,0 +1,160 @@ +/******************************************************************************* + * Copyright (c) 2013 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.tools.internal.editor.provider; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.viewers.TextCellEditor; +import org.eclipse.swt.events.FocusEvent; +import org.eclipse.swt.events.FocusListener; +import org.eclipse.ui.actions.ActionFactory; + +import org.eclipse.sirius.ui.tools.internal.editor.AbstractDTreeEditor; + +/** + * A focusListener which replaces the EMF copy/cut/paste actions with standard + * actions. + * + * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a> + */ +public class DTreeItemEditorFocusListener implements FocusListener { + /** + * Action to cut the content of the cell in the clipboard. + * + * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a> + */ + private class StandardCutAction extends Action { + TextCellEditor textCellEditor; + + /** + * The default constructor. + * + * @param textCellEditor + * The current cell editor + */ + public StandardCutAction(final TextCellEditor textCellEditor) { + this.textCellEditor = textCellEditor; + } + + @Override + public void run() { + textCellEditor.performCut(); + } + } + + /** + * Action to copy the content of the cell in the clipboard. + * + * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a> + */ + private class StandardCopyAction extends Action { + TextCellEditor textCellEditor; + + /** + * The default constructor. + * + * @param textCellEditor + * The current cell editor + */ + public StandardCopyAction(final TextCellEditor textCellEditor) { + this.textCellEditor = textCellEditor; + } + + @Override + public void run() { + textCellEditor.performCopy(); + } + } + + /** + * Action to paste the content of the cell in the clipboard. + * + * @author <a href="mailto:laurent.redor@obeo.fr">Laurent Redor</a> + */ + private class StandardPasteAction extends Action { + TextCellEditor textCellEditor; + + /** + * The default constructor. + * + * @param textCellEditor + * The current cell editor + */ + public StandardPasteAction(final TextCellEditor textCellEditor) { + this.textCellEditor = textCellEditor; + } + + @Override + public void run() { + textCellEditor.performPaste(); + } + } + + AbstractDTreeEditor treeEditor; + + TextCellEditor textCellEditor; + + IAction emfCutAction; + + IAction emfCopyAction; + + IAction emfPasteAction; + + IAction standardCut; + + IAction standardCopy; + + IAction standardPaste; + + /** + * The default constructor. + * + * @param treeEditor + * The current tree editor + * @param textCellEditor + * The current Editor associated to the TreeItem being edited + */ + public DTreeItemEditorFocusListener(final AbstractDTreeEditor treeEditor, final TextCellEditor textCellEditor) { + this.treeEditor = treeEditor; + this.textCellEditor = textCellEditor; + emfCutAction = treeEditor.getActionBars().getGlobalActionHandler(ActionFactory.CUT.getId()); + emfCopyAction = treeEditor.getActionBars().getGlobalActionHandler(ActionFactory.COPY.getId()); + emfPasteAction = treeEditor.getActionBars().getGlobalActionHandler(ActionFactory.PASTE.getId()); + + standardCut = new StandardCutAction(textCellEditor); + standardCopy = new StandardCopyAction(textCellEditor); + standardPaste = new StandardPasteAction(textCellEditor); + } + + /** + * We reset the actions with the EMF actions.<BR> {@inheritDoc} + * + * @see org.eclipse.swt.events.FocusListener#focusLost(org.eclipse.swt.events.FocusEvent) + */ + public void focusLost(final FocusEvent e) { + treeEditor.getActionBars().setGlobalActionHandler(ActionFactory.CUT.getId(), emfCutAction); + treeEditor.getActionBars().setGlobalActionHandler(ActionFactory.COPY.getId(), emfCopyAction); + treeEditor.getActionBars().setGlobalActionHandler(ActionFactory.PASTE.getId(), emfPasteAction); + treeEditor.getActionBars().updateActionBars(); + } + + /** + * We override the EMF actions with the standard action.<BR> {@inheritDoc} + * + * @see org.eclipse.swt.events.FocusListener#focusGained(org.eclipse.swt.events.FocusEvent) + */ + public void focusGained(final FocusEvent e) { + treeEditor.getActionBars().setGlobalActionHandler(ActionFactory.CUT.getId(), standardCut); + treeEditor.getActionBars().setGlobalActionHandler(ActionFactory.COPY.getId(), standardCopy); + treeEditor.getActionBars().setGlobalActionHandler(ActionFactory.PASTE.getId(), standardPaste); + treeEditor.getActionBars().updateActionBars(); + } +} diff --git a/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/provider/TreePopupMenuContributionSupport.java b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/provider/TreePopupMenuContributionSupport.java new file mode 100644 index 0000000000..529e254d79 --- /dev/null +++ b/plugins/org.eclipse.sirius.tree.ui/src/org/eclipse/sirius/tree/ui/tools/internal/editor/provider/TreePopupMenuContributionSupport.java @@ -0,0 +1,339 @@ +/******************************************************************************* + * Copyright (c) 2009, 2011 THALES GLOBAL SERVICES. + * 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: + * Obeo - initial API and implementation + *******************************************************************************/ +package org.eclipse.sirius.tree.ui.tools.internal.editor.provider; + +import java.util.Iterator; + +import org.eclipse.emf.common.command.Command; +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.edit.provider.IItemLabelProvider; +import org.eclipse.emf.edit.ui.provider.ExtendedImageRegistry; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.action.Separator; +import org.eclipse.jface.resource.ImageDescriptor; + +import com.google.common.collect.Iterators; + +import org.eclipse.sirius.common.tools.api.interpreter.IInterpreter; +import org.eclipse.sirius.common.tools.api.util.StringUtil; +import org.eclipse.sirius.SiriusPlugin; +import org.eclipse.sirius.business.api.logger.RuntimeLoggerManager; +import org.eclipse.sirius.business.api.query.IdentifiedElementQuery; +import org.eclipse.sirius.description.tool.CreateInstance; +import org.eclipse.sirius.description.tool.ExternalJavaAction; +import org.eclipse.sirius.description.tool.ExternalJavaActionCall; +import org.eclipse.sirius.description.tool.MenuItemDescription; +import org.eclipse.sirius.description.tool.OperationAction; +import org.eclipse.sirius.description.tool.ToolPackage; +import org.eclipse.sirius.tools.api.ui.ExternalJavaActionProvider; +import org.eclipse.sirius.tools.api.ui.IExternalJavaAction; +import org.eclipse.sirius.tree.DTreeItem; +import org.eclipse.sirius.tree.business.api.command.ITreeCommandFactory; +import org.eclipse.sirius.tree.business.api.query.TreePopupMenuQuery; +import org.eclipse.sirius.tree.description.TreePopupMenu; +import org.eclipse.sirius.tree.ui.provider.TreeUIPlugin; +import org.eclipse.sirius.tree.ui.tools.internal.editor.DTreeViewerManager; +import org.eclipse.sirius.ecore.extender.business.api.accessor.exception.MetaClassNotFoundException; + +/** + * A Class that will populate a {@link DTreeItem}'s contextual menu using all + * the {@link org.eclipse.sirius.description.tool.PopupMenu}s defined with its associate + * {@link org.eclipse.sirius.tree.description.TreeItemMapping}. + * + * @author <a href="mailto:alex.lagarde@obeo.fr">Alex Lagarde</a> + */ +public final class TreePopupMenuContributionSupport { + + /** + * The editing domain. + */ + protected TransactionalEditingDomain domain; + + /** + * The factory to use to create tree-related commands. + */ + protected ITreeCommandFactory treeCommandFactory; + + /** + * Creates a new TreePopupMenuContributionSupport. + * + * @param transactionalEditingDomain + * the domain to use for executing contributed actions + * @param treeCommandFactory + * the command factory to use + */ + public TreePopupMenuContributionSupport(TransactionalEditingDomain transactionalEditingDomain, ITreeCommandFactory treeCommandFactory) { + this.domain = transactionalEditingDomain; + this.treeCommandFactory = treeCommandFactory; + } + + /** + * Adds all menus and actions defined for the given {@link DTreeItem} to the + * given contextual menu. + * + * @param menu + * the contextual menu about to be shown + * @param selectedItem + * the selected {@link DTreeItem} from which getting the + * additional menus and actions + */ + public void contributeToPopupMenu(final IMenuManager menu, DTreeItem selectedItem) { + EList<TreePopupMenu> popupMenus = selectedItem.getActualMapping().getPopupMenus(); + IInterpreter interpreter = SiriusPlugin.getDefault().getInterpreterRegistry().getInterpreter(selectedItem.getTarget()); + boolean haveCreatedAtLeastOnePopupMenu = false; + if (interpreter == null || popupMenus.isEmpty()) { + return; + } + + // For each defined popupMenu + for (TreePopupMenu popupMenu : popupMenus) { + // If the defined popupMenu is applicable (i.e. has a "true" + // precondition) + final Boolean menuPrecondition; + if (StringUtil.isEmpty(popupMenu.getPrecondition())) { + menuPrecondition = true; + } else { + menuPrecondition = RuntimeLoggerManager.INSTANCE.decorate(interpreter).evaluateBoolean(selectedItem.getTarget(), popupMenu, + ToolPackage.eINSTANCE.getAbstractToolDescription_Precondition()); + } + + if (menuPrecondition) { + + // We create a subMenu + final MenuManager subMenu = new MenuManager(new IdentifiedElementQuery(popupMenu).getLabel(), new IdentifiedElementQuery(popupMenu).getLabel().toLowerCase()); + // and populate it with all menu contributions contained it this + // popupMenu + buildActionsFromTreePopupMenu(subMenu, selectedItem, popupMenu, interpreter); + + // If at least one action has been added to the subMenu, we make + // it visible + if (subMenu.getSize() > 0) { + haveCreatedAtLeastOnePopupMenu = true; + subMenu.setParent(menu); + menu.add(subMenu); + subMenu.setVisible(true); + } + } + } + if (haveCreatedAtLeastOnePopupMenu) { + menu.add(new Separator()); + } + + } + + /** + * Builds all the Actions specified in the given popupMenu and adds them to + * the given subMenu + * + * @param subMenu + * the subMenu in which create the actions + * @param selectedItem + * the {@link DTreeItem} from which the contextual menu is + * computed + * @param popupMenu + * the popupMenu containing the Actions to create + * @param domain + */ + private void buildActionsFromTreePopupMenu(IMenuManager subMenu, DTreeItem selectedItem, TreePopupMenu popupMenu, IInterpreter interpreter) { + // For each menu contribution associated to the given popupMenu + for (MenuItemDescription candidateMenuItem : new TreePopupMenuQuery(popupMenu).getMenuItems()) { + // If the menu item is applicable (i.e. has a "true" + // precondition) + final Boolean menuItemPrecondition; + if (StringUtil.isEmpty(candidateMenuItem.getPrecondition())) { + menuItemPrecondition = true; + } else { + menuItemPrecondition = RuntimeLoggerManager.INSTANCE.decorate(interpreter).evaluateBoolean(selectedItem.getTarget(), candidateMenuItem, + ToolPackage.eINSTANCE.getAbstractToolDescription_Precondition()); + } + + if (menuItemPrecondition) { + // We build a jface Action from this menu item + final IAction action = buildActionFromMenuItemDescription(candidateMenuItem, selectedItem); + if (action != null) { + subMenu.add(action); + } + } + } + } + + /** + * Builds a JFace Action from the given {@link MenuItemDescription}, which + * target is the given selected {@link DTreeItem}. + * + * @param candidateMenuItem + * the {@link MenuItemDescription} to create an Action from + * @param selectedItem + * the selected {@link DTreeItem} + * @return a JFace Action created from the given {@link MenuItemDescription} + */ + private IAction buildActionFromMenuItemDescription(MenuItemDescription candidateMenuItem, DTreeItem selectedItem) { + IAction result = null; + // The Menu Item Description can be : + // An External Java Action + if (candidateMenuItem instanceof ExternalJavaAction) { + final ExternalJavaAction javaAction = (ExternalJavaAction) candidateMenuItem; + if (!StringUtil.isEmpty(javaAction.getId())) { + result = buildJavaAction(javaAction, selectedItem, new IdentifiedElementQuery(javaAction).getLabel(), javaAction.getIcon()); + } + } else { + // An External Java Action call + if (candidateMenuItem instanceof ExternalJavaActionCall) { + final ExternalJavaAction javaAction = ((ExternalJavaActionCall) candidateMenuItem).getAction(); + if (javaAction != null && !StringUtil.isEmpty(javaAction.getId())) { + String iconPath = ((ExternalJavaActionCall) candidateMenuItem).getIcon(); + if (StringUtil.isEmpty(iconPath)) { + iconPath = javaAction.getIcon(); + } + result = buildJavaAction(javaAction, selectedItem, new IdentifiedElementQuery(candidateMenuItem).getLabel(), iconPath); + } + // An Operation Action + } else { + if (candidateMenuItem instanceof OperationAction) { + final OperationAction operation = (OperationAction) candidateMenuItem; + if (operation.getInitialOperation().getFirstModelOperations() != null) { + result = buildOperationAction(operation, selectedItem); + } + } + } + } + return result; + } + + /** + * Builds a JFace Action from the given {@link ExternalJavaAction}, which + * target is the given selected {@link DTreeItem}. + * + * @param javaActionItem + * the ExternalJavaAction action to create an Action from + * @param selectedItem + * the selected {@link DTreeItem} + * @param nameOfTheAction + * the name to associate with the created action + * @param iconPath + * the path of the icon to associate with the created action + * @return a JFace Action created from the given {@link ExternalJavaAction} + */ + private IAction buildJavaAction(ExternalJavaAction javaActionItem, DTreeItem selectedItem, String nameOfTheAction, String iconPath) { + // Step 1 : getting the java Action + final IExternalJavaAction javaAction = ExternalJavaActionProvider.INSTANCE.getJavaActionById(javaActionItem.getId()); + + if (javaAction != null) { + // Step 2 : building the command from this java Action + final Command command = this.treeCommandFactory.buildJavaActionFromTool(javaActionItem, selectedItem, javaAction); + + if (command.canExecute()) { + // Step 3 : getting the icon to associate with the action to + // create + ImageDescriptor imageDescriptor = null; + if (!StringUtil.isEmpty(iconPath)) { + imageDescriptor = TreeUIPlugin.findImageDescriptor(iconPath); + } + // Step 4 : creating an action that will call the builded + // command + return new Action(nameOfTheAction, imageDescriptor) { + + @Override + public void run() { + super.run(); + domain.getCommandStack().execute(command); + } + }; + } + } + return null; + } + + /** + * Builds a JFace Action from the given {@link OperationAction}, which + * target is the given selected {@link DTreeItem}. + * + * @param operationAction + * the operation action to create an Action from + * @param selectedItem + * the selected {@link DTreeItem} + * @return a JFace Action created from the given {@link OperationAction} + */ + private IAction buildOperationAction(final OperationAction operationAction, DTreeItem selectedItem) { + // Step 1 : getting the icon to associate with the action to create + ImageDescriptor imageDescriptor = null; + if (!StringUtil.isEmpty(operationAction.getIcon())) { + imageDescriptor = TreeUIPlugin.findImageDescriptor(operationAction.getIcon()); + } else { + // no icon is specified, let's provide a semantic icon as a default + // if we can find a create instance task. + imageDescriptor = TreePopupMenuContributionSupport.findImageDescriptor(operationAction); + } + + // Step 2 : building the command from this OperationAction + final Command operationActionCommand = treeCommandFactory.buildOperationActionFromTool(operationAction, selectedItem); + + if (operationActionCommand.canExecute()) { + // Step 3 : creating an action that will call the builded + // command + return new Action(new IdentifiedElementQuery(operationAction).getLabel(), imageDescriptor) { + @Override + public void run() { + super.run(); + domain.getCommandStack().execute(operationActionCommand); + } + }; + } + return null; + } + + private static ImageDescriptor findImageDescriptor(OperationAction createTool) { + + ImageDescriptor descriptor = DTreeViewerManager.getImageRegistry().getDescriptor(DTreeViewerManager.CREATE_TREE_ITEM_IMG); + EObject created = null; + + Iterator<CreateInstance> createInstances = Iterators.filter(createTool.eAllContents(), CreateInstance.class); + while (created == null && createInstances.hasNext()) { + CreateInstance map = createInstances.next(); + created = TreePopupMenuContributionSupport.tryToInstanciateType(createTool, created, map.getTypeName()); + } + + if (created != null) { + final IItemLabelProvider labelProvider = (IItemLabelProvider) TreeUIPlugin.getPlugin().getItemProvidersAdapterFactory().adapt(created, IItemLabelProvider.class); + if (labelProvider != null) { + ImageDescriptor semanticDescriptor = ExtendedImageRegistry.getInstance().getImageDescriptor(labelProvider.getImage(created)); + if (semanticDescriptor != null) { + descriptor = semanticDescriptor; + } + + } + } + + return descriptor; + } + + private static EObject tryToInstanciateType(OperationAction createTool, EObject created, String map) { + EObject result = created; + if (!StringUtil.isEmpty(map)) { + try { + final EObject anInstance = SiriusPlugin.getDefault().getModelAccessorRegistry().getModelAccessor(createTool).createInstance(map); + result = anInstance; + } catch (final MetaClassNotFoundException e) { + /* + * silent catch, it's just a bit more magic, if we're able to + * retrieve the right type then we'll do. + */ + } + + } + return result; + } +} |