Package org.fusesource.ide.camel.editor.editor

Source Code of org.fusesource.ide.camel.editor.editor.RiderDesignEditor

/*******************************************************************************
* Copyright (c) 2013 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is 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:
*     Red Hat, Inc. - initial API and implementation
******************************************************************************/

package org.fusesource.ide.camel.editor.editor;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.EventObject;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarkerDelta;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.Path;
import org.eclipse.debug.core.DebugEvent;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.IBreakpointsListener;
import org.eclipse.debug.core.IDebugEventSetListener;
import org.eclipse.debug.core.model.IBreakpoint;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.gef.ContextMenuProvider;
import org.eclipse.gef.EditDomain;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPartViewer;
import org.eclipse.gef.GraphicalViewer;
import org.eclipse.gef.KeyHandler;
import org.eclipse.gef.RootEditPart;
import org.eclipse.gef.commands.CommandStack;
import org.eclipse.gef.dnd.TemplateTransferDropTargetListener;
import org.eclipse.gef.editparts.AbstractEditPart;
import org.eclipse.gef.editparts.ScalableRootEditPart;
import org.eclipse.gef.editparts.ZoomManager;
import org.eclipse.gef.requests.CreationFactory;
import org.eclipse.gef.requests.SimpleFactory;
import org.eclipse.gef.ui.actions.ActionRegistry;
import org.eclipse.gef.ui.parts.GraphicalEditorWithFlyoutPalette;
import org.eclipse.gef.ui.parts.SelectionSynchronizer;
import org.eclipse.graphiti.dt.IDiagramTypeProvider;
import org.eclipse.graphiti.features.IFeatureProvider;
import org.eclipse.graphiti.mm.pictograms.Diagram;
import org.eclipse.graphiti.mm.pictograms.PictogramElement;
import org.eclipse.graphiti.platform.IDiagramBehavior;
import org.eclipse.graphiti.services.Graphiti;
import org.eclipse.graphiti.ui.editor.DiagramBehavior;
import org.eclipse.graphiti.ui.editor.DiagramEditor;
import org.eclipse.graphiti.ui.editor.DiagramEditorInput;
import org.eclipse.graphiti.ui.editor.IDiagramEditorInput;
import org.eclipse.graphiti.ui.internal.util.gef.ScalableRootEditPartAnimated;
import org.eclipse.graphiti.ui.platform.IConfigurationProvider;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.util.TransferDropTargetListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.ISelectionService;
import org.eclipse.ui.IURIEditorInput;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.ide.FileStoreEditorInput;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
import org.fusesource.ide.camel.editor.AbstractNodes;
import org.fusesource.ide.camel.editor.Activator;
import org.fusesource.ide.camel.editor.EditorMessages;
import org.fusesource.ide.camel.editor.commands.DiagramOperations;
import org.fusesource.ide.camel.editor.commands.ImportCamelContextElementsCommand;
import org.fusesource.ide.camel.editor.outline.RiderOutlinePage;
import org.fusesource.ide.camel.editor.utils.DiagramUtils;
import org.fusesource.ide.camel.model.AbstractNode;
import org.fusesource.ide.camel.model.RouteContainer;
import org.fusesource.ide.camel.model.RouteSupport;
import org.fusesource.ide.camel.model.generated.Route;
import org.fusesource.ide.camel.model.io.ICamelEditorInput;
import org.fusesource.ide.camel.model.io.IRemoteCamelEditorInput;
import org.fusesource.ide.commons.camel.tools.ValidationHandler;
import org.fusesource.ide.commons.ui.Selections;
import org.fusesource.ide.commons.util.IOUtils;
import org.fusesource.ide.commons.util.Objects;
import org.fusesource.ide.launcher.debug.model.CamelStackFrame;
import org.fusesource.ide.launcher.debug.model.CamelThread;
import org.fusesource.ide.launcher.debug.util.CamelDebugRegistry;
import org.fusesource.ide.launcher.debug.util.CamelDebugRegistryEntry;
import org.fusesource.ide.launcher.debug.util.ICamelDebugConstants;
import org.fusesource.ide.preferences.PreferenceManager;
import org.fusesource.ide.preferences.PreferencesConstants;

/**
* @author lhein
*/
public class RiderDesignEditor extends DiagramEditor implements INodeViewer, IDebugEventSetListener, ISelectionListener, IBreakpointsListener {

  private final RiderDesignEditorData data;

  private RiderEditor editor;
  private KeyHandler keyHandler;

  private AbstractEditPart selectedEditPart;
  private AbstractEditPart lastSelectedEditPart;

  private boolean asyncSwitchToSource;
  private boolean dirty = false;
  private boolean disableCommandEvents;

  private IEditorSite editorSite;
  private IEditorInput editorInput;

  private IProject container;
  @SuppressWarnings("unused")
  private IFile camelContextFile;
  @SuppressWarnings("unused")
  private RouteContainer model;
  private RouteSupport activeRoute;
 
  private CamelDiagramBehaviour camelDiagramBehaviour;
  private boolean graphitiDoesNotMarkAsDirty = true;
 
  private DesignerCache activeConfig;
  private Map<RouteSupport, DesignerCache> cache = new HashMap<RouteSupport, DesignerCache>();

  private AbstractNode highlightedNodeInDebugger;
 
  public class DesignerCache {
    public Diagram diagram;
    public DiagramEditorInput input;
  }

