/* * 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(); } }