From e9bbbbcbef810b952d2c98caaa18d711eabd3a7f Mon Sep 17 00:00:00 2001 From: Christian W. Damus Date: Fri, 26 Feb 2016 17:53:17 -0500 Subject: Bug 474467: Papyrus editors title do not update when their label change Add support for propagation of label-provider change events for labels that are dependent on other elements' labels. Implement such a dependent label for all notation views supported by the Viewpoints mechanism that have no names of their own, including * unnamed Diagrams * unnamed Tables Now that the table label provider depends on table prototypes, the broken prototype references in editor reload tests need to be updated (they were missed in the refactoring when all of the prototypes were removed from the builtin Viewpoints configuration model). Change-Id: I8a9c361129c996188f87ac2851db39e0f66f3acd --- .../contentprovider/AbstractPageModel.java | 86 ++ .../infra/core/sasheditor/internal/EditorPart.java | 1504 ++++++++++---------- .../infra/core/utils/AbstractServiceUtils.java | 47 +- .../emf/providers/DependentEMFLabelProvider.java | 161 +++ .../infra/ui/emf/providers/EMFLabelProvider.java | 648 +++++---- .../emf/providers/ForwardingEMFLabelProvider.java | 82 ++ .../ui/emf/providers/StandardEMFLabelProvider.java | 16 +- .../infra/gmfdiag/common/GmfEditorFactory.java | 78 +- .../common/providers/NotationLabelProvider.java | 161 +-- .../.classpath | 14 +- .../.settings/org.eclipse.jdt.core.prefs | 6 +- .../META-INF/MANIFEST.MF | 2 +- .../common/factory/NattableEditorFactory.java | 52 +- .../nattable/provider/TableLabelProvider.java | 112 +- .../.classpath | 16 +- .../.settings/org.eclipse.jdt.core.prefs | 6 +- .../META-INF/MANIFEST.MF | 5 +- .../policy/UnavailableViewPrototype.java | 9 +- .../infra/viewpoints/policy/ViewPrototype.java | 18 +- .../policy/ViewPrototypeLabelProvider.java | 95 ++ 20 files changed, 1734 insertions(+), 1384 deletions(-) create mode 100644 plugins/infra/core/org.eclipse.papyrus.infra.core.sasheditor/src/org/eclipse/papyrus/infra/core/sasheditor/contentprovider/AbstractPageModel.java create mode 100644 plugins/infra/emf/org.eclipse.papyrus.infra.ui.emf/src/org/eclipse/papyrus/infra/ui/emf/providers/DependentEMFLabelProvider.java create mode 100644 plugins/infra/emf/org.eclipse.papyrus.infra.ui.emf/src/org/eclipse/papyrus/infra/ui/emf/providers/ForwardingEMFLabelProvider.java create mode 100644 plugins/infra/viewpoints/org.eclipse.papyrus.infra.viewpoints.policy/src/org/eclipse/papyrus/infra/viewpoints/policy/ViewPrototypeLabelProvider.java (limited to 'plugins') diff --git a/plugins/infra/core/org.eclipse.papyrus.infra.core.sasheditor/src/org/eclipse/papyrus/infra/core/sasheditor/contentprovider/AbstractPageModel.java b/plugins/infra/core/org.eclipse.papyrus.infra.core.sasheditor/src/org/eclipse/papyrus/infra/core/sasheditor/contentprovider/AbstractPageModel.java new file mode 100644 index 00000000000..394b6887aa8 --- /dev/null +++ b/plugins/infra/core/org.eclipse.papyrus.infra.core.sasheditor/src/org/eclipse/papyrus/infra/core/sasheditor/contentprovider/AbstractPageModel.java @@ -0,0 +1,86 @@ +/***************************************************************************** + * Copyright (c) 2016 Christian W. Damus and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Christian W. Damus - Initial API and implementation + * + *****************************************************************************/ + +package org.eclipse.papyrus.infra.core.sasheditor.contentprovider; + +import java.util.Objects; +import java.util.function.Consumer; + +import org.eclipse.jface.viewers.ILabelProvider; +import org.eclipse.jface.viewers.ILabelProviderListener; +import org.eclipse.swt.graphics.Image; + +/** + * Partial implementation of the {@link IPageModel} protocol. + * + * @since 2.0 + */ +public abstract class AbstractPageModel implements IPageModel { + + private ILabelProvider tabLabelProvider; + private Consumer onLabelChanged = this::noop; + + private final ILabelProviderListener labelListener = event -> { + if (event.getElement() == getRawModel()) { + onLabelChanged.accept(getTabTitle()); + } + }; + + /** + * Initializes me with the label provider to use to render tabs. + * + * @param tabLabelProvider + * a label provider accepting my {@linkplain IPageModel#getRawModel() model}. + * This label provider should not be shared with other clients; I will dispose it when I am {@linkplain #dispose() disposed} + * + * @throws NullPointerException + * if the {@code tabLabelProvider} is {@code null} + */ + public AbstractPageModel(ILabelProvider tabLabelProvider) { + super(); + + this.tabLabelProvider = Objects.requireNonNull(tabLabelProvider, "null tabLabelProvider"); //$NON-NLS-1$ + tabLabelProvider.addListener(labelListener); + } + + /** + * I remove listener from my label provider. + */ + @Override + public void dispose() { + tabLabelProvider.removeListener(labelListener); + tabLabelProvider.dispose(); + } + + protected ILabelProvider getTabLabelProvider() { + return tabLabelProvider; + } + + @Override + public String getTabTitle() { + return tabLabelProvider.getText(getRawModel()); + } + + @Override + public Image getTabIcon() { + return tabLabelProvider.getImage(getRawModel()); + } + + public void onLabelChanged(Consumer handler) { + onLabelChanged = onLabelChanged.andThen(handler); + } + + private void noop(String label) { + // Pass + } +} diff --git a/plugins/infra/core/org.eclipse.papyrus.infra.core.sasheditor/src/org/eclipse/papyrus/infra/core/sasheditor/internal/EditorPart.java b/plugins/infra/core/org.eclipse.papyrus.infra.core.sasheditor/src/org/eclipse/papyrus/infra/core/sasheditor/internal/EditorPart.java index 1abf8c91d38..695848cec83 100644 --- a/plugins/infra/core/org.eclipse.papyrus.infra.core.sasheditor/src/org/eclipse/papyrus/infra/core/sasheditor/internal/EditorPart.java +++ b/plugins/infra/core/org.eclipse.papyrus.infra.core.sasheditor/src/org/eclipse/papyrus/infra/core/sasheditor/internal/EditorPart.java @@ -1,750 +1,754 @@ -/***************************************************************************** - * Copyright (c) 2009, 2015 CEA LIST & LIFL, Christian W. Damus, and others - * - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation - * Christian W. Damus - bug 469188 - * - *****************************************************************************/ -package org.eclipse.papyrus.infra.core.sasheditor.internal; - -import java.io.PrintWriter; -import java.io.StringWriter; - -import org.eclipse.core.runtime.ISafeRunnable; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.SafeRunner; -import org.eclipse.core.runtime.Status; -import org.eclipse.jface.window.Window; -import org.eclipse.papyrus.infra.core.sasheditor.Activator; -import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.IEditorModel; -import org.eclipse.papyrus.infra.core.sasheditor.editor.IEditorPage; -import org.eclipse.papyrus.infra.core.sasheditor.internal.eclipsecopy.IMultiPageEditorSite; -import org.eclipse.papyrus.infra.core.sasheditor.internal.eclipsecopy.MultiPageEditorSite; -import org.eclipse.papyrus.infra.tools.util.PlatformHelper; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.DisposeEvent; -import org.eclipse.swt.events.DisposeListener; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.layout.FillLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Event; -import org.eclipse.swt.widgets.Listener; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.IEditorPart; -import org.eclipse.ui.IEditorSite; -import org.eclipse.ui.IPropertyListener; -import org.eclipse.ui.IWorkbenchPart; -import org.eclipse.ui.IWorkbenchPartSite; -import org.eclipse.ui.PartInitException; -import org.eclipse.ui.internal.ErrorEditorPart; -import org.eclipse.ui.internal.dnd.IDropTarget; -import org.eclipse.ui.internal.misc.StatusUtil; -import org.eclipse.ui.part.EditorActionBarContributor; -import org.eclipse.ui.part.IWorkbenchPartOrientation; - - -/** - * This is a controler/part for an Editor. It is associated to a {@link IEditorModel}. - * This Part encapsulate an Eclipse Editor implementing {@link IEditorPart}. - * - * @author dumoulin - * @author Thomas SZADEL Improve the error text (avoid NPE) - */ -@SuppressWarnings("restriction") -public class EditorPart extends PagePart implements IEditorPage { - - /** - * The model representing the editor. - */ - private IEditorModel editorModel; - - /** - * The created Eclipse editor. - */ - private IEditorPart editorPart; - - /** - * The SWT Control containning the editor's controls. - */ - private Composite editorControl; - - /** - * The MultiPageContainer system. This is the manager of all tiles. - */ - // private SashWindowsContainer tilesContainer; - - /** - * The manager used to access main editor properties like site, actionbars, ... - */ - private IMultiEditorManager multiEditorManager; - - /** - * Parent owning this PagePart. - * Can be null if the Part is orphaned. Even if it is orphaned, the Item still set. - */ - // protected TabFolderPart parent; - - /** - * Listen on mouse enter event. - * Try to get an event indicating that the mouse enter over the editor. - * This can be used to switch the active editor. - * TODO This doesn't work yet. - */ - private Listener mouseEnterListener = new Listener() { - - /** - * (non-Javadoc) - * - * @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event) - */ - @Override - public void handleEvent(Event event) { - // Point globalPos = new Point(event.x, event.y); - // System.out.println(this.getClass().getSimpleName() + ".handleEvent(" + eventName(event.type) + ", " + globalPos + ")"); - } - }; - - /** - * Listener on widget disposed event. When the widget is disposed, the associated IEditor dispose() - * method is called. - * - */ - private DisposeListener widgetDisposedListener = new DisposeListener() { - - /** - * @see org.eclipse.swt.events.DisposeListener#widgetDisposed(org.eclipse.swt.events.DisposeEvent) - * @see SashWindowsContainer#dispose() - * @param e - */ - @Override - public void widgetDisposed(DisposeEvent e) { - // We dispose the associated editor. - disposeEditorPart(); - } - }; - - // To be removed - // private String eventName(int eventType) { - // switch(eventType) { - // case SWT.MouseEnter: - // return "MouseEnter"; - // case SWT.MouseDown: - // return "MouseDown"; - // case SWT.MouseExit: - // return "MouseExit"; - // case SWT.MouseHover: - // return "MouseHover"; - // case SWT.FocusIn: - // return "FocusIn"; - // case SWT.FocusOut: - // return "FocusOut"; - // case SWT.MouseMove: - // return "MouseMove"; - // case SWT.MouseUp: - // return "MouseUp"; - // case SWT.Activate: - // return "Activate"; - // default: - // return Integer.toString(eventType); - // } - // } - - /** - * Constructor. - * - * @param editorModel - * The model of the editor. - */ - public EditorPart(TabFolderPart parent, IEditorModel editorModel, Object rawModel, IMultiEditorManager multiEditorManager) { - super(parent, rawModel); - this.editorModel = editorModel; - this.multiEditorManager = multiEditorManager; - } - - @Override - public T getAdapter(Class adapter) { - return PlatformHelper.getAdapter(editorPart, adapter, ()// - -> PlatformHelper.getAdapter(editorModel, adapter, ()// - -> super.getAdapter(adapter))); - } - - /** - * Create the control of this Part, and children's controls. - * - * @param parent - * The SWT parent of this EditorPart. This is usually the {@link TabFolderPart}'s control. - */ - @Override - public void createPartControl(Composite parent) { - - try { - // Create the editor. - editorPart = createIEditorPart(); - // Initialize it and create its controls. - editorControl = createEditorPartControl(parent, editorPart); - attachListeners(editorControl, true); - } catch (PartInitException e) { - Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getLocalizedMessage(), e)); - // TODO Create a fake Error Page and initialize this part with. - // editorPart = new ErrorEditorPart(); - // editorControl = createEditorPartControl(parent, editorPart); - // editorControl = createErrorPartControl(parent, e); - createErrorEditorPart(parent, e); - } catch (Exception e) { - Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getLocalizedMessage(), e)); - // TODO Create a fake Error Page and initialize this part with. - // editorControl = createErrorPartControl(parent, e); - createErrorEditorPart(parent, e); - } - } - - /** - * Create a Control showing the error. - * - * @param parent - * Parent Control to which the Created Control should be attached - * @param e - * Exception containing the error. - */ - private Composite createErrorPartControl(Composite parent, Exception e) { - - Composite comp = new Composite(parent, SWT.NONE); - comp.setLayout(new FillLayout()); - // Show the stack trace - StringWriter strOut = new StringWriter(); - PrintWriter out = new PrintWriter(strOut); - e.printStackTrace(out); - out.flush(); - out.close(); - - Text diag = new Text(comp, SWT.MULTI); - diag.setSize(64, 32); - - diag.setText(strOut.toString()); - return comp; - } - - /** - * Create an EditorPart showing the Exception. - * This is used when the creation of the regular IEditorPart failed. - * - * @param e - */ - private void createErrorEditorPart(Composite parent, Exception e) { - - try { - PartInitException partInitException = new PartInitException(StatusUtil.getLocalizedMessage(e), StatusUtil.getCause(e)); - editorPart = new ErrorEditorPart(partInitException.getStatus()); - // Initialize it and create its controls. - editorControl = createEditorPartControl(parent, editorPart); - - } catch (Exception ex) { - // Even the ErrorEditorPart creation fail. - // Use a more simple renderer. - Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getLocalizedMessage(), e)); - // TODO Create a fake Error Page and initialize this part with. - editorControl = createErrorPartControl(parent, e); - } - - } - - /** - * Create the editor associated to this TabPart. - * - * @return - * @throws PartInitException - */ - private IEditorPart createIEditorPart() throws PartInitException { - - return editorModel.createIEditorPart(); - } - - /** - * Create the controls required by the editor. - * Init the editor. - * - * @param viewer - * @param editorInput - * @param model - * @return - * @throws PartInitException - */ - private Composite createEditorPartControl(Composite parentControl, IEditorPart editor) throws PartInitException { - IEditorSite site = createSite(editor); - // call init first so that if an exception is thrown, we have created no - // new widgets - editor.init(site, getIMultiEditorManager().getEditorInput()); - Composite editorParent = new Composite(parentControl, getOrientation(editor)); - editorParent.setLayout(new FillLayout()); - // Listen to dispose event - editorParent.addDisposeListener(widgetDisposedListener); - // Create editor controls - editor.createPartControl(editorParent); - editor.addPropertyListener(new IPropertyListener() { - - @Override - public void propertyChanged(Object source, int propertyId) { - EditorPart.this.handlePropertyChange(propertyId); - } - }); - - // TODO test to be removed - // attachListeners(editorParent, false); - return editorParent; - } - - /** - * Attach SWT listeners. - */ - private void attachListeners(Control theControl, boolean recursive) { - - // All following methods listen to the same event. - // So use only one of them - // theControl.addListener(SWT.MouseEnter, mouseEnterListener); - // - // theControl.addListener(SWT.FocusIn, mouseEnterListener); - // theControl.addListener(SWT.MouseMove, mouseEnterListener); - // theControl.addListener(SWT.MouseHover, mouseEnterListener); - // theControl.addListener(SWT.MouseUp, mouseEnterListener); - // theControl.addListener(SWT.MouseDown, mouseEnterListener); - theControl.addListener(SWT.Activate, mouseEnterListener); - - // if (recursive && theControl instanceof Composite) { - // Composite composite = (Composite) theControl; - // Control[] children = composite.getChildren(); - // - // for (int i = 0; i < children.length; i++) { - // Control control = children[i]; - // - // attachListeners(control, true); - // } - // } - } - - /** - * Detach SWT listeners - */ - private void detachListeners(Control theControl, boolean recursive) { - // theControl.removeListener(SWT.MouseEnter, mouseEnterListener); - // theControl.removeListener(SWT.FocusIn, mouseEnterListener); - // theControl.removeListener(SWT.MouseMove, mouseEnterListener); - // theControl.removeListener(SWT.MouseHover, mouseEnterListener); - // theControl.removeListener(SWT.MouseUp, mouseEnterListener); - // theControl.removeListener(SWT.MouseDown, mouseEnterListener); - theControl.removeListener(SWT.Activate, mouseEnterListener); - - // if (recursive && theControl instanceof Composite) { - // Composite composite = (Composite) theControl; - // Control[] children = composite.getChildren(); - // - // for (int i = 0; i < children.length; i++) { - // Control control = children[i]; - // - // detachListeners(control, false); - // } - // } - } - - - /** - * Handles a property change notification from a nested editor. The default implementation simply forwards - * the change to listeners on this multi-page editor by calling firePropertyChange with the same property id. For example, if the - * dirty state of a nested - * editor changes (property id IEditorPart.PROP_DIRTY), this method handles it - * by firing a property change event for IEditorPart.PROP_DIRTY to property listeners on this - * multi-page editor. - *