  private PropertyChangeListener nodePropertyListener = new PropertyChangeListener() {
    /*
     * (non-Javadoc)
     * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
     */
    @Override
    public void propertyChange(PropertyChangeEvent evt) {
      CommandStack commandStack = getCommandStack();
      if (commandStack != null) {
        // TODO need to somehow mark the command stack as dirty so it notifies the parent editor..
        // for now we've the hack using field 'graphitiDoesNotMarkAsDirty'
        PropertyChangeCommand command = new PropertyChangeCommand(evt);
        commandStack.execute(command);
      }

      // TODO Graphiti update the graphical diagram for the selected node
      // the following line causes exceptions when adding node having expressions in it
      Display.getDefault().asyncExec(new Runnable() {

        @Override
        public void run() {
          DiagramOperations.updateSelectedNode(RiderDesignEditor.this);
          getDiagramTypeProvider().getDiagramBehavior().refresh();
        }

      });

      if (selectedEditPart != null) {
        selectedEditPart.refresh();
      } else if (lastSelectedEditPart == null) {

      } else {
        lastSelectedEditPart.refresh();
      }
    }
  };

  private Composite parent;

  public static RiderDesignEditor toRiderDesignEditor(IDiagramBehavior behavior) {
    if (behavior instanceof RiderDesignEditor) {
      return (RiderDesignEditor) behavior;
    }
    return null;
  }

  public static RiderDesignEditor toRiderDesignEditor(IFeatureProvider fp) {
    if (fp == null) {
      return null;
    }
    return toRiderDesignEditor(fp.getDiagramTypeProvider());
  }

  public static RiderDesignEditor toRiderDesignEditor(IDiagramTypeProvider diagramTypeProvider) {
    if (diagramTypeProvider == null) {
      return null;
    }
    return toRiderDesignEditor(diagramTypeProvider.getDiagramBehavior());
  }

  public RiderDesignEditor(RiderEditor parent) {
    this.data = parent.getDesignEditorData();
    this.activeConfig = new DesignerCache();
    this.editor = parent;
    DebugPlugin.getDefault().addDebugEventListener(this);
    if (PlatformUI.getWorkbench().getActiveWorkbenchWindow() != null) {
      ISelectionService sel = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getSelectionService();
      if (sel != null) sel.addSelectionListener(ICamelDebugConstants.DEBUG_VIEW_ID, this);     
    }
    DebugPlugin.getDefault().getBreakpointManager().addBreakpointListener(this);
  }
 
  @Override
  public void init(IEditorSite editorSite, IEditorInput input) throws PartInitException {
    this.editorSite = editorSite;
    this.editorInput = input;
    super.init(editorSite, input);
  }
 
  /* (non-Javadoc)
   * @see org.eclipse.graphiti.ui.editor.DiagramEditor#createDiagramBehavior()
   */
  @Override
  protected DiagramBehavior createDiagramBehavior() {
    this.camelDiagramBehaviour = new CamelDiagramBehaviour(this);
    return this.camelDiagramBehaviour;
  }
 
  /* (non-Javadoc)
   * @see org.eclipse.graphiti.ui.editor.DiagramEditor#getDiagramBehavior()
   */
  @Override
  public DiagramBehavior getDiagramBehavior() {
    return this.camelDiagramBehaviour;
  }
 
  public IConfigurationProvider getConfigurationProvider() {
    return this.camelDiagramBehaviour.getConfigurationProvider();
  }
 
  public RiderEditor getMultiPageEditor() {
    return this.editor;
  }
 
  @Override
  protected void setInput(IEditorInput input) {
   
    setPartName(input.getName());

    super.setInput(input);
   
        if (data.loadModelOnSetInput) {
      loadModelFromInput(input);
    }

        initializeDiagram(activeConfig.diagram);
   
        /**
         * the following is needed because we miss the first debug events and the first breakpoint wouldn't be highlighted otherwise
         */
        try {
          for (CamelDebugRegistryEntry entry : CamelDebugRegistry.getInstance().getEntries().values()) {
            IEditorInput ips = entry.getEditorInput();
        IFile f = (IFile)ips.getAdapter(IFile.class);
            if (f.getFullPath().toFile().getPath().equals(asFileEditorInput(input).getFile().getFullPath().toFile().getPath())) {
              String endpointId = null;
             
              // first highligth the suspended node
              Set<String> ids = entry.getDebugTarget().getDebugger().getSuspendedBreakpointNodeIds();
              if (ids != null && ids.size()>0) {
                endpointId = ids.iterator().next();
              }
              highlightBreakpointNodeWithID(endpointId);
             
              // and then mark all breakpoints
             
            }
          }
        } catch (Exception ex) {
          Activator.getLogger().error(ex);
        }
        /**
         * End of the highlighting code
         */
       
    getEditingDomain().getCommandStack().flush();
  }

  protected void initializeDiagramForSelectedRoute() {
      if (activeRoute == null) {
          return;
      }

      if (activeConfig.diagram == null) {
          // Create the diagram and its file
          activeConfig.diagram = Graphiti.getPeCreateService().createDiagram("CamelContext", "CamelContext", true); //$NON-NLS-1$ //$NON-NLS-2$
          initializeDiagram(activeConfig.diagram);
      }
  }
 
  private void initializeDiagram(Diagram diagram) {
      // set the diagram on the container
    IDiagramTypeProvider diagramTypeProvider = getDiagramTypeProvider();
    if (diagramTypeProvider == null)
      return;
   
      if (diagramTypeProvider.getDiagram() != diagram) {
        diagramTypeProvider.resourceReloaded(activeConfig.diagram);
      }

      // add the diagram contents
        getEditingDomain().getCommandStack().execute(new ImportCamelContextElementsCommand(RiderDesignEditor.this, getEditingDomain(), diagram));

        // layout the diagram
        DiagramOperations.layoutDiagram(RiderDesignEditor.this);

        // setup grid visibility
        setupGridVisibility();
  }

