3d394830b538ceec6c9dab2dce9a9b7d6dd58595
[taxeditor.git] / eu.etaxonomy.taxeditor.store / src / main / java / eu / etaxonomy / taxeditor / model / AbstractUtility.java
1 /**
2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9
10 package eu.etaxonomy.taxeditor.model;
11
12 import java.lang.reflect.Field;
13 import java.lang.reflect.InvocationTargetException;
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.LinkedHashMap;
17 import java.util.List;
18 import java.util.TreeSet;
19 import java.util.UUID;
20
21 import org.apache.commons.lang.StringUtils;
22 import org.apache.log4j.Logger;
23 import org.eclipse.core.commands.ExecutionException;
24 import org.eclipse.core.commands.NotEnabledException;
25 import org.eclipse.core.commands.NotHandledException;
26 import org.eclipse.core.commands.common.NotDefinedException;
27 import org.eclipse.core.commands.operations.AbstractOperation;
28 import org.eclipse.core.commands.operations.IOperationHistory;
29 import org.eclipse.core.runtime.IAdaptable;
30 import org.eclipse.core.runtime.IProgressMonitor;
31 import org.eclipse.core.runtime.IStatus;
32 import org.eclipse.core.runtime.NullProgressMonitor;
33 import org.eclipse.core.runtime.OperationCanceledException;
34 import org.eclipse.core.runtime.Status;
35 import org.eclipse.core.runtime.SubProgressMonitor;
36 import org.eclipse.core.runtime.jobs.ISchedulingRule;
37 import org.eclipse.core.runtime.jobs.Job;
38 import org.eclipse.e4.ui.model.application.ui.basic.MPart;
39 import org.eclipse.jface.action.IStatusLineManager;
40 import org.eclipse.jface.operation.IRunnableWithProgress;
41 import org.eclipse.jface.resource.ColorRegistry;
42 import org.eclipse.jface.resource.FontRegistry;
43 import org.eclipse.jface.viewers.IStructuredSelection;
44 import org.eclipse.jface.viewers.SelectionChangedEvent;
45 import org.eclipse.swt.graphics.Color;
46 import org.eclipse.swt.graphics.Font;
47 import org.eclipse.swt.widgets.Display;
48 import org.eclipse.swt.widgets.Shell;
49 import org.eclipse.ui.IEditorPart;
50 import org.eclipse.ui.IViewPart;
51 import org.eclipse.ui.IViewReference;
52 import org.eclipse.ui.IWorkbench;
53 import org.eclipse.ui.IWorkbenchPage;
54 import org.eclipse.ui.IWorkbenchPart;
55 import org.eclipse.ui.IWorkbenchWindow;
56 import org.eclipse.ui.PartInitException;
57 import org.eclipse.ui.PlatformUI;
58 import org.eclipse.ui.handlers.IHandlerService;
59 import org.eclipse.ui.ide.undo.WorkspaceUndoUtil;
60 import org.eclipse.ui.internal.E4PartWrapper;
61 import org.eclipse.ui.part.EditorPart;
62 import org.eclipse.ui.progress.IProgressConstants;
63 import org.eclipse.ui.progress.IProgressService;
64 import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
65 import org.eclipse.ui.themes.ITheme;
66 import org.eclipse.ui.themes.IThemeManager;
67
68 import eu.etaxonomy.cdm.api.application.CdmApplicationState;
69 import eu.etaxonomy.cdm.api.service.IProgressMonitorService;
70 import eu.etaxonomy.cdm.common.monitor.IRemotingProgressMonitor;
71 import eu.etaxonomy.cdm.model.common.IEnumTerm;
72 import eu.etaxonomy.taxeditor.operation.AbstractPostOperation;
73 import eu.etaxonomy.taxeditor.operation.IFeedbackGenerator;
74 import eu.etaxonomy.taxeditor.operation.IPostMoniteredOperationEnabled;
75 import eu.etaxonomy.taxeditor.operation.IPostOperationEnabled;
76 import eu.etaxonomy.taxeditor.operation.RemotingCdmHandler;
77 import eu.etaxonomy.taxeditor.store.CdmStore;
78 import eu.etaxonomy.taxeditor.store.internal.TaxeditorStorePlugin;
79 import eu.etaxonomy.taxeditor.ui.dialog.ReportTextDialog;
80 import eu.etaxonomy.taxeditor.view.AbstractCdmDataViewer;
81 import eu.etaxonomy.taxeditor.view.detail.DetailsViewPart;
82 import eu.etaxonomy.taxeditor.view.supplementaldata.SupplementalDataViewPart;
83
84 /**
85 *
86 * @author n.hoffmann
87 * @created 11.05.2009
88 * @version 1.0
89 */
90 public abstract class AbstractUtility {
91
92 private static final Logger logger = Logger.getLogger(AbstractUtility.class);
93
94 /** Constant <code>statusLineManager</code> */
95 protected static IStatusLineManager statusLineManager;
96
97
98 public static boolean closeAll() {
99 if(getActivePage()!=null){
100 return getActivePage().closeAllEditors(true);
101 }
102 return false;
103 }
104
105 /**
106 * Close the given editor.
107 *
108 * @param editor
109 * The <tt>MultipageTaxonEditor</tt> to close.
110 * @return <tt>true</tt> on success
111 */
112 public static boolean close(EditorPart editor) {
113 return getActivePage() != null ? getActivePage().closeEditor(editor, true):false;
114 }
115
116 public static Shell getShell() {
117
118 return TaxeditorStorePlugin.getDefault().getWorkbench()
119 .getActiveWorkbenchWindow().getShell();
120 }
121
122 public static IWorkbenchPage getActivePage() {
123 try{
124 return TaxeditorStorePlugin.getDefault().getWorkbench()
125 .getActiveWorkbenchWindow().getActivePage();
126 } catch(NullPointerException npe){
127 return null;
128 }
129 }
130
131 public static IWorkbenchPart getActiveWorkbenchPart() {
132 IWorkbenchPage activePage = getActivePage();
133 if(activePage!=null){
134 IWorkbenchPart activePart = activePage.getActivePart();
135 if(activePart!=null){
136 return activePart;
137 }
138 }
139 return null;
140 }
141
142 public static Object getActiveE4Part() {
143 IWorkbenchPage activePage = getActivePage();
144 if(activePage!=null){
145 IWorkbenchPart activePart = activePage.getActivePart();
146 Object e4WrappedPart = getE4WrappedPart(activePart);
147 return e4WrappedPart!=null?e4WrappedPart:activePart;
148 }
149 return null;
150 }
151
152 public static Object getE4WrappedPart(Object activePart){
153 if(activePart instanceof E4PartWrapper){
154 //FIXME can be removed when E4 migration is complete
155 try {
156 Field field = activePart.getClass().getDeclaredField("wrappedPart");
157 field.setAccessible(true);
158 Object object = field.get(activePart);
159 if(object instanceof MPart){
160 return ((MPart) object).getObject();
161 }
162 } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
163 e.printStackTrace();
164 }
165 }
166 return null;
167 }
168
169 public static IWorkbench getWorkbench() {
170 return TaxeditorStorePlugin.getDefault().getWorkbench();
171 }
172
173 public static IWorkbenchWindow getWorkbenchWindow() {
174 if (getWorkbench().getWorkbenchWindowCount() > 1) {
175 throw new IllegalStateException("More than one workbench window");
176 }
177 return getWorkbench().getWorkbenchWindows()[0];
178 }
179
180 public static IViewPart showView(String id) {
181 try {
182 return PlatformUI.getWorkbench().getActiveWorkbenchWindow()
183 .getActivePage()
184 .showView(id, null, IWorkbenchPage.VIEW_VISIBLE);
185 } catch (PartInitException e) {
186 MessagingUtils.messageDialog("Error opening view", AbstractUtility.class, "Could not open view: " + id, e);
187 return null;
188 }
189 }
190
191 public static void hideView(IViewPart view) {
192 PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
193 .hideView(view);
194 }
195
196 public static IViewPart getView(String id, boolean restore) {
197 IWorkbench workbench = PlatformUI.getWorkbench();
198 IWorkbenchWindow activeWorkbenchWindow = workbench.getActiveWorkbenchWindow();
199 IViewReference[] references = null;
200 if(activeWorkbenchWindow!=null && activeWorkbenchWindow.getActivePage()!=null){
201 references = activeWorkbenchWindow.getActivePage().getViewReferences();
202 }
203 else if(workbench.getWorkbenchWindows().length>0 && workbench.getWorkbenchWindows()[0].getActivePage()!=null){
204 references = workbench.getWorkbenchWindows()[0].getActivePage().getViewReferences();
205 }
206 if(references!=null){
207 for (IViewReference reference : references) {
208 if (reference.getId().equals(id)) {
209 return reference.getView(restore);
210 }
211 }
212 }
213 return null;
214 }
215
216 public static Object getService(Class api) {
217 return TaxeditorStorePlugin.getDefault().getWorkbench().getService(api);
218 }
219
220 public static ITheme getCurrentTheme() {
221 IThemeManager themeManager = TaxeditorStorePlugin.getDefault()
222 .getWorkbench().getThemeManager();
223 return themeManager.getCurrentTheme();
224 }
225
226 /**
227 * Fonts registered to the plugin may be obtained with the Eclipse themeing
228 * functionality. Thus fonts are chooseable by the user via
229 * Preferences->General->Appearance->Colors and Fonts
230 *
231 * @return the FontRegistry for the current theme
232 */
233 public static FontRegistry getFontRegistry() {
234 return getCurrentTheme().getFontRegistry();
235 }
236
237 public static Font getFont(String symbolicName) {
238 return getFontRegistry().get(symbolicName);
239 }
240
241 /**
242 * Color registered to the plugin may be obtained with the Eclipse themeing
243 * functionality. Thus colors are editable by the user via
244 * Preferences->General->Appearance->Colors and Fonts
245 *
246 * @return the ColorRegistry for the current theme
247 */
248 public static ColorRegistry getColorRegistry() {
249 return getCurrentTheme().getColorRegistry();
250 }
251
252 public static Color getColor(String symbolicName) {
253 return getColorRegistry().get(symbolicName);
254 }
255
256 public static IStatus executeOperation(final AbstractPostOperation operation) {
257 if (getOperationHistory() == null) {
258 throw new IllegalArgumentException(
259 "There is no operation history for this context");
260 }
261
262 final IAdaptable uiInfoAdapter = WorkspaceUndoUtil
263 .getUIInfoAdapter(getShell());
264
265 IRunnableWithProgress runnable = new IRunnableWithProgress() {
266
267 @Override
268 public void run(IProgressMonitor monitor)
269 throws InvocationTargetException, InterruptedException {
270 String operationlabel = operation.getLabel();
271 monitor.beginTask(operationlabel, 100);
272 IStatus status = Status.CANCEL_STATUS;
273 try {
274 operation.addContext(IOperationHistory.GLOBAL_UNDO_CONTEXT);
275 status = getOperationHistory().execute(operation, monitor,
276 uiInfoAdapter);
277 } catch (ExecutionException e) {
278
279 MessagingUtils.operationDialog(this, e, TaxeditorStorePlugin.PLUGIN_ID, operationlabel, null);
280
281 } finally {
282 monitor.done();
283 }
284
285 String statusString = status.equals(Status.OK_STATUS) ? "completed"
286 : "cancelled";
287 setStatusLine(operationlabel + " " + statusString + ".");
288
289 }
290 };
291
292 try {
293 runInUI(runnable, null);
294 } catch (Exception e) {
295 MessagingUtils.messageDialog("Error executing operation", AbstractUtility.class, "An error occured while executing " + operation.getLabel(), e);
296 }
297
298 IPostOperationEnabled postOperationEnabled = operation
299 .getPostOperationEnabled();
300 if (postOperationEnabled != null) {
301 postOperationEnabled.onComplete();
302 }
303 return Status.OK_STATUS;
304 }
305
306 public static IStatus executeOperation(final AbstractOperation operation, final RemotingCdmHandler handler) {
307 if (getOperationHistory() == null) {
308 throw new IllegalArgumentException(
309 "There is no operation history for this context");
310 }
311
312 final IAdaptable uiInfoAdapter = WorkspaceUndoUtil
313 .getUIInfoAdapter(getShell());
314
315 IRunnableWithProgress runnable = new IRunnableWithProgress() {
316
317 @Override
318 public void run(IProgressMonitor monitor)
319 throws InvocationTargetException, InterruptedException {
320 String operationlabel = operation.getLabel();
321 monitor.beginTask(operationlabel, 100);
322 IStatus status = Status.CANCEL_STATUS;
323 try {
324 operation.addContext(IOperationHistory.GLOBAL_UNDO_CONTEXT);
325 status = getOperationHistory().execute(operation, monitor,
326 uiInfoAdapter);
327 if(handler != null) {
328 handler.postOperation(status);
329 }
330 } catch (ExecutionException e) {
331 MessagingUtils.operationDialog(this, e, TaxeditorStorePlugin.PLUGIN_ID, operationlabel, null);
332 } finally {
333 monitor.done();
334 }
335
336 String statusString = status.equals(Status.OK_STATUS) ? "completed"
337 : "cancelled";
338 setStatusLine(operationlabel + " " + statusString + ".");
339
340 }
341 };
342
343 try {
344 runInUI(runnable, null);
345 } catch (Exception e) {
346 MessagingUtils.messageDialog("Error executing operation", AbstractUtility.class, "An error occured while executing " + operation.getLabel(), e);
347 }
348
349 return Status.OK_STATUS;
350 }
351
352 /**
353 * Executes a remoting monitored operation
354 *
355 * @param label for the operation
356 * @param uuid of the remoting monitor already started on the server
357 * @param pollInterval in milliseconds
358 * @param cancelable flag which determines whether the operation can be cancelled
359 * @param postOp callback for running post operation logic
360 * @return
361 */
362 public static IStatus executeMoniteredOperation(final String label,
363 final UUID uuid,
364 final int pollInterval,
365 final boolean cancelable,
366 final IPostMoniteredOperationEnabled postOp,
367 final IFeedbackGenerator feedbackGenerator) {
368
369 try {
370 // get the remoting monitor the first time to make sure that the
371 // operation is valid
372 final IProgressMonitorService progressMonitorService = CdmApplicationState.getCurrentAppConfig().getProgressMonitorService();
373 final IRemotingProgressMonitor firstRemotingMonitor = progressMonitorService.getRemotingMonitor(uuid);
374 if(firstRemotingMonitor == null) {
375 throw new IllegalStateException("Remoting progress monitor is null");
376 }
377
378 Job job = new Job(label) {
379
380
381 @Override
382 public IStatus run(IProgressMonitor monitor) {
383 // run the monitor until the operation is finished
384 IRemotingProgressMonitor remotingMonitor;
385 try {
386 remotingMonitor = CdmStore.getProgressMonitorClientManager().pollMonitor(label,
387 uuid,
388 pollInterval,
389 postOp,
390 feedbackGenerator,
391 monitor);
392 } catch (Exception ex) {
393 return new Status(Status.ERROR, TaxeditorStorePlugin.PLUGIN_ID, "Operation Interrupted", ex);
394 }
395 final StringBuilder reportSb = new StringBuilder();
396 // collect reports
397 for(String report : remotingMonitor.getReports()) {
398 reportSb.append(report);
399 }
400 if(!StringUtils.isBlank(reportSb.toString())) {
401 Display.getDefault().asyncExec(new Runnable() {
402 @Override
403 public void run() {
404 // display reports with possibility to save
405 ReportTextDialog dialog = new ReportTextDialog(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell());
406 dialog.setTitle(label + " Report");
407 dialog.setReportText(reportSb.toString());
408 dialog.open();
409 }
410 });
411 }
412 return Status.OK_STATUS;
413 }
414
415 @Override
416 protected void canceling() {
417 CdmStore.getCurrentApplicationConfiguration().getProgressMonitorService().cancel(uuid);
418 }
419 };
420
421 // configure the job
422 job.setProperty(IProgressConstants.KEEP_PROPERTY, true);
423 job.setUser(true);
424 // schedule job
425 job.schedule();
426
427 } catch (Exception e) {
428 MessagingUtils.errorDialog("Error executing operation",
429 AbstractUtility.class,
430 "An error occured while executing " + label,
431 TaxeditorStorePlugin.PLUGIN_ID,
432 e,
433 true);
434 }
435
436 return Status.OK_STATUS;
437 }
438
439 public static IOperationHistory getOperationHistory() {
440 return getWorkbench().getOperationSupport().getOperationHistory();
441 }
442
443 public static void setStatusLine(final String message) {
444 Display.getDefault().asyncExec(new Runnable() {
445
446 @Override
447 public void run() {
448 statusLineManager.setMessage(message);
449 }
450
451 });
452
453 }
454
455 public static IProgressMonitor getMonitor() {
456 statusLineManager.setCancelEnabled(false);
457 return statusLineManager.getProgressMonitor();
458 }
459
460 /**
461 * Starts either the given {@link IProgressMonitor} if it's not
462 * <code>null</code> or a new {@link NullProgressMonitor}.
463 *
464 * @param progressMonitor
465 * The {@link IProgressMonitor} or <code>null</code> if no
466 * progress should be reported.
467 * @param taskName
468 * The name of the main task.
469 * @param steps
470 * The number of steps this task is subdivided into.
471 * @return The {@link IProgressMonitor}.
472 */
473 public static IProgressMonitor startMainMonitor(
474 IProgressMonitor progressMonitor, String taskName, int steps) {
475 IProgressMonitor newMonitor = progressMonitor;
476 if (newMonitor == null) {
477 newMonitor = new NullProgressMonitor();
478 }
479 newMonitor.beginTask(taskName == null ? "" : taskName, steps);
480 newMonitor.subTask(" ");
481 return newMonitor;
482 }
483
484 /**
485 * Creates a {@link SubProgressMonitor} if the given
486 * {@link IProgressMonitor} is not <code>null</code> and not a
487 * {@link NullProgressMonitor}.
488 *
489 * @param progressMonitor
490 * The parent {@link IProgressMonitor} of the
491 * {@link SubProgressMonitor} to be created.
492 * @param ticks
493 * The number of steps this subtask is subdivided into. Must be a
494 * positive number and must not be
495 * {@link IProgressMonitor#UNKNOWN}.
496 * @return The {@link IProgressMonitor}.
497 */
498 public static IProgressMonitor getSubProgressMonitor(
499 IProgressMonitor progressMonitor, int ticks) {
500 if (progressMonitor == null) {
501 return new NullProgressMonitor();
502 }
503 if (progressMonitor instanceof NullProgressMonitor) {
504 return progressMonitor;
505 }
506
507 return new SubProgressMonitor(progressMonitor, ticks);
508 }
509
510 /**
511 * Checks whether the user canceled this operation. If not canceled, the
512 * given number of steps are declared as done.
513 *
514 * @param newMonitor
515 * a {@link org.eclipse.core.runtime.IProgressMonitor} object.
516 * @param steps
517 * a int.
518 */
519 public static void workedChecked(IProgressMonitor newMonitor, int steps) {
520 // In case the progress monitor was canceled throw an exception.
521 if (newMonitor.isCanceled()) {
522 throw new OperationCanceledException();
523 }
524 // Otherwise declare this step as done.
525 newMonitor.worked(steps);
526 }
527
528 /**
529 * Present a progress dialog to the user. This dialog will block the UI
530 *
531 * @param runnable
532 * an implementation of {@link IRunnableWithProgress}
533 * @throws java.lang.InterruptedException
534 * if any.
535 * @throws java.lang.reflect.InvocationTargetException
536 * if any.
537 */
538 public static void busyCursorWhile(IRunnableWithProgress runnable)
539 throws InvocationTargetException, InterruptedException {
540 getProgressService().busyCursorWhile(runnable);
541 }
542
543 public static void runInUI(IRunnableWithProgress runnable,
544 ISchedulingRule rule) throws InvocationTargetException,
545 InterruptedException {
546 getProgressService().runInUI(getWorkbenchWindow(), runnable, rule);
547 }
548
549 public static void run(boolean fork, boolean cancelable,
550 IRunnableWithProgress runnable) throws InvocationTargetException,
551 InterruptedException {
552 getProgressService().run(fork, cancelable, runnable);
553 }
554
555 public static IProgressService getProgressService() {
556 IWorkbench workbench = PlatformUI.getWorkbench();
557 return workbench.getProgressService();
558 }
559
560 public static IWorkbenchSiteProgressService getProgressService2() {
561 return (IWorkbenchSiteProgressService) getService(IWorkbenchSiteProgressService.class);
562 }
563
564 public static String getPluginId() {
565 return "eu.taxeditor";
566 }
567
568 public static IEditorPart getActiveEditor() {
569 return getActivePage() != null ? getActivePage().getActiveEditor()
570 : null;
571 }
572
573 public static Object getActiveE4Editor() {
574 if(getActivePage()!=null){
575 IEditorPart activeEditor = getActivePage().getActiveEditor();
576 Object wrappedPart = getE4WrappedPart(getActivePage().getActivePart());
577 return wrappedPart!=null?wrappedPart:activeEditor;
578 }
579 return null;
580 }
581
582 public static DetailsViewPart getDetailsView() {
583 return (DetailsViewPart) getView(DetailsViewPart.ID, false);
584 }
585
586 public static void refreshDetailsViewer() {
587 if (getDetailsView() != null) {
588 ((AbstractCdmDataViewer) getDetailsView().getViewer()).refresh();
589 }
590 }
591
592 public static void reflowDetailsViewer() {
593 if (getDetailsView() != null) {
594 ((AbstractCdmDataViewer) getDetailsView().getViewer()).reflow();
595 }
596 }
597
598 public static SupplementalDataViewPart getSupplementalDataView() {
599 return (SupplementalDataViewPart) getView(SupplementalDataViewPart.ID,
600 false);
601 }
602
603 public static void reflowSupplementalViewer() {
604 if (getSupplementalDataView() != null) {
605 ((AbstractCdmDataViewer) getSupplementalDataView().getViewer())
606 .reflow();
607 }
608 }
609
610
611 /**
612 * Orders a Collection of {@link IEnumTerm}s according to the term
613 * hierarchy. <br>
614 * <br>
615 * The returned map will be be ordered primarily by root elements,
616 * secondarily by the child elements and their children resp., both ascending alphabetically. <br>
617 * @param terms
618 * A {@link Collection} of {@link IEnumTerm}s for which the term
619 * hierarchy should be created
620 * @return a map which holds the terms as keys and their string
621 * representation via {@link IEnumTerm#getMessage()} as values
622 */
623 public static <T extends IEnumTerm<T>> LinkedHashMap<T, String> orderTerms(Collection<T> terms) {
624 TreeSet<TermNode<T>> parentElements = new TreeSet<TermNode<T>>();
625 parentElements.addAll(getTermHierarchy(terms));
626
627 // create list according to the type hierarchy (root elements alphabetically with recursive children also alphabetically)
628 LinkedHashMap<T, String> result = new LinkedHashMap<T, String>();
629 parseTermTree(parentElements, result, -1);
630 return result;
631 }
632
633 private static<T extends IEnumTerm<T>> void parseTermTree(Collection<TermNode<T>> children, LinkedHashMap<T, String> result, int depth){
634 depth++;
635 for(TermNode<T> node:children){
636 String indentString = "";
637 for(int i=0;i<depth;i++){
638 indentString += " ";
639 }
640 if(depth>0){
641 indentString += "- ";
642 }
643 result.put(node.term, indentString + node.term.getMessage());
644 parseTermTree(node.children, result, depth);
645 }
646 }
647
648 private static<T extends IEnumTerm<T>> void addToParents(List<TermNode<T>> parents, Collection<T> terms){
649 List<TermNode<T>> hasChildrenList = new ArrayList<TermNode<T>>();
650 for(T term:terms){
651 // only terms with parents
652 if(term.getKindOf()!=null){
653 TermNode<T> parentNode = new TermNode<T>(term.getKindOf());
654 TermNode<T> childNode = new TermNode<T>(term);
655 if(parents.contains(parentNode)){
656 // parent found in parent list -> add this term to parent's child list
657 parents.get(parents.indexOf(parentNode)).addChild(childNode);
658 if(!term.getGeneralizationOf().isEmpty()){
659 // has more children -> add to list which will be the parent for the next recursion
660 hasChildrenList.add(childNode);
661 }
662 }
663 }
664 }
665 if(!hasChildrenList.isEmpty()){
666 addToParents(hasChildrenList, terms);
667 }
668 }
669
670 private static<T extends IEnumTerm<T>> List<TermNode<T>> getTermHierarchy(Collection<T> terms){
671 List<TermNode<T>> parents = new ArrayList<TermNode<T>>();
672 // get root elements
673 for(T term:terms){
674 T parentTerm = term.getKindOf();
675 if(parentTerm==null){
676 // root element
677 parents.add(new TermNode<T>(term));
678 }
679 }
680 addToParents(parents, terms);
681 return parents;
682 }
683
684 @SuppressWarnings("unchecked")
685 /**
686 * Recursively iterates over all term parents until no more parent is found i.e. the root node
687 * @param term The term for which the parent should be found
688 * @return the root terms of the term hierarchy
689 */
690 private static<T extends IEnumTerm<T>> T getParentFor(T term){
691 // PP: cast should be safe. Why is Eclipse complaining??
692 T parent = term.getKindOf();
693 if(parent==null){
694 return term;
695 }
696 else{
697 return getParentFor(term.getKindOf());
698 }
699 }
700
701 private static class TermNode<T extends IEnumTerm<T>> implements Comparable<TermNode<T>>{
702 private final T term;
703 private final TreeSet<TermNode<T>> children;
704
705 public TermNode(T term) {
706 super();
707 this.term = term;
708 this.children = new TreeSet<TermNode<T>>();
709 }
710
711 public void addChild(TermNode<T> child){
712 this.children.add(child);
713 }
714
715 public TreeSet<TermNode<T>> getChildren() {
716 return children;
717 }
718
719 public T getTerm() {
720 return term;
721 }
722
723 @Override
724 public int hashCode() {
725 final int prime = 31;
726 int result = 1;
727 result = prime * result + ((term == null) ? 0 : term.hashCode());
728 return result;
729 }
730
731 @Override
732 public boolean equals(Object obj) {
733 if (this == obj) {
734 return true;
735 }
736 if (obj == null) {
737 return false;
738 }
739 if (getClass() != obj.getClass()) {
740 return false;
741 }
742 TermNode other = (TermNode) obj;
743 if (term == null) {
744 if (other.term != null) {
745 return false;
746 }
747 } else if (!term.equals(other.term)) {
748 return false;
749 }
750 return true;
751 }
752
753 @Override
754 public int compareTo(TermNode<T> that) {
755 return this.term.getMessage().compareTo(that.term.getMessage());
756 }
757 }
758
759
760 public static void executeCommand(String commandId, Object source, String pluginId) {
761 IHandlerService handlerService = (IHandlerService) AbstractUtility.getService(IHandlerService.class);
762 Exception exception = null;
763 try {
764 handlerService.executeCommand(commandId, null);
765 } catch (ExecutionException e) {
766 exception = e;
767 } catch (NotDefinedException e) {
768 exception = e;
769 } catch (NotEnabledException e) {
770 exception = e;
771 } catch (NotHandledException e) {
772 exception = e;
773 } finally {
774 if(exception != null) {
775 MessagingUtils.errorDialog("Error executing command",
776 source,
777 "Could not execute command with id " + commandId ,
778 pluginId,
779 exception,
780 true);
781 }
782 }
783 }
784
785 /**
786 * @param event
787 * @return
788 */
789 public static Object getElementsFromSelectionChangedEvent(SelectionChangedEvent event) {
790 IStructuredSelection selection = (IStructuredSelection) event.getSelection();
791 Object selectionToSet;
792 if(selection.size() == 1){
793 selectionToSet = selection.getFirstElement();
794 }
795 else if(!selection.isEmpty()){
796 selectionToSet = selection.toArray();
797 }
798 else{
799 selectionToSet = selection;
800 }
801 return selectionToSet;
802 }
803 }