/* * JBoss, Home of Professional Open Source. * * See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing. * * See the AUTHORS.txt file distributed with this work for a full listing of individual contributors. */ package org.teiid.designer.ui.editors; import java.util.ArrayList; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.IStatus; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IEditorReference; import org.eclipse.ui.IFileEditorInput; import org.eclipse.ui.IPartListener; import org.eclipse.ui.ISelectionListener; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.PartInitException; import org.eclipse.ui.ide.IDE; import org.eclipse.ui.part.IPage; import org.eclipse.ui.part.PageBookView; import org.teiid.designer.core.ModelerCore; import org.teiid.designer.core.workspace.ModelResource; import org.teiid.designer.ui.UiConstants; import org.teiid.designer.ui.UiPlugin; import org.teiid.designer.ui.common.eventsupport.SelectionUtilities; import org.teiid.designer.ui.explorer.ModelExplorerResourceNavigator; import org.teiid.designer.ui.outline.ModelOutlinePage; import org.teiid.designer.ui.views.ModelViewer; import org.teiid.designer.ui.viewsupport.ModelUtilities; /** * <p> * ModelEditorSelectionSynchronizer monitors selection in the WorkbenchWindow to synchronize selection of Model Objects (EObjects) * with the appropriate ModelEditor and it's ModelEditorPages. This class also provides double-click control of ModelEditor for * model objects. * </p> * <p> * The Eclipse UI handles launching editors from IResource objects such as model files and selection synchronization between the * editor and it's corresponding IResource. It is up to this class to handle selection and double-click functionality for objects * within the model IResource. * </p> * <p> * Every ModelEditor has a SelecitonSynchronizer, and synchronization is performed only by the instance whose ModelEditor contains * the appropriate model. * </p> * * @since 8.0 */ public class ModelEditorSelectionSynchronizer implements IPartListener, ISelectionListener, ISelectionProvider, IDoubleClickListener, UiConstants { // ========================================================= // Static /** * Static method for ModelViewers to kick off editors from outside the internal editors framework. */ public static void handleDoubleClick(DoubleClickEvent event) { IStructuredSelection selection = (IStructuredSelection)event.getSelection(); Object object = selection.getFirstElement(); if (object != null) { IFile file = null; if (object instanceof EObject) { // get the model file corresponding to the target ModelResource mdlRsrc = ModelUtilities.getModelResourceForModelObject((EObject)object); if (mdlRsrc != null) { file = (IFile)mdlRsrc.getResource(); } } if (file != null) { IWorkbenchPage page = UiPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow().getActivePage(); if (page != null) { // look through the open editors and see if there is one available for this model file. IEditorReference[] editors = page.getEditorReferences(); for (int i = 0; i < editors.length; ++i) { IEditorPart editor = editors[i].getEditor(false); if (editor != null) { IEditorInput input = editor.getEditorInput(); if (input instanceof IFileEditorInput) { if (file.equals(((IFileEditorInput)input).getFile())) { // found the correct editor - no need to do anything, it's synchronizer will handle return; } } } } // there is no editor open for this object. Open one and hand it the double-click target. try { IEditorPart editor = IDE.openEditor(page, file); if (editor instanceof ModelEditor) { // pass on the double-click, since it's synchronizer wasn't alive to hear it. ((ModelEditor)editor).openModelObject(object); } } catch (PartInitException e) { e.printStackTrace(); } } } } } /** * Static method to determine if there are any ModelEditorSelectionSynchronzer instances available to handle the double-click * of an arbitrary EObject from a ModelViewer. * * @param target * the EObject that was double-clicked * @param instance * the instance of this class that wants to know if it should process the double- click through it's editor. * @return true if the instance should handle the double-click */ private static boolean shouldHandleDoubleClick(Object target, ModelEditorSelectionSynchronizer instance) { // get the model file corresponding to the target IFile file = null; ModelResource modelResrc = null; if (target instanceof EObject) { modelResrc = ModelUtilities.getModelResourceForModelObject((EObject)target); } else if (target instanceof Resource) { modelResrc = ModelerCore.getModelWorkspace().findModelResource((Resource)target); } else if (target instanceof ModelResource) { modelResrc = (ModelResource)target; } if (modelResrc == null) { Util.log(IStatus.WARNING, Util.getString("ModelEditorSelectionSynchronizer.invalidTarget")); //$NON-NLS-1$ return false; } file = (IFile)modelResrc.getResource(); // if the target is inside the synchronizer instance's model file, then handle double-click if (instance.modelFile.equals(file)) { // make sure the instance part is the active editor; if not, activate it IWorkbenchPage page = UiPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow().getActivePage(); if (page != null && page.getActiveEditor() != instance.modelEditor) { page.bringToTop(instance.modelEditor); } // tell the calling instance to go ahead and handle the double-click return true; } // look through the open editors and see if there is one available for this model file. IEditorReference[] editors = instance.modelEditor.getEditorSite().getPage().getEditorReferences(); for (int i = 0; i < editors.length; ++i) { IEditorPart editor = editors[i].getEditor(false); if (editor != null) { IEditorInput input = editor.getEditorInput(); if (input instanceof IFileEditorInput) { if (file.equals(((IFileEditorInput)input).getFile())) { // found the correct editor - no need to do anything, it's synchronizer will handle return false; } } } } // there is no editor open for this object. Open one and hand it the double-click target. try { IEditorPart editor = IDE.openEditor(instance.modelEditor.getEditorSite().getPage(), file); if (editor instanceof ModelEditor) { // pass on the double-click, since it's synchronizer wasn't alive to hear it. ((ModelEditor)editor).openModelObject(target); } } catch (PartInitException e) { e.printStackTrace(); } return false; } // ========================================================= // Variables private ModelEditor modelEditor; private IFile modelFile; private ISelection lastSelection; private ArrayList registeredViewers = new ArrayList(); // ========================================================= // Constructors /** * Construct an instance of ModelEditorSelectionSynchronizer. * * @param editor * the ModelEditor that this instance will be synchronizing across pages and views. * @param model * the Resource that corresponds to the model that this editor is editing. */ ModelEditorSelectionSynchronizer(ModelEditor editor, IFile editorInput) { this.modelEditor = editor; this.modelFile = editorInput; editor.getSite().getWorkbenchWindow().getPartService().addPartListener(this); } // ========================================================= // Methods /** * When an IWorkbenchPart is activated, this method checks to see if the part is, or contains a ModelViewer. If so, it hooks * up the ModelViewer to enable it to control the correct ModelEditor and be synchronized with other ModelViewers in the * workbench. * * @see org.eclipse.ui.IPartListener#partActivated(org.eclipse.ui.IWorkbenchPart) */ @Override public synchronized void partActivated(IWorkbenchPart part) { if (part instanceof ModelViewer) { register((ModelViewer)part); } else if (part instanceof PageBookView) { PageBookView pbv = (PageBookView)part; IPage page = pbv.getCurrentPage(); if (page instanceof ModelViewer) { register((ModelViewer)page); } else if (page instanceof ModelOutlinePage) { // go one more level to pick up any contributed outline pages Object innerPage = ((ModelOutlinePage)page).getCurrentViewer(); if (innerPage instanceof ModelViewer) { register((ModelViewer)innerPage); } } } } /* * (non-Javadoc) * * @see org.eclipse.ui.IPartListener#partBroughtToTop(org.eclipse.ui.IWorkbenchPart) */ @Override public void partBroughtToTop(IWorkbenchPart part) { } /* * (non-Javadoc) * * @see org.eclipse.ui.IPartListener#partClosed(org.eclipse.ui.IWorkbenchPart) */ @Override public void partClosed(IWorkbenchPart part) { if (part instanceof ModelViewer) { unregister((ModelViewer)part); } } /* * (non-Javadoc) * * @see org.eclipse.ui.IPartListener#partDeactivated(org.eclipse.ui.IWorkbenchPart) */ @Override public void partDeactivated(IWorkbenchPart part) { } /* * (non-Javadoc) * * @see org.eclipse.ui.IPartListener#partOpened(org.eclipse.ui.IWorkbenchPart) */ @Override public void partOpened(IWorkbenchPart part) { if (part instanceof ModelViewer) { register((ModelViewer)part); } else if (part instanceof PageBookView) { PageBookView pbv = (PageBookView)part; IPage page = pbv.getCurrentPage(); if (page instanceof ModelViewer) { register((ModelViewer)page); } } } /** * Called by the SelectionService to indicate that a selection has changed in the workbench. Responds by determining if the * selection is an EObject and, if so, sends the selection to this synchronizer's ModelEditor * * @see org.eclipse.ui.ISelectionListener#selectionChanged(org.eclipse.ui.IWorkbenchPart, * org.eclipse.jface.viewers.ISelection) */ @Override public void selectionChanged(IWorkbenchPart part, ISelection selection) { final boolean startedTxn = ModelerCore.startTxn(false, false, null, this); boolean succeeded = false; try { // selection changed is only sent to the ModelEditorPage source IWorkbenchPart // the active part in the workbench, and the part is not the ModelEditor itself. if (isActivePart(part) && !(part instanceof ModelEditor)) { // if the selection is a single EObject... if (selection instanceof IStructuredSelection) { if (((IStructuredSelection)selection).size() == 1) { Object o = ((IStructuredSelection)selection).getFirstElement(); if (o instanceof EObject) { lastSelection = selection; // ... then send it to the current editor page's SelectionChangedListener ModelEditorPage page = (ModelEditorPage)this.modelEditor.getCurrentPage(); if (page != null && page.getModelObjectSelectionChangedListener() != null) { page.getModelObjectSelectionChangedListener() .selectionChanged(new SelectionChangedEvent(this, selection)); } modelEditor.setSelection(selection); } } else if( SelectionUtilities.isMultiSelection(selection)) { int nObjects = SelectionUtilities.getSelectedObjects(selection).size(); int nEObjects = SelectionUtilities.getSelectedEObjects(selection).size(); if( nObjects == nEObjects ) { lastSelection = selection; // ... then send it to the current editor page's SelectionChangedListener ModelEditorPage page = (ModelEditorPage)this.modelEditor.getCurrentPage(); if (page != null && page.getModelObjectSelectionChangedListener() != null) { page.getModelObjectSelectionChangedListener() .selectionChanged(new SelectionChangedEvent(this, selection)); } modelEditor.setSelection(selection); } } else if( SelectionUtilities.isEmptySelection(selection)) { ModelEditorPage page = (ModelEditorPage)this.modelEditor.getCurrentPage(); if (page != null && page.getModelObjectSelectionChangedListener() != null) { page.getModelObjectSelectionChangedListener() .selectionChanged(new SelectionChangedEvent(this, selection)); } modelEditor.setSelection(selection); } } } succeeded = true; } finally { if (startedTxn) { if (succeeded) ModelerCore.commitTxn(); else ModelerCore.rollbackTxn(); } } } /* * (non-Javadoc) * * @see org.eclipse.jface.viewers.ISelectionProvider#getSelection() */ @Override public ISelection getSelection() { return lastSelection; } /* * (non-Javadoc) * * @see org.eclipse.jface.viewers.ISelectionProvider#addSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener) */ @Override public void addSelectionChangedListener(ISelectionChangedListener listener) { // functionality not provided - // this class implements ISelectionProvider only to be the source of SelectionChangeEvent } /* * (non-Javadoc) * * @see org.eclipse.jface.viewers.ISelectionProvider#removeSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener) */ @Override public void removeSelectionChangedListener(ISelectionChangedListener listener) { // functionality not provided - // this class implements ISelectionProvider only to be the source of SelectionChangeEvent } /* * (non-Javadoc) * * @see org.eclipse.jface.viewers.ISelectionProvider#setSelection(org.eclipse.jface.viewers.ISelection) */ @Override public void setSelection(ISelection selection) { lastSelection = selection; selectionChanged(this.modelEditor, selection); } /* * (non-Javadoc) * * @see org.eclipse.jface.viewers.IDoubleClickListener#doubleClick(org.eclipse.jface.viewers.DoubleClickEvent) */ @Override public void doubleClick(DoubleClickEvent event) { // first, get the object out of the event and make sure this is the correct editor IStructuredSelection selection = (IStructuredSelection)event.getSelection(); Object object = selection.getFirstElement(); if (object != null) { if (object instanceof EObject) { // check with the static handler to make sure this is the right editor if (shouldHandleDoubleClick(object, this)) { // Changed per defect 16869 Need to force a change in the // object in the t-editor if open already // Replaced the call below with a ModelEditorManager call. // modelEditor.openModelObject(object); ModelEditorManager.open((EObject)object, false, UiConstants.ObjectEditor.REFRESH_EDITOR_IF_OPEN); } } } } protected synchronized void register(ModelViewer viewer) { if (!registeredViewers.contains(viewer)) { // hook up selection if this is a new ModelViewer if (!(viewer instanceof ModelExplorerResourceNavigator)) viewer.addModelObjectDoubleClickListener(this); registeredViewers.add(viewer); } } protected synchronized void unregister(ModelViewer viewer) { // unhook this ModelViewer viewer.removeModelObjectDoubleClickListener(this); registeredViewers.remove(viewer); } public void dispose() { Object[] viewArray = registeredViewers.toArray(); for (int i = 0; i < viewArray.length; ++i) { unregister((ModelViewer)viewArray[i]); } this.modelEditor.getSite().getWorkbenchWindow().getPartService().removePartListener(this); } private boolean isActivePart(IWorkbenchPart part) { return part == modelEditor.getEditorSite().getWorkbenchWindow().getPartService().getActivePart(); } }