From d50c0fe50cd69947bc7146991afa0826a8c8f53b Mon Sep 17 00:00:00 2001 From: Bruno Sinou Date: Fri, 24 Aug 2012 16:09:41 +0000 Subject: [PATCH] introduce a new view to display JcrResults has a tree. git-svn-id: https://svn.argeo.org/slc/trunk@5541 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- .../client/ui/commands/AddResultFolder.java | 37 ++- .../slc/client/ui/commands/DeleteResult.java | 4 + .../ui/decorators/ResultFailedDecorator.java | 8 +- ...eNodeFolder.java => ParentNodeFolder.java} | 36 ++- .../slc/client/ui/model/ResultFolder.java | 67 ++--- .../client/ui/model/ResultParentUtils.java | 202 ++++++++++++++ .../slc/client/ui/model/SingleResultNode.java | 7 +- .../slc/client/ui/model/VirtualFolder.java | 73 +---- .../client/ui/views/JcrResultTreeView.java | 264 ++++++++++-------- .../org/argeo/slc/jcr/SlcJcrConstants.java | 2 +- .../org/argeo/slc/jcr/SlcJcrResultUtils.java | 32 ++- 11 files changed, 474 insertions(+), 258 deletions(-) rename plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/{SimpleNodeFolder.java => ParentNodeFolder.java} (65%) create mode 100644 plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/ResultParentUtils.java diff --git a/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/commands/AddResultFolder.java b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/commands/AddResultFolder.java index e1b357482..dc61fc477 100644 --- a/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/commands/AddResultFolder.java +++ b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/commands/AddResultFolder.java @@ -23,6 +23,7 @@ import org.argeo.eclipse.ui.ErrorFeedback; import org.argeo.eclipse.ui.dialogs.SingleValue; import org.argeo.slc.SlcException; import org.argeo.slc.client.ui.ClientUiPlugin; +import org.argeo.slc.client.ui.model.ParentNodeFolder; import org.argeo.slc.client.ui.model.ResultFolder; import org.argeo.slc.jcr.SlcJcrResultUtils; import org.eclipse.core.commands.AbstractHandler; @@ -48,18 +49,32 @@ public class AddResultFolder extends AbstractHandler { // Sanity check, already done when populating the corresponding popup // menu. - if (selection != null && selection.size() == 1 - && selection.getFirstElement() instanceof ResultFolder) { - ResultFolder rf = (ResultFolder) selection.getFirstElement(); + if (selection != null && selection.size() == 1) { + Object obj = selection.getFirstElement(); + try { - String folderName = SingleValue.ask("Folder name", - "Enter folder name"); - if (folderName != null) { - Node parentNode = rf.getNode(); - String absPath = parentNode.getPath()+ "/" - + folderName; - SlcJcrResultUtils.createResultFolderNode( - parentNode.getSession(), absPath); + Node parentNode = null; + + if (obj instanceof ResultFolder) { + ResultFolder rf = (ResultFolder) obj; + parentNode = rf.getNode(); + } else if (obj instanceof ParentNodeFolder) { + Node node = ((ParentNodeFolder) obj).getNode(); + if (node.getPath().startsWith( + SlcJcrResultUtils.getMyResultsBasePath(node + .getSession()))) + parentNode = node; + } + + if (parentNode != null) { + String folderName = SingleValue.ask("Folder name", + "Enter folder name"); + if (folderName != null) { + String absPath = parentNode.getPath() + "/" + + folderName; + SlcJcrResultUtils.createResultFolderNode( + parentNode.getSession(), absPath); + } } } catch (RepositoryException e) { throw new SlcException( diff --git a/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/commands/DeleteResult.java b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/commands/DeleteResult.java index 321a6b552..94cdd3e94 100644 --- a/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/commands/DeleteResult.java +++ b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/commands/DeleteResult.java @@ -26,7 +26,9 @@ import javax.jcr.Session; import org.argeo.eclipse.ui.ErrorFeedback; import org.argeo.slc.client.ui.model.ResultFolder; +import org.argeo.slc.client.ui.model.ResultParentUtils; import org.argeo.slc.client.ui.model.SingleResultNode; +import org.argeo.slc.jcr.SlcNames; import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; @@ -83,7 +85,9 @@ public class DeleteResult extends AbstractHandler { for (final String path : nodes) { if (session.itemExists(path)) { node = session.getNode(path); + Node parent = node.getParent(); node.remove(); + ResultParentUtils.updateStatusOnRemoval(parent); } monitor.worked(1); } diff --git a/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/decorators/ResultFailedDecorator.java b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/decorators/ResultFailedDecorator.java index 1d021e2a3..64c759b77 100644 --- a/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/decorators/ResultFailedDecorator.java +++ b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/decorators/ResultFailedDecorator.java @@ -15,8 +15,6 @@ */ package org.argeo.slc.client.ui.decorators; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.argeo.slc.client.ui.ClientUiPlugin; import org.argeo.slc.client.ui.model.ResultParent; import org.eclipse.jface.resource.ImageDescriptor; @@ -30,8 +28,8 @@ import org.eclipse.ui.ISharedImages; public class ResultFailedDecorator extends LabelProvider implements ILabelDecorator { - private final static Log log = LogFactory - .getLog(ResultFailedDecorator.class); + // private final static Log log = LogFactory + // .getLog(ResultFailedDecorator.class); public ResultFailedDecorator() { super(); @@ -45,8 +43,6 @@ public class ResultFailedDecorator extends LabelProvider implements // decorates resource icon with basic decorations provided // by Eclipse if (object instanceof ResultParent) { - log.debug("decorate : " + ((ResultParent) object).getName() - + " - passed : " + ((ResultParent) object).isPassed()); if (!((ResultParent) object).isPassed()) { ImageDescriptor desc = ClientUiPlugin.getDefault() .getWorkbench().getSharedImages() diff --git a/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/SimpleNodeFolder.java b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/ParentNodeFolder.java similarity index 65% rename from plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/SimpleNodeFolder.java rename to plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/ParentNodeFolder.java index c08dafd80..91163c842 100644 --- a/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/SimpleNodeFolder.java +++ b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/ParentNodeFolder.java @@ -21,14 +21,16 @@ import javax.jcr.RepositoryException; import javax.jcr.nodetype.NodeType; import org.argeo.slc.SlcException; +import org.argeo.slc.jcr.SlcJcrResultUtils; import org.argeo.slc.jcr.SlcNames; import org.argeo.slc.jcr.SlcTypes; /** - * UI Tree component that wrap a node of type NT_UNSTRUCTURED. list either other - * folders and/or a list of results. keeps a reference to its parent. + * UI Tree component that wrap a node of type NT_UNSTRUCTURED. list either + * result folders, other folders and/or a list of results. keeps a reference to + * its parent. */ -public class SimpleNodeFolder extends ResultParent { +public class ParentNodeFolder extends ResultParent { private Node node = null; @@ -39,7 +41,7 @@ public class SimpleNodeFolder extends ResultParent { * throws an exception if null * @param name */ - public SimpleNodeFolder(SimpleNodeFolder parent, Node node, String name) { + public ParentNodeFolder(ParentNodeFolder parent, Node node, String name) { super(name); if (node == null) throw new SlcException("Node Object cannot be null"); @@ -58,8 +60,13 @@ public class SimpleNodeFolder extends ResultParent { currNode.getProperty(SlcNames.SLC_TEST_CASE) .getString()); addChild(srn); + } else if (currNode.isNodeType(SlcTypes.SLC_RESULT_FOLDER)) { + // FIXME change label + ResultFolder rf = new ResultFolder(this, currNode, + currNode.getName()); + addChild(rf); } else if (currNode.isNodeType(NodeType.NT_UNSTRUCTURED)) - addChild(new SimpleNodeFolder(this, currNode, + addChild(new ParentNodeFolder(this, currNode, currNode.getName())); } } catch (RepositoryException re) { @@ -77,4 +84,23 @@ public class SimpleNodeFolder extends ResultParent { public Node getNode() { return node; } + + /** + * Overriden in the specific case of "My result" root object to return an + * ordered list of children + */ + public synchronized Object[] getChildren() { + Object[] children = super.getChildren(); + try { + if (node.getPath().equals( + SlcJcrResultUtils.getMyResultsBasePath(node.getSession()))) + return ResultParentUtils.orderChildren(children); + else + return children; + } catch (RepositoryException re) { + throw new SlcException( + "Unexpected error while initializing simple node folder : " + + getName(), re); + } + } } \ No newline at end of file diff --git a/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/ResultFolder.java b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/ResultFolder.java index ac4eb9f7c..a5c43168e 100644 --- a/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/ResultFolder.java +++ b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/ResultFolder.java @@ -27,7 +27,7 @@ import org.argeo.slc.jcr.SlcTypes; * UI Tree component that wrap a node of type ResultFolder. list either other * folders and/or a list of results. keeps a reference to its parent. */ -public class ResultFolder extends ResultParent { +public class ResultFolder extends ResultParent implements Comparable { private Node node = null; @@ -38,16 +38,17 @@ public class ResultFolder extends ResultParent { * throws an exception if null * @param name */ - public ResultFolder(ResultFolder parent, Node node, String name) { + public ResultFolder(ResultParent parent, Node node, String name) { super(name); try { if (node == null) throw new SlcException("Node Object cannot be null"); setParent(parent); this.node = node; - // initialize passed status - setPassed(node.getNode(SlcNames.SLC_STATUS) - .getProperty(SlcNames.SLC_SUCCESS).getBoolean()); + // initialize passed status if possible + if (node.hasNode(SlcNames.SLC_STATUS)) + setPassed(node.getNode(SlcNames.SLC_STATUS) + .getProperty(SlcNames.SLC_SUCCESS).getBoolean()); } catch (RepositoryException re) { throw new SlcException( "Unexpected error while initializing result folder : " @@ -90,51 +91,15 @@ public class ResultFolder extends ResultParent { return node; } - // /** Override normal behavior to initialize display */ - // @Override - // public synchronized Object[] getChildren() { - // if (isLoaded()) { - // return super.getChildren(); - // } else { - // // initialize current object - // try { - // if (node != null) { - // NodeIterator ni = node.getNodes(); - // while (ni.hasNext()) { - // Node currNode = ni.nextNode(); - // if (currNode.isNodeType(SlcTypes.SLC_TEST_RESULT)) - // addChild(new SingleResultNode(this, node, node - // .getProperty(SlcNames.SLC_TEST_CASE) - // .getString())); - // else if (currNode - // .isNodeType(SlcTypes.SLC_RESULT_FOLDER)) - // addChild(new ResultFolder(this, node, - // node.getName())); - // } - // } - // return super.getChildren(); - // } catch (RepositoryException e) { - // throw new ArgeoException( - // "Cannot initialize WorkspaceNode UI object." - // + getName(), e); - // } - // } - // } - - // @Override - // public boolean refreshPassedStatus() { - // Object[] children = getChildren(); - // isPassed = true; - // checkChildrenStatus: for (int i = 0; i <= children.length; i++) { - // if (children[i] instanceof ResultFolder) { - // - // } - // if (!((ResultParent) children[i]).isPassed()) { - // isPassed = false; - // break checkChildrenStatus; - // } - // } - // return isPassed; - // } + /** + * Overriden to return an ordered list of children + */ + public synchronized Object[] getChildren() { + Object[] children = super.getChildren(); + return ResultParentUtils.orderChildren(children); + } + public int compareTo(ResultFolder o) { + return super.compareTo(o); + } } \ No newline at end of file diff --git a/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/ResultParentUtils.java b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/ResultParentUtils.java new file mode 100644 index 000000000..fc4eec77f --- /dev/null +++ b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/ResultParentUtils.java @@ -0,0 +1,202 @@ +package org.argeo.slc.client.ui.model; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.Property; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.jcr.query.Query; +import javax.jcr.query.QueryManager; +import javax.jcr.query.QueryResult; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.SlcException; +import org.argeo.slc.jcr.SlcJcrResultUtils; +import org.argeo.slc.jcr.SlcNames; +import org.argeo.slc.jcr.SlcTypes; + +public class ResultParentUtils { + private final static Log log = LogFactory.getLog(ResultParentUtils.class); + + public static Object[] orderChildren(Object[] children) { + List folders = new ArrayList(); + List results = new ArrayList(); + for (Object child : children) { + if (child instanceof ResultFolder) + folders.add((ResultFolder) child); + else if (child instanceof SingleResultNode) + results.add((SingleResultNode) child); + } + + // Comparator first = Collections.reverseOrder(); + Collections.sort(folders); + // Comparator second = Collections.reverseOrder(); + Collections.sort(results); + + Object[] orderedChildren = new Object[children.length]; + int i = 0; + Iterator it = folders.iterator(); + while (it.hasNext()) { + orderedChildren[i] = it.next(); + i++; + } + Iterator it2 = results.iterator(); + while (it2.hasNext()) { + orderedChildren[i] = it2.next(); + i++; + } + return orderedChildren; + } + + public static ResultParent[] getResultsForDates(Session session, + List dateRelPathes) { + if (dateRelPathes == null || dateRelPathes.size() == 0) + throw new SlcException("Specify at least one correct date as Path"); + + try { + String basePath = SlcJcrResultUtils.getSlcResultsBasePath(session); + Iterator it = dateRelPathes.iterator(); + StringBuffer clause = new StringBuffer(); + clause.append("SELECT * FROM ["); + clause.append(SlcTypes.SLC_DIFF_RESULT); + clause.append("] as results"); + clause.append(" WHERE "); + while (it.hasNext()) { + String absPath = basePath + "/" + it.next(); + clause.append("ISDESCENDANTNODE(results, ["); + clause.append(absPath); + clause.append("]) "); + clause.append(" OR "); + } + // remove last " OR " + clause.delete(clause.length() - 4, clause.length()); + clause.append(" ORDER BY results.[" + Property.JCR_CREATED + + "] DESC"); + + // log.debug("request : " + clause.toString()); + QueryManager qm = session.getWorkspace().getQueryManager(); + Query q = qm.createQuery(clause.toString(), Query.JCR_SQL2); + QueryResult result = q.execute(); + + NodeIterator ni = result.getNodes(); + ResultParent[] results = new ResultParent[(int) ni.getSize()]; + int i = 0; + while (ni.hasNext()) { + Node currNode = ni.nextNode(); + SingleResultNode srn = new SingleResultNode(null, currNode, + currNode.getProperty(SlcNames.SLC_TEST_CASE) + .getString()); + + results[i] = srn; + i++; + } + return results; + } catch (RepositoryException re) { + throw new SlcException( + "Unexpected error while getting Results for given date", re); + } + } + + /** + * recursively update passed status of the parent ResultFolder and its + * parent if needed + * + * @param node + * cannot be null + * + */ + public static void updatePassedStatus(Node node, boolean passed) { + try { + Node pNode = node.getParent(); + if (!pNode.hasNode(SlcNames.SLC_STATUS)) + // we have reached the root of the tree. stop the + // recursivity + return; + boolean pStatus = pNode.getNode(SlcNames.SLC_STATUS) + .getProperty(SlcNames.SLC_SUCCESS).getBoolean(); + if (pStatus == passed) + // nothing to update + return; + else if (!passed) { + // error we only update status of the result folder and its + // parent if needed + pNode.getNode(SlcNames.SLC_STATUS).setProperty( + SlcNames.SLC_SUCCESS, passed); + updatePassedStatus(pNode, passed); + } else { + // success we must first check if all siblings have also + // successfully completed + boolean success = true; + NodeIterator ni = pNode.getNodes(); + children: while (ni.hasNext()) { + Node currNode = ni.nextNode(); + if ((currNode.isNodeType(SlcTypes.SLC_DIFF_RESULT) || currNode + .isNodeType(SlcTypes.SLC_RESULT_FOLDER)) + && !currNode.getNode(SlcNames.SLC_STATUS) + .getProperty(SlcNames.SLC_SUCCESS) + .getBoolean()) { + success = false; + break children; + } + } + if (success) { + pNode.getNode(SlcNames.SLC_STATUS).setProperty( + SlcNames.SLC_SUCCESS, passed); + updatePassedStatus(pNode, passed); + } else + // one of the siblings had also the failed status so + // above tree remains unchanged. + return; + } + } catch (RepositoryException e) { + throw new SlcException("Cannot register listeners", e); + } + } + + public static void updateStatusOnRemoval(Node node) { + try { + if (!node.hasNode(SlcNames.SLC_STATUS)) + // nothing to do + return; + boolean pStatus = node.getNode(SlcNames.SLC_STATUS) + .getProperty(SlcNames.SLC_SUCCESS).getBoolean(); + if (pStatus == true) + // nothing to update + return; + else { + // success we must first check if all siblings have also + // successfully completed + boolean success = true; + NodeIterator ni = node.getNodes(); + children: while (ni.hasNext()) { + Node currNode = ni.nextNode(); + if ((currNode.isNodeType(SlcTypes.SLC_DIFF_RESULT) || currNode + .isNodeType(SlcTypes.SLC_RESULT_FOLDER)) + && !currNode.getNode(SlcNames.SLC_STATUS) + .getProperty(SlcNames.SLC_SUCCESS) + .getBoolean()) { + success = false; + break children; + } + } + if (success) { + node.getNode(SlcNames.SLC_STATUS).setProperty( + SlcNames.SLC_SUCCESS, true); + updatePassedStatus(node, true); + } else + // one of the siblings had also the failed status so + // above tree remains unchanged. + return; + } + } catch (RepositoryException e) { + throw new SlcException("Unexpected error while updating status on removal", e); + } + } + +} diff --git a/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/SingleResultNode.java b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/SingleResultNode.java index 5a08349a9..aa4acea9c 100644 --- a/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/SingleResultNode.java +++ b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/SingleResultNode.java @@ -30,7 +30,8 @@ import org.argeo.slc.jcr.SlcNames; * It has no child. */ -public class SingleResultNode extends ResultParent { +public class SingleResultNode extends ResultParent implements + Comparable { private final Node node; private boolean passed; @@ -84,4 +85,8 @@ public class SingleResultNode extends ResultParent { // Do nothing this object is fully initialized at instantiation time. } + public int compareTo(SingleResultNode o) { + return super.compareTo(o); + } + } diff --git a/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/VirtualFolder.java b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/VirtualFolder.java index c69e562d9..5a6bc77ce 100644 --- a/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/VirtualFolder.java +++ b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/VirtualFolder.java @@ -15,27 +15,18 @@ */ package org.argeo.slc.client.ui.model; -import javax.jcr.Node; -import javax.jcr.NodeIterator; -import javax.jcr.RepositoryException; - -import org.argeo.ArgeoException; -import org.argeo.slc.jcr.SlcNames; -import org.argeo.slc.jcr.SlcTypes; - /** * UI Tree component. Virtual folder to list either other folders and/or a list * of results. Keeps a reference to its parent that might be null if the . */ public class VirtualFolder extends ResultParent { + ResultParent[] children; - private Node node = null; - private boolean isPassed = true; - - public VirtualFolder(VirtualFolder parent, Node node, String name) { + public VirtualFolder(VirtualFolder parent, ResultParent[] children, + String name) { super(name); setParent(parent); - this.node = node; + this.children = children; } @Override @@ -43,56 +34,16 @@ public class VirtualFolder extends ResultParent { super.dispose(); } - /** Override normal behavior to initialize display */ - @Override - public synchronized Object[] getChildren() { - if (isLoaded()) { - return super.getChildren(); - } else { - // initialize current object - try { - if (node != null) { - NodeIterator ni = node.getNodes(); - while (ni.hasNext()) { - Node currNode = ni.nextNode(); - if (currNode.isNodeType(SlcTypes.SLC_TEST_RESULT)) - addChild(new SingleResultNode(this, node, node - .getProperty(SlcNames.SLC_TEST_CASE) - .getString())); - else if (currNode - .isNodeType(SlcTypes.SLC_RESULT_FOLDER)) - addChild(new VirtualFolder(this, node, - node.getName())); - } - } - return super.getChildren(); - } catch (RepositoryException e) { - throw new ArgeoException( - "Cannot initialize WorkspaceNode UI object." - + getName(), e); - } - } - } - - // @Override - // public boolean refreshPassedStatus() { - // Object[] children = getChildren(); - // isPassed = true; - // checkChildrenStatus: for (int i = 0; i <= children.length; i++) { - // if (children[i] instanceof VirtualFolder) { - // - // } - // if (!((ResultParent) children[i]).isPassed()) { - // isPassed = false; - // break checkChildrenStatus; - // } - // } - // return isPassed; - // } - @Override protected void initialize() { - // TODO Auto-generated method stub + if (children != null) + for (ResultParent child : children) + addChild(child); } + public void resetChildren(ResultParent[] children) { + clearChildren(); + this.children = children; + initialize(); + } } \ No newline at end of file diff --git a/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/views/JcrResultTreeView.java b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/views/JcrResultTreeView.java index a00548a2c..ea0e85a44 100644 --- a/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/views/JcrResultTreeView.java +++ b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/views/JcrResultTreeView.java @@ -1,6 +1,7 @@ package org.argeo.slc.client.ui.views; import java.util.ArrayList; +import java.util.Calendar; import java.util.List; import javax.jcr.Node; @@ -11,6 +12,7 @@ import javax.jcr.PropertyType; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.Value; +import javax.jcr.nodetype.NodeType; import javax.jcr.observation.Event; import javax.jcr.observation.EventListener; import javax.jcr.observation.ObservationManager; @@ -25,10 +27,12 @@ import org.argeo.jcr.UserJcrUtils; import org.argeo.slc.SlcException; import org.argeo.slc.client.ui.ClientUiPlugin; import org.argeo.slc.client.ui.commands.AddResultFolder; +import org.argeo.slc.client.ui.model.ParentNodeFolder; import org.argeo.slc.client.ui.model.ResultFolder; import org.argeo.slc.client.ui.model.ResultParent; -import org.argeo.slc.client.ui.model.SimpleNodeFolder; +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; @@ -82,7 +86,13 @@ public class JcrResultTreeView extends ViewPart { private EventListener resultsObserver = null; - private final static String[] observedNodeTypes = { SlcTypes.SLC_TEST_RESULT }; + private final static String[] observedNodeTypes = { + SlcTypes.SLC_TEST_RESULT, SlcTypes.SLC_RESULT_FOLDER, + NodeType.NT_UNSTRUCTURED }; + + // FIXME cache to ease refresh after D&D + private ResultParent lastSelectedElement; + private ResultParent lastSelectedElementParent; /** * To be overridden to adapt size of form and result frames. @@ -114,23 +124,6 @@ public class JcrResultTreeView extends ViewPart { // Refresh the view to initialize it refresh(null); - - try { - ObservationManager observationManager = session.getWorkspace() - .getObservationManager(); - // FIXME Will not be notified if empty result is deleted - if (UserJcrUtils.getUserHome(session) != null) { - resultsObserver = new ResultObserver(resultTreeViewer.getTree() - .getDisplay()); - observationManager.addEventListener(resultsObserver, - Event.PROPERTY_ADDED | Event.NODE_REMOVED, UserJcrUtils - .getUserHome(session).getPath(), true, null, - observedNodeTypes, false); - } - } catch (RepositoryException e) { - throw new SlcException("Cannot register listeners", e); - } - } // The main tree viewer @@ -183,10 +176,12 @@ public class JcrResultTreeView extends ViewPart { .getNode()); else propertiesViewer.setInput(null); + lastSelectedElement = (ResultParent) firstItem; + lastSelectedElementParent = (ResultParent) ((ResultParent) firstItem) + .getParent(); } } }); - return viewer; } @@ -308,16 +303,13 @@ public class JcrResultTreeView extends ViewPart { if (resultParent == null) { resultTreeViewer.setInput(initializeResultTree()); if (resultsObserver == null) { - // force initialization of the resultsObserver, only useful - // if the current view has been displayed before a single - // test has been run try { ObservationManager observationManager = session .getWorkspace().getObservationManager(); resultsObserver = new ResultObserver(resultTreeViewer .getTree().getDisplay()); observationManager.addEventListener(resultsObserver, - Event.PROPERTY_ADDED | Event.NODE_REMOVED, UserJcrUtils + Event.NODE_ADDED | Event.NODE_REMOVED, UserJcrUtils .getUserHome(session).getPath(), true, null, observedNodeTypes, false); } catch (RepositoryException e) { @@ -331,21 +323,63 @@ public class JcrResultTreeView extends ViewPart { ResultFolder currFolder = (ResultFolder) resultParent; jcrRefresh(currFolder.getNode()); currFolder.forceFullRefresh(); + resultTreeViewer.refresh(lastSelectedElement); } } } private ResultParent[] initializeResultTree() { - ResultParent[] roots = new ResultParent[2]; try { - roots[0] = new ResultFolder(null, - SlcJcrResultUtils.getMyResultParentNode(session), - "My results"); - Node otherResultsPar = session.getNode(SlcJcrResultUtils - .getSlcResultsBasePath(session)); - roots[1] = new SimpleNodeFolder(null, otherResultsPar, - "All results"); - return roots; + if (session.nodeExists(SlcJcrResultUtils + .getSlcResultsBasePath(session))) { + ResultParent[] roots = new ResultParent[5]; + + // My results + roots[0] = new ParentNodeFolder(null, + SlcJcrResultUtils.getMyResultParentNode(session), + "My results"); + + // 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"); + return roots; + } else + // no test has yet been processed, we leave the viewer blank + return null; } catch (RepositoryException re) { throw new ArgeoException( "Unexpected error while initializing ResultTree.", re); @@ -367,13 +401,15 @@ public class JcrResultTreeView extends ViewPart { if (selection.size() == 1) { Object obj = selection.getFirstElement(); try { - Node targetParentNode = null; - if (obj instanceof ResultFolder) { - targetParentNode = ((ResultFolder) obj).getNode(); - - if (targetParentNode.isNodeType(SlcTypes.SLC_RESULT_FOLDER)) - isMyResultFolder = true; - } + if (obj instanceof ResultFolder + && (((ResultFolder) obj).getNode()) + .isNodeType(SlcTypes.SLC_RESULT_FOLDER)) + isMyResultFolder = true; + else if (obj instanceof ParentNodeFolder + && (((ParentNodeFolder) obj).getNode().getPath() + .startsWith(SlcJcrResultUtils + .getMyResultsBasePath(session)))) + isMyResultFolder = true; } catch (RepositoryException re) { throw new SlcException( "unexpected error while building condition for context menu", @@ -456,20 +492,30 @@ public class JcrResultTreeView extends ViewPart { // We can only drop under myResults Node targetParentNode = null; if (target instanceof ResultFolder) { - Node currNode = ((ResultFolder) target).getNode(); - - if (currNode.isNodeType(SlcTypes.SLC_RESULT_FOLDER)) { - targetParentNode = currNode; - } + targetParentNode = ((ResultFolder) target).getNode(); + } else if (target instanceof ParentNodeFolder) { + if ((((ParentNodeFolder) target).getNode().getPath() + .startsWith(SlcJcrResultUtils + .getMyResultsBasePath(session)))) + targetParentNode = ((ParentNodeFolder) target) + .getNode(); } else if (target instanceof SingleResultNode) { Node currNode = ((SingleResultNode) target).getNode(); - if (currNode.getParent().isNodeType( - SlcTypes.SLC_RESULT_FOLDER)) + if (currNode + .getParent() + .getPath() + .startsWith( + SlcJcrResultUtils + .getMyResultsBasePath(session))) targetParentNode = currNode.getParent(); } if (targetParentNode != null) { currParentNode = targetParentNode; validDrop = true; + // FIXME + lastSelectedElement = (ResultParent) target; + lastSelectedElementParent = (ResultParent) ((ResultParent) target) + .getParent(); } } catch (RepositoryException re) { throw new SlcException( @@ -486,7 +532,7 @@ public class JcrResultTreeView extends ViewPart { Node target = currParentNode.addNode(source.getName(), source .getPrimaryNodeType().getName()); JcrUtils.copy(source, target); - updatePassedStatus(target, target.getNode(SlcNames.SLC_STATUS) + ResultParentUtils.updatePassedStatus(target, target.getNode(SlcNames.SLC_STATUS) .getProperty(SlcNames.SLC_SUCCESS).getBoolean()); target.getSession().save(); } catch (RepositoryException re) { @@ -495,59 +541,6 @@ public class JcrResultTreeView extends ViewPart { } return true; } - - /** - * recursively update passed status of the parent ResultFolder and its - * parent if needed - * - * @param node - * cannot be null - * - */ - private void updatePassedStatus(Node node, boolean passed) { - try { - Node pNode = node.getParent(); - boolean pStatus = pNode.getNode(SlcNames.SLC_STATUS) - .getProperty(SlcNames.SLC_SUCCESS).getBoolean(); - if (pStatus == passed) - // nothing to update - return; - else if (!passed) { - // error we only update status of the result folder and its - // parent if needed - pNode.getNode(SlcNames.SLC_STATUS).setProperty( - SlcNames.SLC_SUCCESS, passed); - updatePassedStatus(pNode, passed); - } else { - // success we must first check if all siblings have also - // successfully completed - boolean success = true; - NodeIterator ni = pNode.getNodes(); - children: while (ni.hasNext()) { - Node currNode = ni.nextNode(); - if ((currNode.isNodeType(SlcTypes.SLC_DIFF_RESULT) || currNode - .isNodeType(SlcTypes.SLC_RESULT_FOLDER)) - && !currNode.getNode(SlcNames.SLC_STATUS) - .getProperty(SlcNames.SLC_SUCCESS) - .getBoolean()) { - success = false; - break children; - } - } - if (success) { - pNode.getNode(SlcNames.SLC_STATUS).setProperty( - SlcNames.SLC_SUCCESS, passed); - updatePassedStatus(pNode, passed); - } else - // one of the siblings had also the failed status so - // above tree remains unchanged. - return; - } - - } catch (RepositoryException e) { - throw new SlcException("Cannot register listeners", e); - } - } } class ResultObserver extends AsyncUiEventListener { @@ -559,31 +552,72 @@ public class JcrResultTreeView extends ViewPart { @Override protected Boolean willProcessInUiThread(List events) throws RepositoryException { + // unfiltered for the time being + return true; + // for (Event event : events) { + // getLog().debug("Received event " + event); + // int eventType = event.getType(); + // if (eventType == Event.NODE_REMOVED) + // ;//return true; + // String path = event.getPath(); + // int index = path.lastIndexOf('/'); + // String propertyName = path.substring(index + 1); + // if (propertyName.equals(SlcNames.SLC_COMPLETED) + // || propertyName.equals(SlcNames.SLC_UUID)) { + // ;//return true; + // } + // } + // return false; + } + + protected void onEventInUiThread(List events) + throws RepositoryException { + for (Event event : events) { - // getLog().debug("Received event " + event); + getLog().debug("Received event " + event); int eventType = event.getType(); - if (eventType == Event.NODE_REMOVED) - return true; - String path = event.getPath(); - int index = path.lastIndexOf('/'); - String propertyName = path.substring(index + 1); - if (propertyName.equals(SlcNames.SLC_COMPLETED) - || propertyName.equals(SlcNames.SLC_UUID)) { - return true; + if (eventType == Event.NODE_REMOVED) { + String path = event.getPath(); + int index = path.lastIndexOf('/'); + String parPath = path.substring(0, index + 1); + if (session.nodeExists(parPath)) { + Node currNode = session.getNode(parPath); + if (currNode.isNodeType(NodeType.NT_UNSTRUCTURED)) { + refresh(null); + jcrRefresh(currNode); + resultTreeViewer.refresh(true); + resultTreeViewer.expandToLevel( + lastSelectedElementParent, 1); + + } + } + } else if (eventType == Event.NODE_ADDED) { + String path = event.getPath(); + if (session.nodeExists(path)) { + Node currNode = session.getNode(path); + if (currNode.isNodeType(SlcTypes.SLC_DIFF_RESULT) + || currNode + .isNodeType(SlcTypes.SLC_RESULT_FOLDER)) { + refresh(null); + resultTreeViewer.expandToLevel(lastSelectedElement, + 1); + } + } } + // String path = event.getPath(); + // int index = path.lastIndexOf('/'); + // String propertyName = path.substring(index + 1); + // if (propertyName.equals(SlcNames.SLC_COMPLETED) + // || propertyName.equals(SlcNames.SLC_UUID)) { + // } } - return false; - } - protected void onEventInUiThread(List events) - throws RepositoryException { // FIXME implement correct behaviour. treeViewer selection is // disposed by the drag & drop. // resultTreeViewer.refresh(); // refresh(null); // log.warn("Implement refresh."); } - } class PropertiesContentProvider implements IStructuredContentProvider { diff --git a/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcJcrConstants.java b/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcJcrConstants.java index 6c36aa949..4cf955c1d 100644 --- a/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcJcrConstants.java +++ b/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcJcrConstants.java @@ -30,5 +30,5 @@ public interface SlcJcrConstants { /* * SLC SPECIFIC JCR PATHS */ - public final static String SLC_MYRESULT_BASEPATH = "slc:myResults/"; + public final static String SLC_MYRESULT_BASEPATH = "slc:myResults"; } diff --git a/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcJcrResultUtils.java b/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcJcrResultUtils.java index 0f07fe567..ca9dabfe7 100644 --- a/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcJcrResultUtils.java +++ b/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcJcrResultUtils.java @@ -18,7 +18,9 @@ package org.argeo.slc.jcr; import javax.jcr.Node; import javax.jcr.RepositoryException; import javax.jcr.Session; +import javax.jcr.nodetype.NodeType; +import org.apache.jackrabbit.spi.commons.conversion.MalformedPathException; import org.argeo.ArgeoException; import org.argeo.jcr.JcrUtils; import org.argeo.jcr.UserJcrUtils; @@ -58,20 +60,36 @@ public class SlcJcrResultUtils { } } + /** + * Creates a new node with type NodeType.NT_UNSTRUCTURED at the given + * absolute path. If a node already exists at the given path, returns that + * node if it has the correct type and throws an exception otherwise. + * + * @param session + * @return + */ public static Node getMyResultParentNode(Session session) { try { - if (session.nodeExists(SlcJcrResultUtils - .getMyResultsBasePath(session))) - return session.getNode(getMyResultsBasePath(session)); - else - return createResultFolderNode(session, - getMyResultsBasePath(session)); + String absPath = getMyResultsBasePath(session); + if (session.nodeExists(absPath)) { + Node currNode = session.getNode(absPath); + if (currNode.isNodeType(NodeType.NT_UNSTRUCTURED)) + return currNode; + else + throw new SlcException( + "A node already exists at this path : " + absPath + + " that has the wrong type. "); + } else { + Node myResParNode = JcrUtils.mkdirs(session, absPath); + myResParNode.setPrimaryType(NodeType.NT_UNSTRUCTURED); + session.save(); + return myResParNode; + } } catch (RepositoryException re) { throw new ArgeoException( "Unexpected error while creating user MyResult base node.", re); } - } /** -- 2.39.5