From 2bdb18c75fc87cd78ed18843149c469c180f3830 Mon Sep 17 00:00:00 2001 From: Bruno Sinou Date: Wed, 7 Nov 2012 23:57:05 +0000 Subject: [PATCH] enhance result tree viewer git-svn-id: https://svn.argeo.org/slc/trunk@5739 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- .../org.argeo.slc.client.ui/icons/rename.png | Bin 0 -> 237 bytes plugins/org.argeo.slc.client.ui/plugin.xml | 10 + .../org/argeo/slc/client/ui/SlcImages.java | 1 + .../client/ui/commands/AddResultFolder.java | 2 - .../slc/client/ui/commands/DeleteResult.java | 1 - .../ui/commands/RenameResultFolder.java | 76 ++++ .../client/ui/commands/RenameResultNode.java | 90 +++++ .../ui/decorators/ResultFailedDecorator.java | 2 +- .../slc/client/ui/model/ParentNodeFolder.java | 24 +- .../slc/client/ui/model/ResultFolder.java | 50 +-- .../slc/client/ui/model/ResultParent.java | 14 +- .../client/ui/model/ResultParentUtils.java | 2 +- .../slc/client/ui/model/SingleResultNode.java | 12 +- .../ui/providers/ResultTreeLabelProvider.java | 19 +- .../client/ui/views/JcrResultTreeView.java | 327 +++++++++++------- .../ui/wizards/ConfirmOverwriteWizard.java | 184 ++++++++++ 16 files changed, 621 insertions(+), 193 deletions(-) create mode 100644 plugins/org.argeo.slc.client.ui/icons/rename.png create mode 100644 plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/commands/RenameResultFolder.java create mode 100644 plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/commands/RenameResultNode.java create mode 100644 plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/wizards/ConfirmOverwriteWizard.java diff --git a/plugins/org.argeo.slc.client.ui/icons/rename.png b/plugins/org.argeo.slc.client.ui/icons/rename.png new file mode 100644 index 0000000000000000000000000000000000000000..a3884177f2c8dc70bd7b132b49bdffaca5cb582b GIT binary patch literal 237 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFP2=EDU70I=fEU}ZTaaL*e(Cqfr zn;2v?J=An|#I&7Zt4{^3Jsx%JYQp(D$=4sG{Qv(SsHs`i{sfTXFA4Gs28tj7hAVew zECfn1CV9KN@JsAsxC!KN7I;J!18EO1b~~AE2V_`#x;Tb#Tu-iGXXRm$cxvF5Cf6b; zWi5K9!sz)KPkVvGMc?1amMOFyQ(CLGVM@!K7MU3z8P+sU5LIAcFq6zO`FQ7l9ncsC MPgg&ebxsLQ028QH)&Kwi literal 0 HcmV?d00001 diff --git a/plugins/org.argeo.slc.client.ui/plugin.xml b/plugins/org.argeo.slc.client.ui/plugin.xml index e77f45899..85f5bf4b5 100644 --- a/plugins/org.argeo.slc.client.ui/plugin.xml +++ b/plugins/org.argeo.slc.client.ui/plugin.xml @@ -43,6 +43,16 @@ id="org.argeo.slc.client.ui.addResultFolder" name="Add result folder"> + + + + lst = ((IStructuredSelection) selection).iterator(); while (lst.hasNext()) { Object obj = lst.next(); - if (obj instanceof ResultParent) { ResultParent rp = ((ResultParent) obj); buf.append(rp.getName()).append(", "); diff --git a/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/commands/RenameResultFolder.java b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/commands/RenameResultFolder.java new file mode 100644 index 000000000..739c5039d --- /dev/null +++ b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/commands/RenameResultFolder.java @@ -0,0 +1,76 @@ +/* + * 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 javax.jcr.Session; + +import org.argeo.eclipse.ui.dialogs.SingleValue; +import org.argeo.jcr.JcrUtils; +import org.argeo.slc.SlcException; +import org.argeo.slc.client.ui.ClientUiPlugin; +import org.argeo.slc.client.ui.model.ResultFolder; +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.ui.handlers.HandlerUtil; + +/** + * Rename a node of type SlcType.SLC_RESULT_FOLDER by moving it. + */ + +public class RenameResultFolder extends AbstractHandler { + public final static String ID = ClientUiPlugin.ID + ".renameResultFolder"; + public final static ImageDescriptor DEFAULT_IMG_DESCRIPTOR = ClientUiPlugin + .getImageDescriptor("icons/rename.png"); + public final static String DEFAULT_LABEL = "Rename 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) { + Object obj = selection.getFirstElement(); + try { + if (obj instanceof ResultFolder) { + ResultFolder rf = (ResultFolder) obj; + Node sourceNode = rf.getNode(); + String folderName = SingleValue.ask("Rename folder", + "Enter a new folder name"); + if (folderName != null) { + String sourcePath = sourceNode.getPath(); + String targetPath = JcrUtils.parentPath(sourcePath) + + "/" + folderName; + Session session = sourceNode.getSession(); + session.move(sourcePath, targetPath); + session.save(); + } + } + } catch (RepositoryException e) { + throw new SlcException( + "Unexpected exception while refactoring result folder", + e); + } + } + 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/RenameResultNode.java b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/commands/RenameResultNode.java new file mode 100644 index 000000000..86cbed55a --- /dev/null +++ b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/commands/RenameResultNode.java @@ -0,0 +1,90 @@ +/* + * 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.Property; +import javax.jcr.RepositoryException; +import javax.jcr.Session; + +import org.argeo.eclipse.ui.dialogs.SingleValue; +import org.argeo.jcr.JcrUtils; +import org.argeo.slc.SlcException; +import org.argeo.slc.client.ui.ClientUiPlugin; +import org.argeo.slc.client.ui.model.SingleResultNode; +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.handlers.HandlerUtil; + +/** + * Rename a node of type SlcType.SLC_RESULT_FOLDER by moving it. + */ + +public class RenameResultNode extends AbstractHandler { + public final static String ID = ClientUiPlugin.ID + ".renameResultNode"; + public final static ImageDescriptor DEFAULT_IMG_DESCRIPTOR = ClientUiPlugin + .getImageDescriptor("icons/rename.png"); + public final static String DEFAULT_LABEL = "Rename result"; + + 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) { + Object obj = selection.getFirstElement(); + try { + if (obj instanceof SingleResultNode) { + SingleResultNode rf = (SingleResultNode) obj; + Node sourceNode = rf.getNode(); + String folderName = SingleValue.ask("Rename result", + "Enter a new result name"); + if (folderName != null) { + + if (sourceNode.getParent().hasNode(folderName)) { + MessageDialog + .openError(Display.getDefault() + .getActiveShell(), "Error", + "Another object with the same name already exists."); + return null; + } + + String sourcePath = sourceNode.getPath(); + String targetPath = JcrUtils.parentPath(sourcePath) + + "/" + folderName; + Session session = sourceNode.getSession(); + session.move(sourcePath, targetPath); + session.getNode(targetPath).setProperty( + Property.JCR_TITLE, folderName); + session.save(); + } + } + } catch (RepositoryException e) { + throw new SlcException( + "Unexpected exception while refactoring result folder", + e); + } + } + 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/decorators/ResultFailedDecorator.java b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/decorators/ResultFailedDecorator.java index 7878f85a2..adadabbaf 100644 --- a/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/decorators/ResultFailedDecorator.java +++ b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/decorators/ResultFailedDecorator.java @@ -81,7 +81,7 @@ public class ResultFailedDecorator extends LabelProvider implements .getTime()); } catch (RepositoryException re) { throw new SlcException( - "Unexpected defining text decoration for result", re); + "Unexpected error defining text decoration for result", re); } return label + " [" + decoration + "]"; } else diff --git a/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/ParentNodeFolder.java b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/ParentNodeFolder.java index 91163c842..93cef51cd 100644 --- a/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/ParentNodeFolder.java +++ b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/ParentNodeFolder.java @@ -20,18 +20,28 @@ import javax.jcr.NodeIterator; import javax.jcr.RepositoryException; import javax.jcr.nodetype.NodeType; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.argeo.slc.SlcException; import org.argeo.slc.jcr.SlcJcrResultUtils; import org.argeo.slc.jcr.SlcNames; import org.argeo.slc.jcr.SlcTypes; /** - * UI Tree component that wrap a node of type NT_UNSTRUCTURED. list either - * result folders, other folders and/or a list of results. keeps a reference to - * its parent. + * UI Tree component that wrap a node of type NT_UNSTRUCTURED. + * + * It is used for + * + * It thus lists either result folders, other folders and/or a list of results + * and keeps a reference to its parent. */ public class ParentNodeFolder extends ResultParent { - + private final static Log log = LogFactory.getLog(ParentNodeFolder.class); + private Node node = null; /** @@ -65,13 +75,17 @@ public class ParentNodeFolder extends ResultParent { ResultFolder rf = new ResultFolder(this, currNode, currNode.getName()); addChild(rf); + } else if (currNode.isNodeType(SlcTypes.SLC_CHECK)) { + // FIXME : manually skip node types that are not to be + // displayed + // Do nothing } else if (currNode.isNodeType(NodeType.NT_UNSTRUCTURED)) addChild(new ParentNodeFolder(this, currNode, currNode.getName())); } } catch (RepositoryException re) { throw new SlcException( - "Unexpected error while initializing simple node folder : " + "Unexpected error while initializing ParentNodeFolder : " + getName(), re); } } diff --git a/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/ResultFolder.java b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/ResultFolder.java index a5c43168e..f48c5713f 100644 --- a/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/ResultFolder.java +++ b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/ResultFolder.java @@ -16,20 +16,17 @@ 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 implements Comparable { - - private Node node = null; +public class ResultFolder extends ParentNodeFolder implements + Comparable { /** * @@ -38,13 +35,9 @@ public class ResultFolder extends ResultParent implements Comparable second = Collections.reverseOrder(); Collections.sort(results); - Object[] orderedChildren = new Object[children.length]; + Object[] orderedChildren = new Object[folders.size() + results.size()]; int i = 0; Iterator it = folders.iterator(); while (it.hasNext()) { diff --git a/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/SingleResultNode.java b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/SingleResultNode.java index aa4acea9c..c557d7ea0 100644 --- a/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/SingleResultNode.java +++ b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/model/SingleResultNode.java @@ -49,9 +49,15 @@ public class SingleResultNode extends ResultParent implements public boolean refreshPassedStatus() { try { - Node check = node.getNode(SlcNames.SLC_STATUS); - passed = check.getProperty(SlcNames.SLC_SUCCESS).getBoolean(); - return passed; + Node check; + if (node.hasNode(SlcNames.SLC_STATUS)) { + check = node.getNode(SlcNames.SLC_STATUS); + passed = check.getProperty(SlcNames.SLC_SUCCESS).getBoolean(); + return passed; + } else + // Happens only if the UI triggers a refresh while the execution + // is in progress and the corresponding node is being built + return false; } catch (RepositoryException re) { throw new SlcException( "Unexpected error while checking result status", re); 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 index bae1c9dc0..b901a8097 100644 --- 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 @@ -1,6 +1,12 @@ package org.argeo.slc.client.ui.providers; +import javax.jcr.Node; +import javax.jcr.Property; +import javax.jcr.RepositoryException; +import javax.jcr.nodetype.NodeType; + import org.argeo.eclipse.ui.TreeParent; +import org.argeo.slc.SlcException; import org.argeo.slc.client.ui.SlcImages; import org.argeo.slc.client.ui.SlcUiConstants; import org.argeo.slc.client.ui.model.ResultParent; @@ -15,6 +21,16 @@ public class ResultTreeLabelProvider extends LabelProvider { @Override public String getText(Object element) { + if (element instanceof SingleResultNode) { + Node node = ((SingleResultNode) element).getNode(); + try { + if (node.isNodeType(NodeType.MIX_TITLE)) + return node.getProperty(Property.JCR_TITLE).getString(); + } catch (RepositoryException e) { + throw new SlcException("Unexpected error while getting " + + "custom result label", e); + } + } return ((TreeParent) element).getName(); } @@ -27,7 +43,8 @@ public class ResultTreeLabelProvider extends LabelProvider { return SlcImages.PROCESS_COMPLETED; } else if (obj instanceof ResultParent) { ResultParent rParent = (ResultParent) obj; - if (SlcUiConstants.DEFAULT_MY_RESULTS_FOLDER_LABEL.equals(rParent.getName())) + if (SlcUiConstants.DEFAULT_MY_RESULTS_FOLDER_LABEL.equals(rParent + .getName())) return SlcImages.MY_RESULTS_FOLDER; else return SlcImages.FOLDER; diff --git a/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/views/JcrResultTreeView.java b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/views/JcrResultTreeView.java index bef8f2082..798e6f258 100644 --- a/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/views/JcrResultTreeView.java +++ b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/views/JcrResultTreeView.java @@ -17,6 +17,8 @@ import javax.jcr.observation.Event; import javax.jcr.observation.EventListener; import javax.jcr.observation.ObservationManager; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.argeo.ArgeoException; import org.argeo.eclipse.ui.jcr.AsyncUiEventListener; import org.argeo.eclipse.ui.utils.CommandUtils; @@ -26,6 +28,8 @@ import org.argeo.slc.SlcException; import org.argeo.slc.client.ui.ClientUiPlugin; import org.argeo.slc.client.ui.SlcUiConstants; import org.argeo.slc.client.ui.commands.AddResultFolder; +import org.argeo.slc.client.ui.commands.RenameResultFolder; +import org.argeo.slc.client.ui.commands.RenameResultNode; import org.argeo.slc.client.ui.editors.ProcessEditor; import org.argeo.slc.client.ui.editors.ProcessEditorInput; import org.argeo.slc.client.ui.model.ParentNodeFolder; @@ -36,6 +40,7 @@ import org.argeo.slc.client.ui.model.SingleResultNode; import org.argeo.slc.client.ui.model.VirtualFolder; import org.argeo.slc.client.ui.providers.ResultTreeContentProvider; import org.argeo.slc.client.ui.providers.ResultTreeLabelProvider; +import org.argeo.slc.client.ui.wizards.ConfirmOverwriteWizard; import org.argeo.slc.jcr.SlcJcrResultUtils; import org.argeo.slc.jcr.SlcNames; import org.argeo.slc.jcr.SlcTypes; @@ -53,9 +58,11 @@ import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TableViewerColumn; +import org.eclipse.jface.viewers.TreePath; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerDropAdapter; +import org.eclipse.jface.wizard.WizardDialog; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.SashForm; import org.eclipse.swt.dnd.DND; @@ -80,8 +87,7 @@ import org.eclipse.ui.part.ViewPart; public class JcrResultTreeView extends ViewPart { public final static String ID = ClientUiPlugin.ID + ".jcrResultTreeView"; - // private final static Log log = - // LogFactory.getLog(JcrResultTreeView.class); + private final static Log log = LogFactory.getLog(JcrResultTreeView.class); /* DEPENDENCY INJECTION */ private Session session; @@ -96,10 +102,16 @@ public class JcrResultTreeView extends ViewPart { SlcTypes.SLC_TEST_RESULT, SlcTypes.SLC_RESULT_FOLDER, NodeType.NT_UNSTRUCTURED }; - // FIXME cache to ease refresh after D&D + // FIXME cache to ease D&D + private boolean isActionUnderMyResult = false; private ResultParent lastSelectedTargetElement; - private ResultParent lastSelectedTargetElementParent; + private ResultParent lastSelectedSourceElement; private ResultParent lastSelectedSourceElementParent; + private boolean isResultFolder = false; + + // FIXME we cache the fact that we are moving a node to avoid exception + // triggered by the "Add Node" event while moving + // boolean isMoveInProgress = false; /** * To be overridden to adapt size of form and result frames. @@ -173,24 +185,7 @@ public class JcrResultTreeView extends ViewPart { // add change listener to display TestResult information in the property // viewer - viewer.addSelectionChangedListener(new ISelectionChangedListener() { - public void selectionChanged(SelectionChangedEvent event) { - if (!event.getSelection().isEmpty()) { - IStructuredSelection sel = (IStructuredSelection) event - .getSelection(); - Object firstItem = sel.getFirstElement(); - if (firstItem instanceof SingleResultNode) - propertiesViewer - .setInput(((SingleResultNode) firstItem) - .getNode()); - else - propertiesViewer.setInput(null); - lastSelectedTargetElement = (ResultParent) firstItem; - lastSelectedTargetElementParent = (ResultParent) ((ResultParent) firstItem) - .getParent(); - } - } - }); + viewer.addSelectionChangedListener(new MySelectionChangedListener()); return viewer; } @@ -345,7 +340,8 @@ public class JcrResultTreeView extends ViewPart { resultsObserver = new ResultObserver(resultTreeViewer .getTree().getDisplay()); observationManager.addEventListener(resultsObserver, - Event.NODE_ADDED | Event.NODE_REMOVED, UserJcrUtils + Event.NODE_MOVED | Event.NODE_ADDED + | Event.NODE_REMOVED, UserJcrUtils .getUserHome(session).getPath(), true, null, observedNodeTypes, false); } catch (RepositoryException e) { @@ -354,13 +350,16 @@ public class JcrResultTreeView extends ViewPart { } } else { - // FIXME implement refresh for a specific ResultParent object. - if (resultParent instanceof ResultFolder) { - ResultFolder currFolder = (ResultFolder) resultParent; + if (resultParent instanceof ParentNodeFolder) { + ParentNodeFolder currFolder = (ParentNodeFolder) resultParent; jcrRefresh(currFolder.getNode()); currFolder.forceFullRefresh(); - resultTreeViewer.refresh(lastSelectedTargetElement); } + // FIXME: specific refresh does not work + // resultTreeViewer.refresh(currFolder, true); + TreePath[] tps = resultTreeViewer.getExpandedTreePaths(); + resultTreeViewer.setInput(initializeResultTree()); + resultTreeViewer.setExpandedTreePaths(tps); } } @@ -433,19 +432,24 @@ public class JcrResultTreeView extends ViewPart { // Building conditions IStructuredSelection selection = (IStructuredSelection) resultTreeViewer .getSelection(); - boolean isMyResultFolder = false; + boolean canAddSubfolder = false; + boolean isSingleResultNode = false; if (selection.size() == 1) { Object obj = selection.getFirstElement(); try { - if (obj instanceof ResultFolder - && (((ResultFolder) obj).getNode()) - .isNodeType(SlcTypes.SLC_RESULT_FOLDER)) - isMyResultFolder = true; + // if (obj instanceof ResultFolder + // && (((ResultFolder) obj).getNode()) + // .isNodeType(SlcTypes.SLC_RESULT_FOLDER)) + if (isResultFolder) + canAddSubfolder = true; + else if (obj instanceof SingleResultNode) + isSingleResultNode = true; else if (obj instanceof ParentNodeFolder && (((ParentNodeFolder) obj).getNode().getPath() .startsWith(SlcJcrResultUtils .getMyResultsBasePath(session)))) - isMyResultFolder = true; + canAddSubfolder = true; + } catch (RepositoryException re) { throw new SlcException( "unexpected error while building condition for context menu", @@ -457,7 +461,15 @@ public class JcrResultTreeView extends ViewPart { AddResultFolder.DEFAULT_LABEL, ClientUiPlugin.getDefault().getWorkbench().getSharedImages() .getImageDescriptor(ISharedImages.IMG_OBJ_ADD), - isMyResultFolder); + canAddSubfolder); + + CommandUtils.refreshCommand(menuManager, window, RenameResultFolder.ID, + RenameResultFolder.DEFAULT_LABEL, + RenameResultFolder.DEFAULT_IMG_DESCRIPTOR, canAddSubfolder); + + CommandUtils.refreshCommand(menuManager, window, RenameResultNode.ID, + RenameResultNode.DEFAULT_LABEL, + RenameResultNode.DEFAULT_IMG_DESCRIPTOR, isSingleResultNode); } /* INNER CLASSES */ @@ -470,25 +482,26 @@ public class JcrResultTreeView extends ViewPart { boolean doIt = false; // only one node at a time for the time being. if (selection.size() == 1) { - Object obj = selection.getFirstElement(); - if (obj instanceof SingleResultNode) { - Node tNode = ((SingleResultNode) obj).getNode(); - try { - // if (tNode.getPrimaryNodeType().isNodeType( - // SlcTypes.SLC_TEST_RESULT) - // && (tNode.getPath() - // .startsWith(SlcJcrResultUtils - // .getSlcResultsBasePath(session)))) + try { + Object obj = selection.getFirstElement(); + if (obj instanceof SingleResultNode) { + Node tNode = ((SingleResultNode) obj).getNode(); + if (tNode.getPrimaryNodeType().isNodeType( + SlcTypes.SLC_TEST_RESULT)) { + doIt = true; + isResultFolder = false; + } + } else if (obj instanceof ResultFolder) { + Node tNode = ((ResultFolder) obj).getNode(); if (tNode.getPrimaryNodeType().isNodeType( - SlcTypes.SLC_TEST_RESULT)) + SlcTypes.SLC_RESULT_FOLDER)) { doIt = true; - lastSelectedSourceElementParent = (ResultParent) ((SingleResultNode) obj) - .getParent(); - } catch (RepositoryException re) { - throw new SlcException( - "unexpected error while validating drag source", - re); + isResultFolder = true; + } } + } catch (RepositoryException re) { + throw new SlcException( + "unexpected error while validating drag source", re); } } event.doit = doIt; @@ -498,28 +511,29 @@ public class JcrResultTreeView extends ViewPart { IStructuredSelection selection = (IStructuredSelection) resultTreeViewer .getSelection(); Object obj = selection.getFirstElement(); - if (obj instanceof SingleResultNode) { - Node first = ((SingleResultNode) obj).getNode(); - try { + try { + Node first; + if (obj instanceof SingleResultNode) { + first = ((SingleResultNode) obj).getNode(); + event.data = first.getIdentifier(); + } else if (obj instanceof ResultFolder) { + first = ((ResultFolder) obj).getNode(); event.data = first.getIdentifier(); - - } catch (RepositoryException re) { - throw new SlcException( - "unexpected error while setting data", re); } + } catch (RepositoryException re) { + throw new SlcException("unexpected error while setting data", + re); } } public void dragFinished(DragSourceEvent event) { - // implement here tree refresh in case of a move. + // refresh is done via observer } } // Implementation of the Drop Listener protected class ViewDropListener extends ViewerDropAdapter { - - private Node currParentNode = null; - private boolean copyNode = true; + private Node targetParentNode = null; public ViewDropListener(Viewer viewer) { super(viewer); @@ -528,18 +542,18 @@ public class JcrResultTreeView extends ViewPart { @Override public boolean validateDrop(Object target, int operation, TransferData transferType) { + boolean validDrop = false; try { // We can only drop under myResults - Node targetParentNode = null; + Node tpNode = null; if (target instanceof ResultFolder) { - targetParentNode = ((ResultFolder) target).getNode(); + tpNode = ((ResultFolder) target).getNode(); } else if (target instanceof ParentNodeFolder) { if ((((ParentNodeFolder) target).getNode().getPath() .startsWith(SlcJcrResultUtils .getMyResultsBasePath(session)))) - targetParentNode = ((ParentNodeFolder) target) - .getNode(); + tpNode = ((ParentNodeFolder) target).getNode(); } else if (target instanceof SingleResultNode) { Node currNode = ((SingleResultNode) target).getNode(); if (currNode @@ -548,26 +562,28 @@ public class JcrResultTreeView extends ViewPart { .startsWith( SlcJcrResultUtils .getMyResultsBasePath(session))) - targetParentNode = currNode.getParent(); + tpNode = currNode.getParent(); } - if (targetParentNode != null) { - currParentNode = targetParentNode; - validDrop = true; - // FIXME - lastSelectedTargetElement = (ResultParent) target; - lastSelectedTargetElementParent = (ResultParent) ((ResultParent) target) - .getParent(); - } - // Check if it's a move or a copy - if (validDrop) { - String pPath = ""; - if (lastSelectedSourceElementParent instanceof ResultFolder) - pPath = ((ResultFolder) lastSelectedSourceElementParent) - .getNode().getPath(); - if ((pPath.startsWith(SlcJcrResultUtils - .getMyResultsBasePath(session)))) - copyNode = false; + + if (tpNode != null) { + // Sanity check : we cannot move a folder to one of its sub + // folder + boolean doit = true; + if (isResultFolder) { + Node source = ((ParentNodeFolder) lastSelectedSourceElement) + .getNode(); + String sourcePath = source.getPath(); + String targetPath = tpNode.getPath(); + if (targetPath.startsWith(sourcePath)) + doit = false; + } + if (doit) { + targetParentNode = tpNode; + validDrop = true; + lastSelectedTargetElement = (ResultParent) target; + } } + } catch (RepositoryException re) { throw new SlcException( "unexpected error while validating drop target", re); @@ -577,34 +593,56 @@ public class JcrResultTreeView extends ViewPart { @Override public boolean performDrop(Object data) { - + // clear selection to prevent unwanted scrolling of the UI + resultTreeViewer.setSelection(null); try { Node source = session.getNodeByIdentifier((String) data); - if (copyNode) { - Node target = currParentNode.addNode(source.getName(), - source.getPrimaryNodeType().getName()); + + // Check is a node with same name already exists at destination + String name; + if (source.hasProperty(Property.JCR_TITLE)) + name = source.getProperty(Property.JCR_TITLE).getString(); + else if (source.hasProperty(SlcNames.SLC_TEST_CASE)) + name = source.getProperty(SlcNames.SLC_TEST_CASE) + .getString(); + else + name = source.getName(); + + if (targetParentNode.hasNode(name)) { + ConfirmOverwriteWizard wizard = new ConfirmOverwriteWizard( + name, targetParentNode); + WizardDialog dialog = new WizardDialog(Display.getDefault() + .getActiveShell(), wizard); + dialog.open(); + + if (wizard.overwrite()) { + targetParentNode.getNode(name).remove(); + // session.save(); + } else + name = wizard.newName(); + } + + Node target; + if (!isActionUnderMyResult) {// Copy + target = targetParentNode.addNode(name, source + .getPrimaryNodeType().getName()); JcrUtils.copy(source, target); - ResultParentUtils.updatePassedStatus( - target, - target.getNode(SlcNames.SLC_STATUS) - .getProperty(SlcNames.SLC_SUCCESS) - .getBoolean()); - target.getSession().save(); - } else // move only - { + } else {// move String sourcePath = source.getPath(); - String destPath = currParentNode.getPath() + "/" - + source.getName(); + String destPath = targetParentNode.getPath() + "/" + name; session.move(sourcePath, destPath); - session.save(); - Node target = session.getNode(destPath); - ResultParentUtils.updatePassedStatus( - target, - target.getNode(SlcNames.SLC_STATUS) - .getProperty(SlcNames.SLC_SUCCESS) - .getBoolean()); - session.save(); + // session.save(); + target = session.getNode(destPath); } + if (!target.isNodeType(NodeType.MIX_TITLE)) + target.addMixin(NodeType.MIX_TITLE); + target.setProperty(Property.JCR_TITLE, name); + ResultParentUtils + .updatePassedStatus(target, + target.getNode(SlcNames.SLC_STATUS) + .getProperty(SlcNames.SLC_SUCCESS) + .getBoolean()); + session.save(); } catch (RepositoryException re) { throw new SlcException( "unexpected error while copying dropped node", re); @@ -624,57 +662,43 @@ public class JcrResultTreeView extends ViewPart { throws RepositoryException { // unfiltered for the time being return true; - // for (Event event : events) { - // getLog().debug("Received event " + event); - // int eventType = event.getType(); - // if (eventType == Event.NODE_REMOVED) - // ;//return true; - // String path = event.getPath(); - // int index = path.lastIndexOf('/'); - // String propertyName = path.substring(index + 1); - // if (propertyName.equals(SlcNames.SLC_COMPLETED) - // || propertyName.equals(SlcNames.SLC_UUID)) { - // ;//return true; - // } - // } - // return false; } protected void onEventInUiThread(List events) throws RepositoryException { + int i = 0; for (Event event : events) { - getLog().debug("Received event " + event); + i++; + // log.debug("Received event " + event); int eventType = event.getType(); if (eventType == Event.NODE_REMOVED) { String path = event.getPath(); - int index = path.lastIndexOf('/'); - String parPath = path.substring(0, index + 1); + String parPath = JcrUtils.parentPath(path); if (session.nodeExists(parPath)) { Node currNode = session.getNode(parPath); if (currNode.isNodeType(NodeType.NT_UNSTRUCTURED)) { - refresh(null); - jcrRefresh(currNode); - resultTreeViewer.refresh(true); - resultTreeViewer.expandToLevel( - lastSelectedTargetElementParent, 1); - + // jcrRefresh(currNode); + refresh(lastSelectedSourceElementParent); } } } else if (eventType == Event.NODE_ADDED) { + // refresh(lastSelectedTargetElement); String path = event.getPath(); if (session.nodeExists(path)) { Node currNode = session.getNode(path); - if (currNode.isNodeType(SlcTypes.SLC_DIFF_RESULT) + if (currNode.isNodeType(SlcTypes.SLC_TEST_RESULT) || currNode .isNodeType(SlcTypes.SLC_RESULT_FOLDER)) { - refresh(null); - resultTreeViewer.expandToLevel( - lastSelectedTargetElement, 1); + refresh(lastSelectedTargetElement); + // resultTreeViewer.expandToLevel( + // lastSelectedTargetElement, 1); } } } } + if (log.isDebugEnabled()) + log.debug("treated events: " + i); } } @@ -704,6 +728,45 @@ public class JcrResultTreeView extends ViewPart { } } + class MySelectionChangedListener implements ISelectionChangedListener { + + public void selectionChanged(SelectionChangedEvent event) { + if (!event.getSelection().isEmpty()) { + IStructuredSelection sel = (IStructuredSelection) event + .getSelection(); + ResultParent firstItem = (ResultParent) sel.getFirstElement(); + if (firstItem instanceof SingleResultNode) + propertiesViewer.setInput(((SingleResultNode) firstItem) + .getNode()); + else + propertiesViewer.setInput(null); + // update cache for Drag & drop + lastSelectedTargetElement = firstItem; + lastSelectedSourceElement = firstItem; + lastSelectedSourceElementParent = (ResultParent) firstItem + .getParent(); + String pPath = ""; + try { + + if (firstItem instanceof ParentNodeFolder) + pPath = ((ParentNodeFolder) firstItem).getNode() + .getPath(); + else if (firstItem instanceof SingleResultNode) + pPath = ((SingleResultNode) firstItem).getNode() + .getPath(); + } catch (RepositoryException e) { + throw new SlcException( + "Unexpected error while checking parent UI tree", e); + } + if ((pPath.startsWith(SlcJcrResultUtils + .getMyResultsBasePath(session)))) + isActionUnderMyResult = true; + else + isActionUnderMyResult = false; + } + } + } + class ViewDoubleClickListener implements IDoubleClickListener { public void doubleClick(DoubleClickEvent evt) { processDoubleClick(evt); diff --git a/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/wizards/ConfirmOverwriteWizard.java b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/wizards/ConfirmOverwriteWizard.java new file mode 100644 index 000000000..3ec3530c7 --- /dev/null +++ b/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/wizards/ConfirmOverwriteWizard.java @@ -0,0 +1,184 @@ +package org.argeo.slc.client.ui.wizards; + +import javax.jcr.Node; +import javax.jcr.RepositoryException; + +import org.argeo.slc.SlcException; +import org.argeo.slc.client.ui.ClientUiPlugin; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.wizard.Wizard; +import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.ISharedImages; + +public class ConfirmOverwriteWizard extends Wizard { + + // Define widget here to simplify getters + private Button overwriteBtn, renameBtn; + private Text newNameTxt; + private Label newNameLbl; + + // business object + private String sourceNodeName; + private Node targetParentNode; + + private String newName; + private boolean overwrite; + + public ConfirmOverwriteWizard(String sourceNodeName, Node targetParentNode) { + setWindowTitle("Confirm overwrite or define a new name"); + this.sourceNodeName = sourceNodeName; + this.targetParentNode = targetParentNode; + } + + @Override + public void addPages() { + try { + addPage(new MyPage()); + } catch (Exception e) { + throw new SlcException("Cannot add page to wizard ", e); + } + getShell().setImage( + ClientUiPlugin.getDefault().getWorkbench().getSharedImages() + .getImageDescriptor(ISharedImages.IMG_LCL_LINKTO_HELP) + .createImage()); + } + + // Expose info to the calling view + public boolean overwrite() { + return overwrite; + } + + public String newName() { + return newName; + } + + @Override + public boolean performFinish() { + boolean doFinish = false; + + if (canFinish()) { + if (overwriteBtn.getSelection()) + doFinish = MessageDialog.openConfirm(Display.getDefault() + .getActiveShell(), "CAUTION", "All data contained in [" + + sourceNodeName + + "] are about to be definitively destroyed. \n " + + "Are you sure you want to proceed ?"); + else + doFinish = true; + // cache values + } + if (doFinish) { + overwrite = overwriteBtn.getSelection(); + newName = newNameTxt.getText(); + } + return doFinish; + } + + class MyPage extends WizardPage implements ModifyListener { + + public MyPage() { + super(""); + setTitle("An object with same name (" + sourceNodeName + + ") already exists"); + } + + public void createControl(Composite parent) { + Composite composite = new Composite(parent, SWT.NONE); + composite.setLayout(new GridLayout(2, false)); + + // choose between overwrite and rename + overwriteBtn = new Button(composite, SWT.RADIO); + overwriteBtn.setText("Overwrite"); + GridData gd = new GridData(); + gd.horizontalIndent = 30; + gd.horizontalSpan = 2; + overwriteBtn.setLayoutData(gd); + overwriteBtn.setSelection(true); + + renameBtn = new Button(composite, SWT.RADIO); + renameBtn.setText("Rename"); + renameBtn.setSelection(false); + renameBtn.setText("Rename"); + gd = new GridData(); + gd.horizontalIndent = 30; + gd.horizontalSpan = 2; + renameBtn.setLayoutData(gd); + + newNameLbl = new Label(composite, SWT.LEAD); + newNameLbl.setText("New name"); + newNameLbl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, + false)); + newNameLbl.setEnabled(false); + + newNameTxt = new Text(composite, SWT.LEAD | SWT.BORDER); + newNameTxt.setText(sourceNodeName); + newNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, + false)); + if (newNameTxt != null) + newNameTxt.addModifyListener(this); + newNameTxt.setEnabled(false); + + SelectionAdapter sa = new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + updateSelection(overwriteBtn.getSelection()); + } + }; + overwriteBtn.addSelectionListener(sa); + renameBtn.addSelectionListener(sa); + + // Compulsory + setControl(composite); + } + + private void updateSelection(boolean overwrite) { + newNameLbl.setEnabled(!overwrite); + newNameTxt.setEnabled(!overwrite); + if (overwrite) + setPageComplete(true); + else + checkComplete(); + } + + protected String getTechName() { + return newNameTxt.getText(); + } + + public void modifyText(ModifyEvent event) { + checkComplete(); + } + + private void checkComplete() { + try { + + String newName = newNameTxt.getText(); + if (newName == null || "".equals(newName.trim())) { + setMessage("Name cannot be blank or empty", + WizardPage.ERROR); + setPageComplete(false); + } else if (targetParentNode.hasNode(newName)) { + setMessage("An object with the same name already exists.", + WizardPage.ERROR); + setPageComplete(false); + } else { + setMessage("Complete", WizardPage.INFORMATION); + setPageComplete(true); + } + } catch (RepositoryException e) { + throw new SlcException("Unexpected error while checking " + + "children node with same name", e); + } + } + } +} -- 2.39.2