/******************************************************************************* * This file is protected by Copyright. * Please refer to the COPYRIGHT file distributed with this source distribution. * * This file is part of REDHAWK IDE. * * 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 *******************************************************************************/ package gov.redhawk.ide.sad.internal.ui.editor; import gov.redhawk.diagram.DiagramUtil; import gov.redhawk.diagram.editor.URIEditorInputProxy; import gov.redhawk.ide.internal.ui.handlers.CleanUpComponentFilesAction; import gov.redhawk.ide.sad.ui.SadUiActivator; import gov.redhawk.model.sca.ScaWaveform; import gov.redhawk.model.sca.util.ModelUtil; import gov.redhawk.sca.sad.diagram.SadDiagramUtilHelper; import gov.redhawk.sca.sad.diagram.part.SadDiagramEditor; import gov.redhawk.sca.util.PluginUtil; import gov.redhawk.ui.editor.SCAFormEditor; import java.io.IOException; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import mil.jpeojtrs.sca.prf.provider.PrfItemProviderAdapterFactory; import mil.jpeojtrs.sca.sad.SadPackage; import mil.jpeojtrs.sca.sad.SoftwareAssembly; import mil.jpeojtrs.sca.sad.provider.SadItemProviderAdapterFactory; import mil.jpeojtrs.sca.scd.provider.ScdItemProviderAdapterFactory; import mil.jpeojtrs.sca.spd.provider.SpdItemProviderAdapterFactory; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceDelta; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.emf.common.command.BasicCommandStack; import org.eclipse.emf.common.notify.AdapterFactory; import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.common.notify.impl.AdapterImpl; import org.eclipse.emf.common.ui.URIEditorInput; import org.eclipse.emf.common.ui.viewer.IViewerProvider; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EValidator; import org.eclipse.emf.ecore.impl.EStructuralFeatureImpl.ContainmentUpdatingFeatureMapEntry; import org.eclipse.emf.ecore.provider.EcoreItemProviderAdapterFactory; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain; import org.eclipse.emf.edit.provider.AdapterFactoryItemDelegator; import org.eclipse.emf.edit.provider.ComposedAdapterFactory; import org.eclipse.emf.edit.provider.DelegatingWrapperItemProvider; import org.eclipse.emf.transaction.TransactionalEditingDomain; import org.eclipse.gef.EditPart; import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart; import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart; import org.eclipse.gmf.runtime.diagram.ui.parts.IDiagramEditDomain; import org.eclipse.gmf.runtime.diagram.ui.parts.IDiagramGraphicalViewer; import org.eclipse.gmf.runtime.diagram.ui.parts.IDiagramWorkbenchPart; import org.eclipse.gmf.runtime.diagram.ui.properties.views.PropertiesBrowserPage; import org.eclipse.gmf.runtime.diagram.ui.resources.editor.ide.document.FileEditorInputProxy; import org.eclipse.gmf.runtime.emf.core.util.EMFCoreUtil; import org.eclipse.gmf.runtime.notation.Diagram; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.IStatusLineManager; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.ui.IActionBars; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IFileEditorInput; import org.eclipse.ui.PartInitException; import org.eclipse.ui.forms.editor.IFormPage; import org.eclipse.ui.ide.IGotoMarker; import org.eclipse.ui.part.MultiPageSelectionProvider; import org.eclipse.ui.statushandlers.StatusManager; import org.eclipse.ui.views.contentoutline.IContentOutlinePage; import org.eclipse.ui.views.properties.IPropertySheetPage; import org.eclipse.ui.views.properties.tabbed.ITabbedPropertySheetPageContributor; import CF.Application; /** * This is an example of a Sad model editor. */ public class SadEditor extends SCAFormEditor implements ITabbedPropertySheetPageContributor, IDiagramWorkbenchPart, IViewerProvider { public static final String ID = "gov.redhawk.ide.sad.ui.editor.presentation.SadEditorID"; public static final String EDITING_DOMAIN_ID = SadDiagramEditor.EDITING_DOMAIN_ID; private static final String DIAGRAM_PAGE_ID = "2"; /** * This is the content outline page. */ private IContentOutlinePage contentOutlinePage; /** * This is a kludge... */ private IStatusLineManager contentOutlineStatusLineManager; /** * This is the content outline page's viewer. */ private TreeViewer contentOutlineViewer; /** * The graphical diagram editor embedded into this editor. */ private SadDiagramEditor diagramEditor; /** * This keeps track of the active content viewer, which may be either one of * the viewers in the pages or the content outline viewer. */ private Viewer currentViewer; /** * This selection provider coordinates the selections of the various editor * parts. */ private final MultiPageSelectionProvider selectionProvider; private IEditorInput wrappedInput; private ResourceListener nameListener; private IFormPage overviewPage; private IFormPage propertiesPage; private class ResourceListener extends AdapterImpl { private SoftwareAssembly sad; private final Resource sadResource; public ResourceListener(final Resource spdResource) { this.sadResource = spdResource; if (this.sadResource != null) { this.sadResource.eAdapters().add(this); this.sad = getSoftwareAssembly(); if (this.sad != null) { this.sad.eAdapters().add(this); updateTitle(); } } } /** * Gets the soft pkg. * * @return the soft pkg */ private SoftwareAssembly getSoftwareAssembly() { return ModelUtil.getSoftwareAssembly(this.sadResource); } public void dispose() { if (this.sad != null) { this.sad.eAdapters().remove(this); } if (this.sadResource != null) { this.sadResource.eAdapters().remove(this); } } /** * {@inheritDoc} */ @Override public void notifyChanged(final Notification msg) { if (msg.getNotifier() instanceof Resource) { switch (msg.getFeatureID(Resource.class)) { case Resource.RESOURCE__IS_LOADED: if (this.sad != null) { this.sad.eAdapters().remove(this); this.sad = null; } if (this.sadResource.isLoaded()) { this.sad = getSoftwareAssembly(); if (this.sad != null) { this.sad.eAdapters().add(this); updateTitle(); } } break; default: break; } } else if (msg.getNotifier() instanceof SoftwareAssembly) { final int featureID = msg.getFeatureID(SoftwareAssembly.class); if (featureID == SadPackage.SOFTWARE_ASSEMBLY__NAME) { if (msg.getEventType() == Notification.SET) { updateTitle(); } } } } } /** * This creates a model editor. */ public SadEditor() { super(); this.selectionProvider = new MultiPageSelectionProvider(this); this.selectionProvider.addSelectionChangedListener(new ISelectionChangedListener() { @Override public void selectionChanged(final SelectionChangedEvent event) { setStatusLineManager(event.getSelection()); } }); } /** * This is here for the listener to be able to call it. */ @Override protected void firePropertyChange(final int action) { super.firePropertyChange(action); } /** * {@inheritDoc} */ @Override public void setActivePage(final int pageIndex) { if (pageIndex >= 0 && pageIndex < getPageCount()) { super.setActivePage(pageIndex); } } /** * Lazy initialization of the wrapped editor input. * * @return */ protected IEditorInput getWrappedInput() { if (this.wrappedInput == null) { if (getEditorInput() instanceof IFileEditorInput) { this.wrappedInput = new FileEditorInputProxy((IFileEditorInput) getEditorInput(), (TransactionalEditingDomain) getEditingDomain()); } else if (getEditorInput() instanceof URIEditorInput) { this.wrappedInput = new URIEditorInputProxy((URIEditorInput) getEditorInput(), (TransactionalEditingDomain) getEditingDomain()); } else { // should not happen, but who knows... this.wrappedInput = getEditorInput(); } } return this.wrappedInput; } /** * This sets the selection into whichever viewer is active. */ @Override public void setSelectionToViewer(final Collection< ? > collection) { final Collection< ? > theSelection = collection; // Make sure it's okay. // if (theSelection != null && !theSelection.isEmpty()) { // I don't know if this should be run this deferred // because we might have to give the editor a chance to process the // viewer update events // and hence to update the views first. // // final Runnable runnable = new Runnable() { @Override public void run() { // Try to select the items in the current content viewer of // the editor. // if (SadEditor.this.currentViewer != null) { SadEditor.this.currentViewer.setSelection(new StructuredSelection(theSelection.toArray()), true); } } }; runnable.run(); } } /** * This makes sure that one content viewer, either for the current page or * the outline view, if it has focus, is the current one. */ public void setCurrentViewer(final Viewer viewer) { // If it is changing... // if (this.currentViewer != viewer) { // Remember it. // this.currentViewer = viewer; } } /** * This returns the viewer as required by the {@link IViewerProvider} * interface. */ @Override public Viewer getViewer() { return this.currentViewer; } /** * This is how the framework determines which interfaces we implement. */ @SuppressWarnings({ "unchecked" }) @Override public Object getAdapter(@SuppressWarnings("rawtypes") final Class key) { if (key.equals(IPropertySheetPage.class)) { return getPropertySheetPage(); } else if (key.equals(IGotoMarker.class)) { return this; } else if (key.equals(ScaWaveform.class)) { return PluginUtil.adapt(ScaWaveform.class, getSoftwareAssembly()); } else if (key.isAssignableFrom(Application.class)) { return PluginUtil.adapt(ScaWaveform.class, getSoftwareAssembly()); } else { return super.getAdapter(key); } } /** * This accesses a cached version of the content outliner. */ public IContentOutlinePage getContentOutlinePage() { return this.contentOutlinePage; } /** * This accesses a cached version of the property sheet. */ public IPropertySheetPage getPropertySheetPage() { return new PropertiesBrowserPage(this); } @Override protected String getPropertyEditorPageKey(final IFileEditorInput input) { final String retVal = super.getPropertyEditorPageKey(input); if (retVal == null) { return DIAGRAM_PAGE_ID; } return retVal; } /** * This deals with how we want selection in the outliner to affect the other * views. */ @SuppressWarnings("unchecked") public void handleContentOutlineSelection(final Object selection) { // // If the diagram viewer is active, we need to map the selection // // to the corresponding EditParts. final List<Object> selectionList = new ArrayList<Object>(); if (selection instanceof DelegatingWrapperItemProvider) { final Object item = ((DelegatingWrapperItemProvider) selection).getValue(); if (item instanceof ContainmentUpdatingFeatureMapEntry) { final Object value = ((ContainmentUpdatingFeatureMapEntry) item).getValue(); if (value instanceof EObject) { final String elementID = EMFCoreUtil.getProxyID((EObject) value); selectionList.addAll(this.diagramEditor.getDiagramGraphicalViewer().findEditPartsForElement(elementID, IGraphicalEditPart.class)); } this.selectionProvider.setSelection(new StructuredSelection(selectionList)); } else if (item instanceof DelegatingWrapperItemProvider) { this.handleContentOutlineSelection(item); } } } @Override public void gotoMarker(final IMarker marker) { try { if (marker.getType().equals(EValidator.MARKER)) { final String uriAttribute = marker.getAttribute(EValidator.URI_ATTRIBUTE, null); if (uriAttribute != null) { final URI uri = URI.createURI(uriAttribute); final EObject eObject = getEditingDomain().getResourceSet().getEObject(uri, true); if (eObject != null) { setSelectionToViewer(Collections.singleton(getWrapper(eObject))); } } } } catch (final CoreException exception) { StatusManager.getManager().handle(new Status(IStatus.ERROR, SadUiActivator.getPluginId(), "Failed to go to marker.", exception), StatusManager.LOG | StatusManager.SHOW); } } private Object getWrapper(final EObject eObject) { return AdapterFactoryEditingDomain.getWrapper(eObject, getEditingDomain()); } public void setStatusLineManager(final ISelection selection) { final IStatusLineManager statusLineManager; if (this.currentViewer != null && this.currentViewer == this.contentOutlineViewer) { statusLineManager = this.contentOutlineStatusLineManager; } else { statusLineManager = getActionBars().getStatusLineManager(); } if (statusLineManager != null) { if (selection instanceof IStructuredSelection) { final Collection< ? > collection = ((IStructuredSelection) selection).toList(); switch (collection.size()) { case 0: statusLineManager.setMessage("Selected Nothing"); break; case 1: final String text = new AdapterFactoryItemDelegator(getAdapterFactory()).getText(collection.iterator().next()); statusLineManager.setMessage(MessageFormat.format("Selected Object: {0}", text)); break; default: statusLineManager.setMessage(MessageFormat.format("Selected {0} Objects", Integer.toString(collection.size()))); break; } } else { statusLineManager.setMessage(""); } } } /** * {@inheritDoc} */ @Override public boolean isDirty() { if (this.getMainResource() != null && !this.getMainResource().getURI().isPlatform()) { return false; } return super.isDirty(); } /** * This implements {@link org.eclipse.jface.action.IMenuListener} to help * fill the context menus with contributions from the Edit menu. */ @Override public void menuAboutToShow(final IMenuManager menuManager) { ((IMenuListener) getEditorSite().getActionBarContributor()).menuAboutToShow(menuManager); } @Override public void dispose() { if (this.contentOutlinePage != null) { this.contentOutlinePage.dispose(); } if (this.nameListener != null) { this.nameListener.dispose(); this.nameListener = null; } super.dispose(); } /* * (non-Javadoc) * * @see * org.eclipse.ui.views.properties.tabbed.ITabbedPropertySheetPageContributor * #getContributorId() */ @Override public String getContributorId() { if (this.diagramEditor == null) { return null; } return this.diagramEditor.getContributorId(); } /* * (non-Javadoc) * * @see * org.eclipse.gmf.runtime.diagram.ui.parts.IDiagramWorkbenchPart#getDiagram * () */ @Override public Diagram getDiagram() { if (this.diagramEditor == null) { return null; } return this.diagramEditor.getDiagram(); } /* * (non-Javadoc) * * @seeorg.eclipse.gmf.runtime.diagram.ui.parts.IDiagramWorkbenchPart# * getDiagramEditDomain() */ @Override public IDiagramEditDomain getDiagramEditDomain() { if (this.diagramEditor == null) { return null; } return this.diagramEditor.getDiagramEditDomain(); } /* * (non-Javadoc) * * @seeorg.eclipse.gmf.runtime.diagram.ui.parts.IDiagramWorkbenchPart# * getDiagramEditPart() */ @Override public DiagramEditPart getDiagramEditPart() { if (this.diagramEditor == null) { return null; } return this.diagramEditor.getDiagramEditPart(); } /* * (non-Javadoc) * * @seeorg.eclipse.gmf.runtime.diagram.ui.parts.IDiagramWorkbenchPart# * getDiagramGraphicalViewer() */ @Override public IDiagramGraphicalViewer getDiagramGraphicalViewer() { if (this.diagramEditor == null) { return null; } return this.diagramEditor.getDiagramGraphicalViewer(); } /** * {@inheritDoc} */ @Override public String getTitle() { String name = null; final SoftwareAssembly sad = getSoftwareAssembly(); if (sad != null) { name = sad.getName(); if (name == null) { name = getEditorInput().getName(); } } if (name != null) { return name; } else { return super.getTitle(); } } /** * @return */ private SoftwareAssembly getSoftwareAssembly() { return ModelUtil.getSoftwareAssembly(getMainResource()); } /** * {@inheritDoc} */ @Override protected void addPages() { // Only creates the other pages if there is something that can be edited // if (!getEditingDomain().getResourceSet().getResources().isEmpty() && !(getEditingDomain().getResourceSet().getResources().get(0)).getContents().isEmpty()) { try { int pageIndex = 0; final Resource sadResource = getMainResource(); addNameListener(sadResource); final IFormPage page = createOverviewPage(sadResource); setOverviewPage(page); this.addPage(page); this.propertiesPage = createPropertiesPage(sadResource); addPage(propertiesPage); final SadDiagramEditor editor = createDiagramEditor(); setDiagramEditor(editor); final IEditorInput diagramInput = createDiagramInput(sadResource); pageIndex = addPage(editor, diagramInput); setPageText(pageIndex, "Diagram"); final IEditorPart textEditor = createTextEditor(getEditorInput()); if (textEditor != null) { final int sadSourcePageNum = addPage(textEditor, this.getEditorInput()); this.setPageText(sadSourcePageNum, this.getEditorInput().getName()); } getEditingDomain().getCommandStack().removeCommandStackListener(getCommandStackListener()); } catch (final PartInitException e) { StatusManager.getManager().handle(new Status(IStatus.ERROR, SadUiActivator.getPluginId(), "Failed to create editor parts.", e), StatusManager.LOG | StatusManager.SHOW); } catch (final IOException e) { StatusManager.getManager().handle(new Status(IStatus.ERROR, SadUiActivator.getPluginId(), "Failed to create editor parts.", e), StatusManager.LOG | StatusManager.SHOW); } catch (final CoreException e) { StatusManager.getManager().handle(new Status(IStatus.ERROR, SadUiActivator.getPluginId(), "Failed to create editor parts.", e), StatusManager.LOG | StatusManager.SHOW); } } } public IFormPage getPropertiesPage() { return propertiesPage; } protected IFormPage createPropertiesPage(Resource sadResource) { SadPropertiesPage retVal = new SadPropertiesPage(this, "propertiesPage", "Properties", true); retVal.setInput(sadResource); return retVal; } protected void addNameListener(final Resource sadResource) { this.nameListener = new ResourceListener(sadResource); } protected IEditorInput createDiagramInput(final Resource sadResource) throws IOException, CoreException { final URI diagramURI = DiagramUtil.getDiagramResourceURI(SadDiagramUtilHelper.INSTANCE, sadResource); DiagramUtil.initializeDiagramResource(SadDiagramUtilHelper.INSTANCE, diagramURI, sadResource); return DiagramUtil.getDiagramWrappedInput(diagramURI, (TransactionalEditingDomain) this.getEditingDomain()); } protected SadDiagramEditor createDiagramEditor() { return new CustomDiagramEditor(this); } protected void setDiagramEditor(final SadDiagramEditor diagramEditor) { this.diagramEditor = diagramEditor; } /** * */ protected IFormPage createOverviewPage(final Resource sadResource) { final SadOverviewPage retVal = new SadOverviewPage(this); retVal.setInput(sadResource); return retVal; } protected void setOverviewPage(final IFormPage overviewPage) { this.overviewPage = overviewPage; } /** * {@inheritDoc} */ @Override protected void handleDocumentChange(final Resource resource) { super.handleDocumentChange(resource); for (final Object part : this.getDiagramEditPart().getChildren()) { if (part instanceof EditPart) { ((EditPart) part).refresh(); } } } /** * {@inheritDoc} */ @Override protected IContentOutlinePage createContentOutline() { IContentOutlinePage myOutline = (IContentOutlinePage) this.diagramEditor.getAdapter(IContentOutlinePage.class); if (myOutline == null) { myOutline = new WaveformOutlinePage(this); } this.contentOutlinePage = myOutline; // Listen to selection so that we can handle it is a special way. // // this.contentOutlinePage.addSelectionChangedListener(new ISelectionChangedListener() { // // This ensures that we handle selections correctly. // // @Override public void selectionChanged(final SelectionChangedEvent event) { handleContentOutlineSelection(event.getSelection()); } }); return this.contentOutlinePage; } /** * {@inheritDoc} */ @Override public String getEditingDomainId() { return SadEditor.EDITING_DOMAIN_ID; } /** * {@inheritDoc} */ @Override protected AdapterFactory getSpecificAdapterFactory() { final ComposedAdapterFactory factory = new ComposedAdapterFactory(); factory.addAdapterFactory(new SadItemProviderAdapterFactory()); factory.addAdapterFactory(new EcoreItemProviderAdapterFactory()); factory.addAdapterFactory(new SpdItemProviderAdapterFactory()); factory.addAdapterFactory(new ScdItemProviderAdapterFactory()); factory.addAdapterFactory(new PrfItemProviderAdapterFactory()); return factory; } public IActionBars getActionBars() { return getActionBarContributor().getActionBars(); } @Override public List<Object> getOutlineItems() { final List<Object> myList = new ArrayList<Object>(); if (this.overviewPage != null) { myList.add(this.overviewPage); } if (getSoftwareAssembly().getPartitioning() != null) { myList.add(getSoftwareAssembly().getPartitioning()); } return myList; } @Override protected void emfDoSave(final IProgressMonitor progressMonitor) { // Refresh the necessary state. We are delegating the save to the diagram page // ((BasicCommandStack) getEditingDomain().getCommandStack()).saveIsDone(); } @Override public boolean isPersisted(final Resource resource) { return resource.getURI().equals(getSoftwareAssembly().eResource().getURI()) && super.isPersisted(resource); } @Override public void doSave(final IProgressMonitor monitor) { final CleanUpComponentFilesAction cleanAction = new CleanUpComponentFilesAction(); cleanAction.setRoot(getSoftwareAssembly()); cleanAction.run(); super.doSave(monitor); } /** * {@inheritDoc} */ @Override protected void resourceChanged(final IResource resource, final IResourceDelta delta) { //Make sure we don't call resource changed on a non sad resource if (this.isValidSadResource(resource) && !delta.getResource().getWorkspace().isAutoBuilding()) { super.resourceChanged(resource, delta); } validate(); } /** * Evaluate the given resource to determine if it is a resource that can be associated with the SadEditor. * * @param resource The IResource to evaluate * @return <code> true </code> if this is an sad resource; <code> false </code> otherwise */ private boolean isValidSadResource(final IResource resource) { final String path = resource.getFullPath().toOSString(); if (path.endsWith(SadPackage.FILE_EXTENSION)) { return true; } return false; } public SadDiagramEditor getDiagramEditor() { return this.diagramEditor; } }