/*
* CustomStsToolDiagramDocumentEditor.java
*
* This file is part of the STS-Tool project.
* Copyright (c) 2011-2012 "University of Trento - DISI" All rights reserved.
*
* Is strictly forbidden to remove this copyright notice from this source code.
*
* Disclaimer of Warranty:
* STS-Tool (this software) is provided "as-is" and without warranty of any kind,
* express, implied or otherwise, including without limitation, any warranty of
* merchantability or fitness for a particular purpose.
* In no event shall the copyright holder or contributors be liable for any direct,
* indirect, incidental, special, exemplary, or consequential damages
* including, but not limited to, procurement of substitute goods or services;
* loss of use, data, or profits; or business interruption) however caused and on
* any theory of liability, whether in contract, strict liability, or tort (including
* negligence or otherwise) arising in any way out of the use of this software, even
* if advised of the possibility of such damage.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3
* as published by the Free Software Foundation with the addition of the
* following permission added to Section 15 as permitted in Section 7(a):
* FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
* "University of Trento - DISI","University of Trento - DISI" DISCLAIMS THE
* WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
*
* See the GNU Affero General Public License for more details.
* You should have received a copy of the GNU Affero General Public License
* along with this program; if not, see http://www.gnu.org/licenses or write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA, 02110-1301 USA, or download the license from the following URL:
* http://www.sts-tool.eu/License.php
*
* For more information, please contact STS-Tool group at this
* address: ststool@disi.unitn.it
*
*/
package eu.aniketos.wp1.ststool.diagram.custom.part;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.EventObject;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.Viewport;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.emf.common.ui.URIEditorInput;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.gef.AccessibleEditPart;
import org.eclipse.gef.DefaultEditDomain;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.ExposeHelper;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.KeyHandler;
import org.eclipse.gef.KeyStroke;
import org.eclipse.gef.commands.CommandStack;
import org.eclipse.gef.commands.CommandStackEvent;
import org.eclipse.gef.commands.CommandStackEventListener;
import org.eclipse.gef.commands.CommandStackListener;
import org.eclipse.gef.palette.PaletteRoot;
import org.eclipse.gef.ui.actions.GEFActionConstants;
import org.eclipse.gef.ui.palette.PaletteViewer;
import org.eclipse.gef.ui.parts.ScrollingGraphicalViewer;
import org.eclipse.gmf.runtime.common.core.command.ICommand;
import org.eclipse.gmf.runtime.common.core.util.Log;
import org.eclipse.gmf.runtime.common.core.util.Trace;
import org.eclipse.gmf.runtime.common.ui.action.*;
import org.eclipse.gmf.runtime.diagram.ui.actions.ActionIds;
import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
import org.eclipse.gmf.runtime.diagram.ui.internal.DiagramUIDebugOptions;
import org.eclipse.gmf.runtime.diagram.ui.internal.DiagramUIPlugin;
import org.eclipse.gmf.runtime.diagram.ui.internal.DiagramUIStatusCodes;
import org.eclipse.gmf.runtime.diagram.ui.parts.*;
import org.eclipse.gmf.runtime.diagram.ui.resources.editor.document.IDocumentProvider;
import org.eclipse.gmf.runtime.diagram.ui.resources.editor.internal.l10n.EditorMessages;
import org.eclipse.gmf.runtime.diagram.ui.resources.editor.parts.DiagramDocumentEditor;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
import eu.aniketos.wp1.ststool.StsToolDiagram;
import eu.aniketos.wp1.ststool.diagram.custom.editpart.CustomStsToolDiagramEditPart;
import eu.aniketos.wp1.ststool.diagram.custom.figure.STSErrorType;
import eu.aniketos.wp1.ststool.diagram.custom.palette.CustomStsPaletteFactory;
import eu.aniketos.wp1.ststool.diagram.custom.palette.PaletteViewerExEx;
import eu.aniketos.wp1.ststool.diagram.custom.view.ViewChangeListener;
import eu.aniketos.wp1.ststool.diagram.custom.view.ViewsManager;
import eu.aniketos.wp1.ststool.diagram.edit.commands.WarningDialogCommandException;
import eu.aniketos.wp1.ststool.diagram.edit.parts.AgentEditPart;
import eu.aniketos.wp1.ststool.diagram.edit.parts.AuthorisationEditPart;
import eu.aniketos.wp1.ststool.diagram.edit.parts.CompatibleDutiesEditPart;
import eu.aniketos.wp1.ststool.diagram.edit.parts.DelegationEditPart;
import eu.aniketos.wp1.ststool.diagram.edit.parts.EventEditPart;
import eu.aniketos.wp1.ststool.diagram.edit.parts.Goal2EditPart;
import eu.aniketos.wp1.ststool.diagram.edit.parts.GoalDecompositionANDEditPart;
import eu.aniketos.wp1.ststool.diagram.edit.parts.GoalDecompositionOREditPart;
import eu.aniketos.wp1.ststool.diagram.edit.parts.IResourceEditPart;
import eu.aniketos.wp1.ststool.diagram.edit.parts.IncompatibleDutiesEditPart;
import eu.aniketos.wp1.ststool.diagram.edit.parts.ModifyEditPart;
import eu.aniketos.wp1.ststool.diagram.edit.parts.NeedEditPart;
import eu.aniketos.wp1.ststool.diagram.edit.parts.NegativeGoalContributionEditPart;
import eu.aniketos.wp1.ststool.diagram.edit.parts.OwnEditPart;
import eu.aniketos.wp1.ststool.diagram.edit.parts.PartOfEditPart;
import eu.aniketos.wp1.ststool.diagram.edit.parts.PlayEditPart;
import eu.aniketos.wp1.ststool.diagram.edit.parts.PositiveGoalContributionEditPart;
import eu.aniketos.wp1.ststool.diagram.edit.parts.ProduceEditPart;
import eu.aniketos.wp1.ststool.diagram.edit.parts.ProvisionEditPart;
import eu.aniketos.wp1.ststool.diagram.edit.parts.RoleEditPart;
import eu.aniketos.wp1.ststool.diagram.edit.parts.TResource2EditPart;
import eu.aniketos.wp1.ststool.diagram.edit.parts.TangibleByEditPart;
import eu.aniketos.wp1.ststool.diagram.edit.parts.ThreatEditPart;
import eu.aniketos.wp1.ststool.modelProvider.ISTSModelProvider;
@SuppressWarnings("restriction")
public abstract class CustomStsToolDiagramDocumentEditor extends DiagramDocumentEditor implements ViewChangeListener, ISTSModelProvider {
PaletteRoot paletteRoot;
private String baseName;
private Map<String, Object> tempPreferenceMap;
/**
* Default Constructor
*
* @see org.eclipse.gmf.runtime.diagram.ui.resources.editor.parts.DiagramDocumentEditor#DiagramDocumentEditor(boolean)
*/
public CustomStsToolDiagramDocumentEditor(boolean hasFlyoutPalette) {
super(hasFlyoutPalette);
tempPreferenceMap = new HashMap<String, Object>();
}
public Map getPreferenceMap(){
return tempPreferenceMap;
}
@Override
protected PaletteRoot createPaletteRoot(PaletteRoot existingPaletteRoot){
PaletteRoot root = super.createPaletteRoot(existingPaletteRoot);
CustomStsPaletteFactory.fillPalette(root);
return root;
}
/**
* Return a string used as base name for the editor
*
* @return The basic name of the editor
*/
public String getBaseName(){
if (baseName == null) {
String[] result = ((URIEditorInput) getEditorInput()).getURI().path().split("/");
baseName = result[result.length - 1];
}
return baseName;
}
/**
* Method that override the default key binding for some functions
*/
protected void rebindKey(){
try {
KeyHandler keyHandler = getDiagramGraphicalViewer().getKeyHandler();
keyHandler.put(KeyStroke.getPressed(SWT.DEL, 127, 0), getActionRegistry().getAction(ActionIds.ACTION_DELETE_FROM_MODEL));
keyHandler.put(KeyStroke.getPressed(SWT.BS, 8, 0), getActionRegistry().getAction(ActionIds.ACTION_DELETE_FROM_MODEL));
keyHandler.put(KeyStroke.getPressed('+', SWT.KEYPAD_ADD, SWT.CONTROL), getActionRegistry().getAction(GEFActionConstants.ZOOM_IN));
keyHandler.put(KeyStroke.getPressed('-', SWT.KEYPAD_SUBTRACT, SWT.CONTROL), getActionRegistry().getAction(GEFActionConstants.ZOOM_OUT));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
*
*/
@Override
public void setFocus(){
super.setFocus();
CustomStsPaletteFactory.hideElements(getViewsManager());
getDiagramEditPart().refresh();
}
/**
* @return the default ViewManager for the current editor
*/
public ViewsManager getViewsManager(){
return ((CustomStsToolDiagramEditPart) getDiagramEditPart()).getViewsManager();
}
/**
*
*/
@Override
protected void initializeGraphicalViewer(){
super.initializeGraphicalViewer();
getViewsManager().addViewChangeListener(this);
setPartName(getBaseName() + " (" + getViewsManager().getCurrentView().getName() + ")");
}
/**
* Manage the change of view, updating the diagram and the palette.
*
* @param view
* The new view
*/
@Override
public void changedView(int view){
if (view == ViewsManager.FULL_VIEW) {
CustomStsPaletteFactory.hideAll();
} else {
CustomStsPaletteFactory.hideElements(getViewsManager());
}
getDiagramEditPart().refresh();
if (view != ViewsManager.EMPTY_VIEW) {
setPartName(getBaseName() + " (" + getViewsManager().getCurrentView().getName() + ")");
}
}
/**
* Implementation of the "Save As" for the current editor. The user is prompted to input a new filename, then the new file is opened
*
* @param progressMonitor
* The progress monitor for the operation
*/
@Override
protected void performSaveAs(IProgressMonitor progressMonitor){
URIEditorInput input = (URIEditorInput) getEditorInput();
URI inputURI = input.getURI();
Shell shell = getSite().getShell();
FileDialog dialog = new FileDialog(shell, SWT.SAVE);
dialog.setOverwrite(true);
dialog.setFilterNames(new String[] { "ststool_diagram" });
dialog.setFilterExtensions(new String[] { "*.ststool_diagram" });
dialog.setFilterPath(inputURI.toFileString()); // Windows path
dialog.setFileName("copy_" + input.getName());
String destinationPath = dialog.open();
if (destinationPath == null) return;
File outFile = new File(destinationPath);
try {
File inputFile = new File(inputURI.toFileString());
File tempFile = File.createTempFile("ststemp", "sts");
copyfile(inputFile, tempFile);
performSave(true, progressMonitor);
copyfile(inputFile, outFile);
copyfile(tempFile, inputFile);
URI uri = URI.createURI(outFile.toURI().toASCIIString());
final URIEditorInput newInput = new URIEditorInput(uri);
//setInput(newInput);
IWorkbenchPage page = getSite().getWorkbenchWindow().getWorkbench().getActiveWorkbenchWindow().getActivePage();
try {
page.openEditor(newInput, "eu.aniketos.wp1.ststool.diagram.part.StsToolDiagramEditorID", true);
} catch (PartInitException e) {
e.printStackTrace();
}
close(false);
tempFile.delete();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Method to copy 2 file
*
* @param original
* the original file.
* @param copy
* the copy file
*/
private void copyfile(File original,File copy){
try {
InputStream in = new FileInputStream(original);
OutputStream out = new FileOutputStream(copy);
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
} catch (FileNotFoundException ex) {
System.err.println(ex.getMessage() + " in the specified directory.");
} catch (IOException e) {
System.err.println(e.getMessage());
}
}
/**
*
*/
@Override
public boolean isSaveAsAllowed(){
return (getEditorInput() instanceof URIEditorInput) && ((URIEditorInput) getEditorInput()).getURI().isFile();
}
/**
*
*/
@Override
public void setInput(IEditorInput input){
super.setInput(input);
}
@Override
public StsToolDiagram getStsModel(){
return (StsToolDiagram) getDiagram().getElement();
}
@Override
public void doSave(IProgressMonitor progressMonitor){
IDocumentProvider p = getDocumentProvider();
if (p == null) return;
getDiagramGraphicalViewer().getContents().refresh();
if (p.isDeleted(getEditorInput())) {
if (isSaveAsAllowed()) {
/*
* 1GEUSSR: ITPUI:ALL - User should never loose changes made in the editors.
* Changed Behavior to make sure that if called inside a regular save (because
* of deletion of input element) there is a way to report back to the caller.
*/
performSaveAs(progressMonitor);
} else {
Shell shell = getSite().getShell();
String title = EditorMessages.Editor_error_save_deleted_title;
String msg = EditorMessages.Editor_error_save_deleted_message;
MessageDialog.openError(shell, title, msg);
}
} else {
updateState(getEditorInput());
validateState(getEditorInput());
performSave(false, progressMonitor);
}
}
/**
* Creates a diagram edit domain
*/
protected void createDiagramEditDomain() {
DiagramEditDomain editDomain = new DiagramEditDomain(this);
editDomain.setActionManager(createActionManager());
setEditDomain(editDomain);
}
/**
* Configures my diagram edit domain with its command stack.
*/
@Override
protected void configureDiagramEditDomain(){
DefaultEditDomain editDomain = getEditDomain();
if (editDomain != null) {
CommandStack stack = editDomain.getCommandStack();
if (stack != null) {
// dispose the old stack
stack.dispose();
}
// create and assign the new stack
DiagramCommandStack diagramStack = new DiagramCommandStack(getDiagramEditDomain()) {
@Override
protected void execute(ICommand command,IProgressMonitor progressMonitor){
if (progressMonitor != null) {
try {
command.addContext(getUndoContext());
getOperationHistory().execute(command, progressMonitor, null);
} catch (WarningDialogCommandException e) {
} catch (ExecutionException e) {
Trace.catching(DiagramUIPlugin.getInstance(),
DiagramUIDebugOptions.EXCEPTIONS_CATCHING,
getClass(), "execute", e); //$NON-NLS-1$
Log.error(DiagramUIPlugin.getInstance(),
DiagramUIStatusCodes.COMMAND_FAILURE, "execute", e); //$NON-NLS-1$
}
} else {
try {
command.addContext(getUndoContext());
getOperationHistory().execute(command,
new NullProgressMonitor(), null);
} catch (WarningDialogCommandException e) {
} catch (ExecutionException e) {
Trace.catching(DiagramUIPlugin.getInstance(),
DiagramUIDebugOptions.EXCEPTIONS_CATCHING,
getClass(), "execute", e); //$NON-NLS-1$
Log.error(DiagramUIPlugin.getInstance(),
DiagramUIStatusCodes.COMMAND_FAILURE, "execute", e); //$NON-NLS-1$
}
}
/*int view = getViewsManager().getCurrentIntView();
getViewsManager().setCurrentView(ViewsManager.EMPTY_VIEW);
getViewsManager().setCurrentView(view);*/
}
};
diagramStack.setOperationHistory(getOperationHistory());
// changes made on the stack can be undone from this editor
diagramStack.setUndoContext(getUndoContext());
editDomain.setCommandStack(diagramStack);
}
// editDomain.getCommandStack().addCommandStackListener(new CommandStackListener() {
//
// @Override
// public void commandStackChanged(EventObject event) {
// System.out.println("ssss");
//
// }
// });
}
public DefaultEditDomain getDefEditDomain(){
return getEditDomain();
}
private final static List<Class> classes = new ArrayList<Class>();
static {
classes.add(AgentEditPart.class);
classes.add(AuthorisationEditPart.class);
classes.add(CompatibleDutiesEditPart.class);
classes.add(DelegationEditPart.class);
classes.add(EventEditPart.class);
classes.add(Goal2EditPart.class);
classes.add(GoalDecompositionANDEditPart.class);
classes.add(GoalDecompositionOREditPart.class);
classes.add(IncompatibleDutiesEditPart.class);
classes.add(IResourceEditPart.class);
classes.add(NeedEditPart.class);
classes.add(ModifyEditPart.class);
classes.add(NegativeGoalContributionEditPart.class);
classes.add(OwnEditPart.class);
classes.add(PartOfEditPart.class);
classes.add(PlayEditPart.class);
classes.add(PositiveGoalContributionEditPart.class);
classes.add(ProduceEditPart.class);
classes.add(ProvisionEditPart.class);
classes.add(RoleEditPart.class);
classes.add(TangibleByEditPart.class);
classes.add(ThreatEditPart.class);
classes.add(TResource2EditPart.class);
}
public void focusObject(EObject o){
IGraphicalEditPart ep = getEditPartForEObject(o);
if (ep != null) {
if (ep.isSelectable()) {
getDiagramGraphicalViewer().select(ep);
//org.eclipse.gmf.runtime.diagram.ui.parts.DiagramGraphicalViewer
getDiagramGraphicalViewer().reveal(ep);
}
}
}
/**
* Creates a ScrollingGraphicalViewer without the drop adapter which excludes drag and drop functionality from other defined views (XML) Subclasses must override this method to include the DnD functionality
*
* @return ScrollingGraphicalViewer
*/
@Override
protected ScrollingGraphicalViewer createScrollingGraphicalViewer(){
return new DiagramGraphicalViewer() {
@Override
public void reveal(EditPart part){
if (part == null) return;
EditPart current = part.getParent();
while (current != null) {
ExposeHelper helper = (ExposeHelper) current.getAdapter(ExposeHelper.class);
if (helper != null) helper.exposeDescendant(part);
current = current.getParent();
}
AccessibleEditPart acc = (AccessibleEditPart) part.getAdapter(AccessibleEditPart.class);
if (acc != null) getControl().getAccessible().setFocus(acc.getAccessibleID());
Viewport port = getFigureCanvas().getViewport();
IFigure target = ((GraphicalEditPart) part).getFigure();
Rectangle exposeRegion = target.getBounds().getCopy();
target = target.getParent();
while (target != null && target != port) {
target.translateToParent(exposeRegion);
target = target.getParent();
}
Dimension viewportSize = port.getClientArea().getSize();
Point topLeft = exposeRegion.getTopLeft();
Point center=topLeft.translate(exposeRegion.width/1,exposeRegion.height/2);
getFigureCanvas().scrollSmoothTo(center.x-(viewportSize.width/2),center.y-(viewportSize.height/2));
}
};
}
private Map<EObject, Integer> errorMarkerMap = new HashMap<EObject, Integer>();
private Map<EObject, Integer> warningMarkerMap = new HashMap<EObject, Integer>();
public void setMarkerValue(EObject o,boolean error){
if (o == null) return;
if (error) {
if (!errorMarkerMap.containsKey(o)) {
errorMarkerMap.put(o, new Integer(0));
}
errorMarkerMap.put(o, errorMarkerMap.get(o) + 1);
} else {
if (!warningMarkerMap.containsKey(o)) {
warningMarkerMap.put(o, new Integer(0));
}
warningMarkerMap.put(o, warningMarkerMap.get(o) + 1);
}
}
public void removeMarkerValue(EObject o,boolean error){
if (o == null) return;
if (error) {
if (errorMarkerMap.containsKey(o)) {
Integer i = errorMarkerMap.get(o);
if (i == 1) {
errorMarkerMap.remove(o);
} else {
errorMarkerMap.put(o, new Integer(i - 1));
}
}
} else {
if (warningMarkerMap.containsKey(o)) {
Integer i = warningMarkerMap.get(o);
if (i == 1) {
warningMarkerMap.remove(o);
} else {
warningMarkerMap.put(o, new Integer(i - 1));
}
}
}
}
public void refresh(){
int x = getViewsManager().getCurrentIntView();
getViewsManager().setCurrentView(ViewsManager.EMPTY_VIEW);
getViewsManager().setCurrentView(x);
}
public void clearAllMarker(){
errorMarkerMap.clear();
warningMarkerMap.clear();
refresh();
}
public STSErrorType getMarkerValue(IGraphicalEditPart ep){
EObject obj = (EObject) ((IAdaptable) ep).getAdapter(EObject.class);
if (obj != null) {
if (errorMarkerMap.containsKey(obj)) {
return STSErrorType.ERROR;
} else if (warningMarkerMap.containsKey(obj)) { return STSErrorType.WARNING; }
}
return STSErrorType.NO_ERROR;
}
private IGraphicalEditPart getEditPartForEObject(EObject o){
if (o == null) return null;
for (Object editPart : getDiagramGraphicalViewer().getEditPartRegistry().values()) {
if (classes.contains(editPart.getClass()) && ((IAdaptable) editPart).getAdapter(EObject.class) == o) { return (IGraphicalEditPart) editPart; }
}
return null;
}
@Override
protected PaletteViewer constructPaletteViewer(){
PaletteViewerExEx paletteViewer = new PaletteViewerExEx();
return paletteViewer;
}
}