blob: 359fa2cfa76f0ac65014cdc36116340c9c28e5ea [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.ivyde.eclipse.resolvevisualizer;
import java.awt.Dimension;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Stack;
import org.apache.ivy.core.report.ResolveReport;
import org.apache.ivyde.eclipse.cp.IvyClasspathContainer;
import org.apache.ivyde.eclipse.resolvevisualizer.label.ILabelDecoratorAlgorithm;
import org.apache.ivyde.eclipse.resolvevisualizer.model.IvyNodeElement;
import org.apache.ivyde.eclipse.resolvevisualizer.model.IvyNodeElementAdapter;
import org.apache.ivyde.eclipse.resolvevisualizer.model.IvyNodeElementFilterAdapter;
import org.eclipse.jface.action.Action;
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.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
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.ViewerFilter;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.zest.core.viewers.AbstractZoomableViewer;
import org.eclipse.zest.core.viewers.EntityConnectionData;
import org.eclipse.zest.core.viewers.GraphViewer;
import org.eclipse.zest.core.viewers.IZoomableWorkbenchPart;
import org.eclipse.zest.core.viewers.ZoomContributionViewItem;
import org.eclipse.zest.core.widgets.Graph;
import org.eclipse.zest.core.widgets.GraphItem;
import org.eclipse.zest.core.widgets.GraphNode;
import org.eclipse.zest.core.widgets.ZestStyles;
import org.eclipse.zest.layouts.LayoutAlgorithm;
import org.eclipse.zest.layouts.LayoutStyles;
import org.eclipse.zest.layouts.algorithms.CompositeLayoutAlgorithm;
import org.eclipse.zest.layouts.algorithms.DirectedGraphLayoutAlgorithm;
import org.eclipse.zest.layouts.algorithms.HorizontalShift;
public class ResolveVisualizerView extends ViewPart implements IZoomableWorkbenchPart {
private GraphViewer viewer;
private FormToolkit toolKit;
private Action focusDialogAction;
private Action focusDialogActionToolbar;
private Action focusOnSelectionAction;
private Action hideSelectionAction;
private Action showHiddenAction;
private Action applyDefaultLayoutAction;
private Action historyAction;
private Action forwardAction;
private Action refreshAction;
private ZoomContributionViewItem contextZoomContributionViewItem;
private ZoomContributionViewItem toolbarZoomContributionViewItem;
private Stack/* <IvyNodeElement> */historyStack;
private Stack/* <IvyNodeElement> */forwardStack;
private IvyNodeElement currentRoot;
private IvyNodeElement currentSelection;
private IvyClasspathContainer currentContainer;
private ResolveVisualizerContentProvider contentProvider = new ResolveVisualizerContentProvider();
private MessageContentProvider messageContentProvider = new MessageContentProvider();
private IvyNodeLabelProvider labelProvider;
private ResolveVisualizerForm visualizationForm;
private ForceHiddenFilter forceHiddenFilter;
public ResolveVisualizerView() {
historyStack = new Stack/* <IvyNodeElement> */();
forwardStack = new Stack/* <IvyNodeElement> */();
forceHiddenFilter = new ForceHiddenFilter();
forceHiddenFilter.setEnabled(true);
contentProvider.addFilter(forceHiddenFilter);
}
/**
* This is a callback that will allow us to create the viewer and initialize it.
*/
public void createPartControl(Composite parent) {
toolKit = new FormToolkit(parent.getDisplay());
visualizationForm = new ResolveVisualizerForm(parent, toolKit, this);
viewer = visualizationForm.getGraphViewer();
this.labelProvider = new IvyNodeLabelProvider(this.viewer);
viewer.setLabelProvider(labelProvider);
viewer.setContentProvider(contentProvider);
viewer.setInput(null);
viewer.setConnectionStyle(ZestStyles.CONNECTIONS_DIRECTED);
viewer.setLayoutAlgorithm(new CompositeLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING,
new LayoutAlgorithm[] { new DirectedGraphLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING),
new HorizontalShift(LayoutStyles.NO_LAYOUT_NODE_RESIZING) }));
viewer.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
Object selectedElement = ((IStructuredSelection) event.getSelection()).getFirstElement();
if (selectedElement instanceof EntityConnectionData) {
return;
}
ResolveVisualizerView.this.selectionChanged((IvyNodeElement) selectedElement);
}
});
viewer.addDoubleClickListener(new IDoubleClickListener() {
public void doubleClick(DoubleClickEvent event) {
focusOnSelectionAction.run();
}
});
visualizationForm.getSearchBox().addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
String textString = visualizationForm.getSearchBox().getText();
HashMap figureListing = new HashMap();
ArrayList list = new ArrayList();
Iterator iterator = viewer.getGraphControl().getNodes().iterator();
while (iterator.hasNext()) {
GraphItem item = (GraphItem) iterator.next();
figureListing.put(item.getText(), item);
}
iterator = figureListing.keySet().iterator();
if (textString.length() > 0) {
while (iterator.hasNext()) {
String string = (String) iterator.next();
if (string.toLowerCase().indexOf(textString.toLowerCase()) >= 0) {
list.add(figureListing.get(string));
}
}
}
viewer.getGraphControl().setSelection((GraphItem[]) list.toArray(new GraphItem[list.size()]));
}
});
messageContentProvider.setMessageManager(visualizationForm.getManagedForm().getMessageManager());
contextZoomContributionViewItem = new ZoomContributionViewItem(this);
toolbarZoomContributionViewItem = new ZoomContributionViewItem(this);
// Create the help context id for the viewer's control
makeActions();
hookContextMenu();
contributeToActionBars();
}
private void hookContextMenu() {
MenuManager menuMgr = new MenuManager("#PopupMenu");
menuMgr.setRemoveAllWhenShown(true);
menuMgr.addMenuListener(new IMenuListener() {
public void menuAboutToShow(IMenuManager manager) {
ResolveVisualizerView.this.fillContextMenu(manager);
}
});
Menu menu = menuMgr.createContextMenu(viewer.getControl());
viewer.getControl().setMenu(menu);
getSite().registerContextMenu(menuMgr, viewer);
}
private void contributeToActionBars() {
IActionBars bars = getViewSite().getActionBars();
bars.getMenuManager().add(toolbarZoomContributionViewItem);
fillLocalPullDown(bars.getMenuManager());
fillLocalToolBar(bars.getToolBarManager());
}
private void fillLocalPullDown(IMenuManager manager) {
}
private void fillContextMenu(IMenuManager manager) {
manager.add(new Separator());
manager.add(focusDialogAction);
manager.add(focusOnSelectionAction);
manager.add(new Separator());
manager.add(historyAction);
manager.add(forwardAction);
manager.add(new Separator());
manager.add(hideSelectionAction);
manager.add(showHiddenAction);
manager.add(new Separator());
manager.add(refreshAction);
manager.add(applyDefaultLayoutAction);
manager.add(new Separator());
manager.add(contextZoomContributionViewItem);
}
private void fillLocalToolBar(IToolBarManager toolBarManager) {
toolBarManager.add(refreshAction);
toolBarManager.add(focusDialogActionToolbar);
toolBarManager.add(new Separator());
toolBarManager.add(historyAction);
toolBarManager.add(forwardAction);
}
private void makeActions() {
refreshAction = new Action() {
public void run() {
final IvyClasspathContainer container = currentContainer;
if (container == null) {
// nothing as been actually selected
return;
}
ResolveReport report = container.getResolveReport();
if (report == null) {
// TODO we might want to launch some resolve here
// or at least open a popup inviting the end user to launch one
return;
}
// a resolve report is already saved on the container's state, we will use it
focusOnContainer(container);
// When a new container is selected, disable the forward action
// The forward action only stores history when the back button was used (much like a browser)
forwardStack.clear();
forwardAction.setEnabled(false);
}
};
refreshAction.setText("Resolve");
refreshAction.setEnabled(true);
refreshAction.setImageDescriptor(Plugin.getImageDescriptor("icons/refresh.gif"));
focusDialogAction = new Action() {
public void run() {
ClasspathContainerSelectionDialog dialog = new ClasspathContainerSelectionDialog(viewer.getControl()
.getShell());
dialog.create();
int dialogStatus = dialog.open();
if (dialogStatus == Window.OK) {
currentContainer = (IvyClasspathContainer) dialog.getFirstResult();
refreshAction.run();
}
}
};
focusDialogAction.setText("Focus on ivy file...");
focusDialogActionToolbar = new Action() {
public void run() {
focusDialogAction.run();
}
};
focusDialogActionToolbar.setToolTipText("Focus on ivy file...");
focusDialogActionToolbar.setImageDescriptor(ResolveVisualizerPlugin.getImageDescriptor("icons/focus.gif"));
focusOnSelectionAction = new Action() {
public void run() {
if (currentSelection != null) {
if (currentRoot != currentSelection) {
if (currentRoot != null) {
historyStack.push(currentRoot);
historyAction.setEnabled(true);
}
focusOn(currentSelection);
}
}
}
};
focusOnSelectionAction.setText("Focus on selection");
focusOnSelectionAction.setEnabled(false);
historyAction = new Action() {
public void run() {
if (historyStack.size() > 0) {
IvyNodeElement element = (IvyNodeElement) historyStack.pop();
forwardStack.push(currentRoot);
forwardAction.setEnabled(true);
focusOn(element);
if (historyStack.size() <= 0) {
historyAction.setEnabled(false);
}
}
}
};
historyAction.setText("Back");
historyAction.setToolTipText("Back");
historyAction.setEnabled(false);
historyAction.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages()
.getImageDescriptor(ISharedImages.IMG_TOOL_BACK));
forwardAction = new Action() {
public void run() {
if (forwardStack.size() > 0) {
IvyNodeElement element = (IvyNodeElement) forwardStack.pop();
historyStack.push(currentRoot);
historyAction.setEnabled(true);
focusOn(element);
if (forwardStack.size() <= 0) {
forwardAction.setEnabled(false);
}
}
}
};
forwardAction.setText("Forward");
forwardAction.setToolTipText("Forward");
forwardAction.setEnabled(false);
forwardAction.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages()
.getImageDescriptor(ISharedImages.IMG_TOOL_FORWARD));
hideSelectionAction = new Action() {
public void run() {
forceHiddenFilter.addHidden(currentSelection);
refresh();
}
};
hideSelectionAction.setText("Hide");
showHiddenAction = new Action() {
public void run() {
forceHiddenFilter.clearHidden();
refresh();
}
};
showHiddenAction.setText("Show hidden");
applyDefaultLayoutAction = new Action() {
public void run() {
viewer.applyLayout();
}
};
applyDefaultLayoutAction.setText("Apply default layout");
}
/**
* Passing the focus request to the viewer's control.
*/
public void setFocus() {
viewer.getControl().setFocus();
}
private final void focusOnContainer(IvyClasspathContainer container) {
ResolveReport report = container.getResolveReport();
if (report != null) {
forceHiddenFilter.clearHidden();
visualizationForm.getForm().setText(
ResolveVisualizerForm.HeaderText + " - " + container.getConf().getIvyXmlPath() + " in \""
+ container.getConf().getJavaProject().getProject().getName() + "\"");
IvyNodeElement nextRoot = IvyNodeElementAdapter.adapt(report);
if (currentRoot != nextRoot) {
if (currentRoot != null) {
historyStack.push(currentRoot);
historyAction.setEnabled(true);
}
focusOn(nextRoot);
}
}
}
/**
* Update the view to focus on a particular bundle. If record history is set to true, and bundle does not equal the
* current bundle, then the current bundle will be saved on the history stack
*
* @param focus
* @param recordHistory
*/
public void focusOn(IvyNodeElement focus) {
viewer.setSelection(new StructuredSelection(focus));
viewer.setFilters(new ViewerFilter[] {});
viewer.setInput(focus);
Iterator nodes = viewer.getGraphControl().getNodes().iterator();
Graph graph = viewer.getGraphControl();
Dimension centre = new Dimension(graph.getBounds().width / 2, graph.getBounds().height / 2);
while (nodes.hasNext()) {
GraphNode graphNode = (GraphNode) nodes.next();
if (graphNode.getLocation().x <= 1 && graphNode.getLocation().y <= 1) {
graphNode.setLocation(centre.width, centre.height);
}
}
currentRoot = focus;
if (viewer.getGraphControl().getNodes().size() > 0) {
visualizationForm.enableSearchBox(true);
} else {
visualizationForm.enableSearchBox(false);
}
visualizationForm.enableSearchBox(true);
focusOnSelectionAction.setEnabled(true);
selectionChanged(focus);
}
/**
* Handle the select changed. This will update the view whenever a selection occurs.
*
* @param selectedItem
*/
private void selectionChanged(IvyNodeElement selectedItem) {
currentSelection = selectedItem;
labelProvider.setCurrentSelection(currentRoot, selectedItem);
messageContentProvider.selectionChanged(currentRoot);
viewer.update(contentProvider.getElements(currentRoot), null);
}
public AbstractZoomableViewer getZoomableViewer() {
return viewer;
}
public void setAutoSelectDecorator(ILabelDecoratorAlgorithm algorithm) {
labelProvider.setAutoSelectDecorator(algorithm);
if (viewer.getSelection() != null) {
Object selected = ((IStructuredSelection) viewer.getSelection()).getFirstElement();
this.selectionChanged((IvyNodeElement) selected);
}
}
public ResolveVisualizerContentProvider getContentProvider() {
return contentProvider;
}
public void refresh() {
viewer.refresh();
viewer.applyLayout();
}
public IvyNodeElement getCurrentRoot() {
return currentRoot;
}
private class ForceHiddenFilter extends IvyNodeElementFilterAdapter {
private Collection/* <IvyNodeElement> */forceHidden = new HashSet/* <IvyNodeElement> */();
public boolean accept(IvyNodeElement unfiltered) {
return !forceHidden.contains(unfiltered);
}
public void addHidden(IvyNodeElement hide) {
forceHidden.addAll(Arrays.asList(hide.getDeepDependencies()));
}
public void clearHidden() {
forceHidden.clear();
}
}
}