| /* |
| * 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.io.PrintWriter; |
| import java.io.StringWriter; |
| import java.util.ArrayList; |
| import java.util.Set; |
| |
| import org.apache.ivyde.eclipse.resolvevisualizer.label.AllCallersAlgorithm; |
| import org.apache.ivyde.eclipse.resolvevisualizer.label.AllDependencyAlgorithm; |
| import org.apache.ivyde.eclipse.resolvevisualizer.label.AllRootPathsAlgorithm; |
| import org.apache.ivyde.eclipse.resolvevisualizer.label.SameModuleIdAlgorithm; |
| import org.apache.ivyde.eclipse.resolvevisualizer.label.ShortestRootPathAlgorithm; |
| import org.apache.ivyde.eclipse.resolvevisualizer.model.IvyNodeElement; |
| import org.apache.ivyde.eclipse.resolvevisualizer.model.IvyNodeElementFilterAdapter; |
| import org.eclipse.draw2d.ColorConstants; |
| import org.eclipse.draw2d.FigureCanvas; |
| import org.eclipse.draw2d.LineBorder; |
| import org.eclipse.draw2d.parts.ScrollableThumbnail; |
| import org.eclipse.jface.dialogs.IMessageProvider; |
| import org.eclipse.jface.viewers.StructuredSelection; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.custom.SashForm; |
| import org.eclipse.swt.events.ModifyEvent; |
| import org.eclipse.swt.events.ModifyListener; |
| import org.eclipse.swt.events.SelectionAdapter; |
| import org.eclipse.swt.events.SelectionEvent; |
| import org.eclipse.swt.graphics.Color; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.swt.graphics.Point; |
| import org.eclipse.swt.layout.FillLayout; |
| import org.eclipse.swt.layout.FormAttachment; |
| import org.eclipse.swt.layout.FormData; |
| import org.eclipse.swt.layout.FormLayout; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.layout.GridLayout; |
| import org.eclipse.swt.widgets.Button; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Group; |
| import org.eclipse.swt.widgets.Label; |
| import org.eclipse.swt.widgets.Link; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.swt.widgets.Spinner; |
| import org.eclipse.swt.widgets.Text; |
| import org.eclipse.ui.ISharedImages; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.forms.IMessage; |
| import org.eclipse.ui.forms.ManagedForm; |
| import org.eclipse.ui.forms.events.HyperlinkAdapter; |
| import org.eclipse.ui.forms.events.HyperlinkEvent; |
| import org.eclipse.ui.forms.widgets.Form; |
| import org.eclipse.ui.forms.widgets.FormText; |
| import org.eclipse.ui.forms.widgets.FormToolkit; |
| import org.eclipse.ui.forms.widgets.ScrolledForm; |
| import org.eclipse.ui.forms.widgets.Section; |
| import org.eclipse.ui.forms.widgets.TableWrapData; |
| import org.eclipse.ui.forms.widgets.TableWrapLayout; |
| import org.eclipse.zest.core.viewers.GraphViewer; |
| import org.eclipse.zest.core.widgets.Graph; |
| |
| public class ResolveVisualizerForm { |
| public static final String HeaderText = "Ivy Resolve Visualization"; |
| |
| private FormToolkit toolkit; |
| private GraphViewer viewer; |
| private ScrolledForm form; |
| private ManagedForm managedForm; |
| private ResolveVisualizerView view; |
| |
| private Label searchLabel; |
| private Text searchBox; |
| |
| private SashForm sash; |
| |
| // various auto-select options |
| private Button showAllDependencies; |
| private Button showAllCallers; |
| private Button showShortestRootPath; |
| private Button showAllRootPaths; |
| private Button showSameModuleId; |
| |
| private Button evictionFilterEnablement; |
| private Button depthLimitFilterEnablement; |
| private Spinner depthLimit; |
| |
| private ThumbnailNavigator thumbnailNavigator; |
| |
| private DepthFilter depthFilter = new DepthFilter(); |
| private EvictionFilter evictionFilter = new EvictionFilter(); |
| |
| public ResolveVisualizerForm(Composite parent, FormToolkit toolkit, ResolveVisualizerView view) { |
| this.toolkit = toolkit; |
| this.view = view; |
| form = this.toolkit.createScrolledForm(parent); |
| managedForm = new ManagedForm(this.toolkit, this.form); |
| createHeaderRegion(form); |
| FillLayout layout = new FillLayout(); |
| layout.marginHeight = 10; |
| layout.marginWidth = 4; |
| form.getBody().setLayout(layout); |
| |
| this.toolkit.decorateFormHeading(this.form.getForm()); |
| createSash(form.getBody()); |
| |
| view.getContentProvider().addFilter(depthFilter); |
| view.getContentProvider().addFilter(evictionFilter); |
| } |
| |
| /** |
| * Creates the section of the form where the graph is drawn |
| * |
| * @param parent |
| */ |
| private void createGraphSection(Composite parent) { |
| Section section = this.toolkit.createSection(parent, Section.TITLE_BAR); |
| thumbnailNavigator = new ThumbnailNavigator(section, SWT.NONE); |
| viewer = new InternalGraphViewer(thumbnailNavigator, SWT.NONE); |
| viewer.getGraphControl().setVerticalScrollBarVisibility(FigureCanvas.NEVER); |
| viewer.getGraphControl().setHorizontalScrollBarVisibility(FigureCanvas.NEVER); |
| thumbnailNavigator.setGraph((Graph) viewer.getControl()); |
| thumbnailNavigator.setSize(100, 25); |
| section.setClient(thumbnailNavigator); |
| } |
| |
| private void createHeaderRegion(ScrolledForm form) { |
| Composite headClient = new Composite(form.getForm().getHead(), SWT.NULL); |
| GridLayout glayout = new GridLayout(); |
| glayout.marginWidth = glayout.marginHeight = 0; |
| glayout.numColumns = 3; |
| headClient.setLayout(glayout); |
| headClient.setBackgroundMode(SWT.INHERIT_DEFAULT); |
| searchLabel = new Label(headClient, SWT.NONE); |
| searchLabel.setText("Search:"); |
| searchBox = toolkit.createText(headClient, ""); |
| GridData data = new GridData(); |
| data.widthHint = 300; |
| searchBox.setLayoutData(data); |
| |
| toolkit.paintBordersFor(headClient); |
| form.setHeadClient(headClient); |
| form.setText(HeaderText); |
| enableSearchBox(false); |
| |
| form.getForm().addMessageHyperlinkListener(new HyperlinkAdapter() { |
| public void linkActivated(org.eclipse.ui.forms.events.HyperlinkEvent e) { |
| String title = e.getLabel(); |
| Object href = e.getHref(); |
| if (href instanceof IMessage[] && ((IMessage[]) href).length > 1) { |
| Point hl = ((Control) e.widget).toDisplay(0, 0); |
| hl.x += 10; |
| hl.y += 10; |
| final Shell shell = new Shell(ResolveVisualizerForm.this.form.getShell(), SWT.ON_TOP | SWT.TOOL); |
| shell.setImage(getImage(ResolveVisualizerForm.this.form.getMessageType())); |
| shell.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE)); |
| shell.setBackgroundMode(SWT.INHERIT_DEFAULT); |
| GridLayout layout = new GridLayout(); |
| layout.numColumns = 1; |
| layout.verticalSpacing = 0; |
| shell.setText(title); |
| shell.setLayout(layout); |
| Link link = new Link(shell, SWT.NONE); |
| link.setText("<A>close</A>"); |
| GridData data = new GridData(SWT.RIGHT, SWT.CENTER, false, false); |
| link.setLayoutData(data); |
| link.addSelectionListener(new SelectionAdapter() { |
| public void widgetSelected(SelectionEvent e) { |
| shell.close(); |
| } |
| }); |
| Group group = new Group(shell, SWT.NONE); |
| data = new GridData(SWT.LEFT, SWT.TOP, true, true); |
| group.setLayoutData(data); |
| group.setLayout(layout); |
| group.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE)); |
| FormText text = toolkit.createFormText(group, true); |
| configureFormText(ResolveVisualizerForm.this.form.getForm(), text); |
| if (href instanceof IMessage[]) { |
| text.setText(createFormTextContent((IMessage[]) href), true, false); |
| } |
| |
| shell.setLocation(hl); |
| shell.pack(); |
| shell.open(); |
| } else if (href instanceof IMessage[]) { |
| IMessage oneMessage = ((IMessage[]) href)[0]; |
| Set/* <IvyNodeElement> */conflicts = (Set/* <IvyNodeElement> */) oneMessage.getData(); |
| if (conflicts != null) { |
| viewer.setSelection(new StructuredSelection(new ArrayList(conflicts))); |
| } |
| } |
| } |
| }); |
| } |
| |
| public void enableSearchBox(boolean enable) { |
| this.searchLabel.setEnabled(enable); |
| this.searchBox.setEnabled(enable); |
| } |
| |
| /** |
| * Creates the sash form to separate the graph from the controls. |
| * |
| * @param parent |
| */ |
| private void createSash(Composite parent) { |
| sash = new SashForm(parent, SWT.NONE); |
| this.toolkit.paintBordersFor(parent); |
| |
| createGraphSection(sash); |
| createOptionsSection(sash); |
| sash.setWeights(new int[] { 10, 2 }); |
| } |
| |
| private void createOptionsSection(Composite parent) { |
| Section controls = this.toolkit.createSection(parent, Section.TITLE_BAR | Section.EXPANDED); |
| |
| controls.setText("Options"); |
| Composite controlComposite = new Composite(controls, SWT.NONE) { |
| public Point computeSize(int hint, int hint2, boolean changed) { |
| return new Point(0, 0); |
| } |
| }; |
| this.toolkit.adapt(controlComposite); |
| controlComposite.setLayout(new GridLayout()); |
| |
| Section autoSelectOptions = this.toolkit.createSection(controlComposite, Section.EXPANDED); |
| autoSelectOptions.setText("Auto Selection"); |
| autoSelectOptions.setLayout(new FillLayout()); |
| Composite autoSelectOptionsComposite = this.toolkit.createComposite(autoSelectOptions); |
| autoSelectOptionsComposite.setLayout(new TableWrapLayout()); |
| |
| showShortestRootPath = this.toolkit |
| .createButton(autoSelectOptionsComposite, "Shortest path to root", SWT.RADIO); |
| showShortestRootPath.setLayoutData(new TableWrapData(TableWrapData.FILL)); |
| showShortestRootPath.setSelection(true); |
| showShortestRootPath.addSelectionListener(new SelectionAdapter() { |
| public void widgetSelected(SelectionEvent e) { |
| view.setAutoSelectDecorator(new ShortestRootPathAlgorithm()); |
| } |
| }); |
| |
| showAllRootPaths = this.toolkit.createButton(autoSelectOptionsComposite, "All paths to root", SWT.RADIO); |
| showAllRootPaths.setLayoutData(new TableWrapData(TableWrapData.FILL)); |
| showAllRootPaths.addSelectionListener(new SelectionAdapter() { |
| public void widgetSelected(SelectionEvent e) { |
| view.setAutoSelectDecorator(new AllRootPathsAlgorithm()); |
| } |
| }); |
| |
| showAllCallers = this.toolkit.createButton(autoSelectOptionsComposite, "All callers", SWT.RADIO); |
| showAllCallers.setLayoutData(new TableWrapData(TableWrapData.FILL)); |
| showAllCallers.addSelectionListener(new SelectionAdapter() { |
| public void widgetSelected(SelectionEvent e) { |
| view.setAutoSelectDecorator(new AllCallersAlgorithm()); |
| } |
| }); |
| |
| showAllDependencies = this.toolkit.createButton(autoSelectOptionsComposite, "All dependencies", SWT.RADIO); |
| showAllDependencies.setLayoutData(new TableWrapData(TableWrapData.FILL)); |
| showAllDependencies.addSelectionListener(new SelectionAdapter() { |
| public void widgetSelected(SelectionEvent e) { |
| view.setAutoSelectDecorator(new AllDependencyAlgorithm()); |
| } |
| }); |
| |
| showSameModuleId = this.toolkit.createButton(autoSelectOptionsComposite, "Other revisions", SWT.RADIO); |
| showSameModuleId.setLayoutData(new TableWrapData(TableWrapData.FILL)); |
| showSameModuleId.addSelectionListener(new SelectionAdapter() { |
| public void widgetSelected(SelectionEvent e) { |
| view.setAutoSelectDecorator(new SameModuleIdAlgorithm()); |
| } |
| }); |
| |
| autoSelectOptions.setClient(autoSelectOptionsComposite); |
| |
| Section filterOptions = this.toolkit.createSection(controlComposite, Section.EXPANDED); |
| filterOptions.setText("Filter Options"); |
| filterOptions.setLayout(new FillLayout()); |
| Composite filterOptionsComposite = this.toolkit.createComposite(filterOptions); |
| filterOptionsComposite.setLayout(new TableWrapLayout()); |
| |
| evictionFilterEnablement = this.toolkit.createButton(filterOptionsComposite, "Hide evicted nodes", SWT.CHECK); |
| evictionFilterEnablement.setLayoutData(new TableWrapData(TableWrapData.FILL)); |
| evictionFilterEnablement.setSelection(true); |
| evictionFilter.setEnabled(true); |
| evictionFilterEnablement.addSelectionListener(new SelectionAdapter() { |
| public void widgetSelected(SelectionEvent e) { |
| if (evictionFilterEnablement.getSelection()) { |
| evictionFilter.setEnabled(true); |
| view.refresh(); |
| } else { |
| evictionFilter.setEnabled(false); |
| view.refresh(); |
| } |
| } |
| }); |
| |
| depthLimitFilterEnablement = this.toolkit.createButton(filterOptionsComposite, "Limit depth", SWT.CHECK); |
| depthLimitFilterEnablement.setLayoutData(new TableWrapData(TableWrapData.FILL)); |
| depthLimitFilterEnablement.addSelectionListener(new SelectionAdapter() { |
| public void widgetSelected(SelectionEvent e) { |
| if (depthLimitFilterEnablement.getSelection()) { |
| depthFilter.setDepth(depthLimit.getSelection()); |
| depthFilter.setEnabled(true); |
| view.refresh(); |
| depthLimit.setEnabled(true); |
| } else { |
| depthFilter.setEnabled(false); |
| view.refresh(); |
| depthLimit.setEnabled(false); |
| } |
| } |
| }); |
| |
| depthLimit = new Spinner(filterOptionsComposite, 0); |
| toolkit.adapt(depthLimit); |
| depthLimit.setMinimum(1); |
| depthLimit.setSelection(2); |
| depthLimit.setIncrement(1); |
| depthLimit.setSize(150, 40); |
| depthLimit.setBackground(new Color(Display.getDefault(), 216, 228, 248)); |
| depthLimit.setEnabled(false); |
| depthLimit.addModifyListener(new ModifyListener() { |
| public void modifyText(ModifyEvent e) { |
| depthFilter.setDepth(depthLimit.getSelection()); |
| depthFilter.setEnabled(true); |
| view.refresh(); |
| } |
| }); |
| |
| filterOptions.setClient(filterOptionsComposite); |
| |
| controls.setClient(controlComposite); |
| } |
| |
| public GraphViewer getGraphViewer() { |
| return viewer; |
| } |
| |
| public ScrolledForm getForm() { |
| return form; |
| } |
| |
| public Text getSearchBox() { |
| return this.searchBox; |
| } |
| |
| private class InternalGraphViewer extends GraphViewer { |
| public InternalGraphViewer(Composite parent, int style) { |
| super(parent, style); |
| Graph graph = new Graph(parent, style) { |
| public Point computeSize(int hint, int hint2, boolean changed) { |
| return new Point(0, 0); |
| } |
| }; |
| setControl(graph); |
| } |
| } |
| |
| private static class ThumbnailNavigator extends Composite { |
| FigureCanvas thumbnail; |
| ScrollableThumbnail tb; |
| |
| public ThumbnailNavigator(Composite parent, int style) { |
| super(parent, style); |
| this.setLayout(new FormLayout()); |
| createZoomableCanvas(this); |
| } |
| |
| public void setGraph(Graph graph) { |
| if (graph.getParent() != this) { |
| throw new AssertionError("Graph must be a child of this zoomable composite."); |
| } |
| createContents(graph); |
| tb.setViewport(graph.getViewport()); |
| tb.setSource(graph.getContents()); |
| } |
| |
| private void createZoomableCanvas(Composite parent) { |
| FormData data = new FormData(); |
| data.top = new FormAttachment(100, -100); |
| data.left = new FormAttachment(100, -100); |
| data.right = new FormAttachment(100, 0); |
| data.bottom = new FormAttachment(100, 0); |
| |
| thumbnail = new FigureCanvas(parent, SWT.NONE); |
| thumbnail.setBackground(ColorConstants.white); |
| thumbnail.setLayoutData(data); |
| |
| tb = new ScrollableThumbnail(); |
| tb.setBorder(new LineBorder(1)); |
| thumbnail.setContents(tb); |
| } |
| |
| private void createContents(Control control) { |
| FormData data = new FormData(); |
| data.top = new FormAttachment(0, 0); |
| data.left = new FormAttachment(0, 0); |
| data.right = new FormAttachment(100, 0); |
| data.bottom = new FormAttachment(100, 0); |
| control.setParent(this); |
| control.setLayoutData(data); |
| } |
| |
| } |
| |
| private class DepthFilter extends IvyNodeElementFilterAdapter { |
| private int depth = 2; |
| |
| public boolean accept(IvyNodeElement unfiltered) { |
| return unfiltered.getDepth() - view.getCurrentRoot().getDepth() <= depth; |
| } |
| |
| public void setDepth(int depth) { |
| this.depth = depth; |
| } |
| } |
| |
| private class EvictionFilter extends IvyNodeElementFilterAdapter { |
| public boolean accept(IvyNodeElement unfiltered) { |
| return !unfiltered.isEvicted(); |
| } |
| } |
| |
| public ManagedForm getManagedForm() { |
| return managedForm; |
| } |
| |
| private Image getImage(int type) { |
| switch (type) { |
| case IMessageProvider.ERROR: |
| return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJS_ERROR_TSK); |
| case IMessageProvider.WARNING: |
| return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJS_WARN_TSK); |
| case IMessageProvider.INFORMATION: |
| return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJS_INFO_TSK); |
| } |
| return null; |
| } |
| |
| private void configureFormText(final Form form, FormText text) { |
| text.addHyperlinkListener(new HyperlinkAdapter() { |
| public void linkActivated(HyperlinkEvent e) { |
| String is = (String) e.getHref(); |
| try { |
| ((FormText) e.widget).getShell().dispose(); |
| int index = Integer.parseInt(is); |
| IMessage[] messages = form.getChildrenMessages(); |
| IMessage message = messages[index]; |
| Set/* <IvyNodeElement> */conflicts = (Set/* <IvyNodeElement> */) message.getData(); |
| if (conflicts != null) { |
| viewer.setSelection(new StructuredSelection(new ArrayList(conflicts))); |
| } |
| } catch (NumberFormatException ex) { |
| } |
| } |
| }); |
| text.setImage("error", getImage(IMessageProvider.ERROR)); |
| text.setImage("warning", getImage(IMessageProvider.WARNING)); |
| text.setImage("info", getImage(IMessageProvider.INFORMATION)); |
| } |
| |
| String createFormTextContent(IMessage[] messages) { |
| StringWriter sw = new StringWriter(); |
| PrintWriter pw = new PrintWriter(sw); |
| pw.println("<form>"); |
| for (int i = 0; i < messages.length; i++) { |
| IMessage message = messages[i]; |
| pw.print("<li vspace=\"false\" style=\"image\" indent=\"16\" value=\""); |
| switch (message.getMessageType()) { |
| case IMessageProvider.ERROR: |
| pw.print("error"); |
| break; |
| case IMessageProvider.WARNING: |
| pw.print("warning"); |
| break; |
| case IMessageProvider.INFORMATION: |
| pw.print("info"); |
| break; |
| } |
| pw.print("\"> <a href=\""); |
| pw.print(i + ""); |
| pw.print("\">"); |
| if (message.getPrefix() != null) { |
| pw.print(message.getPrefix()); |
| } |
| pw.print(message.getMessage()); |
| pw.println("</a></li>"); |
| } |
| pw.println("</form>"); |
| pw.flush(); |
| return sw.toString(); |
| } |
| } |