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