/*******************************************************************************
* Copyright (c) 2005-2008 Polarion Software.
* 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:
* Igor Burilo - Initial API and implementation
*******************************************************************************/
package org.eclipse.team.svn.revision.graph.graphic;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.gef.DefaultEditDomain;
import org.eclipse.gef.EditPartViewer;
import org.eclipse.gef.GraphicalViewer;
import org.eclipse.gef.MouseWheelHandler;
import org.eclipse.gef.MouseWheelZoomHandler;
import org.eclipse.gef.editparts.ScalableRootEditPart;
import org.eclipse.gef.editparts.ZoomManager;
import org.eclipse.gef.ui.actions.ActionRegistry;
import org.eclipse.gef.ui.parts.GraphicalViewerKeyHandler;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.widgets.Control;
import org.eclipse.team.svn.core.operation.AbstractActionOperation;
import org.eclipse.team.svn.core.operation.CompositeOperation;
import org.eclipse.team.svn.core.operation.IActionOperation;
import org.eclipse.team.svn.core.operation.UnreportableException;
import org.eclipse.team.svn.core.resource.IRepositoryResource;
import org.eclipse.team.svn.revision.graph.SVNRevisionGraphMessages;
import org.eclipse.team.svn.revision.graph.SVNRevisionGraphPlugin;
import org.eclipse.team.svn.revision.graph.cache.RepositoryCacheInfo;
import org.eclipse.team.svn.revision.graph.cache.RepositoryCachesManager;
import org.eclipse.team.svn.revision.graph.cache.TimeMeasure;
import org.eclipse.team.svn.revision.graph.graphic.actions.AddRevisionLinksAction;
import org.eclipse.team.svn.revision.graph.graphic.actions.ComparePropertiesAction;
import org.eclipse.team.svn.revision.graph.graphic.actions.CompareWithEachOtherAction;
import org.eclipse.team.svn.revision.graph.graphic.actions.CompareWithHeadAction;
import org.eclipse.team.svn.revision.graph.graphic.actions.CompareWithPreviousAction;
import org.eclipse.team.svn.revision.graph.graphic.actions.CreateBranchTagAction;
import org.eclipse.team.svn.revision.graph.graphic.actions.CreatePatchAction;
import org.eclipse.team.svn.revision.graph.graphic.actions.ExportAction;
import org.eclipse.team.svn.revision.graph.graphic.actions.ExtractAction;
import org.eclipse.team.svn.revision.graph.graphic.actions.HideIncomingMergeConnectionsAction;
import org.eclipse.team.svn.revision.graph.graphic.actions.HideOutgoingMergeConnectionsAction;
import org.eclipse.team.svn.revision.graph.graphic.actions.OpenAction;
import org.eclipse.team.svn.revision.graph.graphic.actions.RevisionGraphContextMenuManager;
import org.eclipse.team.svn.revision.graph.graphic.actions.ShowAnnotationAction;
import org.eclipse.team.svn.revision.graph.graphic.actions.ShowHistoryAction;
import org.eclipse.team.svn.revision.graph.graphic.actions.ShowIncomingMergeConnectionsAction;
import org.eclipse.team.svn.revision.graph.graphic.actions.ShowOutgoingMergeConnectionsAction;
import org.eclipse.team.svn.revision.graph.graphic.actions.ShowPropertiesAction;
import org.eclipse.team.svn.revision.graph.graphic.editpart.GraphEditPartFactory;
import org.eclipse.team.svn.revision.graph.graphic.editpart.GraphScalableRootEditPart;
import org.eclipse.team.svn.revision.graph.operation.AddMergeInfoOperation;
import org.eclipse.team.svn.revision.graph.operation.CheckRepositoryConnectionOperation;
import org.eclipse.team.svn.revision.graph.operation.CreateCacheDataOperation;
import org.eclipse.team.svn.revision.graph.operation.CreateRevisionGraphModelOperation;
import org.eclipse.team.svn.revision.graph.operation.RevisionGraphUtility;
import org.eclipse.team.svn.revision.graph.preferences.SVNRevisionGraphPreferences;
import org.eclipse.team.svn.ui.action.remote.BranchTagAction;
import org.eclipse.team.svn.ui.utility.UIMonitorUtility;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
/**
* @author Igor Burilo
*/
public class RevisionGraphEditor extends GraphicalEditor {
protected RevisionGraphOutlinePage outlinePage;
public RevisionGraphEditor() {
setEditDomain(new DefaultEditDomain(this));
}
@Override
public void init(IEditorSite site, IEditorInput input) throws PartInitException {
super.init(site, input);
}
/**
* Set up the editor's inital content (after creation).
*/
@Override
protected void initializeGraphicalViewer() {
/*
* This can be a time consuming operation, e.g.
* for 43000 revisions it takes about 62 sec.
* But it seems we can't do anything with it, as
* this operation has to be executed in UI thread.
*
* See GEF bug: https://bugs.eclipse.org/bugs/show_bug.cgi?id=255534
*/
GraphicalViewer viewer = getGraphicalViewer();
TimeMeasure setContentsMeasure = new TimeMeasure("Set contents"); //$NON-NLS-1$
//set the contents of this editor
viewer.setContents(getModel());
setContentsMeasure.end();
// listen for dropped parts
//viewer.addDropTargetListener(createTransferDropTargetListener());
}
/* (non-Javadoc)
* @see org.eclipse.ui.part.EditorPart#setInput(org.eclipse.ui.IEditorInput)
*/
@Override
protected void setInput(IEditorInput input) {
super.setInput(input);
IRepositoryResource resource = ((RevisionGraphEditorInput) input).getResource();
String partName = SVNRevisionGraphMessages.format(SVNRevisionGraphMessages.RevisionGraphEditor_EditName, new Object[]{resource.getName(), resource.getSelectedRevision().toString()});
this.setPartName(partName);
}
/**
* See {@link RevisionGraphEditorInput#getModel()}
*/
public Object getModel() {
RevisionGraphEditorInput editorInput = (RevisionGraphEditorInput) this.getEditorInput();
return editorInput.getModel();
}
/**
* Configure the graphical viewer before it receives contents.
*
This is the place to choose an appropriate RootEditPart and EditPartFactory
* for your editor. The RootEditPart determines the behavior of the editor's "work-area".
* For example, GEF includes zoomable and scrollable root edit parts. The EditPartFactory
* maps model elements to edit parts (controllers).
* @see org.eclipse.gef.ui.parts.GraphicalEditor#configureGraphicalViewer()
*/
@Override
protected void configureGraphicalViewer() {
super.configureGraphicalViewer();
GraphicalViewer viewer = getGraphicalViewer();
GraphScalableRootEditPart root = new GraphScalableRootEditPart();
//zoom
List zoomLevels = new ArrayList(3);
zoomLevels.add(ZoomManager.FIT_ALL);
zoomLevels.add(ZoomManager.FIT_WIDTH);
zoomLevels.add(ZoomManager.FIT_HEIGHT);
root.getZoomManager().setZoomLevelContributions(zoomLevels);
//it seems we don't need it
// IAction zoomIn = new ZoomInAction(root.getZoomManager());
// IAction zoomOut = new ZoomOutAction(root.getZoomManager());
// getActionRegistry().registerAction(zoomIn);
// getActionRegistry().registerAction(zoomOut);
// getSite().getKeyBindingService().registerAction(zoomIn);
// getSite().getKeyBindingService().registerAction(zoomOut);
root.getZoomManager().setZoom(1);
// Scroll-wheel Zoom
getGraphicalViewer().setProperty(MouseWheelHandler.KeyGenerator.getKey(SWT.MOD1),
MouseWheelZoomHandler.SINGLETON);
viewer.setRootEditPart(root);
viewer.setEditPartFactory(new GraphEditPartFactory());
viewer.setKeyHandler(new GraphicalViewerKeyHandler(viewer));
Object model = this.getModel();
if (model instanceof RevisionRootNode) {
((RevisionRootNode) model).init();
//context menu
RevisionGraphContextMenuManager menuManager = new RevisionGraphContextMenuManager(viewer, this, getActionRegistry());
viewer.setContextMenu(menuManager);
getSite().registerContextMenu(menuManager, viewer);
//add key listener
viewer.getControl().addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent event) {
if (event.keyCode == SWT.F5) {
RevisionGraphEditor.this.handleRefresh();
}
}
});
}
}
public void handleRefresh() {
final Object objModel = this.getModel();
if (!(objModel instanceof RevisionRootNode)) {
return;
}
final RevisionRootNode previousModel = (RevisionRootNode) objModel;
final IRepositoryResource resource = previousModel.getRepositoryResource();
//TODO disable editor during refresh: take note that cancel can be called
CompositeOperation op = new CompositeOperation("Operation_RefreshGraph", SVNRevisionGraphMessages.class); //$NON-NLS-1$
//check if cache is calculating now
RepositoryCacheInfo cacheInfo = SVNRevisionGraphPlugin.instance().getRepositoryCachesManager().getCache(resource);
if (cacheInfo != null && cacheInfo.isCacheDataCalculating()) {
UIMonitorUtility.getDisplay().syncExec(new Runnable() {
public void run() {
MessageDialog dlg = RevisionGraphUtility.getCacheCalculatingDialog(RepositoryCachesManager.getRepositoryRoot(resource));
dlg.open();
}
});
return;
}
//check repository connection
CheckRepositoryConnectionOperation checkConnectionOp = new CheckRepositoryConnectionOperation(resource, previousModel.isIncludeMergeInfo(), false);
op.add(checkConnectionOp);
//update cache
boolean isSkipFetchErrors = SVNRevisionGraphPreferences.getGraphBoolean(SVNRevisionGraphPlugin.instance().getPreferenceStore(), SVNRevisionGraphPreferences.GRAPH_SKIP_ERRORS);
CreateCacheDataOperation updateCacheOp = new CreateCacheDataOperation(resource, true, checkConnectionOp, isSkipFetchErrors);
op.add(updateCacheOp, new IActionOperation[]{checkConnectionOp});
//create model
final CreateRevisionGraphModelOperation createModelOp = new CreateRevisionGraphModelOperation(resource, updateCacheOp);
createModelOp.setRevisionsRange(previousModel.getFromRevision(), previousModel.getToRevision());
op.add(createModelOp, new IActionOperation[]{updateCacheOp});
//add merge info
AddMergeInfoOperation addMergeInfoOp = new AddMergeInfoOperation(createModelOp, checkConnectionOp);
op.add(addMergeInfoOp, new IActionOperation[]{createModelOp});
//visualize
op.add(new AbstractActionOperation("Operation_RefreshGraph", SVNRevisionGraphMessages.class) { //$NON-NLS-1$
protected void runImpl(IProgressMonitor monitor) throws Exception {
if (createModelOp.getModel() != null) {
UIMonitorUtility.getDisplay().syncExec(new Runnable() {
public void run() {
GraphicalViewer viewer = getGraphicalViewer();
Control control = null;
if (viewer != null && (control = viewer.getControl()) != null && !control.isDisposed()) {
RevisionRootNode modelObject = new RevisionRootNode(resource, createModelOp.getModel(), createModelOp.getRepositoryCache());
((RevisionGraphEditorInput) getEditorInput()).setModel(modelObject);
previousModel.refresh(modelObject);
modelObject.init();
viewer.setContents(modelObject);
}
}
});
} else {
//it should not happen in normal case
throw new UnreportableException("Failed to update revision graph, its model is null"); //$NON-NLS-1$
}
}
}, new IActionOperation[] {createModelOp});
UIMonitorUtility.doTaskScheduledDefault(this, op);
}
protected RevisionGraphOutlinePage getOutlinePage() {
if(this.outlinePage == null && this.getGraphicalViewer() != null) {
this.outlinePage = new RevisionGraphOutlinePage(this.getGraphicalViewer());
}
return this.outlinePage;
}
public Object getAdapter(Class adapter) {
if(adapter == GraphicalViewer.class || adapter == EditPartViewer.class) {
return getGraphicalViewer();
} else if(adapter == ZoomManager.class) {
return ((ScalableRootEditPart) getGraphicalViewer().getRootEditPart()).getZoomManager();
}
else if (adapter == IContentOutlinePage.class) {
return new RevisionGraphOutlinePage(this.getGraphicalViewer());
}
return super.getAdapter(adapter);
}
@Override
public void doSave(IProgressMonitor monitor) {
}
public boolean isDirty() {
return false;
}
public boolean isSaveAsAllowed() {
return false;
}
@Override
protected void createActions() {
//register other actions
ActionRegistry registry = getActionRegistry();
IAction action;
List selectedActions = getSelectionActions();
action = new ShowHistoryAction(this);
registry.registerAction(action);
selectedActions.add(action.getId());
action = new CompareWithEachOtherAction(this);
registry.registerAction(action);
selectedActions.add(action.getId());
action = new CompareWithHeadAction(this);
registry.registerAction(action);
selectedActions.add(action.getId());
action = new CompareWithPreviousAction(this);
registry.registerAction(action);
selectedActions.add(action.getId());
action = new ShowPropertiesAction(this);
registry.registerAction(action);
selectedActions.add(action.getId());
action = new ComparePropertiesAction(this);
registry.registerAction(action);
selectedActions.add(action.getId());
action = new ExportAction(this);
registry.registerAction(action);
selectedActions.add(action.getId());
action = new CreatePatchAction(this);
registry.registerAction(action);
selectedActions.add(action.getId());
action = new ExtractAction(this);
registry.registerAction(action);
selectedActions.add(action.getId());
action = new CreateBranchTagAction(this, BranchTagAction.BRANCH_ACTION);
registry.registerAction(action);
selectedActions.add(action.getId());
action = new CreateBranchTagAction(this, BranchTagAction.TAG_ACTION);
registry.registerAction(action);
selectedActions.add(action.getId());
action = new AddRevisionLinksAction(this);
registry.registerAction(action);
selectedActions.add(action.getId());
action = new OpenAction(this);
registry.registerAction(action);
selectedActions.add(action.getId());
action = new ShowAnnotationAction(this);
registry.registerAction(action);
selectedActions.add(action.getId());
action = new ShowOutgoingMergeConnectionsAction(this);
registry.registerAction(action);
selectedActions.add(action.getId());
action = new HideOutgoingMergeConnectionsAction(this);
registry.registerAction(action);
selectedActions.add(action.getId());
action = new ShowIncomingMergeConnectionsAction(this);
registry.registerAction(action);
selectedActions.add(action.getId());
action = new HideIncomingMergeConnectionsAction(this);
registry.registerAction(action);
selectedActions.add(action.getId());
}
public GraphicalViewer getViewer() {
return getGraphicalViewer();
}
@Override
public void dispose() {
//clear resources
RevisionGraphEditorInput editorInput = (RevisionGraphEditorInput) this.getEditorInput();
if (editorInput != null) {
Object model = editorInput.getModel();
if (model instanceof RevisionRootNode) {
RevisionRootNode rootNode = (RevisionRootNode) model;
rootNode.getRepositoryCache().getCacheInfo().disposeRepositoryCache(rootNode.getRepositoryResource());
}
editorInput.setModel(null);
}
super.dispose();
}
}