/* * #%~ * Combinatorial Testing * %% * Copyright (C) 2008 - 2014 Overture * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program. If not, see * <http://www.gnu.org/licenses/gpl-3.0.html>. * #~% */ package org.overture.ide.plugins.combinatorialtesting.views; import java.io.File; import java.util.concurrent.CancellationException; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; 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.resource.ImageDescriptor; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.ITreeSelection; import org.eclipse.jface.viewers.ITreeViewerListener; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.TreeExpansionEvent; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.jface.viewers.ViewerSorter; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.TreeItem; import org.eclipse.ui.IActionBars; import org.eclipse.ui.IPageLayout; import org.eclipse.ui.IViewPart; import org.eclipse.ui.IWorkbenchActionConstants; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.console.ConsolePlugin; import org.eclipse.ui.console.IConsole; import org.eclipse.ui.console.IConsoleConstants; import org.eclipse.ui.console.IConsoleManager; import org.eclipse.ui.console.MessageConsole; import org.eclipse.ui.console.MessageConsoleStream; import org.eclipse.ui.part.ViewPart; import org.eclipse.ui.plugin.AbstractUIPlugin; import org.overture.ast.definitions.ANamedTraceDefinition; import org.overture.ast.definitions.SClassDefinition; import org.overture.ast.modules.AModuleModules; import org.overture.ast.node.INode; import org.overture.ide.core.IVdmModel; import org.overture.ide.core.resources.IVdmProject; import org.overture.ide.plugins.combinatorialtesting.ITracesConstants; import org.overture.ide.plugins.combinatorialtesting.OvertureTracesPlugin; import org.overture.ide.plugins.combinatorialtesting.debug.TraceDebugLauncher; import org.overture.ide.plugins.combinatorialtesting.internal.ITracesDisplay; import org.overture.ide.plugins.combinatorialtesting.internal.VdmjTracesHelper; import org.overture.ide.plugins.combinatorialtesting.views.internal.InconclusiveTraceViewerFilter; import org.overture.ide.plugins.combinatorialtesting.views.internal.OkTraceViewerFilter; import org.overture.ide.plugins.combinatorialtesting.views.internal.TraceNodeSorter; import org.overture.ide.plugins.combinatorialtesting.views.internal.TraceViewerSorter; import org.overture.ide.plugins.combinatorialtesting.views.treeView.ITreeNode; import org.overture.ide.plugins.combinatorialtesting.views.treeView.NotYetReadyTreeNode; import org.overture.ide.plugins.combinatorialtesting.views.treeView.ProjectTreeNode; import org.overture.ide.plugins.combinatorialtesting.views.treeView.TraceTestGroup; import org.overture.ide.plugins.combinatorialtesting.views.treeView.TraceTestTreeNode; import org.overture.ide.plugins.combinatorialtesting.views.treeView.TraceTreeNode; import org.overture.ide.ui.utility.EditorUtility; public class TracesTreeView extends ViewPart implements ITracesDisplay { private TreeViewer viewer; private Action actionRunSelected; private Action actionRunSelectedAdvanced; private Action actionSetOkFilter; private Action actionSetSort; private Action actionSetInconclusiveFilter; private Action actionSendToInterpreter; private Action refreshAction; final Display display = Display.getCurrent(); Button buttonSetSort = null; private ViewerFilter okFilter = new OkTraceViewerFilter(); private ViewerSorter traceSorter = new TraceViewerSorter(); private ViewerSorter defaultTraceSorter = new TraceNodeSorter(); private ViewerFilter inconclusiveFilter = new InconclusiveTraceViewerFilter(); /** * The constructor. */ public TracesTreeView() { } private void init() { viewer.setContentProvider(new ViewContentProvider(this)); viewer.setLabelProvider(new ViewLabelProvider()); viewer.setSorter(defaultTraceSorter); viewer.setInput(getViewSite()); } /** * This is a callback that will allow us to create the viewer and initialize it. */ @Override public void createPartControl(Composite parent) { viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); getSite().setSelectionProvider(viewer); makeActions(); hookContextMenu(); hookTreeAction(); contributeToActionBars(); init(); } private void hookContextMenu() { MenuManager menuMgr = new MenuManager("#PopupMenu"); menuMgr.setRemoveAllWhenShown(true); menuMgr.addMenuListener(new IMenuListener() { public void menuAboutToShow(IMenuManager manager) { TracesTreeView.this.fillContextMenu(manager); } }); Menu menu = menuMgr.createContextMenu(viewer.getControl()); viewer.getControl().setMenu(menu); getSite().registerContextMenu(menuMgr, viewer); } private void contributeToActionBars() { IActionBars bars = getViewSite().getActionBars(); fillLocalPullDown(bars.getMenuManager()); fillLocalToolBar(bars.getToolBarManager()); } private void fillLocalPullDown(IMenuManager manager) { manager.add(actionSetSort); manager.add(new Separator()); manager.add(actionSetOkFilter); manager.add(actionSetInconclusiveFilter); } private void fillContextMenu(IMenuManager manager) { ISelection selection = viewer.getSelection(); Object obj = ((IStructuredSelection) selection).getFirstElement(); if (obj instanceof ProjectTreeNode /* || obj instanceof ClassTreeNode */ || obj instanceof SClassDefinition || obj instanceof AModuleModules || obj instanceof TraceTreeNode) // || { manager.add(actionRunSelected); manager.add(actionRunSelectedAdvanced); } if (obj instanceof TraceTestTreeNode) { if (((TraceTestTreeNode) obj).getStatus() != null) { manager.add(actionSendToInterpreter); } } manager.add(new Separator()); manager.add(refreshAction); manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); } private void fillLocalToolBar(IToolBarManager manager) { manager.add(refreshAction); manager.add(actionSetSort); manager.add(new Separator()); manager.add(actionSetOkFilter); manager.add(actionSetInconclusiveFilter); } private final Image getImage(String path) { ImageDescriptor theDescriptor = AbstractUIPlugin.imageDescriptorFromPlugin("org.overture.ide.plugins.combinatorialtesting", path); Image theImage = null; if (theDescriptor != null) { theImage = theDescriptor.createImage(); } return theImage; } private void makeActions() { refreshAction = new Action("Refresh",OvertureTracesPlugin.getImageDescriptor(OvertureTracesPlugin.IMG_REFRESH)) { @Override public void run() { Job job = new Job("Refresh Projects") { @Override protected IStatus run(IProgressMonitor monitor) { refreshAction.setEnabled(false); for (IVdmProject proj : TraceAstUtility.getProjects()) { IVdmModel model = proj.getModel(); model.refresh(false, null); } refreshAction.setEnabled(true); display.asyncExec(new Runnable() { public void run() { init(); } }); return Status.OK_STATUS; } }; job.schedule(); } }; actionRunSelected = new Action("Full Evaluation") { @Override public void run() { ISelection selection = viewer.getSelection(); final Object obj = ((IStructuredSelection) selection).getFirstElement(); handleEvaluateTrace(obj, null); } }; actionRunSelected.setImageDescriptor(OvertureTracesPlugin.getImageDescriptor(OvertureTracesPlugin.IMG_RUN_SELECTED_TRACE)); actionRunSelectedAdvanced = new Action("Filtered Evaluation",OvertureTracesPlugin.getImageDescriptor(OvertureTracesPlugin.IMG_RUN_SELECTED_TRACE)) { @Override public void run() { Shell dialog = new Shell(display, SWT.DIALOG_TRIM); dialog.setText("Select filtering options"); dialog.setSize(200, 200); Image ctIcon = getImage(new StringBuilder("icons").append(File.separator).append("ctool16").append(File.separator).append("ct_tsk.png").toString()); dialog.setImage(ctIcon); final TraceOptionsDialog d = new TraceOptionsDialog(dialog, SWT.DIALOG_TRIM); d.pack(); dialog.pack(); Point pt = display.getCursorLocation(); dialog.setLocation(pt.x - d.getSize().x / 2, pt.y - d.getSize().y / 2); dialog.open(); while (!dialog.isDisposed()) { if (d.isCanceled) { return; } if (!display.readAndDispatch()) { display.sleep(); } } if (d.isCanceled || d.getTraceReductionType() == null) { return; } ISelection selection = viewer.getSelection(); final Object obj = ((IStructuredSelection) selection).getFirstElement(); handleEvaluateTrace(obj, d); } }; actionSetOkFilter = new Action("Filter ok results",Action.AS_CHECK_BOX) { @Override public void run() { ViewerFilter[] filters = viewer.getFilters(); boolean isSet = false; for (ViewerFilter viewerFilter : filters) { if (viewerFilter.equals(okFilter)) { isSet = true; } } if (isSet) { viewer.removeFilter(okFilter); } else { viewer.addFilter(okFilter); } } }; actionSetOkFilter.setToolTipText("Filter all ok results from tree"); actionSetOkFilter.setImageDescriptor(OvertureTracesPlugin.getImageDescriptor(OvertureTracesPlugin.IMG_TRACE_TEST_CASE_FILTER_SUCCES)); actionSetInconclusiveFilter = new Action("Filter inconclusive results",Action.AS_CHECK_BOX) { @Override public void run() { ViewerFilter[] filters = viewer.getFilters(); boolean isSet = false; for (ViewerFilter viewerFilter : filters) { if (viewerFilter.equals(inconclusiveFilter)) { isSet = true; } } if (isSet) { viewer.removeFilter(inconclusiveFilter); } else { viewer.addFilter(inconclusiveFilter); } } }; actionSetInconclusiveFilter.setToolTipText("Filter all inconclusive results from tree"); actionSetInconclusiveFilter.setImageDescriptor(OvertureTracesPlugin.getImageDescriptor(OvertureTracesPlugin.IMG_TRACE_TEST_CASE_FILTER_UNDETERMINED)); actionSetSort = new Action("Sort",Action.AS_CHECK_BOX) { @Override public void run() { if (!actionSetSort.isChecked()) { viewer.setSorter(defaultTraceSorter); OvertureTracesPlugin.getDefault().getPreferenceStore().setValue(ITracesConstants.SORT_VIEW, false); } else { viewer.setSorter(traceSorter); OvertureTracesPlugin.getDefault().getPreferenceStore().setValue(ITracesConstants.SORT_VIEW, true); } } }; actionSetSort.setToolTipText("Sort by verdict: Fail, Inconclusive, ok, etc."); actionSetSort.setImageDescriptor(OvertureTracesPlugin.getImageDescriptor(OvertureTracesPlugin.IMG_TRACE_TEST_SORT)); actionSetSort.setChecked(OvertureTracesPlugin.getDefault().getPreferenceStore().getBoolean(ITracesConstants.SORT_VIEW)); actionSetSort.run(); actionSendToInterpreter = new Action("Send to Interpreter",OvertureTracesPlugin.getImageDescriptor(OvertureTracesPlugin.IMG_INTERPRETER)) { @Override public void run() { ISelection selection = viewer.getSelection(); final Object obj = ((IStructuredSelection) selection).getFirstElement(); if (obj instanceof TraceTestTreeNode) { TraceTestTreeNode traceTestNode = (TraceTestTreeNode) obj; TraceTreeNode traceNode = null; ITreeNode n = traceTestNode; while (n != null && !(n instanceof ProjectTreeNode)) { if (n instanceof TraceTreeNode) { traceNode = (TraceTreeNode) n; } n = n.getParent(); } new TraceDebugLauncher().Launch(TraceAstUtility.getProject(traceNode.getTraceDefinition()), traceNode.getInfo(), traceTestNode.getNumber()); } } }; } private void hookTreeAction() { viewer.addSelectionChangedListener(new ISelectionChangedListener() { public void selectionChanged(SelectionChangedEvent event) { Object selection = ((ITreeSelection) event.getSelection()).getFirstElement(); if (selection instanceof TraceTreeNode) { TraceTreeNode tn = (TraceTreeNode) selection; gotoTraceDefinition(tn); } else if (selection instanceof TraceTestTreeNode) { if (!(selection instanceof NotYetReadyTreeNode) && !(selection instanceof TraceTestGroup) && ((TraceTestTreeNode) selection).getStatus() == null) { try { PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().showView(IPageLayout.ID_PROGRESS_VIEW); } catch (PartInitException e) { OvertureTracesPlugin.log(e); } } else { try { IViewPart view = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().showView(ITracesConstants.TRACES_TEST_ID); if (view instanceof TraceTest) { TraceTest traceTestView = (TraceTest) view; traceTestView.selectionChanged(TracesTreeView.this, event.getSelection()); } gotoTraceDefinition(findTraceTreeNode((TraceTestTreeNode) selection)); } catch (PartInitException e) { OvertureTracesPlugin.log(e); } } } } private TraceTreeNode findTraceTreeNode(ITreeNode selection) { if (selection != null) { if (selection.getParent() == null) { return null; } else if (selection.getParent() instanceof TraceTreeNode) { return (TraceTreeNode) selection.getParent(); } else { return findTraceTreeNode(selection.getParent()); } } return null; } }); viewer.addTreeListener(new ITreeViewerListener() { public void treeCollapsed(TreeExpansionEvent event) { Object expandingElement = event.getElement(); if (expandingElement instanceof TraceTreeNode) { TraceTreeNode node = (TraceTreeNode) expandingElement; node.unloadTests(); refreshTree(); } else if (expandingElement instanceof TraceTestGroup) { TraceTestGroup node = (TraceTestGroup) expandingElement; node.unloadTests(); refreshTree(); } } public void treeExpanded(TreeExpansionEvent event) { Object expandingElement = event.getElement(); if (expandingElement instanceof TraceTreeNode) { TraceTreeNode node = (TraceTreeNode) expandingElement; try { node.loadTests(); } catch (Exception e) { OvertureTracesPlugin.log(e); } refreshTree(); } else if (expandingElement instanceof TraceTestGroup) { TraceTestGroup node = (TraceTestGroup) expandingElement; try { node.loadTests(); } catch (Exception e) { OvertureTracesPlugin.log(e); } refreshTree(); } } }); } private void refreshTree() { display.asyncExec(new Runnable() { public void run() { if (viewer != null && !viewer.getControl().isDisposed()) { viewer.refresh(); viewer.getControl().update(); actionSetSort.run(); } } }); } /** * Passing the focus request to the viewer's control. */ @Override public void setFocus() { viewer.getControl().setFocus(); } private void ConsolePrint(final String message) { display.asyncExec(new Runnable() { public void run() { try { MessageConsole myConsole = findConsole("TracesConsole"); MessageConsoleStream out = myConsole.newMessageStream(); out.println(message); } catch (Exception e) { OvertureTracesPlugin.log(e); } } }); } private void ConsoleError(final String message) { display.asyncExec(new Runnable() { public void run() { try { MessageConsole myConsole = findConsole("TracesConsole"); MessageConsoleStream out = myConsole.newMessageStream(); out.setColor(Display.getCurrent().getSystemColor(SWT.COLOR_RED)); out.println(message); IWorkbenchWindow activeWorkbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); if (activeWorkbenchWindow != null) { IWorkbenchPage activePage = activeWorkbenchWindow.getActivePage(); if (activePage != null) { activePage.showView(IConsoleConstants.ID_CONSOLE_VIEW, null, IWorkbenchPage.VIEW_VISIBLE); } } } catch (Exception e) { OvertureTracesPlugin.log(e); } } }); } private void gotoTraceDefinition(TraceTreeNode tn) { if (tn == null || tn.getTraceDefinition() == null) { return; } IVdmProject vdmProject = TraceAstUtility.getProject(tn.getTraceDefinition()); IFile file = vdmProject.findIFile(tn.getTraceDefinition().getLocation().getFile()); EditorUtility.gotoLocation(file, tn.getTraceDefinition().getLocation(), tn.getName()); } private MessageConsole findConsole(String name) { ConsolePlugin plugin = ConsolePlugin.getDefault(); IConsoleManager conMan = plugin.getConsoleManager(); IConsole[] existing = conMan.getConsoles(); for (int i = 0; i < existing.length; i++) { if (name.equals(existing[i].getName())) { return (MessageConsole) existing[i]; } } // no console found, so create a new one MessageConsole myConsole = new MessageConsole(name, null); conMan.addConsoles(new IConsole[] { myConsole }); return myConsole; } private void handleEvaluateTrace(Object selectedItem, final TraceOptionsDialog optionsDialog) { IVdmProject project = null; INode container = null; ANamedTraceDefinition traceDef = null; if (selectedItem instanceof ProjectTreeNode) { ProjectTreeNode pn = (ProjectTreeNode) selectedItem; project = pn.project; } else if (selectedItem instanceof SClassDefinition || selectedItem instanceof AModuleModules) { project = TraceAstUtility.getProject((INode) selectedItem); container = (INode) selectedItem; } else if (selectedItem instanceof TraceTreeNode) { traceDef = ((TraceTreeNode) selectedItem).getTraceDefinition(); container = TraceAstUtility.getTraceDefinitionContainer(traceDef); project = TraceAstUtility.getProject(traceDef); } else if (selectedItem instanceof IVdmProject) { project = (IVdmProject) selectedItem; } final IVdmProject finalProject = project; final INode finalContainer = container; final ANamedTraceDefinition finalTraceDef = traceDef; Job executeTestJob = new Job("CT evaluating selected tests") { @Override protected IStatus run(IProgressMonitor monitor) { try { try { evaluateTraces(finalProject, finalContainer, finalTraceDef, optionsDialog, monitor); } catch (CancellationException e) { ConsolePrint(e.getMessage()); } catch (Exception e) { ConsoleError(e.getMessage()); OvertureTracesPlugin.log(e); } monitor.done(); } catch (Exception e) { OvertureTracesPlugin.log(e); } // expandTraces(0); return new Status(IStatus.OK, ITracesConstants.PLUGIN_ID, IStatus.OK, "CT Test evaluation finished", null); } }; executeTestJob.schedule(); } private void evaluateTraces(final IVdmProject project, INode container, ANamedTraceDefinition traceDef, TraceOptionsDialog filterDialog, IProgressMonitor monitor) throws Exception { if (project == null) { return; } VdmjTracesHelper traceRunner = new VdmjTracesHelper(getSite().getShell(), project); if (filterDialog == null) { traceRunner.evaluateTraces(container, traceDef, monitor, this); } else { traceRunner.evaluateTraces(container, traceDef, filterDialog.getSubset(), filterDialog.getTraceReductionType(), filterDialog.getSeed(), monitor, this); } } public void updateView(final IVdmProject project) { display.asyncExec(new Runnable() { public void run() { if (viewer == null || viewer.getControl().isDisposed())// TODO { return; // skip if disposed } TreeItem[] aa = viewer.getTree().getItems(); // boolean insertProject = true; for (TreeItem treeItem : aa) { if (treeItem.getData() instanceof ProjectTreeNode && ((ProjectTreeNode) treeItem.getData()).getName().equals(project.getName())) { if (viewer.getContentProvider() instanceof ViewContentProvider) { ((ViewContentProvider) viewer.getContentProvider()).resetCache(project); } viewer.refresh(); viewer.getControl().update(); actionSetSort.run(); } } } }); try { ((IProject) project.getAdapter(IProject.class)).refreshLocal(IResource.DEPTH_INFINITE, null); } catch (CoreException e) { } } }