  @Override
  public void createPartControl(Composite parent) {
    this.parent = parent;
    super.createPartControl(parent);
  }

  protected void contributeToActionBars() {
    IActionBars bars = null;
    if (editorSite != null) {
      bars = editorSite.getActionBars();
    } else {
      Activator.getLogger().warning("No IEditorSite registered for " + this);
      return;
    }
    fillLocalToolBar(bars.getToolBarManager());
  }

  protected void fillLocalToolBar(IToolBarManager manager) {
  }


  public Composite getParent() {
    return parent;
  }

  /**
   * @param editingDomain the editingDomain to set
   */
  public void setEditingDomain(TransactionalEditingDomain editingDomain) {
//    this.editingDomain = editingDomain;
  }

  public String getCamelContextURI() {
    RouteSupport selectedRoute = getSelectedRoute();
    String id = selectedRoute.getId();
    if (id == null || id.length() == 0) {
      id = "#" + selectedRoute.hashCode();
    }
    IFile file = getCamelContextFile();
    if (file != null) {
      return file.getFullPath().toString() + "_" + id;
    } else {
      IRemoteCamelEditorInput input = getRemoteCamelEditorInput();
      if (input != null) {
        return input.getUriText();
      }
    }
    return id;
  }

  public IFile getCamelContextFile() {
    IFileEditorInput fileEditorInput = getFileEditorInput();
    if (fileEditorInput != null) {
      return fileEditorInput.getFile();
    }
    return null;
  }
 
  public void setCamelContextFile(IFile file) {
    this.camelContextFile = file;
  }
 
  protected IFileEditorInput getFileEditorInput() {
    return asFileEditorInput(editorInput);
  }

  protected IRemoteCamelEditorInput getRemoteCamelEditorInput() {
    return asRemoteCamelEditorInput(editorInput);
  }

