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"
--- /dev/null
+/*
+ * 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";
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*\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
--- /dev/null
+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
+/*
+ * 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;
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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();
+
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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.
+ }
+
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+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
--- /dev/null
+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;
+ }
+}
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;
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);
}
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
public void setSession(Session session) {
this.session = session;
}
-
}
\ No newline at end of file
--- /dev/null
+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
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;
} 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)
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)
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/";
}
--- /dev/null
+/*
+ * 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
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";
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";
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()) {
+ * (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