introduce a new view to display JcrResults has a tree.
authorBruno Sinou <bsinou@argeo.org>
Wed, 22 Aug 2012 14:49:15 +0000 (14:49 +0000)
committerBruno Sinou <bsinou@argeo.org>
Wed, 22 Aug 2012 14:49:15 +0000 (14:49 +0000)
git-svn-id: https://svn.argeo.org/slc/trunk@5533 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

22 files changed:
plugins/org.argeo.slc.client.ui/plugin.xml
plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/SlcUiConstants.java [new file with mode: 0644]
plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/commands/AddResultFolder.java [new file with mode: 0644]
plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/commands/DeleteResult.java [new file with mode: 0644]
plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/commands/RefreshJcrResultTreeView.java [new file with mode: 0644]
plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/commands/RunSlcFlow.java
plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/decorators/ResultFailedDecorator.java [new file with mode: 0644]
plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/ResultFolder.java [new file with mode: 0644]
plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/ResultParent.java [new file with mode: 0644]
plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/SimpleNodeFolder.java [new file with mode: 0644]
plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/SingleResultNode.java [new file with mode: 0644]
plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/VirtualFolder.java [new file with mode: 0644]
plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/providers/ResultTreeContentProvider.java [new file with mode: 0644]
plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/providers/ResultTreeLabelProvider.java [new file with mode: 0644]
plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/views/JcrResultListView.java
plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/views/JcrResultTreeView.java [new file with mode: 0644]
runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/JcrTestResult.java
runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcJcrConstants.java
runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcJcrResultUtils.java [new file with mode: 0644]
runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcTypes.java
runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/execution/JcrResultListener.java
runtime/org.argeo.slc.support.jcr/src/main/resources/org/argeo/slc/jcr/slc.cnd

index bd423323bfc2a54b48396e2d132d9ceb32490489..7ee6be7aa41855ae264997c78cf51521d998c786 100644 (file)
                id="org.argeo.slc.client.ui.updateModule"
                name="Update Module">
            </command>
+           
+           <!-- Commands that do not need dependency injection --> 
+           <command
+               defaultHandler="org.argeo.slc.client.ui.commands.AddResultFolder"
+               id="org.argeo.slc.client.ui.addResultFolder"
+               name="Add result folder">
+           </command>
+           <command
+               defaultHandler="org.argeo.slc.client.ui.commands.RefreshJcrResultTreeView"
+               id="org.argeo.slc.client.ui.refreshJcrResultTreeView"
+               name="Refresh">
+               <commandParameter
+                       id="org.argeo.slc.client.ui.param.refreshType"
+                       name="Refresh type">
+                       </commandParameter>
+           </command>
            <!--
                <command
                defaultHandler="org.argeo.eclipse.spring.SpringCommandHandler"
