/*
* Copyright (c) 2012-2016 Marsha Chechik, Alessio Di Sandro, Michalis Famelis,
* Rick Salay.
* 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:
* Alessio Di Sandro - Implementation.
*/
package edu.toronto.cs.se.mmint.mid.diagram.part;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.emf.common.ui.URIEditorInput;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.edit.ui.dnd.LocalTransfer;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.emf.workspace.util.WorkspaceSynchronizer;
import org.eclipse.gef.EditPartViewer;
import org.eclipse.gef.palette.PaletteContainer;
import org.eclipse.gef.palette.PaletteRoot;
import org.eclipse.gef.palette.PanningSelectionToolEntry;
import org.eclipse.gef.palette.ToolEntry;
import org.eclipse.gmf.runtime.common.ui.services.marker.MarkerNavigationService;
import org.eclipse.gmf.runtime.diagram.core.preferences.PreferencesHint;
import org.eclipse.gmf.runtime.diagram.ui.actions.ActionIds;
import org.eclipse.gmf.runtime.diagram.ui.internal.services.palette.PaletteToolEntry;
import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramDropTargetListener;
import org.eclipse.gmf.runtime.diagram.ui.resources.editor.document.IDiagramDocument;
import org.eclipse.gmf.runtime.diagram.ui.resources.editor.document.IDocument;
import org.eclipse.gmf.runtime.diagram.ui.resources.editor.document.IDocumentProvider;
import org.eclipse.gmf.runtime.diagram.ui.resources.editor.parts.DiagramDocumentEditor;
import org.eclipse.gmf.runtime.notation.Diagram;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.gmf.tooling.runtime.part.LastClickPositionProvider;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.util.LocalSelectionTransfer;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.window.Window;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.dnd.TransferData;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorMatchingStrategy;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorReference;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.SaveAsDialog;
import org.eclipse.ui.ide.IGotoMarker;
import org.eclipse.ui.navigator.resources.ProjectExplorer;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.part.IShowInTargetList;
import org.eclipse.ui.part.ShowInContext;
import edu.toronto.cs.se.mmint.MMINT;
import edu.toronto.cs.se.mmint.MMINTException;
import edu.toronto.cs.se.mmint.mid.MID;
import edu.toronto.cs.se.mmint.mid.diagram.navigator.MIDNavigatorItem;
/**
* @generated
*/
public class MIDDiagramEditor extends DiagramDocumentEditor implements IGotoMarker {
/**
* @generated
*/
public static final String ID = "edu.toronto.cs.se.mmint.mid.diagram.part.MIDDiagramEditorID"; //$NON-NLS-1$
/**
* @generated
*/
public static final String CONTEXT_ID = "edu.toronto.cs.se.mmint.mid.diagram.ui.diagramContext"; //$NON-NLS-1$
/**
* @generated
*/
private LastClickPositionProvider myLastClickPositionProvider;
/**
* @generated
*/
public MIDDiagramEditor() {
super(true);
}
/**
* @generated
*/
protected String getContextID() {
return CONTEXT_ID;
}
/**
* @generated
*/
protected PaletteRoot createPaletteRootGen(PaletteRoot existingPaletteRoot) {
PaletteRoot root = super.createPaletteRoot(existingPaletteRoot);
new MIDPaletteFactory().fillPalette(root);
return root;
}
/**
* @generated NOT
*/
protected PaletteRoot createPaletteRoot(PaletteRoot existingPaletteRoot) {
PaletteRoot root = createPaletteRootGen(existingPaletteRoot);
MID mid = (MID) this.getDiagram().getElement();
for (Object paletteContainer : root.getChildren()) {
List<ToolEntry> paletteEntriesToDel = new ArrayList<>();
for (Object paletteEntry : ((PaletteContainer) paletteContainer).getChildren()) {
if (paletteEntry instanceof ToolEntry && !(paletteEntry instanceof PanningSelectionToolEntry
|| paletteEntry instanceof PaletteToolEntry)) {
ToolEntry toolEntry = (ToolEntry) paletteEntry;
String label = toolEntry.getLabel();
String description = toolEntry.getDescription();
//TODO MMINT[MODELREL] Re-enable once support is implemented
if (label.contains("Import Nary")) {
paletteEntriesToDel.add(toolEntry);
continue;
}
switch (mid.getLevel()) { // Customize the palette labels and entries for each MID level
case TYPES:
if (label.contains("Import")) {
paletteEntriesToDel.add(toolEntry);
break;
}
label += " Type";
description += " Type";
break;
case INSTANCES:
if (label.contains("Operator")) {
paletteEntriesToDel.add(toolEntry);
}
break;
case WORKFLOWS:
if (label.contains("Operator") || label.contains("Import")) {
paletteEntriesToDel.add(toolEntry);
break;
}
description = description + " in the Workflow";
break;
default:
// should never happen
}
toolEntry.setLabel(label);
toolEntry.setDescription(description);
}
}
((PaletteContainer) paletteContainer).getChildren().removeAll(paletteEntriesToDel);
}
return root;
}
/**
* @generated
*/
protected PreferencesHint getPreferencesHint() {
return MIDDiagramEditorPlugin.DIAGRAM_PREFERENCES_HINT;
}
/**
* @generated
*/
public String getContributorId() {
return MIDDiagramEditorPlugin.ID;
}
/**
* @generated
*/
@SuppressWarnings("rawtypes")
public Object getAdapter(Class type) {
if (type == IShowInTargetList.class) {
return new IShowInTargetList() {
public String[] getShowInTargetIds() {
return new String[] { ProjectExplorer.VIEW_ID };
}
};
}
return super.getAdapter(type);
}
/**
* @generated
*/
protected IDocumentProvider getDocumentProvider(IEditorInput input) {
if (input instanceof IFileEditorInput || input instanceof URIEditorInput) {
return MIDDiagramEditorPlugin.getInstance().getDocumentProvider();
}
return super.getDocumentProvider(input);
}
/**
* @generated
*/
public TransactionalEditingDomain getEditingDomain() {
IDocument document = getEditorInput() != null ? getDocumentProvider().getDocument(getEditorInput()) : null;
if (document instanceof IDiagramDocument) {
return ((IDiagramDocument) document).getEditingDomain();
}
return super.getEditingDomain();
}
/**
* @generated
*/
protected void setDocumentProvider(IEditorInput input) {
if (input instanceof IFileEditorInput || input instanceof URIEditorInput) {
setDocumentProvider(MIDDiagramEditorPlugin.getInstance().getDocumentProvider());
}
else {
super.setDocumentProvider(input);
}
}
/**
* @generated
*/
public void gotoMarker(IMarker marker) {
MarkerNavigationService.getInstance().gotoMarker(this, marker);
}
/**
* @generated
*/
public boolean isSaveAsAllowed() {
return true;
}
/**
* @generated NOT
*/
protected void performSave(boolean overwrite, IProgressMonitor progressMonitor) {
IDocumentProvider provider = getDocumentProvider();
if (provider == null)
return;
try {
provider.aboutToChange(getEditorInput());
IEditorInput input = getEditorInput();
provider.saveDocument(progressMonitor, input, getDocumentProvider().getDocument(input), overwrite);
editorSaved();
}
catch (CoreException x) {
IStatus status = x.getStatus();
if (status == null || status.getSeverity() != IStatus.CANCEL)
handleExceptionOnSave(x, progressMonitor);
}
finally {
provider.changed(getEditorInput());
}
MID mid1 = (MID) this.getDiagram().getElement();
if (mid1.isTypesLevel()) {
MMINT.syncTypeMID(mid1);
// diagram sync required
final String relDiagramId = "edu.toronto.cs.se.mmint.mid.relationship.diagram.part.RelationshipDiagramEditorID";
for (IEditorReference editorRef : PlatformUI
.getWorkbench()
.getActiveWorkbenchWindow()
.getActivePage()
.getEditorReferences()) {
IEditorPart editorPart = editorRef.getEditor(false);
if (!(editorPart instanceof DiagramDocumentEditor)) {
continue;
}
DiagramDocumentEditor editor = (DiagramDocumentEditor) editorPart;
if (!editor.getSite().getId().equals(relDiagramId)) {
continue;
}
MID mid2 = (MID) editor.getDiagram().getElement().eContainer();
if (mid2.isTypesLevel()) {
IDocumentProvider provider2 = editor.getDocumentProvider();
try {
provider2.synchronize(editorRef.getEditorInput());
}
catch (Exception e) {
MMINTException.print(IStatus.ERROR, "Diagram synchronization failed", e);
}
}
}
}
}
/**
* @generated
*/
public void doSaveAs() {
performSaveAs(new NullProgressMonitor());
}
/**
* @generated
*/
protected void performSaveAs(IProgressMonitor progressMonitor) {
Shell shell = getSite().getShell();
IEditorInput input = getEditorInput();
SaveAsDialog dialog = new SaveAsDialog(shell);
IFile original = input instanceof IFileEditorInput ? ((IFileEditorInput) input).getFile() : null;
if (original != null) {
dialog.setOriginalFile(original);
}
dialog.create();
IDocumentProvider provider = getDocumentProvider();
if (provider == null) {
// editor has been programmatically closed while the dialog was open
return;
}
if (provider.isDeleted(input) && original != null) {
String message = NLS.bind(Messages.MIDDiagramEditor_SavingDeletedFile, original.getName());
dialog.setErrorMessage(null);
dialog.setMessage(message, IMessageProvider.WARNING);
}
if (dialog.open() == Window.CANCEL) {
if (progressMonitor != null) {
progressMonitor.setCanceled(true);
}
return;
}
IPath filePath = dialog.getResult();
if (filePath == null) {
if (progressMonitor != null) {
progressMonitor.setCanceled(true);
}
return;
}
IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
IFile file = workspaceRoot.getFile(filePath);
final IEditorInput newInput = new FileEditorInput(file);
// Check if the editor is already open
IEditorMatchingStrategy matchingStrategy = getEditorDescriptor().getEditorMatchingStrategy();
IEditorReference[] editorRefs = PlatformUI
.getWorkbench()
.getActiveWorkbenchWindow()
.getActivePage()
.getEditorReferences();
for (int i = 0; i < editorRefs.length; i++) {
if (matchingStrategy.matches(editorRefs[i], newInput)) {
MessageDialog.openWarning(
shell,
Messages.MIDDiagramEditor_SaveAsErrorTitle,
Messages.MIDDiagramEditor_SaveAsErrorMessage);
return;
}
}
boolean success = false;
try {
provider.aboutToChange(newInput);
getDocumentProvider(newInput)
.saveDocument(progressMonitor, newInput, getDocumentProvider().getDocument(getEditorInput()), true);
success = true;
}
catch (CoreException x) {
IStatus status = x.getStatus();
if (status == null || status.getSeverity() != IStatus.CANCEL) {
ErrorDialog.openError(
shell,
Messages.MIDDiagramEditor_SaveErrorTitle,
Messages.MIDDiagramEditor_SaveErrorMessage,
x.getStatus());
}
}
finally {
provider.changed(newInput);
if (success) {
setInput(newInput);
}
}
if (progressMonitor != null) {
progressMonitor.setCanceled(!success);
}
}
/**
* @generated
*/
public ShowInContext getShowInContext() {
return new ShowInContext(getEditorInput(), getNavigatorSelection());
}
/**
* @generated
*/
private ISelection getNavigatorSelection() {
IDiagramDocument document = getDiagramDocument();
if (document == null) {
return StructuredSelection.EMPTY;
}
Diagram diagram = document.getDiagram();
if (diagram == null || diagram.eResource() == null) {
return StructuredSelection.EMPTY;
}
IFile file = WorkspaceSynchronizer.getFile(diagram.eResource());
if (file != null) {
MIDNavigatorItem item = new MIDNavigatorItem(diagram, file, false);
return new StructuredSelection(item);
}
return StructuredSelection.EMPTY;
}
/**
* @generated
*/
protected void configureGraphicalViewer() {
super.configureGraphicalViewer();
DiagramEditorContextMenuProvider provider = new DiagramEditorContextMenuProvider(
this,
getDiagramGraphicalViewer());
getDiagramGraphicalViewer().setContextMenu(provider);
getSite().registerContextMenu(ActionIds.DIAGRAM_EDITOR_CONTEXT_MENU, provider, getDiagramGraphicalViewer());
}
/**
* @generated
*/
protected void initializeGraphicalViewer() {
super.initializeGraphicalViewer();
getDiagramGraphicalViewer().addDropTargetListener(
new DropTargetListener(getDiagramGraphicalViewer(), LocalSelectionTransfer.getTransfer()) {
protected Object getJavaObject(TransferData data) {
return LocalSelectionTransfer.getTransfer().nativeToJava(data);
}
});
getDiagramGraphicalViewer()
.addDropTargetListener(new DropTargetListener(getDiagramGraphicalViewer(), LocalTransfer.getInstance()) {
protected Object getJavaObject(TransferData data) {
return LocalTransfer.getInstance().nativeToJava(data);
}
});
startupLastClickPositionProvider();
}
/**
* @generated
*/
protected void startupLastClickPositionProvider() {
if (myLastClickPositionProvider == null) {
myLastClickPositionProvider = new LastClickPositionProvider(this);
myLastClickPositionProvider.attachToService();
}
}
/**
* @generated
*/
protected void shutDownLastClickPositionProvider() {
if (myLastClickPositionProvider != null) {
myLastClickPositionProvider.detachFromService();
myLastClickPositionProvider.dispose();
myLastClickPositionProvider = null;
}
}
/**
* @generated
*/
@Override
public void dispose() {
shutDownLastClickPositionProvider();
super.dispose();
}
/**
* @generated
*/
private abstract class DropTargetListener extends DiagramDropTargetListener {
/**
* @generated
*/
public DropTargetListener(EditPartViewer viewer, Transfer xfer) {
super(viewer, xfer);
}
/**
* @generated
*/
protected List getObjectsBeingDropped() {
TransferData data = getCurrentEvent().currentDataType;
HashSet<URI> uris = new HashSet<URI>();
Object transferedObject = getJavaObject(data);
if (transferedObject instanceof IStructuredSelection) {
IStructuredSelection selection = (IStructuredSelection) transferedObject;
for (Iterator<?> it = selection.iterator(); it.hasNext();) {
Object nextSelectedObject = it.next();
if (nextSelectedObject instanceof MIDNavigatorItem) {
View view = ((MIDNavigatorItem) nextSelectedObject).getView();
nextSelectedObject = view.getElement();
}
else if (nextSelectedObject instanceof IAdaptable) {
IAdaptable adaptable = (IAdaptable) nextSelectedObject;
nextSelectedObject = adaptable.getAdapter(EObject.class);
}
if (nextSelectedObject instanceof EObject) {
EObject modelElement = (EObject) nextSelectedObject;
uris.add(EcoreUtil.getURI(modelElement));
}
}
}
ArrayList<EObject> result = new ArrayList<EObject>(uris.size());
for (URI nextURI : uris) {
EObject modelObject = getEditingDomain().getResourceSet().getEObject(nextURI, true);
result.add(modelObject);
}
return result;
}
/**
* @generated
*/
protected abstract Object getJavaObject(TransferData data);
}
}