- * Subclasses may extend or reimplement this method. - *

- * - * @param propertyId - * the id of the property that changed - */ - private void handlePropertyChange(int propertyId) { - // cedric : old fashion, deprecated ? - getSashWindowContainer().firePropertyChange(propertyId); - // relay the event to the page lifecycle event notifier - getSashWindowContainer().getLifeCycleEventProvider().firePageFirePropertyChangeEvent(this, propertyId); - } - - /** - * Creates the site for the given nested editor. The MultiPageEditorPart implementation - * of this method creates an instance of MultiPageEditorSite. Subclasses may - * reimplement to create more specialized sites. - * - * @param editor - * the nested editor - * @return the editor site - */ - protected IEditorSite createSite(IEditorPart editor) { - EditorActionBarContributor contributor = createEditorActionBarContributor(); - - return new MultiPageEditorSite(multiEditorManager.getEditorSite(), editor, contributor); - } - - /** - * Create the EditorActionBarContributor requested by the editor. - * Creation is done by delegating to the IMultiEditorNestedPartManager. - * - * @return - */ - private EditorActionBarContributor createEditorActionBarContributor() { - EditorActionBarContributor contributor = editorModel.getActionBarContributor(); - return contributor; - } - - /** - * Get the orientation of the editor. - * - * @param editor - * @return int the orientation flag - * @see SWT#RIGHT_TO_LEFT - * @see SWT#LEFT_TO_RIGHT - * @see SWT#NONE - */ - private int getOrientation(IEditorPart editor) { - if (editor instanceof IWorkbenchPartOrientation) { - return ((IWorkbenchPartOrientation) editor).getOrientation(); - } - return Window.getDefaultOrientation(); - } - - /** - * Get the nested part manager. - * - * @return - */ - private IMultiEditorManager getIMultiEditorManager() { - return multiEditorManager; - } - - - /** - * /** - * Dispose all resources used by this part.
- * The Part should not be used after it has been disposed. - */ - @Override - public void dispose() { - - detachListeners(editorControl, true); - // dispose the SWT root control - // This should also trigger the disposal of associated editor. - editorControl.dispose(); - // Dispose the editor. - // disposeEditorPart(); - - // clean up properties to help GC - editorModel = null; - // editorPart = null; - rawModel = null; - } - - /** - * Dispose this part and all its children. - * The method is called recursively on children of the part.
- * SWT resources have already been disposed. We don't need to dispose them again. - * - */ - @Override - public void disposeThisAndChildren() { - - // Dispose the editor (normally this should be already done). - disposeEditorPart(); - - // clean up properties to help GC - editorModel = null; - // editorPart = null; - rawModel = null; - } - - - /** - * Disposes the associated editor and its site. - * Do not dispose it twice. - * - * @param part - * The part to dispose; must not be null. - * @copy copied from org.eclipse.ui.part.MultiPageEditorPart.disposePart(IWorkbenchPart) v3.8 - */ - private void disposeEditorPart() { - - // Is the editor already disposed ? - if (editorPart == null) { - return; - } - - final IWorkbenchPart part = editorPart; - editorPart = null; - - SafeRunner.run(new ISafeRunnable() { - - @Override - public void run() { - IWorkbenchPartSite partSite = part.getSite(); - part.dispose(); - if (partSite instanceof IMultiPageEditorSite) { - ((IMultiPageEditorSite) partSite).dispose(); - } - } - - @Override - public void handleException(Throwable e) { - // Exception has already being logged by Core. Do nothing. - } - }); - } - - - /** - * As we are a final Tile, we should be the requested part. - * Return this TilePart. - * - * @param toFind - * @return - */ - public PagePart findPart(Point toFind) { - return this; - } - - /** - * Locates the part that intersects the given point and that have the expected type - * - * @param toFind - * @return - */ - @Override - public PagePart findPartAt(Point toFind, Class expectedTileType) { - - if (expectedTileType == this.getClass()) { - return this; - } - - // Not found !! - // The tile contains the position, but the type is not found. - throw new UnsupportedOperationException("Tile match the expected position '" + toFind + "' but there is no Tile of requested type '" + expectedTileType.getClass().getName() + "'"); - } - - /** - * @param control - * @return - */ - public PagePart findPart(Object control) { - if (getControl() == control) { - return this; - } - - // Not found - return null; - } - - /** - * Returns the active nested editor if there is one. - *

- * Subclasses should not override this method - *

- * - * @return the active nested editor, or null if none - */ - @Override - public IEditorPart getIEditorPart() { - return editorPart; - } - - /** - * Get associated SWT Control. - * - * @return - */ - @Override - public Composite getControl() { - return editorControl; - } - - - /** - * This is a container method. Not necessary in Leaf Tile. - * TODO: change the interface. - * - * @param draggedObject - * @param position - * @return - */ - public IDropTarget getDropTarget(Object draggedObject, TabFolderPart sourcePart, Point position) { - return null; - } - - - /** - * @return - */ - @Override - public GarbageState getGarbageState() { - return garbageState; - } - - - /** - * Is the associated editor dirty ? - * Delegate to {@link IEditorPart.isDirty()} - * - * @return true if the associated editor is dirty. - * - * @unused - */ - public boolean isDirty() { - return editorPart.isDirty(); - } - - - - /** - * Change the parent of the Tile. The parent is changed, and the control is - * attached to the parent control. Change garbage state to {@link GarbageState.REPARENTED}. - * Do not detach the Tile from its old parent. - * - * @param newParent - * The tilePart that should be used as part parent. - * @param compositeParent - * The composite that should be used as parent. - */ - @Override - public void reparent(TabFolderPart newParent) { - - // Change the tile parent - this.parent = newParent; - // Change the SWT parent. - editorControl.setParent(newParent.getControl()); - - // Change state - if (garbageState == GarbageState.UNVISITED || garbageState == GarbageState.ORPHANED || garbageState == GarbageState.CREATED) { - garbageState = GarbageState.REPARENTED; - } else { - // Bad state, this is an internal error - // TODO : log a warning ? - throw new IllegalStateException("Try to change state from " + garbageState.toString() + " to REPARENTED. This is forbidden."); - } - - } - - - /** - * Asks this part to take focus within the workbench. - * Set the focus on the active nested part if the part is a container. - */ - @Override - public void setFocus() { - if (editorPart != null) { - try { - editorPart.setFocus(); - } catch (Exception ex) { - Activator.log.error(ex); - } - } - } - - - /** - * Synchronize the Part, and its children. PartMap contains a snapshot of the available part before - * the synchronization. After synchronization, unreachable parts should be marked "orphaned" (= no - * parent). - * Do nothing in this implementation, as we are a final leaf, and there is nothing to synchronize - * with the underlying model. - * - * @param partMap - */ - public void synchronize2(PartLists partMap) { - - } - - - /** - * Garbage this part. - * This part will be not used anymore. - * The part is already marked as ORPHANED. It is not used anymore. It is already detached - * from its parent.
- * This method is called by the sashwindows garbage mechanism after the Part has been marked as ORPHANED. - * All resources associated to this part can be disposed. - * - */ - @Override - public void garbage() { - dispose(); - // fire appropriate life cycle event - getSashWindowContainer().getLifeCycleEventProvider().firePageClosedEvent(this); - } - - - /** - * Accept the provided visitor. - * Call the corresponding accept method in the visitor. - * - * @param visitor - * @return - */ - @Override - public boolean visit(IPartVisitor visitor) { - return visitor.accept(this); - } - - /** - * Visit the children of this Tile. - * There is no child, so do nothing. - * - * @param visitor - */ - public boolean visitChildren(IPartVisitor visitor) { - return true; - } - - - /** - * Show item status. - */ - protected void showStatus() { - // System.out.println( "EditorTile: " - // + " disposed=" + editorControl.isDisposed() - // + ", visible=" + editorControl.isVisible() - // + ", garbState=" + garbageState - // + ", '" + editorPart.getTitle() - // + "', " + this); - String title = (editorPart != null ? editorPart.getTitle() : "no editorPart"); - System.out.printf("EditorTile: disposed=%-5b, visible=%-5b, garbState=%-10s, %s, %s\n", editorControl.isDisposed(), (editorControl.isDisposed() ? false : editorControl.isVisible()), garbageState, title, this); - - } - - /** - * Get the title for this part. {@inheritDoc} - */ - @Override - public String getPageTitle() { - try { - return editorModel.getTabTitle(); - } catch (Exception ex) { - Activator.log.error(ex); - return "Error"; - } - } - - /** - * Return an icon for this part. {@inheritDoc} - */ - @Override - public Image getPageIcon() { - try { - return editorModel.getTabIcon(); - } catch (Exception ex) { - Activator.log.error(ex); - return null; - } - } -} +/***************************************************************************** + * Copyright (c) 2009, 2016 CEA LIST, LIFL, Christian W. Damus, and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation + * Christian W. Damus - bugs 469188, 474467 + * + *****************************************************************************/ +package org.eclipse.papyrus.infra.core.sasheditor.internal; + +import java.io.PrintWriter; +import java.io.StringWriter; + +import org.eclipse.core.runtime.ISafeRunnable; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.SafeRunner; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.window.Window; +import org.eclipse.papyrus.infra.core.sasheditor.Activator; +import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.AbstractPageModel; +import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.IEditorModel; +import org.eclipse.papyrus.infra.core.sasheditor.editor.IEditorPage; +import org.eclipse.papyrus.infra.core.sasheditor.internal.eclipsecopy.IMultiPageEditorSite; +import org.eclipse.papyrus.infra.core.sasheditor.internal.eclipsecopy.MultiPageEditorSite; +import org.eclipse.papyrus.infra.tools.util.PlatformHelper; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IEditorSite; +import org.eclipse.ui.IPropertyListener; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.IWorkbenchPartSite; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.internal.ErrorEditorPart; +import org.eclipse.ui.internal.dnd.IDropTarget; +import org.eclipse.ui.internal.misc.StatusUtil; +import org.eclipse.ui.part.EditorActionBarContributor; +import org.eclipse.ui.part.IWorkbenchPartOrientation; + + +/** + * This is a controler/part for an Editor. It is associated to a {@link IEditorModel}. + * This Part encapsulate an Eclipse Editor implementing {@link IEditorPart}. + * + * @author dumoulin + * @author Thomas SZADEL Improve the error text (avoid NPE) + */ +@SuppressWarnings("restriction") +public class EditorPart extends PagePart implements IEditorPage { + + /** + * The model representing the editor. + */ + private IEditorModel editorModel; + + /** + * The created Eclipse editor. + */ + private IEditorPart editorPart; + + /** + * The SWT Control containning the editor's controls. + */ + private Composite editorControl; + + /** + * The MultiPageContainer system. This is the manager of all tiles. + */ + // private SashWindowsContainer tilesContainer; + + /** + * The manager used to access main editor properties like site, actionbars, ... + */ + private IMultiEditorManager multiEditorManager; + + /** + * Parent owning this PagePart. + * Can be null if the Part is orphaned. Even if it is orphaned, the Item still set. + */ + // protected TabFolderPart parent; + + /** + * Listen on mouse enter event. + * Try to get an event indicating that the mouse enter over the editor. + * This can be used to switch the active editor. + * TODO This doesn't work yet. + */ + private Listener mouseEnterListener = new Listener() { + + /** + * (non-Javadoc) + * + * @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event) + */ + @Override + public void handleEvent(Event event) { + // Point globalPos = new Point(event.x, event.y); + // System.out.println(this.getClass().getSimpleName() + ".handleEvent(" + eventName(event.type) + ", " + globalPos + ")"); + } + }; + + /** + * Listener on widget disposed event. When the widget is disposed, the associated IEditor dispose() + * method is called. + * + */ + private DisposeListener widgetDisposedListener = new DisposeListener() { + + /** + * @see org.eclipse.swt.events.DisposeListener#widgetDisposed(org.eclipse.swt.events.DisposeEvent) + * @see SashWindowsContainer#dispose() + * @param e + */ + @Override + public void widgetDisposed(DisposeEvent e) { + // We dispose the associated editor. + disposeEditorPart(); + } + }; + + // To be removed + // private String eventName(int eventType) { + // switch(eventType) { + // case SWT.MouseEnter: + // return "MouseEnter"; + // case SWT.MouseDown: + // return "MouseDown"; + // case SWT.MouseExit: + // return "MouseExit"; + // case SWT.MouseHover: + // return "MouseHover"; + // case SWT.FocusIn: + // return "FocusIn"; + // case SWT.FocusOut: + // return "FocusOut"; + // case SWT.MouseMove: + // return "MouseMove"; + // case SWT.MouseUp: + // return "MouseUp"; + // case SWT.Activate: + // return "Activate"; + // default: + // return Integer.toString(eventType); + // } + // } + + /** + * Constructor. + * + * @param editorModel + * The model of the editor. + */ + public EditorPart(TabFolderPart parent, IEditorModel editorModel, Object rawModel, IMultiEditorManager multiEditorManager) { + super(parent, rawModel); + this.editorModel = editorModel; + this.multiEditorManager = multiEditorManager; + + if (editorModel instanceof AbstractPageModel) { + ((AbstractPageModel) editorModel).onLabelChanged(label -> refreshTab()); + } + } + + @Override + public T getAdapter(Class adapter) { + return PlatformHelper.getAdapter(editorPart, adapter, ()// + -> PlatformHelper.getAdapter(editorModel, adapter, ()// + -> super.getAdapter(adapter))); + } + + /** + * Create the control of this Part, and children's controls. + * + * @param parent + * The SWT parent of this EditorPart. This is usually the {@link TabFolderPart}'s control. + */ + @Override + public void createPartControl(Composite parent) { + + try { + // Create the editor. + editorPart = createIEditorPart(); + // Initialize it and create its controls. + editorControl = createEditorPartControl(parent, editorPart); + attachListeners(editorControl, true); + } catch (PartInitException e) { + Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getLocalizedMessage(), e)); + // TODO Create a fake Error Page and initialize this part with. + // editorPart = new ErrorEditorPart(); + // editorControl = createEditorPartControl(parent, editorPart); + // editorControl = createErrorPartControl(parent, e); + createErrorEditorPart(parent, e); + } catch (Exception e) { + Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getLocalizedMessage(), e)); + // TODO Create a fake Error Page and initialize this part with. + // editorControl = createErrorPartControl(parent, e); + createErrorEditorPart(parent, e); + } + } + + /** + * Create a Control showing the error. + * + * @param parent + * Parent Control to which the Created Control should be attached + * @param e + * Exception containing the error. + */ + private Composite createErrorPartControl(Composite parent, Exception e) { + + Composite comp = new Composite(parent, SWT.NONE); + comp.setLayout(new FillLayout()); + // Show the stack trace + StringWriter strOut = new StringWriter(); + PrintWriter out = new PrintWriter(strOut); + e.printStackTrace(out); + out.flush(); + out.close(); + + Text diag = new Text(comp, SWT.MULTI); + diag.setSize(64, 32); + + diag.setText(strOut.toString()); + return comp; + } + + /** + * Create an EditorPart showing the Exception. + * This is used when the creation of the regular IEditorPart failed. + * + * @param e + */ + private void createErrorEditorPart(Composite parent, Exception e) { + + try { + PartInitException partInitException = new PartInitException(StatusUtil.getLocalizedMessage(e), StatusUtil.getCause(e)); + editorPart = new ErrorEditorPart(partInitException.getStatus()); + // Initialize it and create its controls. + editorControl = createEditorPartControl(parent, editorPart); + + } catch (Exception ex) { + // Even the ErrorEditorPart creation fail. + // Use a more simple renderer. + Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getLocalizedMessage(), e)); + // TODO Create a fake Error Page and initialize this part with. + editorControl = createErrorPartControl(parent, e); + } + + } + + /** + * Create the editor associated to this TabPart. + * + * @return + * @throws PartInitException + */ + private IEditorPart createIEditorPart() throws PartInitException { + + return editorModel.createIEditorPart(); + } + + /** + * Create the controls required by the editor. + * Init the editor. + * + * @param viewer + * @param editorInput + * @param model + * @return + * @throws PartInitException + */ + private Composite createEditorPartControl(Composite parentControl, IEditorPart editor) throws PartInitException { + IEditorSite site = createSite(editor); + // call init first so that if an exception is thrown, we have created no + // new widgets + editor.init(site, getIMultiEditorManager().getEditorInput()); + Composite editorParent = new Composite(parentControl, getOrientation(editor)); + editorParent.setLayout(new FillLayout()); + // Listen to dispose event + editorParent.addDisposeListener(widgetDisposedListener); + // Create editor controls + editor.createPartControl(editorParent); + editor.addPropertyListener(new IPropertyListener() { + + @Override + public void propertyChanged(Object source, int propertyId) { + EditorPart.this.handlePropertyChange(propertyId); + } + }); + + // TODO test to be removed + // attachListeners(editorParent, false); + return editorParent; + } + + /** + * Attach SWT listeners. + */ + private void attachListeners(Control theControl, boolean recursive) { + + // All following methods listen to the same event. + // So use only one of them + // theControl.addListener(SWT.MouseEnter, mouseEnterListener); + // + // theControl.addListener(SWT.FocusIn, mouseEnterListener); + // theControl.addListener(SWT.MouseMove, mouseEnterListener); + // theControl.addListener(SWT.MouseHover, mouseEnterListener); + // theControl.addListener(SWT.MouseUp, mouseEnterListener); + // theControl.addListener(SWT.MouseDown, mouseEnterListener); + theControl.addListener(SWT.Activate, mouseEnterListener); + + // if (recursive && theControl instanceof Composite) { + // Composite composite = (Composite) theControl; + // Control[] children = composite.getChildren(); + // + // for (int i = 0; i < children.length; i++) { + // Control control = children[i]; + // + // attachListeners(control, true); + // } + // } + } + + /** + * Detach SWT listeners + */ + private void detachListeners(Control theControl, boolean recursive) { + // theControl.removeListener(SWT.MouseEnter, mouseEnterListener); + // theControl.removeListener(SWT.FocusIn, mouseEnterListener); + // theControl.removeListener(SWT.MouseMove, mouseEnterListener); + // theControl.removeListener(SWT.MouseHover, mouseEnterListener); + // theControl.removeListener(SWT.MouseUp, mouseEnterListener); + // theControl.removeListener(SWT.MouseDown, mouseEnterListener); + theControl.removeListener(SWT.Activate, mouseEnterListener); + + // if (recursive && theControl instanceof Composite) { + // Composite composite = (Composite) theControl; + // Control[] children = composite.getChildren(); + // + // for (int i = 0; i < children.length; i++) { + // Control control = children[i]; + // + // detachListeners(control, false); + // } + // } + } + + + /** + * Handles a property change notification from a nested editor. The default implementation simply forwards + * the change to listeners on this multi-page editor by calling firePropertyChange with the same property id. For example, if the + * dirty state of a nested + * editor changes (property id IEditorPart.PROP_DIRTY), this method handles it + * by firing a property change event for IEditorPart.PROP_DIRTY to property listeners on this + * multi-page editor. + *

+ * Subclasses may extend or reimplement this method. + *

+ * + * @param propertyId + * the id of the property that changed + */ + private void handlePropertyChange(int propertyId) { + // cedric : old fashion, deprecated ? + getSashWindowContainer().firePropertyChange(propertyId); + // relay the event to the page lifecycle event notifier + getSashWindowContainer().getLifeCycleEventProvider().firePageFirePropertyChangeEvent(this, propertyId); + } + + /** + * Creates the site for the given nested editor. The MultiPageEditorPart implementation + * of this method creates an instance of MultiPageEditorSite. Subclasses may + * reimplement to create more specialized sites. + * + * @param editor + * the nested editor + * @return the editor site + */ + protected IEditorSite createSite(IEditorPart editor) { + EditorActionBarContributor contributor = createEditorActionBarContributor(); + + return new MultiPageEditorSite(multiEditorManager.getEditorSite(), editor, contributor); + } + + /** + * Create the EditorActionBarContributor requested by the editor. + * Creation is done by delegating to the IMultiEditorNestedPartManager. + * + * @return + */ + private EditorActionBarContributor createEditorActionBarContributor() { + EditorActionBarContributor contributor = editorModel.getActionBarContributor(); + return contributor; + } + + /** + * Get the orientation of the editor. + * + * @param editor + * @return int the orientation flag + * @see SWT#RIGHT_TO_LEFT + * @see SWT#LEFT_TO_RIGHT + * @see SWT#NONE + */ + private int getOrientation(IEditorPart editor) { + if (editor instanceof IWorkbenchPartOrientation) { + return ((IWorkbenchPartOrientation) editor).getOrientation(); + } + return Window.getDefaultOrientation(); + } + + /** + * Get the nested part manager. + * + * @return + */ + private IMultiEditorManager getIMultiEditorManager() { + return multiEditorManager; + } + + + /** + * /** + * Dispose all resources used by this part.
+ * The Part should not be used after it has been disposed. + */ + @Override + public void dispose() { + + detachListeners(editorControl, true); + // dispose the SWT root control + // This should also trigger the disposal of associated editor. + editorControl.dispose(); + // Dispose the editor. + // disposeEditorPart(); + + // clean up properties to help GC + editorModel = null; + // editorPart = null; + rawModel = null; + } + + /** + * Dispose this part and all its children. + * The method is called recursively on children of the part.
+ * SWT resources have already been disposed. We don't need to dispose them again. + * + */ + @Override + public void disposeThisAndChildren() { + + // Dispose the editor (normally this should be already done). + disposeEditorPart(); + + // clean up properties to help GC + editorModel = null; + // editorPart = null; + rawModel = null; + } + + + /** + * Disposes the associated editor and its site. + * Do not dispose it twice. + * + * @param part + * The part to dispose; must not be null. + * @copy copied from org.eclipse.ui.part.MultiPageEditorPart.disposePart(IWorkbenchPart) v3.8 + */ + private void disposeEditorPart() { + + // Is the editor already disposed ? + if (editorPart == null) { + return; + } + + final IWorkbenchPart part = editorPart; + editorPart = null; + + SafeRunner.run(new ISafeRunnable() { + + @Override + public void run() { + IWorkbenchPartSite partSite = part.getSite(); + part.dispose(); + if (partSite instanceof IMultiPageEditorSite) { + ((IMultiPageEditorSite) partSite).dispose(); + } + } + + @Override + public void handleException(Throwable e) { + // Exception has already being logged by Core. Do nothing. + } + }); + } + + + /** + * As we are a final Tile, we should be the requested part. + * Return this TilePart. + * + * @param toFind + * @return + */ + public PagePart findPart(Point toFind) { + return this; + } + + /** + * Locates the part that intersects the given point and that have the expected type + * + * @param toFind + * @return + */ + @Override + public PagePart findPartAt(Point toFind, Class expectedTileType) { + + if (expectedTileType == this.getClass()) { + return this; + } + + // Not found !! + // The tile contains the position, but the type is not found. + throw new UnsupportedOperationException("Tile match the expected position '" + toFind + "' but there is no Tile of requested type '" + expectedTileType.getClass().getName() + "'"); + } + + /** + * @param control + * @return + */ + public PagePart findPart(Object control) { + if (getControl() == control) { + return this; + } + + // Not found + return null; + } + + /** + * Returns the active nested editor if there is one. + *

+ * Subclasses should not override this method + *

+ * + * @return the active nested editor, or null if none + */ + @Override + public IEditorPart getIEditorPart() { + return editorPart; + } + + /** + * Get associated SWT Control. + * + * @return + */ + @Override + public Composite getControl() { + return editorControl; + } + + + /** + * This is a container method. Not necessary in Leaf Tile. + * TODO: change the interface. + * + * @param draggedObject + * @param position + * @return + */ + public IDropTarget getDropTarget(Object draggedObject, TabFolderPart sourcePart, Point position) { + return null; + } + + + /** + * @return + */ + @Override + public GarbageState getGarbageState() { + return garbageState; + } + + + /** + * Is the associated editor dirty ? + * Delegate to {@link IEditorPart.isDirty()} + * + * @return true if the associated editor is dirty. + * + * @unused + */ + public boolean isDirty() { + return editorPart.isDirty(); + } + + + + /** + * Change the parent of the Tile. The parent is changed, and the control is + * attached to the parent control. Change garbage state to {@link GarbageState.REPARENTED}. + * Do not detach the Tile from its old parent. + * + * @param newParent + * The tilePart that should be used as part parent. + * @param compositeParent + * The composite that should be used as parent. + */ + @Override + public void reparent(TabFolderPart newParent) { + + // Change the tile parent + this.parent = newParent; + // Change the SWT parent. + editorControl.setParent(newParent.getControl()); + + // Change state + if (garbageState == GarbageState.UNVISITED || garbageState == GarbageState.ORPHANED || garbageState == GarbageState.CREATED) { + garbageState = GarbageState.REPARENTED; + } else { + // Bad state, this is an internal error + // TODO : log a warning ? + throw new IllegalStateException("Try to change state from " + garbageState.toString() + " to REPARENTED. This is forbidden."); + } + + } + + + /** + * Asks this part to take focus within the workbench. + * Set the focus on the active nested part if the part is a container. + */ + @Override + public void setFocus() { + if (editorPart != null) { + try { + editorPart.setFocus(); + } catch (Exception ex) { + Activator.log.error(ex); + } + } + } + + + /** + * Synchronize the Part, and its children. PartMap contains a snapshot of the available part before + * the synchronization. After synchronization, unreachable parts should be marked "orphaned" (= no + * parent). + * Do nothing in this implementation, as we are a final leaf, and there is nothing to synchronize + * with the underlying model. + * + * @param partMap + */ + public void synchronize2(PartLists partMap) { + + } + + + /** + * Garbage this part. + * This part will be not used anymore. + * The part is already marked as ORPHANED. It is not used anymore. It is already detached + * from its parent.
+ * This method is called by the sashwindows garbage mechanism after the Part has been marked as ORPHANED. + * All resources associated to this part can be disposed. + * + */ + @Override + public void garbage() { + dispose(); + // fire appropriate life cycle event + getSashWindowContainer().getLifeCycleEventProvider().firePageClosedEvent(this); + } + + + /** + * Accept the provided visitor. + * Call the corresponding accept method in the visitor. + * + * @param visitor + * @return + */ + @Override + public boolean visit(IPartVisitor visitor) { + return visitor.accept(this); + } + + /** + * Visit the children of this Tile. + * There is no child, so do nothing. + * + * @param visitor + */ + public boolean visitChildren(IPartVisitor visitor) { + return true; + } + + + /** + * Show item status. + */ + protected void showStatus() { + // System.out.println( "EditorTile: " + // + " disposed=" + editorControl.isDisposed() + // + ", visible=" + editorControl.isVisible() + // + ", garbState=" + garbageState + // + ", '" + editorPart.getTitle() + // + "', " + this); + String title = (editorPart != null ? editorPart.getTitle() : "no editorPart"); + System.out.printf("EditorTile: disposed=%-5b, visible=%-5b, garbState=%-10s, %s, %s\n", editorControl.isDisposed(), (editorControl.isDisposed() ? false : editorControl.isVisible()), garbageState, title, this); + + } + + /** + * Get the title for this part. {@inheritDoc} + */ + @Override + public String getPageTitle() { + try { + return editorModel.getTabTitle(); + } catch (Exception ex) { + Activator.log.error(ex); + return "Error"; + } + } + + /** + * Return an icon for this part. {@inheritDoc} + */ + @Override + public Image getPageIcon() { + try { + return editorModel.getTabIcon(); + } catch (Exception ex) { + Activator.log.error(ex); + return null; + } + } +} diff --git a/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/utils/AbstractServiceUtils.java b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/utils/AbstractServiceUtils.java index 54fd40a134c..5176b8d88d2 100644 --- a/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/utils/AbstractServiceUtils.java +++ b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/utils/AbstractServiceUtils.java @@ -1,7 +1,6 @@ /***************************************************************************** * Copyright (c) 2010, 2016 LIFL, CEA LIST, Christian W. Damus, and others. * - * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -9,13 +8,14 @@ * * Contributors: * Cedric Dumoulin (LIFL) cedric.dumoulin@lifl.fr - Initial API and implementation - * Christian W. Damus - bug 468030 - * Christian W. Damus - bug 485220 + * Christian W. Damus - bugs 468030, 485220, 474467 * *****************************************************************************/ package org.eclipse.papyrus.infra.core.utils; +import java.util.Optional; + import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.emf.transaction.TransactionalEditingDomain; import org.eclipse.papyrus.infra.core.Activator; @@ -226,4 +226,45 @@ public abstract class AbstractServiceUtils { } }; } + + /** + * Attempts to obtain the service registry from the given context object. + * + * @param from + * the context object + * @return maybe the registry + * + * @since 2.0 + */ + protected Optional tryServiceRegistry(T from) { + try { + return Optional.ofNullable(getServiceRegistry(from)); + } catch (ServiceException e) { + Activator.log.error(e); + return Optional.empty(); + } + } + + /** + * Attempts to obtain the requested from the registry associated with + * the given context object. + * + * @param from + * the context object + * @param serviceType + * the type of service to obtain + * @return maybe the service + * + * @since 2.0 + */ + public Optional tryService(T from, Class serviceType) { + return tryServiceRegistry(from).map(services -> { + try { + return services.getService(serviceType); + } catch (ServiceException e) { + Activator.log.error(e); + return (S) null; + } + }); + } } diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.ui.emf/src/org/eclipse/papyrus/infra/ui/emf/providers/DependentEMFLabelProvider.java b/plugins/infra/emf/org.eclipse.papyrus.infra.ui.emf/src/org/eclipse/papyrus/infra/ui/emf/providers/DependentEMFLabelProvider.java new file mode 100644 index 00000000000..172c59496c0 --- /dev/null +++ b/plugins/infra/emf/org.eclipse.papyrus.infra.ui.emf/src/org/eclipse/papyrus/infra/ui/emf/providers/DependentEMFLabelProvider.java @@ -0,0 +1,161 @@ +/***************************************************************************** + * Copyright (c) 2016 Christian W. Damus and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Christian W. Damus - Initial API and implementation + * + *****************************************************************************/ + +package org.eclipse.papyrus.infra.ui.emf.providers; + +import java.util.Map; +import java.util.Set; +import java.util.WeakHashMap; +import java.util.concurrent.CopyOnWriteArrayList; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.jface.viewers.ILabelProviderListener; +import org.eclipse.jface.viewers.LabelProviderChangedEvent; + +import com.google.common.collect.MapMaker; +import com.google.common.collect.Sets; + +/** + * A specialized {@link EMFLabelProvider} for label providers that compute labels + * for objects from labels of objects on which they depend. For example, in a + * banking system, an account label may be something like "Fred's Chequing" + * in which the label depends on the label of the account holder. If the holder's + * name changes from "Fred" to something else, the account's label also must be + * recomputed. + */ +public class DependentEMFLabelProvider extends EMFLabelProvider { + + private SubscriptionListener subscriptionListener; + + private final CopyOnWriteArrayList listeners = new CopyOnWriteArrayList<>(); + + public DependentEMFLabelProvider() { + super(new ForwardingEMFLabelProvider()); + } + + @Override + public void dispose() { + if (subscriptionListener != null) { + subscriptionListener.dispose(); + } + + super.dispose(); + } + + /** + * Subscribe to label changes of the given {@code object} to notify that its + * {@code dependent}'s label accordingly changes. + * + * @param object + * an object to listen to + * @param dependent + * an object that depends on its labels + */ + protected void subscribe(EObject object, EObject dependent) { + if (baseEMFLabelProvider instanceof ForwardingEMFLabelProvider) { + SubscriptionListener subs = getSubscriptionListener(); + subs.add(object, dependent); + } + } + + /** + * Unsubscribe from label changes of the given {@code object} because the + * {@link dependent}'s labels no longer depend on it. + * + * @param object + * an object to listen to + * @param dependent + * an object that no longer depends on its labels + */ + protected void unsubscribe(EObject object, EObject dependent) { + // If we didn't create the listener, yet, then it can't be attached to anything + if (subscriptionListener != null) { + subscriptionListener.remove(object, dependent); + } + } + + private SubscriptionListener getSubscriptionListener() { + if (subscriptionListener == null) { + subscriptionListener = new SubscriptionListener(); + ((ForwardingEMFLabelProvider) baseEMFLabelProvider).addListener(subscriptionListener); + } + + return subscriptionListener; + } + + @Override + public void addListener(ILabelProviderListener listener) { + super.addListener(listener); + listeners.addIfAbsent(listener); + } + + @Override + public void removeListener(ILabelProviderListener listener) { + listeners.remove(listener); + super.removeListener(listener); + } + + protected void fireLabelProviderChange(Object object) { + if (!listeners.isEmpty()) { + LabelProviderChangedEvent event = new LabelProviderChangedEvent(this, object); + listeners.forEach(l -> l.labelProviderChanged(event)); + } + } + + // + // Nested types + // + + private class SubscriptionListener implements ILabelProviderListener { + private final Map> subscriptions = new MapMaker().weakKeys().makeMap(); + + @Override + public void labelProviderChanged(LabelProviderChangedEvent event) { + Set dependents = subscriptions.get(event.getElement()); + if (dependents != null) { + dependents.forEach(DependentEMFLabelProvider.this::fireLabelProviderChange); + } + } + + void add(EObject subscription, EObject dependent) { + subscriptions.computeIfAbsent(subscription, x -> Sets.newSetFromMap(new WeakHashMap<>())) + .add(dependent); + } + + void remove(EObject subscription, EObject dependent) { + Set dependents = subscriptions.get(subscription); + if (dependents != null) { + dependents.remove(dependent); + if (dependents.isEmpty()) { + subscriptions.remove(subscription); + } + if (subscriptions.isEmpty()) { + this.dispose(); + } + } + } + + void dispose() { + if (baseEMFLabelProvider instanceof ForwardingEMFLabelProvider) { + ((ForwardingEMFLabelProvider) baseEMFLabelProvider).removeListener(this); + } + + subscriptions.clear(); + + if (subscriptionListener == this) { + subscriptionListener = null; + } + } + } + +} diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.ui.emf/src/org/eclipse/papyrus/infra/ui/emf/providers/EMFLabelProvider.java b/plugins/infra/emf/org.eclipse.papyrus.infra.ui.emf/src/org/eclipse/papyrus/infra/ui/emf/providers/EMFLabelProvider.java index 20e055e6a78..0a970d1c29c 100644 --- a/plugins/infra/emf/org.eclipse.papyrus.infra.ui.emf/src/org/eclipse/papyrus/infra/ui/emf/providers/EMFLabelProvider.java +++ b/plugins/infra/emf/org.eclipse.papyrus.infra.ui.emf/src/org/eclipse/papyrus/infra/ui/emf/providers/EMFLabelProvider.java @@ -1,302 +1,346 @@ -/***************************************************************************** - * Copyright (c) 2011 CEA LIST. - * - * 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: - * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation - *****************************************************************************/ -package org.eclipse.papyrus.infra.ui.emf.providers; - -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.eclipse.emf.ecore.EClass; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.jface.viewers.ILabelProvider; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.papyrus.emf.facet.custom.metamodel.v0_2_0.internal.treeproxy.TreeElement; -import org.eclipse.papyrus.emf.facet.custom.ui.internal.DecoratingCustomizedLabelProvider; -import org.eclipse.papyrus.emf.facet.custom.ui.internal.ResolvingCustomizedLabelProvider; -import org.eclipse.papyrus.infra.emf.utils.EMFHelper; -import org.eclipse.papyrus.infra.services.labelprovider.service.IDetailLabelProvider; -import org.eclipse.papyrus.infra.services.labelprovider.service.IQualifierLabelProvider; -import org.eclipse.papyrus.infra.ui.internal.emf.Activator; -import org.eclipse.swt.graphics.Image; - -/** - * This class handles labels for EMF Objects - * The class can handle the following cases : - * - An EObject (Which can be resolved with {@link EMFHelper#getEObject(Object)}) - * - A IStructuredSelection containing EObject(s) - * - * @author Camille Letavernier - */ -public class EMFLabelProvider extends ResolvingCustomizedLabelProvider implements IDetailLabelProvider, IQualifierLabelProvider { - - protected ILabelProvider baseEMFLabelProvider; - - /** - * Creates a new EMFObjectLabelProvider. - */ - public EMFLabelProvider() { - super(new DecoratingCustomizedLabelProvider(Activator.getDefault().getCustomizationManager())); // Note: CustomizableModelLabelProvider doesn't use the CustomizationManager. It relies on the content provider's CustomizationManager - baseEMFLabelProvider = new StandardEMFLabelProvider(); - } - - /** - * {@inheritDoc} - */ - @Override - public String getText(Object element) { - if (element == null) { - return ""; //$NON-NLS-1$ - } - - if (element instanceof TreeElement) { - return super.getText(element); - } - - EObject eObject = EMFHelper.getEObject(element); - if (eObject != null) { - return getText(eObject); - } - - if (element instanceof IStructuredSelection) { - return getText((IStructuredSelection) element); - } - - return element.toString(); - } - - protected String getText(EObject element) { - return baseEMFLabelProvider.getText(element); - } - - protected String getText(IStructuredSelection selection) { - if (selection.isEmpty()) { - return ""; //$NON-NLS-1$ - } - - if (selection.size() == 1) { - return getText(selection.getFirstElement()); - } else { - final List selectionAsList = selection.toList(); - String str = ""; - for (int i = 0; i < selectionAsList.size(); i++) { - final String txt = getText(selectionAsList.get(i)); - if (txt != null) { - str += txt; - } - if (i < selectionAsList.size() - 1) { - str += ", "; - } - } - return str; - } - } - - /** - * {@inheritDoc} - */ - @Override - public Image getImage(Object element) { - if (element instanceof TreeElement) { - return super.getImage(element); - } - - EObject eObject = EMFHelper.getEObject(element); - if (eObject != null) { - return getImage(eObject); - } - - if (element instanceof IStructuredSelection) { - return getImage((IStructuredSelection) element); - } - - return null; - } - - protected Image getImage(EObject eObject) { - return baseEMFLabelProvider.getImage(eObject); - } - - protected Image getImage(IStructuredSelection selection) { - if (selection.isEmpty()) { - return null; - } else if (selection.size() == 1) { - return getImage(selection.getFirstElement()); - } - - final List selectionAsList = selection.toList(); - final Set selectedEObject = new HashSet(); - boolean isEObjectSelection = true; - for (final Object current : selectionAsList) { - final EObject obj = EMFHelper.getEObject(current); - if (obj != null) { - selectedEObject.add(obj); - } else { - isEObjectSelection = false; - } - } - - if (isEObjectSelection) {// all selected elements are EObject - if (selectedEObject.size() == 1 || hasCommonImage(selectedEObject)) { - return getImage(selectedEObject.toArray()[0]); - } else { - final EClass common = org.eclipse.papyrus.emf.facet.util.emf.core.internal.EMFUtils.computeLeastCommonSupertype(getEClasses(selectedEObject)); - if (!common.isAbstract()) { - // FIXME : the label provider service should manage this case - final Object instance = common.getEPackage().getEFactoryInstance().create(common); - return getNonCommonIcon(instance); - } - } - } else if (selectedEObject.size() == 0) { - // the multiple selection contains any EObject - } else { - // the selection contains EObject and others elements - } - return null; - } - - /** - * - * @param objects - * a collection of objects - * @return - * true if the image found for each object is the same false of if the collection is empty or the image returned - * for each object is not the same - */ - protected boolean hasCommonImage(final Collection objects) { - if (!objects.isEmpty()) { - final Image lastImage = getImage(objects.toArray()[0]); - for (final Object current : objects) { - if (lastImage != getImage(current)) { - return false; - } - } - } else { - return false; - } - return true; - } - - /** - * - * @param commonEClass - * the eClass - * @return - * the icon to use for this eclass - */ - protected Image getNonCommonIcon(final Object commonObject) { - return getImage(commonObject); - } - - /** - * - * @param objects - * a collection of eobject - * @return - * the set of eclasses for the parameter objects - */ - private Set getEClasses(final Collection objects) { - final Set eclasses = new HashSet(); - for (final EObject current : objects) { - eclasses.add(current.eClass()); - } - return eclasses; - } - - public String getDetail(Object object) { - object = EMFHelper.getEObject(object); - return getText(object) + " - " + getQualifiedClassName(object); //$NON-NLS-1$ - } - - /** - * Returns the qualified Class name of the given EObject, or an - * empty String if the object is not an EObject - * - * @param object - * @return The qualified name of this object's class, or an empty - * String if the object is not an EObject - */ - protected String getQualifiedClassName(Object object) { - if (object instanceof EObject) { - EObject eObject = (EObject) object; - EClass eClass = eObject.eClass(); - return EMFHelper.getQualifiedName(eClass, "::"); //$NON-NLS-1$ - } - return ""; //$NON-NLS-1$ - } - - - - public String getQualifierText(Object element) { - String result = null; - - EObject parent = getParentObject(element); - if (parent != null) { - result = getQualifiedText(parent); - } - - return result; - } - - private EObject getParentObject(Object element) { - EObject result = null; - - if (element != null) { - EObject eObject = EMFHelper.getEObject(element); - if (eObject != null) { - result = getParent(eObject); - } - } - - return result; - } - - public Image getQualifierImage(Object element) { - Image result = null; - - EObject parent = getParentObject(element); - if (parent != null) { - result = getImage(parent); - } - - return result; - } - - protected EObject getParent(EObject object) { - return object.eContainer(); - } - - protected String getQualifiedText(EObject object) { - StringBuilder result = new StringBuilder(); - - appendQualifiedText(object, result); - - return result.toString(); - } - - protected void appendQualifiedText(EObject object, StringBuilder buf) { - EObject parent = getParent(object); - if (parent != null) { - appendQualifiedText(parent, buf); - } - - if (buf.length() > 0) { - buf.append("::"); - } - - String name = getText(object); - if (name == null) { - name = String.format("<%s>", object.eClass().getName()); - } - buf.append(name); - } -} +/***************************************************************************** + * Copyright (c) 2011, 2016 CEA LIST, Christian W. Damus, and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation + * Christian W. Damus - bug 474467 + * + *****************************************************************************/ +package org.eclipse.papyrus.infra.ui.emf.providers; + +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider; +import org.eclipse.jface.viewers.ILabelProvider; +import org.eclipse.jface.viewers.ILabelProviderListener; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.papyrus.emf.facet.custom.metamodel.v0_2_0.internal.treeproxy.TreeElement; +import org.eclipse.papyrus.emf.facet.custom.ui.internal.DecoratingCustomizedLabelProvider; +import org.eclipse.papyrus.emf.facet.custom.ui.internal.ResolvingCustomizedLabelProvider; +import org.eclipse.papyrus.infra.emf.utils.EMFHelper; +import org.eclipse.papyrus.infra.services.labelprovider.service.IDetailLabelProvider; +import org.eclipse.papyrus.infra.services.labelprovider.service.IQualifierLabelProvider; +import org.eclipse.papyrus.infra.ui.internal.emf.Activator; +import org.eclipse.swt.graphics.Image; + +/** + * This class handles labels for EMF Objects + * The class can handle the following cases : + * - An EObject (Which can be resolved with {@link EMFHelper#getEObject(Object)}) + * - A IStructuredSelection containing EObject(s) + * + * @author Camille Letavernier + */ +public class EMFLabelProvider extends ResolvingCustomizedLabelProvider implements IDetailLabelProvider, IQualifierLabelProvider { + + protected ILabelProvider baseEMFLabelProvider; + + /** + * Creates a new EMFObjectLabelProvider. + */ + public EMFLabelProvider() { + this(new StandardEMFLabelProvider()); + } + + EMFLabelProvider(ILabelProvider baseEMFLabelProvider) { + // Note: CustomizableModelLabelProvider doesn't use the CustomizationManager. + // It relies on the content provider's CustomizationManager + super(new DecoratingCustomizedLabelProvider(Activator.getDefault().getCustomizationManager())); + this.baseEMFLabelProvider = baseEMFLabelProvider; + } + + @Override + public void dispose() { + baseEMFLabelProvider.dispose(); + + super.dispose(); + } + + /** + * {@inheritDoc} + */ + @Override + public String getText(Object element) { + if (element == null) { + return ""; //$NON-NLS-1$ + } + + if (element instanceof TreeElement) { + return super.getText(element); + } + + EObject eObject = EMFHelper.getEObject(element); + if (eObject != null) { + return getText(eObject); + } + + if (element instanceof IStructuredSelection) { + return getText((IStructuredSelection) element); + } + + return element.toString(); + } + + protected String getText(EObject element) { + return baseEMFLabelProvider.getText(element); + } + + protected String getText(IStructuredSelection selection) { + if (selection.isEmpty()) { + return ""; //$NON-NLS-1$ + } + + if (selection.size() == 1) { + return getText(selection.getFirstElement()); + } else { + final List selectionAsList = selection.toList(); + String str = ""; + for (int i = 0; i < selectionAsList.size(); i++) { + final String txt = getText(selectionAsList.get(i)); + if (txt != null) { + str += txt; + } + if (i < selectionAsList.size() - 1) { + str += ", "; + } + } + return str; + } + } + + /** + * {@inheritDoc} + */ + @Override + public Image getImage(Object element) { + if (element instanceof TreeElement) { + return super.getImage(element); + } + + EObject eObject = EMFHelper.getEObject(element); + if (eObject != null) { + return getImage(eObject); + } + + if (element instanceof IStructuredSelection) { + return getImage((IStructuredSelection) element); + } + + return null; + } + + protected Image getImage(EObject eObject) { + return baseEMFLabelProvider.getImage(eObject); + } + + protected Image getImage(IStructuredSelection selection) { + if (selection.isEmpty()) { + return null; + } else if (selection.size() == 1) { + return getImage(selection.getFirstElement()); + } + + final List selectionAsList = selection.toList(); + final Set selectedEObject = new HashSet(); + boolean isEObjectSelection = true; + for (final Object current : selectionAsList) { + final EObject obj = EMFHelper.getEObject(current); + if (obj != null) { + selectedEObject.add(obj); + } else { + isEObjectSelection = false; + } + } + + if (isEObjectSelection) {// all selected elements are EObject + if (selectedEObject.size() == 1 || hasCommonImage(selectedEObject)) { + return getImage(selectedEObject.toArray()[0]); + } else { + final EClass common = org.eclipse.papyrus.emf.facet.util.emf.core.internal.EMFUtils.computeLeastCommonSupertype(getEClasses(selectedEObject)); + if (!common.isAbstract()) { + // FIXME : the label provider service should manage this case + final Object instance = common.getEPackage().getEFactoryInstance().create(common); + return getNonCommonIcon(instance); + } + } + } else if (selectedEObject.size() == 0) { + // the multiple selection contains any EObject + } else { + // the selection contains EObject and others elements + } + return null; + } + + /** + * + * @param objects + * a collection of objects + * @return + * true if the image found for each object is the same false of if the collection is empty or the image returned + * for each object is not the same + */ + protected boolean hasCommonImage(final Collection objects) { + if (!objects.isEmpty()) { + final Image lastImage = getImage(objects.toArray()[0]); + for (final Object current : objects) { + if (lastImage != getImage(current)) { + return false; + } + } + } else { + return false; + } + return true; + } + + /** + * + * @param commonEClass + * the eClass + * @return + * the icon to use for this eclass + */ + protected Image getNonCommonIcon(final Object commonObject) { + return getImage(commonObject); + } + + /** + * + * @param objects + * a collection of eobject + * @return + * the set of eclasses for the parameter objects + */ + private Set getEClasses(final Collection objects) { + final Set eclasses = new HashSet(); + for (final EObject current : objects) { + eclasses.add(current.eClass()); + } + return eclasses; + } + + @Override + public String getDetail(Object object) { + object = EMFHelper.getEObject(object); + return getText(object) + " - " + getQualifiedClassName(object); //$NON-NLS-1$ + } + + /** + * Returns the qualified Class name of the given EObject, or an + * empty String if the object is not an EObject + * + * @param object + * @return The qualified name of this object's class, or an empty + * String if the object is not an EObject + */ + protected String getQualifiedClassName(Object object) { + if (object instanceof EObject) { + EObject eObject = (EObject) object; + EClass eClass = eObject.eClass(); + return EMFHelper.getQualifiedName(eClass, "::"); //$NON-NLS-1$ + } + return ""; //$NON-NLS-1$ + } + + + + @Override + public String getQualifierText(Object element) { + String result = null; + + EObject parent = getParentObject(element); + if (parent != null) { + result = getQualifiedText(parent); + } + + return result; + } + + private EObject getParentObject(Object element) { + EObject result = null; + + if (element != null) { + EObject eObject = EMFHelper.getEObject(element); + if (eObject != null) { + result = getParent(eObject); + } + } + + return result; + } + + @Override + public Image getQualifierImage(Object element) { + Image result = null; + + EObject parent = getParentObject(element); + if (parent != null) { + result = getImage(parent); + } + + return result; + } + + protected EObject getParent(EObject object) { + return object.eContainer(); + } + + protected String getQualifiedText(EObject object) { + StringBuilder result = new StringBuilder(); + + appendQualifiedText(object, result); + + return result.toString(); + } + + protected void appendQualifiedText(EObject object, StringBuilder buf) { + EObject parent = getParent(object); + if (parent != null) { + appendQualifiedText(parent, buf); + } + + if (buf.length() > 0) { + buf.append("::"); + } + + String name = getText(object); + if (name == null) { + name = String.format("<%s>", object.eClass().getName()); + } + buf.append(name); + } + + @Override + public void addListener(ILabelProviderListener listener) { + super.addListener(listener); + baseEMFLabelProvider.addListener(listener); + + // If we're adding a listener to it, presumably we want its + // notifications, so enable them + if (baseEMFLabelProvider.getClass() == StandardEMFLabelProvider.class) { + // Replace it with a fowarding provider + baseEMFLabelProvider.dispose(); + baseEMFLabelProvider = new ForwardingEMFLabelProvider(); + baseEMFLabelProvider.addListener(listener); + } else if (baseEMFLabelProvider instanceof AdapterFactoryLabelProvider) { + // Trust that it will notify if enabled + ((AdapterFactoryLabelProvider) baseEMFLabelProvider).setFireLabelUpdateNotifications(true); + } + } + + @Override + public void removeListener(ILabelProviderListener listener) { + baseEMFLabelProvider.removeListener(listener); + super.removeListener(listener); + } +} diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.ui.emf/src/org/eclipse/papyrus/infra/ui/emf/providers/ForwardingEMFLabelProvider.java b/plugins/infra/emf/org.eclipse.papyrus.infra.ui.emf/src/org/eclipse/papyrus/infra/ui/emf/providers/ForwardingEMFLabelProvider.java new file mode 100644 index 00000000000..a998f1a1097 --- /dev/null +++ b/plugins/infra/emf/org.eclipse.papyrus.infra.ui.emf/src/org/eclipse/papyrus/infra/ui/emf/providers/ForwardingEMFLabelProvider.java @@ -0,0 +1,82 @@ +/***************************************************************************** + * Copyright (c) 2016 Christian W. Damus and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Christian W. Damus - Initial API and implementation + * + *****************************************************************************/ + +package org.eclipse.papyrus.infra.ui.emf.providers; + +import java.util.Map; +import java.util.concurrent.ConcurrentMap; + +import org.eclipse.emf.common.notify.AdapterFactory; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.edit.provider.IChangeNotifier; +import org.eclipse.emf.edit.provider.IItemLabelProvider; +import org.eclipse.emf.edit.provider.INotifyChangedListener; + +import com.google.common.collect.MapMaker; + +/** + * A specialized {@link StandardEMFLabelProvider} that forwards change notifications + * from the label-providers to which it delegates. By default, it + * {@linkplain #isFireLabelUpdateNotifications() fires label update notifications} + * because that is the presumed purpose of using this class in the first place. + */ +public class ForwardingEMFLabelProvider extends StandardEMFLabelProvider { + + // Need to track this because EMF's change notifiers don't prevent multiple attachment + // of the same listener + private final ConcurrentMap forwards = new MapMaker().weakKeys().weakValues().makeMap(); + + private INotifyChangedListener forwardingListener; + + public ForwardingEMFLabelProvider() { + super(); + + // I am used in contexts where JFace label provider events are needed + setFireLabelUpdateNotifications(true); + } + + @Override + public void dispose() { + try { + for (Map.Entry next : forwards.entrySet()) { + next.getKey().removeListener(next.getValue()); + } + forwards.clear(); + } finally { + super.dispose(); + } + } + + @Override + IItemLabelProvider adapt(AdapterFactory adapterFactory, EObject object) { + IItemLabelProvider result = super.adapt(adapterFactory, object); + + if (result instanceof IChangeNotifier) { + // Hook it up for forwarding + IChangeNotifier notifier = (IChangeNotifier) result; + if (forwards.putIfAbsent(notifier, getForwardingListener()) == null) { + notifier.addListener(getForwardingListener()); + } + } + + return result; + } + + private INotifyChangedListener getForwardingListener() { + if (forwardingListener == null) { + forwardingListener = notification -> notifyChanged(notification); + } + return forwardingListener; + } + +} diff --git a/plugins/infra/emf/org.eclipse.papyrus.infra.ui.emf/src/org/eclipse/papyrus/infra/ui/emf/providers/StandardEMFLabelProvider.java b/plugins/infra/emf/org.eclipse.papyrus.infra.ui.emf/src/org/eclipse/papyrus/infra/ui/emf/providers/StandardEMFLabelProvider.java index d659ec48007..62b12fa7200 100644 --- a/plugins/infra/emf/org.eclipse.papyrus.infra.ui.emf/src/org/eclipse/papyrus/infra/ui/emf/providers/StandardEMFLabelProvider.java +++ b/plugins/infra/emf/org.eclipse.papyrus.infra.ui.emf/src/org/eclipse/papyrus/infra/ui/emf/providers/StandardEMFLabelProvider.java @@ -1,5 +1,6 @@ /******************************************************************************* - * Copyright (c) 2008 Obeo. + * Copyright (c) 2008, 2016 Obeo, CEA LIST, Christian W. Damus, and others. + * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -9,6 +10,8 @@ * Obeo - initial API and implementation * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Added support for enum literals * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Implementation of IDetailLabelProvider + * Christian W. Damus - bug 474467 + * *******************************************************************************/ package org.eclipse.papyrus.infra.ui.emf.providers; @@ -42,9 +45,6 @@ import org.eclipse.swt.graphics.Image; */ public class StandardEMFLabelProvider extends AdapterFactoryLabelProvider implements IDetailLabelProvider { - /** item provider class */ - private static final Class IItemLabelProviderClass = IItemLabelProvider.class; - /** list of adapter factories, identified by their Ids */ private static Map factories = new HashMap(); @@ -154,12 +154,16 @@ public class StandardEMFLabelProvider extends AdapterFactoryLabelProvider implem if (eObject != null) { AdapterFactory adapterFactory = getEditFactory(eObject); if (adapterFactory != null) { - return (IItemLabelProvider) adapterFactory.adapt(eObject, IItemLabelProviderClass); + itemLabelProvider = adapt(adapterFactory, eObject); } } return itemLabelProvider; } + IItemLabelProvider adapt(AdapterFactory adapterFactory, EObject object) { + return (IItemLabelProvider) adapterFactory.adapt(object, IItemLabelProvider.class); + } + /** * Gets the edit factory. * @@ -205,6 +209,7 @@ public class StandardEMFLabelProvider extends AdapterFactoryLabelProvider implem return factory; } + @Override public String getDetail(Object object) { object = EMFHelper.getEObject(object); return getText(object) + " - " + getQualifiedClassName(object); //$NON-NLS-1$ @@ -226,5 +231,4 @@ public class StandardEMFLabelProvider extends AdapterFactoryLabelProvider implem } return ""; //$NON-NLS-1$ } - } diff --git a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/src/org/eclipse/papyrus/infra/gmfdiag/common/GmfEditorFactory.java b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/src/org/eclipse/papyrus/infra/gmfdiag/common/GmfEditorFactory.java index 15ebfc9c20b..7092088acc3 100644 --- a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/src/org/eclipse/papyrus/infra/gmfdiag/common/GmfEditorFactory.java +++ b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/src/org/eclipse/papyrus/infra/gmfdiag/common/GmfEditorFactory.java @@ -1,6 +1,5 @@ /***************************************************************************** - * Copyright (c) 2008, 2014 LIFL, CEA LIST, and others. - * + * Copyright (c) 2008, 2016 LIFL, CEA LIST, Christian W. Damus, and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -11,6 +10,7 @@ * Cedric Dumoulin Cedric.dumoulin@lifl.fr - Initial API and implementation * Christian W. Damus (CEA) - service hook for integrating tools into graphical editor (CDO) * Christian W. Damus (CEA) - bug 392301 + * Christian W. Damus - bug 474467 * *****************************************************************************/ package org.eclipse.papyrus.infra.gmfdiag.common; @@ -19,19 +19,19 @@ import java.lang.reflect.Constructor; import org.eclipse.gef.ui.parts.GraphicalEditor; import org.eclipse.gmf.runtime.notation.Diagram; -import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.papyrus.infra.core.editor.BackboneException; +import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.AbstractPageModel; import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.IEditorModel; import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.IPageModel; import org.eclipse.papyrus.infra.core.services.ServiceException; import org.eclipse.papyrus.infra.core.services.ServicesRegistry; -import org.eclipse.papyrus.infra.emf.utils.ServiceUtilsForEObject; +import org.eclipse.papyrus.infra.core.utils.ServiceUtils; import org.eclipse.papyrus.infra.gmfdiag.common.messages.Messages; -import org.eclipse.papyrus.infra.gmfdiag.common.utils.DiagramUtils; +import org.eclipse.papyrus.infra.gmfdiag.common.providers.NotationLabelProvider; import org.eclipse.papyrus.infra.services.labelprovider.service.LabelProviderService; import org.eclipse.papyrus.infra.ui.extension.diagrameditor.AbstractEditorFactory; import org.eclipse.papyrus.infra.ui.multidiagram.actionbarcontributor.ActionBarContributorRegistry; -import org.eclipse.swt.graphics.Image; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.PartInitException; import org.eclipse.ui.part.EditorActionBarContributor; @@ -83,17 +83,14 @@ public class GmfEditorFactory extends AbstractEditorFactory { } - /** - * - * @see org.eclipse.papyrus.infra.ui.extension.diagrameditor.IPluggableEditorFactory#createIPageModel(java.lang.Object) - * @param pageIdentifier - * @return - * - */ @Override public IPageModel createIPageModel(Object pageIdentifier) { + ServicesRegistry services = getServiceRegistry(); + ILabelProvider labels = ServiceUtils.getInstance().tryService(services, LabelProviderService.class) + .map(lps -> lps.getLabelProvider(pageIdentifier)) + .orElseGet(NotationLabelProvider::new); - return new GMFEditorModel((Diagram) pageIdentifier, getServiceRegistry()); + return new GMFEditorModel((Diagram) pageIdentifier, services, labels); } /** @@ -102,7 +99,7 @@ public class GmfEditorFactory extends AbstractEditorFactory { * @author dumoulin * */ - class GMFEditorModel implements IEditorModel { + class GMFEditorModel extends AbstractPageModel implements IEditorModel { /** * The Diagram object describing the diagram. @@ -114,13 +111,13 @@ public class GmfEditorFactory extends AbstractEditorFactory { */ private ServicesRegistry servicesRegistry; - private Image tabIcon; - /** * * Constructor. */ - public GMFEditorModel(Diagram pageIdentifier, ServicesRegistry servicesRegistry) { + public GMFEditorModel(Diagram pageIdentifier, ServicesRegistry servicesRegistry, ILabelProvider labels) { + super(labels); + diagram = pageIdentifier; this.servicesRegistry = servicesRegistry; } @@ -204,51 +201,6 @@ public class GmfEditorFactory extends AbstractEditorFactory { public Object getRawModel() { return diagram; } - - /** - * Get the icon to be shown by Tabs - * - * @see org.eclipse.papyrus.infra.core.sasheditor.contentprovider.IPageModel#getTabIcon() - * @return - * - */ - @Override - public Image getTabIcon() { - if (tabIcon == null) { - ImageDescriptor imageDescriptor = DiagramUtils.getPrototype(diagram).getIconDescriptor(); - if (imageDescriptor != null) { - tabIcon = imageDescriptor.createImage(); - } - } - - return tabIcon; - } - - /** - * Get the title of the Diagram. - * - * @see org.eclipse.papyrus.infra.core.sasheditor.contentprovider.IPageModel#getTabTitle() - * @return - * - */ - @Override - public String getTabTitle() { - try { - LabelProviderService service = ServiceUtilsForEObject.getInstance().getService(LabelProviderService.class, diagram); - return service.getLabelProvider().getText(diagram); - } catch (ServiceException e) { - Activator.log.error(e); - } - return diagram.getName(); - } - - @Override - public void dispose() { - if (tabIcon != null) { - tabIcon.dispose(); - tabIcon = null; - } - } } } diff --git a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/src/org/eclipse/papyrus/infra/gmfdiag/common/providers/NotationLabelProvider.java b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/src/org/eclipse/papyrus/infra/gmfdiag/common/providers/NotationLabelProvider.java index 8a33dd14ea1..7dc1bc51caa 100644 --- a/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/src/org/eclipse/papyrus/infra/gmfdiag/common/providers/NotationLabelProvider.java +++ b/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.common/src/org/eclipse/papyrus/infra/gmfdiag/common/providers/NotationLabelProvider.java @@ -1,92 +1,69 @@ -/***************************************************************************** - * Copyright (c) 2012 CEA LIST. - * - * 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: - * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation - *****************************************************************************/ -package org.eclipse.papyrus.infra.gmfdiag.common.providers; - -import org.eclipse.emf.ecore.EObject; -import org.eclipse.gef.EditPart; -import org.eclipse.gmf.runtime.diagram.ui.editparts.ResizableCompartmentEditPart; -import org.eclipse.gmf.runtime.diagram.ui.services.editpart.EditPartService; -import org.eclipse.gmf.runtime.notation.BasicCompartment; -import org.eclipse.gmf.runtime.notation.DecorationNode; -import org.eclipse.gmf.runtime.notation.Diagram; -import org.eclipse.gmf.runtime.notation.View; -import org.eclipse.papyrus.infra.gmfdiag.common.Activator; -import org.eclipse.papyrus.infra.gmfdiag.common.types.NotationTypesMap; -import org.eclipse.papyrus.infra.gmfdiag.common.utils.DiagramUtils; -import org.eclipse.papyrus.infra.ui.emf.providers.EMFLabelProvider; -import org.eclipse.papyrus.infra.viewpoints.policy.ViewPrototype; -import org.eclipse.swt.graphics.Image; - -/** - * A Label Provider for GMF Notation model - */ -public class NotationLabelProvider extends EMFLabelProvider { - - /** icon for a compartment */ - public static final String ICON_COMPARTMENT = "/icons/none_comp_vis.gif"; //$NON-NLS-1$ - - @Override - public void dispose() { - super.dispose(); - } - - @Override - protected Image getImage(EObject element) { - if (element instanceof Diagram) { - ViewPrototype proto = DiagramUtils.getPrototype((Diagram) element); - if (proto == null) { - return null; - } - return proto.getIcon(); - } - - // if the element is a compartment - if (element instanceof BasicCompartment || element instanceof DecorationNode) { - return org.eclipse.papyrus.infra.widgets.Activator.getDefault().getImage(Activator.ID, ICON_COMPARTMENT); - } - - return super.getImage(element); - } - - /** - * - * @see org.eclipse.jface.viewers.ILabelProvider#getText(java.lang.Object) - * - * @param element - * @return - *
    - *
  • if element is a {@link NamedElement}, we return its name
  • - *
  • else if element is a {@link Element}, we return its type + a index
  • - *
  • else return Messages#EditorLabelProvider_No_name
  • - *
- */ - @Override - protected String getText(EObject element) { - if (element instanceof Diagram) { - return ((Diagram) element).getName(); - } - - if (element instanceof View) { // maybe it is a view of a compartment - String humanType = NotationTypesMap.instance.getHumanReadableType((View) element); - if (humanType != null) { - return humanType; - } - - EditPart dummyEP = EditPartService.getInstance().createGraphicEditPart((View) element); - if (dummyEP instanceof ResizableCompartmentEditPart) { - return ((ResizableCompartmentEditPart) dummyEP).getCompartmentName(); - } - } - - return super.getText(element); - } -} +/***************************************************************************** + * Copyright (c) 2012, 2016 CEA LIST, Christian W. Damus, and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation + * Christian W. Damus - bug 474467 + * + *****************************************************************************/ +package org.eclipse.papyrus.infra.gmfdiag.common.providers; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.gef.EditPart; +import org.eclipse.gmf.runtime.diagram.ui.editparts.ResizableCompartmentEditPart; +import org.eclipse.gmf.runtime.diagram.ui.services.editpart.EditPartService; +import org.eclipse.gmf.runtime.notation.BasicCompartment; +import org.eclipse.gmf.runtime.notation.DecorationNode; +import org.eclipse.gmf.runtime.notation.Diagram; +import org.eclipse.gmf.runtime.notation.View; +import org.eclipse.papyrus.infra.gmfdiag.common.Activator; +import org.eclipse.papyrus.infra.gmfdiag.common.types.NotationTypesMap; +import org.eclipse.papyrus.infra.viewpoints.policy.ViewPrototypeLabelProvider; +import org.eclipse.swt.graphics.Image; + +/** + * A Label Provider for GMF Notation model + */ +public class NotationLabelProvider extends ViewPrototypeLabelProvider { + + /** icon for a compartment */ + public static final String ICON_COMPARTMENT = "/icons/none_comp_vis.gif"; //$NON-NLS-1$ + + @Override + protected Image getImage(EObject element) { + // if the element is a compartment + if (element instanceof BasicCompartment || element instanceof DecorationNode) { + return org.eclipse.papyrus.infra.widgets.Activator.getDefault().getImage(Activator.ID, ICON_COMPARTMENT); + } + + return super.getImage(element); + } + + @Override + protected String getText(EObject element) { + String result = null; + + if (element instanceof Diagram) { + result = super.getText(element); + } else if (element instanceof View) { // maybe it is a view of a compartment + String humanType = NotationTypesMap.instance.getHumanReadableType((View) element); + if (humanType != null) { + result = humanType; + } else { + EditPart dummyEP = EditPartService.getInstance().createGraphicEditPart((View) element); + if (dummyEP instanceof ResizableCompartmentEditPart) { + result = ((ResizableCompartmentEditPart) dummyEP).getCompartmentName(); + } + } + } else { + result = super.getText(element); + } + + return result; + } +} diff --git a/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable.common/.classpath b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable.common/.classpath index 8a8f1668cdc..eca7bdba8f0 100644 --- a/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable.common/.classpath +++ b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable.common/.classpath @@ -1,7 +1,7 @@ - - - - - - - + + + + + + + diff --git a/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable.common/.settings/org.eclipse.jdt.core.prefs b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable.common/.settings/org.eclipse.jdt.core.prefs index 94d61f00da6..b3aa6d60f94 100644 --- a/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable.common/.settings/org.eclipse.jdt.core.prefs +++ b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable.common/.settings/org.eclipse.jdt.core.prefs @@ -1,10 +1,10 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 -org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.compiler.source=1.8 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 diff --git a/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable.common/META-INF/MANIFEST.MF b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable.common/META-INF/MANIFEST.MF index 6f08492aac3..2f19d31ecec 100644 --- a/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable.common/META-INF/MANIFEST.MF +++ b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable.common/META-INF/MANIFEST.MF @@ -23,4 +23,4 @@ Bundle-Name: %Bundle-Name Bundle-Activator: org.eclipse.papyrus.infra.nattable.common.Activator Bundle-ManifestVersion: 2 Bundle-SymbolicName: org.eclipse.papyrus.infra.nattable.common;singleton:=true -Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 diff --git a/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable.common/src/org/eclipse/papyrus/infra/nattable/common/factory/NattableEditorFactory.java b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable.common/src/org/eclipse/papyrus/infra/nattable/common/factory/NattableEditorFactory.java index adeab806353..f6fb244db5b 100644 --- a/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable.common/src/org/eclipse/papyrus/infra/nattable/common/factory/NattableEditorFactory.java +++ b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable.common/src/org/eclipse/papyrus/infra/nattable/common/factory/NattableEditorFactory.java @@ -1,6 +1,5 @@ /***************************************************************************** - * Copyright (c) 2011, 2014 LIFL, CEA LIST, and others. - * + * Copyright (c) 2011, 2016 LIFL, CEA LIST, Christian W. Damus, and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -11,23 +10,28 @@ * Cedric Dumoulin (LIFL) cedric.dumoulin@lifl.fr - Initial API and implementation * Vincent Lorenzo (CEA-LIST) vincent.lorenzo@cea.fr * Christian W. Damus (CEA) - bug 392301 + * Christian W. Damus - bug 474467 * *****************************************************************************/ package org.eclipse.papyrus.infra.nattable.common.factory; import java.lang.reflect.Constructor; +import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.papyrus.infra.core.editor.BackboneException; +import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.AbstractPageModel; import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.IEditorModel; import org.eclipse.papyrus.infra.core.sasheditor.contentprovider.IPageModel; import org.eclipse.papyrus.infra.core.services.ServiceException; import org.eclipse.papyrus.infra.core.services.ServicesRegistry; +import org.eclipse.papyrus.infra.core.utils.ServiceUtils; import org.eclipse.papyrus.infra.nattable.Activator; import org.eclipse.papyrus.infra.nattable.common.editor.NatTableEditor; import org.eclipse.papyrus.infra.nattable.model.nattable.Table; +import org.eclipse.papyrus.infra.nattable.provider.TableLabelProvider; +import org.eclipse.papyrus.infra.services.labelprovider.service.LabelProviderService; import org.eclipse.papyrus.infra.ui.extension.diagrameditor.AbstractEditorFactory; import org.eclipse.papyrus.infra.ui.multidiagram.actionbarcontributor.ActionBarContributorRegistry; -import org.eclipse.swt.graphics.Image; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.PartInitException; import org.eclipse.ui.part.EditorActionBarContributor; @@ -64,7 +68,12 @@ public class NattableEditorFactory extends AbstractEditorFactory { */ @Override public IPageModel createIPageModel(Object pageIdentifier) { - return new NattableEditorModel(pageIdentifier, getServiceRegistry()); + ServicesRegistry services = getServiceRegistry(); + ILabelProvider labels = ServiceUtils.getInstance().tryService(services, LabelProviderService.class) + .map(lps -> lps.getLabelProvider(pageIdentifier)) + .orElseGet(TableLabelProvider::new); + + return new NattableEditorModel(pageIdentifier, services, labels); } /** @@ -84,7 +93,7 @@ public class NattableEditorFactory extends AbstractEditorFactory { * @author cedric dumoulin * */ - class NattableEditorModel implements IEditorModel { + class NattableEditorModel extends AbstractPageModel implements IEditorModel { /** @@ -106,7 +115,9 @@ public class NattableEditorFactory extends AbstractEditorFactory { * * Constructor. */ - public NattableEditorModel(Object pageIdentifier, ServicesRegistry servicesRegistry) { + public NattableEditorModel(Object pageIdentifier, ServicesRegistry servicesRegistry, ILabelProvider labels) { + super(labels); + this.rawModel = (Table) pageIdentifier; this.servicesRegistry = servicesRegistry; } @@ -186,34 +197,5 @@ public class NattableEditorFactory extends AbstractEditorFactory { public Object getRawModel() { return this.rawModel; } - - /** - * Get the icon to be shown by Tabs - * - * @see org.eclipse.papyrus.infra.core.sasheditor.contentprovider.IPageModel#getTabIcon() - * @return - * - */ - @Override - public Image getTabIcon() { - return org.eclipse.papyrus.infra.widgets.Activator.getDefault().getImage(this.rawModel.getTableConfiguration().getIconPath()); - } - - /** - * Get the title of the Diagram. - * - * @see org.eclipse.papyrus.infra.core.sasheditor.contentprovider.IPageModel#getTabTitle() - * @return - * - */ - @Override - public String getTabTitle() { - return this.rawModel.getName(); - } - - @Override - public void dispose() { - // Pass. The tab icon is a plugin-shared image - } } } diff --git a/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/provider/TableLabelProvider.java b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/provider/TableLabelProvider.java index 794a90418a7..f5383eecc89 100644 --- a/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/provider/TableLabelProvider.java +++ b/plugins/infra/nattable/org.eclipse.papyrus.infra.nattable/src/org/eclipse/papyrus/infra/nattable/provider/TableLabelProvider.java @@ -1,5 +1,5 @@ /***************************************************************************** - * Copyright (c) 2013 CEA LIST. + * Copyright (c) 2013, 2016 CEA LIST, Christian W. Damus, and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -8,17 +8,16 @@ * * Contributors: * Juan Cadavid (CEA LIST) juan.cadavid@cea.fr - Initial API and implementation + * Christian W. Damus - bug 474467 + * *****************************************************************************/ package org.eclipse.papyrus.infra.nattable.provider; -import java.util.Collection; - import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.papyrus.infra.emf.utils.EMFHelper; import org.eclipse.papyrus.infra.nattable.model.nattable.Table; import org.eclipse.papyrus.infra.services.labelprovider.service.IFilteredLabelProvider; -import org.eclipse.papyrus.infra.ui.emf.providers.EMFLabelProvider; -import org.eclipse.papyrus.infra.widgets.Activator; +import org.eclipse.papyrus.infra.viewpoints.policy.ViewPrototypeLabelProvider; import org.eclipse.swt.graphics.Image; /** @@ -26,74 +25,16 @@ import org.eclipse.swt.graphics.Image; * This labelprovider provides icon and text for tables to display them in treeviewer AND in the property view * */ -public class TableLabelProvider extends EMFLabelProvider implements IFilteredLabelProvider { +public class TableLabelProvider extends ViewPrototypeLabelProvider implements IFilteredLabelProvider { - /** - * - * @see org.eclipse.papyrus.infra.ui.emf.providers.EMFLabelProvider#getText(java.lang.Object) - * - * @param table - * @return - */ - @Override - public String getText(Object table) { - if (table instanceof IStructuredSelection) { - return super.getText((IStructuredSelection) table); - } - - Object el = EMFHelper.getEObject(table); - - if (el instanceof Table) { - return ((Table) el).getName(); - } - return ""; //$NON-NLS-1$ - } - - /** - * - * @see org.eclipse.papyrus.infra.ui.emf.providers.EMFLabelProvider#getImage(java.lang.Object) - * - * @param table - * @return - */ - @Override - public Image getImage(Object table) { - if (table instanceof IStructuredSelection) { - return getImage(((IStructuredSelection) table)); - } - - table = EMFHelper.getEObject(table); - - if (table instanceof Table) { - final String iconPath = getIcon((Table) table); - if (iconPath != null) { - return Activator.getDefault().getImage(iconPath); - } - } - return null; - } - - protected String getIcon(Table table) { - if (table == null || table.getTableConfiguration() == null || table.getTableConfiguration().getIconPath() == null) { - return null; - } - return table.getTableConfiguration().getIconPath(); - } - - /** - * - * @see org.eclipse.papyrus.infra.services.labelprovider.service.IFilteredLabelProvider#accept(java.lang.Object) - * - * @param object - * @return - */ @Override public boolean accept(Object object) { if (object instanceof IStructuredSelection) { return accept((IStructuredSelection) object); } - return EMFHelper.getEObject(object) instanceof Table; + boolean result = EMFHelper.getEObject(object) instanceof Table; + return result; } /** @@ -101,7 +42,7 @@ public class TableLabelProvider extends EMFLabelProvider implements IFilteredLab * @param selection * a selection * @return - * true if all elements in the selection are accepted + * true if all elements in the selection are accepted */ protected boolean accept(final IStructuredSelection selection) { for (final Object current : selection.toList()) { @@ -112,43 +53,6 @@ public class TableLabelProvider extends EMFLabelProvider implements IFilteredLab return true; } - /** - * - * @see org.eclipse.papyrus.infra.ui.emf.providers.EMFLabelProvider#hasCommonImage(java.util.Collection) - * - * @param objects - * @return - * true if all selected table have the same icon - */ - @Override - protected boolean hasCommonImage(Collection objects) { - String iconPath = null; - for (Object current : objects) { - if (!(current instanceof Table)) { - return false; - } - - String icon = getIcon((Table) current); - if (icon == null && iconPath != null) { - return false; - } - - if (iconPath == null) { - iconPath = icon; - } else if (!iconPath.equals(icon)) { - return false; - } - } - return true; - } - - /** - * - * @see org.eclipse.papyrus.infra.ui.emf.providers.EMFLabelProvider#getNonCommonIcon(java.lang.Object) - * - * @param commonObject - * @return - */ @Override protected Image getNonCommonIcon(final Object commonObject) { return org.eclipse.papyrus.infra.widgets.Activator.getDefault().getImage(org.eclipse.papyrus.infra.nattable.Activator.PLUGIN_ID, "/icons/table.gif"); diff --git a/plugins/infra/viewpoints/org.eclipse.papyrus.infra.viewpoints.policy/.classpath b/plugins/infra/viewpoints/org.eclipse.papyrus.infra.viewpoints.policy/.classpath index ed2585fb3f4..f0c55498599 100755 --- a/plugins/infra/viewpoints/org.eclipse.papyrus.infra.viewpoints.policy/.classpath +++ b/plugins/infra/viewpoints/org.eclipse.papyrus.infra.viewpoints.policy/.classpath @@ -1,8 +1,8 @@ - - - - - - - - + + + + + + + + diff --git a/plugins/infra/viewpoints/org.eclipse.papyrus.infra.viewpoints.policy/.settings/org.eclipse.jdt.core.prefs b/plugins/infra/viewpoints/org.eclipse.papyrus.infra.viewpoints.policy/.settings/org.eclipse.jdt.core.prefs index 4759947300a..62a08f4494d 100755 --- a/plugins/infra/viewpoints/org.eclipse.papyrus.infra.viewpoints.policy/.settings/org.eclipse.jdt.core.prefs +++ b/plugins/infra/viewpoints/org.eclipse.papyrus.infra.viewpoints.policy/.settings/org.eclipse.jdt.core.prefs @@ -1,10 +1,10 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 -org.eclipse.jdt.core.compiler.compliance=1.5 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.5 +org.eclipse.jdt.core.compiler.source=1.8 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 diff --git a/plugins/infra/viewpoints/org.eclipse.papyrus.infra.viewpoints.policy/META-INF/MANIFEST.MF b/plugins/infra/viewpoints/org.eclipse.papyrus.infra.viewpoints.policy/META-INF/MANIFEST.MF index 91d463d9a96..f1bbf28c833 100755 --- a/plugins/infra/viewpoints/org.eclipse.papyrus.infra.viewpoints.policy/META-INF/MANIFEST.MF +++ b/plugins/infra/viewpoints/org.eclipse.papyrus.infra.viewpoints.policy/META-INF/MANIFEST.MF @@ -15,7 +15,8 @@ Require-Bundle: org.eclipse.ui;bundle-version="[3.107.0,4.0.0)";visibility:=reex org.eclipse.papyrus.infra.viewpoints.iso42010;bundle-version="[1.2.0,2.0.0)";visibility:=reexport, org.eclipse.papyrus.infra.viewpoints.configuration;bundle-version="[1.2.0,2.0.0)";visibility:=reexport, org.eclipse.papyrus.infra.constraints;bundle-version="[2.0.0,3.0.0)";visibility:=reexport, - org.eclipse.papyrus.infra.widgets;bundle-version="[2.0.0,3.0.0)" + org.eclipse.papyrus.infra.widgets;bundle-version="[2.0.0,3.0.0)", + org.eclipse.papyrus.infra.ui.emf;bundle-version="[1.2.0,2.0.0)" Bundle-Vendor: %providerName Bundle-ActivationPolicy: lazy Bundle-ClassPath: . @@ -25,4 +26,4 @@ Bundle-Name: %pluginName Bundle-ManifestVersion: 2 Bundle-Activator: org.eclipse.papyrus.infra.viewpoints.policy.Activator Bundle-SymbolicName: org.eclipse.papyrus.infra.viewpoints.policy;singleton:=true -Bundle-RequiredExecutionEnvironment: J2SE-1.5 +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 diff --git a/plugins/infra/viewpoints/org.eclipse.papyrus.infra.viewpoints.policy/src/org/eclipse/papyrus/infra/viewpoints/policy/UnavailableViewPrototype.java b/plugins/infra/viewpoints/org.eclipse.papyrus.infra.viewpoints.policy/src/org/eclipse/papyrus/infra/viewpoints/policy/UnavailableViewPrototype.java index 663897e863a..9689ea5ad15 100755 --- a/plugins/infra/viewpoints/org.eclipse.papyrus.infra.viewpoints.policy/src/org/eclipse/papyrus/infra/viewpoints/policy/UnavailableViewPrototype.java +++ b/plugins/infra/viewpoints/org.eclipse.papyrus.infra.viewpoints.policy/src/org/eclipse/papyrus/infra/viewpoints/policy/UnavailableViewPrototype.java @@ -1,6 +1,5 @@ /***************************************************************************** - * Copyright (c) 2013 CEA LIST. - * + * Copyright (c) 2013, 2016 CEA LIST, Christian W. Damus, and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -9,6 +8,7 @@ * * Contributors: * Laurent Wouters laurent.wouters@cea.fr - Initial API and implementation + * Christian W. Damus - bug 474467 * *****************************************************************************/ package org.eclipse.papyrus.infra.viewpoints.policy; @@ -49,6 +49,11 @@ public class UnavailableViewPrototype extends ViewPrototype { return true; } + @Override + public boolean isUnavailable() { + return true; + } + /** * @see org.eclipse.papyrus.infra.viewpoints.policy.ViewPrototype#getImplementation() */ diff --git a/plugins/infra/viewpoints/org.eclipse.papyrus.infra.viewpoints.policy/src/org/eclipse/papyrus/infra/viewpoints/policy/ViewPrototype.java b/plugins/infra/viewpoints/org.eclipse.papyrus.infra.viewpoints.policy/src/org/eclipse/papyrus/infra/viewpoints/policy/ViewPrototype.java index 7b4ea6c23ad..e0b95afe2e4 100755 --- a/plugins/infra/viewpoints/org.eclipse.papyrus.infra.viewpoints.policy/src/org/eclipse/papyrus/infra/viewpoints/policy/ViewPrototype.java +++ b/plugins/infra/viewpoints/org.eclipse.papyrus.infra.viewpoints.policy/src/org/eclipse/papyrus/infra/viewpoints/policy/ViewPrototype.java @@ -1,6 +1,5 @@ /***************************************************************************** - * Copyright (c) 2013 CEA LIST. - * + * Copyright (c) 2013, 2016 CEA LIST, Christian W. Damus, and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -9,6 +8,7 @@ * * Contributors: * Laurent Wouters laurent.wouters@cea.fr - Initial API and implementation + * Christian W. Damus - bug 474467 * *****************************************************************************/ package org.eclipse.papyrus.infra.viewpoints.policy; @@ -158,7 +158,7 @@ public abstract class ViewPrototype { * * @param view * The view for which a prototype is expected - * @return The view's prototype + * @return The view's prototype, never {@code null} but possibly {@link #isUnavailable() unavailable} */ public static ViewPrototype get(EObject view) { for (IViewTypeHelper helper : HELPERS) { @@ -226,6 +226,17 @@ public abstract class ViewPrototype { return isNatural(configuration); } + /** + * Queries whether the prototype is unavailable, effectively a Null Object. + * + * @return whether the prototype is a non-view prototype + * + * @since 1.2 + */ + public boolean isUnavailable() { + return false; + } + /** * Gets the ID of the implementation of this prototype * @@ -419,6 +430,7 @@ public abstract class ViewPrototype { /** * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) */ + @Override public int compare(ViewPrototype proto1, ViewPrototype proto2) { Integer p1 = getPriority(proto1); Integer p2 = getPriority(proto2); diff --git a/plugins/infra/viewpoints/org.eclipse.papyrus.infra.viewpoints.policy/src/org/eclipse/papyrus/infra/viewpoints/policy/ViewPrototypeLabelProvider.java b/plugins/infra/viewpoints/org.eclipse.papyrus.infra.viewpoints.policy/src/org/eclipse/papyrus/infra/viewpoints/policy/ViewPrototypeLabelProvider.java new file mode 100644 index 00000000000..5e71ff35851 --- /dev/null +++ b/plugins/infra/viewpoints/org.eclipse.papyrus.infra.viewpoints.policy/src/org/eclipse/papyrus/infra/viewpoints/policy/ViewPrototypeLabelProvider.java @@ -0,0 +1,95 @@ +/***************************************************************************** + * Copyright (c) 2012, 2016 CEA LIST, Christian W. Damus, and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation + * Christian W. Damus - bug 474467 + * + *****************************************************************************/ +package org.eclipse.papyrus.infra.viewpoints.policy; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.gmf.runtime.emf.core.util.EMFCoreUtil; +import org.eclipse.osgi.util.NLS; +import org.eclipse.papyrus.infra.ui.emf.providers.DependentEMFLabelProvider; +import org.eclipse.swt.graphics.Image; + +/** + * A Label Provider for viewpoint-based notations. + * + * @since 1.2 + */ +public class ViewPrototypeLabelProvider extends DependentEMFLabelProvider { + + @Override + protected Image getImage(EObject element) { + Image result; + + ViewPrototype proto = ViewPrototype.get(element); + if (proto != null) { + // This is shared by the Widgets plug-in activator, so don't + // dispose it + result = proto.getIcon(); + } else { + result = super.getImage(element); + } + + return result; + } + + @Override + protected String getText(EObject element) { + // Hit the delegate to ensure that the item provider adapter is attached + // for notifications + String result = super.getText(element); + + ViewPrototype proto = ViewPrototype.get(element); + if (!proto.isUnavailable()) { + EObject context = proto.getRootOf(element); + result = getName(element); + + if ((result != null) && !result.isEmpty()) { + if (context != null) { + // In case we were deriving a label from it + unsubscribe(context, element); + } + } else { + if (context != null) { + String contextLabel = getText(context); + result = NLS.bind("({0} of {1})", proto.getLabel(), contextLabel); + + // Update when the context's label changes + subscribe(context, element); + } else { + result = NLS.bind("({1})", proto.getLabel()); + } + + if ((result == null) || result.isEmpty()) { + result = "(unnamed)"; + } + } + } // else just keep the super result + + return result; + } + + /** + * Attempts to infer the name of an {@code object} by looking for a string-valued + * attribute named "name". + * + * @param object + * an object + * + * @return a best-effort name for the {@code object} + * + * @see EMFCoreUtil#getName(EObject) + */ + protected String getName(EObject object) { + return EMFCoreUtil.getName(object); + } +} -- cgit v1.2.3