/*******************************************************************************
* Copyright (c) 2012 BundleMaker Project Team
* 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:
* Nils Hartmann - initial API and implementation
******************************************************************************/
package org.bundlemaker.core.ui.view.transformationhistory.view;
import java.lang.reflect.InvocationTargetException;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import org.bundlemaker.core.analysis.IBundleMakerArtifact;
import org.bundlemaker.core.analysis.IRootArtifact;
import org.bundlemaker.core.resource.IModularizedSystem;
import org.bundlemaker.core.resource.ITransformation;
import org.bundlemaker.core.selection.IArtifactSelection;
import org.bundlemaker.core.ui.artifact.CommonNavigatorUtils;
import org.bundlemaker.core.ui.event.selection.workbench.view.AbstractArtifactSelectionAwareViewPart;
import org.bundlemaker.core.ui.view.transformationhistory.ITransformationLabelProvider;
import org.bundlemaker.core.ui.view.transformationhistory.internal.TransformationHistoryImages;
import org.bundlemaker.core.ui.view.transformationhistory.labelprovider.AddArtifactsTransformationLabelProvider;
import org.bundlemaker.core.ui.view.transformationhistory.labelprovider.CreateGroupTransformationLabelProvider;
import org.bundlemaker.core.ui.view.transformationhistory.labelprovider.CreateModuleTransformationLabelProvider;
import org.bundlemaker.core.ui.view.transformationhistory.labelprovider.RenameModuleTransformationLabelProvider;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.layout.TreeColumnLayout;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.TreeViewerColumn;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IWorkbenchActionConstants;
/**
* @author Nils Hartmann (nils@nilshartmann.net)
*
*/
public class HistoryView extends AbstractArtifactSelectionAwareViewPart {
/**
* The ID of the view as specified by the extension.
*/
public static final String ID = "org.bundlemaker.core.ui.transformations.history.view.HistoryView";
private TreeViewer _viewer;
private Action _resetAction;
private Action _pinSelectionAction;
private Action _undoLastTransformationAction;
protected boolean _selectionPinnned = false;
/**
* Comparator to make sure ordering in the tree (top-level elements) always remain the same
*/
private final RootArtifactComparator _rootArtifactComparator = new RootArtifactComparator();
/**
* The constructor.
*/
public HistoryView() {
}
/**
* This is a callback that will allow us to create the viewer and initialize it.
*/
@Override
public void createPartControl(Composite parent) {
_viewer = new TreeViewer(parent, SWT.H_SCROLL | SWT.V_SCROLL | SWT.SINGLE | SWT.FULL_SELECTION);
_viewer.setContentProvider(new HistoryViewContentProvider());
createTreeColumns();
createActions();
hookContextMenu();
hookDoubleClickAction();
contributeToActionBars();
_viewer.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
HistoryView.this.refreshEnablement();
}
});
refreshEnablement();
}
protected List<ITransformationLabelProvider> getRegisteredTransformationLabelProvider() {
// TODO use extension points
List<ITransformationLabelProvider> registeredTransformationLabelProviders = new LinkedList<ITransformationLabelProvider>();
registeredTransformationLabelProviders.add(new CreateGroupTransformationLabelProvider());
registeredTransformationLabelProviders.add(new AddArtifactsTransformationLabelProvider());
registeredTransformationLabelProviders.add(new CreateModuleTransformationLabelProvider());
registeredTransformationLabelProviders.add(new RenameModuleTransformationLabelProvider());
return registeredTransformationLabelProviders;
}
private void createTreeColumns() {
List<ITransformationLabelProvider> registeredTransformationLabelProvider = getRegisteredTransformationLabelProvider();
Tree tree = _viewer.getTree();
TreeColumnLayout layout = new TreeColumnLayout();
TreeViewerColumn column = new TreeViewerColumn(_viewer, SWT.NONE);
column.getColumn().setText("Transformation");
column.setLabelProvider(new HistoryViewTitleColumnLabelProvider(registeredTransformationLabelProvider));
column.getColumn().setResizable(true);
column.getColumn().setMoveable(false);
layout.setColumnData(column.getColumn(), new ColumnWeightData(20));
column = new TreeViewerColumn(_viewer, SWT.NONE);
column.setLabelProvider(new HistoryViewDetailsColumnLabelProvider(registeredTransformationLabelProvider));
column.getColumn().setText("Details");
column.getColumn().setResizable(true);
column.getColumn().setMoveable(false);
layout.setColumnData(column.getColumn(), new ColumnWeightData(80));
tree.getParent().setLayout(layout);
tree.setLinesVisible(true);
tree.setHeaderVisible(true);
tree.layout(true);
}
private void refreshEnablement() {
IStructuredSelection structuredSelection = (IStructuredSelection) _viewer.getSelection();
boolean hasSelection = !structuredSelection.isEmpty();
if (hasSelection) {
IModularizedSystem modularizedSystem = getSelectedModularizedSystem();
// Actions are enabled if a transformation or an modularized system with at least one transformation is selected
boolean actionsEnabled = (modularizedSystem != null && !modularizedSystem.getTransformations().isEmpty());
_undoLastTransformationAction.setEnabled(actionsEnabled);
_resetAction.setEnabled(actionsEnabled);
//
return;
}
// No selection.
// Reset action is always disabled in this case
_resetAction.setEnabled(false);
// Undo action is enabled if there is exactly one Modularized System that has at least one transformation
List<IRootArtifact> viewerContent = getViewerContent();
if (viewerContent.size() != 1) {
_undoLastTransformationAction.setEnabled(false);
return;
}
_undoLastTransformationAction.setEnabled(!viewerContent.get(0).getModularizedSystem().getTransformations()
.isEmpty());
}
/**
* @return
*/
private IModularizedSystem getSelectedModularizedSystem() {
IStructuredSelection structuredSelection = (IStructuredSelection) _viewer.getSelection();
if (structuredSelection.isEmpty()) {
return null;
}
Object o = structuredSelection.getFirstElement();
if (o instanceof IRootArtifact) {
return ((IRootArtifact) o).getModularizedSystem();
}
if (o instanceof ITransformation) {
return getModularizedSystem((ITransformation) o);
}
return null;
}
private void hookContextMenu() {
MenuManager menuMgr = new MenuManager("#PopupMenu");
menuMgr.setRemoveAllWhenShown(true);
menuMgr.addMenuListener(new IMenuListener() {
@Override
public void menuAboutToShow(IMenuManager manager) {
HistoryView.this.fillContextMenu(manager);
}
});
Menu menu = menuMgr.createContextMenu(_viewer.getControl());
_viewer.getControl().setMenu(menu);
// Do not register for now
// getSite().registerContextMenu(menuMgr, _viewer);
}
private void contributeToActionBars() {
IActionBars bars = getViewSite().getActionBars();
fillLocalPullDown(bars.getMenuManager());
fillLocalToolBar(bars.getToolBarManager());
}
private void fillLocalPullDown(IMenuManager manager) {
// manager.add(action2);
}
private void fillContextMenu(IMenuManager manager) {
manager.add(_resetAction);
manager.add(_undoLastTransformationAction);
manager.add(new Separator());
// Other plug-ins can contribute there actions here
manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
}
private void fillLocalToolBar(IToolBarManager manager) {
manager.add(_pinSelectionAction);
manager.add(_undoLastTransformationAction);
// manager.add(_resetAction);
// manager.add(action2);
// manager.add(new Separator());
}
private void createActions() {
_resetAction = new Action() {
@Override
public void run() {
resetHistory();
}
};
_resetAction.setText("Reset to this Transformation");
_resetAction.setToolTipText("Resets the History to this Transformation by undoing all later Transformations");
_resetAction.setImageDescriptor(TransformationHistoryImages.RESET_ICON.getImageDescriptor());
_undoLastTransformationAction = new Action() {
@Override
public void run() {
undoLastTransformation();
}
};
_undoLastTransformationAction.setText("Undo last Transformation");
_undoLastTransformationAction.setToolTipText("Reverts the last executed Transformation on the selected System");
_undoLastTransformationAction.setImageDescriptor(TransformationHistoryImages.UNDO_TRANSFORMATION
.getImageDescriptor());
_pinSelectionAction = new PinSelectionAction();
}
private void hookDoubleClickAction() {
//
}
private void resetHistory() {
IStructuredSelection selection = (IStructuredSelection) _viewer.getSelection();
if (selection.isEmpty()) {
return;
}
Object firstElement = selection.getFirstElement();
// If no transformation is selected undo complete history
final ITransformation transformation = (firstElement instanceof ITransformation) ? (ITransformation) firstElement
: null;
final IModularizedSystem modularizedSystem = (firstElement instanceof IRootArtifact) ? ((IRootArtifact) firstElement)
.getModularizedSystem() : getModularizedSystem(transformation);
ProgressMonitorDialog dialog = new ProgressMonitorDialog(getViewSite().getShell());
try {
dialog.run(true, true, new IRunnableWithProgress() {
@Override
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
modularizedSystem.undoUntilTransformation(monitor, transformation);
}
});
CommonNavigatorUtils.refresh(CommonNavigatorUtils.PROJECT_EXPLORER_VIEW_ID);
} catch (InvocationTargetException e) {
// TODO
e.printStackTrace();
} catch (InterruptedException e) {
// doesn't matter
}
refreshEnablement();
}
private void undoLastTransformation() {
IStructuredSelection selection = (IStructuredSelection) _viewer.getSelection();
IModularizedSystem modularizedSystem;
if (selection.isEmpty()) {
List<IRootArtifact> viewerContent = getViewerContent();
if (viewerContent.size() < 1) {
return;
}
IRootArtifact rootArtifact = viewerContent.get(0);
modularizedSystem = rootArtifact.getModularizedSystem();
} else {
Object firstElement = selection.getFirstElement();
modularizedSystem = (firstElement instanceof IRootArtifact) ? ((IRootArtifact) firstElement)
.getModularizedSystem() : getModularizedSystem((ITransformation) firstElement);
}
modularizedSystem.undoLastTransformation();
CommonNavigatorUtils.refresh(CommonNavigatorUtils.PROJECT_EXPLORER_VIEW_ID);
_viewer.refresh();
refreshEnablement();
}
/**
* @param transformation
* @return
*/
private IModularizedSystem getModularizedSystem(ITransformation transformation) {
List<IRootArtifact> systems = getViewerContent();
for (IRootArtifact rootArtifact : systems) {
IModularizedSystem modularizedSystem = rootArtifact.getModularizedSystem();
if (modularizedSystem.getTransformations().contains(transformation)) {
return modularizedSystem;
}
}
throw new IllegalStateException("Transformation without Modularized System detected: " + transformation);
}
private void showMessage(String message) {
MessageDialog.openInformation(_viewer.getControl().getShell(), "Transformation History", message);
}
private List<IRootArtifact> getViewerContent() {
List<IRootArtifact> systems = (List<IRootArtifact>) _viewer.getInput();
if (systems == null) {
systems = Collections.emptyList();
}
return systems;
}
/**
* Passing the focus request to the viewer's control.
*/
@Override
public void setFocus() {
_viewer.getControl().setFocus();
}
/*
* (non-Javadoc)
*
* @see org.bundlemaker.core.ui.event.selection.workbench.view.AbstractArtifactSelectionAwareViewPart#
* setCurrentArtifactSelection(org.bundlemaker.core.ui.event.selection.IArtifactSelection)
*/
@Override
protected void setCurrentArtifactSelection(IArtifactSelection artifactSelection) {
if (isSelectionPinnned() && getCurrentArtifactSelection().hasSelectedArtifacts()) {
// artifacts are already selected and selection is pinned: ignore new selection
return;
}
super.setCurrentArtifactSelection(artifactSelection);
List<IBundleMakerArtifact> selectedArtifacts = artifactSelection.getSelectedArtifacts();
setContentFromArtifacts(selectedArtifacts);
}
public void setContentFromArtifacts(List<IBundleMakerArtifact> artifacts) {
final List<IRootArtifact> newModularizedSystems = new LinkedList<IRootArtifact>();
// Determine new list of modularized systems from selected IArtifacts
for (IBundleMakerArtifact artifact : artifacts) {
IRootArtifact root = artifact.getRoot();
// IModularizedSystem modularizedSystem = root.getModularizedSystem();
if (!newModularizedSystems.contains(root)) {
newModularizedSystems.add(root);
}
}
// Sort
Collections.sort(newModularizedSystems, _rootArtifactComparator);
@SuppressWarnings("unchecked")
List<IRootArtifact> currentModularizedSystems = (List<IRootArtifact>) _viewer.getInput();
if (!newModularizedSystems.equals(currentModularizedSystems)) {
_viewer.setInput(newModularizedSystems);
if (newModularizedSystems.size() == 1) {
// if only one system is select expand by default
_viewer.expandAll();
}
}
refreshEnablement();
}
/**
* @return the selectionPinnned
*/
public boolean isSelectionPinnned() {
return _selectionPinnned;
}
/**
* @param selectionPinnned
* the selectionPinnned to set
*/
public void setSelectionPinnned(boolean selectionPinnned) {
_selectionPinnned = selectionPinnned;
}
/*
* (non-Javadoc)
*
* @see org.bundlemaker.core.ui.event.selection.workbench.view.AbstractArtifactSelectionAwareViewPart#getProviderId()
*/
@Override
protected String getProviderId() {
return ID;
}
class RootArtifactComparator implements Comparator<IRootArtifact> {
private final ModularizedSystemComparator _modularizedSystemComparator = new ModularizedSystemComparator();
/*
* (non-Javadoc)
*
* @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
*/
@Override
public int compare(IRootArtifact mod1, IRootArtifact mod2) {
return _modularizedSystemComparator.compare(mod1.getModularizedSystem(), mod2.getModularizedSystem());
}
}
class ModularizedSystemComparator implements Comparator<IModularizedSystem> {
/*
* (non-Javadoc)
*
* @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
*/
@Override
public int compare(IModularizedSystem mod1, IModularizedSystem mod2) {
int result = mod1.getBundleMakerProject().getName().compareTo(mod2.getBundleMakerProject().getName());
if (result == 0) {
// projects are equal, compare modularized system name
result = mod1.getName().compareTo(mod2.getName());
}
return 0;
}
}
class PinSelectionAction extends Action {
public PinSelectionAction() {
super("Pin Selection", IAction.AS_CHECK_BOX);
setToolTipText("Pin Selection");
setImageDescriptor(TransformationHistoryImages.PIN_SELECTION.getImageDescriptor());
update();
}
@Override
public void run() {
setSelectionPinnned(isChecked());
}
public void update() {
setChecked(isSelectionPinnned());
}
}
}