Java tutorial
/***************************************************************************** * Copyright (c) 2010 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: * Patrick Tessier (CEA LIST) Patrick.tessier@cea.fr - Initial API and implementation * Vincent Lorenzo (CEA LIST) Vincent.lorenzo@cea.fr - 343950: [Model Explorer] [TableEditor] Function "Link with Editor" *****************************************************************************/ package org.eclipse.papyrus.modelexplorer; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import org.eclipse.core.commands.operations.IUndoContext; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.edit.domain.EditingDomain; import org.eclipse.emf.edit.domain.IEditingDomainProvider; import org.eclipse.emf.transaction.ResourceSetChangeEvent; import org.eclipse.emf.transaction.ResourceSetListener; import org.eclipse.emf.transaction.ResourceSetListenerImpl; import org.eclipse.emf.transaction.TransactionalEditingDomain; import org.eclipse.gmf.runtime.notation.Diagram; import org.eclipse.jface.viewers.ColumnViewerToolTipSupport; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.window.ToolTip; import org.eclipse.papyrus.core.editor.IMultiDiagramEditor; import org.eclipse.papyrus.core.lifecycleevents.IEditorInputChangedListener; import org.eclipse.papyrus.core.lifecycleevents.ISaveAndDirtyService; import org.eclipse.papyrus.core.services.ServiceException; import org.eclipse.papyrus.core.ui.IRevealSemanticElement; import org.eclipse.papyrus.core.utils.EditorUtils; import org.eclipse.papyrus.core.utils.ServiceUtils; import org.eclipse.papyrus.modelexplorer.listener.DoubleClickListener; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeItem; import org.eclipse.ui.IActionBars; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IMemento; import org.eclipse.ui.ISaveablePart; import org.eclipse.ui.ISelectionListener; import org.eclipse.ui.IViewSite; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.actions.ActionFactory; import org.eclipse.ui.internal.navigator.NavigatorContentService; import org.eclipse.ui.internal.navigator.extensions.NavigatorContentDescriptor; import org.eclipse.ui.navigator.CommonNavigator; import org.eclipse.ui.navigator.CommonViewer; import org.eclipse.ui.operations.RedoActionHandler; import org.eclipse.ui.operations.UndoActionHandler; import org.eclipse.ui.part.FileEditorInput; import org.eclipse.ui.views.properties.IPropertySheetPage; import org.eclipse.ui.views.properties.tabbed.ITabbedPropertySheetPageContributor; import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage; /** * Papyrus Model Explorer associated to one {@link IMultiDiagramEditor}. * This ModelExplorer is linked to one single {@link IMultiDiagramEditor}. It doesn't change its * source when the current Editor change. To allow to explore different Model, use a {@link ModelExplorerPageBookView}. * */ public class ModelExplorerView extends CommonNavigator implements IRevealSemanticElement, IEditingDomainProvider { /** The associated EditorPart */ private IMultiDiagramEditor editorPart; /** The save aservice associated to the editor. */ private ISaveAndDirtyService saveAndDirtyService; /** editing domain used to read/write the model */ private TransactionalEditingDomain editingDomain; /** Flag to avoid reentrant call to refresh. */ private AtomicBoolean isRefreshing = new AtomicBoolean(false); /** * Listener on {@link ISaveAndDirtyService#addInputChangedListener(IEditorInputChangedListener)} */ protected IEditorInputChangedListener editorInputChangedListener = new IEditorInputChangedListener() { /** * This method is called when the editor input is changed from the ISaveAndDirtyService. * @see org.eclipse.papyrus.core.lifecycleevents.IEditorInputChangedListener#editorInputChanged(org.eclipse.ui.part.FileEditorInput) * * @param fileEditorInput */ public void editorInputChanged(FileEditorInput fileEditorInput) { // Change the editor input. setPartName(fileEditorInput.getName()); } /** * The isDirty flag has changed, reflect its new value * @see org.eclipse.papyrus.core.lifecycleevents.IEditorInputChangedListener#isDirtyChanged() * */ public void isDirtyChanged() { firePropertyChange(IEditorPart.PROP_DIRTY); } }; /** Undo action handler */ UndoActionHandler undoHandler; /** Redo action handler */ RedoActionHandler redoHandler; /** The {@link IPropertySheetPage} this model explorer will use. */ private IPropertySheetPage propertySheetPage = null; /** * * Constructor. * * @param part * The part associated to this ModelExplorer */ public ModelExplorerView(IMultiDiagramEditor part) { this.editorPart = part; setLinkingEnabled(true); try { this.saveAndDirtyService = editorPart.getServicesRegistry().getService(ISaveAndDirtyService.class); } catch (ServiceException e) { e.printStackTrace(); } } /** * Handle a selection change in the editor. * * @param part * @param selection */ private void handleSelectionChangedFromDiagramEditor(IWorkbenchPart part, ISelection selection) { // Handle selection from diagram editor if (isLinkingEnabled()) { if (part instanceof IEditorPart) { if (selection instanceof IStructuredSelection) { Iterator<?> selectionIterator = ((IStructuredSelection) selection).iterator(); ArrayList<Object> semanticElementList = new ArrayList<Object>(); while (selectionIterator.hasNext()) { Object currentSelection = selectionIterator.next(); if (currentSelection instanceof IAdaptable) { Object semanticElement = ((IAdaptable) currentSelection).getAdapter(EObject.class); if (semanticElement != null) { semanticElementList.add(semanticElement); } //when we are in a table, the selected element are EObject } else if (currentSelection instanceof EObject) { semanticElementList.add(currentSelection); } } revealSemanticElement(semanticElementList); } } } } /** * look for the path the list of element (comes from the content provider) to go the eObject * @param eobject that we look for. * @param objects a list of elements where eobject can be wrapped. * @return the list of modelElementItem ( from the root to the element that wrap the eobject) */ protected List<Object> searchPath(EObject eobject, List<Object> objects) { SemanticFromModelExplorer semanticGetter = new SemanticFromModelExplorer(); List<Object> path = new ArrayList<Object>(); ITreeContentProvider contentProvider = (ITreeContentProvider) getCommonViewer().getContentProvider(); for (Object o : objects) { // Search matches in this level if (!(o instanceof Diagram) && o instanceof IAdaptable) { if (eobject.equals((EObject) ((IAdaptable) o).getAdapter(EObject.class))) { path.add(o); return path; } } // Find childs only for feature container for (int i = 0; i < contentProvider.getChildren(o).length; i++) { Object treeItem = contentProvider.getChildren(o)[i]; List<Object> tmppath = new ArrayList<Object>(); Object element = semanticGetter.getSemanticElement(treeItem); if (element != null) { if (element instanceof EReference) { if (((EReference) element).isContainment() && (!((EReference) element).isDerived())) { List<Object> childs = new ArrayList<Object>(); childs.add(treeItem); tmppath = searchPath(eobject, childs); } } else { if (element instanceof EObject) { List<Object> childs = new ArrayList<Object>(); childs.add(treeItem); tmppath = searchPath(eobject, childs); } } } // if tmppath contains the wrapped eobject we have find the good path if (tmppath.size() > 0) { if (tmppath.get(tmppath.size() - 1) instanceof IAdaptable) { if (eobject.equals((EObject) ((IAdaptable) (tmppath.get(tmppath.size() - 1))) .getAdapter(EObject.class))) { path.add(o); path.addAll(tmppath); return path; } } } } } return new ArrayList<Object>(); } /** * {@inheritDoc} */ // FIXME Use of internal class (NavigatorContentService) - in the hope that the bug gets fixed soon. @Override protected CommonViewer createCommonViewerObject(Composite aParent) { CommonViewer viewer = new CustomCommonViewer(getViewSite().getId(), aParent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); // enable tool-tips // workaround for bug 311827: the Common Viewer always uses NavigatorDecoratingLabelProvider // as a wrapper for the LabelProvider provided by the application. The NavigatorDecoratingLabelProvider // does not delegate tooltip related functions but defines them as empty. NavigatorContentService contentService = new NavigatorContentService(getViewSite().getId()); @SuppressWarnings("unchecked") // get label provider from content service (which in turn evaluates extension points in // function of the input) Set<Object> descriptors = contentService.findDescriptorsByTriggerPoint(getInitialInput(), false); for (Object descriptor : descriptors) { if (descriptor instanceof NavigatorContentDescriptor) { try { ILabelProvider labelProvider = ((NavigatorContentDescriptor) descriptor).createLabelProvider(); viewer.setLabelProvider(labelProvider); } catch (CoreException e) { Activator.log.error(e); } break; } } ColumnViewerToolTipSupport.enableFor(viewer, ToolTip.NO_RECREATE); return viewer; } @Override public void createPartControl(Composite aParent) { super.createPartControl(aParent); getCommonViewer().setSorter(null); ((CustomCommonViewer) getCommonViewer()).getDropAdapter().setFeedbackEnabled(true); getCommonViewer().addDoubleClickListener(new DoubleClickListener()); Tree tree = getCommonViewer().getTree(); Activator.getDefault().getCustomizationManager().installCustomPainter(tree); } /** * Return the control used to render this View * * @see org.eclipse.papyrus.core.ui.pagebookview.IPageBookNestableViewPart#getControl() * * @return the main control of the navigator viewer */ public Control getControl() { return getCommonViewer().getControl(); } /** * {@inheritDoc} */ @Override public void init(IViewSite site, IMemento aMemento) throws PartInitException { super.init(site, aMemento); // Hook undo/redo action // hookGlobalHistoryHandler(site); // page.addPartListener(partListener); activate(); } /** * {@inheritDoc} */ @Override public void init(IViewSite site) throws PartInitException { super.init(site); IWorkbenchPage page = site.getPage(); // an ISelectionListener to react to workbench selection changes. page.addSelectionListener(new ISelectionListener() { public void selectionChanged(IWorkbenchPart part, ISelection selection) { handleSelectionChangedFromDiagramEditor(part, selection); } }); } /** * Hook the global undo/redi actions. */ private void hookGlobalHistoryHandler(IViewSite site) { undoHandler = new UndoActionHandler(site, null); redoHandler = new RedoActionHandler(site, null); IActionBars actionBars = site.getActionBars(); actionBars.setGlobalActionHandler(ActionFactory.UNDO.getId(), undoHandler); actionBars.setGlobalActionHandler(ActionFactory.REDO.getId(), redoHandler); } /** * {@link ResourceSetListener} to listen and react to changes in the * resource set. */ private final ResourceSetListener resourceSetListener = new ResourceSetListenerImpl() { /** * {@inheritDoc} */ @Override public void resourceSetChanged(ResourceSetChangeEvent event) { super.resourceSetChanged(event); handleResourceSetChanged(event); } }; /** * Run in a UI thread to avoid non UI thread exception. * @param event */ private void handleResourceSetChanged(ResourceSetChangeEvent event) { PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() { /** * {@inheritDoc} */ public void run() { refresh(); } }); } /** * refresh the view. */ public void refresh() { // Need to refresh, even if (temporarily) invisible // (Better alternative?: store refresh event and execute once visible again) if (getControl().isDisposed()) return; // avoid reentrant call // Refresh only of we are not already refreshing. if (isRefreshing.compareAndSet(false, true)) { if (!getCommonViewer().isBusy()) getCommonViewer().refresh(); isRefreshing.set(false); } } /** * {@inheritDoc} */ @Override protected Object getInitialInput() { if (editorPart != null) { return editorPart.getServicesRegistry(); } else { return super.getInitialInput(); } } /** * Activate specified Part. */ private void activate() { if (editorPart != null) { try { this.editingDomain = ServiceUtils.getInstance() .getTransactionalEditingDomain(editorPart.getServicesRegistry()); // this.editingDomain = EditorUtils.getTransactionalEditingDomain(editorPart.getServicesRegistry()); // Set Viewer input if it already exist if (getCommonViewer() != null) { getCommonViewer().setInput(editorPart.getServicesRegistry()); } editingDomain.addResourceSetListener(resourceSetListener); } catch (ServiceException e) { // Can't get EditingDomain, skip } // Listen to isDirty flag saveAndDirtyService.addInputChangedListener(editorInputChangedListener); // Hook // if(undoHandler != null){ // IUndoContext undoContext = getUndoContext(part); // undoHandler.setContext(undoContext); // undoHandler.update(); // redoHandler.setContext(undoContext); // redoHandler.update(); // } } if (this.getCommonViewer() != null) { refresh(); } } /** * Get the undo context associated to the part. * * @param part * @return */ private IUndoContext getUndoContext(IMultiDiagramEditor part) { return (IUndoContext) part.getAdapter(IUndoContext.class); } /** * Deactivate the Model Explorer. */ private void deactivate() { // deactivate global handler if (editorPart != null) { if (Activator.log.isDebugEnabled()) { Activator.log.debug("deactivate " + editorPart.getTitle()); //$NON-NLS-1$ } // Stop Listenning to isDirty flag saveAndDirtyService.removeInputChangedListener(editorInputChangedListener); // unhook // IUndoContext undoContext = getUndoContext(editorPart); // undoHandler.setContext(undoContext); // undoHandler.update(); // redoHandler.setContext(undoContext); // redoHandler.update(); } editorPart = null; if (editingDomain != null) { editingDomain.removeResourceSetListener(resourceSetListener); } } /** * {@inheritDoc} */ @Override public void dispose() { super.dispose(); deactivate(); } /** * Retrieves the {@link IPropertySheetPage} that his Model Explorer uses. * * @return */ private IPropertySheetPage getPropertySheetPage() { final IMultiDiagramEditor multiDiagramEditor = EditorUtils.getMultiDiagramEditor(); if (multiDiagramEditor != null) { if (propertySheetPage == null) { if (multiDiagramEditor instanceof ITabbedPropertySheetPageContributor) { ITabbedPropertySheetPageContributor contributor = (ITabbedPropertySheetPageContributor) multiDiagramEditor; this.propertySheetPage = new TabbedPropertySheetPage(contributor); } } return propertySheetPage; } return null; } /** * in order to see element if the property view */ @SuppressWarnings("rawtypes") public Object getAdapter(Class adapter) { if (IPropertySheetPage.class.equals(adapter)) { return getPropertySheetPage(); } if (IUndoContext.class.equals(adapter)) { // Return the IUndoContext of the currently selected editor. if (editorPart != null) { return editorPart.getAdapter(IUndoContext.class); } // Let the parent return the adapter. } if (ISaveablePart.class.equals(adapter)) { return saveAndDirtyService; } return super.getAdapter(adapter); } /** * {@inheritDoc} * * @return the EditingDomain used by the properties view */ public EditingDomain getEditingDomain() { return editingDomain; } /** * {@inheritDoc} */ @Override public void selectReveal(ISelection selection) { if (getCommonViewer() != null) { getCommonViewer().setSelection(selection, true); } } public void expandItems(List<Object> treeElementList, TreeItem[] list) { //the treeElement has more tan one element if (treeElementList.size() > 0) { for (int i = 0; i < list.length; i++) { if (list[i].getData() != null && list[i].getData().equals(treeElementList.get(0))) { if (treeElementList.size() > 1) {//Do no expand the last Object[] toexpand = { treeElementList.get(0) }; getCommonViewer().setExpandedElements(toexpand); } ArrayList<Object> tmpList = new ArrayList<Object>(); tmpList.addAll(treeElementList); tmpList.remove(tmpList.get(0)); expandItems(tmpList, list[i].getItems()); } } } } /** * {@inheritDoc} */ public void revealSemanticElement(List<?> elementList) { //for each element we reveal it Iterator<?> elementListIterator = elementList.iterator(); ArrayList<Object> treeElementToSelect = new ArrayList<Object>(); while (elementListIterator.hasNext()) { Object currentElement = (Object) elementListIterator.next(); //test if the type is an EObject if (currentElement instanceof EObject) { EObject currentEObject = (EObject) currentElement; //the content provider exist? if (getCommonViewer().getContentProvider() != null) { //need the root in order to find all element in the tree Object root = getCommonViewer().getInput(); //look for the path in order to access to this element List<Object> path = searchPath(currentEObject, Arrays.asList( ((ITreeContentProvider) getCommonViewer().getContentProvider()).getElements(root))); if (path.size() > 0) { //expand in the common viewer the path expandItems(path, getCommonViewer().getTree().getItems()); treeElementToSelect.add(path.get(path.size() - 1)); } } } selectReveal(new StructuredSelection(treeElementToSelect)); } } }