/******************************************************************************* * Copyright (c) 2009 the CHISEL group and contributors. 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: Del Myers - initial API and implementation *******************************************************************************/ package ca.uvic.chisel.javasketch.ui.internal.presentation; import java.lang.reflect.InvocationTargetException; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.ListenerList; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.ISchedulingRule; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IType; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.ContributionItem; import org.eclipse.jface.action.IAction; 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.operation.IRunnableWithProgress; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.resource.ImageRegistry; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.Widget; import org.eclipse.ui.IMemento; import org.eclipse.ui.ISelectionListener; import org.eclipse.ui.IViewSite; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.commands.ICommandService; import org.eclipse.ui.internal.operations.TimeTriggeredProgressMonitorDialog; import org.eclipse.ui.menus.CommandContributionItem; import org.eclipse.ui.menus.CommandContributionItemParameter; import org.eclipse.ui.part.ViewPart; import org.eclipse.ui.progress.UIJob; import org.eclipse.ui.views.contentoutline.IContentOutlinePage; import org.eclipse.ui.views.properties.IPropertySheetPage; import org.eclipse.ui.views.properties.tabbed.ITabbedPropertySheetPageContributor; import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage; import org.eclipse.zest.custom.sequence.widgets.Activation; import org.eclipse.zest.custom.sequence.widgets.Call; import org.eclipse.zest.custom.sequence.widgets.Message; import org.eclipse.zest.custom.sequence.widgets.MessageGroup; import org.eclipse.zest.custom.sequence.widgets.UMLItem; import org.eclipse.zest.custom.sequence.widgets.UMLSequenceChart; import org.eclipse.zest.custom.uml.viewers.BreadCrumbViewer; import org.eclipse.zest.custom.uml.viewers.IMessageGrouping; import org.eclipse.zest.custom.uml.viewers.ISequenceContentExtension2; import org.eclipse.zest.custom.uml.viewers.ISequenceViewerListener; import org.eclipse.zest.custom.uml.viewers.SequenceViewerEvent; import org.eclipse.zest.custom.uml.viewers.SequenceViewerGroupEvent; import org.eclipse.zest.custom.uml.viewers.SequenceViewerRootEvent; import org.eclipse.zest.custom.uml.viewers.UMLSequenceViewer; import ca.uvic.chisel.javasketch.IProgramSketch; import ca.uvic.chisel.javasketch.ISketchEventListener; import ca.uvic.chisel.javasketch.ISketchInterestListener; import ca.uvic.chisel.javasketch.SketchEvent; import ca.uvic.chisel.javasketch.SketchInterestEvent; import ca.uvic.chisel.javasketch.SketchPlugin; import ca.uvic.chisel.javasketch.data.model.IActivation; import ca.uvic.chisel.javasketch.data.model.IActivationEvent; import ca.uvic.chisel.javasketch.data.model.ICall; import ca.uvic.chisel.javasketch.data.model.IMessage; import ca.uvic.chisel.javasketch.data.model.IOriginMessage; import ca.uvic.chisel.javasketch.data.model.ITargetMessage; import ca.uvic.chisel.javasketch.data.model.IThread; import ca.uvic.chisel.javasketch.data.model.ITraceClass; import ca.uvic.chisel.javasketch.data.model.ITraceClassMethod; import ca.uvic.chisel.javasketch.data.model.ITraceEvent; import ca.uvic.chisel.javasketch.data.model.ITraceEventListener; import ca.uvic.chisel.javasketch.data.model.ITraceMetaEvent; import ca.uvic.chisel.javasketch.data.model.ITraceModel; import ca.uvic.chisel.javasketch.data.model.ITraceModelProxy; import ca.uvic.chisel.javasketch.data.model.imple.internal.ActivationImpl; import ca.uvic.chisel.javasketch.data.model.imple.internal.ThreadImpl; import ca.uvic.chisel.javasketch.data.model.imple.internal.TraceImpl; import ca.uvic.chisel.javasketch.internal.ast.groups.ASTMessageGroupingTree; import ca.uvic.chisel.javasketch.ui.ISketchImageConstants; import ca.uvic.chisel.javasketch.ui.internal.preferences.ISketchPluginPreferences; import ca.uvic.chisel.javasketch.ui.internal.presentation.MarkRangeForSelectionJob.InvocationReference; import ca.uvic.chisel.javasketch.ui.internal.presentation.commands.CollapseAllHandler; import ca.uvic.chisel.javasketch.ui.internal.presentation.commands.ExpandAllHandler; import ca.uvic.chisel.javasketch.ui.internal.presentation.commands.FocusInHandler; import ca.uvic.chisel.javasketch.ui.internal.presentation.commands.FocusUpHandler; import ca.uvic.chisel.javasketch.ui.internal.presentation.commands.ScreenshotHandler; import ca.uvic.chisel.javasketch.ui.internal.presentation.commands.SelectIterationAction; import ca.uvic.chisel.javasketch.ui.internal.presentation.metadata.PresentationData; import ca.uvic.chisel.widgets.RangeAnnotation; import ca.uvic.chisel.widgets.RangeSlider; import ca.uvic.chisel.widgets.TimeField; @SuppressWarnings("restriction") public class JavaThreadSequenceView extends ViewPart implements IJavaSketchPresenter, ITabbedPropertySheetPageContributor, ISketchInterestListener { public static final String VIEW_ID = "ca.uvic.chisel.javasketch.threadView"; private static final String LAST_TRACE = "last_trace"; private static final String LAST_THREAD = "last_thread"; private class InternalSelectionProvider implements ISelectionProvider { ListenerList selectionListeners = new ListenerList(); private ISelection selection = StructuredSelection.EMPTY; /* (non-Javadoc) * @see org.eclipse.jface.viewers.ISelectionProvider#addSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener) */ @Override public void addSelectionChangedListener( ISelectionChangedListener listener) { selectionListeners.add(listener); } /* (non-Javadoc) * @see org.eclipse.jface.viewers.ISelectionProvider#getSelection() */ @Override public ISelection getSelection() { return selection; } /* (non-Javadoc) * @see org.eclipse.jface.viewers.ISelectionProvider#removeSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener) */ @Override public void removeSelectionChangedListener( ISelectionChangedListener listener) { selectionListeners.remove(listener); } /* (non-Javadoc) * @see org.eclipse.jface.viewers.ISelectionProvider#setSelection(org.eclipse.jface.viewers.ISelection) */ @Override public void setSelection(ISelection selection) { if (selection == null) { return; } if (this.selection != null) { if (this.selection.equals(selection)) { return; } } this.selection = selection; SelectionChangedEvent event = new SelectionChangedEvent(this, selection); for (Object o : selectionListeners.getListeners()) { ((ISelectionChangedListener)o).selectionChanged(event); } //update commands ICommandService service = (ICommandService) SketchPlugin.getDefault().getWorkbench().getService(ICommandService.class); if (service != null) { service.refreshElements(FocusInHandler.COMMAND_ID, null); } } public void dispose() { selectionListeners.clear(); } } /** * @author Del Myers * */ private final class InternalSelectionChangedListener implements ISelectionChangedListener { @Override public void selectionChanged(SelectionChangedEvent event) { IJavaElement[] elements = new IJavaElement[0]; if (javaSelection != null) { elements = javaSelection.toArray(elements); } rangeJob.cancel(); rangeJob.schedule(elements); selectionProvider.setSelection(event.getSelection()); } } /** * @author Del Myers * */ private final class PresentationListener implements ISequenceViewerListener, ISchedulingRule { private IProgressMonitor progress; @Override public void rootChanged(SequenceViewerRootEvent event) { if (isCancelled()) { reset(); return; } PresentationData pd = PresentationData.connect(getSketch()); if (pd != null) { try { pd.setThreadRoot(thread, (IActivation) event .getSequenceViewer().getRootActivation()); } finally { pd.disconnect(); } } } @Override public void groupExpanded(SequenceViewerGroupEvent event) { if (isCancelled()) { reset(); return; } setGroupExpansion(event, true); } private void setGroupExpansion(SequenceViewerGroupEvent event, boolean b) { if (isCancelled()) { reset(); return; } PresentationData pd = PresentationData.connect(getSketch()); if (pd != null) { try { ASTMessageGroupingTree grouping = getGroupIng(event .getGroup()); if (grouping != null) { pd.setGroupExpanded((IActivation) event.getGroup() .getActivationElement(), grouping, b); } } finally { pd.disconnect(); } } } @Override public void groupCollapsed(SequenceViewerGroupEvent event) { if (isCancelled()) { reset(); return; } setGroupExpansion(event, false); } @Override public void elementExpanded(SequenceViewerEvent event) { if (isCancelled()) { reset(); return; } setActivationExpanded(event, true); internalResetExpansionStates((IActivation) event.getElement()); } /** * */ private void reset() { this.progress = null; } @Override public void elementCollapsed(SequenceViewerEvent event) { if (isCancelled()) { reset(); return; } setActivationExpanded(event, false); } /** * @return */ private boolean isCancelled() { return (progress != null && progress.isCanceled()); } private void setActivationExpanded(SequenceViewerEvent event, boolean b) { if (event.getElement() instanceof IActivation) { PresentationData pd = PresentationData.connect(getSketch()); if (pd != null) { try { pd.setActivationExpanded((IActivation) event .getElement(), b); } finally { pd.disconnect(); } } } } /* (non-Javadoc) * @see org.eclipse.core.runtime.jobs.ISchedulingRule#contains(org.eclipse.core.runtime.jobs.ISchedulingRule) */ @Override public boolean contains(ISchedulingRule rule) { if (isConflicting(rule)) { return true; } return false; } /* (non-Javadoc) * @see org.eclipse.core.runtime.jobs.ISchedulingRule#isConflicting(org.eclipse.core.runtime.jobs.ISchedulingRule) */ @Override public boolean isConflicting(ISchedulingRule rule) { return (rule instanceof PresentationListener); } /** * @param monitor */ public void setProgress(IProgressMonitor monitor) { this.progress = monitor; } } /** * @author Del Myers * */ private final class ISketchEventListenerImplementation implements ISketchEventListener { @Override public void handleSketchEvent(final SketchEvent fevent) { getViewSite().getShell().getDisplay().asyncExec(new Runnable() { public void run() { try { IProgramSketch sketch = SketchPlugin.getDefault() .getSketch(thread); SketchEvent event = fevent; if (sketch != null && sketch.equals(event.getSketch())) { switch (event.getType()) { case SketchAnalysisStarted: case SketchAnalysisEnded: case SketchAnalysisInterrupted: case SketchRefreshed: if (thread != null && !thread.isValid()) { for (IThread test : sketch.getTraceData() .getThreads()) { if (test.getID() == thread.getID() && test.getName().equals( thread.getName())) { setInput(test); return; } } thread = null; setInput(thread); } else { resetViewers(); } break; case SketchDeleted: setInput(null); break; } } } catch (Throwable t) { t.printStackTrace(); } } }); } } private final class RefreshActivationListener implements ITraceEventListener { /* * (non-Javadoc) * @see * ca.uvic.chisel.javasketch.data.model.ITraceEventListener#handleEvents * (ca.uvic.chisel.javasketch.data.model.ITraceEvent[]) */ @Override public void handleEvents(ITraceEvent[] events) { for (ITraceEvent event : events) { switch (event.getType()) { case ActivationEventType: IActivation[] activations = ((IActivationEvent) event) .getActivations(); refreshActivationsJob.cancel(); refreshActivationsJob.schedule(activations); break; } } } } private class RefreshActivationsJob extends UIJob { private IActivation[] activations; public RefreshActivationsJob() { super("Refreshing Activations"); activations = new IActivation[0]; } /* * (non-Javadoc) * @see * org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime * .IProgressMonitor) */ @Override public IStatus runInUIThread(IProgressMonitor monitor) { synchronized (activations) { for (IActivation activation : activations) { viewer.refresh(activation); } } return Status.OK_STATUS; } public void schedule(IActivation[] activations) { if (activations == null) { return; } synchronized (this.activations) { if (activations.length != this.activations.length) { this.activations = new IActivation[activations.length]; } System.arraycopy(activations, 0, this.activations, 0, activations.length); } if (this.activations.length > 0) { schedule(); } } } private class RequestReconnaissanceJob extends Job { private class FilterAnimator implements Runnable { private int index = 0; private boolean up; private boolean running = false; FilterAnimator() { } /* (non-Javadoc) * @see java.lang.Runnable#run() */ @Override public void run() { if (running) { enableReconnaissanceAction.setImageDescriptor(filterImages[index]); if (up) { index++; if (index >= filterImages.length) { index = filterImages.length-2; up = false; } } else { index--; if (index < 0) { index = 1; up = true; } } PlatformUI.getWorkbench().getDisplay().timerExec(150, this); } else { if (enableReconnaissanceAction.isChecked()) { enableReconnaissanceAction.setImageDescriptor(filterImages[3]); } else { enableReconnaissanceAction.setImageDescriptor(filterImages[0]); } } } public void stop() { running = false; } public void start() { if (!running) { running = true; index = 0; PlatformUI.getWorkbench().getDisplay().asyncExec(this); } } } private FilterAnimator animator; /** * @param name */ public RequestReconnaissanceJob() { super("Filtering Thread"); animator = new FilterAnimator(); } /* (non-Javadoc) * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor) */ @Override protected IStatus run(IProgressMonitor monitor) { animator.start(); SketchPlugin.getDefault().getDOI().requestFiltering(thread, monitor); IPreferenceStore store = SketchPlugin.getDefault().getPreferenceStore(); if (monitor.isCanceled()) { store.setValue(ISketchPluginPreferences.DIAGRAM_RECONNAISSANCE, false); enableReconnaissanceAction.setChecked(false); animator.stop(); return Status.CANCEL_STATUS; } else { store.setValue(ISketchPluginPreferences.DIAGRAM_RECONNAISSANCE, true); animator.start(); enableReconnaissanceAction.setChecked(true); } animator.stop(); if (store.getBoolean(ISketchPluginPreferences.DIAGRAM_RECON_HIDE)) { refreshJob.cancel(); refreshJob.schedule(); } else { getSite().getWorkbenchWindow().getShell().getDisplay().asyncExec(new Runnable(){ @Override public void run() { updateForReconnaissanceFiltering(); updateAll(); } }); } return Status.OK_STATUS; } } private class RequestReconnaissanceAction extends Action { /* (non-Javadoc) * @see org.eclipse.jface.action.Action#run() */ /** * */ public RequestReconnaissanceAction() { super("Filter", IAction.AS_CHECK_BOX); } @Override public void run() { IPreferenceStore store = SketchPlugin.getDefault().getPreferenceStore(); if (isChecked()) { requestReconnaissanceJob.cancel(); requestReconnaissanceJob.schedule(); setImageDescriptor(filterImages[3]); } else { store.setValue(ISketchPluginPreferences.DIAGRAM_RECONNAISSANCE, false); setImageDescriptor(filterImages[0]); requestReconnaissanceJob.cancel(); if (store.getBoolean(ISketchPluginPreferences.DIAGRAM_RECON_HIDE)) { refreshJob.cancel(); refreshJob.schedule(); } else { updateForReconnaissanceFiltering(); updateAll(); } } } } public class ToggleReconFilterAction extends Action { /** * */ public ToggleReconFilterAction() { super("Exclude Hidden Method Calls", IAction.AS_CHECK_BOX); } public void run() { IPreferenceStore store = SketchPlugin.getDefault().getPreferenceStore(); store.setValue(ISketchPluginPreferences.DIAGRAM_RECON_HIDE, isChecked()); if (store.getBoolean(ISketchPluginPreferences.DIAGRAM_RECONNAISSANCE)) { refreshJob.cancel(); refreshJob.schedule(); } } } private class SwapLoopAction extends Action { private IActivation activation; private ASTMessageGroupingTree nodeToSwap; public SwapLoopAction(IActivation a, ASTMessageGroupingTree nodeToSwap) { this.activation = a; this.nodeToSwap = nodeToSwap; } /* * (non-Javadoc) * @see org.eclipse.jface.action.Action#run() */ @Override public void run() { PresentationData pd = PresentationData.connect(SketchPlugin .getDefault().getSketch(activation)); if (pd != null) { try { pd.swapLoop(activation, nodeToSwap, reconnaissanceEnabled() && hidingUnusedCalls()); } finally { pd.disconnect(); } viewer.refresh(activation); resetExpansionStates(activation); } super.run(); } } private class InternalPreferenceListener implements IPropertyChangeListener{ /* (non-Javadoc) * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent) */ @Override public void propertyChange(PropertyChangeEvent event) { String property = event.getProperty(); if (ISketchPluginPreferences.COMPACT_LOOPS_PREFERENCE.equals(property) || ISketchPluginPreferences.DISPLAY_GROUPS_PREFERENCE.equals(property)) { refreshJob.cancel(); refreshJob.schedule(); } } } UMLSequenceViewer viewer; private InternalSelectionProvider selectionProvider; private UIJob refreshJob; private RangeSlider timeRange; private ContributionItem collapseAllAction; private ContributionItem expandAllAction; private ContributionItem focusInAction; private ContributionItem focusUpAction; private RequestReconnaissanceAction enableReconnaissanceAction; private ThumbnailOutlinePage outlinePage; private BreadCrumbViewer breadcrumb; private ISelectionListener javaSelectionListener; private MarkRangeForSelectionJob rangeJob; private ISketchEventListener sketchListener; private IThread thread; private RefreshActivationsJob refreshActivationsJob; private RequestReconnaissanceJob requestReconnaissanceJob; private ITraceEventListener activationChangeListener; private PresentationListener presentationListener; private ArrayList<IJavaElement> javaSelection; private ISelectionChangedListener internalSelectionListener; private TimeField maxTime; private TimeField minTime; private InternalPreferenceListener preferenceListener; private ImageDescriptor[] filterImages; private ToggleReconFilterAction toggleReconFilterAction; public JavaThreadSequenceView() { refreshJob = new UIJob("Refreshing sequence viewer") { @Override public IStatus runInUIThread(IProgressMonitor monitor) { try { viewer.refresh(); } catch (Exception e) { IStatus status = new Status(IStatus.ERROR, SketchPlugin.PLUGIN_ID, "Error refreshing sequence viewer", e); SketchPlugin.getDefault().getLog().log(status); } return Status.OK_STATUS; } }; requestReconnaissanceJob = new RequestReconnaissanceJob(); activationChangeListener = new RefreshActivationListener(); this.refreshActivationsJob = new RefreshActivationsJob(); preferenceListener = new InternalPreferenceListener(); javaSelectionListener = new ISelectionListener() { @Override public void selectionChanged(IWorkbenchPart part, ISelection selection) { updateForSelection(selection); } }; } /** * @param selection */ protected void updateForSelection(ISelection selection) { ArrayList<IJavaElement> javaElements = new ArrayList<IJavaElement>(); if (selection instanceof IStructuredSelection) { IStructuredSelection ss = (IStructuredSelection) selection; Iterator<?> iterator = ss.iterator(); while (iterator.hasNext()) { Object o = iterator.next(); if (o instanceof IAdaptable) { IJavaElement element = (IJavaElement) ((IAdaptable) o) .getAdapter(IJavaElement.class); if (element instanceof IType) { javaElements.add(element); } else if (element instanceof IMethod) { javaElements.add(element); } } } } if (javaElements.size() > 0) { this.javaSelection = javaElements; rangeJob.cancel(); rangeJob.schedule(javaElements .toArray(new IJavaElement[javaElements.size()])); } } public void setInput(IThread newInput) { if (newInput == thread) { return; } if (thread != null) { thread.getTrace().removeListener(activationChangeListener); } thread = newInput; if (thread != null) { thread.getTrace().addListener(activationChangeListener); setPartName(thread.getName()); } final IActivation activation = thread.getRoot().getActivation(); resetExpansionStates(activation); } /** * */ public void resetExpansionStates(final IActivation activation) { IRunnableWithProgress initializer = new IRunnableWithProgress() { @Override public void run(IProgressMonitor monitor) { monitor.beginTask("Initializing Sequence Diagram", IProgressMonitor.UNKNOWN); presentationListener.setProgress(monitor); if (viewer != null) { resetViewers(); PresentationData pd = PresentationData.connect(getSketch()); if (pd != null) { try { if (pd.isExpanded(activation)) { viewer.setExpanded(activation, true); } } finally { pd.disconnect(); } } if (enableReconnaissanceAction.isChecked()) { requestReconnaissanceJob.cancel(); requestReconnaissanceJob.schedule(); } } updateForReconnaissanceFiltering(); monitor.done(); } }; try { getSite().getWorkbenchWindow().getWorkbench().getProgressService().runInUI(getSite().getWorkbenchWindow(), initializer, presentationListener); } catch (InvocationTargetException e) { SketchPlugin.getDefault().log(e); } catch (InterruptedException e) { } } /** * Just sets the background color for when reconnaissance filtering is enabled * to make sure that the user can know whether the current visualized thread * is in the active trace. */ private void updateForReconnaissanceFiltering() { UMLSequenceChart chart = viewer.getChart(); IProgramSketch activeSketch = SketchPlugin.getDefault().getActiveSketch(); chart.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE)); if (reconnaissanceEnabled()) { if (activeSketch != null) { if (!activeSketch.equals(SketchPlugin.getDefault().getSketch(thread))) { chart.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_GRAY)); } } } } /** * */ protected void internalResetExpansionStates(IActivation activation) { if (!viewer.getExpanded(activation)) return; PresentationData pd = PresentationData.connect(getSketch()); if (pd != null) { try { // use the widget itself because it will be faster than // querying the content provider again viewer.getChart().setRedraw(false); Widget w = viewer.testFindItem(activation); if (w instanceof Activation) { Activation aw = (Activation) w; for (Message m : aw.getMessages()) { //read and dispatch so things don't get look like they //hang if (m instanceof Call) { Call c = (Call) m; Activation target = c.getTarget(); if (target != null && !target.isDisposed() && target.getData() instanceof IActivation) { IActivation ta = (IActivation) target.getData(); viewer.setExpanded(ta, pd.isExpanded(ta)); viewer.getChart().getDisplay().readAndDispatch(); } } } for (MessageGroup group : aw.getMessageGroups()) { IMessageGrouping o = (IMessageGrouping) group.getData(); if (o instanceof IAdaptable) { ASTMessageGroupingTree node = (ASTMessageGroupingTree) ((IAdaptable) o) .getAdapter(ASTMessageGroupingTree.class); if (node != null) { viewer.setGroupingExpanded(o, pd .isGroupExpanded(activation, node)); viewer.getChart().getDisplay().readAndDispatch(); } } } } } catch (Exception e) { SketchPlugin.getDefault().log(e); } finally { pd.disconnect(); viewer.getChart().setRedraw(true); } } } protected ASTMessageGroupingTree getGroupIng(IMessageGrouping group) { if (group instanceof IAdaptable) { IAdaptable adapt = (IAdaptable) group; return (ASTMessageGroupingTree) adapt .getAdapter(ASTMessageGroupingTree.class); } return null; } protected IProgramSketch getSketch() { return SketchPlugin.getDefault().getSketch(thread); } /* * (non-Javadoc) * @see org.eclipse.ui.part.ViewPart#saveState(org.eclipse.ui.IMemento) */ @Override public void saveState(IMemento memento) { if (memento == null) { return; } if (thread == null) { return; } memento.putString(LAST_TRACE, thread.getTrace().getLaunchID()); memento.putString(LAST_THREAD, thread.getIdentifier()); super.saveState(memento); } /* * (non-Javadoc) * @see org.eclipse.ui.part.ViewPart#init(org.eclipse.ui.IViewSite, * org.eclipse.ui.IMemento) */ @Override public void init(IViewSite site, IMemento memento) throws PartInitException { super.init(site, memento); SketchPlugin.getDefault().getDOI().addSketchInterestListener(this); // if (memento != null) { // String lastTrace = memento.getString(LAST_TRACE); // String lastThread = memento.getString(LAST_THREAD); // if (lastTrace != null && lastThread != null) { // IProgramSketch sketch = // SketchPlugin.getDefault().getSketch(lastTrace); // if (sketch != null) { // ITrace trace = sketch.getTraceData(); // for (IThread thread : trace.getThreads()) { // if (thread.getIdentifier().equals(lastThread)) { // setInput(thread); // return; // } // } // } // } // } } @Override public void createPartControl(Composite parent) { filterImages = new ImageDescriptor[4]; ImageRegistry reg = SketchPlugin.getDefault().getImageRegistry(); filterImages[0] = reg.getDescriptor(ISketchImageConstants.ICON_ELEMENT_VISIBLE); filterImages[1] = reg.getDescriptor(ISketchImageConstants.ICON_ELEMENT_VISIBLE+"2-3"); filterImages[2] = reg.getDescriptor(ISketchImageConstants.ICON_ELEMENT_VISIBLE+"1-3"); filterImages[3] = reg.getDescriptor(ISketchImageConstants.ICON_ELEMENT_FILTERED); Composite page = new Composite(parent, SWT.NONE); GridLayout layout = new GridLayout(1, false); page.setLayout(layout); breadcrumb = new BreadCrumbViewer(page, SWT.BORDER); breadcrumb.setContentProvider(new BreadCrumbContentProvider()); breadcrumb.setLabelProvider(new TraceThreadLabelProvider()); breadcrumb.getControl().setLayoutData( new GridData(SWT.FILL, SWT.FILL, true, false)); viewer = new UMLSequenceViewer(page, SWT.V_SCROLL | SWT.H_SCROLL | SWT.VIRTUAL); viewer.setUseHashlookup(true); viewer.setContentProvider(new TraceThreadContentProvider()); viewer.setLabelProvider(new TraceThreadLabelProvider()); viewer.setMessageGrouper(new ASTMessageGrouper()); viewer.addFilter(new ViewerFilter(){ @Override public boolean select(Viewer viewer, Object parentElement, Object element) { boolean reconFilter = SketchPlugin.getDefault().getPreferenceStore().getBoolean(ISketchPluginPreferences.DIAGRAM_RECON_HIDE); if (reconFilter && enableReconnaissanceAction.isChecked() && element instanceof ICall) { ICall call = (ICall) element; double interest = SketchPlugin.getDefault().getDOI().getInterest(call); if (interest < .3) { return false; } } return true; }}); internalSelectionListener = new InternalSelectionChangedListener(); viewer.addSelectionChangedListener(internalSelectionListener); viewer.getControl().addMouseListener(new NavigateToCodeListener()); viewer.getControl().setBackground( parent.getDisplay().getSystemColor(SWT.COLOR_WHITE)); viewer.getControl().setLayoutData( new GridData(SWT.FILL, SWT.FILL, true, true)); presentationListener = new PresentationListener(); viewer.addSequenceListener(presentationListener); new BreadCrumbHook(breadcrumb, viewer); createTimeRange(page, thread); viewer.setInput(thread); createActions(); createContextMenu(); getViewSite().getActionBars().getToolBarManager().add(enableReconnaissanceAction); getViewSite().getActionBars().getMenuManager().add(toggleReconFilterAction); //add the drop-down menu IMenuManager manager = getViewSite().getActionBars().getMenuManager(); manager.add(new Separator("presentation")); getViewSite().getPage().addSelectionListener(javaSelectionListener); selectionProvider = new InternalSelectionProvider(); getViewSite().setSelectionProvider(selectionProvider); sketchListener = new ISketchEventListenerImplementation(); SketchPlugin.getDefault().addSketchEventListener(sketchListener); SketchPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(preferenceListener); } /* * (non-Javadoc) * @see org.eclipse.ui.part.WorkbenchPart#dispose() */ @Override public void dispose() { viewer.removeSequenceListener(presentationListener); viewer.removeSelectionChangedListener(internalSelectionListener); selectionProvider.dispose(); if (thread != null) { thread.getTrace().removeListener(activationChangeListener); } getViewSite().getPage().removeSelectionListener(javaSelectionListener); SketchPlugin.getDefault().removeSketchEventListener(sketchListener); SketchPlugin.getDefault().getPreferenceStore().removePropertyChangeListener(preferenceListener); SketchPlugin.getDefault().getDOI().removeSketchInterestListener(this); super.dispose(); } /** * @param page */ private void createTimeRange(Composite page, IThread thread) { Composite rangeComposite = new Composite(page, SWT.NONE); GridData gd = new GridData(SWT.FILL, SWT.FILL, true, false); rangeComposite.setLayoutData(gd); GridLayout layout = new GridLayout(3, false); layout.horizontalSpacing = 3; layout.verticalSpacing = 0; layout.marginWidth = 0; layout.marginHeight = 0; rangeComposite.setLayout(layout); minTime = new TimeField(rangeComposite, SWT.NONE); gd = new GridData(SWT.FILL, SWT.FILL, false, false); gd.heightHint = 15; minTime.setLayoutData(gd); timeRange = new RangeSlider(rangeComposite, SWT.NONE); timeRange.setForeground(page.getDisplay().getSystemColor( SWT.COLOR_DARK_GRAY)); timeRange.setBackground(page.getDisplay().getSystemColor( SWT.COLOR_GREEN)); gd = new GridData(SWT.FILL, SWT.CENTER, true, false); gd.heightHint = 15; timeRange.setLayoutData(gd); if (thread != null) { long min = thread.getRoot().getActivation().getTime(); long max = thread.getRoot().getActivation().getDuration() + min; timeRange.setMinimum(min); timeRange.setMaximum(max); timeRange.setSelectedMinimum(min); timeRange.setSelectedMaximum(max); } maxTime = new TimeField(rangeComposite, SWT.NONE); gd = new GridData(SWT.FILL, SWT.FILL, false, false); gd.heightHint = 15; maxTime.setLayoutData(gd); minTime.setTime(timeRange.getMinimum()); maxTime.setTime(timeRange.getMaximum()); timeRange.addSelectionListener(new SelectionListener() { public void widgetDefaultSelected(SelectionEvent e) { } public void widgetSelected(SelectionEvent e) { if (e.width < 0 || e.height < 0) { if (e.data instanceof InvocationReference) { InvocationReference ref = (InvocationReference) e.data; StructuredSelection selection = new StructuredSelection(ref.activation); selectionProvider.setSelection(selection); } return; } boolean changed = false; if (minTime.getTime() != timeRange.getSelectedMinimum()) { minTime.setTime(timeRange.getSelectedMinimum()); changed = true; } if (maxTime.getTime() != timeRange.getSelectedMaximum()) { maxTime.setTime(timeRange.getSelectedMaximum()); changed = true; } if (changed) { refreshJob.cancel(); refreshJob.schedule(2000); } } }); viewer.addFilter(new TimeFilter(timeRange)); ModifyListener typedTimeListener = new ModifyListener() { @Override public void modifyText(ModifyEvent e) { if (e.widget == maxTime) { timeRange.setSelectedMaximum(maxTime.getTime()); } else if (e.widget == minTime) { timeRange.setSelectedMinimum(minTime.getTime()); } refreshJob.cancel(); refreshJob.schedule(2000); } }; minTime.addModifyListener(typedTimeListener); maxTime.addModifyListener(typedTimeListener); rangeComposite.pack(); rangeJob = new MarkRangeForSelectionJob(this); new TimeLineTooltip(this); new TimeLineAnnotationHook(this); } /** * */ protected void resetViewers() { if (viewer == null || viewer.getChart().isDisposed()) { return; } if (viewer.getInput() != thread) { viewer.setInput(thread); } if (thread == null) { minTime.setTime(0); maxTime.setTime(0); return; } IWorkbenchPage page = getViewSite().getPage(); Display display = getSite().getShell().getDisplay(); // add annotations for the pause/resume events List<ITraceMetaEvent> events = thread.getTrace().getEvents(); IProgramSketch sketch = SketchPlugin.getDefault().getSketch(thread); RangeAnnotation annotation = null; // first remove all of the old annotations for (RangeAnnotation a : timeRange.getRanges()) { if ("PAUSE".equals(a.getText())) { a.dispose(); } } if (sketch != null) { // search for the newest thread for the sketch, as it may have // changed for (IThread t : sketch.getTraceData().getThreads()) { if (t.getName().equals(thread.getName())) { if (t.getID() == thread.getID()) { if (this.thread != t) { this.thread = t; } } break; } } } if (thread != null) { long min = thread.getRoot().getActivation().getTime(); long max = thread.getRoot().getActivation().getDuration() + min; timeRange.setMinimum(min); timeRange.setMaximum(max); timeRange.setSelectedMinimum(min); timeRange.setSelectedMaximum(max); minTime.setTime(min); maxTime.setTime(max); } else { minTime.setTime(0); maxTime.setTime(0); } for (ITraceMetaEvent event : events) { String text = event.getText(); if (text.equals("PAUSE IN THREAD " + thread.getID())) { if (annotation != null) { annotation.setLength(event.getTime() - annotation.getOffset()); } annotation = new RangeAnnotation(timeRange); annotation.setOffset(event.getTime()); annotation.setText("PAUSE"); annotation.setBackground(display .getSystemColor(SWT.COLOR_YELLOW)); } else if (text.equals("RESUME IN THREAD " + thread.getID())) { if (annotation == null) { annotation = new RangeAnnotation(timeRange); annotation.setText("PAUSE"); annotation.setBackground(display .getSystemColor(SWT.COLOR_YELLOW)); annotation.setOffset(thread.getRoot().getTime()); } annotation.setLength(event.getTime() - annotation.getOffset()); annotation = null; } } updateForSelection(page.getSelection()); if (thread != viewer.getInput()) { viewer.setInput(thread); } viewer.refresh(); } /** * */ private void createActions() { focusInAction = createContributionItem(FocusInHandler.COMMAND_ID); expandAllAction = createContributionItem(ExpandAllHandler.COMMAND_ID); collapseAllAction = createContributionItem(CollapseAllHandler.COMMAND_ID); focusUpAction = createContributionItem(FocusUpHandler.COMMAND_ID); enableReconnaissanceAction = new RequestReconnaissanceAction(); enableReconnaissanceAction.setText("Filter"); enableReconnaissanceAction.setImageDescriptor(SketchPlugin.getDefault().getImageRegistry().getDescriptor(ISketchImageConstants.ICON_ELEMENT_VISIBLE)); IPreferenceStore store = SketchPlugin.getDefault().getPreferenceStore(); enableReconnaissanceAction.setChecked(store.getBoolean(ISketchPluginPreferences.DIAGRAM_RECONNAISSANCE)); this.toggleReconFilterAction = new ToggleReconFilterAction(); toggleReconFilterAction.setChecked(store.getBoolean(ISketchPluginPreferences.DIAGRAM_RECON_HIDE)); toggleReconFilterAction.setText("Hide Unnecessary Calls"); // focusUpAction = new FocusUpHandler(viewer); // focusUpAction.setText("Focus On Parent"); // focusUpAction.setImageDescriptor( // SketchPlugin.imageDescriptorFromPlugin("images/etool16/up.gif") // ); // expandAllAction = new ExpandAllHandler(viewer); // expandAllAction.setText("Expand All Children"); // expandAllAction.setImageDescriptor( // SketchPlugin.imageDescriptorFromPlugin("images/etool16/expandAll.gif") // ); // collapseAllAction = new CollapseAllHandler(viewer); // collapseAllAction.setText("Collapse All Children"); // collapseAllAction.setImageDescriptor( // SketchPlugin.imageDescriptorFromPlugin("images/etool16/collapseAll.gif") // ); } private CommandContributionItem createContributionItem(String commandId) { CommandContributionItemParameter parameters = new CommandContributionItemParameter( SketchPlugin.getDefault().getWorkbench(), null, commandId, SWT.PUSH); return new CommandContributionItem(parameters); } private void createContextMenu() { MenuManager manager = new MenuManager("JavaSketchEditor", "#JavaSketchEditorPopUp"); Menu menu = manager.createContextMenu(viewer.getChart()); // getSite().registerContextMenu(manager, viewer); manager.setRemoveAllWhenShown(true); manager.addMenuListener(new IMenuListener() { @Override public void menuAboutToShow(IMenuManager manager) { Point location = Display.getCurrent().getCursorLocation(); location = viewer.getChart().toControl(location); Object element = viewer.elementAt(location.x, location.y); fillContextMenu(manager, element); } }); viewer.getChart().setMenu(menu); getSite().registerContextMenu("#JavaSketchEditorPopUp", manager, selectionProvider); } /** * Opens the context menu to be filled with actions. * * @param manager */ private void fillContextMenu(IMenuManager manager, Object elementUnderCursor) { if (elementUnderCursor instanceof IMessageGrouping) { IMessageGrouping grouping = (IMessageGrouping) elementUnderCursor; if (elementUnderCursor instanceof IAdaptable) { ASTMessageGroupingTree node = (ASTMessageGroupingTree) ((IAdaptable) elementUnderCursor) .getAdapter(ASTMessageGroupingTree.class); if (node != null) { IActivation activation = (IActivation) grouping .getActivationElement(); ASTMessageGroupingTree[] iterations = node.getIterations(); int selected = 0; for (int i = 0; i < iterations.length; i++) { ASTMessageGroupingTree iteration = iterations[i]; if (!isEmptyIteration(iteration)) { selected++; IAction swapAction = new SwapLoopAction(activation, iteration); swapAction.setText("Iteration " + iteration.getIteration()); manager.add(swapAction); if (selected >= 9) { SelectIterationAction selector = new SelectIterationAction( activation, iterations, this); selector.setText("Select Iteration..."); manager.add(selector); break; } } } } return; } } if (focusInAction.isEnabled()) { manager.add(focusInAction); } if (focusUpAction.isEnabled()) { manager.add(focusUpAction); } if (collapseAllAction.isEnabled()) { manager.add(collapseAllAction); } if (expandAllAction.isEnabled()) { manager.add(expandAllAction); } manager.add(createContributionItem(ScreenshotHandler.COMMAND_ID)); } /** * @param iteration * @return */ private boolean isEmptyIteration(ASTMessageGroupingTree iteration) { if (!reconnaissanceEnabled() || !hidingUnusedCalls()) { return false; } for (String id : iteration.getMessageIdentifiers()) { ITraceModelProxy proxy = getThread().getTrace().getElement(id); IOriginMessage message = (IOriginMessage) proxy.getElement(); double interest = SketchPlugin.getDefault().getDOI().getInterest(message); if (interest > .3) { return false; } } return true; } @Override public void setFocus() {} /* * (non-Javadoc) * @see org.eclipse.ui.part.WorkbenchPart#getAdapter(java.lang.Class) */ @SuppressWarnings("unchecked") @Override public Object getAdapter(Class adapter) { if (IContentOutlinePage.class.equals(adapter)) { if (outlinePage == null) { outlinePage = new ThumbnailOutlinePage(viewer.getChart()); } return outlinePage; } else if (IPropertySheetPage.class.equals(adapter)) { return new TabbedPropertySheetPage(this); } return super.getAdapter(adapter); } public RangeSlider getTimeRange() { return timeRange; } /** * @return */ public UMLSequenceViewer getSequenceChartViewer() { return viewer; } /* * (non-Javadoc) * @see * ca.uvic.chisel.javasketch.ui.internal.presentation.IJavaSketchPresenter * #getThread() */ @Override public IThread getThread() { return thread; } /** * @param thread2 * @param first */ public void reveal(ITraceModel element, String threadIdentifier) { if (element != null) { if (viewer.isVisible(element)) { //simply reveal it viewer.reveal(element); return; } LinkedList<Object> pathToRoot = new LinkedList<Object>(); final IActivation activation = findFirstActivation(element, threadIdentifier); if (activation == null) return; Object newInput = activation.getArrival().getThread(); Object input = viewer.getInput(); if (input != newInput) { setInput((IThread)newInput); } input = newInput; if (newInput == null) return; ISequenceContentExtension2 provider = (ISequenceContentExtension2) viewer .getContentProvider(); Object[] roots = ((IStructuredContentProvider) provider) .getElements(input); if (roots.length <= 0) return; Object currentRoot = roots[0]; Object currentParent = activation; while (currentParent != null && !currentParent.equals(currentRoot)) { pathToRoot.addFirst(currentParent); Object call = provider.getCall(currentParent); if (call != null) { currentParent = provider.getOriginActivation(call); } else { currentParent = null; } } pathToRoot.addFirst(currentRoot); TimeTriggeredProgressMonitorDialog progress = new TimeTriggeredProgressMonitorDialog( viewer.getControl().getShell(), 1000); try { progress.run(false, true, new ExpandToRootRunnable(viewer, pathToRoot, false) { /* * (non-Javadoc) * @seeca.uvic.chisel.javasketch.ui.internal.presentation. * ExpandToRootRunnable * #run(org.eclipse.core.runtime.IProgressMonitor) */ @Override public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { super.run(monitor); viewer.reveal(activation); } }); } catch (InvocationTargetException ex) { SketchPlugin.getDefault().log(ex); } catch (InterruptedException e1) { } } } /** * @param event * @param tm */ private IActivation findFirstActivation(ITraceModel tm, String threadId) { if (tm != null) { try { Connection c = ((TraceImpl) tm.getTrace()).getConnection(); Statement s = c.createStatement(); if (tm instanceof IActivation) { return (IActivation) tm; } else if (tm instanceof IThread) { try { return ((IThread) tm).getRoot().getActivation(); } catch (NullPointerException e) { } } else if (tm instanceof ITraceClass) { ITraceClass tc = (ITraceClass) tm; String queryString = "SELECT a.model_id FROM Activation a, Message m WHERE a.type_name = '" + tc.getName() + "' AND a.model_id = m.activation_id" + " ORDER BY m.time, a.model_id"; if (threadId != null) { ITraceModelProxy proxy = tm.getTrace().getElement(threadId); if (proxy != null) { ITraceModel thread = (IThread) proxy.getElement(); if (thread instanceof ThreadImpl) { queryString = "SELECT a.model_id FROM Activation a, Message m WHERE a.type_name = '" + tc.getName() + "' AND a.model_id = m.activation_id" + " AND thread_id = " + ((ThreadImpl)thread).getModelID() + " ORDER BY m.time, a.model_id"; } } } ResultSet results = s .executeQuery(queryString); if (results.next()) { String identifier = ActivationImpl .getIdentifierFromModel(results.getString(1)); ITraceModelProxy proxy = tm.getTrace().getElement( identifier); if (proxy != null) { return (IActivation) proxy.getElement(); } } } else if (tm instanceof ITraceClassMethod) { ITraceClassMethod tcm = (ITraceClassMethod) tm; String queryString = "SELECT a.model_id FROM Activation a, Message m WHERE a.type_name = '" + tcm.getTraceClass().getName() + "' AND a.method_name = '" + tcm.getName() + "' AND a.method_signature = '" + tcm.getSignature() + "' AND a.model_id = m.activation_id" + " ORDER BY m.time, a.model_id"; if (threadId != null) { ITraceModelProxy proxy = tm.getTrace().getElement(threadId); if (proxy != null) { ITraceModel thread = (IThread) proxy.getElement(); if (thread instanceof ThreadImpl) { queryString = "SELECT a.model_id FROM Activation a, Message m WHERE a.type_name = '" + tcm.getTraceClass().getName() + "' AND a.method_name = '" + tcm.getName() + "' AND a.method_signature = '" + tcm.getSignature() + "' AND thread_id = " + ((ThreadImpl)thread).getModelID() + " AND a.model_id = m.activation_id" + " ORDER BY m.time, a.model_id"; } } } ResultSet results = s .executeQuery(queryString); if (results.next()) { String modelId = results.getString(1); String identifier = ActivationImpl .getIdentifierFromModel(modelId); ITraceModelProxy proxy = tm.getTrace().getElement( identifier); if (proxy != null) { return (IActivation) proxy.getElement(); } } } else if (tm instanceof ITargetMessage) { return ((IMessage) tm).getActivation(); } else if (tm instanceof IOriginMessage) { return ((IOriginMessage)tm).getTarget().getActivation(); } else if (tm instanceof IActivation) { return (IActivation) tm; } } catch (SQLException e) { SketchPlugin.getDefault().log(e); } } return null; } /* * (non-Javadoc) * @see * org.eclipse.ui.views.properties.tabbed.ITabbedPropertySheetPageContributor * #getContributorId() */ @Override public String getContributorId() { return "ca.uvic.chisel.javasketch.modelProperties"; } /* (non-Javadoc) * @see ca.uvic.chisel.javasketch.ISketchInterestListener#sketchInterestChanged(ca.uvic.chisel.javasketch.SketchInterestEvent) */ @Override public synchronized void sketchInterestChanged(SketchInterestEvent event) { if (requestReconnaissanceJob != null) { requestReconnaissanceJob.cancel(); } if (enableReconnaissanceAction != null && enableReconnaissanceAction.isChecked()) { requestReconnaissanceJob.schedule(); } } public boolean reconnaissanceEnabled() { boolean reconEnabled = SketchPlugin.getDefault().getPreferenceStore().getBoolean(ISketchPluginPreferences.DIAGRAM_RECONNAISSANCE); return reconEnabled; } public boolean hidingUnusedCalls() { boolean reconHide = SketchPlugin.getDefault().getPreferenceStore().getBoolean(ISketchPluginPreferences.DIAGRAM_RECON_HIDE); return reconHide; } /** * */ protected void updateAll() { if (Display.getCurrent() == null) { return; } UMLSequenceChart chart = viewer.getChart(); if (!chart.isDisposed()) { UMLItem[] items = chart.getItems(); for (UMLItem item : items) { if (chart.isDisposed()) { break; } if (item != null && !item.isDisposed()) { viewer.update(item.getData(), null); } Display.getCurrent().readAndDispatch(); } } } }