]> git.argeo.org Git - gpl/argeo-slc.git/blob - JcrResultTreeView.java
152e15c6e89bdf4f40cc44a1664d4a701b2ae0f2
[gpl/argeo-slc.git] / JcrResultTreeView.java
1 /*
2 * Copyright (C) 2007-2012 Argeo GmbH
3 *
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16 package org.argeo.slc.client.ui.views;
17
18 import java.util.ArrayList;
19 import java.util.Calendar;
20 import java.util.List;
21
22 import javax.jcr.Node;
23 import javax.jcr.NodeIterator;
24 import javax.jcr.Property;
25 import javax.jcr.PropertyIterator;
26 import javax.jcr.PropertyType;
27 import javax.jcr.RepositoryException;
28 import javax.jcr.Session;
29 import javax.jcr.Value;
30 import javax.jcr.nodetype.NodeType;
31 import javax.jcr.observation.Event;
32 import javax.jcr.observation.EventListener;
33 import javax.jcr.observation.ObservationManager;
34
35 import org.argeo.ArgeoException;
36 import org.argeo.eclipse.ui.jcr.AsyncUiEventListener;
37 import org.argeo.eclipse.ui.utils.CommandUtils;
38 import org.argeo.jcr.JcrUtils;
39 import org.argeo.slc.SlcException;
40 import org.argeo.slc.client.ui.ClientUiPlugin;
41 import org.argeo.slc.client.ui.SlcUiConstants;
42 import org.argeo.slc.client.ui.commands.AddResultFolder;
43 import org.argeo.slc.client.ui.commands.RenameResultFolder;
44 import org.argeo.slc.client.ui.commands.RenameResultNode;
45 import org.argeo.slc.client.ui.editors.ProcessEditor;
46 import org.argeo.slc.client.ui.editors.ProcessEditorInput;
47 import org.argeo.slc.client.ui.model.ParentNodeFolder;
48 import org.argeo.slc.client.ui.model.ResultFolder;
49 import org.argeo.slc.client.ui.model.ResultItemsComparator;
50 import org.argeo.slc.client.ui.model.ResultItemsComparer;
51 import org.argeo.slc.client.ui.model.ResultParent;
52 import org.argeo.slc.client.ui.model.ResultParentUtils;
53 import org.argeo.slc.client.ui.model.SingleResultNode;
54 import org.argeo.slc.client.ui.model.VirtualFolder;
55 import org.argeo.slc.client.ui.providers.ResultTreeContentProvider;
56 import org.argeo.slc.client.ui.providers.ResultTreeLabelProvider;
57 import org.argeo.slc.client.ui.wizards.ConfirmOverwriteWizard;
58 import org.argeo.slc.jcr.SlcJcrResultUtils;
59 import org.argeo.slc.jcr.SlcNames;
60 import org.argeo.slc.jcr.SlcTypes;
61 import org.eclipse.jface.action.IMenuListener;
62 import org.eclipse.jface.action.IMenuManager;
63 import org.eclipse.jface.action.MenuManager;
64 import org.eclipse.jface.viewers.ColumnLabelProvider;
65 import org.eclipse.jface.viewers.DecoratingLabelProvider;
66 import org.eclipse.jface.viewers.DoubleClickEvent;
67 import org.eclipse.jface.viewers.IDoubleClickListener;
68 import org.eclipse.jface.viewers.ILabelDecorator;
69 import org.eclipse.jface.viewers.ISelectionChangedListener;
70 import org.eclipse.jface.viewers.IStructuredContentProvider;
71 import org.eclipse.jface.viewers.IStructuredSelection;
72 import org.eclipse.jface.viewers.SelectionChangedEvent;
73 import org.eclipse.jface.viewers.TableViewer;
74 import org.eclipse.jface.viewers.TableViewerColumn;
75 import org.eclipse.jface.viewers.TreePath;
76 import org.eclipse.jface.viewers.TreeViewer;
77 import org.eclipse.jface.viewers.Viewer;
78 import org.eclipse.jface.viewers.ViewerDropAdapter;
79 import org.eclipse.jface.wizard.WizardDialog;
80 import org.eclipse.swt.SWT;
81 import org.eclipse.swt.custom.SashForm;
82 import org.eclipse.swt.dnd.DND;
83 import org.eclipse.swt.dnd.DragSourceEvent;
84 import org.eclipse.swt.dnd.DragSourceListener;
85 import org.eclipse.swt.dnd.TextTransfer;
86 import org.eclipse.swt.dnd.Transfer;
87 import org.eclipse.swt.dnd.TransferData;
88 import org.eclipse.swt.layout.FillLayout;
89 import org.eclipse.swt.layout.GridData;
90 import org.eclipse.swt.layout.GridLayout;
91 import org.eclipse.swt.widgets.Composite;
92 import org.eclipse.swt.widgets.Display;
93 import org.eclipse.swt.widgets.Menu;
94 import org.eclipse.ui.ISharedImages;
95 import org.eclipse.ui.IWorkbenchPage;
96 import org.eclipse.ui.IWorkbenchWindow;
97 import org.eclipse.ui.PlatformUI;
98 import org.eclipse.ui.part.ViewPart;
99
100 /** SLC generic JCR Result tree view. */
101 public class JcrResultTreeView extends ViewPart {
102 public final static String ID = ClientUiPlugin.ID + ".jcrResultTreeView";
103
104 // private final static Log log =
105 // LogFactory.getLog(JcrResultTreeView.class);
106
107 /* DEPENDENCY INJECTION */
108 private Session session;
109
110 // This page widgets
111 private TreeViewer resultTreeViewer;
112 private TableViewer propertiesViewer;
113
114 private EventListener myResultsObserver = null;
115 private EventListener allResultsObserver = null;
116
117 // under My Results
118 private final static String[] observedNodeTypesUnderMyResult = {
119 SlcTypes.SLC_TEST_RESULT, SlcTypes.SLC_RESULT_FOLDER,
120 SlcTypes.SLC_MY_RESULT_ROOT_FOLDER };
121
122 private final static String[] observedNodeTypesUnderAllResults = {
123 SlcTypes.SLC_TEST_RESULT, NodeType.NT_UNSTRUCTURED };
124
125 // FIXME cache to ease D&D
126 private boolean isActionUnderMyResult = false;
127 // private ResultParent lastSelectedTargetElement;
128 private ResultParent lastSelectedSourceElement;
129 private ResultParent lastSelectedSourceElementParent;
130 private boolean isResultFolder = false;
131
132 // FIXME we cache the fact that we are moving a node to avoid exception
133 // triggered by the "Add Node" event while moving
134 // boolean isMoveInProgress = false;
135
136 /**
137 * To be overridden to adapt size of form and result frames.
138 */
139 protected int[] getWeights() {
140 return new int[] { 70, 30 };
141 }
142
143 @Override
144 public void createPartControl(Composite parent) {
145 parent.setLayout(new FillLayout());
146 // Main layout
147 SashForm sashForm = new SashForm(parent, SWT.VERTICAL);
148 sashForm.setSashWidth(4);
149 sashForm.setLayout(new FillLayout());
150
151 // Create the tree on top of the view
152 Composite top = new Composite(sashForm, SWT.NONE);
153 GridLayout gl = new GridLayout(1, false);
154 top.setLayout(gl);
155 resultTreeViewer = createResultsTreeViewer(top);
156
157 // Create the property viewer on the bottom
158 Composite bottom = new Composite(sashForm, SWT.NONE);
159 bottom.setLayout(new GridLayout(1, false));
160 propertiesViewer = createPropertiesViewer(bottom);
161
162 sashForm.setWeights(getWeights());
163
164 setOrderedInput(resultTreeViewer);
165
166 // Initialize observer
167 try {
168 ObservationManager observationManager = session.getWorkspace()
169 .getObservationManager();
170 myResultsObserver = new MyResultsObserver(resultTreeViewer
171 .getTree().getDisplay());
172 allResultsObserver = new AllResultsObserver(resultTreeViewer
173 .getTree().getDisplay());
174
175 // observe tree changes under MyResults
176 observationManager.addEventListener(myResultsObserver,
177 Event.NODE_ADDED | Event.NODE_REMOVED,
178 SlcJcrResultUtils.getMyResultsBasePath(session), true,
179 null, observedNodeTypesUnderMyResult, false);
180 // observe tree changes under All results
181 observationManager.addEventListener(allResultsObserver,
182 Event.NODE_ADDED | Event.NODE_REMOVED,
183 SlcJcrResultUtils.getSlcResultsBasePath(session), true,
184 null, observedNodeTypesUnderAllResults, false);
185 } catch (RepositoryException e) {
186 throw new SlcException("Cannot register listeners", e);
187 }
188 }
189
190 /**
191 * Override default behaviour so that default defined order remains
192 * unchanged on first level of the tree
193 */
194 private void setOrderedInput(TreeViewer viewer) {
195 // Add specific ordering
196 resultTreeViewer.setInput(null);
197 viewer.setComparator(null);
198 resultTreeViewer.setInput(initializeResultTree());
199 viewer.setComparator(new ResultItemsComparator());
200 }
201
202 // The main tree viewer
203 protected TreeViewer createResultsTreeViewer(Composite parent) {
204 int style = SWT.BORDER | SWT.MULTI;
205
206 TreeViewer viewer = new TreeViewer(parent, style);
207 viewer.getTree().setLayoutData(
208 new GridData(SWT.FILL, SWT.FILL, true, true));
209
210 viewer.setContentProvider(new ResultTreeContentProvider());
211
212 // Add label provider with label decorator
213 ResultTreeLabelProvider rtLblProvider = new ResultTreeLabelProvider();
214 ILabelDecorator decorator = ClientUiPlugin.getDefault().getWorkbench()
215 .getDecoratorManager().getLabelDecorator();
216 viewer.setLabelProvider(new DecoratingLabelProvider(rtLblProvider,
217 decorator));
218 viewer.addDoubleClickListener(new ViewDoubleClickListener());
219
220 // Override default behaviour to insure that 2 distincts results that
221 // have the same name will be correctly and distincly returned by
222 // corresponding
223 // TreeViewer.getSelection() method.
224 viewer.setComparer(new ResultItemsComparer());
225
226 // viewer.setLabelProvider(rtLblProvider);
227 getSite().setSelectionProvider(viewer);
228
229 // add drag & drop support
230 int operations = DND.DROP_COPY | DND.DROP_MOVE;
231 Transfer[] tt = new Transfer[] { TextTransfer.getInstance() };
232 viewer.addDragSupport(operations, tt, new ViewDragListener());
233 viewer.addDropSupport(operations, tt, new ViewDropListener(viewer));
234
235 // add context menu
236 MenuManager menuManager = new MenuManager();
237 Menu menu = menuManager.createContextMenu(viewer.getTree());
238 menuManager.addMenuListener(new IMenuListener() {
239 public void menuAboutToShow(IMenuManager manager) {
240 contextMenuAboutToShow(manager);
241 }
242 });
243 viewer.getTree().setMenu(menu);
244 getSite().registerContextMenu(menuManager, viewer);
245
246 // add change listener to display TestResult information in the property
247 // viewer
248 viewer.addSelectionChangedListener(new MySelectionChangedListener());
249 return viewer;
250 }
251
252 // Detailed property viewer
253 protected TableViewer createPropertiesViewer(Composite parent) {
254 propertiesViewer = new TableViewer(parent);
255 propertiesViewer.getTable().setLayoutData(
256 new GridData(SWT.FILL, SWT.FILL, true, true));
257 propertiesViewer.getTable().setHeaderVisible(true);
258 propertiesViewer.setContentProvider(new PropertiesContentProvider());
259 TableViewerColumn col = new TableViewerColumn(propertiesViewer,
260 SWT.NONE);
261 col.getColumn().setText("Name");
262 col.getColumn().setWidth(200);
263 col.setLabelProvider(new ColumnLabelProvider() {
264 public String getText(Object element) {
265 try {
266 return ((Property) element).getName();
267 } catch (RepositoryException e) {
268 throw new ArgeoException(
269 "Unexpected exception in label provider", e);
270 }
271 }
272 });
273 col = new TableViewerColumn(propertiesViewer, SWT.NONE);
274 col.getColumn().setText("Value");
275 col.getColumn().setWidth(400);
276 col.setLabelProvider(new ColumnLabelProvider() {
277 public String getText(Object element) {
278 try {
279 Property property = (Property) element;
280 if (property.getType() == PropertyType.BINARY)
281 return "<binary>";
282 else if (property.isMultiple()) {
283 StringBuffer buf = new StringBuffer("[");
284 Value[] values = property.getValues();
285 for (int i = 0; i < values.length; i++) {
286 if (i != 0)
287 buf.append(", ");
288 buf.append(values[i].getString());
289 }
290 buf.append(']');
291 return buf.toString();
292 } else
293 return property.getValue().getString();
294 } catch (RepositoryException e) {
295 throw new ArgeoException(
296 "Unexpected exception in label provider", e);
297 }
298 }
299 });
300 col = new TableViewerColumn(propertiesViewer, SWT.NONE);
301 col.getColumn().setText("Type");
302 col.getColumn().setWidth(200);
303 col.setLabelProvider(new ColumnLabelProvider() {
304 public String getText(Object element) {
305 try {
306 return PropertyType.nameFromValue(((Property) element)
307 .getType());
308 } catch (RepositoryException e) {
309 throw new ArgeoException(
310 "Unexpected exception in label provider", e);
311 }
312 }
313 });
314 propertiesViewer.setInput(getViewSite());
315 return propertiesViewer;
316 }
317
318 /**
319 * Override to provide specific behaviour. Typically to enable the display
320 * of a result file.
321 *
322 * @param evt
323 */
324 protected void processDoubleClick(DoubleClickEvent evt) {
325 Object obj = ((IStructuredSelection) evt.getSelection())
326 .getFirstElement();
327 try {
328 if (obj instanceof SingleResultNode) {
329 SingleResultNode srNode = (SingleResultNode) obj;
330 Node node = srNode.getNode();
331 // FIXME: open a default result editor
332 if (node.isNodeType(SlcTypes.SLC_PROCESS)) {
333 IWorkbenchPage activePage = PlatformUI.getWorkbench()
334 .getActiveWorkbenchWindow().getActivePage();
335 activePage.openEditor(
336 new ProcessEditorInput(node.getPath()),
337 ProcessEditor.ID);
338 }
339 }
340 } catch (Exception e) {
341 throw new SlcException("Cannot open " + obj, e);
342 }
343 }
344
345 @Override
346 public void setFocus() {
347 }
348
349 /**
350 * refreshes the passed resultParent and its corresponding subtree. It
351 * refreshes the whole viewer if null is passed.
352 *
353 * @param ResultParent
354 *
355 */
356 public void refresh(ResultParent resultParent) {
357 if (resultParent == null) {
358 if (!resultTreeViewer.getTree().isDisposed()) {
359 TreePath[] tps = resultTreeViewer.getExpandedTreePaths();
360 setOrderedInput(resultTreeViewer);
361 resultTreeViewer.setExpandedTreePaths(tps);
362 } else
363 setOrderedInput(resultTreeViewer);
364 } else {
365 if (resultParent instanceof ParentNodeFolder) {
366 ParentNodeFolder currFolder = (ParentNodeFolder) resultParent;
367 jcrRefresh(currFolder.getNode());
368 currFolder.forceFullRefresh();
369 }
370 // FIXME: specific refresh does not work
371 // resultTreeViewer.refresh(resultParent, true);
372 refresh(null);
373 }
374 }
375
376 /**
377 * refreshes the passed node and its corresponding subtree.
378 *
379 * @param node
380 * cannot be null
381 *
382 */
383 public boolean jcrRefresh(Node node) {
384 // if (log.isDebugEnabled())
385 // log.debug(" JCR refreshing " + node + "...");
386 // Thread.dumpStack();
387 boolean isPassed = true;
388 try {
389 if (node.isNodeType(SlcTypes.SLC_TEST_RESULT)) {
390 isPassed = node.getNode(SlcNames.SLC_STATUS)
391 .getProperty(SlcNames.SLC_SUCCESS).getBoolean();
392 } else if (node.isNodeType(SlcTypes.SLC_RESULT_FOLDER)) {
393 NodeIterator ni = node.getNodes();
394 while (ni.hasNext()) {
395 Node currChild = ni.nextNode();
396 isPassed = isPassed & jcrRefresh(currChild);
397 }
398 if (isPassed != node.getNode(SlcNames.SLC_STATUS)
399 .getProperty(SlcNames.SLC_SUCCESS).getBoolean()) {
400 node.getNode(SlcNames.SLC_STATUS).setProperty(
401 SlcNames.SLC_SUCCESS, isPassed);
402 node.getSession().save();
403 return isPassed;
404 }
405 } else
406 ; // do nothing
407 } catch (RepositoryException e) {
408 throw new SlcException("Cannot register listeners", e);
409 }
410 return isPassed;
411 }
412
413 private ResultParent[] initializeResultTree() {
414 try {
415 // Force initialization of the tree structure if needed
416 SlcJcrResultUtils.getSlcResultsParentNode(session);
417 SlcJcrResultUtils.getMyResultParentNode(session);
418 // Remove yesterday and last 7 days virtual folders
419 // ResultParent[] roots = new ResultParent[5];
420 ResultParent[] roots = new ResultParent[3];
421
422 // My results
423 roots[0] = new ParentNodeFolder(null,
424 SlcJcrResultUtils.getMyResultParentNode(session),
425 SlcUiConstants.DEFAULT_MY_RESULTS_FOLDER_LABEL);
426
427 // today
428 Calendar cal = Calendar.getInstance();
429 String relPath = JcrUtils.dateAsPath(cal);
430 List<String> datePathes = new ArrayList<String>();
431 datePathes.add(relPath);
432 roots[1] = new VirtualFolder(null,
433 ResultParentUtils.getResultsForDates(session, datePathes),
434 "Today");
435
436 // // Yesterday
437 // cal = Calendar.getInstance();
438 // cal.add(Calendar.DAY_OF_YEAR, -1);
439 // relPath = JcrUtils.dateAsPath(cal);
440 // datePathes = new ArrayList<String>();
441 // datePathes.add(relPath);
442 // roots[2] = new VirtualFolder(null,
443 // ResultParentUtils.getResultsForDates(session, datePathes),
444 // "Yesterday");
445 // // Last 7 days
446 //
447 // cal = Calendar.getInstance();
448 // datePathes = new ArrayList<String>();
449 //
450 // for (int i = 0; i < 7; i++) {
451 // cal.add(Calendar.DAY_OF_YEAR, -i);
452 // relPath = JcrUtils.dateAsPath(cal);
453 // datePathes.add(relPath);
454 // }
455 // roots[3] = new VirtualFolder(null,
456 // ResultParentUtils.getResultsForDates(session, datePathes),
457 // "Last 7 days");
458
459 // All results
460 Node otherResultsPar = session.getNode(SlcJcrResultUtils
461 .getSlcResultsBasePath(session));
462 // roots[4] = new ParentNodeFolder(null, otherResultsPar,
463 // "All results");
464 roots[2] = new ParentNodeFolder(null, otherResultsPar,
465 "All results");
466 return roots;
467 } catch (RepositoryException re) {
468 throw new ArgeoException(
469 "Unexpected error while initializing ResultTree.", re);
470 }
471 }
472
473 // Manage context menu
474 /**
475 * Defines the commands that will pop up in the context menu.
476 **/
477 protected void contextMenuAboutToShow(IMenuManager menuManager) {
478 IWorkbenchWindow window = ClientUiPlugin.getDefault().getWorkbench()
479 .getActiveWorkbenchWindow();
480
481 IStructuredSelection selection = (IStructuredSelection) resultTreeViewer
482 .getSelection();
483 boolean canAddSubfolder = false;
484 boolean canRenamefolder = false;
485 boolean isSingleResultNode = false;
486 // Building conditions
487 if (selection.size() == 1) {
488 Object obj = selection.getFirstElement();
489 try {
490 if (obj instanceof SingleResultNode)
491 isSingleResultNode = true;
492 else if (obj instanceof ParentNodeFolder) {
493 Node cNode = ((ParentNodeFolder) obj).getNode();
494 if (cNode.isNodeType(SlcTypes.SLC_RESULT_FOLDER)) {
495 canAddSubfolder = true;
496 canRenamefolder = true;
497 } else if (cNode
498 .isNodeType(SlcTypes.SLC_MY_RESULT_ROOT_FOLDER)) {
499 canAddSubfolder = true;
500 }
501 }
502 } catch (RepositoryException re) {
503 throw new SlcException(
504 "unexpected error while building condition for context menu",
505 re);
506 }
507 }
508 // Effective Refresh
509 CommandUtils.refreshCommand(menuManager, window, AddResultFolder.ID,
510 AddResultFolder.DEFAULT_LABEL,
511 ClientUiPlugin.getDefault().getWorkbench().getSharedImages()
512 .getImageDescriptor(ISharedImages.IMG_OBJ_ADD),
513 canAddSubfolder);
514
515 CommandUtils.refreshCommand(menuManager, window, RenameResultFolder.ID,
516 RenameResultFolder.DEFAULT_LABEL,
517 RenameResultFolder.DEFAULT_IMG_DESCRIPTOR, canRenamefolder);
518
519 CommandUtils.refreshCommand(menuManager, window, RenameResultNode.ID,
520 RenameResultNode.DEFAULT_LABEL,
521 RenameResultNode.DEFAULT_IMG_DESCRIPTOR, isSingleResultNode);
522 }
523
524 /* INNER CLASSES */
525 class ViewDragListener implements DragSourceListener {
526
527 public void dragStart(DragSourceEvent event) {
528 // Check if the drag action should start.
529 IStructuredSelection selection = (IStructuredSelection) resultTreeViewer
530 .getSelection();
531 boolean doIt = false;
532 // only one node at a time for the time being.
533 if (selection.size() == 1) {
534 try {
535 Object obj = selection.getFirstElement();
536 if (obj instanceof SingleResultNode) {
537 Node tNode = ((SingleResultNode) obj).getNode();
538 if (tNode.getPrimaryNodeType().isNodeType(
539 SlcTypes.SLC_TEST_RESULT)) {
540 doIt = true;
541 isResultFolder = false;
542 }
543 } else if (obj instanceof ResultFolder) {
544 Node tNode = ((ResultFolder) obj).getNode();
545 if (tNode.getPrimaryNodeType().isNodeType(
546 SlcTypes.SLC_RESULT_FOLDER)) {
547 doIt = true;
548 isResultFolder = true;
549 }
550 }
551 } catch (RepositoryException re) {
552 throw new SlcException(
553 "unexpected error while validating drag source", re);
554 }
555 }
556 event.doit = doIt;
557 }
558
559 public void dragSetData(DragSourceEvent event) {
560 IStructuredSelection selection = (IStructuredSelection) resultTreeViewer
561 .getSelection();
562 Object obj = selection.getFirstElement();
563 try {
564 Node first;
565 if (obj instanceof SingleResultNode) {
566 first = ((SingleResultNode) obj).getNode();
567 event.data = first.getIdentifier();
568 } else if (obj instanceof ResultFolder) {
569 first = ((ResultFolder) obj).getNode();
570 event.data = first.getIdentifier();
571 }
572 } catch (RepositoryException re) {
573 throw new SlcException("unexpected error while setting data",
574 re);
575 }
576 }
577
578 public void dragFinished(DragSourceEvent event) {
579 // refresh is done via observer
580 }
581 }
582
583 // Implementation of the Drop Listener
584 protected class ViewDropListener extends ViewerDropAdapter {
585 private Node targetParentNode = null;
586
587 public ViewDropListener(Viewer viewer) {
588 super(viewer);
589 }
590
591 @Override
592 public boolean validateDrop(Object target, int operation,
593 TransferData transferType) {
594 boolean validDrop = false;
595 try {
596 // We can only drop under myResults
597 Node tpNode = null;
598 if (target instanceof SingleResultNode) {
599 Node currNode = ((SingleResultNode) target).getNode();
600 String pPath = currNode.getParent().getPath();
601 if (pPath.startsWith(SlcJcrResultUtils
602 .getMyResultsBasePath(session)))
603 tpNode = currNode.getParent();
604 } else if (target instanceof ResultFolder) {
605 tpNode = ((ResultFolder) target).getNode();
606 } else if (target instanceof ParentNodeFolder) {
607 Node node = ((ParentNodeFolder) target).getNode();
608 if (node.isNodeType(SlcTypes.SLC_MY_RESULT_ROOT_FOLDER))
609 tpNode = ((ParentNodeFolder) target).getNode();
610 }
611
612 if (tpNode != null) {
613 // Sanity check : we cannot move a folder to one of its sub
614 // folder or neither move an object in the same parent
615 // folder
616 boolean doit = true;
617 Node source = null;
618 if (isResultFolder) {
619 source = ((ParentNodeFolder) lastSelectedSourceElement)
620 .getNode();
621 if (tpNode.getPath().startsWith(source.getPath())
622 || source.getParent().getPath()
623 .equals(tpNode.getPath()))
624 doit = false;
625 } else if (lastSelectedSourceElement instanceof SingleResultNode) {
626 source = ((SingleResultNode) lastSelectedSourceElement)
627 .getNode();
628 String sourceParentPath = JcrUtils.parentPath(source
629 .getPath());
630 if (tpNode.getPath().equals(sourceParentPath))
631 doit = false;
632 }
633 if (doit) {
634 targetParentNode = tpNode;
635 validDrop = true;
636 // lastSelectedTargetElement = (ResultParent) target;
637 }
638 }
639 } catch (RepositoryException re) {
640 throw new SlcException(
641 "unexpected error while validating drop target", re);
642 }
643 return validDrop;
644 }
645
646 @Override
647 public boolean performDrop(Object data) {
648 // clear selection to prevent unwanted scrolling of the UI
649 resultTreeViewer.setSelection(null);
650 try {
651 Node source = session.getNodeByIdentifier((String) data);
652
653 String name;
654 if (source.hasProperty(Property.JCR_TITLE))
655 name = source.getProperty(Property.JCR_TITLE).getString();
656 else if (source.hasProperty(SlcNames.SLC_TEST_CASE))
657 name = source.getProperty(SlcNames.SLC_TEST_CASE)
658 .getString();
659 else
660 name = source.getName();
661
662 // Check if a user defined folder result with same name exists
663 // at target
664 if (targetParentNode.hasNode(name)
665 && targetParentNode.getNode(name).isNodeType(
666 SlcTypes.SLC_RESULT_FOLDER)) {
667 ConfirmOverwriteWizard wizard = new ConfirmOverwriteWizard(
668 name, targetParentNode);
669 WizardDialog dialog = new WizardDialog(Display.getDefault()
670 .getActiveShell(), wizard);
671
672 if (dialog.open() == WizardDialog.CANCEL)
673 return true;
674
675 if (wizard.overwrite()) {
676 targetParentNode.getNode(name).remove();
677 // session.save();
678 } else
679 name = wizard.newName();
680 }
681
682 Node target;
683 boolean passedStatus = source.getNode(SlcNames.SLC_STATUS)
684 .getProperty(SlcNames.SLC_SUCCESS).getBoolean();
685 if (!isActionUnderMyResult) {// Copy
686 target = targetParentNode.addNode(source.getName(), source
687 .getPrimaryNodeType().getName());
688 JcrUtils.copy(source, target);
689 } else {// move
690 String sourcePath = source.getPath();
691 String destPath = targetParentNode.getPath() + "/" + name;
692 session.move(sourcePath, destPath);
693 // session.save();
694 // Update passed status of the parent source Node
695 ResultParentUtils.updatePassedStatus(
696 session.getNode(JcrUtils.parentPath(sourcePath)),
697 true);
698 target = session.getNode(destPath);
699
700 }
701 if (!target.isNodeType(NodeType.MIX_TITLE))
702 target.addMixin(NodeType.MIX_TITLE);
703 target.setProperty(Property.JCR_TITLE, name);
704 ResultParentUtils.updatePassedStatus(target.getParent(),
705 passedStatus);
706 session.save();
707 } catch (RepositoryException re) {
708 throw new SlcException(
709 "unexpected error while copying dropped node", re);
710 }
711 return true;
712 }
713 }
714
715 class MyResultsObserver extends AsyncUiEventListener {
716
717 public MyResultsObserver(Display display) {
718 super(display);
719 }
720
721 @Override
722 protected Boolean willProcessInUiThread(List<Event> events)
723 throws RepositoryException {
724 // unfiltered for the time being
725 return true;
726 }
727
728 protected void onEventInUiThread(List<Event> events)
729 throws RepositoryException {
730 List<Node> nodesToRefresh = new ArrayList<Node>();
731
732 for (Event event : events) {
733 String parPath = JcrUtils.parentPath(event.getPath());
734 if (session.nodeExists(parPath)) {
735 Node node = session.getNode(parPath);
736 if (!nodesToRefresh.contains(node)) {
737 nodesToRefresh.add(node);
738 }
739 }
740 }
741
742 // Update check nodes
743 for (Node node : nodesToRefresh)
744 jcrRefresh(node);
745 refresh(null);
746 }
747 }
748
749 class AllResultsObserver extends AsyncUiEventListener {
750
751 public AllResultsObserver(Display display) {
752 super(display);
753 }
754
755 @Override
756 protected Boolean willProcessInUiThread(List<Event> events)
757 throws RepositoryException {
758 // unfiltered for the time being
759 return true;
760 }
761
762 protected void onEventInUiThread(List<Event> events)
763 throws RepositoryException {
764 if (lastSelectedSourceElementParent != null)
765 refresh(lastSelectedSourceElementParent);
766 }
767 }
768
769 class PropertiesContentProvider implements IStructuredContentProvider {
770
771 public void dispose() {
772 }
773
774 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
775 }
776
777 public Object[] getElements(Object inputElement) {
778 try {
779 if (inputElement instanceof Node) {
780 List<Property> props = new ArrayList<Property>();
781 PropertyIterator pit = ((Node) inputElement)
782 .getProperties();
783 while (pit.hasNext())
784 props.add(pit.nextProperty());
785 return props.toArray();
786 }
787 return new Object[] {};
788 } catch (RepositoryException e) {
789 throw new ArgeoException("Cannot get element for "
790 + inputElement, e);
791 }
792 }
793 }
794
795 class MySelectionChangedListener implements ISelectionChangedListener {
796
797 public void selectionChanged(SelectionChangedEvent event) {
798 if (!event.getSelection().isEmpty()) {
799 IStructuredSelection sel = (IStructuredSelection) event
800 .getSelection();
801 ResultParent firstItem = (ResultParent) sel.getFirstElement();
802 if (firstItem instanceof SingleResultNode)
803 propertiesViewer.setInput(((SingleResultNode) firstItem)
804 .getNode());
805 else
806 propertiesViewer.setInput(null);
807 // update cache for Drag & drop
808 // lastSelectedTargetElement = firstItem;
809 lastSelectedSourceElement = firstItem;
810 lastSelectedSourceElementParent = (ResultParent) firstItem
811 .getParent();
812 String pPath = "";
813 try {
814
815 if (firstItem instanceof ParentNodeFolder)
816 pPath = ((ParentNodeFolder) firstItem).getNode()
817 .getPath();
818 else if (firstItem instanceof SingleResultNode)
819 pPath = ((SingleResultNode) firstItem).getNode()
820 .getPath();
821 } catch (RepositoryException e) {
822 throw new SlcException(
823 "Unexpected error while checking parent UI tree", e);
824 }
825 if ((pPath.startsWith(SlcJcrResultUtils
826 .getMyResultsBasePath(session))))
827 isActionUnderMyResult = true;
828 else
829 isActionUnderMyResult = false;
830 }
831 }
832 }
833
834 class ViewDoubleClickListener implements IDoubleClickListener {
835 public void doubleClick(DoubleClickEvent evt) {
836 processDoubleClick(evt);
837 }
838
839 }
840
841 /* DEPENDENCY INJECTION */
842 public void setSession(Session session) {
843 this.session = session;
844 }
845
846 }