  public IFileEditorInput asFileEditorInput(IEditorInput input) {
    if (input instanceof IFileEditorInput) {
      return (IFileEditorInput) input;
    } else if (input instanceof ICamelEditorInput) {
      ICamelEditorInput camelEditorInput = (ICamelEditorInput) input;
      IEditorInput fileEditorInput = camelEditorInput.getFileEditorInput();
      if (fileEditorInput instanceof IFileEditorInput) {
        return (IFileEditorInput) fileEditorInput;
      } else if (fileEditorInput instanceof FileStoreEditorInput) {
        FileStoreEditorInput fsei = (FileStoreEditorInput)fileEditorInput;
        return new FileEditorInput((IFile)input.getAdapter(IFile.class));
      }
    } else if (input instanceof IDiagramEditorInput) {
        org.eclipse.emf.common.util.URI uri = ((IDiagramEditorInput)input).getUri();
        if (uri.isPlatformResource()) {
            return new FileEditorInput(ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(uri.toPlatformString(true))));
        }
    }
    return null;
  }

  public IRemoteCamelEditorInput asRemoteCamelEditorInput(IEditorInput input) {
    if (input instanceof IRemoteCamelEditorInput) {
      return (IRemoteCamelEditorInput) input;
    } else if (input instanceof ICamelEditorInput) {
      ICamelEditorInput camelEditorInput = (ICamelEditorInput) input;
      IEditorInput fileEditorInput = camelEditorInput.getFileEditorInput();
      if (fileEditorInput instanceof IRemoteCamelEditorInput) {
        return (IRemoteCamelEditorInput) fileEditorInput;
      }
    } else if (input instanceof IURIEditorInput) {
      final IURIEditorInput uriInput = (IURIEditorInput) input;
      return new IRemoteCamelEditorInput() {

        @Override
        public String getUriText() {
          return uriInput.getName();
        }

        @Override
        public String getXml() throws IOException {
          return IOUtils.loadText(uriInput.getURI().toURL().openStream(), "UTF-8");
        }
      };
        } else if (input instanceof DiagramEditorInput) {
            final DiagramEditorInput uriInput = (DiagramEditorInput) input;
            return new IRemoteCamelEditorInput() {

                @Override
                public String getUriText() {
                    return uriInput.getName();
                }

                @Override
                public String getXml() throws IOException {
                    try {
                        return IOUtils.loadText(new URI(uriInput.getUri().toString()).toURL().openStream(), "UTF-8");
                    } catch (URISyntaxException e) {
                        throw new IOException("Unable to resolve resource.", e);
                    }
                }
            };
    }
    return null;
  }


  /*
   * (non-Javadoc)
   * @see org.fusesource.ide.camel.editor.editor.INodeViewer#getSelectedNode()
   */
  @Override
  public AbstractNode getSelectedNode() {
    // return the currently active selection
    return AbstractNodes.getSelectedNode(Selections.getSelection(getEditorSite()));
    //return this.data.selectedNode;
  }

  /*
   * (non-Javadoc)
   * @see org.fusesource.ide.camel.editor.editor.INodeViewer#setSelectedNode(org.fusesource.ide.camel.model.AbstractNode)
   */
  @Override
  public void setSelectedNode(AbstractNode newSelection) {
    if (newSelection != null) {
      Object selectEditPart = findEditPart(newSelection, getRootEditPart());
      if (selectEditPart != null) {
        getEditorSite().getSelectionProvider().setSelection(new StructuredSelection(selectEditPart));
      } else {
        Activator.getLogger().error("Could not find editPart for selection: " + newSelection, new Exception());
      }
    }
    this.data.selectedNode = newSelection;
  }


  /**
   * Finds the given node by walking the edit part tree looking for the correct one
   */
  @SuppressWarnings("unchecked")
  public static EditPart findEditPart(AbstractNode node, EditPart part) {
    if (part instanceof RootEditPart) {
      RootEditPart root = (RootEditPart) part;
      EditPart contents = root.getContents();
      if (contents != null) {
        return findEditPart(node, contents);
      }
    }
    if (part instanceof EditPart) {
      EditPart nodeEditPart = part;
      AbstractNode modelNode = AbstractNodes.toAbstractNode(nodeEditPart);
      if (Objects.equal(node, modelNode)) {
        return nodeEditPart;
      }
    }
    List<EditPart> children = part.getChildren();
    for (EditPart childPart : children) {
      EditPart answer = findEditPart(node, childPart);
      if (answer != null) {
        return answer;
      }
    }
    return null;
  }

  public AbstractEditPart getLastSelectedEditPart() {
    return lastSelectedEditPart;
  }

  /*
   * (non-Javadoc)
   * @see org.eclipse.gef.ui.parts.GraphicalEditor#getCommandStack()
   */
  @Override
  public CommandStack getCommandStack() {
    return getEditDomain().getCommandStack();
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.eclipse.gef.ui.parts.GraphicalEditor#selectionChanged(org.eclipse
   * .ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
   */
  @Override
  public void selectionChanged(IWorkbenchPart part, ISelection selection) {
    // If not the active editor, ignore selection changed.
    if (getSite().getPage().getActiveEditor() == editor
        && editor.getActiveEditor() == this) {
      updateActions(getSelectionActions());

      if (selection instanceof StructuredSelection) {
        StructuredSelection structuredSelection = (StructuredSelection) selection;
        Object firstElement = structuredSelection.getFirstElement();
        if (firstElement instanceof AbstractEditPart) {
          selectedEditPart = (AbstractEditPart) firstElement;
          AbstractNode node = AbstractNodes.toAbstractNode(firstElement);
          if (node != null) {
            if (data.selectedNode != null) {
              data.selectedNode
              .removePropertyChangeListener(nodePropertyListener);
            }
            data.selectedNode = node;
            data.selectedNode
            .addPropertyChangeListener(nodePropertyListener);
          }
          if (selectedEditPart != null) {
            lastSelectedEditPart = selectedEditPart;
          }
        } else if (firstElement instanceof CamelStackFrame) {
          CamelStackFrame stackFrame = (CamelStackFrame)firstElement;
          highlightBreakpointNodeWithID(stackFrame.getEndpointId());
        } else if (firstElement instanceof CamelThread) {
          CamelThread t = (CamelThread)firstElement;
          try {
            CamelStackFrame stackFrame = (CamelStackFrame)t.getTopStackFrame();
            if (stackFrame != null) {
              highlightBreakpointNodeWithID(stackFrame.getEndpointId())
            }
          } catch (DebugException e) {
            Activator.getLogger().error(e);
          }
        }
      }
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.gef.ui.parts.GraphicalEditor#configureGraphicalViewer()
   */
  @Override
  protected void configureGraphicalViewer() {
    super.configureGraphicalViewer();

    GraphicalViewer viewer = getGraphicalViewer();
    /*
    // TODO Graphiti
    viewer.setEditPartFactory(new RouteEditPartFactory());

    double[] zoomLevels;
    ArrayList<String> zoomContributions;
    rootEditPart = new ScalableRootEditPart();
    viewer.setRootEditPart(rootEditPart);

    ZoomManager manager = rootEditPart.getZoomManager();
    getActionRegistry().registerAction(new ZoomInAction(manager));
    getActionRegistry().registerAction(new ZoomOutAction(manager));
    // zooms possible. 1 = 100%
    zoomLevels = new double[] { 0.25, 0.5, 0.75, 1.0, 1.5, 2.0, 2.5, 3.0,
        4.0, 5.0, 10.0, 20.0 };
    manager.setZoomLevels(zoomLevels);

    zoomContributions = new ArrayList<String>();
    zoomContributions.add(ZoomManager.FIT_ALL);
    zoomContributions.add(ZoomManager.FIT_HEIGHT);
    zoomContributions.add(ZoomManager.FIT_WIDTH);
    manager.setZoomLevelContributions(zoomContributions);

    KeyHandler keyHandler = new KeyHandler();
    keyHandler.put(KeyStroke.getPressed(SWT.DEL, 127, 0),
        getActionRegistry().getAction(ActionFactory.DELETE.getId()));
    keyHandler.put(KeyStroke.getPressed('+', SWT.KEYPAD_ADD, 0),
        getActionRegistry().getAction(GEFActionConstants.ZOOM_IN));
    keyHandler.put(KeyStroke.getPressed('-', SWT.KEYPAD_SUBTRACT, 0),
        getActionRegistry().getAction(GEFActionConstants.ZOOM_OUT));
    viewer.setProperty(MouseWheelHandler.KeyGenerator.getKey(SWT.NONE),
        MouseWheelZoomHandler.SINGLETON);
    viewer.setKeyHandler(keyHandler);

    // IMPORTANT: the following is a dirty workaround to get the delete
    // action behave normal. Without this code no delete will be
    // possible. TODO: try to get this fixed by time.
    ActionRegistry registry = getActionRegistry();
    String id = ActionFactory.UNDO.getId();
    getEditorSite().getKeyBindingService().registerAction(
        registry.getAction(id));
    id = ActionFactory.REDO.getId();
    getEditorSite().getKeyBindingService().registerAction(
        registry.getAction(id));
    id = ActionFactory.DELETE.getId();
    getEditorSite().getKeyBindingService().registerAction(
        registry.getAction(id));

     */
    ContextMenuProvider provider = new RiderEditorContextMenuProvider(this, this, viewer, getActionRegistry());
    viewer.setContextMenu(provider);
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.eclipse.gef.ui.parts.GraphicalEditor#commandStackChanged(java.util
   * .EventObject)
   */
  @Override
  public void commandStackChanged(EventObject event) {
    super.commandStackChanged(event);
    fireModelDirty();
  }

  /* (non-Javadoc)
   * @see org.eclipse.graphiti.ui.editor.DiagramEditor#isDirty()
   */
  @Override
  public boolean isDirty() {
    return this.dirty;
  }
 
  /**
   * @param dirty the dirty to set
   */
  public void setDirty(boolean dirty) {
    this.dirty = dirty;
    firePropertyChange(PROP_DIRTY);
  }
 
  protected void fireModelDirty() {
    setDirty(true);

    // only mark the diagram as changed if we really have just performed a command
    // (rather than just doing a save which just clears the dirty flag)
    boolean changed = getCommandStack().isDirty();
    if (!disableCommandEvents && (changed || graphitiDoesNotMarkAsDirty)) {
      data.diagramChanged = true;
    }
  }

  /**
   * Create a transfer drop target listener. When using a
   * CombinedTemplateCreationEntry tool in the palette, this will enable model
   * element creation by dragging from the palette.
   *
   * @see #createPaletteViewerProvider()
   */
  private TransferDropTargetListener createTransferDropTargetListener() {
    return new TemplateTransferDropTargetListener(getGraphicalViewer()) {
      /*
       * (non-Javadoc)
       * @see org.eclipse.gef.dnd.TemplateTransferDropTargetListener#getFactory(java.lang.Object)
       */
      @SuppressWarnings("rawtypes")
      @Override
      protected CreationFactory getFactory(final Object template) {
        if (template instanceof CreationFactory) {
          return (CreationFactory) template;
        } else if (template instanceof Class) {
          return new SimpleFactory((Class) template);
        } else {
          Activator.getLogger().debug("============= Template: " + template + " is not a CreationFactory or Class! " + Objects.typeName(template));
          return new CreationFactory() {

            @Override
            public Object getNewObject() {
              return template;
            }

            @Override
            public Object getObjectType() {
              if (template == null) {
                return null;
              }
              return template.getClass();
            }

          };
        }
      }
    };
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.eclipse.gef.ui.parts.GraphicalEditorWithFlyoutPalette#getAdapter(
   * java.lang.Class)
   */
  @Override
  public Object getAdapter(@SuppressWarnings("rawtypes") Class type) {
    if (type == GraphicalViewer.class
        || type == GraphicalEditorWithFlyoutPalette.class
        || type == EditPartViewer.class) {
      return getGraphicalViewer();
    } else if (type == CommandStack.class) {
      return getCommandStack();
    } else if (type == EditDomain.class) {
      return getEditDomain();
    } else if (type == ActionRegistry.class) {
      return getActionRegistry();
    } else if (type == ZoomManager.class) {
      GraphicalViewer graphicalViewer = getGraphicalViewer();
      if (graphicalViewer == null)
        return null;
     
      RootEditPart root = graphicalViewer.getRootEditPart();
      if (root instanceof ScalableRootEditPartAnimated) {
        ScalableRootEditPartAnimated scalableRoot = (ScalableRootEditPartAnimated) root;
        return scalableRoot.getZoomManager();
      } else if (root instanceof ScalableRootEditPart) {
        return ((ScalableRootEditPart) root).getZoomManager();
      }
      return null;
    } else if (type == IContentOutlinePage.class) {
      return new RiderOutlinePage(this);
    }
    return super.getAdapter(type);
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.gef.ui.parts.GraphicalEditorWithFlyoutPalette#
   * initializeGraphicalViewer()
   */
  @Override
  public void initializeGraphicalViewer() {
    super.initializeGraphicalViewer();
    GraphicalViewer viewer = getGraphicalViewer();

    // listen for dropped parts
    viewer.addDropTargetListener(createTransferDropTargetListener());
  }

  /**
   * handles exception while loading model
   *
   * @param e
   *            the exception
   * @throws PartInitException
   */
  private void handleLoadException(Exception e) {
    Activator.getLogger().error("** Load failed. Using default model. **", e);
    try {
      this.setModel(new RouteContainer());
    } catch (PartInitException e1) {
      Activator.getLogger().warning("Failed to reload the diagram: " + e, e);
    }
    getModel().setFailedToParseXml(true);
  }
 
  /**
   * refresh the editor contents
   */
  public void update() {
    DiagramOperations.updateDiagram(RiderDesignEditor.this);
    getDiagramBehavior().refresh();
    if (getDiagram() != null) selectPictogramElements(new PictogramElement[] { getDiagram().getContainer() });
  }

  /**
   * fires a model change event to all listeners
   */
  public void fireModelChanged() {
    for (ModelChangeListener listener : data.modelChangeListeners) {
      listener.onModelChange();
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.gef.ui.parts.GraphicalEditor#getActionRegistry()
   */
  @Override
  public ActionRegistry getActionRegistry() {
    return super.getActionRegistry();
  }

  /**
   * @return the model
   */
  public RouteContainer getModel() {
    if (data.model == null && editorInput != null) {
      data.lazyLoading = true;
      try {
        loadModelFromInput(editorInput);
      } finally {
        data.lazyLoading = false;
      }
    }
    return this.data.model;
  }

  public void setModel(RouteContainer model) throws PartInitException {
    if (model != this.data.model){
      this.data.model = model;
      this.data.selectedRoute = null;

      setInitialRoute();
    }
  }

  public RouteSupport getSelectedRoute() {
    if (data.selectedRoute == null) {
      List<AbstractNode> children = getModel().getChildren();
      if (children != null) {
        int size = children.size();
        int idx = data.selectedRouteIndex;
        if (idx < 0 || idx >= size) {
          idx = 0;
        }
        if (size > 0) {
          AbstractNode node = children.get(idx);
          if (node instanceof RouteSupport) {
            data.selectedRoute = (RouteSupport) node;
          }
        }
      }
    }
    if (data.selectedRoute == null) {
      setInitialRoute();
    }
    return data.selectedRoute;
  }

  public void clearSelectedRouteCache() {
    this.data.selectedRoute = null;
    this.data.selectedRouteIndex = -1;
  }

  public void setSelectedRoute(RouteSupport selectedRoute) {
    if (this.data.selectedRoute != selectedRoute) {
      int index = data.indexOfRoute(selectedRoute);
      setSelectedRouteIndex(index);
    }
  }

  public void switchRoute(final RouteSupport newRoute) {
    if (newRoute == activeRoute) {
      return;
    }
    if (activeRoute != null) {
      this.cache.put(activeRoute, activeConfig);
    }
    activeRoute = newRoute;
    if (this.cache.containsKey(newRoute)) {
      this.activeConfig = this.cache.get(newRoute);
    } else {
      DiagramEditorInput oldInput = this.activeConfig.input;
      this.activeConfig = new DesignerCache();
      this.activeConfig.input = oldInput;
    }
    refreshDiagramContents();
  }
 
  public void refreshDiagramContents() {
    initializeDiagramForSelectedRoute();
    if (activeConfig.diagram != null) {
      getDiagramTypeProvider().init(activeConfig.diagram, getDiagramBehavior());
      getDiagramBehavior().getRefreshBehavior().initRefresh();
          setPictogramElementsForSelection(null);
          GraphicalViewer graphicalViewer = getGraphicalViewer();
         
          if (graphicalViewer == null)
            return;
         
          // set Diagram as contents for the graphical viewer and refresh
          graphicalViewer.setContents(activeConfig.diagram);         
          getDiagramBehavior().refreshContent();
    }
  }

  private void setInitialRoute() {
    if (getModel() != null) {
      if (getModel().getChildren().isEmpty()) {
        // lets add an empty route for now...
        Route route = new Route();
        getModel().addChild(route);
      }
      this.activeRoute = (RouteSupport)getModel().getChildren().get(0);
      this.data.selectedRoute = activeRoute;
    }
  }

  public void setSelectedRouteIndex(int index) {
    if (this.data.selectedRouteIndex != index && index >= 0) {
      this.data.selectedRouteIndex = index;
      this.data.selectedRoute = (RouteSupport) getModel().getChildren().get(index);

      // now lets recreate the model so that we don't get any Graphiti woe since the model is intertwined with the diagram
      //data.recreateModel();

      switchRoute(data.selectedRoute);
    }
  }

  public void setupGridVisibilityAsync() {
    Display.getDefault().asyncExec(new Runnable() {
      @Override
      public void run() {
          setupGridVisibility();
          }
      });
  }

  public void setupGridVisibility() {
    // TODO is this causing transaction issues???
    DiagramOperations.updateGridColor(RiderDesignEditor.this);

    // retrieve the grid visibility setting
    boolean gridVisible = PreferenceManager.getInstance().loadPreferenceAsBoolean(PreferencesConstants.EDITOR_GRID_VISIBILITY);

    // reset the grid visibility flag
    DiagramUtils.setGridVisible(gridVisible);
  }

  /**
   * @return the container
   */
  public IProject getContainer() {
    return this.container;
  }
 
  public void setContainer(IProject container) {
    this.container = container;
  }

  /* (non-Javadoc)
   * @see org.eclipse.gef.ui.parts.GraphicalEditor#getSelectionSynchronizer()
   */
  @Override
  protected SelectionSynchronizer getSelectionSynchronizer() {
    return super.getSelectionSynchronizer();
  }
 
  public SelectionSynchronizer getSelectionSyncer() {
    return getSelectionSynchronizer();
  }

  /**
   * @return the keyHandler
   */
  public KeyHandler getKeyHandler() {
    return this.keyHandler;
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.gef.ui.parts.GraphicalEditor#dispose()
   */
  @Override
  public void dispose() {
    DebugPlugin.getDefault().removeDebugEventListener(this);
   
    if (PlatformUI.getWorkbench().getActiveWorkbenchWindow() != null) {
      ISelectionService sel = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getSelectionService();
      if (sel != null) sel.removeSelectionListener(ICamelDebugConstants.DEBUG_VIEW_ID, this);     
    }
   
    this.editorInput = null;
    this.activeConfig = null;

    // dispose the ActionRegistry (will dispose all actions)
    ActionRegistry actionRegistry = getActionRegistry();
    if (actionRegistry != null) {
      actionRegistry.dispose();
    }
    // important: always call super implementation of dispose
    if (getDiagramTypeProvider() != null)
      super.dispose();
  }


  protected void loadModelFromInput(IEditorInput editorInput) {
    data.loaded = false;
    try {
      if (editorInput instanceof IFileEditorInput) {
        IFile file = ((IFileEditorInput) editorInput).getFile();
        loadModelFromFile(file);
      } else if (editorInput instanceof ICamelEditorInput) {
        ICamelEditorInput camelInput = (ICamelEditorInput) editorInput;
        editor.onInputLoading(camelInput);
        this.setModel(camelInput.loadModel());
      } else if (editorInput instanceof IURIEditorInput) {
        editor.onInputLoading(editorInput);
        IURIEditorInput uriInput = (IURIEditorInput) editorInput;
        URI uri = uriInput.getURI();
        URL url = uri.toURL();
        if (url == null) {
          Activator.getLogger().warning("Unsupported URI type " + uri);
        } else {
          String xml = IOUtils.loadText(url.openStream(), "UTF-8");
          this.setModel(data.marshaller.loadRoutesFromText(xml));
        }
      } else {
        editor.onInputLoading(editorInput);
        Activator.getLogger().warning("Unsupported IEditorInput type " + editorInput);
      }
    } catch (Exception e) {
      handleLoadException(e);
      // lets switch to the source view as we tried to load invalid XML
      switchToSourceEditor();
    } finally {
      if (asyncSwitchToSource) {
        // lets not marked as loaded until we've switched the view...
      } else {
        data.loaded = true;
      }
    }
  }

  protected void switchToSourceEditor() {
    asyncSwitchToSource = true;
    editor.switchToSourceEditor();
  }

  /**
   * loads the model from file
   *
   * @param file
   *            the file to load from
   * @throws PartInitException
   */
  public void loadModelFromFile(IFile file) throws Exception {
    editor.onFileLoading(file);
    this.setModel(data.marshaller.loadRoutes(file));
    if (file.getName().contentEquals("switchyard.xml")) {
      MessageDialog.openWarning(getSite().getShell(), EditorMessages.switchyardFoundTitle,
          EditorMessages.switchyardFoundText);
      switchToSourceEditor();
    }
    ValidationHandler status = this.getModel().validate();
    if (status.hasErrors()) {
      switchToSourceEditor();
    }
  }

  public void loadModelFromRemoteContext(ICamelEditorInput editorInput) throws IOException, PartInitException {
    editor.onInputLoading(editorInput);
    this.setModel(editorInput.loadModel());
  }
 
  public void loadEditorText(String text) {
    try {
      this.setModel(data.marshaller.loadRoutesFromText(text));
      validateXml();
    } catch (Exception e) {
      showValidationError(e);
    }
  }

  /**
   * lets validate the XML against the XSD in case its bad & warn of possible losses
   */
  public void validateXml() throws Exception {
    if (data.loaded) {
      // if we have no model it means lets try reparse the XML again...
      if (this.getModel() == null || this.getModel().isFailedToParseXml()) {
        IDocument document = editor.getDocument();
        if (document != null) {
          String text = document.get();
          loadEditorText(text);
        }

      } else {
        ValidationHandler status = this.getModel().validate();
        if (status.hasErrors()) {
          String error = status.userMessage();
          showXmlValidationError(error);
        }
      }
    }
  }

  public void autoLayoutRoute() {
    Display.getCurrent().asyncExec(new Runnable() {
     
      @Override
      public void run() {
        DiagramOperations.layoutDiagram(RiderDesignEditor.this)
      }
    });   
  }

  public Diagram getDiagram() {
    return activeConfig == null ? null : activeConfig.diagram;
  }

  public void setTransactionalEditingDomain(TransactionalEditingDomain editingDomain) {
//    this.editingDomain = editingDomain;
  }

  protected DiagramEditorInput getDiagramInput() {
    DiagramEditorInput diagramInput = null;
    IEditorInput input = getEditorInput();
    if (input instanceof DiagramEditorInput) {
      diagramInput = (DiagramEditorInput) input;
    }
    return diagramInput;
  }

  /* (non-Javadoc)
   * @see org.eclipse.ui.part.EditorPart#getEditorInput()
   */
  @Override
  public IEditorInput getEditorInput() {
    if (this.editorInput != null) {
      return this.editorInput;
    }
    return super.getEditorInput();
  }
 
  public String updateEditorText(String editorXml) {
    return data.marshaller.updateText(editorXml, getModel());
  }

  public void runIfDiagramModified(Runnable block) {
    runIfDiagramModified(block, true);
  }

  public void runIfDiagramModified(Runnable block, boolean async) {
    // called when we've switched to the text view so lets clear that we've shown the validation error
    data.shownValidationError = false;
    if (data.diagramChanged) {
      try {
        if (async) {
          Display.getDefault().syncExec(block);
        } else {
          block.run();
        }
      } finally {
        clearChangedFlags();
      }
    }
  }

  protected void clearChangedFlags() {
    data.diagramChanged = false;
    data.textChanged = false;
    getCommandStack().markSaveLocation();
    getEditingDomain().getCommandStack().flush();
    setDirty(false);
  }
 
  public void onTextEditorPropertyChange() {
    data.textChanged = true;
  }

  public void runIfTextModified(Runnable block) {
    try {
      Display.getDefault().syncExec(block);
      validateXml();
    } catch (Exception e) {
      showValidationError(e);
    } finally {
      // note we could be clearing the flags before we perform the block
      clearChangedFlags();
    }
    if (asyncSwitchToSource) {
      // we should now have switched on loading to the text view now
      // so lets re-enable error warnings.
      asyncSwitchToSource = false;
      data.loaded = true;
    }
  }

  protected void showValidationError(Exception e) {
    String text = e.getMessage();
    if (e instanceof RuntimeException) {
      Throwable cause = e.getCause();
      if (cause != null) {
        text = cause.getMessage();
        Activator.getLogger().error(e);
      } else {
        Activator.getLogger().error(e);
      }
    }
    showXmlValidationError(text);
  }

  public void showXmlValidationError(String text) {
    if (data.loaded && !data.shownValidationError) {
      String message = NLS.bind(EditorMessages.saveModifiedTextFailedText, text);
      data.shownValidationError = true;
      MessageDialog.openWarning(getSite().getShell(), EditorMessages.saveModifiedTextFailedTitle, message);
    }
  }

  public void markXmlSaved() {
    CommandStack stack = getCommandStack();
    if (stack == null) {
      Activator.getLogger().warning("No command stack available when trying to save document!");
    } else {
      stack.markSaveLocation();
    }
  }

  public IFeatureProvider getFeatureProvider() {
    return getDiagramTypeProvider().getFeatureProvider();
  }

  protected RootEditPart getRootEditPart() {
    return getGraphicalViewer().getRootEditPart();
  }

  public void addModelChangeListener(ModelChangeListener listener) {
    data.modelChangeListeners.add(listener);
  }

  public void removeModelChangeListener(ModelChangeListener listener) {
    data.modelChangeListeners.remove(listener);
  }

  /**
   * clears the cache
   */
  public void clearCache() {
    activeRoute = null;
    this.activeConfig.diagram = null;
    getDiagramTypeProvider().getDiagram().eResource().eAdapters().clear();
    getEditingDomain().getResourceSet().getResources().remove(getDiagramTypeProvider().getDiagram().eResource());
  }

  public void addNewRoute() {
    DiagramOperations.addNewRoute(this);
  }

  public void deleteRoute() {
    RouteSupport selectedRoute = getSelectedRoute();
    if (selectedRoute != null) {
      DiagramOperations.deleteRoute(this, selectedRoute);
    }
  }

  /**
   * @return the editor
   */
  public RiderEditor getEditor() {
    return this.editor;
  }
 
  public DesignerCache getActiveConfig() {
    return this.activeConfig;
  }
 
  /* (non-Javadoc)
   * @see org.eclipse.debug.core.IBreakpointsListener#breakpointsAdded(org.eclipse.debug.core.model.IBreakpoint[])
   */
  @Override
  public void breakpointsAdded(IBreakpoint[] breakpoints) {
    Display.getDefault().asyncExec(new Runnable() {
      @Override
      public void run() {
        refreshDiagramContents();       
      }
    });
  }
 
  /* (non-Javadoc)
   * @see org.eclipse.debug.core.IBreakpointsListener#breakpointsChanged(org.eclipse.debug.core.model.IBreakpoint[], org.eclipse.core.resources.IMarkerDelta[])
   */
  @Override
  public void breakpointsChanged(IBreakpoint[] breakpoints,
      IMarkerDelta[] deltas) {
    Display.getDefault().asyncExec(new Runnable() {
      @Override
      public void run() {
        refreshDiagramContents();       
      }
    });
  }
 
  /* (non-Javadoc)
   * @see org.eclipse.debug.core.IBreakpointsListener#breakpointsRemoved(org.eclipse.debug.core.model.IBreakpoint[], org.eclipse.core.resources.IMarkerDelta[])
   */
  @Override
  public void breakpointsRemoved(IBreakpoint[] breakpoints,
      IMarkerDelta[] deltas) {
    Display.getDefault().asyncExec(new Runnable() {
      @Override
      public void run() {
        refreshDiagramContents();       
      }
    });
  }

  /* (non-Javadoc)
   * @see org.eclipse.debug.core.IDebugEventSetListener#handleDebugEvents(org.eclipse.debug.core.DebugEvent[])
   */
  @Override
  public void handleDebugEvents(DebugEvent[] events) {
    for (DebugEvent ev : events) {
      System.err.println(ev);
      if (ev.getSource() instanceof CamelThread == false && ev.getSource() instanceof CamelStackFrame == false) continue;
      if (ev.getSource() instanceof CamelThread && (ev.getKind() == DebugEvent.TERMINATE || ev.getKind() == DebugEvent.RESUME)) {
        // we are only interested in hit camel breakpoints
        resetHighlightBreakpointNode();
      } else {
        if (ev.getSource() instanceof CamelThread) {
          CamelThread thread = (CamelThread)ev.getSource();
          if (ev.getKind() == DebugEvent.SUSPEND && ev.getDetail() == DebugEvent.BREAKPOINT) {
            // a breakpoint was hit and thread is on suspend -> stack should be selected in tree now
            try {
              CamelStackFrame stackFrame = (CamelStackFrame)thread.getTopStackFrame();
              if (stackFrame != null) highlightBreakpointNodeWithID(stackFrame.getEndpointId());
            } catch (DebugException ex) {
              Activator.getLogger().error(ex);
            }
          }
        }
      }
    }
  }
 
  /**
   * @return the highlightedNodeInDebugger
   */
  public synchronized AbstractNode getHighlightedNodeInDebugger() {
    return this.highlightedNodeInDebugger;
  }
 
  /**
   * highlights the node currently in breakpoint
   *
   * @param endpointNodeId  the node id
   */
  private synchronized void highlightBreakpointNodeWithID(String endpointNodeId) {
    // get the correct node for the id
    final AbstractNode node = getModel().getNode(endpointNodeId);
   
    if (node == null) return;
    if (this.highlightedNodeInDebugger != null && node.getId() != null && node.getId().equals(highlightedNodeInDebugger.getId())) return;

    // reset old highlight
    resetHighlightBreakpointNode();
   
    // add highlight to new node
    setDebugHighLight(node, true);
       
    // remember the new highlighted node
    this.highlightedNodeInDebugger = node;
  }
 
  /**
   * resets the highlight from the highlighted node
   */
  private synchronized void resetHighlightBreakpointNode() {
    setDebugHighLight(this.highlightedNodeInDebugger, false);
    this.highlightedNodeInDebugger = null;
  }
 
  /**
   * switches the debug highlight for a given node on or off
   *
   * @param bo      the node
   * @param highlight    the highlight status
   */
  private synchronized void setDebugHighLight(AbstractNode bo, boolean highlight) {
    if (bo == null) return;
   
    // delegate to an operation command for async transacted diagram update
    DiagramOperations.highlightNode(this, bo, highlight);
  }
}
TOP

Related Classes of org.fusesource.ide.camel.editor.editor.RiderDesignEditor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.