/**
* 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.ui.dcd.editor.presentation;
import gov.redhawk.diagram.DiagramUtil;
import gov.redhawk.diagram.editor.URIEditorInputProxy;
import gov.redhawk.model.sca.ScaPackage;
import gov.redhawk.model.sca.util.ModelUtil;
import gov.redhawk.sca.dcd.diagram.DcdDiagramUtilHelper;
import gov.redhawk.sca.dcd.diagram.part.DcdDiagramEditor;
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.dcd.DcdPackage;
import mil.jpeojtrs.sca.dcd.DeviceConfiguration;
import mil.jpeojtrs.sca.dcd.provider.DcdItemProviderAdapterFactory;
import mil.jpeojtrs.sca.prf.provider.PrfItemProviderAdapterFactory;
import mil.jpeojtrs.sca.scd.provider.ScdItemProviderAdapterFactory;
import mil.jpeojtrs.sca.spd.provider.SpdItemProviderAdapterFactory;
import org.eclipse.core.resources.IMarker;
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.Adapter;
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.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.ui.provider.AdapterFactoryContentProvider;
import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider;
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.action.IToolBarManager;
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.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.ide.IGotoMarker;
import org.eclipse.ui.part.MultiPageSelectionProvider;
import org.eclipse.ui.statushandlers.StatusManager;
import org.eclipse.ui.views.contentoutline.ContentOutlinePage;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
import org.eclipse.ui.views.properties.IPropertySheetPage;
import org.eclipse.ui.views.properties.tabbed.ITabbedPropertySheetPageContributor;
/**
* This is an example of a Dcd model editor.
*/
public class NodeEditor extends SCAFormEditor implements ITabbedPropertySheetPageContributor, IDiagramWorkbenchPart, IViewerProvider {
public static final String ID = "gov.redhawk.ui.dcd.editor.presentation.NodeEditorID";
public static final String EDITING_DOMAIN_ID = DcdDiagramEditor.EDITING_DOMAIN_ID;
/**
* 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 DcdDiagramEditor 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 int dcdSourcePageNum;
private final Adapter nameListener = new AdapterImpl() {
/**
* {@inheritDoc}
*/
@Override
public void notifyChanged(final Notification msg) {
super.notifyChanged(msg);
final int featureID = msg.getFeatureID(DeviceConfiguration.class);
if (featureID == DcdPackage.DEVICE_CONFIGURATION__NAME) {
if (msg.getEventType() == Notification.SET) {
updateTitle();
}
}
}
};
private final Adapter disposeListener = new AdapterImpl() {
@Override
public void notifyChanged(final org.eclipse.emf.common.notify.Notification msg) {
switch (msg.getFeatureID(gov.redhawk.model.sca.IDisposable.class)) {
case ScaPackage.IDISPOSABLE__DISPOSED:
if (msg.getNewBooleanValue()) {
PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
getSite().getPage().closeEditor(NodeEditor.this, true);
}
});
}
break;
default:
break;
}
}
};
/**
* This creates a model editor.
*/
public NodeEditor() {
super();
initializeEditingDomain();
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);
}
/**
* 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 (NodeEditor.this.currentViewer != null) {
NodeEditor.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("rawtypes")
@Override
public Object getAdapter(final Class key) {
if (key.equals(IPropertySheetPage.class)) {
return getPropertySheetPage();
} else if (key.equals(IGotoMarker.class)) {
return this;
} else if (key.equals(DeviceConfiguration.class)) {
return PluginUtil.adapt(DeviceConfiguration.class, getDeviceConfiguration());
} else {
return super.getAdapter(key);
}
}
/**
* This accesses a cached version of the property sheet.
*/
public IPropertySheetPage getPropertySheetPage() {
return new PropertiesBrowserPage(this);
}
@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(AdapterFactoryEditingDomain.getWrapper(eObject, getEditingDomain())));
}
}
}
} catch (final CoreException exception) {
StatusManager.getManager().handle(new Status(IStatus.ERROR, NodeExplorerPlugin.getPluginId(), "Failed to go to marker.", exception),
StatusManager.LOG | StatusManager.SHOW);
}
}
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("");
}
}
}
/**
* 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() {
final DeviceConfiguration dcd = getDeviceConfiguration();
if (dcd != null) {
dcd.eAdapters().remove(this.nameListener);
}
// Node listener dispose listener
if (this.contentOutlinePage != null) {
this.contentOutlinePage.dispose();
}
super.dispose();
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.ui.views.properties.tabbed.ITabbedPropertySheetPageContributor
* #getContributorId()
*/
@Override
public String getContributorId() {
if (this.diagramEditor != null) {
return this.diagramEditor.getContributorId();
} else {
return null;
}
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.gmf.runtime.diagram.ui.parts.IDiagramWorkbenchPart#getDiagram
* ()
*/
@Override
public Diagram getDiagram() {
if (this.diagramEditor != null) {
return this.diagramEditor.getDiagram();
} else {
return null;
}
}
/*
* (non-Javadoc)
*
* @seeorg.eclipse.gmf.runtime.diagram.ui.parts.IDiagramWorkbenchPart#
* getDiagramEditDomain()
*/
@Override
public IDiagramEditDomain getDiagramEditDomain() {
if (this.diagramEditor != null) {
return this.diagramEditor.getDiagramEditDomain();
} else {
return null;
}
}
/*
* (non-Javadoc)
*
* @seeorg.eclipse.gmf.runtime.diagram.ui.parts.IDiagramWorkbenchPart#
* getDiagramEditPart()
*/
@Override
public DiagramEditPart getDiagramEditPart() {
if (this.diagramEditor != null) {
return this.diagramEditor.getDiagramEditPart();
} else {
return null;
}
}
/*
* (non-Javadoc)
*
* @seeorg.eclipse.gmf.runtime.diagram.ui.parts.IDiagramWorkbenchPart#
* getDiagramGraphicalViewer()
*/
@Override
public IDiagramGraphicalViewer getDiagramGraphicalViewer() {
if (this.diagramEditor != null) {
return this.diagramEditor.getDiagramGraphicalViewer();
} else {
return null;
}
}
/**
* {@inheritDoc}
*/
@Override
public String getTitle() {
String name = null;
final DeviceConfiguration dcd = getDeviceConfiguration();
if (dcd != null) {
name = dcd.getName();
if (name == null) {
name = getEditorInput().getName();
}
}
if (name != null) {
return name;
} else {
return super.getTitle();
}
}
/**
* @return
*/
private DeviceConfiguration getDeviceConfiguration() {
return ModelUtil.getDeviceConfiguration(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;
final URI diagramURI = DiagramUtil.getDiagramResourceURI(DcdDiagramUtilHelper.INSTANCE, getMainResource());
DiagramUtil.initializeDiagramResource(DcdDiagramUtilHelper.INSTANCE, diagramURI, getMainResource());
// This is the page for the graphical diagram viewer.
//
final IEditorInput diagramInput = DiagramUtil.getDiagramWrappedInput(diagramURI, (TransactionalEditingDomain) this.getEditingDomain());
this.diagramEditor = new ExplorerDiagramEditor();
pageIndex = addPage(this.diagramEditor, diagramInput);
setPageText(pageIndex, "Diagram");
try {
this.dcdSourcePageNum = addPage(createTextEditor(getEditorInput()), this.getEditorInput());
this.setPageText(this.dcdSourcePageNum, this.getEditorInput().getName());
} catch (final NullPointerException e) {
// PASS
// FIXME Why does this throw a null pointer when loaded from the server
}
getDeviceConfiguration().eAdapters().add(this.nameListener);
final DeviceConfiguration activeNode = getDeviceConfiguration();
if (activeNode != null) {
activeNode.eAdapters().add(this.disposeListener);
}
} catch (final PartInitException e) {
StatusManager.getManager().handle(new Status(IStatus.ERROR, NodeExplorerPlugin.getPluginID(), "Failed to create editor parts.", e),
StatusManager.LOG | StatusManager.SHOW);
} catch (final IOException e) {
StatusManager.getManager().handle(new Status(IStatus.ERROR, NodeExplorerPlugin.getPluginID(), "Failed to create editor parts.", e),
StatusManager.LOG | StatusManager.SHOW);
} catch (final CoreException e) {
StatusManager.getManager().handle(new Status(IStatus.ERROR, NodeExplorerPlugin.getPluginID(), "Failed to create editor parts.", e),
StatusManager.LOG | StatusManager.SHOW);
}
} else {
final Label label = new Label(getContainer(), SWT.None);
label.setText("Failed to load editor.");
addPage(label);
}
}
/**
* {@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() {
return getContentOutlinePage();
}
/**
* This accesses a cached version of the content outliner.
*/
public IContentOutlinePage getContentOutlinePage() {
if (this.contentOutlinePage != null) {
// The content outline is just a tree.
//
class MyContentOutlinePage extends ContentOutlinePage {
@Override
public void createControl(final Composite parent) {
super.createControl(parent);
NodeEditor.this.contentOutlineViewer = getTreeViewer();
NodeEditor.this.contentOutlineViewer.addSelectionChangedListener(this);
// Set up the tree viewer.
//
NodeEditor.this.contentOutlineViewer.setContentProvider(new AdapterFactoryContentProvider(getAdapterFactory()));
NodeEditor.this.contentOutlineViewer.setLabelProvider(new AdapterFactoryLabelProvider(getAdapterFactory()));
NodeEditor.this.contentOutlineViewer.setInput(getEditingDomain().getResourceSet());
// Make sure our popups work.
//
createContextMenuFor(NodeEditor.this.contentOutlineViewer);
if (!getEditingDomain().getResourceSet().getResources().isEmpty()) {
// Select the root object in the view.
//
NodeEditor.this.contentOutlineViewer.setSelection(new StructuredSelection(getEditingDomain().getResourceSet().getResources().get(0)),
true);
}
}
@Override
public void makeContributions(final IMenuManager menuManager, final IToolBarManager toolBarManager, final IStatusLineManager statusLineManager) {
super.makeContributions(menuManager, toolBarManager, statusLineManager);
NodeEditor.this.contentOutlineStatusLineManager = statusLineManager;
}
@Override
public void setActionBars(final IActionBars actionBars) {
super.setActionBars(actionBars);
// TODO
// getMyActionBarContributor().shareGlobalActions(this,
// actionBars);
}
}
this.contentOutlinePage = new MyContentOutlinePage();
// 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;
}
/**
* This deals with how we want selection in the outliner to affect the other
* views.
*/
@SuppressWarnings("unchecked")
public void handleContentOutlineSelection(final ISelection selection) {
if (!selection.isEmpty() && selection instanceof IStructuredSelection) {
final List< ? > selectedElements = ((IStructuredSelection) selection).toList();
if (getActiveEditor() == this.diagramEditor) {
// If the diagram viewer is active, we need to map the selection
// to the corresponding EditParts.
//
final ArrayList<Object> selectionList = new ArrayList<Object>();
for (final Object selectedElement : selectedElements) {
if (selectedElement instanceof EObject) {
final String elementID = EMFCoreUtil.getProxyID((EObject) selectedElement);
selectionList.addAll(this.diagramEditor.getDiagramGraphicalViewer().findEditPartsForElement(elementID, IGraphicalEditPart.class));
}
this.selectionProvider.setSelection(new StructuredSelection(selectionList));
}
}
}
}
/**
* {@inheritDoc}
*/
@Override
public String getEditingDomainId() {
return NodeEditor.EDITING_DOMAIN_ID;
}
/**
* {@inheritDoc}
*/
@Override
protected AdapterFactory getSpecificAdapterFactory() {
final ComposedAdapterFactory factory = new ComposedAdapterFactory();
factory.addAdapterFactory(new DcdItemProviderAdapterFactory());
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() {
return null;
}
@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(getDeviceConfiguration().eResource().getURI()) && super.isPersisted(resource);
}
/**
* {@inheritDoc}
*/
@Override
public boolean isDirty() {
return false;
}
@Override
public void doSave(final IProgressMonitor monitor) {
throw new UnsupportedOperationException();
}
}