From 4b38b1423c853147c13c9b1e62103abee0a92e96 Mon Sep 17 00:00:00 2001 From: Bruno Sinou Date: Thu, 7 Apr 2011 15:49:10 +0000 Subject: [PATCH] Add commands and tha ability to manage more than one item at a time in the result list view git-svn-id: https://svn.argeo.org/slc/trunk@4429 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- .../META-INF/MANIFEST.MF | 2 + .../META-INF/spring/commands.xml | 10 +- .../org.argeo.slc.client.ui/plugin.xml | 348 +++++++++--------- .../RemoveSelectedResultFromResultList.java | 33 ++ .../commands/ResultDetailsDisplayHandler.java | 35 +- .../slc/client/ui/views/ResultDetailView.java | 24 +- .../slc/client/ui/views/ResultListView.java | 235 +++++++++--- 7 files changed, 451 insertions(+), 236 deletions(-) create mode 100644 eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/commands/RemoveSelectedResultFromResultList.java diff --git a/eclipse/plugins/org.argeo.slc.client.ui/META-INF/MANIFEST.MF b/eclipse/plugins/org.argeo.slc.client.ui/META-INF/MANIFEST.MF index 6b1039d1e..3d0eb14ed 100644 --- a/eclipse/plugins/org.argeo.slc.client.ui/META-INF/MANIFEST.MF +++ b/eclipse/plugins/org.argeo.slc.client.ui/META-INF/MANIFEST.MF @@ -16,6 +16,7 @@ Export-Package: org.argeo.slc.client.ui, org.argeo.slc.client.ui.views Import-Package: org.apache.commons.io;version="1.4.0", org.apache.commons.logging;version="1.1.1", + org.argeo, org.argeo.eclipse.spring, org.argeo.eclipse.ui, org.argeo.slc, @@ -43,3 +44,4 @@ Import-Package: org.apache.commons.io;version="1.4.0", org.springframework.beans.factory, org.springframework.context, org.springframework.core.io.support + diff --git a/eclipse/plugins/org.argeo.slc.client.ui/META-INF/spring/commands.xml b/eclipse/plugins/org.argeo.slc.client.ui/META-INF/spring/commands.xml index 5df3ab1b0..76fee4681 100644 --- a/eclipse/plugins/org.argeo.slc.client.ui/META-INF/spring/commands.xml +++ b/eclipse/plugins/org.argeo.slc.client.ui/META-INF/spring/commands.xml @@ -4,10 +4,18 @@ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> + + + + + + @@ -37,6 +45,6 @@ scope="prototype"> + scope="prototype"> diff --git a/eclipse/plugins/org.argeo.slc.client.ui/plugin.xml b/eclipse/plugins/org.argeo.slc.client.ui/plugin.xml index 7a47446bf..72e5cbc81 100644 --- a/eclipse/plugins/org.argeo.slc.client.ui/plugin.xml +++ b/eclipse/plugins/org.argeo.slc.client.ui/plugin.xml @@ -1,135 +1,149 @@ - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - + point="org.eclipse.ui.views"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + - - + + + + + commandId="org.argeo.slc.client.ui.removeSelectedResultFromResultList" + icon="icons/removeAll.png" + label="Remove selected" + tooltip="Remove selected items from the result list (Also on server side, cannot be undone)"> - - - - - - - - - - - - - - + + + + + + + + + + + + + + \ No newline at end of file diff --git a/eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/commands/RemoveSelectedResultFromResultList.java b/eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/commands/RemoveSelectedResultFromResultList.java new file mode 100644 index 000000000..2eb0854f9 --- /dev/null +++ b/eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/commands/RemoveSelectedResultFromResultList.java @@ -0,0 +1,33 @@ +package org.argeo.slc.client.ui.commands; + +import org.argeo.slc.client.ui.views.ResultListView; +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.ui.handlers.HandlerUtil; + +/** + * + * @author bsinou + * + * Launch the batch built in the ProcessBuilderView + * + * NOTE : only one batch is supported with this command, if more than + * one batch is planned, this class must be updated with parameter. + */ + +public class RemoveSelectedResultFromResultList extends AbstractHandler { + public final static String ID = "org.argeo.slc.client.ui.removeSelectedResultFromResultList"; + + // private final static Log log = + // LogFactory.getLog(RemoveSelectedProcessFromBatchHandler.class); + + public Object execute(ExecutionEvent event) throws ExecutionException { + ResultListView rlView = (ResultListView) HandlerUtil + .getActiveWorkbenchWindow(event).getActivePage() + .findView(ResultListView.ID); + rlView.removeSelected(); + return null; + } + +} diff --git a/eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/commands/ResultDetailsDisplayHandler.java b/eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/commands/ResultDetailsDisplayHandler.java index aa4346072..52bce6bc3 100644 --- a/eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/commands/ResultDetailsDisplayHandler.java +++ b/eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/commands/ResultDetailsDisplayHandler.java @@ -1,6 +1,10 @@ package org.argeo.slc.client.ui.commands; +import java.util.Iterator; +import java.util.List; + import org.argeo.slc.client.ui.views.ResultDetailView; +import org.argeo.slc.client.ui.views.ResultListView; import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; @@ -18,20 +22,21 @@ public class ResultDetailsDisplayHandler extends AbstractHandler { // private static final Log log = LogFactory // .getLog(ResultDetailsDisplayHandler.class); + public final static String ID = "org.argeo.slc.client.ui.displayResultDetails"; + public Object execute(ExecutionEvent event) throws ExecutionException { + // We rather directly retrieve the corresponding view than use command + // parameters. + // We pass the UUID of the test result we want to display via command // parameters. - String uuid = event - .getParameter("org.argeo.slc.client.commands.resultUuid"); + // String uuid = event + // .getParameter("org.argeo.slc.client.commands.resultUuid"); // TODO : remove this. // if (uuid == null || "".equals(uuid)) { // try { - // ResultListView pbv = (ResultListView) HandlerUtil - // .getActiveWorkbenchWindow(event).getActivePage() - // .showView(ResultListView.ID); - // uuid = pbv.getSelectedResult()[0]; // } catch (PartInitException e) { // // TODO Auto-generated catch block // e.printStackTrace(); @@ -45,11 +50,21 @@ public class ResultDetailsDisplayHandler extends AbstractHandler { // should be made visible and activated. Use of this mode has the same // effect as calling try { - ResultDetailView rView = (ResultDetailView) HandlerUtil + ResultListView rlv = (ResultListView) HandlerUtil .getActiveWorkbenchWindow(event).getActivePage() - .showView(ResultDetailView.ID, "UUID-" + uuid, 1); - rView.setUuid(uuid); - rView.retrieveResults(); + .findView(ResultListView.ID); + List ids = rlv.getSelectedResultsId(); + + ResultDetailView rView; + Iterator it = ids.iterator(); + while (it.hasNext()) { + String uuid = it.next(); + rView = (ResultDetailView) HandlerUtil + .getActiveWorkbenchWindow(event).getActivePage() + .showView(ResultDetailView.ID, "UUID-" + uuid, 1); + rView.setUuid(uuid); + rView.retrieveResults(); + } } catch (Exception e) { e.printStackTrace(); } diff --git a/eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/views/ResultDetailView.java b/eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/views/ResultDetailView.java index 2c81ffdce..840f31d68 100644 --- a/eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/views/ResultDetailView.java +++ b/eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/views/ResultDetailView.java @@ -25,8 +25,8 @@ public class ResultDetailView extends ViewPart { private final static Log log = LogFactory.getLog(ResultDetailView.class); public static final String ID = "org.argeo.slc.client.ui.resultDetailView"; - protected String[] columnNames = new String[] { "Test", "State", "Message", - "Id" }; + protected String[] columnNames = new String[] { "Test", "Message", + "Exception Msg" }; private TreeViewer viewer; private Tree resultDetailTree; @@ -56,9 +56,14 @@ public class ResultDetailView extends ViewPart { // 0 and it will look as if the column didn't exist. switch (i) { case 0: - column.setWidth(230); + column.setWidth(180); + break; case 1: - column.setWidth(200); + column.setWidth(150); + break; + case 2: + column.setWidth(150); + break; default: column.setWidth(70); } @@ -68,17 +73,18 @@ public class ResultDetailView extends ViewPart { viewer.setContentProvider(contentProvider); // viewer.setLabelProvider(new ResultDetailLabelProvider()); - log.debug("Injected LabelProvider :" + labelProvider.toString()); + if (log.isTraceEnabled()) + log.debug("Injected LabelProvider :" + labelProvider.toString()); // TIP: It seems, that if the table has not defined any TreeColumns then // a plain LabelProvider will be used. Since, we don't provide an // instance of LabelProvider, a default one will be used and - // the TableLableProvider is ignored without notice. Took me quite + // the TableLabelProvider is ignored without notice. Took me quite // a while to find that one out. viewer.setLabelProvider(labelProvider); - log.debug("Persisted labelProvider :" - + viewer.getLabelProvider().toString()); - // viewer.setInput(getViewSite()); + if (log.isTraceEnabled()) + log.debug("Persisted labelProvider :" + + viewer.getLabelProvider().toString()); // viewer.expandAll(); diff --git a/eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/views/ResultListView.java b/eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/views/ResultListView.java index 837456d5b..79618dddd 100644 --- a/eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/views/ResultListView.java +++ b/eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/views/ResultListView.java @@ -3,13 +3,18 @@ package org.argeo.slc.client.ui.views; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.argeo.ArgeoException; +import org.argeo.eclipse.ui.GenericTableComparator; import org.argeo.slc.SlcException; import org.argeo.slc.client.ui.ClientUiPlugin; +import org.argeo.slc.client.ui.commands.RemoveSelectedResultFromResultList; +import org.argeo.slc.client.ui.commands.ResultDetailsDisplayHandler; import org.argeo.slc.core.test.tree.ResultAttributes; import org.argeo.slc.dao.test.tree.TreeTestResultCollectionDao; import org.eclipse.core.commands.Command; @@ -31,6 +36,8 @@ import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Menu; @@ -50,21 +57,30 @@ public class ResultListView extends ViewPart { public static final String ID = "org.argeo.slc.client.ui.resultListView"; - private final static String DISPLAY_CMD_ID = "org.argeo.slc.client.ui.displayResultDetails"; + // TODO : remove dependency from SLC on Sparta private final static String DISPLAY_AS_XLS_CMD_ID = "com.capco.sparta.client.ui.displayResultDetailsWithExcel"; private final static String SAVE_AS_XLS_CMD_ID = "com.capco.sparta.client.ui.saveResultAsExcelFile"; + + private final static String PLATFORM = SWT.getPlatform(); + + private final static String DISPLAY_CMD_ID = ResultDetailsDisplayHandler.ID; + private final static String REMOVE_CMD_ID = RemoveSelectedResultFromResultList.ID; private final static String UUID_PARAM_ID = "org.argeo.slc.client.commands.resultUuid"; private final static String NAME_PARAM_ID = "org.argeo.slc.client.commands.resultName"; - private final static String PLATFORM = SWT.getPlatform(); private final static SimpleDateFormat dateFormatter = new SimpleDateFormat( - "MM/dd/yyyy 'at' HH:mm:ss"); + "MM/dd/yy', 'HH:mm:ss"); private TableViewer viewer; private TreeTestResultCollectionDao testResultCollectionDao; + private CurrentTableComparator comparator; + private ResultAttributes selectedRa; + // handle locally which result are shown or not + private List removedResults = new ArrayList(); + public void createPartControl(Composite parent) { Table table = createTable(parent); viewer = new TableViewer(table); @@ -74,8 +90,13 @@ public class ResultListView extends ViewPart { viewer.addDoubleClickListener(new ViewDoubleClickListener()); viewer.addSelectionChangedListener(new SelectionChangedListener()); - // create the context menu + // Initializes sort mecanism + // by default we sort by date asc + comparator = new CurrentTableComparator(1, + GenericTableComparator.ASCENDING); + viewer.setComparator(comparator); + // create the context menu MenuManager menuManager = new MenuManager(); Menu menu = menuManager.createContextMenu(viewer.getControl()); menuManager.addMenuListener(new IMenuListener() { @@ -89,7 +110,7 @@ public class ResultListView extends ViewPart { } protected Table createTable(Composite parent) { - int style = SWT.SINGLE | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL + int style = SWT.MULTI | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION; // does not function with RAP, commented for the moment being // | SWT.HIDE_SELECTION; @@ -108,37 +129,86 @@ public class ResultListView extends ViewPart { TableColumn column = new TableColumn(table, SWT.LEFT, 0); column.setText("Test Case"); column.setWidth(200); + column.addSelectionListener(getSelectionAdapter(column, 0)); column = new TableColumn(table, SWT.LEFT, 1); column.setText("Close Date"); - column.setWidth(120); + column.setWidth(130); + column.addSelectionListener(getSelectionAdapter(column, 1)); column = new TableColumn(table, SWT.LEFT, 2); column.setText("UUID"); column.setWidth(300); + column.addSelectionListener(getSelectionAdapter(column, 2)); return table; } - // TODO : Improve this methods. - // For now it is a workaround because we cannot dynamically update context - // menu to pass the UUID as command parameter - // public String[] getSelectedResult() { - // Object obj = ((IStructuredSelection) viewer.getSelection()) - // .getFirstElement(); - // - // String[] attributes = new String[2]; - // - // if (obj == null || !(obj instanceof ResultAttributes)) - // return null; - // else { - // ResultAttributes ra = (ResultAttributes) obj; - // attributes[0] = ra.getUuid(); - // attributes[1] = (ra.getAttributes().get("testCase") == null) ? null - // : ra.getAttributes().get("testCase"); - // return attributes; - // } - // } + // Manage list of the result + public void setFocus() { + viewer.getControl().setFocus(); + } + + /** Initialize the view **/ + public void retrieveResults() { + try { + List lst = testResultCollectionDao + .listResultAttributes(null); + if (log.isTraceEnabled()) + log.trace("Result attributes count: " + lst.size()); + + // handle removed result from the list locally + // Might be optimised. + Iterator it = removedResults.iterator(); + removeResult: while (it.hasNext()) { + ResultAttributes curRa = it.next(); + String curRaId = curRa.getUuid(); + for (Iterator it2 = lst.iterator(); it2 + .hasNext();) { + ResultAttributes tmpRa = it2.next(); + if (tmpRa.getUuid().equals(curRaId)) { + lst.remove(tmpRa); + continue removeResult; + } + } + if (lst.contains(curRa)) + lst.remove(curRa); + } + viewer.setInput(lst); + } catch (Exception e) { + throw new ArgeoException("Cannot refresh the result List", e); + } + } + + public List getSelectedResultsId() { + List resultIds = new ArrayList(); + IStructuredSelection curSelection = (IStructuredSelection) viewer + .getSelection(); + Iterator it = curSelection.iterator(); + while (it.hasNext()) { + ResultAttributes curResult = (ResultAttributes) it.next(); + resultIds.add(curResult.getUuid()); + } + return resultIds; + } + + /** + * Remove selected items from the result list. This process is handled + * locally in the UI side : trying to handle that on the server side throws + * HibernateLazyInit exception, especially when trying to access + * TreeTestResultCollection items. + */ + public void removeSelected() { + IStructuredSelection curSelection = (IStructuredSelection) viewer + .getSelection(); + Iterator it = curSelection.iterator(); + while (it.hasNext()) { + ResultAttributes curResult = (ResultAttributes) it.next(); + if (!removedResults.contains(curResult)) + removedResults.add(curResult); + } + retrieveResults(); + } // View Specific inner class @@ -156,7 +226,10 @@ public class ResultListView extends ViewPart { } } - private void refreshCommand(IMenuManager menuManager, + // Relatively useless in the current case. + // Yet we keep it as sample code to show how we can implement a context menu + // which commands are dynamically linked to the selected item of a control + protected void refreshCommand(IMenuManager menuManager, IServiceLocator locator, String cmdId, String label, String iconPath) { IContributionItem ici = menuManager.find(cmdId); if (ici != null) @@ -168,13 +241,14 @@ public class ResultListView extends ViewPart { contributionItemParameter.label = label; contributionItemParameter.icon = ClientUiPlugin .getImageDescriptor(iconPath); - - Map params = new HashMap(); - params.put(UUID_PARAM_ID, selectedRa.getUuid()); - params.put(NAME_PARAM_ID, - (selectedRa.getAttributes().get("testCase") == null) ? null - : selectedRa.getAttributes().get("testCase")); - contributionItemParameter.parameters = params; + if (!REMOVE_CMD_ID.equals(cmdId)) { + Map params = new HashMap(); + params.put(UUID_PARAM_ID, selectedRa.getUuid()); + params.put(NAME_PARAM_ID, + (selectedRa.getAttributes().get("testCase") == null) ? null + : selectedRa.getAttributes().get("testCase")); + contributionItemParameter.parameters = params; + } CommandContributionItem cci = new CommandContributionItem( contributionItemParameter); @@ -182,24 +256,31 @@ public class ResultListView extends ViewPart { menuManager.add(cci); } - private void contextMenuAboutToShow(IMenuManager menuManager) { + /** + * Defines the commands that will pop up in the context menu. Might be + * overriden by user to add or remove certain commands. + **/ + protected void contextMenuAboutToShow(IMenuManager menuManager) { IWorkbenchWindow window = ClientUiPlugin.getDefault().getWorkbench() .getActiveWorkbenchWindow(); refreshCommand(menuManager, window, DISPLAY_CMD_ID, - "Display as a tree", "icons/result_details.gif"); + "Display selected as tree", "icons/result_details.gif"); // We only show this command on windows OS if (PLATFORM.equals("win32") || PLATFORM.equals("wpf")) { refreshCommand(menuManager, window, DISPLAY_AS_XLS_CMD_ID, - "Display with Excel", "icons/excel.png"); + "Display selected with Excel", "icons/excel.png"); } refreshCommand(menuManager, window, SAVE_AS_XLS_CMD_ID, - "Save as Excel file", "icons/excel.png"); + "Save selected as Excel files", "icons/excel.png"); + + refreshCommand(menuManager, window, REMOVE_CMD_ID, "Remove selected", + "icons/removeAll.png"); + } // Providers - protected static class ViewContentProvider implements IStructuredContentProvider { @@ -244,22 +325,72 @@ public class ResultListView extends ViewPart { } - public void setFocus() { - viewer.getControl().setFocus(); - } + // Sort Mecanism + private class CurrentTableComparator extends GenericTableComparator { - public void retrieveResults() { - try { - List lst = testResultCollectionDao - .listResultAttributes(null); - if (log.isTraceEnabled()) - log.trace("Result attributes count: " + lst.size()); - viewer.setInput(lst); - // viewer.refresh(); - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); + public CurrentTableComparator(int colIndex, int direction) { + super(colIndex, direction); } + + @Override + public int compare(Viewer viewer, Object r1, Object r2) { + + int rc = 0; + ResultAttributes ra1 = (ResultAttributes) r1; + ResultAttributes ra2 = (ResultAttributes) r2; + + switch (propertyIndex) { + case 0: + if (ra1.getAttributes().get("testCase") == null) + rc = -1; + else if (ra2.getAttributes().get("testCase") == null) + rc = 1; + else + rc = ra1.getAttributes().get("testCase") + .compareTo(ra2.getAttributes().get("testCase")); + break; + case 1: + // result with close date == null are put at the end : either + // they are nor finished or in error + if (ra1.getCloseDate() == null) + rc = 1; + else if (ra2.getCloseDate() == null) + rc = -1; + else + rc = ra1.getCloseDate().compareTo(ra2.getCloseDate()); + break; + case 2: + rc = ra1.getUuid().compareTo(ra2.getUuid()); + break; + } + + if (direction == DESCENDING) { + rc = -rc; + } + return rc; + } + } + + private SelectionAdapter getSelectionAdapter(final TableColumn column, + final int index) { + + SelectionAdapter selectionAdapter = new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + + comparator.setColumn(index); + int dir = viewer.getTable().getSortDirection(); + if (viewer.getTable().getSortColumn() == column) { + dir = dir == SWT.UP ? SWT.DOWN : SWT.UP; + } else { + dir = SWT.DOWN; + } + viewer.getTable().setSortDirection(dir); + viewer.getTable().setSortColumn(column); + viewer.refresh(); + } + }; + return selectionAdapter; } // Handle Events -- 2.39.2