2 * Copyright (C) 2007-2012 Argeo GmbH
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org
.argeo
.slc
.client
.ui
.views
;
18 import java
.text
.DateFormat
;
19 import java
.text
.SimpleDateFormat
;
20 import java
.util
.ArrayList
;
21 import java
.util
.Calendar
;
22 import java
.util
.Iterator
;
23 import java
.util
.List
;
25 import javax
.jcr
.Node
;
26 import javax
.jcr
.NodeIterator
;
27 import javax
.jcr
.Property
;
28 import javax
.jcr
.Repository
;
29 import javax
.jcr
.RepositoryException
;
30 import javax
.jcr
.Session
;
31 import javax
.jcr
.nodetype
.NodeType
;
32 import javax
.jcr
.observation
.Event
;
33 import javax
.jcr
.observation
.EventListener
;
34 import javax
.jcr
.observation
.ObservationManager
;
36 import org
.argeo
.ArgeoException
;
37 import org
.argeo
.eclipse
.ui
.jcr
.AsyncUiEventListener
;
38 import org
.argeo
.eclipse
.ui
.utils
.CommandUtils
;
39 import org
.argeo
.jcr
.JcrUtils
;
40 import org
.argeo
.slc
.SlcException
;
41 import org
.argeo
.slc
.client
.ui
.ClientUiPlugin
;
42 import org
.argeo
.slc
.client
.ui
.SlcUiConstants
;
43 import org
.argeo
.slc
.client
.ui
.commands
.AddResultFolder
;
44 import org
.argeo
.slc
.client
.ui
.commands
.DeleteItems
;
45 import org
.argeo
.slc
.client
.ui
.commands
.RefreshJcrResultTreeView
;
46 import org
.argeo
.slc
.client
.ui
.commands
.RenameResultFolder
;
47 import org
.argeo
.slc
.client
.ui
.commands
.RenameResultNode
;
48 import org
.argeo
.slc
.client
.ui
.editors
.ProcessEditor
;
49 import org
.argeo
.slc
.client
.ui
.editors
.ProcessEditorInput
;
50 import org
.argeo
.slc
.client
.ui
.model
.ParentNodeFolder
;
51 import org
.argeo
.slc
.client
.ui
.model
.ResultFolder
;
52 import org
.argeo
.slc
.client
.ui
.model
.ResultItemsComparator
;
53 import org
.argeo
.slc
.client
.ui
.model
.ResultItemsComparer
;
54 import org
.argeo
.slc
.client
.ui
.model
.ResultParent
;
55 import org
.argeo
.slc
.client
.ui
.model
.ResultParentUtils
;
56 import org
.argeo
.slc
.client
.ui
.model
.SingleResultNode
;
57 import org
.argeo
.slc
.client
.ui
.model
.VirtualFolder
;
58 import org
.argeo
.slc
.client
.ui
.providers
.ResultTreeContentProvider
;
59 import org
.argeo
.slc
.client
.ui
.providers
.ResultTreeLabelProvider
;
60 import org
.argeo
.slc
.jcr
.SlcJcrResultUtils
;
61 import org
.argeo
.slc
.jcr
.SlcNames
;
62 import org
.argeo
.slc
.jcr
.SlcTypes
;
63 import org
.eclipse
.jface
.action
.IMenuListener
;
64 import org
.eclipse
.jface
.action
.IMenuManager
;
65 import org
.eclipse
.jface
.action
.MenuManager
;
66 import org
.eclipse
.jface
.dialogs
.MessageDialog
;
67 import org
.eclipse
.jface
.viewers
.ColumnLabelProvider
;
68 import org
.eclipse
.jface
.viewers
.DecoratingLabelProvider
;
69 import org
.eclipse
.jface
.viewers
.DoubleClickEvent
;
70 import org
.eclipse
.jface
.viewers
.IDoubleClickListener
;
71 import org
.eclipse
.jface
.viewers
.ILabelDecorator
;
72 import org
.eclipse
.jface
.viewers
.ISelectionChangedListener
;
73 import org
.eclipse
.jface
.viewers
.IStructuredContentProvider
;
74 import org
.eclipse
.jface
.viewers
.IStructuredSelection
;
75 import org
.eclipse
.jface
.viewers
.SelectionChangedEvent
;
76 import org
.eclipse
.jface
.viewers
.TableViewer
;
77 import org
.eclipse
.jface
.viewers
.TableViewerColumn
;
78 import org
.eclipse
.jface
.viewers
.TreePath
;
79 import org
.eclipse
.jface
.viewers
.TreeViewer
;
80 import org
.eclipse
.jface
.viewers
.Viewer
;
81 import org
.eclipse
.jface
.viewers
.ViewerDropAdapter
;
82 import org
.eclipse
.swt
.SWT
;
83 import org
.eclipse
.swt
.custom
.SashForm
;
84 import org
.eclipse
.swt
.dnd
.DND
;
85 import org
.eclipse
.swt
.dnd
.DragSourceEvent
;
86 import org
.eclipse
.swt
.dnd
.DragSourceListener
;
87 import org
.eclipse
.swt
.dnd
.TextTransfer
;
88 import org
.eclipse
.swt
.dnd
.Transfer
;
89 import org
.eclipse
.swt
.dnd
.TransferData
;
90 import org
.eclipse
.swt
.layout
.FillLayout
;
91 import org
.eclipse
.swt
.layout
.GridData
;
92 import org
.eclipse
.swt
.layout
.GridLayout
;
93 import org
.eclipse
.swt
.widgets
.Composite
;
94 import org
.eclipse
.swt
.widgets
.Display
;
95 import org
.eclipse
.swt
.widgets
.Menu
;
96 import org
.eclipse
.ui
.ISharedImages
;
97 import org
.eclipse
.ui
.IWorkbenchPage
;
98 import org
.eclipse
.ui
.IWorkbenchWindow
;
99 import org
.eclipse
.ui
.PlatformUI
;
100 import org
.eclipse
.ui
.part
.ViewPart
;
102 /** SLC generic JCR Result tree view. */
103 public class JcrResultTreeView
extends ViewPart
{
104 public final static String ID
= ClientUiPlugin
.ID
+ ".jcrResultTreeView";
106 private final static DateFormat dateFormat
= new SimpleDateFormat(
107 SlcUiConstants
.DEFAULT_DISPLAY_DATE_TIME_FORMAT
);
109 // private final static Log log =
110 // LogFactory.getLog(JcrResultTreeView.class);
112 /* DEPENDENCY INJECTION */
113 private Session session
;
116 private TreeViewer resultTreeViewer
;
117 private TableViewer propertiesViewer
;
119 private EventListener myResultsObserver
= null;
120 private EventListener allResultsObserver
= null;
123 private final static String
[] observedNodeTypesUnderMyResult
= {
124 SlcTypes
.SLC_TEST_RESULT
, SlcTypes
.SLC_RESULT_FOLDER
,
125 SlcTypes
.SLC_MY_RESULT_ROOT_FOLDER
};
127 private final static String
[] observedNodeTypesUnderAllResults
= {
128 SlcTypes
.SLC_TEST_RESULT
, NodeType
.NT_UNSTRUCTURED
};
130 private boolean isResultFolder
= false;
133 * To be overridden to adapt size of form and result frames.
135 protected int[] getWeights() {
136 return new int[] { 70, 30 };
140 public void createPartControl(Composite parent
) {
141 parent
.setLayout(new FillLayout());
143 SashForm sashForm
= new SashForm(parent
, SWT
.VERTICAL
);
144 sashForm
.setSashWidth(4);
145 sashForm
.setLayout(new FillLayout());
147 // Create the tree on top of the view
148 Composite top
= new Composite(sashForm
, SWT
.NONE
);
149 GridLayout gl
= new GridLayout(1, false);
151 resultTreeViewer
= createResultsTreeViewer(top
);
153 // Create the property viewer on the bottom
154 Composite bottom
= new Composite(sashForm
, SWT
.NONE
);
155 bottom
.setLayout(new GridLayout(1, false));
156 propertiesViewer
= createPropertiesViewer(bottom
);
158 sashForm
.setWeights(getWeights());
160 setOrderedInput(resultTreeViewer
);
162 // Initialize observer
164 ObservationManager observationManager
= session
.getWorkspace()
165 .getObservationManager();
166 myResultsObserver
= new MyResultsObserver(resultTreeViewer
167 .getTree().getDisplay());
168 allResultsObserver
= new AllResultsObserver(resultTreeViewer
169 .getTree().getDisplay());
171 // observe tree changes under MyResults
172 observationManager
.addEventListener(myResultsObserver
,
173 Event
.NODE_ADDED
| Event
.NODE_REMOVED
,
174 SlcJcrResultUtils
.getMyResultsBasePath(session
), true,
175 null, observedNodeTypesUnderMyResult
, false);
176 // observe tree changes under All results
177 observationManager
.addEventListener(allResultsObserver
,
178 Event
.NODE_ADDED
| Event
.NODE_REMOVED
,
179 SlcJcrResultUtils
.getSlcResultsBasePath(session
), true,
180 null, observedNodeTypesUnderAllResults
, false);
181 } catch (RepositoryException e
) {
182 throw new SlcException("Cannot register listeners", e
);
187 * Override default behaviour so that default defined order remains
188 * unchanged on first level of the tree
190 private void setOrderedInput(TreeViewer viewer
) {
191 // Add specific ordering
192 viewer
.setInput(null);
193 viewer
.setComparator(null);
194 viewer
.setInput(initializeResultTree());
195 viewer
.setComparator(new ResultItemsComparator());
198 // The main tree viewer
199 protected TreeViewer
createResultsTreeViewer(Composite parent
) {
200 int style
= SWT
.BORDER
| SWT
.MULTI
;
202 TreeViewer viewer
= new TreeViewer(parent
, style
);
203 viewer
.getTree().setLayoutData(
204 new GridData(SWT
.FILL
, SWT
.FILL
, true, true));
206 viewer
.setContentProvider(new ResultTreeContentProvider());
208 // Add label provider with label decorator
209 ResultTreeLabelProvider rtLblProvider
= new ResultTreeLabelProvider();
210 ILabelDecorator decorator
= ClientUiPlugin
.getDefault().getWorkbench()
211 .getDecoratorManager().getLabelDecorator();
212 viewer
.setLabelProvider(new DecoratingLabelProvider(rtLblProvider
,
214 viewer
.addDoubleClickListener(new ViewDoubleClickListener());
216 // Override default behaviour to insure that 2 distincts results that
217 // have the same name will be correctly and distincly returned by
218 // corresponding TreeViewer.getSelection() method.
219 viewer
.setComparer(new ResultItemsComparer());
221 // viewer.setLabelProvider(rtLblProvider);
222 getSite().setSelectionProvider(viewer
);
224 // add drag & drop support
225 int operations
= DND
.DROP_COPY
| DND
.DROP_MOVE
;
226 Transfer
[] tt
= new Transfer
[] { TextTransfer
.getInstance() };
227 viewer
.addDragSupport(operations
, tt
, new ViewDragListener());
228 viewer
.addDropSupport(operations
, tt
, new ViewDropListener(viewer
));
231 MenuManager menuManager
= new MenuManager();
232 Menu menu
= menuManager
.createContextMenu(viewer
.getTree());
233 menuManager
.addMenuListener(new IMenuListener() {
234 public void menuAboutToShow(IMenuManager manager
) {
235 contextMenuAboutToShow(manager
);
238 viewer
.getTree().setMenu(menu
);
239 menuManager
.setRemoveAllWhenShown(true);
241 getSite().registerContextMenu(menuManager
, viewer
);
243 // add change listener to display TestResult information in the property
245 viewer
.addSelectionChangedListener(new MySelectionChangedListener());
249 // Detailed property viewer
250 protected TableViewer
createPropertiesViewer(Composite parent
) {
251 propertiesViewer
= new TableViewer(parent
);
252 propertiesViewer
.getTable().setLayoutData(
253 new GridData(SWT
.FILL
, SWT
.FILL
, true, true));
254 propertiesViewer
.getTable().setHeaderVisible(true);
255 propertiesViewer
.setContentProvider(new PropertiesContentProvider());
256 TableViewerColumn col
= new TableViewerColumn(propertiesViewer
,
258 col
.getColumn().setText("Name");
259 col
.getColumn().setWidth(100);
260 col
.setLabelProvider(new ColumnLabelProvider() {
261 public String
getText(Object element
) {
263 String name
= ((Property
) element
).getName();
265 if (SlcNames
.SLC_TEST_CASE
.equals(name
))
267 else if (SlcNames
.SLC_COMPLETED
.equals(name
))
268 value
= "Completed on";
269 else if (SlcNames
.SLC_SUCCESS
.equals(name
))
271 else if (SlcNames
.SLC_MESSAGE
.equals(name
))
273 else if (SlcNames
.SLC_ERROR_MESSAGE
.equals(name
))
276 } catch (RepositoryException e
) {
277 throw new ArgeoException(
278 "Unexpected exception in label provider", e
);
282 col
= new TableViewerColumn(propertiesViewer
, SWT
.NONE
);
283 col
.getColumn().setText("Value");
284 col
.getColumn().setWidth(200);
285 col
.setLabelProvider(new ColumnLabelProvider() {
286 public String
getText(Object element
) {
288 Property property
= (Property
) element
;
289 String name
= property
.getName();
292 if (SlcNames
.SLC_TEST_CASE
.equals(name
)
293 || SlcNames
.SLC_ERROR_MESSAGE
.equals(name
)
294 || SlcNames
.SLC_MESSAGE
.equals(name
))
295 value
= property
.getValue().getString();
296 else if (SlcNames
.SLC_COMPLETED
.equals(name
)) {
297 Calendar date
= property
.getValue().getDate();
298 value
= dateFormat
.format(date
.getTime());
299 } else if (SlcNames
.SLC_SUCCESS
.equals(name
)) {
300 if (property
.getValue().getBoolean())
303 if (property
.getParent().hasProperty(
304 SlcNames
.SLC_ERROR_MESSAGE
))
311 } catch (RepositoryException e
) {
312 throw new ArgeoException(
313 "Unexpected exception in label provider", e
);
317 propertiesViewer
.setInput(getViewSite());
318 return propertiesViewer
;
322 * Override to provide specific behaviour. Typically to enable the display
327 protected void processDoubleClick(DoubleClickEvent evt
) {
328 Object obj
= ((IStructuredSelection
) evt
.getSelection())
331 if (obj
instanceof SingleResultNode
) {
332 SingleResultNode srNode
= (SingleResultNode
) obj
;
333 Node node
= srNode
.getNode();
334 // FIXME: open a default result editor
335 if (node
.isNodeType(SlcTypes
.SLC_PROCESS
)) {
336 IWorkbenchPage activePage
= PlatformUI
.getWorkbench()
337 .getActiveWorkbenchWindow().getActivePage();
338 activePage
.openEditor(
339 new ProcessEditorInput(node
.getPath()),
343 } catch (Exception e
) {
344 throw new SlcException("Cannot open " + obj
, e
);
349 public void setFocus() {
353 * refreshes the passed resultParent and its corresponding subtree. It
354 * refreshes the whole viewer if null is passed.
356 * @param ResultParent
359 public void refresh(ResultParent resultParent
) {
360 if (resultParent
== null) {
361 if (!resultTreeViewer
.getTree().isDisposed()) {
362 TreePath
[] tps
= resultTreeViewer
.getExpandedTreePaths();
363 setOrderedInput(resultTreeViewer
);
364 resultTreeViewer
.setExpandedTreePaths(tps
);
366 setOrderedInput(resultTreeViewer
);
368 if (resultParent
instanceof ParentNodeFolder
) {
369 ParentNodeFolder currFolder
= (ParentNodeFolder
) resultParent
;
370 jcrRefresh(currFolder
.getNode());
371 currFolder
.forceFullRefresh();
373 // FIXME: specific refresh does not work
374 // resultTreeViewer.refresh(resultParent, true);
380 * refreshes the passed node and its corresponding subtree.
386 public boolean jcrRefresh(Node node
) {
387 // if (log.isDebugEnabled())
388 // log.debug(" JCR refreshing " + node + "...");
389 // Thread.dumpStack();
390 boolean isPassed
= true;
392 if (node
.isNodeType(SlcTypes
.SLC_TEST_RESULT
)) {
393 isPassed
= node
.getNode(SlcNames
.SLC_AGGREGATED_STATUS
)
394 .getProperty(SlcNames
.SLC_SUCCESS
).getBoolean();
395 } else if (node
.isNodeType(SlcTypes
.SLC_RESULT_FOLDER
)) {
396 NodeIterator ni
= node
.getNodes();
397 while (ni
.hasNext()) {
398 Node currChild
= ni
.nextNode();
399 isPassed
= isPassed
& jcrRefresh(currChild
);
401 if (isPassed
!= node
.getNode(SlcNames
.SLC_AGGREGATED_STATUS
)
402 .getProperty(SlcNames
.SLC_SUCCESS
).getBoolean()) {
403 node
.getNode(SlcNames
.SLC_AGGREGATED_STATUS
).setProperty(
404 SlcNames
.SLC_SUCCESS
, isPassed
);
405 node
.getSession().save();
410 } catch (RepositoryException e
) {
411 throw new SlcException("Cannot register listeners", e
);
416 private ResultParent
[] initializeResultTree() {
418 // Force initialization of the tree structure if needed
419 SlcJcrResultUtils
.getSlcResultsParentNode(session
);
420 SlcJcrResultUtils
.getMyResultParentNode(session
);
421 // Remove yesterday and last 7 days virtual folders
422 // ResultParent[] roots = new ResultParent[5];
423 ResultParent
[] roots
= new ResultParent
[3];
426 roots
[0] = new ParentNodeFolder(null,
427 SlcJcrResultUtils
.getMyResultParentNode(session
),
428 SlcUiConstants
.DEFAULT_MY_RESULTS_FOLDER_LABEL
);
431 Calendar cal
= Calendar
.getInstance();
432 String relPath
= JcrUtils
.dateAsPath(cal
);
433 List
<String
> datePathes
= new ArrayList
<String
>();
434 datePathes
.add(relPath
);
435 roots
[1] = new VirtualFolder(null,
436 ResultParentUtils
.getResultsForDates(session
, datePathes
),
440 // cal = Calendar.getInstance();
441 // cal.add(Calendar.DAY_OF_YEAR, -1);
442 // relPath = JcrUtils.dateAsPath(cal);
443 // datePathes = new ArrayList<String>();
444 // datePathes.add(relPath);
445 // roots[2] = new VirtualFolder(null,
446 // ResultParentUtils.getResultsForDates(session, datePathes),
450 // cal = Calendar.getInstance();
451 // datePathes = new ArrayList<String>();
453 // for (int i = 0; i < 7; i++) {
454 // cal.add(Calendar.DAY_OF_YEAR, -i);
455 // relPath = JcrUtils.dateAsPath(cal);
456 // datePathes.add(relPath);
458 // roots[3] = new VirtualFolder(null,
459 // ResultParentUtils.getResultsForDates(session, datePathes),
463 Node otherResultsPar
= session
.getNode(SlcJcrResultUtils
464 .getSlcResultsBasePath(session
));
465 // roots[4] = new ParentNodeFolder(null, otherResultsPar,
467 roots
[2] = new ParentNodeFolder(null, otherResultsPar
,
470 } catch (RepositoryException re
) {
471 throw new ArgeoException(
472 "Unexpected error while initializing ResultTree.", re
);
476 // Manage context menu
478 * Defines the commands that will pop up in the context menu.
480 protected void contextMenuAboutToShow(IMenuManager menuManager
) {
481 IWorkbenchWindow window
= ClientUiPlugin
.getDefault().getWorkbench()
482 .getActiveWorkbenchWindow();
484 IStructuredSelection selection
= (IStructuredSelection
) resultTreeViewer
486 boolean canAddSubfolder
= false;
487 boolean canRenamefolder
= false;
488 boolean isSingleResultNode
= false;
489 boolean isUnderMyResult
= false;
490 boolean validMultipleDelete
= false;
493 // Building conditions
494 if (selection
.size() == 1) {
495 Object obj
= selection
.getFirstElement();
496 if (obj
instanceof SingleResultNode
)
497 isSingleResultNode
= true;
498 else if (obj
instanceof ParentNodeFolder
) {
499 Node cNode
= ((ParentNodeFolder
) obj
).getNode();
500 if (cNode
.isNodeType(SlcTypes
.SLC_RESULT_FOLDER
)) {
501 canAddSubfolder
= true;
502 canRenamefolder
= true;
503 isUnderMyResult
= true;
505 .isNodeType(SlcTypes
.SLC_MY_RESULT_ROOT_FOLDER
)) {
506 canAddSubfolder
= true;
510 @SuppressWarnings("rawtypes")
511 Iterator it
= selection
.iterator();
512 multicheck
: while (it
.hasNext()) {
513 validMultipleDelete
= true;
514 Object obj
= it
.next();
515 if (obj
instanceof SingleResultNode
)
517 else if (obj
instanceof ParentNodeFolder
) {
518 Node cNode
= ((ParentNodeFolder
) obj
).getNode();
519 if (cNode
.isNodeType(SlcTypes
.SLC_RESULT_FOLDER
))
522 validMultipleDelete
= false;
526 validMultipleDelete
= false;
531 } catch (RepositoryException re
) {
532 throw new SlcException(
533 "unexpected error while building condition for context menu",
538 CommandUtils
.refreshCommand(menuManager
, window
,
539 RefreshJcrResultTreeView
.ID
,
540 RefreshJcrResultTreeView
.DEFAULT_LABEL
,
541 RefreshJcrResultTreeView
.DEFAULT_IMG_DESCRIPTOR
, true);
543 CommandUtils
.refreshCommand(menuManager
, window
, DeleteItems
.ID
,
544 DeleteItems
.DEFAULT_LABEL
, DeleteItems
.DEFAULT_IMG_DESCRIPTOR
,
545 isUnderMyResult
|| isSingleResultNode
|| validMultipleDelete
);
547 CommandUtils
.refreshCommand(menuManager
, window
, AddResultFolder
.ID
,
548 AddResultFolder
.DEFAULT_LABEL
,
549 ClientUiPlugin
.getDefault().getWorkbench().getSharedImages()
550 .getImageDescriptor(ISharedImages
.IMG_OBJ_ADD
),
553 CommandUtils
.refreshCommand(menuManager
, window
, RenameResultFolder
.ID
,
554 RenameResultFolder
.DEFAULT_LABEL
,
555 RenameResultFolder
.DEFAULT_IMG_DESCRIPTOR
, canRenamefolder
);
557 // Command removed for the time being.
558 CommandUtils
.refreshCommand(menuManager
, window
, RenameResultNode
.ID
,
559 RenameResultNode
.DEFAULT_LABEL
,
560 RenameResultNode
.DEFAULT_IMG_DESCRIPTOR
, false);
562 // Test to be removed
563 // If you use this pattern, do not forget to call
564 // menuManager.setRemoveAllWhenShown(true);
565 // when creating the menuManager
567 // menuManager.add(new Action("Test") {
568 // public void run() {
569 // log.debug("do something");
575 class ViewDragListener
implements DragSourceListener
{
577 public void dragStart(DragSourceEvent event
) {
578 // Check if the drag action should start.
579 IStructuredSelection selection
= (IStructuredSelection
) resultTreeViewer
581 boolean doIt
= false;
583 // FIXME clean this code.
585 if (selection
.size() == 1) {
586 Object obj
= selection
.getFirstElement();
587 if (obj
instanceof ResultFolder
) {
588 Node tNode
= ((ResultFolder
) obj
).getNode();
589 if (tNode
.getPrimaryNodeType().isNodeType(
590 SlcTypes
.SLC_RESULT_FOLDER
)) {
592 isResultFolder
= true;
595 isResultFolder
= false;
597 isResultFolder
= false;
599 if (!isResultFolder
) {
600 @SuppressWarnings("rawtypes")
601 Iterator it
= selection
.iterator();
602 while (it
.hasNext()) {
603 Object obj
= it
.next();
604 if (obj
instanceof SingleResultNode
) {
605 Node tNode
= ((SingleResultNode
) obj
).getNode();
606 if (tNode
.getPrimaryNodeType().isNodeType(
607 SlcTypes
.SLC_TEST_RESULT
)) {
614 } catch (RepositoryException re
) {
615 throw new SlcException(
616 "unexpected error while validating drag source", re
);
621 public void dragSetData(DragSourceEvent event
) {
622 IStructuredSelection selection
= (IStructuredSelection
) resultTreeViewer
626 // specific case of a result folder
627 if (isResultFolder
) {
628 Object obj
= selection
.getFirstElement();
629 event
.data
= ((ResultFolder
) obj
).getNode().getIdentifier();
631 @SuppressWarnings("rawtypes")
632 Iterator it
= selection
.iterator();
633 StringBuilder nodes
= new StringBuilder();
634 while (it
.hasNext()) {
635 Object obj
= it
.next();
636 if (obj
instanceof SingleResultNode
) {
637 Node tNode
= ((SingleResultNode
) obj
).getNode();
638 if (tNode
.getPrimaryNodeType().isNodeType(
639 SlcTypes
.SLC_TEST_RESULT
)) {
640 nodes
.append(tNode
.getIdentifier()).append(";");
644 event
.data
= nodes
.toString();
646 } catch (RepositoryException re
) {
647 throw new SlcException("unexpected error while setting data",
652 public void dragFinished(DragSourceEvent event
) {
653 // refresh is done via observer
657 // Implementation of the Drop Listener
658 protected class ViewDropListener
extends ViewerDropAdapter
{
659 private Node targetParentNode
= null;
661 public ViewDropListener(Viewer viewer
) {
666 public boolean validateDrop(Object target
, int operation
,
667 TransferData transferType
) {
668 boolean validDrop
= false;
670 // We can only drop under myResults
672 if (target
instanceof SingleResultNode
) {
673 Node currNode
= ((SingleResultNode
) target
).getNode();
674 String pPath
= currNode
.getParent().getPath();
675 if (pPath
.startsWith(SlcJcrResultUtils
676 .getMyResultsBasePath(session
)))
677 tpNode
= currNode
.getParent();
678 } else if (target
instanceof ResultFolder
) {
679 tpNode
= ((ResultFolder
) target
).getNode();
680 } else if (target
instanceof ParentNodeFolder
) {
681 Node node
= ((ParentNodeFolder
) target
).getNode();
682 if (node
.isNodeType(SlcTypes
.SLC_MY_RESULT_ROOT_FOLDER
))
683 tpNode
= ((ParentNodeFolder
) target
).getNode();
686 if (tpNode
!= null) {
687 targetParentNode
= tpNode
;
690 } catch (RepositoryException re
) {
691 throw new SlcException(
692 "unexpected error while validating drop target", re
);
698 public boolean performDrop(Object data
) {
699 // clear selection to prevent unwanted scrolling of the UI
700 resultTreeViewer
.setSelection(null);
702 if (isResultFolder
) {
703 // Sanity check : we cannot move a folder to one of its sub
704 // folder or neither move an object in the same parent
706 Node source
= session
.getNodeByIdentifier((String
) data
);
707 if (targetParentNode
.getPath().startsWith(source
.getPath())
708 || source
.getParent().getPath()
709 .equals(targetParentNode
.getPath()))
713 String sourcePath
= source
.getPath();
714 String destPath
= targetParentNode
.getPath() + "/"
716 session
.move(sourcePath
, destPath
);
717 // Update passed status of the parent source Node
718 ResultParentUtils
.updatePassedStatus(
719 session
.getNode(JcrUtils
.parentPath(sourcePath
)),
721 // Node target = session.getNode(destPath);
726 String
[] datas
= ((String
) data
).split(";");
727 nodesToCopy
: for (String id
: datas
) {
729 Node source
= session
.getNodeByIdentifier(id
);
731 if (source
.hasProperty(Property
.JCR_TITLE
))
732 name
= source
.getProperty(Property
.JCR_TITLE
)
734 else if (source
.hasProperty(SlcNames
.SLC_TEST_CASE
))
735 name
= source
.getProperty(SlcNames
.SLC_TEST_CASE
)
738 name
= source
.getName();
740 // Check if another copy of the same test instance already
742 NodeIterator ni
= targetParentNode
.getNodes();
743 String slcUid
= source
.getProperty(SlcNames
.SLC_UUID
)
745 while (ni
.hasNext()) {
746 Node curr
= ni
.nextNode();
747 if (curr
.hasProperty(SlcNames
.SLC_UUID
)
748 && slcUid
.equals(curr
.getProperty(
749 SlcNames
.SLC_UUID
).getString())) {
752 PlatformUI
.getWorkbench()
755 "Duplicated instance.",
756 "An instance of the same test case ("
758 + ") exists at destination.\n "
759 + "This item will not be neither copied nor moved.");
760 continue nodesToCopy
;
766 boolean passedStatus
= false;
767 if (source
.hasNode(SlcNames
.SLC_AGGREGATED_STATUS
))
768 passedStatus
= source
769 .getNode(SlcNames
.SLC_AGGREGATED_STATUS
)
770 .getProperty(SlcNames
.SLC_SUCCESS
).getBoolean();
772 boolean isActionUnderMyResult
= source
.getPath()
775 .getMyResultsBasePath(session
));
777 if (!isActionUnderMyResult
) {// Copy
778 target
= targetParentNode
.addNode(source
.getName(),
779 source
.getPrimaryNodeType().getName());
780 JcrUtils
.copy(source
, target
);
782 String sourcePath
= source
.getPath();
783 String destPath
= targetParentNode
.getPath() + "/"
785 session
.move(sourcePath
, destPath
);
786 // Update passed status of the parent source Node
788 .updatePassedStatus(session
.getNode(JcrUtils
789 .parentPath(sourcePath
)), true);
790 target
= session
.getNode(destPath
);
793 if (!target
.isNodeType(NodeType
.MIX_TITLE
))
794 target
.addMixin(NodeType
.MIX_TITLE
);
795 target
.setProperty(Property
.JCR_TITLE
, name
);
796 ResultParentUtils
.updatePassedStatus(target
.getParent(),
800 } catch (RepositoryException re
) {
801 throw new SlcException(
802 "unexpected error while copying dropped node", re
);
809 class MyResultsObserver
extends AsyncUiEventListener
{
811 public MyResultsObserver(Display display
) {
816 protected Boolean
willProcessInUiThread(List
<Event
> events
)
817 throws RepositoryException
{
818 // unfiltered for the time being
822 protected void onEventInUiThread(List
<Event
> events
)
823 throws RepositoryException
{
824 List
<Node
> nodesToRefresh
= new ArrayList
<Node
>();
826 for (Event event
: events
) {
827 String parPath
= JcrUtils
.parentPath(event
.getPath());
828 if (session
.nodeExists(parPath
)) {
829 Node node
= session
.getNode(parPath
);
830 if (!nodesToRefresh
.contains(node
)) {
831 nodesToRefresh
.add(node
);
836 // Update check nodes
837 for (Node node
: nodesToRefresh
)
843 class AllResultsObserver
extends AsyncUiEventListener
{
845 public AllResultsObserver(Display display
) {
850 protected Boolean
willProcessInUiThread(List
<Event
> events
)
851 throws RepositoryException
{
852 // unfiltered for the time being
856 protected void onEventInUiThread(List
<Event
> events
)
857 throws RepositoryException
{
859 // if (lastSelectedSourceElementParent != null)
860 // refresh(lastSelectedSourceElementParent);
864 class PropertiesContentProvider
implements IStructuredContentProvider
{
866 public void dispose() {
869 public void inputChanged(Viewer viewer
, Object oldInput
, Object newInput
) {
872 public Object
[] getElements(Object inputElement
) {
874 if (inputElement
instanceof Node
) {
875 Node node
= (Node
) inputElement
;
876 if (node
.isNodeType(SlcTypes
.SLC_TEST_RESULT
)) {
877 List
<Property
> props
= new ArrayList
<Property
>();
878 if (node
.hasProperty(SlcNames
.SLC_TEST_CASE
))
879 props
.add(node
.getProperty(SlcNames
.SLC_TEST_CASE
));
880 if (node
.hasProperty(SlcNames
.SLC_COMPLETED
))
881 props
.add(node
.getProperty(SlcNames
.SLC_COMPLETED
));
882 if (node
.hasNode(SlcNames
.SLC_AGGREGATED_STATUS
)) {
884 .getNode(SlcNames
.SLC_AGGREGATED_STATUS
);
885 props
.add(status
.getProperty(SlcNames
.SLC_SUCCESS
));
886 if (status
.hasProperty(SlcNames
.SLC_MESSAGE
))
888 .getProperty(SlcNames
.SLC_MESSAGE
));
889 if (status
.hasProperty(SlcNames
.SLC_ERROR_MESSAGE
))
891 .getProperty(SlcNames
.SLC_ERROR_MESSAGE
));
893 return props
.toArray();
896 return new Object
[] {};
898 } catch (RepositoryException e
) {
899 throw new ArgeoException("Cannot get element for "
905 class MySelectionChangedListener
implements ISelectionChangedListener
{
907 public void selectionChanged(SelectionChangedEvent event
) {
908 if (!event
.getSelection().isEmpty()) {
909 IStructuredSelection sel
= (IStructuredSelection
) event
911 ResultParent firstItem
= (ResultParent
) sel
.getFirstElement();
912 if (firstItem
instanceof SingleResultNode
)
913 propertiesViewer
.setInput(((SingleResultNode
) firstItem
)
916 propertiesViewer
.setInput(null);
917 // update cache for Drag & drop
918 // lastSelectedTargetElement = firstItem;
919 // lastSelectedSourceElement = firstItem;
920 // lastSelectedSourceElementParent = (ResultParent) firstItem
922 // String pPath = "";
925 // if (firstItem instanceof ParentNodeFolder)
926 // pPath = ((ParentNodeFolder) firstItem).getNode()
928 // else if (firstItem instanceof SingleResultNode)
929 // pPath = ((SingleResultNode) firstItem).getNode()
931 // } catch (RepositoryException e) {
932 // throw new SlcException(
933 // "Unexpected error while checking parent UI tree", e);
935 // if ((pPath.startsWith(SlcJcrResultUtils
936 // .getMyResultsBasePath(session))))
937 // isActionUnderMyResult = true;
939 // isActionUnderMyResult = false;
944 class ViewDoubleClickListener
implements IDoubleClickListener
{
945 public void doubleClick(DoubleClickEvent evt
) {
946 processDoubleClick(evt
);
951 /* DEPENDENCY INJECTION */
953 public void setSession(Session session
) {
954 this.session
= session
;
957 public void dispose() {
958 // JcrUtils.unregisterQuietly(session.getWorkspace(), resultsObserver);
959 JcrUtils
.logoutQuietly(session
);
963 public void setRepository(Repository repository
) {
965 session
= repository
.login();
966 } catch (RepositoryException re
) {
967 throw new SlcException("Unable to log in Repository " + repository
,