package org.bundlemaker.core.ui.editor.xref3;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.bundlemaker.core.analysis.IBundleMakerArtifact;
import org.bundlemaker.core.analysis.IDependency;
import org.bundlemaker.core.analysis.IRootArtifact;
import org.bundlemaker.core.common.history.History;
import org.bundlemaker.core.common.history.IHistoryChangedListener;
import org.bundlemaker.core.jtype.ITypeArtifact;
import org.bundlemaker.core.selection.Selection;
import org.bundlemaker.core.ui.artifact.tree.ArtifactTreeContentProvider;
import org.bundlemaker.core.ui.artifact.tree.ArtifactTreeLabelProvider;
import org.bundlemaker.core.ui.artifact.tree.ArtifactTreeViewerFactory;
import org.bundlemaker.core.ui.artifact.tree.VisibleArtifactsFilter;
import org.bundlemaker.core.ui.view.dependencytree.DefaultExpandStrategy;
import org.bundlemaker.core.ui.view.dependencytree.Helper;
import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.GroupMarker;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.IWorkbenchPartSite;
/**
* <p>
* </p>
*
* @author Gerd Wütherich (gerd@gerd-wuetherich.de)
*/
public class XRefComposite extends Composite {
/** the from tree viewer */
private TreeViewer _fromTreeViewer;
/** the to tree viewer */
private TreeViewer _centerViewer;
/** the to tree viewer */
private TreeViewer _toTreeViewer;
/** Label that displays details about the current selection */
private Label _detailsLabel;
/** - */
private String _providerId;
/** - */
private DefaultExpandStrategy _expandStrategy;
private XRefTreeArtifactLabelProvider _artifactLabelProvider;
private IWorkbenchPartSite _site;
private SelectionHistory _selectionHistory;
/**
* <p>
* Creates a new instance of type {@link XRefComposite}.
* </p>
*
* @param parent
* @param iWorkbenchPartSite
*/
public XRefComposite(Composite parent, String providerId, IWorkbenchPartSite iWorkbenchPartSite) {
super(parent, SWT.NONE);
Assert.isNotNull(providerId);
_providerId = providerId;
_site = iWorkbenchPartSite;
init();
}
public void setSelectedArtifacts(List<IBundleMakerArtifact> artifacts) {
if (artifacts.isEmpty()) {
return;
}
IRootArtifact rootArtifact = artifacts.get(0).getRoot();
// Set Tree Viewer input
_fromTreeViewer.setInput(rootArtifact);
_centerViewer.setInput(rootArtifact);
_toTreeViewer.setInput(rootArtifact);
IBundleMakerArtifact[] selectedArtifacts = new IBundleMakerArtifact[artifacts.size()];
for (int i = 0; i < artifacts.size(); i++) {
IBundleMakerArtifact artifact = artifacts.get(i);
if (artifact.isInstanceOf(IRootArtifact.class)) {
artifact = ((ArtifactTreeContentProvider) _centerViewer.getContentProvider()).getVirtualRoot();
}
selectedArtifacts[i] = artifact;
}
StructuredSelection selection = new StructuredSelection(selectedArtifacts);
// (Re-)Expand Tree Viewer according to User settings
_expandStrategy.exandTreeViewer();
// Make sure selected Artifacts are visible in Center Tree Viewer
_centerViewer.setSelection(selection, true);
_fromTreeViewer.setSelection(new StructuredSelection());
_toTreeViewer.setSelection(new StructuredSelection());
// _fromTreeViewer.setSelection(
// new StructuredSelection(((ArtifactTreeContentProvider) _fromTreeViewer.getContentProvider()).getVirtualRoot()),
// true);
// expand at least to level two, to make sure that more than the root artifact is visible
_centerViewer.expandToLevel(2);
if (selectedArtifacts.length == 1) {
_centerViewer.expandToLevel(selectedArtifacts[0], 1);
}
_centerViewer.getTree().setFocus();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.swt.widgets.Composite#setFocus()
*/
@Override
public boolean setFocus() {
return _centerViewer.getTree().setFocus();
}
protected IRootArtifact getVirtualRoot(TreeViewer treeViewer) {
ArtifactTreeContentProvider artifactTreeContentProvider = (ArtifactTreeContentProvider) treeViewer
.getContentProvider();
return artifactTreeContentProvider.getVirtualRoot();
}
private Composite createToolBarComposite() {
Composite fromToolbar = new Composite(this, SWT.BORDER_SOLID);
GridData gridData = new GridData();
gridData.verticalAlignment = SWT.TOP;
gridData.horizontalAlignment = SWT.FILL;
gridData.grabExcessHorizontalSpace = true;
gridData.grabExcessVerticalSpace = false;
fromToolbar.setLayoutData(gridData);
fromToolbar.setLayout(new GridLayout(1, false));
return fromToolbar;
}
/**
* <p>
* </p>
*/
private void init() {
//
this.setLayout(new GridLayout(3, true));
//
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=162698
// https://bugs.eclipse.org/bugs/attachment.cgi?id=52918
Composite fromToolBarComposite = createToolBarComposite();
Composite centerToolBarComposite = createToolBarComposite();
Composite toToolBarComposite = createToolBarComposite();
//
_fromTreeViewer = ArtifactTreeViewerFactory.createDefaultArtifactTreeViewer(this);
_centerViewer = ArtifactTreeViewerFactory.createDefaultArtifactTreeViewer(this);
_toTreeViewer = ArtifactTreeViewerFactory.createDefaultArtifactTreeViewer(this);
_selectionHistory = new SelectionHistory(_fromTreeViewer, _centerViewer, _toTreeViewer);
_expandStrategy = new DefaultExpandStrategy();
_expandStrategy.init(_fromTreeViewer, _toTreeViewer);
_detailsLabel = new Label(this, SWT.NONE);
GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false, 3, 1);
_detailsLabel.setLayoutData(gridData);
//
_fromTreeViewer.setLabelProvider(new ArtifactTreeLabelProvider());
_artifactLabelProvider = new XRefTreeArtifactLabelProvider();
_centerViewer.setLabelProvider(_artifactLabelProvider);
_toTreeViewer.setLabelProvider(new ArtifactTreeLabelProvider());
// add SelectionListeners
_fromTreeViewer.addSelectionChangedListener(new FromArtifactsSelectionChangedListener());
_centerViewer.addSelectionChangedListener(new CenterArtifactsSelectionChangedListener());
_toTreeViewer.addSelectionChangedListener(new ToArtifactSelectionChangedListener());
// === Context-Menu Center Viewer ===
MenuManager menuMgr = new MenuManager();
menuMgr.setRemoveAllWhenShown(true);
menuMgr.addMenuListener(new IMenuListener() {
@Override
public void menuAboutToShow(IMenuManager mgr) {
fillContextMenu(mgr);
}
});
// menuMgr.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
Menu menu = menuMgr.createContextMenu(_centerViewer.getControl());
_centerViewer.getControl().setMenu(menu);
_site.registerContextMenu(menuMgr, _centerViewer);
_site.setSelectionProvider(_centerViewer);
// === Toolbar =====
ToolBarManager mgr1 = new ToolBarManager();
ExpandStrategyActionGroup fromGroup = new ExpandStrategyActionGroup(_expandStrategy, false);
fromGroup.fill(mgr1);
mgr1.createControl(fromToolBarComposite);
ToolBarManager mgr2 = new ToolBarManager();
mgr2.add(new BackInHistoryAction(_selectionHistory));
// mgr2.add(new ResetHistoryAction(_selectionHistory));
mgr2.add(new ForwadInHistoryAction(_selectionHistory));
mgr2.createControl(centerToolBarComposite);
ToolBarManager mgr3 = new ToolBarManager();
ExpandStrategyActionGroup toGroup = new ExpandStrategyActionGroup(_expandStrategy, true);
toGroup.fill(mgr3);
mgr3.createControl(toToolBarComposite);
}
private void fillContextMenu(IMenuManager manager) {
manager.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));
CreateModuleFromReferencedArtifactsAction action = new CreateModuleFromReferencedArtifactsAction(
_artifactLabelProvider.getBundleMakerArtifacts());
MoveReferencedArtifactsAction moveReferencedArtifactsAction = new MoveReferencedArtifactsAction(
_artifactLabelProvider.getBundleMakerArtifacts());
manager.add(new Separator("artifactsGroup"));
manager.appendToGroup("artifactsGroup", action);
manager.appendToGroup("artifactsGroup", moveReferencedArtifactsAction);
}
/**
* <p>
* </p>
*
* @param treeViewer
* @param visibleArtifacts
*/
private VisibleArtifactsFilter setVisibleArtifacts(TreeViewer treeViewer,
Collection<IBundleMakerArtifact> visibleArtifacts) {
Assert.isNotNull(treeViewer);
Assert.isNotNull(visibleArtifacts);
//
VisibleArtifactsFilter result = null;
// set redraw to false
treeViewer.getTree().setRedraw(false);
// set the filter
result = new VisibleArtifactsFilter(visibleArtifacts);
treeViewer.setFilters(new ViewerFilter[] { result });
// redraw again
treeViewer.getTree().setRedraw(true);
//
return result;
}
protected void setSelectedCenterArtifacts(Collection<IBundleMakerArtifact> selectedArtifacts) {
// store the top item
TreeItem toTreeTopItem = _toTreeViewer.getTree().getTopItem();
TreeItem fromTreeTopItem = _fromTreeViewer.getTree().getTopItem();
//
Set<IBundleMakerArtifact> fromArtifacts = new HashSet<IBundleMakerArtifact>();
for (IBundleMakerArtifact artifact : selectedArtifacts) {
if ("<< Missing Types >>".equals(artifact.getName())) {
// TODO WORKAROUND!!! BM-374
Collection<IDependency> missingTypesDependencies = artifact.getRoot().getDependenciesTo(artifact);
for (IDependency iDependency : missingTypesDependencies) {
Collection<IDependency> coreDependencies = iDependency.getCoreDependencies();
for (IDependency coreDependency : coreDependencies) {
fromArtifacts.add(coreDependency.getFrom());
}
}
} else {
Collection<IDependency> fromDependencies = artifact.getDependenciesFrom();
for (IDependency dep : fromDependencies) {
fromArtifacts.add(dep.getFrom());
}
}
}
//
Set<IBundleMakerArtifact> toArtifacts = new HashSet<IBundleMakerArtifact>();
for (IBundleMakerArtifact artifact : selectedArtifacts) {
Collection<IDependency> toDependencies = artifact.getDependenciesTo();
for (IDependency dep : toDependencies) {
toArtifacts.add(dep.getTo());
}
}
//
setVisibleArtifacts(_toTreeViewer, toArtifacts);
setVisibleArtifacts(_fromTreeViewer, fromArtifacts);
_expandStrategy.exandTreeViewer();
// Update Details Label
String detailsString = (selectedArtifacts.size() > 1 ? selectedArtifacts.size() + " Artifacts" : selectedArtifacts
.iterator().next().getName());
int fromSize = fromArtifacts.size();
detailsString += ", Referenced By: " + fromSize + " " + (fromSize > 1 ? "Artifacts" : "Artifact");
int toSize = toArtifacts.size();
detailsString += ", Referencing: " + toSize + " " + (toSize > 1 ? "Artifacts" : "Artifact");
_detailsLabel.setText(detailsString);
setSelectedDependencies(null);
// set the top item again
if (toTreeTopItem != null && !toTreeTopItem.isDisposed()) {
_toTreeViewer.getTree().setTopItem(toTreeTopItem);
} else if (_toTreeViewer.getTree().getItemCount() > 0) {
_toTreeViewer.getTree().setTopItem(_toTreeViewer.getTree().getItem(0));
}
if (fromTreeTopItem != null && !fromTreeTopItem.isDisposed()) {
_fromTreeViewer.getTree().setTopItem(fromTreeTopItem);
} else if (_fromTreeViewer.getTree().getItemCount() > 0) {
_fromTreeViewer.getTree().setTopItem(_fromTreeViewer.getTree().getItem(0));
}
}
/**
* <p>
* </p>
*
* @return
*/
protected String getDependencySelectionId() {
return Selection.MAIN_DEPENDENCY_SELECTION_ID;
}
/**
* <p>
* </p>
*
* @param selectedDetailDependencies
*/
private void setSelectedDependencies(Collection<IDependency> dependencies) {
//
Selection.instance().getDependencySelectionService()
.setSelection(getDependencySelectionId(), _providerId, dependencies);
}
/**
* <p>
* </p>
*
* @author Gerd Wütherich (gerd@gerd-wuetherich.de)
*
*/
private final class CenterArtifactsSelectionChangedListener implements ISelectionChangedListener {
/**
* {@inheritDoc}
*/
@Override
public void selectionChanged(SelectionChangedEvent event) {
//
IStructuredSelection structuredSelection = (IStructuredSelection) event.getSelection();
if (structuredSelection.isEmpty()) {
return;
}
List<IBundleMakerArtifact> selectedArtifacts = Helper.toArtifactList(structuredSelection.toList());
// don't highlight anything
_artifactLabelProvider.setBundleMakerArtifacts(null);
// reset selections in from and to viewer
_fromTreeViewer.setSelection(new StructuredSelection());
_toTreeViewer.setSelection(new StructuredSelection());
setSelectedCenterArtifacts(selectedArtifacts);
_centerViewer.refresh();
}
}
/**
* <p>
* </p>
*
* @author Gerd Wütherich (gerd@gerd-wuetherich.de)
*/
private final class FromArtifactsSelectionChangedListener implements ISelectionChangedListener {
/**
* {@inheritDoc}
*/
@Override
public void selectionChanged(SelectionChangedEvent event) {
//
IStructuredSelection structuredSelection = (IStructuredSelection) event.getSelection();
if (structuredSelection.isEmpty()) {
return;
}
// Reset Selection in 'to' Viewer
_toTreeViewer.setSelection(new StructuredSelection());
highlightSelectedDependencies(structuredSelection, true);
}
}
/**
* @param structuredSelection
* @param to
*/
protected void highlightSelectedDependencies(IStructuredSelection structuredSelection, boolean to) {
// Detect highlighted artifacts
List<IBundleMakerArtifact> selectedArtifacts = Helper.toArtifactList(structuredSelection.toList());
List<IBundleMakerArtifact> selectedCenterArtifacts = Helper.toArtifactList(_centerViewer.getSelection());
// Holds the dependencies that are published via DependencySelectionService
List<IDependency> selectedDpendencies = new LinkedList<IDependency>();
// Holds the Artifacts that should be highlighted in the center tree
Set<IBundleMakerArtifact> highlightedArtifacts = new HashSet<IBundleMakerArtifact>();
for (final IBundleMakerArtifact selectedArtifact : selectedArtifacts) {
Collection<IDependency> dependencies;
if (selectedArtifact instanceof ITypeArtifact) {
// TODO: WORKAROUND BM-369
Collection<IDependency> tempDependencies = (to ? selectedArtifact.getDependenciesTo() : selectedArtifact
.getDependenciesFrom());
dependencies = new HashSet<IDependency>();
for (IDependency iDependency : tempDependencies) {
IBundleMakerArtifact candidate = (to ? iDependency.getFrom() : iDependency.getTo());
if (candidate.equals(selectedArtifact)) {
dependencies.add(iDependency);
}
}
} else {
dependencies = (to ? selectedArtifact.getDependenciesTo(selectedCenterArtifacts) : selectedArtifact
.getDependenciesFrom(selectedCenterArtifacts));
}
for (IDependency dep : dependencies) {
selectedDpendencies.add(dep);
Collection<IDependency> coreDependencies = dep.getCoreDependencies();
for (IDependency coreDependency : coreDependencies) {
IBundleMakerArtifact referencedArtifact = (to ? coreDependency.getTo() : coreDependency.getFrom());
highlightedArtifacts.add(referencedArtifact);
// highlight all parents of the referenced artifact up to the selection in the center
while (referencedArtifact != null) {
if (selectedCenterArtifacts.contains(referencedArtifact)) {
break;
}
highlightedArtifacts.add(referencedArtifact);
referencedArtifact = referencedArtifact.getParent();
}
}
}
}
//
setSelectedDependencies(selectedDpendencies);
//
_artifactLabelProvider.setBundleMakerArtifacts(highlightedArtifacts);
_centerViewer.refresh();
// Build readable summery
String detailsText;
if (to) {
detailsText = (selectedArtifacts.size() == 1 ? selectedArtifacts.get(0).getName() + " references "
: selectedArtifacts.size() + " Artifacts referencing ");
int fromSize = highlightedArtifacts.size();
detailsText += fromSize + (fromSize == 1 ? " Artifact" : " Artifacts");
detailsText += " in " + selectedArtifacts.get(0).getRoot().getName();
} else {
detailsText = (selectedArtifacts.size() == 1 ? selectedArtifacts.get(0).getName() + " referenced by "
: selectedArtifacts.size() + " Artifacts referenced by ");
int toSize = highlightedArtifacts.size();
detailsText += toSize + (toSize == 1 ? " Artifact" : " Artifacts");
detailsText += " in " + selectedArtifacts.get(0).getRoot().getName();
}
_detailsLabel.setText(detailsText);
}
/**
* <p>
* </p>
*
* @author Gerd Wütherich (gerd@gerd-wuetherich.de)
*/
private final class ToArtifactSelectionChangedListener implements ISelectionChangedListener {
/**
* {@inheritDoc}
*/
@Override
public void selectionChanged(SelectionChangedEvent event) {
//
IStructuredSelection structuredSelection = (IStructuredSelection) event.getSelection();
if (structuredSelection.isEmpty()) {
return;
}
// Reset Selection in 'from' Viewer
_fromTreeViewer.setSelection(new StructuredSelection());
highlightSelectedDependencies(structuredSelection, false);
}
}
class BackInHistoryAction extends Action implements IHistoryChangedListener<TreeSelectionSnapshot> {
private final SelectionHistory _history;
public BackInHistoryAction(SelectionHistory history) {
super("Back");
_history = history;
setToolTipText("Go back in Selection History");
setImageDescriptor(XRefViewImages.NAV_BACKWARD_ENABLED.getImageDescriptor());
setDisabledImageDescriptor(XRefViewImages.NAV_BACKWARD_DISABLED.getImageDescriptor());
history.addHistoryChangedListener(this);
}
@Override
public void run() {
_history.goBack();
}
@Override
public void historyChanged(History<TreeSelectionSnapshot> history) {
setEnabled(history.canGoBack());
}
}
class ForwadInHistoryAction extends Action implements IHistoryChangedListener<TreeSelectionSnapshot> {
private final SelectionHistory _history;
public ForwadInHistoryAction(SelectionHistory history) {
super("Forward");
setToolTipText("Go forward in Selection History");
setImageDescriptor(XRefViewImages.NAV_FORWARD_ENABLED.getImageDescriptor());
setDisabledImageDescriptor(XRefViewImages.NAV_FORWARD_DISABLED.getImageDescriptor());
_history = history;
history.addHistoryChangedListener(this);
}
@Override
public void run() {
_history.goForward();
}
@Override
public void historyChanged(History<TreeSelectionSnapshot> history) {
setEnabled(history.canGoForward());
}
}
class SelectionHistory extends History<TreeSelectionSnapshot> implements ISelectionChangedListener {
boolean _mute = false;
public SelectionHistory(TreeViewer... viewers) {
for (TreeViewer treeViewer : viewers) {
treeViewer.addSelectionChangedListener(this);
}
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent
* )
*/
@Override
public void selectionChanged(SelectionChangedEvent event) {
TreeViewer in = (TreeViewer) event.getSource();
if (_mute) {
return;
}
IStructuredSelection selection = (IStructuredSelection) event.getSelection();
if (selection.isEmpty()) {
return;
}
TreeSelectionSnapshot userSelection = new TreeSelectionSnapshot();
userSelection.addSelection(_fromTreeViewer, _fromTreeViewer == in);
userSelection.addSelection(_centerViewer, _centerViewer == in);
userSelection.addSelection(_toTreeViewer, _toTreeViewer == in);
add(userSelection);
}
/*
* (non-Javadoc)
*
* @see org.bundlemaker.core.util.history.History#goBack()
*/
@Override
public void goBack() {
super.goBack();
reselect(getCurrent());
}
/*
* (non-Javadoc)
*
* @see org.bundlemaker.core.util.history.History#goForward()
*/
@Override
public void goForward() {
super.goForward();
reselect(getCurrent());
}
public void reselect(TreeSelectionSnapshot userSelection) {
_mute = true;
try {
userSelection.reselect();
} finally {
_mute = false;
}
}
}
/**
*
*/
public void refresh() {
_centerViewer.refresh();
_fromTreeViewer.refresh();
_toTreeViewer.refresh();
}
// class ResetHistoryAction extends Action implements ISelectionHistoryChangedListener {
// private final SelectionHistory _history;
//
// public ResetHistoryAction(SelectionHistory history) {
// super("Reset");
// _history = history;
//
// history.addSelectionHistoryChangedListener(this);
// }
//
// @Override
// public void run() {
// _history.reset();
// }
//
// @Override
// public void historyChanged(SelectionHistory history) {
// setEnabled(history.canReset());
// }
// }
}