diff --git a/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/SlcUiConstants.java b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/SlcUiConstants.java
new file mode 100644 (file)
index 0000000..073c16e
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2007-2012 Mathieu Baudier
+ *
+ * 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;
+
+/** SLC UI common constants */
+public interface SlcUiConstants {
+
+       /*
+        * MISCEALLENEOUS
+        */
+       public final static String DEFAULT_DISPLAY_DATE_FORMAT = "MM/dd/yy";
+       public final static String DEFAULT_DISPLAY_DATE_TIME_FORMAT = "MM/dd/yyyy, HH:mm:ss";
+}
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
new file mode 100644 (file)
index 0000000..e1b3574
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2007-2012 Mathieu Baudier
+ *
+ * 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.commands;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+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.ResultFolder;
+import org.argeo.slc.jcr.SlcJcrResultUtils;
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * Add a new SlcType.SLC_RESULT_FOLDER node to the current user "my result"
+ * tree. This handler is only intended to bu used with JcrResultTreeView and its
+ * descendants.
+ */
+
+public class AddResultFolder extends AbstractHandler {
+       public final static String ID = ClientUiPlugin.ID + ".addResultFolder";
+       public final static String DEFAULT_ICON_REL_PATH = "icons/addFolder.gif";
+       public final static String DEFAULT_LABEL = "New result folder";
+
+       public Object execute(ExecutionEvent event) throws ExecutionException {
+               IStructuredSelection selection = (IStructuredSelection) HandlerUtil
+                               .getActiveWorkbenchWindow(event).getActivePage().getSelection();
+
+               // 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();
+                       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);
+                               }
+                       } catch (RepositoryException e) {
+                               throw new SlcException(
+                                               "Unexpected exception while creating result folder", e);
+                       }
+               } else {
+                       ErrorFeedback.show("Can only add file folder to a node");
+               }
+               return null;
+       }
+}
\ No newline at end of file
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
new file mode 100644 (file)
index 0000000..321a6b5
--- /dev/null
@@ -0,0 +1,109 @@
+/*\r
+ * Copyright (C) 2007-2012 Mathieu Baudier\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *         http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+package org.argeo.slc.client.ui.commands;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Iterator;\r
+import java.util.List;\r
+\r
+import javax.jcr.Node;\r
+import javax.jcr.RepositoryException;\r
+import javax.jcr.Session;\r
+\r
+import org.argeo.eclipse.ui.ErrorFeedback;\r
+import org.argeo.slc.client.ui.model.ResultFolder;\r
+import org.argeo.slc.client.ui.model.SingleResultNode;\r
+import org.eclipse.core.commands.AbstractHandler;\r
+import org.eclipse.core.commands.ExecutionEvent;\r
+import org.eclipse.core.commands.ExecutionException;\r
+import org.eclipse.core.runtime.IProgressMonitor;\r
+import org.eclipse.core.runtime.IStatus;\r
+import org.eclipse.core.runtime.Status;\r
+import org.eclipse.core.runtime.jobs.Job;\r
+import org.eclipse.jface.dialogs.MessageDialog;\r
+import org.eclipse.jface.viewers.ISelection;\r
+import org.eclipse.jface.viewers.IStructuredSelection;\r
+import org.eclipse.ui.handlers.HandlerUtil;\r
+\r
+/** Deletes one or many results */\r
+public class DeleteResult extends AbstractHandler {\r
+       /* DEPENDENCY INJECTION */\r
+       private Session session;\r
+\r
+       public Object execute(final ExecutionEvent event) throws ExecutionException {\r
+               final ISelection selection = HandlerUtil\r
+                               .getActiveWorkbenchWindow(event).getActivePage().getSelection();\r
+\r
+               if (!MessageDialog.openConfirm(HandlerUtil.getActiveShell(event),\r
+                               "Confirm",\r
+                               "Are you sure that you want to delete these results?"))\r
+                       return null;\r
+\r
+               Job job = new Job("Delete results") {\r
+                       @Override\r
+                       protected IStatus run(IProgressMonitor monitor) {\r
+                               if (selection != null\r
+                                               && selection instanceof IStructuredSelection) {\r
+                                       List<String> nodes = new ArrayList<String>();\r
+                                       Iterator<?> it = ((IStructuredSelection) selection)\r
+                                                       .iterator();\r
+                                       Object obj = null;\r
+                                       try {\r
+                                               while (it.hasNext()) {\r
+                                                       obj = it.next();\r
+                                                       if (obj instanceof ResultFolder) {\r
+                                                               Node node = ((ResultFolder) obj).getNode();\r
+                                                               nodes.add(node.getPath());\r
+                                                       } else if (obj instanceof SingleResultNode) {\r
+                                                               Node node = ((SingleResultNode) obj).getNode();\r
+                                                               nodes.add(node.getPath());\r
+                                                       }\r
+                                               }\r
+                                       } catch (RepositoryException e) {\r
+                                               ErrorFeedback.show("Cannot list nodes", e);\r
+                                               return null;\r
+                                       }\r
+                                       monitor.beginTask("Delete results", nodes.size());\r
+                                       Node node = null;\r
+                                       try {\r
+                                               for (final String path : nodes) {\r
+                                                       if (session.itemExists(path)) {\r
+                                                               node = session.getNode(path);\r
+                                                               node.remove();\r
+                                                       }\r
+                                                       monitor.worked(1);\r
+                                               }\r
+                                               session.save();\r
+                                       } catch (RepositoryException e) {\r
+                                               ErrorFeedback.show("Cannot delete node " + node, e);\r
+                                       }\r
+                                       monitor.done();\r
+                               }\r
+                               return Status.OK_STATUS;\r
+                       }\r
+\r
+               };\r
+               job.setUser(true);\r
+               job.schedule();\r
+               return null;\r
+       }\r
+\r
+       /* DEPENDENCY INJECTION */\r
+       public void setSession(Session session) {\r
+               this.session = session;\r
+       }\r
+}\r
diff --git a/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/commands/RefreshJcrResultTreeView.java b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/commands/RefreshJcrResultTreeView.java
new file mode 100644 (file)
index 0000000..9661775
--- /dev/null
@@ -0,0 +1,66 @@
+package org.argeo.slc.client.ui.commands;\r
+\r
+/*\r
+ * Copyright (C) 2007-2012 Mathieu Baudier\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *         http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+import java.util.Iterator;\r
+\r
+import org.argeo.slc.client.ui.ClientUiPlugin;\r
+import org.argeo.slc.client.ui.model.ResultParent;\r
+import org.argeo.slc.client.ui.views.JcrResultTreeView;\r
+import org.eclipse.core.commands.AbstractHandler;\r
+import org.eclipse.core.commands.ExecutionEvent;\r
+import org.eclipse.core.commands.ExecutionException;\r
+import org.eclipse.jface.viewers.IStructuredSelection;\r
+import org.eclipse.ui.handlers.HandlerUtil;\r
+\r
+/**\r
+ * Force refresh the ResultTreeView. This command is only intended to be called\r
+ * by either the toolbar menu of the view or by the popup menu. Refresh due to\r
+ * data changes must be triggered by Observers\r
+ */\r
+public class RefreshJcrResultTreeView extends AbstractHandler {\r
+       public final static String ID = ClientUiPlugin.ID\r
+                       + ".refreshJcrResultTreeView";\r
+       public final static String PARAM_REFRESH_TYPE = ClientUiPlugin.ID\r
+                       + ".param.refreshType";\r
+       public final static String PARAM_REFRESH_TYPE_FULL = "fullRefresh";\r
+\r
+       public Object execute(final ExecutionEvent event) throws ExecutionException {\r
+               String refreshType = event.getParameter(PARAM_REFRESH_TYPE);\r
+               JcrResultTreeView view = (JcrResultTreeView) HandlerUtil\r
+                               .getActiveWorkbenchWindow(event).getActivePage()\r
+                               .getActivePart();\r
+\r
+               // force full refresh without preserving selection from the tool bar\r
+               if (PARAM_REFRESH_TYPE_FULL.equals(refreshType))\r
+                       view.refresh(null);\r
+               else {\r
+                       IStructuredSelection selection = (IStructuredSelection) HandlerUtil\r
+                                       .getActiveWorkbenchWindow(event).getActivePage()\r
+                                       .getSelection();\r
+                       @SuppressWarnings("rawtypes")\r
+                       Iterator it = selection.iterator();\r
+                       while (it.hasNext()) {\r
+                               Object obj = it.next();\r
+                               if (obj instanceof ResultParent) {\r
+                                       view.refresh((ResultParent) obj);\r
+                               }\r
+                       }\r
+               }\r
+               return null;\r
+       }\r
+}\r
index 00f989d62127c4869751cbaf07404b4133c3d343..4ae7f97e69eb10fe605e9b21ce1e98edf67face8 100644 (file)
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2007-2012 Mathieu Baudier
+ *
+ * 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.commands;
 
 import java.util.HashMap;
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
new file mode 100644 (file)
index 0000000..1d021e2
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2007-2012 Mathieu Baudier
+ *
+ * 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.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;
+import org.eclipse.jface.viewers.DecorationOverlayIcon;
+import org.eclipse.jface.viewers.IDecoration;
+import org.eclipse.jface.viewers.ILabelDecorator;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.ISharedImages;
+
+public class ResultFailedDecorator extends LabelProvider implements
+               ILabelDecorator {
+
+       private final static Log log = LogFactory
+                       .getLog(ResultFailedDecorator.class);
+
+       public ResultFailedDecorator() {
+               super();
+       }
+
+       // Method to decorate Image
+       public Image decorateImage(Image image, Object object) {
+
+               // This method returns an annotated image or null if the
+               // image need not be decorated. Returning a null image
+               // 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()
+                                               .getImageDescriptor(ISharedImages.IMG_DEC_FIELD_ERROR);
+                               DecorationOverlayIcon decoratedImage = new DecorationOverlayIcon(
+                                               image, desc, IDecoration.TOP_LEFT);
+                               return decoratedImage.createImage();
+                       } else
+                               return null;
+               }
+               return null;
+       }
+
+       // Method to decorate Text
+       public String decorateText(String label, Object object) {
+               return null;
+       }
+}
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
new file mode 100644 (file)
index 0000000..ac4eb9f
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2007-2012 Mathieu Baudier
+ *
+ * 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.model;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+
+import org.argeo.slc.SlcException;
+import org.argeo.slc.jcr.SlcNames;
+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 {
+
+       private Node node = null;
+
+       /**
+        * 
+        * @param parent
+        * @param node
+        *            throws an exception if null
+        * @param name
+        */
+       public ResultFolder(ResultFolder 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());
+               } catch (RepositoryException re) {
+                       throw new SlcException(
+                                       "Unexpected error while initializing result folder : "
+                                                       + getName(), re);
+               }
+
+       }
+
+       @Override
+       protected void initialize() {
+               try {
+                       NodeIterator ni = node.getNodes();
+                       while (ni.hasNext()) {
+                               Node currNode = ni.nextNode();
+                               if (currNode.isNodeType(SlcTypes.SLC_TEST_RESULT)) {
+                                       SingleResultNode srn = new SingleResultNode(this, currNode,
+                                                       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);
+                               }
+                       }
+               } catch (RepositoryException re) {
+                       throw new SlcException(
+                                       "Unexpected error while initializing result folder : "
+                                                       + getName(), re);
+               }
+       }
+
+       @Override
+       public synchronized void dispose() {
+               super.dispose();
+       }
+
+       public Node getNode() {
+               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;
+       // }
+
+}
\ No newline at end of file
diff --git a/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/ResultParent.java b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/ResultParent.java
new file mode 100644 (file)
index 0000000..ecbffca
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2007-2012 Mathieu Baudier
+ *
+ * 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.model;
+
+import org.argeo.eclipse.ui.TreeParent;
+
+/**
+ * Common base UI object to build result Tree.
+ */
+
+public abstract class ResultParent extends TreeParent {
+
+       public ResultParent(String name) {
+               super(name);
+       }
+
+       private boolean isPassed = true;
+
+       protected synchronized void setPassed(boolean isPassed) {
+               this.isPassed = isPassed;
+       }
+
+       public boolean isPassed() {
+               return isPassed;
+       }
+
+       @Override
+       public synchronized boolean hasChildren() {
+               if (!isLoaded())
+                       initialize();
+               return super.hasChildren();
+       }
+
+       public void forceFullRefresh() {
+               clearChildren();
+               initialize();
+       }
+
+       protected abstract void initialize();
+
+}
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/SimpleNodeFolder.java
new file mode 100644 (file)
index 0000000..c08dafd
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2007-2012 Mathieu Baudier
+ *
+ * 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.model;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NodeType;
+
+import org.argeo.slc.SlcException;
+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.
+ */
+public class SimpleNodeFolder extends ResultParent {
+
+       private Node node = null;
+
+       /**
+        * 
+        * @param parent
+        * @param node
+        *            throws an exception if null
+        * @param name
+        */
+       public SimpleNodeFolder(SimpleNodeFolder parent, Node node, String name) {
+               super(name);
+               if (node == null)
+                       throw new SlcException("Node Object cannot be null");
+               setParent(parent);
+               this.node = node;
+       }
+
+       @Override
+       protected void initialize() {
+               try {
+                       NodeIterator ni = node.getNodes();
+                       while (ni.hasNext()) {
+                               Node currNode = ni.nextNode();
+                               if (currNode.isNodeType(SlcTypes.SLC_TEST_RESULT)) {
+                                       SingleResultNode srn = new SingleResultNode(this, currNode,
+                                                       currNode.getProperty(SlcNames.SLC_TEST_CASE)
+                                                                       .getString());
+                                       addChild(srn);
+                               } else if (currNode.isNodeType(NodeType.NT_UNSTRUCTURED))
+                                       addChild(new SimpleNodeFolder(this, currNode,
+                                                       currNode.getName()));
+                       }
+               } catch (RepositoryException re) {
+                       throw new SlcException(
+                                       "Unexpected error while initializing simple node folder : "
+                                                       + getName(), re);
+               }
+       }
+
+       @Override
+       public synchronized void dispose() {
+               super.dispose();
+       }
+
+       public Node getNode() {
+               return node;
+       }
+}
\ No newline at end of file
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
new file mode 100644 (file)
index 0000000..5a08349
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2007-2012 Mathieu Baudier
+ *
+ * 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.model;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Workspace;
+
+import org.argeo.eclipse.ui.TreeParent;
+import org.argeo.slc.SlcException;
+import org.argeo.slc.jcr.SlcNames;
+
+/**
+ * UI Tree component. Wraps a result node of a JCR {@link Workspace}. It also
+ * keeps a reference to its parent node that can either be a
+ * {@link ResultFolder}, a {@link SingleResultNode} or a {@link VirtualFolder}.
+ * It has no child.
+ */
+
+public class SingleResultNode extends ResultParent {
+
+       private final Node node;
+       private boolean passed;
+
+       // keeps a local reference to the node's name to avoid exception when the
+       // session is lost
+
+       /** Creates a new UiNode in the UI Tree */
+       public SingleResultNode(TreeParent parent, Node node, String name) {
+               super(name);
+               setParent(parent);
+               this.node = node;
+               setPassed(refreshPassedStatus());
+       }
+
+       public boolean refreshPassedStatus() {
+               try {
+                       Node check = node.getNode(SlcNames.SLC_STATUS);
+                       passed = check.getProperty(SlcNames.SLC_SUCCESS).getBoolean();
+                       return passed;
+               } catch (RepositoryException re) {
+                       throw new SlcException(
+                                       "Unexpected error while checking result status", re);
+               }
+       }
+
+       /** returns the node wrapped by the current UI object */
+       public Node getNode() {
+               return node;
+       }
+
+       /**
+        * Override normal behavior : Results have no children for this view
+        */
+       @Override
+       public synchronized Object[] getChildren() {
+               return null;
+       }
+
+       @Override
+       public boolean hasChildren() {
+               return false;
+       }
+
+       public boolean isPassed() {
+               return passed;
+       }
+
+       @Override
+       protected void initialize() {
+               // Do nothing this object is fully initialized at instantiation time.
+       }
+
+}
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
new file mode 100644 (file)
index 0000000..c69e562
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2007-2012 Mathieu Baudier
+ *
+ * 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.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 {
+
+       private Node node = null;
+       private boolean isPassed = true;
+
+       public VirtualFolder(VirtualFolder parent, Node node, String name) {
+               super(name);
+               setParent(parent);
+               this.node = node;
+       }
+
+       @Override
+       public synchronized void dispose() {
+               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
+       }
+
+}
\ No newline at end of file
diff --git a/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/providers/ResultTreeContentProvider.java b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/providers/ResultTreeContentProvider.java
new file mode 100644 (file)
index 0000000..c2594ec
--- /dev/null
@@ -0,0 +1,40 @@
+package org.argeo.slc.client.ui.providers;
+
+import org.argeo.eclipse.ui.TreeParent;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+
+/** Basic content provider for a tree of result */
+public class ResultTreeContentProvider implements ITreeContentProvider {
+
+       /**
+        * @param parent
+        *            Pass current user home as parameter
+        * 
+        */
+       public Object[] getElements(Object parent) {
+               if (parent instanceof Object[])
+                       return (Object[]) parent;
+               else
+                       return null;
+       }
+
+       public Object getParent(Object child) {
+               return ((TreeParent) child).getParent();
+       }
+
+       public Object[] getChildren(Object parent) {
+               return ((TreeParent) parent).getChildren();
+       }
+
+       public boolean hasChildren(Object parent) {
+               return ((TreeParent) parent).hasChildren();
+       }
+
+       public void dispose() {
+               // FIXME implement if needed
+       }
+
+       public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+       }
+}
\ No newline at end of file
diff --git a/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/providers/ResultTreeLabelProvider.java b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/providers/ResultTreeLabelProvider.java
new file mode 100644 (file)
index 0000000..251f066
--- /dev/null
@@ -0,0 +1,30 @@
+package org.argeo.slc.client.ui.providers;
+
+import org.argeo.eclipse.ui.TreeParent;
+import org.argeo.slc.client.ui.SlcImages;
+import org.argeo.slc.client.ui.model.ResultParent;
+import org.argeo.slc.client.ui.model.SingleResultNode;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.swt.graphics.Image;
+
+/** Basic label provider for a tree of result */
+public class ResultTreeLabelProvider extends LabelProvider {
+
+       @Override
+       public String getText(Object element) {
+               return ((TreeParent) element).getName();
+       }
+
+       public Image getImage(Object obj) {
+               if (obj instanceof SingleResultNode) {
+                       // FIXME add realtime modification of process icon (SCHEDULED,
+                       // RUNNING, COMPLETED...)
+                       // Node resultNode = ((SingleResultNode) obj).getNode();
+                       // int status = SlcJcrUtils.aggregateTestStatus(resultNode);
+                       return SlcImages.PROCESS_COMPLETED;
+               } else if (obj instanceof ResultParent)
+                       return SlcImages.FOLDER;
+               else
+                       return null;
+       }
+}
index 322256b7194caf56c8d68c5e7f82676618757151..e4e3575e6cc347014f492f0afe04a590a46962d5 100644 (file)
@@ -35,7 +35,7 @@ import org.argeo.jcr.JcrUtils;
 import org.argeo.slc.SlcException;
 import org.argeo.slc.client.ui.editors.ProcessEditor;
 import org.argeo.slc.client.ui.editors.ProcessEditorInput;
