X-Git-Url: http://git.argeo.org/?a=blobdiff_plain;f=org.argeo.slc.client.ui%2Fsrc%2Forg%2Fargeo%2Fslc%2Fclient%2Fui%2Fviews%2FJcrResultTreeView.java;h=824dcfd727a0e50a554b60542082eac171636d61;hb=e07ded4632e53f8b8869763bc1f1f4091361e76e;hp=a7d63413ddae19d549f46d54c8a21131342ef566;hpb=149f170df5b5430cd816a4c80347a37055415139;p=gpl%2Fargeo-slc.git diff --git a/org.argeo.slc.client.ui/src/org/argeo/slc/client/ui/views/JcrResultTreeView.java b/org.argeo.slc.client.ui/src/org/argeo/slc/client/ui/views/JcrResultTreeView.java index a7d63413d..824dcfd72 100644 --- a/org.argeo.slc.client.ui/src/org/argeo/slc/client/ui/views/JcrResultTreeView.java +++ b/org.argeo.slc.client.ui/src/org/argeo/slc/client/ui/views/JcrResultTreeView.java @@ -1,967 +1,953 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed 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.argeo.slc.client.ui.views; - -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Iterator; -import java.util.List; - -import javax.jcr.Node; -import javax.jcr.NodeIterator; -import javax.jcr.Property; -import javax.jcr.Repository; -import javax.jcr.RepositoryException; -import javax.jcr.Session; -import javax.jcr.nodetype.NodeType; -import javax.jcr.observation.Event; -import javax.jcr.observation.EventListener; -import javax.jcr.observation.ObservationManager; - -import org.argeo.cms.ui.workbench.util.CommandUtils; -import org.argeo.eclipse.ui.jcr.AsyncUiEventListener; -import org.argeo.jcr.JcrUtils; -import org.argeo.slc.SlcException; -import org.argeo.slc.client.ui.ClientUiPlugin; -import org.argeo.slc.client.ui.SlcUiConstants; -import org.argeo.slc.client.ui.commands.AddResultFolder; -import org.argeo.slc.client.ui.commands.DeleteItems; -import org.argeo.slc.client.ui.commands.RefreshJcrResultTreeView; -import org.argeo.slc.client.ui.commands.RenameResultFolder; -import org.argeo.slc.client.ui.commands.RenameResultNode; -import org.argeo.slc.client.ui.editors.ProcessEditor; -import org.argeo.slc.client.ui.editors.ProcessEditorInput; -import org.argeo.slc.client.ui.model.ParentNodeFolder; -import org.argeo.slc.client.ui.model.ResultFolder; -import org.argeo.slc.client.ui.model.ResultItemsComparator; -import org.argeo.slc.client.ui.model.ResultItemsComparer; -import org.argeo.slc.client.ui.model.ResultParent; -import org.argeo.slc.client.ui.model.ResultParentUtils; -import org.argeo.slc.client.ui.model.SingleResultNode; -import org.argeo.slc.client.ui.model.VirtualFolder; -import org.argeo.slc.client.ui.providers.ResultTreeContentProvider; -import org.argeo.slc.client.ui.providers.ResultTreeLabelProvider; -import org.argeo.slc.jcr.SlcJcrResultUtils; -import org.argeo.slc.jcr.SlcNames; -import org.argeo.slc.jcr.SlcTypes; -import org.eclipse.jface.action.IMenuListener; -import org.eclipse.jface.action.IMenuManager; -import org.eclipse.jface.action.MenuManager; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.viewers.ColumnLabelProvider; -import org.eclipse.jface.viewers.DecoratingLabelProvider; -import org.eclipse.jface.viewers.DoubleClickEvent; -import org.eclipse.jface.viewers.IDoubleClickListener; -import org.eclipse.jface.viewers.ILabelDecorator; -import org.eclipse.jface.viewers.ISelectionChangedListener; -import org.eclipse.jface.viewers.IStructuredContentProvider; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.viewers.SelectionChangedEvent; -import org.eclipse.jface.viewers.TableViewer; -import org.eclipse.jface.viewers.TableViewerColumn; -import org.eclipse.jface.viewers.TreePath; -import org.eclipse.jface.viewers.TreeViewer; -import org.eclipse.jface.viewers.Viewer; -import org.eclipse.jface.viewers.ViewerDropAdapter; -import org.eclipse.swt.SWT; -import org.eclipse.swt.custom.SashForm; -import org.eclipse.swt.dnd.DND; -import org.eclipse.swt.dnd.DragSourceEvent; -import org.eclipse.swt.dnd.DragSourceListener; -import org.eclipse.swt.dnd.TextTransfer; -import org.eclipse.swt.dnd.Transfer; -import org.eclipse.swt.dnd.TransferData; -import org.eclipse.swt.layout.FillLayout; -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.ui.ISharedImages; -import org.eclipse.ui.IWorkbenchPage; -import org.eclipse.ui.IWorkbenchWindow; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.part.ViewPart; - -/** SLC generic JCR Result tree view. */ -public class JcrResultTreeView extends ViewPart { - public final static String ID = ClientUiPlugin.ID + ".jcrResultTreeView"; - - private final static DateFormat dateFormat = new SimpleDateFormat( - SlcUiConstants.DEFAULT_DISPLAY_DATE_TIME_FORMAT); - - // private final static Log log = - // LogFactory.getLog(JcrResultTreeView.class); - - /* DEPENDENCY INJECTION */ - private Repository repository; - private Session session; - - // This page widgets - private TreeViewer resultTreeViewer; - private TableViewer propertiesViewer; - - private EventListener myResultsObserver = null; - private EventListener allResultsObserver = null; - - // under My Results - private final static String[] observedNodeTypesUnderMyResult = { - SlcTypes.SLC_TEST_RESULT, SlcTypes.SLC_RESULT_FOLDER, - SlcTypes.SLC_MY_RESULT_ROOT_FOLDER }; - - private final static String[] observedNodeTypesUnderAllResults = { - SlcTypes.SLC_TEST_RESULT, NodeType.NT_UNSTRUCTURED }; - - private boolean isResultFolder = false; - - /** - * To be overridden to adapt size of form and result frames. - */ - protected int[] getWeights() { - return new int[] { 70, 30 }; - } - - @Override - public void createPartControl(Composite parent) { - try { - session = repository.login(); - } catch (RepositoryException e1) { - throw new SlcException("Cannot log in to repository"); - } - - parent.setLayout(new FillLayout()); - // Main layout - SashForm sashForm = new SashForm(parent, SWT.VERTICAL); - sashForm.setSashWidth(4); - sashForm.setLayout(new FillLayout()); - - // Create the tree on top of the view - Composite top = new Composite(sashForm, SWT.NONE); - GridLayout gl = new GridLayout(1, false); - top.setLayout(gl); - resultTreeViewer = createResultsTreeViewer(top); - - // Create the property viewer on the bottom - Composite bottom = new Composite(sashForm, SWT.NONE); - bottom.setLayout(new GridLayout(1, false)); - propertiesViewer = createPropertiesViewer(bottom); - - sashForm.setWeights(getWeights()); - - setOrderedInput(resultTreeViewer); - - // Initialize observer - try { - ObservationManager observationManager = session.getWorkspace() - .getObservationManager(); - myResultsObserver = new MyResultsObserver(resultTreeViewer - .getTree().getDisplay()); - allResultsObserver = new AllResultsObserver(resultTreeViewer - .getTree().getDisplay()); - - // observe tree changes under MyResults - observationManager.addEventListener(myResultsObserver, - Event.NODE_ADDED | Event.NODE_REMOVED, - SlcJcrResultUtils.getMyResultsBasePath(session), true, - null, observedNodeTypesUnderMyResult, false); - // observe tree changes under All results - observationManager.addEventListener(allResultsObserver, - Event.NODE_ADDED | Event.NODE_REMOVED, - SlcJcrResultUtils.getSlcResultsBasePath(session), true, - null, observedNodeTypesUnderAllResults, false); - } catch (RepositoryException e) { - throw new SlcException("Cannot register listeners", e); - } - } - - /** - * Override default behaviour so that default defined order remains - * unchanged on first level of the tree - */ - private void setOrderedInput(TreeViewer viewer) { - // Add specific ordering - viewer.setInput(null); - viewer.setComparator(null); - viewer.setInput(initializeResultTree()); - viewer.setComparator(new ResultItemsComparator()); - } - - // The main tree viewer - protected TreeViewer createResultsTreeViewer(Composite parent) { - int style = SWT.BORDER | SWT.MULTI; - - TreeViewer viewer = new TreeViewer(parent, style); - viewer.getTree().setLayoutData( - new GridData(SWT.FILL, SWT.FILL, true, true)); - - viewer.setContentProvider(new ResultTreeContentProvider()); - - // Add label provider with label decorator - ResultTreeLabelProvider rtLblProvider = new ResultTreeLabelProvider(); - ILabelDecorator decorator = ClientUiPlugin.getDefault().getWorkbench() - .getDecoratorManager().getLabelDecorator(); - viewer.setLabelProvider(new DecoratingLabelProvider(rtLblProvider, - decorator)); - viewer.addDoubleClickListener(new ViewDoubleClickListener()); - - // Override default behaviour to insure that 2 distincts results that - // have the same name will be correctly and distincly returned by - // corresponding TreeViewer.getSelection() method. - viewer.setComparer(new ResultItemsComparer()); - - // viewer.setLabelProvider(rtLblProvider); - getSite().setSelectionProvider(viewer); - - // add drag & drop support - int operations = DND.DROP_COPY | DND.DROP_MOVE; - Transfer[] tt = new Transfer[] { TextTransfer.getInstance() }; - viewer.addDragSupport(operations, tt, new ViewDragListener()); - viewer.addDropSupport(operations, tt, new ViewDropListener(viewer)); - - // add context menu - MenuManager menuManager = new MenuManager(); - Menu menu = menuManager.createContextMenu(viewer.getTree()); - menuManager.addMenuListener(new IMenuListener() { - public void menuAboutToShow(IMenuManager manager) { - contextMenuAboutToShow(manager); - } - }); - viewer.getTree().setMenu(menu); - menuManager.setRemoveAllWhenShown(true); - - getSite().registerContextMenu(menuManager, viewer); - - // add change listener to display TestResult information in the property - // viewer - viewer.addSelectionChangedListener(new MySelectionChangedListener()); - return viewer; - } - - // Detailed property viewer - protected TableViewer createPropertiesViewer(Composite parent) { - propertiesViewer = new TableViewer(parent); - propertiesViewer.getTable().setLayoutData( - new GridData(SWT.FILL, SWT.FILL, true, true)); - propertiesViewer.getTable().setHeaderVisible(true); - propertiesViewer.setContentProvider(new PropertiesContentProvider()); - TableViewerColumn col = new TableViewerColumn(propertiesViewer, - SWT.NONE); - col.getColumn().setText("Name"); - col.getColumn().setWidth(100); - col.setLabelProvider(new ColumnLabelProvider() { - public String getText(Object element) { - try { - String name = ((Property) element).getName(); - String value = null; - if (SlcNames.SLC_TEST_CASE.equals(name)) - value = "Test case"; - else if (SlcNames.SLC_COMPLETED.equals(name)) - value = "Completed on"; - else if (SlcNames.SLC_SUCCESS.equals(name)) - value = "Status"; - else if (SlcNames.SLC_MESSAGE.equals(name)) - value = "Message"; - else if (SlcNames.SLC_ERROR_MESSAGE.equals(name)) - value = "Error"; - return value; - } catch (RepositoryException e) { - throw new SlcException( - "Unexpected exception in label provider", e); - } - } - }); - col = new TableViewerColumn(propertiesViewer, SWT.NONE); - col.getColumn().setText("Value"); - col.getColumn().setWidth(200); - col.setLabelProvider(new ColumnLabelProvider() { - public String getText(Object element) { - try { - Property property = (Property) element; - String name = property.getName(); - String value = null; - - if (SlcNames.SLC_TEST_CASE.equals(name) - || SlcNames.SLC_ERROR_MESSAGE.equals(name) - || SlcNames.SLC_MESSAGE.equals(name)) - value = property.getValue().getString(); - else if (SlcNames.SLC_COMPLETED.equals(name)) { - Calendar date = property.getValue().getDate(); - value = dateFormat.format(date.getTime()); - } else if (SlcNames.SLC_SUCCESS.equals(name)) { - if (property.getValue().getBoolean()) - value = "PASSED"; - else { - if (property.getParent().hasProperty( - SlcNames.SLC_ERROR_MESSAGE)) - value = "ERROR"; - else - value = "FAILED"; - } - } - return value; - } catch (RepositoryException e) { - throw new SlcException( - "Unexpected exception in label provider", e); - } - } - }); - propertiesViewer.setInput(getViewSite()); - return propertiesViewer; - } - - /** - * Override to provide specific behaviour. Typically to enable the display - * of a result file. - * - * @param evt - */ - protected void processDoubleClick(DoubleClickEvent evt) { - Object obj = ((IStructuredSelection) evt.getSelection()) - .getFirstElement(); - try { - if (obj instanceof SingleResultNode) { - SingleResultNode srNode = (SingleResultNode) obj; - Node node = srNode.getNode(); - // FIXME: open a default result editor - if (node.isNodeType(SlcTypes.SLC_PROCESS)) { - IWorkbenchPage activePage = PlatformUI.getWorkbench() - .getActiveWorkbenchWindow().getActivePage(); - activePage.openEditor( - new ProcessEditorInput(node.getPath()), - ProcessEditor.ID); - } - } - } catch (Exception e) { - throw new SlcException("Cannot open " + obj, e); - } - } - - @Override - public void setFocus() { - } - - /** - * refreshes the passed resultParent and its corresponding subtree. It - * refreshes the whole viewer if null is passed. - * - * @param ResultParent - * - */ - public void refresh(ResultParent resultParent) { - if (resultParent == null) { - if (!resultTreeViewer.getTree().isDisposed()) { - TreePath[] tps = resultTreeViewer.getExpandedTreePaths(); - setOrderedInput(resultTreeViewer); - resultTreeViewer.setExpandedTreePaths(tps); - } else - setOrderedInput(resultTreeViewer); - } else { - if (resultParent instanceof ParentNodeFolder) { - ParentNodeFolder currFolder = (ParentNodeFolder) resultParent; - jcrRefresh(currFolder.getNode()); - currFolder.forceFullRefresh(); - } - // FIXME: specific refresh does not work - // resultTreeViewer.refresh(resultParent, true); - refresh(null); - } - } - - /** - * refreshes the passed node and its corresponding subtree. - * - * @param node - * cannot be null - * - */ - public boolean jcrRefresh(Node node) { - // if (log.isDebugEnabled()) - // log.debug(" JCR refreshing " + node + "..."); - // Thread.dumpStack(); - boolean isPassed = true; - try { - if (node.isNodeType(SlcTypes.SLC_TEST_RESULT)) { - isPassed = node.getNode(SlcNames.SLC_AGGREGATED_STATUS) - .getProperty(SlcNames.SLC_SUCCESS).getBoolean(); - } else if (node.isNodeType(SlcTypes.SLC_RESULT_FOLDER)) { - NodeIterator ni = node.getNodes(); - while (ni.hasNext()) { - Node currChild = ni.nextNode(); - isPassed = isPassed & jcrRefresh(currChild); - } - if (isPassed != node.getNode(SlcNames.SLC_AGGREGATED_STATUS) - .getProperty(SlcNames.SLC_SUCCESS).getBoolean()) { - node.getNode(SlcNames.SLC_AGGREGATED_STATUS).setProperty( - SlcNames.SLC_SUCCESS, isPassed); - node.getSession().save(); - return isPassed; - } - } else - ; // do nothing - } catch (RepositoryException e) { - throw new SlcException("Cannot register listeners", e); - } - return isPassed; - } - - private ResultParent[] initializeResultTree() { - try { - // Force initialization of the tree structure if needed - SlcJcrResultUtils.getSlcResultsParentNode(session); - SlcJcrResultUtils.getMyResultParentNode(session); - // Remove yesterday and last 7 days virtual folders - // ResultParent[] roots = new ResultParent[5]; - ResultParent[] roots = new ResultParent[3]; - - // My results - roots[0] = new ParentNodeFolder(null, - SlcJcrResultUtils.getMyResultParentNode(session), - SlcUiConstants.DEFAULT_MY_RESULTS_FOLDER_LABEL); - - // today - Calendar cal = Calendar.getInstance(); - String relPath = JcrUtils.dateAsPath(cal); - List datePathes = new ArrayList(); - datePathes.add(relPath); - roots[1] = new VirtualFolder(null, - ResultParentUtils.getResultsForDates(session, datePathes), - "Today"); - - // // Yesterday - // cal = Calendar.getInstance(); - // cal.add(Calendar.DAY_OF_YEAR, -1); - // relPath = JcrUtils.dateAsPath(cal); - // datePathes = new ArrayList(); - // datePathes.add(relPath); - // roots[2] = new VirtualFolder(null, - // ResultParentUtils.getResultsForDates(session, datePathes), - // "Yesterday"); - // // Last 7 days - // - // cal = Calendar.getInstance(); - // datePathes = new ArrayList(); - // - // for (int i = 0; i < 7; i++) { - // cal.add(Calendar.DAY_OF_YEAR, -i); - // relPath = JcrUtils.dateAsPath(cal); - // datePathes.add(relPath); - // } - // roots[3] = new VirtualFolder(null, - // ResultParentUtils.getResultsForDates(session, datePathes), - // "Last 7 days"); - - // All results - Node otherResultsPar = session.getNode(SlcJcrResultUtils - .getSlcResultsBasePath(session)); - // roots[4] = new ParentNodeFolder(null, otherResultsPar, - // "All results"); - roots[2] = new ParentNodeFolder(null, otherResultsPar, - "All results"); - return roots; - } catch (RepositoryException re) { - throw new SlcException( - "Unexpected error while initializing ResultTree.", re); - } - } - - // Manage context menu - /** - * Defines the commands that will pop up in the context menu. - **/ - protected void contextMenuAboutToShow(IMenuManager menuManager) { - IWorkbenchWindow window = ClientUiPlugin.getDefault().getWorkbench() - .getActiveWorkbenchWindow(); - - IStructuredSelection selection = (IStructuredSelection) resultTreeViewer - .getSelection(); - boolean canAddSubfolder = false; - boolean canRenamefolder = false; - boolean isSingleResultNode = false; - boolean isUnderMyResult = false; - boolean validMultipleDelete = false; - try { - - // Building conditions - if (selection.size() == 1) { - Object obj = selection.getFirstElement(); - if (obj instanceof SingleResultNode) - isSingleResultNode = true; - else if (obj instanceof ParentNodeFolder) { - Node cNode = ((ParentNodeFolder) obj).getNode(); - if (cNode.isNodeType(SlcTypes.SLC_RESULT_FOLDER)) { - canAddSubfolder = true; - canRenamefolder = true; - isUnderMyResult = true; - } else if (cNode - .isNodeType(SlcTypes.SLC_MY_RESULT_ROOT_FOLDER)) { - canAddSubfolder = true; - } - } - } else { - @SuppressWarnings("rawtypes") - Iterator it = selection.iterator(); - multicheck: while (it.hasNext()) { - validMultipleDelete = true; - Object obj = it.next(); - if (obj instanceof SingleResultNode) - continue multicheck; - else if (obj instanceof ParentNodeFolder) { - Node cNode = ((ParentNodeFolder) obj).getNode(); - if (cNode.isNodeType(SlcTypes.SLC_RESULT_FOLDER)) - continue multicheck; - else { - validMultipleDelete = false; - break multicheck; - } - } else { - validMultipleDelete = false; - break multicheck; - } - } - } - } catch (RepositoryException re) { - throw new SlcException( - "unexpected error while building condition for context menu", - re); - } - - // Effective Refresh - CommandUtils.refreshCommand(menuManager, window, - RefreshJcrResultTreeView.ID, - RefreshJcrResultTreeView.DEFAULT_LABEL, - RefreshJcrResultTreeView.DEFAULT_IMG_DESCRIPTOR, true); - - CommandUtils.refreshCommand(menuManager, window, DeleteItems.ID, - DeleteItems.DEFAULT_LABEL, DeleteItems.DEFAULT_IMG_DESCRIPTOR, - isUnderMyResult || isSingleResultNode || validMultipleDelete); - - CommandUtils.refreshCommand(menuManager, window, AddResultFolder.ID, - AddResultFolder.DEFAULT_LABEL, - ClientUiPlugin.getDefault().getWorkbench().getSharedImages() - .getImageDescriptor(ISharedImages.IMG_OBJ_ADD), - canAddSubfolder); - - CommandUtils.refreshCommand(menuManager, window, RenameResultFolder.ID, - RenameResultFolder.DEFAULT_LABEL, - RenameResultFolder.DEFAULT_IMG_DESCRIPTOR, canRenamefolder); - - // Command removed for the time being. - CommandUtils.refreshCommand(menuManager, window, RenameResultNode.ID, - RenameResultNode.DEFAULT_LABEL, - RenameResultNode.DEFAULT_IMG_DESCRIPTOR, false); - - // Test to be removed - // If you use this pattern, do not forget to call - // menuManager.setRemoveAllWhenShown(true); - // when creating the menuManager - - // menuManager.add(new Action("Test") { - // public void run() { - // log.debug("do something"); - // } - // }); - } - - /* INNER CLASSES */ - class ViewDragListener implements DragSourceListener { - - public void dragStart(DragSourceEvent event) { - // Check if the drag action should start. - IStructuredSelection selection = (IStructuredSelection) resultTreeViewer - .getSelection(); - boolean doIt = false; - - // FIXME clean this code. - try { - if (selection.size() == 1) { - Object obj = selection.getFirstElement(); - if (obj instanceof ResultFolder) { - Node tNode = ((ResultFolder) obj).getNode(); - if (tNode.getPrimaryNodeType().isNodeType( - SlcTypes.SLC_RESULT_FOLDER)) { - doIt = true; - isResultFolder = true; - } - } else - isResultFolder = false; - } else - isResultFolder = false; - - if (!isResultFolder) { - @SuppressWarnings("rawtypes") - Iterator it = selection.iterator(); - while (it.hasNext()) { - Object obj = it.next(); - if (obj instanceof SingleResultNode) { - Node tNode = ((SingleResultNode) obj).getNode(); - if (tNode.getPrimaryNodeType().isNodeType( - SlcTypes.SLC_TEST_RESULT)) { - doIt = true; - } - } - } - } - - } catch (RepositoryException re) { - throw new SlcException( - "unexpected error while validating drag source", re); - } - event.doit = doIt; - } - - public void dragSetData(DragSourceEvent event) { - IStructuredSelection selection = (IStructuredSelection) resultTreeViewer - .getSelection(); - - try { - // specific case of a result folder - if (isResultFolder) { - Object obj = selection.getFirstElement(); - event.data = ((ResultFolder) obj).getNode().getIdentifier(); - } else { - @SuppressWarnings("rawtypes") - Iterator it = selection.iterator(); - StringBuilder nodes = new StringBuilder(); - while (it.hasNext()) { - Object obj = it.next(); - if (obj instanceof SingleResultNode) { - Node tNode = ((SingleResultNode) obj).getNode(); - if (tNode.getPrimaryNodeType().isNodeType( - SlcTypes.SLC_TEST_RESULT)) { - nodes.append(tNode.getIdentifier()).append(";"); - } - } - } - event.data = nodes.toString(); - } - } catch (RepositoryException re) { - throw new SlcException("unexpected error while setting data", - re); - } - } - - public void dragFinished(DragSourceEvent event) { - // refresh is done via observer - } - } - - // Implementation of the Drop Listener - protected class ViewDropListener extends ViewerDropAdapter { - private Node targetParentNode = null; - - public ViewDropListener(Viewer viewer) { - super(viewer); - } - - @Override - public boolean validateDrop(Object target, int operation, - TransferData transferType) { - boolean validDrop = false; - try { - // We can only drop under myResults - Node tpNode = null; - if (target instanceof SingleResultNode) { - Node currNode = ((SingleResultNode) target).getNode(); - String pPath = currNode.getParent().getPath(); - if (pPath.startsWith(SlcJcrResultUtils - .getMyResultsBasePath(session))) - tpNode = currNode.getParent(); - } else if (target instanceof ResultFolder) { - tpNode = ((ResultFolder) target).getNode(); - } else if (target instanceof ParentNodeFolder) { - Node node = ((ParentNodeFolder) target).getNode(); - if (node.isNodeType(SlcTypes.SLC_MY_RESULT_ROOT_FOLDER)) - tpNode = ((ParentNodeFolder) target).getNode(); - } - - if (tpNode != null) { - targetParentNode = tpNode; - validDrop = true; - } - } catch (RepositoryException re) { - throw new SlcException( - "unexpected error while validating drop target", re); - } - return validDrop; - } - - @Override - public boolean performDrop(Object data) { - // clear selection to prevent unwanted scrolling of the UI - resultTreeViewer.setSelection(null); - try { - if (isResultFolder) { - // Sanity check : we cannot move a folder to one of its sub - // folder or neither move an object in the same parent - // folder - Node source = session.getNodeByIdentifier((String) data); - if (targetParentNode.getPath().startsWith(source.getPath()) - || source.getParent().getPath() - .equals(targetParentNode.getPath())) - return false; - - // Move - String sourcePath = source.getPath(); - String destPath = targetParentNode.getPath() + "/" - + source.getName(); - session.move(sourcePath, destPath); - // Update passed status of the parent source Node - ResultParentUtils.updatePassedStatus( - session.getNode(JcrUtils.parentPath(sourcePath)), - true); - // Node target = session.getNode(destPath); - session.save(); - return true; - } - - String[] datas = ((String) data).split(";"); - nodesToCopy: for (String id : datas) { - - Node source = session.getNodeByIdentifier(id); - String name; - if (source.hasProperty(Property.JCR_TITLE)) - name = source.getProperty(Property.JCR_TITLE) - .getString(); - else if (source.hasProperty(SlcNames.SLC_TEST_CASE)) - name = source.getProperty(SlcNames.SLC_TEST_CASE) - .getString(); - else - name = source.getName(); - - // Check if another copy of the same test instance already - // exists at target - NodeIterator ni = targetParentNode.getNodes(); - String slcUid = source.getProperty(SlcNames.SLC_UUID) - .getString(); - while (ni.hasNext()) { - Node curr = ni.nextNode(); - if (curr.hasProperty(SlcNames.SLC_UUID) - && slcUid.equals(curr.getProperty( - SlcNames.SLC_UUID).getString())) { - MessageDialog - .openWarning( - PlatformUI.getWorkbench() - .getDisplay() - .getActiveShell(), - "Duplicated instance.", - "An instance of the same test case (" - + name - + ") exists at destination.\n " - + "This item will not be neither copied nor moved."); - continue nodesToCopy; - - } - } - - Node target; - boolean passedStatus = false; - if (source.hasNode(SlcNames.SLC_AGGREGATED_STATUS)) - passedStatus = source - .getNode(SlcNames.SLC_AGGREGATED_STATUS) - .getProperty(SlcNames.SLC_SUCCESS).getBoolean(); - - boolean isActionUnderMyResult = source.getPath() - .startsWith( - SlcJcrResultUtils - .getMyResultsBasePath(session)); - - if (!isActionUnderMyResult) {// Copy - target = targetParentNode.addNode(source.getName(), - source.getPrimaryNodeType().getName()); - JcrUtils.copy(source, target); - } else {// move - String sourcePath = source.getPath(); - String destPath = targetParentNode.getPath() + "/" - + name; - session.move(sourcePath, destPath); - // Update passed status of the parent source Node - ResultParentUtils - .updatePassedStatus(session.getNode(JcrUtils - .parentPath(sourcePath)), true); - target = session.getNode(destPath); - - } - if (!target.isNodeType(NodeType.MIX_TITLE)) - target.addMixin(NodeType.MIX_TITLE); - target.setProperty(Property.JCR_TITLE, name); - ResultParentUtils.updatePassedStatus(target.getParent(), - passedStatus); - session.save(); - } - } catch (RepositoryException re) { - throw new SlcException( - "unexpected error while copying dropped node", re); - - } - return true; - } - } - - class MyResultsObserver extends AsyncUiEventListener { - - public MyResultsObserver(Display display) { - super(display); - } - - @Override - protected Boolean willProcessInUiThread(List events) - throws RepositoryException { - // unfiltered for the time being - return true; - } - - protected void onEventInUiThread(List events) - throws RepositoryException { - List nodesToRefresh = new ArrayList(); - - for (Event event : events) { - String parPath = JcrUtils.parentPath(event.getPath()); - if (session.nodeExists(parPath)) { - Node node = session.getNode(parPath); - if (!nodesToRefresh.contains(node)) { - nodesToRefresh.add(node); - } - } - } - - // Update check nodes - for (Node node : nodesToRefresh) - jcrRefresh(node); - refresh(null); - } - } - - class AllResultsObserver extends AsyncUiEventListener { - - public AllResultsObserver(Display display) { - super(display); - } - - @Override - protected Boolean willProcessInUiThread(List events) - throws RepositoryException { - // unfiltered for the time being - return true; - } - - protected void onEventInUiThread(List events) - throws RepositoryException { - refresh(null); - // if (lastSelectedSourceElementParent != null) - // refresh(lastSelectedSourceElementParent); - } - } - - class PropertiesContentProvider implements IStructuredContentProvider { - - public void dispose() { - } - - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - } - - public Object[] getElements(Object inputElement) { - try { - if (inputElement instanceof Node) { - Node node = (Node) inputElement; - if (node.isNodeType(SlcTypes.SLC_TEST_RESULT)) { - List props = new ArrayList(); - if (node.hasProperty(SlcNames.SLC_TEST_CASE)) - props.add(node.getProperty(SlcNames.SLC_TEST_CASE)); - if (node.hasProperty(SlcNames.SLC_COMPLETED)) - props.add(node.getProperty(SlcNames.SLC_COMPLETED)); - if (node.hasNode(SlcNames.SLC_AGGREGATED_STATUS)) { - Node status = node - .getNode(SlcNames.SLC_AGGREGATED_STATUS); - props.add(status.getProperty(SlcNames.SLC_SUCCESS)); - if (status.hasProperty(SlcNames.SLC_MESSAGE)) - props.add(status - .getProperty(SlcNames.SLC_MESSAGE)); - if (status.hasProperty(SlcNames.SLC_ERROR_MESSAGE)) - props.add(status - .getProperty(SlcNames.SLC_ERROR_MESSAGE)); - } - return props.toArray(); - } - } - return new Object[] {}; - - } catch (RepositoryException e) { - throw new SlcException("Cannot get element for " - + inputElement, e); - } - } - } - - class MySelectionChangedListener implements ISelectionChangedListener { - - public void selectionChanged(SelectionChangedEvent event) { - if (!event.getSelection().isEmpty()) { - IStructuredSelection sel = (IStructuredSelection) event - .getSelection(); - ResultParent firstItem = (ResultParent) sel.getFirstElement(); - if (firstItem instanceof SingleResultNode) - propertiesViewer.setInput(((SingleResultNode) firstItem) - .getNode()); - else - propertiesViewer.setInput(null); - // update cache for Drag & drop - // lastSelectedTargetElement = firstItem; - // lastSelectedSourceElement = firstItem; - // lastSelectedSourceElementParent = (ResultParent) firstItem - // .getParent(); - // String pPath = ""; - // try { - // - // if (firstItem instanceof ParentNodeFolder) - // pPath = ((ParentNodeFolder) firstItem).getNode() - // .getPath(); - // else if (firstItem instanceof SingleResultNode) - // pPath = ((SingleResultNode) firstItem).getNode() - // .getPath(); - // } catch (RepositoryException e) { - // throw new SlcException( - // "Unexpected error while checking parent UI tree", e); - // } - // if ((pPath.startsWith(SlcJcrResultUtils - // .getMyResultsBasePath(session)))) - // isActionUnderMyResult = true; - // else - // isActionUnderMyResult = false; - } - } - } - - class ViewDoubleClickListener implements IDoubleClickListener { - public void doubleClick(DoubleClickEvent evt) { - processDoubleClick(evt); - } - - } - - /* DEPENDENCY INJECTION */ - public void dispose() { - // JcrUtils.unregisterQuietly(session.getWorkspace(), resultsObserver); - JcrUtils.logoutQuietly(session); - super.dispose(); - } - - public void setRepository(Repository repository) { - this.repository = repository; - } -} \ No newline at end of file +package org.argeo.slc.client.ui.views; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Iterator; +import java.util.List; + +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.Property; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.jcr.nodetype.NodeType; +import javax.jcr.observation.Event; +import javax.jcr.observation.EventListener; +import javax.jcr.observation.ObservationManager; + +import org.argeo.api.NodeConstants; +import org.argeo.cms.ui.workbench.util.CommandUtils; +import org.argeo.eclipse.ui.jcr.AsyncUiEventListener; +import org.argeo.jcr.JcrUtils; +import org.argeo.slc.SlcException; +import org.argeo.slc.SlcNames; +import org.argeo.slc.SlcTypes; +import org.argeo.slc.client.ui.ClientUiPlugin; +import org.argeo.slc.client.ui.SlcUiConstants; +import org.argeo.slc.client.ui.commands.AddResultFolder; +import org.argeo.slc.client.ui.commands.DeleteItems; +import org.argeo.slc.client.ui.commands.RefreshJcrResultTreeView; +import org.argeo.slc.client.ui.commands.RenameResultFolder; +import org.argeo.slc.client.ui.commands.RenameResultNode; +import org.argeo.slc.client.ui.editors.ProcessEditor; +import org.argeo.slc.client.ui.editors.ProcessEditorInput; +import org.argeo.slc.client.ui.model.ParentNodeFolder; +import org.argeo.slc.client.ui.model.ResultFolder; +import org.argeo.slc.client.ui.model.ResultItemsComparator; +import org.argeo.slc.client.ui.model.ResultItemsComparer; +import org.argeo.slc.client.ui.model.ResultParent; +import org.argeo.slc.client.ui.model.ResultParentUtils; +import org.argeo.slc.client.ui.model.SingleResultNode; +import org.argeo.slc.client.ui.model.VirtualFolder; +import org.argeo.slc.client.ui.providers.ResultTreeContentProvider; +import org.argeo.slc.client.ui.providers.ResultTreeLabelProvider; +import org.argeo.slc.jcr.SlcJcrResultUtils; +import org.eclipse.jface.action.IMenuListener; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.viewers.ColumnLabelProvider; +import org.eclipse.jface.viewers.DecoratingLabelProvider; +import org.eclipse.jface.viewers.DoubleClickEvent; +import org.eclipse.jface.viewers.IDoubleClickListener; +import org.eclipse.jface.viewers.ILabelDecorator; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.TableViewerColumn; +import org.eclipse.jface.viewers.TreePath; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerDropAdapter; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.SashForm; +import org.eclipse.swt.dnd.DND; +import org.eclipse.swt.dnd.DragSourceEvent; +import org.eclipse.swt.dnd.DragSourceListener; +import org.eclipse.swt.dnd.TextTransfer; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.dnd.TransferData; +import org.eclipse.swt.layout.FillLayout; +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.ui.ISharedImages; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.part.ViewPart; + +/** SLC generic JCR Result tree view. */ +public class JcrResultTreeView extends ViewPart { + public final static String ID = ClientUiPlugin.ID + ".jcrResultTreeView"; + + private final static DateFormat dateFormat = new SimpleDateFormat( + SlcUiConstants.DEFAULT_DISPLAY_DATE_TIME_FORMAT); + + // private final static Log log = + // LogFactory.getLog(JcrResultTreeView.class); + + /* DEPENDENCY INJECTION */ + private Repository repository; + private Session session; + + // This page widgets + private TreeViewer resultTreeViewer; + private TableViewer propertiesViewer; + + private EventListener myResultsObserver = null; + private EventListener allResultsObserver = null; + + // under My Results + private final static String[] observedNodeTypesUnderMyResult = { + SlcTypes.SLC_TEST_RESULT, SlcTypes.SLC_RESULT_FOLDER, + SlcTypes.SLC_MY_RESULT_ROOT_FOLDER }; + + private final static String[] observedNodeTypesUnderAllResults = { + SlcTypes.SLC_TEST_RESULT, NodeType.NT_UNSTRUCTURED }; + + private boolean isResultFolder = false; + + /** + * To be overridden to adapt size of form and result frames. + */ + protected int[] getWeights() { + return new int[] { 70, 30 }; + } + + @Override + public void createPartControl(Composite parent) { + try { + session = repository.login(NodeConstants.HOME_WORKSPACE); + } catch (RepositoryException e1) { + throw new SlcException("Cannot log in to repository"); + } + + parent.setLayout(new FillLayout()); + // Main layout + SashForm sashForm = new SashForm(parent, SWT.VERTICAL); + sashForm.setSashWidth(4); + sashForm.setLayout(new FillLayout()); + + // Create the tree on top of the view + Composite top = new Composite(sashForm, SWT.NONE); + GridLayout gl = new GridLayout(1, false); + top.setLayout(gl); + resultTreeViewer = createResultsTreeViewer(top); + + // Create the property viewer on the bottom + Composite bottom = new Composite(sashForm, SWT.NONE); + bottom.setLayout(new GridLayout(1, false)); + propertiesViewer = createPropertiesViewer(bottom); + + sashForm.setWeights(getWeights()); + + setOrderedInput(resultTreeViewer); + + // Initialize observer + try { + ObservationManager observationManager = session.getWorkspace() + .getObservationManager(); + myResultsObserver = new MyResultsObserver(resultTreeViewer + .getTree().getDisplay()); + allResultsObserver = new AllResultsObserver(resultTreeViewer + .getTree().getDisplay()); + + // observe tree changes under MyResults + observationManager.addEventListener(myResultsObserver, + Event.NODE_ADDED | Event.NODE_REMOVED, + SlcJcrResultUtils.getMyResultsBasePath(session), true, + null, observedNodeTypesUnderMyResult, false); + // observe tree changes under All results + observationManager.addEventListener(allResultsObserver, + Event.NODE_ADDED | Event.NODE_REMOVED, + SlcJcrResultUtils.getSlcResultsBasePath(session), true, + null, observedNodeTypesUnderAllResults, false); + } catch (RepositoryException e) { + throw new SlcException("Cannot register listeners", e); + } + } + + /** + * Override default behaviour so that default defined order remains + * unchanged on first level of the tree + */ + private void setOrderedInput(TreeViewer viewer) { + // Add specific ordering + viewer.setInput(null); + viewer.setComparator(null); + viewer.setInput(initializeResultTree()); + viewer.setComparator(new ResultItemsComparator()); + } + + // The main tree viewer + protected TreeViewer createResultsTreeViewer(Composite parent) { + int style = SWT.BORDER | SWT.MULTI; + + TreeViewer viewer = new TreeViewer(parent, style); + viewer.getTree().setLayoutData( + new GridData(SWT.FILL, SWT.FILL, true, true)); + + viewer.setContentProvider(new ResultTreeContentProvider()); + + // Add label provider with label decorator + ResultTreeLabelProvider rtLblProvider = new ResultTreeLabelProvider(); + ILabelDecorator decorator = ClientUiPlugin.getDefault().getWorkbench() + .getDecoratorManager().getLabelDecorator(); + viewer.setLabelProvider(new DecoratingLabelProvider(rtLblProvider, + decorator)); + viewer.addDoubleClickListener(new ViewDoubleClickListener()); + + // Override default behaviour to insure that 2 distincts results that + // have the same name will be correctly and distincly returned by + // corresponding TreeViewer.getSelection() method. + viewer.setComparer(new ResultItemsComparer()); + + // viewer.setLabelProvider(rtLblProvider); + getSite().setSelectionProvider(viewer); + + // add drag & drop support + int operations = DND.DROP_COPY | DND.DROP_MOVE; + Transfer[] tt = new Transfer[] { TextTransfer.getInstance() }; + viewer.addDragSupport(operations, tt, new ViewDragListener()); + viewer.addDropSupport(operations, tt, new ViewDropListener(viewer)); + + // add context menu + MenuManager menuManager = new MenuManager(); + Menu menu = menuManager.createContextMenu(viewer.getTree()); + menuManager.addMenuListener(new IMenuListener() { + public void menuAboutToShow(IMenuManager manager) { + contextMenuAboutToShow(manager); + } + }); + viewer.getTree().setMenu(menu); + menuManager.setRemoveAllWhenShown(true); + + getSite().registerContextMenu(menuManager, viewer); + + // add change listener to display TestResult information in the property + // viewer + viewer.addSelectionChangedListener(new MySelectionChangedListener()); + return viewer; + } + + // Detailed property viewer + protected TableViewer createPropertiesViewer(Composite parent) { + propertiesViewer = new TableViewer(parent); + propertiesViewer.getTable().setLayoutData( + new GridData(SWT.FILL, SWT.FILL, true, true)); + propertiesViewer.getTable().setHeaderVisible(true); + propertiesViewer.setContentProvider(new PropertiesContentProvider()); + TableViewerColumn col = new TableViewerColumn(propertiesViewer, + SWT.NONE); + col.getColumn().setText("Name"); + col.getColumn().setWidth(100); + col.setLabelProvider(new ColumnLabelProvider() { + public String getText(Object element) { + try { + String name = ((Property) element).getName(); + String value = null; + if (SlcNames.SLC_TEST_CASE.equals(name)) + value = "Test case"; + else if (SlcNames.SLC_COMPLETED.equals(name)) + value = "Completed on"; + else if (SlcNames.SLC_SUCCESS.equals(name)) + value = "Status"; + else if (SlcNames.SLC_MESSAGE.equals(name)) + value = "Message"; + else if (SlcNames.SLC_ERROR_MESSAGE.equals(name)) + value = "Error"; + return value; + } catch (RepositoryException e) { + throw new SlcException( + "Unexpected exception in label provider", e); + } + } + }); + col = new TableViewerColumn(propertiesViewer, SWT.NONE); + col.getColumn().setText("Value"); + col.getColumn().setWidth(200); + col.setLabelProvider(new ColumnLabelProvider() { + public String getText(Object element) { + try { + Property property = (Property) element; + String name = property.getName(); + String value = null; + + if (SlcNames.SLC_TEST_CASE.equals(name) + || SlcNames.SLC_ERROR_MESSAGE.equals(name) + || SlcNames.SLC_MESSAGE.equals(name)) + value = property.getValue().getString(); + else if (SlcNames.SLC_COMPLETED.equals(name)) { + Calendar date = property.getValue().getDate(); + value = dateFormat.format(date.getTime()); + } else if (SlcNames.SLC_SUCCESS.equals(name)) { + if (property.getValue().getBoolean()) + value = "PASSED"; + else { + if (property.getParent().hasProperty( + SlcNames.SLC_ERROR_MESSAGE)) + value = "ERROR"; + else + value = "FAILED"; + } + } + return value; + } catch (RepositoryException e) { + throw new SlcException( + "Unexpected exception in label provider", e); + } + } + }); + propertiesViewer.setInput(getViewSite()); + return propertiesViewer; + } + + /** + * Override to provide specific behaviour. Typically to enable the display + * of a result file. + * + * @param evt + */ + protected void processDoubleClick(DoubleClickEvent evt) { + Object obj = ((IStructuredSelection) evt.getSelection()) + .getFirstElement(); + try { + if (obj instanceof SingleResultNode) { + SingleResultNode srNode = (SingleResultNode) obj; + Node node = srNode.getNode(); + // FIXME: open a default result editor + if (node.isNodeType(SlcTypes.SLC_PROCESS)) { + IWorkbenchPage activePage = PlatformUI.getWorkbench() + .getActiveWorkbenchWindow().getActivePage(); + activePage.openEditor( + new ProcessEditorInput(node.getPath()), + ProcessEditor.ID); + } + } + } catch (Exception e) { + throw new SlcException("Cannot open " + obj, e); + } + } + + @Override + public void setFocus() { + } + + /** + * refreshes the passed resultParent and its corresponding subtree. It + * refreshes the whole viewer if null is passed. + * + * @param ResultParent + * + */ + public void refresh(ResultParent resultParent) { + if (resultParent == null) { + if (!resultTreeViewer.getTree().isDisposed()) { + TreePath[] tps = resultTreeViewer.getExpandedTreePaths(); + setOrderedInput(resultTreeViewer); + resultTreeViewer.setExpandedTreePaths(tps); + } else + setOrderedInput(resultTreeViewer); + } else { + if (resultParent instanceof ParentNodeFolder) { + ParentNodeFolder currFolder = (ParentNodeFolder) resultParent; + jcrRefresh(currFolder.getNode()); + currFolder.forceFullRefresh(); + } + // FIXME: specific refresh does not work + // resultTreeViewer.refresh(resultParent, true); + refresh(null); + } + } + + /** + * refreshes the passed node and its corresponding subtree. + * + * @param node + * cannot be null + * + */ + public boolean jcrRefresh(Node node) { + // if (log.isDebugEnabled()) + // log.debug(" JCR refreshing " + node + "..."); + // Thread.dumpStack(); + boolean isPassed = true; + try { + if (node.isNodeType(SlcTypes.SLC_TEST_RESULT)) { + isPassed = node.getNode(SlcNames.SLC_AGGREGATED_STATUS) + .getProperty(SlcNames.SLC_SUCCESS).getBoolean(); + } else if (node.isNodeType(SlcTypes.SLC_RESULT_FOLDER)) { + NodeIterator ni = node.getNodes(); + while (ni.hasNext()) { + Node currChild = ni.nextNode(); + isPassed = isPassed & jcrRefresh(currChild); + } + if (isPassed != node.getNode(SlcNames.SLC_AGGREGATED_STATUS) + .getProperty(SlcNames.SLC_SUCCESS).getBoolean()) { + node.getNode(SlcNames.SLC_AGGREGATED_STATUS).setProperty( + SlcNames.SLC_SUCCESS, isPassed); + node.getSession().save(); + return isPassed; + } + } else + ; // do nothing + } catch (RepositoryException e) { + throw new SlcException("Cannot register listeners", e); + } + return isPassed; + } + + private ResultParent[] initializeResultTree() { + try { + // Force initialization of the tree structure if needed + SlcJcrResultUtils.getSlcResultsParentNode(session); + SlcJcrResultUtils.getMyResultParentNode(session); + // Remove yesterday and last 7 days virtual folders + // ResultParent[] roots = new ResultParent[5]; + ResultParent[] roots = new ResultParent[3]; + + // My results + roots[0] = new ParentNodeFolder(null, + SlcJcrResultUtils.getMyResultParentNode(session), + SlcUiConstants.DEFAULT_MY_RESULTS_FOLDER_LABEL); + + // today + Calendar cal = Calendar.getInstance(); + String relPath = JcrUtils.dateAsPath(cal); + List datePathes = new ArrayList(); + datePathes.add(relPath); + roots[1] = new VirtualFolder(null, + ResultParentUtils.getResultsForDates(session, datePathes), + "Today"); + + // // Yesterday + // cal = Calendar.getInstance(); + // cal.add(Calendar.DAY_OF_YEAR, -1); + // relPath = JcrUtils.dateAsPath(cal); + // datePathes = new ArrayList(); + // datePathes.add(relPath); + // roots[2] = new VirtualFolder(null, + // ResultParentUtils.getResultsForDates(session, datePathes), + // "Yesterday"); + // // Last 7 days + // + // cal = Calendar.getInstance(); + // datePathes = new ArrayList(); + // + // for (int i = 0; i < 7; i++) { + // cal.add(Calendar.DAY_OF_YEAR, -i); + // relPath = JcrUtils.dateAsPath(cal); + // datePathes.add(relPath); + // } + // roots[3] = new VirtualFolder(null, + // ResultParentUtils.getResultsForDates(session, datePathes), + // "Last 7 days"); + + // All results + Node otherResultsPar = session.getNode(SlcJcrResultUtils + .getSlcResultsBasePath(session)); + // roots[4] = new ParentNodeFolder(null, otherResultsPar, + // "All results"); + roots[2] = new ParentNodeFolder(null, otherResultsPar, + "All results"); + return roots; + } catch (RepositoryException re) { + throw new SlcException( + "Unexpected error while initializing ResultTree.", re); + } + } + + // Manage context menu + /** + * Defines the commands that will pop up in the context menu. + **/ + protected void contextMenuAboutToShow(IMenuManager menuManager) { + IWorkbenchWindow window = ClientUiPlugin.getDefault().getWorkbench() + .getActiveWorkbenchWindow(); + + IStructuredSelection selection = (IStructuredSelection) resultTreeViewer + .getSelection(); + boolean canAddSubfolder = false; + boolean canRenamefolder = false; + boolean isSingleResultNode = false; + boolean isUnderMyResult = false; + boolean validMultipleDelete = false; + try { + + // Building conditions + if (selection.size() == 1) { + Object obj = selection.getFirstElement(); + if (obj instanceof SingleResultNode) + isSingleResultNode = true; + else if (obj instanceof ParentNodeFolder) { + Node cNode = ((ParentNodeFolder) obj).getNode(); + if (cNode.isNodeType(SlcTypes.SLC_RESULT_FOLDER)) { + canAddSubfolder = true; + canRenamefolder = true; + isUnderMyResult = true; + } else if (cNode + .isNodeType(SlcTypes.SLC_MY_RESULT_ROOT_FOLDER)) { + canAddSubfolder = true; + } + } + } else { + @SuppressWarnings("rawtypes") + Iterator it = selection.iterator(); + multicheck: while (it.hasNext()) { + validMultipleDelete = true; + Object obj = it.next(); + if (obj instanceof SingleResultNode) + continue multicheck; + else if (obj instanceof ParentNodeFolder) { + Node cNode = ((ParentNodeFolder) obj).getNode(); + if (cNode.isNodeType(SlcTypes.SLC_RESULT_FOLDER)) + continue multicheck; + else { + validMultipleDelete = false; + break multicheck; + } + } else { + validMultipleDelete = false; + break multicheck; + } + } + } + } catch (RepositoryException re) { + throw new SlcException( + "unexpected error while building condition for context menu", + re); + } + + // Effective Refresh + CommandUtils.refreshCommand(menuManager, window, + RefreshJcrResultTreeView.ID, + RefreshJcrResultTreeView.DEFAULT_LABEL, + RefreshJcrResultTreeView.DEFAULT_IMG_DESCRIPTOR, true); + + CommandUtils.refreshCommand(menuManager, window, DeleteItems.ID, + DeleteItems.DEFAULT_LABEL, DeleteItems.DEFAULT_IMG_DESCRIPTOR, + isUnderMyResult || isSingleResultNode || validMultipleDelete); + + CommandUtils.refreshCommand(menuManager, window, AddResultFolder.ID, + AddResultFolder.DEFAULT_LABEL, + ClientUiPlugin.getDefault().getWorkbench().getSharedImages() + .getImageDescriptor(ISharedImages.IMG_OBJ_ADD), + canAddSubfolder); + + CommandUtils.refreshCommand(menuManager, window, RenameResultFolder.ID, + RenameResultFolder.DEFAULT_LABEL, + RenameResultFolder.DEFAULT_IMG_DESCRIPTOR, canRenamefolder); + + // Command removed for the time being. + CommandUtils.refreshCommand(menuManager, window, RenameResultNode.ID, + RenameResultNode.DEFAULT_LABEL, + RenameResultNode.DEFAULT_IMG_DESCRIPTOR, false); + + // Test to be removed + // If you use this pattern, do not forget to call + // menuManager.setRemoveAllWhenShown(true); + // when creating the menuManager + + // menuManager.add(new Action("Test") { + // public void run() { + // log.debug("do something"); + // } + // }); + } + + /* INNER CLASSES */ + class ViewDragListener implements DragSourceListener { + + public void dragStart(DragSourceEvent event) { + // Check if the drag action should start. + IStructuredSelection selection = (IStructuredSelection) resultTreeViewer + .getSelection(); + boolean doIt = false; + + // FIXME clean this code. + try { + if (selection.size() == 1) { + Object obj = selection.getFirstElement(); + if (obj instanceof ResultFolder) { + Node tNode = ((ResultFolder) obj).getNode(); + if (tNode.getPrimaryNodeType().isNodeType( + SlcTypes.SLC_RESULT_FOLDER)) { + doIt = true; + isResultFolder = true; + } + } else + isResultFolder = false; + } else + isResultFolder = false; + + if (!isResultFolder) { + @SuppressWarnings("rawtypes") + Iterator it = selection.iterator(); + while (it.hasNext()) { + Object obj = it.next(); + if (obj instanceof SingleResultNode) { + Node tNode = ((SingleResultNode) obj).getNode(); + if (tNode.getPrimaryNodeType().isNodeType( + SlcTypes.SLC_TEST_RESULT)) { + doIt = true; + } + } + } + } + + } catch (RepositoryException re) { + throw new SlcException( + "unexpected error while validating drag source", re); + } + event.doit = doIt; + } + + public void dragSetData(DragSourceEvent event) { + IStructuredSelection selection = (IStructuredSelection) resultTreeViewer + .getSelection(); + + try { + // specific case of a result folder + if (isResultFolder) { + Object obj = selection.getFirstElement(); + event.data = ((ResultFolder) obj).getNode().getIdentifier(); + } else { + @SuppressWarnings("rawtypes") + Iterator it = selection.iterator(); + StringBuilder nodes = new StringBuilder(); + while (it.hasNext()) { + Object obj = it.next(); + if (obj instanceof SingleResultNode) { + Node tNode = ((SingleResultNode) obj).getNode(); + if (tNode.getPrimaryNodeType().isNodeType( + SlcTypes.SLC_TEST_RESULT)) { + nodes.append(tNode.getIdentifier()).append(";"); + } + } + } + event.data = nodes.toString(); + } + } catch (RepositoryException re) { + throw new SlcException("unexpected error while setting data", + re); + } + } + + public void dragFinished(DragSourceEvent event) { + // refresh is done via observer + } + } + + // Implementation of the Drop Listener + protected class ViewDropListener extends ViewerDropAdapter { + private Node targetParentNode = null; + + public ViewDropListener(Viewer viewer) { + super(viewer); + } + + @Override + public boolean validateDrop(Object target, int operation, + TransferData transferType) { + boolean validDrop = false; + try { + // We can only drop under myResults + Node tpNode = null; + if (target instanceof SingleResultNode) { + Node currNode = ((SingleResultNode) target).getNode(); + String pPath = currNode.getParent().getPath(); + if (pPath.startsWith(SlcJcrResultUtils + .getMyResultsBasePath(session))) + tpNode = currNode.getParent(); + } else if (target instanceof ResultFolder) { + tpNode = ((ResultFolder) target).getNode(); + } else if (target instanceof ParentNodeFolder) { + Node node = ((ParentNodeFolder) target).getNode(); + if (node.isNodeType(SlcTypes.SLC_MY_RESULT_ROOT_FOLDER)) + tpNode = ((ParentNodeFolder) target).getNode(); + } + + if (tpNode != null) { + targetParentNode = tpNode; + validDrop = true; + } + } catch (RepositoryException re) { + throw new SlcException( + "unexpected error while validating drop target", re); + } + return validDrop; + } + + @Override + public boolean performDrop(Object data) { + // clear selection to prevent unwanted scrolling of the UI + resultTreeViewer.setSelection(null); + try { + if (isResultFolder) { + // Sanity check : we cannot move a folder to one of its sub + // folder or neither move an object in the same parent + // folder + Node source = session.getNodeByIdentifier((String) data); + if (targetParentNode.getPath().startsWith(source.getPath()) + || source.getParent().getPath() + .equals(targetParentNode.getPath())) + return false; + + // Move + String sourcePath = source.getPath(); + String destPath = targetParentNode.getPath() + "/" + + source.getName(); + session.move(sourcePath, destPath); + // Update passed status of the parent source Node + ResultParentUtils.updatePassedStatus( + session.getNode(JcrUtils.parentPath(sourcePath)), + true); + // Node target = session.getNode(destPath); + session.save(); + return true; + } + + String[] datas = ((String) data).split(";"); + nodesToCopy: for (String id : datas) { + + Node source = session.getNodeByIdentifier(id); + String name; + if (source.hasProperty(Property.JCR_TITLE)) + name = source.getProperty(Property.JCR_TITLE) + .getString(); + else if (source.hasProperty(SlcNames.SLC_TEST_CASE)) + name = source.getProperty(SlcNames.SLC_TEST_CASE) + .getString(); + else + name = source.getName(); + + // Check if another copy of the same test instance already + // exists at target + NodeIterator ni = targetParentNode.getNodes(); + String slcUid = source.getProperty(SlcNames.SLC_UUID) + .getString(); + while (ni.hasNext()) { + Node curr = ni.nextNode(); + if (curr.hasProperty(SlcNames.SLC_UUID) + && slcUid.equals(curr.getProperty( + SlcNames.SLC_UUID).getString())) { + MessageDialog + .openWarning( + PlatformUI.getWorkbench() + .getDisplay() + .getActiveShell(), + "Duplicated instance.", + "An instance of the same test case (" + + name + + ") exists at destination.\n " + + "This item will not be neither copied nor moved."); + continue nodesToCopy; + + } + } + + Node target; + boolean passedStatus = false; + if (source.hasNode(SlcNames.SLC_AGGREGATED_STATUS)) + passedStatus = source + .getNode(SlcNames.SLC_AGGREGATED_STATUS) + .getProperty(SlcNames.SLC_SUCCESS).getBoolean(); + + boolean isActionUnderMyResult = source.getPath() + .startsWith( + SlcJcrResultUtils + .getMyResultsBasePath(session)); + + if (!isActionUnderMyResult) {// Copy + target = targetParentNode.addNode(source.getName(), + source.getPrimaryNodeType().getName()); + JcrUtils.copy(source, target); + } else {// move + String sourcePath = source.getPath(); + String destPath = targetParentNode.getPath() + "/" + + name; + session.move(sourcePath, destPath); + // Update passed status of the parent source Node + ResultParentUtils + .updatePassedStatus(session.getNode(JcrUtils + .parentPath(sourcePath)), true); + target = session.getNode(destPath); + + } + if (!target.isNodeType(NodeType.MIX_TITLE)) + target.addMixin(NodeType.MIX_TITLE); + target.setProperty(Property.JCR_TITLE, name); + ResultParentUtils.updatePassedStatus(target.getParent(), + passedStatus); + session.save(); + } + } catch (RepositoryException re) { + throw new SlcException( + "unexpected error while copying dropped node", re); + + } + return true; + } + } + + class MyResultsObserver extends AsyncUiEventListener { + + public MyResultsObserver(Display display) { + super(display); + } + + @Override + protected Boolean willProcessInUiThread(List events) + throws RepositoryException { + // unfiltered for the time being + return true; + } + + protected void onEventInUiThread(List events) + throws RepositoryException { + List nodesToRefresh = new ArrayList(); + + for (Event event : events) { + String parPath = JcrUtils.parentPath(event.getPath()); + if (session.nodeExists(parPath)) { + Node node = session.getNode(parPath); + if (!nodesToRefresh.contains(node)) { + nodesToRefresh.add(node); + } + } + } + + // Update check nodes + for (Node node : nodesToRefresh) + jcrRefresh(node); + refresh(null); + } + } + + class AllResultsObserver extends AsyncUiEventListener { + + public AllResultsObserver(Display display) { + super(display); + } + + @Override + protected Boolean willProcessInUiThread(List events) + throws RepositoryException { + // unfiltered for the time being + return true; + } + + protected void onEventInUiThread(List events) + throws RepositoryException { + refresh(null); + // if (lastSelectedSourceElementParent != null) + // refresh(lastSelectedSourceElementParent); + } + } + + class PropertiesContentProvider implements IStructuredContentProvider { + + public void dispose() { + } + + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + } + + public Object[] getElements(Object inputElement) { + try { + if (inputElement instanceof Node) { + Node node = (Node) inputElement; + if (node.isNodeType(SlcTypes.SLC_TEST_RESULT)) { + List props = new ArrayList(); + if (node.hasProperty(SlcNames.SLC_TEST_CASE)) + props.add(node.getProperty(SlcNames.SLC_TEST_CASE)); + if (node.hasProperty(SlcNames.SLC_COMPLETED)) + props.add(node.getProperty(SlcNames.SLC_COMPLETED)); + if (node.hasNode(SlcNames.SLC_AGGREGATED_STATUS)) { + Node status = node + .getNode(SlcNames.SLC_AGGREGATED_STATUS); + props.add(status.getProperty(SlcNames.SLC_SUCCESS)); + if (status.hasProperty(SlcNames.SLC_MESSAGE)) + props.add(status + .getProperty(SlcNames.SLC_MESSAGE)); + if (status.hasProperty(SlcNames.SLC_ERROR_MESSAGE)) + props.add(status + .getProperty(SlcNames.SLC_ERROR_MESSAGE)); + } + return props.toArray(); + } + } + return new Object[] {}; + + } catch (RepositoryException e) { + throw new SlcException("Cannot get element for " + + inputElement, e); + } + } + } + + class MySelectionChangedListener implements ISelectionChangedListener { + + public void selectionChanged(SelectionChangedEvent event) { + if (!event.getSelection().isEmpty()) { + IStructuredSelection sel = (IStructuredSelection) event + .getSelection(); + ResultParent firstItem = (ResultParent) sel.getFirstElement(); + if (firstItem instanceof SingleResultNode) + propertiesViewer.setInput(((SingleResultNode) firstItem) + .getNode()); + else + propertiesViewer.setInput(null); + // update cache for Drag & drop + // lastSelectedTargetElement = firstItem; + // lastSelectedSourceElement = firstItem; + // lastSelectedSourceElementParent = (ResultParent) firstItem + // .getParent(); + // String pPath = ""; + // try { + // + // if (firstItem instanceof ParentNodeFolder) + // pPath = ((ParentNodeFolder) firstItem).getNode() + // .getPath(); + // else if (firstItem instanceof SingleResultNode) + // pPath = ((SingleResultNode) firstItem).getNode() + // .getPath(); + // } catch (RepositoryException e) { + // throw new SlcException( + // "Unexpected error while checking parent UI tree", e); + // } + // if ((pPath.startsWith(SlcJcrResultUtils + // .getMyResultsBasePath(session)))) + // isActionUnderMyResult = true; + // else + // isActionUnderMyResult = false; + } + } + } + + class ViewDoubleClickListener implements IDoubleClickListener { + public void doubleClick(DoubleClickEvent evt) { + processDoubleClick(evt); + } + + } + + /* DEPENDENCY INJECTION */ + public void dispose() { + // JcrUtils.unregisterQuietly(session.getWorkspace(), resultsObserver); + JcrUtils.logoutQuietly(session); + super.dispose(); + } + + public void setRepository(Repository repository) { + this.repository = repository; + } +}