-import org.argeo.slc.jcr.SlcJcrConstants;
+import org.argeo.slc.jcr.SlcJcrResultUtils;
 import org.argeo.slc.jcr.SlcNames;
 import org.argeo.slc.jcr.SlcTypes;
 import org.eclipse.jface.viewers.ColumnLabelProvider;
@@ -87,12 +87,12 @@ public class JcrResultListView extends ViewPart implements SlcNames {
                try {
                        ObservationManager observationManager = session.getWorkspace()
                                        .getObservationManager();
-                       String[] nodeTypes = { SlcTypes.SLC_RESULT };
+                       String[] nodeTypes = { SlcTypes.SLC_TEST_RESULT };
                        // FIXME Will not be notified if empty result is deleted
                        observationManager.addEventListener(resultsObserver,
                                        Event.PROPERTY_ADDED | Event.NODE_REMOVED,
-                                       SlcJcrConstants.RESULTS_BASE_PATH, true, null, nodeTypes,
-                                       false);
+                                       SlcJcrResultUtils.getSlcResultsBasePath(session), true,
+                                       null, nodeTypes, false);
                } catch (RepositoryException e) {
                        throw new SlcException("Cannot register listeners", e);
                }
@@ -167,7 +167,8 @@ public class JcrResultListView extends ViewPart implements SlcNames {
                public Object[] getElements(Object inputElement) {
                        try {
                                // TODO filter, optimize with virtual table, ...
-                               String sql = "SELECT * from [slc:result] ORDER BY [jcr:lastModified] DESC";
+                               String sql = "SELECT * from [" + SlcTypes.SLC_TEST_RESULT
+                                               + "] ORDER BY [jcr:lastModified] DESC";
                                Query query = session.getWorkspace().getQueryManager()
                                                .createQuery(sql, Query.JCR_SQL2);
                                // TODO paging
@@ -276,5 +277,4 @@ public class JcrResultListView extends ViewPart implements SlcNames {
        public void setSession(Session session) {
                this.session = session;
        }
-
 }
\ 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
new file mode 100644 (file)
index 0000000..443674b
--- /dev/null
@@ -0,0 +1,620 @@
+package org.argeo.slc.client.ui.views;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import javax.jcr.Node;\r
+import javax.jcr.NodeIterator;\r
+import javax.jcr.Property;\r
+import javax.jcr.PropertyIterator;\r
+import javax.jcr.PropertyType;\r
+import javax.jcr.RepositoryException;\r
+import javax.jcr.Session;\r
+import javax.jcr.Value;\r
+import javax.jcr.observation.Event;\r
+import javax.jcr.observation.EventListener;\r
+import javax.jcr.observation.ObservationManager;\r
+\r
+import org.apache.commons.logging.Log;\r
+import org.apache.commons.logging.LogFactory;\r
+import org.argeo.ArgeoException;\r
+import org.argeo.eclipse.ui.jcr.AsyncUiEventListener;\r
+import org.argeo.eclipse.ui.utils.CommandUtils;\r
+import org.argeo.jcr.JcrUtils;\r
+import org.argeo.slc.SlcException;\r
+import org.argeo.slc.client.ui.ClientUiPlugin;\r
+import org.argeo.slc.client.ui.commands.AddResultFolder;\r
+import org.argeo.slc.client.ui.model.ResultFolder;\r
+import org.argeo.slc.client.ui.model.ResultParent;\r
+import org.argeo.slc.client.ui.model.SimpleNodeFolder;\r
+import org.argeo.slc.client.ui.model.SingleResultNode;\r
+import org.argeo.slc.client.ui.providers.ResultTreeContentProvider;\r
+import org.argeo.slc.client.ui.providers.ResultTreeLabelProvider;\r
+import org.argeo.slc.jcr.SlcJcrResultUtils;\r
+import org.argeo.slc.jcr.SlcNames;\r
+import org.argeo.slc.jcr.SlcTypes;\r
+import org.eclipse.jface.action.IMenuListener;\r
+import org.eclipse.jface.action.IMenuManager;\r
+import org.eclipse.jface.action.MenuManager;\r
+import org.eclipse.jface.viewers.ColumnLabelProvider;\r
+import org.eclipse.jface.viewers.DecoratingLabelProvider;\r
+import org.eclipse.jface.viewers.ILabelDecorator;\r
+import org.eclipse.jface.viewers.ISelectionChangedListener;\r
+import org.eclipse.jface.viewers.IStructuredContentProvider;\r
+import org.eclipse.jface.viewers.IStructuredSelection;\r
+import org.eclipse.jface.viewers.SelectionChangedEvent;\r
+import org.eclipse.jface.viewers.TableViewer;\r
+import org.eclipse.jface.viewers.TableViewerColumn;\r
+import org.eclipse.jface.viewers.TreeViewer;\r
+import org.eclipse.jface.viewers.Viewer;\r
+import org.eclipse.jface.viewers.ViewerDropAdapter;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.custom.SashForm;\r
+import org.eclipse.swt.dnd.DND;\r
+import org.eclipse.swt.dnd.DragSourceEvent;\r
+import org.eclipse.swt.dnd.DragSourceListener;\r
+import org.eclipse.swt.dnd.TextTransfer;\r
+import org.eclipse.swt.dnd.Transfer;\r
+import org.eclipse.swt.dnd.TransferData;\r
+import org.eclipse.swt.layout.FillLayout;\r
+import org.eclipse.swt.layout.GridData;\r
+import org.eclipse.swt.layout.GridLayout;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Display;\r
+import org.eclipse.swt.widgets.Menu;\r
+import org.eclipse.ui.ISharedImages;\r
+import org.eclipse.ui.IWorkbenchWindow;\r
+import org.eclipse.ui.part.ViewPart;\r
+\r
+/** SLC generic JCR Result tree view. */\r
+public class JcrResultTreeView extends ViewPart {\r
+       public final static String ID = ClientUiPlugin.ID + ".jcrResultTreeView";\r
+\r
+       private final static Log log = LogFactory.getLog(JcrResultTreeView.class);\r
+\r
+       /* DEPENDENCY INJECTION */\r
+       private Session session;\r
+\r
+       // This page widgets\r
+       private TreeViewer resultTreeViewer;\r
+       private TableViewer propertiesViewer;\r
+\r
+       private EventListener resultsObserver = null;\r
+\r
+       private final static String[] observedNodeTypes = { SlcTypes.SLC_TEST_RESULT };\r
+\r
+       /**\r
+        * To be overridden to adapt size of form and result frames.\r
+        */\r
+       protected int[] getWeights() {\r
+               return new int[] { 70, 30 };\r
+       }\r
+\r
+       @Override\r
+       public void createPartControl(Composite parent) {\r
+               parent.setLayout(new FillLayout());\r
+               // Main layout\r
+               SashForm sashForm = new SashForm(parent, SWT.VERTICAL);\r
+               sashForm.setSashWidth(4);\r
+               sashForm.setLayout(new FillLayout());\r
+\r
+               // Create the tree on top of the view\r
+               Composite top = new Composite(sashForm, SWT.NONE);\r
+               GridLayout gl = new GridLayout(1, false);\r
+               top.setLayout(gl);\r
+               resultTreeViewer = createResultsTreeViewer(top);\r
+\r
+               // Create the property viewer on the bottom\r
+               Composite bottom = new Composite(sashForm, SWT.NONE);\r
+               bottom.setLayout(new GridLayout(1, false));\r
+               propertiesViewer = createPropertiesViewer(bottom);\r
+\r
+               sashForm.setWeights(getWeights());\r
+\r
+               // Refresh the view to initialize it\r
+               refresh(null);\r
+\r
+               try {\r
+                       ObservationManager observationManager = session.getWorkspace()\r
+                                       .getObservationManager();\r
+                       // FIXME Will not be notified if empty result is deleted\r
+                       if (JcrUtils.getUserHome(session) != null) {\r
+                               resultsObserver = new ResultObserver(resultTreeViewer.getTree()\r
+                                               .getDisplay());\r
+                               observationManager.addEventListener(resultsObserver,\r
+                                               Event.PROPERTY_ADDED | Event.NODE_REMOVED, JcrUtils\r
+                                                               .getUserHome(session).getPath(), true, null,\r
+                                               observedNodeTypes, false);\r
+                       }\r
+               } catch (RepositoryException e) {\r
+                       throw new SlcException("Cannot register listeners", e);\r
+               }\r
+\r
+       }\r
+\r
+       // The main tree viewer\r
+       protected TreeViewer createResultsTreeViewer(Composite parent) {\r
+               int style = SWT.BORDER | SWT.MULTI;\r
+\r
+               TreeViewer viewer = new TreeViewer(parent, style);\r
+               viewer.getTree().setLayoutData(\r
+                               new GridData(SWT.FILL, SWT.FILL, true, true));\r
+\r
+               viewer.setContentProvider(new ResultTreeContentProvider());\r
+\r
+               // Add label provider with label decorator\r
+               ResultTreeLabelProvider rtLblProvider = new ResultTreeLabelProvider();\r
+               ILabelDecorator decorator = ClientUiPlugin.getDefault().getWorkbench()\r
+                               .getDecoratorManager().getLabelDecorator();\r
+               viewer.setLabelProvider(new DecoratingLabelProvider(rtLblProvider,\r
+                               decorator));\r
+               // viewer.setLabelProvider(rtLblProvider);\r
+               getSite().setSelectionProvider(viewer);\r
+\r
+               // add drag & drop support\r
+               int operations = DND.DROP_COPY | DND.DROP_MOVE;\r
+               Transfer[] tt = new Transfer[] { TextTransfer.getInstance() };\r
+               viewer.addDragSupport(operations, tt, new ViewDragListener());\r
+               viewer.addDropSupport(operations, tt, new ViewDropListener(viewer));\r
+\r
+               // add context menu\r
+               MenuManager menuManager = new MenuManager();\r
+               Menu menu = menuManager.createContextMenu(viewer.getTree());\r
+               menuManager.addMenuListener(new IMenuListener() {\r
+                       public void menuAboutToShow(IMenuManager manager) {\r
+                               contextMenuAboutToShow(manager);\r
+                       }\r
+               });\r
+               viewer.getTree().setMenu(menu);\r
+               getSite().registerContextMenu(menuManager, viewer);\r
+\r
+               // add change listener to display TestResult information in the property\r
+               // viewer\r
+               viewer.addSelectionChangedListener(new ISelectionChangedListener() {\r
+                       public void selectionChanged(SelectionChangedEvent event) {\r
+                               if (!event.getSelection().isEmpty()) {\r
+                                       IStructuredSelection sel = (IStructuredSelection) event\r
+                                                       .getSelection();\r
+                                       Object firstItem = sel.getFirstElement();\r
+                                       if (firstItem instanceof SingleResultNode)\r
+                                               propertiesViewer\r
+                                                               .setInput(((SingleResultNode) firstItem)\r
+                                                                               .getNode());\r
+                                       else\r
+                                               propertiesViewer.setInput(null);\r
+                               }\r
+                       }\r
+               });\r
+\r
+               return viewer;\r
+       }\r
+\r
+       // Detailed property viewer\r
+       protected TableViewer createPropertiesViewer(Composite parent) {\r
+               propertiesViewer = new TableViewer(parent);\r
+               propertiesViewer.getTable().setLayoutData(\r
+                               new GridData(SWT.FILL, SWT.FILL, true, true));\r
+               propertiesViewer.getTable().setHeaderVisible(true);\r
+               propertiesViewer.setContentProvider(new PropertiesContentProvider());\r
+               TableViewerColumn col = new TableViewerColumn(propertiesViewer,\r
+                               SWT.NONE);\r
+               col.getColumn().setText("Name");\r
+               col.getColumn().setWidth(200);\r
+               col.setLabelProvider(new ColumnLabelProvider() {\r
+                       public String getText(Object element) {\r
+                               try {\r
+                                       return ((Property) element).getName();\r
+                               } catch (RepositoryException e) {\r
+                                       throw new ArgeoException(\r
+                                                       "Unexpected exception in label provider", e);\r
+                               }\r
+                       }\r
+               });\r
+               col = new TableViewerColumn(propertiesViewer, SWT.NONE);\r
+               col.getColumn().setText("Value");\r
+               col.getColumn().setWidth(400);\r
+               col.setLabelProvider(new ColumnLabelProvider() {\r
+                       public String getText(Object element) {\r
+                               try {\r
+                                       Property property = (Property) element;\r
+                                       if (property.getType() == PropertyType.BINARY)\r
+                                               return "<binary>";\r
+                                       else if (property.isMultiple()) {\r
+                                               StringBuffer buf = new StringBuffer("[");\r
+                                               Value[] values = property.getValues();\r
+                                               for (int i = 0; i < values.length; i++) {\r
+                                                       if (i != 0)\r
+                                                               buf.append(", ");\r
+                                                       buf.append(values[i].getString());\r
+                                               }\r
+                                               buf.append(']');\r
+                                               return buf.toString();\r
+                                       } else\r
+                                               return property.getValue().getString();\r
+                               } catch (RepositoryException e) {\r
+                                       throw new ArgeoException(\r
+                                                       "Unexpected exception in label provider", e);\r
+                               }\r
+                       }\r
+               });\r
+               col = new TableViewerColumn(propertiesViewer, SWT.NONE);\r
+               col.getColumn().setText("Type");\r
+               col.getColumn().setWidth(200);\r
+               col.setLabelProvider(new ColumnLabelProvider() {\r
+                       public String getText(Object element) {\r
+                               try {\r
+                                       return PropertyType.nameFromValue(((Property) element)\r
+                                                       .getType());\r
+                               } catch (RepositoryException e) {\r
+                                       throw new ArgeoException(\r
+                                                       "Unexpected exception in label provider", e);\r
+                               }\r
+                       }\r
+               });\r
+               propertiesViewer.setInput(getViewSite());\r
+               return propertiesViewer;\r
+       }\r
+\r
+       @Override\r
+       public void setFocus() {\r
+       }\r
+\r
+       /**\r
+        * refreshes the passed node and its corresponding subtree.\r
+        * \r
+        * @param node\r
+        *            cannot be null\r
+        * \r
+        */\r
+       public boolean jcrRefresh(Node node) {\r
+               boolean isPassed = true;\r
+               try {\r
+                       if (node.isNodeType(SlcTypes.SLC_TEST_RESULT)) {\r
+                               isPassed = node.getNode(SlcNames.SLC_STATUS)\r
+                                               .getProperty(SlcNames.SLC_SUCCESS).getBoolean();\r
+                       } else if (node.isNodeType(SlcTypes.SLC_RESULT_FOLDER)) {\r
+                               NodeIterator ni = node.getNodes();\r
+                               // quicker but wrong : refresh will stop as soon as a failed\r
+                               // test is found and the whole tree won't be refreshed\r
+                               // while (isPassed && ni.hasNext()){\r
+                               while (ni.hasNext()) {\r
+                                       Node currChild = ni.nextNode();\r
+                                       isPassed = isPassed & jcrRefresh(currChild);\r
+                               }\r
+                               if (isPassed != node.getNode(SlcNames.SLC_STATUS)\r
+                                               .getProperty(SlcNames.SLC_SUCCESS).getBoolean()) {\r
+                                       node.getNode(SlcNames.SLC_STATUS).setProperty(\r
+                                                       SlcNames.SLC_SUCCESS, isPassed);\r
+                                       node.getSession().save();\r
+                                       return isPassed;\r
+                               }\r
+                       } else\r
+                               ; // do nothing\r
+               } catch (RepositoryException e) {\r
+                       throw new SlcException("Cannot register listeners", e);\r
+               }\r
+               return isPassed;\r
+       }\r
+\r
+       /**\r
+        * refreshes the passed resultParent and its corresponding subtree. It\r
+        * refreshes the whole viewer if null is passed.\r
+        * \r
+        * @param ResultParent\r
+        * \r
+        */\r
+       public void refresh(ResultParent resultParent) {\r
+               if (resultParent == null) {\r
+                       resultTreeViewer.setInput(initializeResultTree());\r
+                       if (resultsObserver == null) {\r
+                               // force initialization of the resultsObserver, only useful\r
+                               // if the current view has been displayed before a single\r
+                               // test has been run\r
+                               try {\r
+                                       ObservationManager observationManager = session\r
+                                                       .getWorkspace().getObservationManager();\r
+                                       resultsObserver = new ResultObserver(resultTreeViewer\r
+                                                       .getTree().getDisplay());\r
+                                       observationManager.addEventListener(resultsObserver,\r
+                                                       Event.PROPERTY_ADDED | Event.NODE_REMOVED, JcrUtils\r
+                                                                       .getUserHome(session).getPath(), true,\r
+                                                       null, observedNodeTypes, false);\r
+                               } catch (RepositoryException e) {\r
+                                       throw new SlcException("Cannot register listeners", e);\r
+                               }\r
+                       }\r
+\r
+               } else {\r
+                       // FIXME implement refresh for a specific ResultParent object.\r
+                       if (resultParent instanceof ResultFolder) {\r
+                               ResultFolder currFolder = (ResultFolder) resultParent;\r
+                               jcrRefresh(currFolder.getNode());\r
+                               currFolder.forceFullRefresh();\r
+                       }\r
+               }\r
+       }\r
+\r
+       private ResultParent[] initializeResultTree() {\r
+               ResultParent[] roots = new ResultParent[2];\r
+               try {\r
+                       roots[0] = new ResultFolder(null,\r
+                                       SlcJcrResultUtils.getMyResultParentNode(session),\r
+                                       "My results");\r
+                       Node otherResultsPar = session.getNode(SlcJcrResultUtils\r
+                                       .getSlcResultsBasePath(session));\r
+                       roots[1] = new SimpleNodeFolder(null, otherResultsPar,\r
+                                       "All results");\r
+                       return roots;\r
+               } catch (RepositoryException re) {\r
+                       throw new ArgeoException(\r
+                                       "Unexpected error while initializing ResultTree.", re);\r
+               }\r
+       }\r
+\r
+       // Manage context menu\r
+       /**\r
+        * Defines the commands that will pop up in the context menu.\r
+        **/\r
+       protected void contextMenuAboutToShow(IMenuManager menuManager) {\r
+               IWorkbenchWindow window = ClientUiPlugin.getDefault().getWorkbench()\r
+                               .getActiveWorkbenchWindow();\r
+\r
+               // Building conditions\r
+               IStructuredSelection selection = (IStructuredSelection) resultTreeViewer\r
+                               .getSelection();\r
+               boolean isMyResultFolder = false;\r
+               if (selection.size() == 1) {\r
+                       Object obj = selection.getFirstElement();\r
+                       try {\r
+                               Node targetParentNode = null;\r
+                               if (obj instanceof ResultFolder) {\r
+                                       targetParentNode = ((ResultFolder) obj).getNode();\r
+\r
+                                       if (targetParentNode.isNodeType(SlcTypes.SLC_RESULT_FOLDER))\r
+                                               isMyResultFolder = true;\r
+                               }\r
+                       } catch (RepositoryException re) {\r
+                               throw new SlcException(\r
+                                               "unexpected error while building condition for context menu",\r
+                                               re);\r
+                       }\r
+               }\r
+               // Effective Refresh\r
+               CommandUtils.refreshCommand(menuManager, window, AddResultFolder.ID,\r
+                               AddResultFolder.DEFAULT_LABEL,\r
+                               ClientUiPlugin.getDefault().getWorkbench().getSharedImages()\r
+                                               .getImageDescriptor(ISharedImages.IMG_OBJ_ADD),\r
+                               isMyResultFolder);\r
+       }\r
+\r
+       /* INNER CLASSES */\r
+       class ViewDragListener implements DragSourceListener {\r
+\r
+               public void dragStart(DragSourceEvent event) {\r
+                       // Check if the drag action should start.\r
+\r
+                       IStructuredSelection selection = (IStructuredSelection) resultTreeViewer\r
+                                       .getSelection();\r
+                       boolean doIt = false;\r
+                       // only one node at a time for the time being.\r
+                       if (selection.size() == 1) {\r
+                               Object obj = selection.getFirstElement();\r
+                               if (obj instanceof SingleResultNode) {\r
+                                       Node tNode = ((SingleResultNode) obj).getNode();\r
+                                       try {\r
+                                               if (tNode.getPrimaryNodeType().isNodeType(\r
+                                                               SlcTypes.SLC_TEST_RESULT)\r
+                                                               && (tNode.getPath()\r
+                                                                               .startsWith(SlcJcrResultUtils\r
+                                                                                               .getSlcResultsBasePath(session))))\r
+                                                       doIt = true;\r
+                                       } catch (RepositoryException re) {\r
+                                               throw new SlcException(\r
+                                                               "unexpected error while validating drag source",\r
+                                                               re);\r
+                                       }\r
+                               }\r
+                       }\r
+                       event.doit = doIt;\r
+               }\r
+\r
+               public void dragSetData(DragSourceEvent event) {\r
+                       IStructuredSelection selection = (IStructuredSelection) resultTreeViewer\r
+                                       .getSelection();\r
+                       Object obj = selection.getFirstElement();\r
+                       if (obj instanceof SingleResultNode) {\r
+                               Node first = ((SingleResultNode) obj).getNode();\r
+                               try {\r
+                                       event.data = first.getIdentifier();\r
+                               } catch (RepositoryException re) {\r
+                                       throw new SlcException(\r
+                                                       "unexpected error while setting data", re);\r
+                               }\r
+                       }\r
+               }\r
+\r
+               public void dragFinished(DragSourceEvent event) {\r
+                       // implement here tree refresh in case of a move.\r
+               }\r
+       }\r
+\r
+       // Implementation of the Drop Listener\r
+       protected class ViewDropListener extends ViewerDropAdapter {\r
+\r
+               private Node currParentNode = null;\r
+\r
+               public ViewDropListener(Viewer viewer) {\r
+                       super(viewer);\r
+               }\r
+\r
+               @Override\r
+               public boolean validateDrop(Object target, int operation,\r
+                               TransferData transferType) {\r
+                       boolean validDrop = false;\r
+                       try {\r
+                               // We can only drop under myResults\r
+                               Node targetParentNode = null;\r
+                               if (target instanceof ResultFolder) {\r
+                                       Node currNode = ((ResultFolder) target).getNode();\r
+\r
+                                       if (currNode.isNodeType(SlcTypes.SLC_RESULT_FOLDER)) {\r
+                                               targetParentNode = currNode;\r
+                                       }\r
+                               } else if (target instanceof SingleResultNode) {\r
+                                       Node currNode = ((SingleResultNode) target).getNode();\r
+                                       if (currNode.getParent().isNodeType(\r
+                                                       SlcTypes.SLC_RESULT_FOLDER))\r
+                                               targetParentNode = currNode.getParent();\r
+                               }\r
+                               if (targetParentNode != null) {\r
+                                       currParentNode = targetParentNode;\r
+                                       validDrop = true;\r
+                               }\r
+                       } catch (RepositoryException re) {\r
+                               throw new SlcException(\r
+                                               "unexpected error while validating drop target", re);\r
+                       }\r
+                       return validDrop;\r
+               }\r
+\r
+               @Override\r
+               public boolean performDrop(Object data) {\r
+\r
+                       try {\r
+                               Node source = session.getNodeByIdentifier((String) data);\r
+                               Node target = currParentNode.addNode(source.getName(), source\r
+                                               .getPrimaryNodeType().getName());\r
+                               JcrUtils.copy(source, target);\r
+                               updatePassedStatus(target, target.getNode(SlcNames.SLC_STATUS)\r
+                                               .getProperty(SlcNames.SLC_SUCCESS).getBoolean());\r
+                               target.getSession().save();\r
+                       } catch (RepositoryException re) {\r
+                               throw new SlcException(\r
+                                               "unexpected error while copying dropped node", re);\r
+                       }\r
+                       return true;\r
+               }\r
+\r
+               /**\r
+                * recursively update passed status of the parent ResultFolder and its\r
+                * parent if needed\r
+                * \r
+                * @param node\r
+                *            cannot be null\r
+                * \r
+                */\r
+               private void updatePassedStatus(Node node, boolean passed) {\r
+                       try {\r
+                               Node pNode = node.getParent();\r
+                               boolean pStatus = pNode.getNode(SlcNames.SLC_STATUS)\r
+                                               .getProperty(SlcNames.SLC_SUCCESS).getBoolean();\r
+                               if (pStatus == passed)\r
+                                       // nothing to update\r
+                                       return;\r
+                               else if (!passed) {\r
+                                       // error we only update status of the result folder and its\r
+                                       // parent if needed\r
+                                       pNode.getNode(SlcNames.SLC_STATUS).setProperty(\r
+                                                       SlcNames.SLC_SUCCESS, passed);\r
+                                       updatePassedStatus(pNode, passed);\r
+                               } else {\r
+                                       // success we must first check if all siblings have also\r
+                                       // successfully completed\r
+                                       boolean success = true;\r
+                                       NodeIterator ni = pNode.getNodes();\r
+                                       children: while (ni.hasNext()) {\r
+                                               Node currNode = ni.nextNode();\r
+                                               if ((currNode.isNodeType(SlcTypes.SLC_DIFF_RESULT) || currNode\r
+                                                               .isNodeType(SlcTypes.SLC_RESULT_FOLDER))\r
+                                                               && !currNode.getNode(SlcNames.SLC_STATUS)\r
+                                                                               .getProperty(SlcNames.SLC_SUCCESS)\r
+                                                                               .getBoolean()) {\r
+                                                       success = false;\r
+                                                       break children;\r
+                                               }\r
+                                       }\r
+                                       if (success) {\r
+                                               pNode.getNode(SlcNames.SLC_STATUS).setProperty(\r
+                                                               SlcNames.SLC_SUCCESS, passed);\r
+                                               updatePassedStatus(pNode, passed);\r
+                                       } else\r
+                                               // one of the siblings had also the failed status so\r
+                                               // above tree remains unchanged.\r
+                                               return;\r
+                               }\r
+\r
+                       } catch (RepositoryException e) {\r
+                               throw new SlcException("Cannot register listeners", e);\r
+                       }\r
+               }\r
+       }\r
+\r
+       class ResultObserver extends AsyncUiEventListener {\r
+\r
+               public ResultObserver(Display display) {\r
+                       super(display);\r
+               }\r
+\r
+               @Override\r
+               protected Boolean willProcessInUiThread(List<Event> events)\r
+                               throws RepositoryException {\r
+                       for (Event event : events) {\r
+                               // getLog().debug("Received event " + event);\r
+                               int eventType = event.getType();\r
+                               if (eventType == Event.NODE_REMOVED)\r
+                                       return true;\r
+                               String path = event.getPath();\r
+                               int index = path.lastIndexOf('/');\r
+                               String propertyName = path.substring(index + 1);\r
+                               if (propertyName.equals(SlcNames.SLC_COMPLETED)\r
+                                               || propertyName.equals(SlcNames.SLC_UUID)) {\r
+                                       return true;\r
+                               }\r
+                       }\r
+                       return false;\r
+               }\r
+\r
+               protected void onEventInUiThread(List<Event> events)\r
+                               throws RepositoryException {\r
+                       // FIXME implement correct behaviour. treeViewer selection is\r
+                       // disposed by the drag & drop.\r
+                       // resultTreeViewer.refresh();\r
+                       // refresh(null);\r
+                       // log.warn("Implement refresh.");\r
+               }\r
+\r
+       }\r
+\r
+       class PropertiesContentProvider implements IStructuredContentProvider {\r
+               // private JcrItemsComparator itemComparator = new JcrItemsComparator();\r
+\r
+               public void dispose() {\r
+               }\r
+\r
+               public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {\r
+               }\r
+\r
+               public Object[] getElements(Object inputElement) {\r
+                       try {\r
+                               if (inputElement instanceof Node) {\r
+                                       List<Property> props = new ArrayList<Property>();\r
+                                       PropertyIterator pit = ((Node) inputElement)\r
+                                                       .getProperties();\r
+                                       while (pit.hasNext())\r
+                                               props.add(pit.nextProperty());\r
+                                       return props.toArray();\r
+                               }\r
+                               return new Object[] {};\r
+                       } catch (RepositoryException e) {\r
+                               throw new ArgeoException("Cannot get element for "\r
+                                               + inputElement, e);\r
+                       }\r
+               }\r
+       }\r
+\r
+       /* DEPENDENCY INJECTION */\r
+       public void setSession(Session session) {\r
+               this.session = session;\r
+       }\r
+\r
+}\r
index f96e88ea7fc090fadfb5488698db9d6d57e5ccf9..818d4f333bbc7d2f5f11fea705519cf8daa83fa1 100644 (file)
@@ -38,13 +38,13 @@ import org.argeo.slc.test.TestResultPart;
 import org.argeo.slc.test.TestRun;
 import org.argeo.slc.test.TestStatus;
 
-/** {@link TestResult} wrapping a JCR node of type {@link SlcTypes#SLC_RESULT}. */
+/** {@link TestResult} wrapping a JCR node of type {@link SlcTypes#SLC_TEST_RESULT}. */
 public class JcrTestResult implements TestResult, SlcNames, AttachmentsEnabled {
        /** Should only be set for an already existing result. */
        private String uuid;
        private Repository repository;
        private Session session;
-       private String resultType = SlcTypes.SLC_RESULT;
+       private String resultType = SlcTypes.SLC_TEST_RESULT;
 
        /** cached for performance purposes */
        private String nodeIdentifier = null;
@@ -93,7 +93,8 @@ public class JcrTestResult implements TestResult, SlcNames, AttachmentsEnabled {
                        } else {
                                QueryManager qm = session.getWorkspace().getQueryManager();
                                Query q = qm.createQuery(
-                                               "select * from [slc:result] where [slc:uuid]='" + uuid
+                                               "select * from [" + SlcTypes.SLC_TEST_RESULT
+                                               + "] where [slc:uuid]='" + uuid
                                                                + "'", Query.JCR_SQL2);
                                resultNode = JcrUtils.querySingleNode(q);
                                if (resultNode != null)
@@ -111,9 +112,7 @@ public class JcrTestResult implements TestResult, SlcNames, AttachmentsEnabled {
        public void addResultPart(TestResultPart testResultPart) {
                Node node = getNode();
                try {
-                       // TODO: find a better way to name it by default
-                       String partName = Long.toString(System.currentTimeMillis());
-                       Node resultPartNode = node.addNode(partName, SlcTypes.SLC_CHECK);
+                       Node resultPartNode = node.addNode(SlcNames.SLC_STATUS, SlcTypes.SLC_CHECK);
                        resultPartNode.setProperty(SLC_SUCCESS,
                                        testResultPart.getStatus() == TestStatus.PASSED);
                        if (testResultPart.getMessage() != null)
index a1e42f49b95d338b8c7fb03a580eb1c5d1d66bdc..6c36aa949527bf94bfd76814238f3ac0d702cafa 100644 (file)
@@ -22,8 +22,13 @@ public interface SlcJcrConstants {
        public final static String PROCESSES_BASE_PATH = SLC_BASE_PATH
                        + "/slc:processes";
        public final static String AGENTS_BASE_PATH = SLC_BASE_PATH + "/slc:agents";
-       public final static String RESULTS_BASE_PATH = SLC_BASE_PATH
-                       + "/slc:results";
+       // public final static String RESULTS_BASE_PATH = SLC_BASE_PATH
+       // + "/slc:results";
        public final static String VM_AGENT_FACTORY_PATH = AGENTS_BASE_PATH
                        + "/slc:vm";
+       
+       /*
+        * SLC SPECIFIC JCR PATHS
+        */
+       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
new file mode 100644 (file)
index 0000000..9546c35
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2007-2012 Mathieu Baudier
+ *
+ * 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.jcr;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.argeo.ArgeoException;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.slc.SlcException;
+
+/**
+ * Utilities around the SLC JCR Result model. Note that it relies on fixed base
+ * paths (convention over configuration) for optimization purposes.
+ */
+public class SlcJcrResultUtils {
+
+       /**
+        * Returns the path to the current slc:result node
+        */
+       public static String getSlcResultsBasePath(Session session) {
+               try {
+
+                       return JcrUtils.getUserHome(session).getPath() + "/"
+                                       + SlcNames.SLC_RESULTS;
+               } catch (RepositoryException re) {
+                       throw new ArgeoException(
+                                       "Unexpected error while getting Slc Results Base Path.", re);
+               }
+       }
+
+       /**
+        * Returns the path to the current Result UI specific node, depending the
+        * current user
+        */
+       public static String getMyResultsBasePath(Session session) {
+               try {
+                       return JcrUtils.getUserHome(session).getPath() + "/"
+                                       + SlcJcrConstants.SLC_MYRESULT_BASEPATH;
+               } catch (RepositoryException re) {
+                       throw new ArgeoException(
+                                       "Unexpected error while getting Slc Results Base Path.", re);
+               }
+       }
+
+       public static Node getMyResultParentNode(Session session) {
+               try {
+                       if (session.nodeExists(SlcJcrResultUtils
+                                       .getMyResultsBasePath(session)))
+                               return session.getNode(getMyResultsBasePath(session));
+                       else
+                               return createResultFolderNode(session,
+                                               getMyResultsBasePath(session));
+               } catch (RepositoryException re) {
+                       throw new ArgeoException(
+                                       "Unexpected error while creating user MyResult base node.",
+                                       re);
+               }
+
+       }
+
+       /**
+        * Creates a new node with type SlcTypes.SLC_RESULT_FOLDER 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
+        * @param absPath
+        * @return
+        */
+       public static synchronized Node createResultFolderNode(Session session,
+                       String absPath) {
+               try {
+                       if (session.nodeExists(absPath)) {
+                               // Sanity check
+                               Node currNode = session.getNode(absPath);
+                               if (currNode.isNodeType(SlcTypes.SLC_RESULT_FOLDER))
+                                       return currNode;
+                               else
+                                       throw new SlcException(
+                                                       "A node already exists at this path : " + absPath
+                                                                       + " that has the wrong type. ");
+                       }
+                       Node rfNode = JcrUtils.mkdirs(session, absPath);
+                       rfNode.setPrimaryType(SlcTypes.SLC_RESULT_FOLDER);
+                       Node statusNode = rfNode.addNode(SlcNames.SLC_STATUS,
+                                       SlcTypes.SLC_CHECK);
+                       statusNode.setProperty(SlcNames.SLC_SUCCESS, true);
+                       session.save();
+                       return rfNode;
+               } catch (RepositoryException re) {
+                       throw new ArgeoException(
+                                       "Unexpected error while creating Result Folder node.", re);
+               }
+       }
+}
\ No newline at end of file
index 96b3d9e4d963a237999b3f04db4562f50456faf0..25f830d97839119023be83ab1435debfa499bbb4 100644 (file)
@@ -31,10 +31,11 @@ public interface SlcTypes {
        public final static String SLC_PRIMITIVE_SPEC_ATTRIBUTE = "slc:primitiveSpecAttribute";
        public final static String SLC_REF_SPEC_ATTRIBUTE = "slc:refSpecAttribute";
 
-       public final static String SLC_RESULT = "slc:result";
+       public final static String SLC_TEST_RESULT = "slc:testResult";
        public final static String SLC_CHECK = "slc:check";
        public final static String SLC_PROPERTY = "slc:property";
        public final static String SLC_DIFF_RESULT = "slc:diffResult";
+       public final static String SLC_RESULT_FOLDER = "slc:resultFolder";
 
        // Log levels
        public final static String SLC_LOG_ENTRY = "slc:logEntry";
@@ -60,7 +61,7 @@ public interface SlcTypes {
        public final static String SLC_DYNAMIC_IMPORTED_PACKAGE = "slc:dynamicImportedPackage";
        public final static String SLC_REQUIRED_BUNDLE = "slc:requiredBundle";
        public final static String SLC_FRAGMENT_HOST = "slc:fragmentHost";
-       
+
        // origin
        public final static String SLC_KNOWN_ORIGIN = "slc:knownOrigin";
        public final static String SLC_PROXIED = "slc:proxied";
index 12ade515dcc7d772f5c49671a029747bb5b6ef69..b5af2c8ec0d8aa5031811664ce4ec4b0a0ee493c 100644 (file)
@@ -169,7 +169,7 @@ public class JcrResultListener implements TreeTestResultListener, SlcNames {
                        throws RepositoryException {
                String uuid = testResult.getUuid();
                String path = SlcJcrUtils.createResultPath(session.getUserID(), uuid);
-               Node resultNode = JcrUtils.mkdirs(session, path, SlcTypes.SLC_RESULT);
+               Node resultNode = JcrUtils.mkdirs(session, path, SlcTypes.SLC_TEST_RESULT);
                resultNode.setProperty(SLC_UUID, uuid);
                for (Map.Entry<String, String> entry : testResult.getAttributes()
                                .entrySet()) {
index 4e8a4e68889d5d4e1484658b65fa9aa147e1c218..f527902cb73bba47e88bf125df51795ce2abf315 100644 (file)
@@ -95,15 +95,21 @@ mixin
 + * (slc:executionSpecAttribute) *
 
 // RESULT
-[slc:result] > nt:unstructured, mix:created, mix:lastModified
+[slc:testResult] > nt:unstructured, mix:created, mix:lastModified
 - slc:uuid (STRING) ! m
 - slc:testCase (STRING)
 - slc:completed (DATE)
++ slc:testStatus (slc:check)
 
-[slc:diffResult] > slc:result
+[slc:diffResult] > slc:testResult
 + slc:summary
 + slc:issues
 
+[slc:resultFolder] > nt:unstructured
++ slc:folderStatus (slc:check)
++ * (slc:resultFolder) *
++ * (slc:testResult) *
+
 [slc:check] > nt:unstructured
 // true for PASSED, false for FAILED or ERROR
 - slc:success (BOOLEAN) ! m