fixing: #4110 (imlement nicer warning dialogue in Taxon Editor for permission denied...
[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.io.PrintWriter;
14 import java.io.StringWriter;
15 import java.io.Writer;
16 import java.lang.reflect.InvocationTargetException;
17 import java.util.ArrayList;
18 import java.util.Collection;
19 import java.util.LinkedHashMap;
20 import java.util.List;
21 import java.util.TreeSet;
22
23 import org.apache.log4j.Logger;
24 import org.eclipse.core.commands.ExecutionException;
25 import org.eclipse.core.commands.operations.IOperationHistory;
26 import org.eclipse.core.runtime.IAdaptable;
27 import org.eclipse.core.runtime.ILog;
28 import org.eclipse.core.runtime.IProgressMonitor;
29 import org.eclipse.core.runtime.IStatus;
30 import org.eclipse.core.runtime.MultiStatus;
31 import org.eclipse.core.runtime.NullProgressMonitor;
32 import org.eclipse.core.runtime.OperationCanceledException;
33 import org.eclipse.core.runtime.Status;
34 import org.eclipse.core.runtime.SubProgressMonitor;
35 import org.eclipse.core.runtime.jobs.ISchedulingRule;
36 import org.eclipse.jface.action.IStatusLineManager;
37 import org.eclipse.jface.dialogs.ErrorDialog;
38 import org.eclipse.jface.dialogs.MessageDialog;
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.ide.undo.WorkspaceUndoUtil;
56 import org.eclipse.ui.part.EditorPart;
57 import org.eclipse.ui.progress.IProgressService;
58 import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
59 import org.eclipse.ui.themes.ITheme;
60 import org.eclipse.ui.themes.IThemeManager;
61
62 import eu.etaxonomy.cdm.model.common.IEnumTerm;
63 import eu.etaxonomy.cdm.persistence.hibernate.permission.SecurityExceptionUtils;
64 import eu.etaxonomy.taxeditor.operation.AbstractPostOperation;
65 import eu.etaxonomy.taxeditor.operation.IPostOperationEnabled;
66 import eu.etaxonomy.taxeditor.store.internal.TaxeditorStorePlugin;
67 import eu.etaxonomy.taxeditor.view.AbstractCdmDataViewer;
68 import eu.etaxonomy.taxeditor.view.detail.DetailsViewPart;
69 import eu.etaxonomy.taxeditor.view.supplementaldata.SupplementalDataViewPart;
70
71 /**
72 * <p>
73 * Abstract AbstractUtility class.
74 * </p>
75 *
76 * @author n.hoffmann
77 * @created 11.05.2009
78 * @version 1.0
79 */
80 public abstract class AbstractUtility {
81
82 /** Constant <code>statusLineManager</code> */
83 protected static IStatusLineManager statusLineManager;
84
85 /**
86 * <p>
87 * closeAll
88 * </p>
89 *
90 * @return a boolean.
91 */
92 public static boolean closeAll() {
93 return getActivePage().closeAllEditors(true);
94 }
95
96 /**
97 * Close the given editor.
98 *
99 * @param editor
100 * The <tt>MultipageTaxonEditor</tt> to close.
101 * @return <tt>true</tt> on success
102 */
103 public static boolean close(EditorPart editor) {
104 return getActivePage().closeEditor(editor, true);
105 }
106
107 /**
108 * <p>
109 * getShell
110 * </p>
111 *
112 * @return a {@link org.eclipse.swt.widgets.Shell} object.
113 */
114 public static Shell getShell() {
115
116 return TaxeditorStorePlugin.getDefault().getWorkbench()
117 .getActiveWorkbenchWindow().getShell();
118 }
119
120 /**
121 * <p>
122 * getActivePage
123 * </p>
124 *
125 * @return a {@link org.eclipse.ui.IWorkbenchPage} object.
126 */
127 public static IWorkbenchPage getActivePage() {
128
129 return TaxeditorStorePlugin.getDefault().getWorkbench()
130 .getActiveWorkbenchWindow().getActivePage();
131 }
132
133 /**
134 * <p>
135 * getActivePart
136 * </p>
137 *
138 * @return a {@link org.eclipse.ui.IWorkbenchPart} object.
139 */
140 public static IWorkbenchPart getActivePart() {
141 return getActivePage() != null ? getActivePage().getActivePart() : null;
142 }
143
144 public static IWorkbench getWorkbench() {
145 return TaxeditorStorePlugin.getDefault().getWorkbench();
146 }
147
148 /**
149 * <p>
150 * getWorkbenchWindow
151 * </p>
152 *
153 * @return a {@link org.eclipse.jface.window.ApplicationWindow} object.
154 */
155 public static ApplicationWindow getWorkbenchWindow() {
156 if (getWorkbench().getWorkbenchWindowCount() > 1) {
157 throw new IllegalStateException("More than one workbench window");
158 }
159 return (ApplicationWindow) getWorkbench().getWorkbenchWindows()[0];
160 }
161
162 /**
163 * <p>
164 * showView
165 * </p>
166 *
167 * @param id
168 * a {@link java.lang.String} object.
169 * @return a {@link org.eclipse.ui.IViewPart} object.
170 */
171 public static IViewPart showView(String id) {
172 try {
173 return PlatformUI.getWorkbench().getActiveWorkbenchWindow()
174 .getActivePage()
175 .showView(id, null, IWorkbenchPage.VIEW_VISIBLE);
176 } catch (PartInitException e) {
177 errorDialog("Error opening view", AbstractUtility.class, "Could not open view: " + id, e);
178 return null;
179 }
180 }
181
182 /**
183 * <p>
184 * hideView
185 * </p>
186 *
187 * @param view
188 * a {@link org.eclipse.ui.IViewPart} object.
189 */
190 public static void hideView(IViewPart view) {
191 PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
192 .hideView(view);
193 }
194
195 /**
196 * <p>
197 * getView
198 * </p>
199 *
200 * @param id
201 * a {@link java.lang.String} object.
202 * @param restore
203 * a boolean.
204 * @return a {@link org.eclipse.ui.IViewPart} object.
205 */
206 public static IViewPart getView(String id, boolean restore) {
207 IViewReference[] references = PlatformUI.getWorkbench()
208 .getActiveWorkbenchWindow().getActivePage().getViewReferences();
209 for (IViewReference reference : references) {
210 if (reference.getId().equals(id)) {
211 return reference.getView(restore);
212 }
213 }
214 return null;
215 }
216
217 /**
218 * <p>
219 * getService
220 * </p>
221 *
222 * @param api
223 * a {@link java.lang.Class} object.
224 * @return a {@link java.lang.Object} object.
225 */
226 public static Object getService(Class api) {
227 return TaxeditorStorePlugin.getDefault().getWorkbench().getService(api);
228 }
229
230 /**
231 * <p>
232 * getCurrentTheme
233 * </p>
234 *
235 * @return a {@link org.eclipse.ui.themes.ITheme} object.
236 */
237 public static ITheme getCurrentTheme() {
238 IThemeManager themeManager = TaxeditorStorePlugin.getDefault()
239 .getWorkbench().getThemeManager();
240 return themeManager.getCurrentTheme();
241 }
242
243 /**
244 * Fonts registered to the plugin may be obtained with the Eclipse themeing
245 * functionality. Thus fonts are chooseable by the user via
246 * Preferences->General->Appearance->Colors and Fonts
247 *
248 * @return the FontRegistry for the current theme
249 */
250 public static FontRegistry getFontRegistry() {
251 return getCurrentTheme().getFontRegistry();
252 }
253
254 /**
255 * <p>
256 * getFont
257 * </p>
258 *
259 * @param symbolicName
260 * a {@link java.lang.String} object.
261 * @return a {@link org.eclipse.swt.graphics.Font} object.
262 */
263 public static Font getFont(String symbolicName) {
264 return getFontRegistry().get(symbolicName);
265 }
266
267 /**
268 * Color registered to the plugin may be obtained with the Eclipse themeing
269 * functionality. Thus colors are editable by the user via
270 * Preferences->General->Appearance->Colors and Fonts
271 *
272 * @return the ColorRegistry for the current theme
273 */
274 public static ColorRegistry getColorRegistry() {
275 return getCurrentTheme().getColorRegistry();
276 }
277
278 /**
279 * <p>
280 * getColor
281 * </p>
282 *
283 * @param symbolicName
284 * a {@link java.lang.String} object.
285 * @return a {@link org.eclipse.swt.graphics.Color} object.
286 */
287 public static Color getColor(String symbolicName) {
288 return getColorRegistry().get(symbolicName);
289 }
290
291 /**
292 * Open a message box that informs the user about unimplemented
293 * functionality. This method is for developer convenience.
294 *
295 * @param source
296 * a {@link java.lang.Object} object.
297 */
298 public static void notImplementedMessage(Object source) {
299 warningDialog("Not yet implemented", source,
300 "This functionality is not yet implemented.");
301 }
302
303 /**
304 * <p>
305 * informationDialog
306 * </p>
307 *
308 * @param title
309 * a {@link java.lang.String} object.
310 * @param message
311 * a {@link java.lang.String} object.
312 */
313 public static void informationDialog(final String title,
314 final String message) {
315 Display.getDefault().asyncExec(new Runnable() {
316
317 @Override
318 public void run() {
319 MessageDialog.openInformation(getShell(), title, message);
320 }
321 });
322 }
323
324 public static void informationDialog(final String title,
325 final IStatus status) {
326 informationDialog(title, status.getMessage());
327 }
328
329 /**
330 * <p>
331 * warningDialog
332 * </p>
333 *
334 * @param title
335 * The dialogs title
336 * @param source
337 * The object where the warning was generated (used by log4j)
338 * @param message
339 * An informative String to be presented to the user
340 */
341 public static void warningDialog(final String title, final Object source,
342 final String message) {
343 Display.getDefault().asyncExec(new Runnable() {
344
345 @Override
346 public void run() {
347 MessageDialog.openWarning(getShell(), title, message);
348 Class<? extends Object> clazz = source != null ? source
349 .getClass() : AbstractUtility.class;
350 warn(clazz, message);
351 }
352 });
353 }
354
355 /**
356 * @param title
357 * @param termBase
358 * @param status
359 */
360 public static void warningDialog(String title, Object source,
361 IStatus status) {
362 warningDialog(title, source, status.getMessage());
363 }
364
365 /**
366 * <p>
367 * errorDialog
368 * </p>
369 *
370 * @param title
371 * The dialogs title
372 * @param source
373 * The object where the warning was generated (used by log4j)
374 * @param message
375 * An informative String to be presented to the user
376 * @param title
377 * The dialogs title
378 * @param t
379 * a Throwable if one exists or null
380 */
381 public static void errorDialog(final String title, final Object source,
382 final String message, final Throwable t) {
383 Display.getDefault().asyncExec(new Runnable() {
384
385 @Override
386 public void run() {
387 MessageDialog.openError(getShell(), title, message + getCauseRecursively(t));
388 Class<? extends Object> clazz = source != null ? source
389 .getClass() : this.getClass();
390 error(clazz, message, t);
391 }
392
393 private String getCauseRecursively(Throwable t) {
394 if(t == null){
395 return "";
396 }
397
398 if(t.getCause() != null){
399 return getCauseRecursively(t.getCause());
400 }else{
401 return String.format("\n\nException: %s\nMessage: %s", t.getClass().getSimpleName(), t.getMessage());
402 }
403
404 }
405 });
406 }
407
408 public static void errorDialog(final String title, final Object source,
409 final String message){
410 errorDialog(title, source, message, null);
411 }
412
413 /**
414 * <p>
415 * errorDialog
416 * </p>
417 *
418 * @param title
419 * a {@link java.lang.String} object.
420 * @param source
421 * a {@link java.lang.Object} object.
422 * @param status
423 * a {@link org.eclipse.core.runtime.IStatus} object.
424 */
425 public static void errorDialog(final String title, final Object source,
426 final IStatus status) {
427 Display.getDefault().asyncExec(new Runnable() {
428
429 @Override
430 public void run() {
431 ErrorDialog.openError(getShell(), title, null, status);
432 Class<? extends Object> clazz = source != null ? source
433 .getClass() : this.getClass();
434 error(clazz, status);
435 }
436 });
437 }
438
439 /**
440 * <p>
441 * confirmDialog
442 * </p>
443 *
444 * @param title
445 * a {@link java.lang.String} object.
446 * @param message
447 * a {@link java.lang.String} object.
448 * @return a boolean.
449 */
450 public static boolean confirmDialog(String title, String message) {
451 return MessageDialog.openQuestion(getShell(), title, message);
452 }
453
454 /**
455 * <p>
456 * executeOperation
457 * </p>
458 *
459 * @param operation
460 * a
461 * {@link eu.etaxonomy.taxeditor.operation.AbstractPostTaxonOperation}
462 * object.
463 * @return a {@link org.eclipse.core.runtime.IStatus} object.
464 */
465 public static IStatus executeOperation(final AbstractPostOperation operation) {
466 if (getOperationHistory() == null) {
467 throw new IllegalArgumentException(
468 "There is no operation history for this context");
469 }
470
471 final IAdaptable uiInfoAdapter = WorkspaceUndoUtil
472 .getUIInfoAdapter(getShell());
473
474 IRunnableWithProgress runnable = new IRunnableWithProgress() {
475
476 @Override
477 public void run(IProgressMonitor monitor)
478 throws InvocationTargetException, InterruptedException {
479 String operationlabel = operation.getLabel();
480 monitor.beginTask(operationlabel, 100);
481 IStatus status = Status.CANCEL_STATUS;
482 try {
483 operation.addContext(IOperationHistory.GLOBAL_UNDO_CONTEXT);
484 status = getOperationHistory().execute(operation, monitor,
485 uiInfoAdapter);
486 } catch (ExecutionException e) {
487
488 dialogForAbortedOperation(e, this, operationlabel, null);
489
490 } finally {
491 monitor.done();
492 }
493
494 String statusString = status.equals(Status.OK_STATUS) ? "completed"
495 : "cancelled";
496 setStatusLine(operationlabel + " " + statusString + ".");
497
498 }
499 };
500
501 try {
502 runInUI(runnable, null);
503 } catch (Exception e) {
504 errorDialog("Error executing operation", AbstractUtility.class, "An error occured while executing " + operation.getLabel(), e);
505 }
506
507 // // Start the main progress monitor.
508 // IProgressMonitor newMonitor =
509 // startMainMonitor(getMonitor(),operation.getLabel(), 100);
510 //
511 // // Check whether operation was canceled and do some steps.
512 // workedChecked(newMonitor, 10);
513 //
514 // try {
515 // IStatus status = getOperationHistory().execute(operation, newMonitor,
516 // WorkspaceUndoUtil.getUIInfoAdapter(getShell()));
517 //
518 // // Check whether operation was canceled and do some steps.
519 // workedChecked(newMonitor, 30);
520 //
521 // String statusString = status.equals(Status.OK_STATUS) ? "completed" :
522 // "cancelled";
523 // setStatusLine(operation.getLabel() + " " + statusString + ".");
524 //
525 // return status;
526 // } catch (ExecutionException e) {
527 // logger.error("Error executing operation: " + operation.getLabel(),
528 // e);
529 // errorDialog("Error executing operation: " + operation.getLabel(),
530 // "Please refer to the error log.");
531 // }
532 // finally {
533 //
534 // // Stop the progress monitor.
535 // newMonitor.done();
536 // }
537
538 IPostOperationEnabled postOperationEnabled = operation
539 .getPostOperationEnabled();
540 if (postOperationEnabled != null) {
541 postOperationEnabled.onComplete();
542 }
543 return Status.OK_STATUS;
544 }
545
546 /**
547 * <p>
548 * getOperationHistory
549 * </p>
550 *
551 * @return a {@link org.eclipse.core.commands.operations.IOperationHistory}
552 * object.
553 */
554 public static IOperationHistory getOperationHistory() {
555 return getWorkbench().getOperationSupport().getOperationHistory();
556 }
557
558 /**
559 * <p>
560 * setStatusLine
561 * </p>
562 *
563 * @param message
564 * a {@link java.lang.String} object.
565 */
566 public static void setStatusLine(final String message) {
567 Display.getDefault().asyncExec(new Runnable() {
568
569 @Override
570 public void run() {
571 statusLineManager.setMessage(message);
572 }
573
574 });
575
576 }
577
578 /**
579 * <p>
580 * getMonitor
581 * </p>
582 *
583 * @return a {@link org.eclipse.core.runtime.IProgressMonitor} object.
584 */
585 public static IProgressMonitor getMonitor() {
586 statusLineManager.setCancelEnabled(false);
587 return statusLineManager.getProgressMonitor();
588 }
589
590 /**
591 * Starts either the given {@link IProgressMonitor} if it's not
592 * <code>null</code> or a new {@link NullProgressMonitor}.
593 *
594 * @param progressMonitor
595 * The {@link IProgressMonitor} or <code>null</code> if no
596 * progress should be reported.
597 * @param taskName
598 * The name of the main task.
599 * @param steps
600 * The number of steps this task is subdivided into.
601 * @return The {@link IProgressMonitor}.
602 */
603 public static IProgressMonitor startMainMonitor(
604 IProgressMonitor progressMonitor, String taskName, int steps) {
605 IProgressMonitor newMonitor = progressMonitor;
606 if (newMonitor == null) {
607 newMonitor = new NullProgressMonitor();
608 }
609 newMonitor.beginTask(taskName == null ? "" : taskName, steps);
610 newMonitor.subTask(" ");
611 return newMonitor;
612 }
613
614 /**
615 * Creates a {@link SubProgressMonitor} if the given
616 * {@link IProgressMonitor} is not <code>null</code> and not a
617 * {@link NullProgressMonitor}.
618 *
619 * @param progressMonitor
620 * The parent {@link IProgressMonitor} of the
621 * {@link SubProgressMonitor} to be created.
622 * @param ticks
623 * The number of steps this subtask is subdivided into. Must be a
624 * positive number and must not be
625 * {@link IProgressMonitor#UNKNOWN}.
626 * @return The {@link IProgressMonitor}.
627 */
628 public static IProgressMonitor getSubProgressMonitor(
629 IProgressMonitor progressMonitor, int ticks) {
630 if (progressMonitor == null) {
631 return new NullProgressMonitor();
632 }
633 if (progressMonitor instanceof NullProgressMonitor) {
634 return progressMonitor;
635 }
636
637 return new SubProgressMonitor(progressMonitor, ticks);
638 }
639
640 /**
641 * Checks whether the user canceled this operation. If not canceled, the
642 * given number of steps are declared as done.
643 *
644 * @param newMonitor
645 * a {@link org.eclipse.core.runtime.IProgressMonitor} object.
646 * @param steps
647 * a int.
648 */
649 public static void workedChecked(IProgressMonitor newMonitor, int steps) {
650 // In case the progress monitor was canceled throw an exception.
651 if (newMonitor.isCanceled()) {
652 throw new OperationCanceledException();
653 }
654 // Otherwise declare this step as done.
655 newMonitor.worked(steps);
656 }
657
658 /**
659 * Present a progress dialog to the user. This dialog will block the UI
660 *
661 * @param runnable
662 * an implementation of {@link IRunnableWithProgress}
663 * @throws java.lang.InterruptedException
664 * if any.
665 * @throws java.lang.reflect.InvocationTargetException
666 * if any.
667 */
668 public static void busyCursorWhile(IRunnableWithProgress runnable)
669 throws InvocationTargetException, InterruptedException {
670 getProgressService().busyCursorWhile(runnable);
671 }
672
673 /**
674 * <p>
675 * runInUI
676 * </p>
677 *
678 * @see {@link IProgressService#runInUI(org.eclipse.jface.operation.IRunnableContext, IRunnableWithProgress, ISchedulingRule)}
679 * @param runnable
680 * a {@link org.eclipse.jface.operation.IRunnableWithProgress}
681 * object.
682 * @param rule
683 * a {@link org.eclipse.core.runtime.jobs.ISchedulingRule}
684 * object.
685 * @throws java.lang.reflect.InvocationTargetException
686 * if any.
687 * @throws java.lang.InterruptedException
688 * if any.
689 */
690 public static void runInUI(IRunnableWithProgress runnable,
691 ISchedulingRule rule) throws InvocationTargetException,
692 InterruptedException {
693 getProgressService().runInUI(getWorkbenchWindow(), runnable, rule);
694 }
695
696 /**
697 * <p>
698 * run
699 * </p>
700 *
701 * @param fork
702 * a boolean.
703 * @param cancelable
704 * a boolean.
705 * @param runnable
706 * a {@link org.eclipse.jface.operation.IRunnableWithProgress}
707 * object.
708 * @throws java.lang.reflect.InvocationTargetException
709 * if any.
710 * @throws java.lang.InterruptedException
711 * if any.
712 */
713 public static void run(boolean fork, boolean cancelable,
714 IRunnableWithProgress runnable) throws InvocationTargetException,
715 InterruptedException {
716 getProgressService().run(fork, cancelable, runnable);
717 }
718
719 /**
720 * <p>
721 * getProgressService
722 * </p>
723 *
724 * @return a {@link org.eclipse.ui.progress.IProgressService} object.
725 */
726 public static IProgressService getProgressService() {
727 IWorkbench workbench = PlatformUI.getWorkbench();
728 return workbench.getProgressService();
729 }
730
731 /**
732 * <p>
733 * getProgressService2
734 * </p>
735 *
736 * @return a {@link org.eclipse.ui.progress.IWorkbenchSiteProgressService}
737 * object.
738 */
739 public static IWorkbenchSiteProgressService getProgressService2() {
740 return (IWorkbenchSiteProgressService) getService(IWorkbenchSiteProgressService.class);
741 }
742
743 /**
744 * <p>
745 * info
746 * </p>
747 *
748 * @param message
749 * a {@link java.lang.String} object.
750 */
751 public static void info(String message) {
752 IStatus status = new Status(IStatus.INFO, getPluginId(), message);
753 info(status);
754 }
755
756 /**
757 * <p>
758 * info
759 * </p>
760 *
761 * @param status
762 * a {@link org.eclipse.core.runtime.IStatus} object.
763 */
764 public static void info(IStatus status) {
765 log(status);
766 }
767
768 /**
769 * <p>
770 * warn
771 * </p>
772 *
773 * @param source
774 * a {@link java.lang.Class} object.
775 * @param message
776 * a {@link java.lang.String} object.
777 */
778 public static void warn(Class source, String message) {
779 IStatus status = new Status(IStatus.WARNING, getPluginId(), message);
780 getLog4JLogger(source).warn(message);
781 log(status);
782 }
783
784 public static void warn(Class source, IStatus status) {
785 getLog4JLogger(source).warn(status.getMessage(), status.getException());
786 log(status);
787 }
788
789 public static void warn(Class source, Throwable t) {
790 IStatus status = new Status(IStatus.WARNING, getPluginId(), t.getMessage(), t);
791 getLog4JLogger(source).warn(t);
792 log(status);
793 }
794
795 /**
796 * <p>
797 * error
798 * </p>
799 *
800 * @param source
801 * a {@link java.lang.Class} object.
802 * @param t
803 * a {@link java.lang.Throwable} object.
804 */
805 public static void error(Class source, Throwable t) {
806 error(source.getClass(), t.getMessage(), t);
807 }
808
809 /**
810 * <p>
811 * error
812 * </p>
813 *
814 * @param source
815 * a {@link java.lang.Class} object.
816 * @param message
817 * a {@link java.lang.String} object.
818 * @param t
819 * a {@link java.lang.Throwable} object.
820 */
821 public static void error(Class source, String message, Throwable t) {
822 IStatus status = new Status(IStatus.ERROR, getPluginId(), message, t);
823 error(source, status);
824 }
825
826 /**
827 * <p>
828 * error
829 * </p>
830 *
831 * @param source
832 * a {@link java.lang.Class} object.
833 * @param status
834 * a {@link org.eclipse.core.runtime.IStatus} object.
835 */
836 public static void error(Class source, IStatus status) {
837 getLog4JLogger(source)
838 .error(status.getMessage(), status.getException());
839 log(status);
840 }
841
842 /**
843 * <p>
844 * getLog4JLogger
845 * </p>
846 *
847 * @param clazz
848 * a {@link java.lang.Class} object.
849 * @return a {@link org.apache.log4j.Logger} object.
850 */
851 public static Logger getLog4JLogger(Class clazz) {
852 return Logger.getLogger(clazz);
853 }
854
855 /**
856 * @see {@link ILog#log(IStatus)}
857 *
858 * @param status
859 */
860 private static void log(IStatus status) {
861 TaxeditorStorePlugin.getDefault().getLog().log(status);
862 }
863
864 /**
865 * <p>
866 * getPluginId
867 * </p>
868 *
869 * @return a {@link java.lang.String} object.
870 */
871 public static String getPluginId() {
872 return "eu.taxeditor";
873 }
874
875 /**
876 * <p>
877 * getActiveEditor
878 * </p>
879 *
880 * @return a {@link org.eclipse.ui.IEditorPart} object.
881 */
882 public static IEditorPart getActiveEditor() {
883 return getActivePage() != null ? getActivePage().getActiveEditor()
884 : null;
885 }
886
887 /**
888 * <p>
889 * getDetailsView
890 * </p>
891 *
892 * @return a {@link eu.etaxonomy.taxeditor.view.detail.DetailsViewPart}
893 * object.
894 */
895 public static DetailsViewPart getDetailsView() {
896 return (DetailsViewPart) getView(DetailsViewPart.ID, false);
897 }
898
899 /**
900 * <p>
901 * refreshDetailsViewer
902 * </p>
903 */
904 public static void refreshDetailsViewer() {
905 if (getDetailsView() != null) {
906 ((AbstractCdmDataViewer) getDetailsView().getViewer()).refresh();
907 }
908 }
909
910 /**
911 * <p>
912 * reflowDetailsViewer
913 * </p>
914 */
915 public static void reflowDetailsViewer() {
916 if (getDetailsView() != null) {
917 ((AbstractCdmDataViewer) getDetailsView().getViewer()).reflow();
918 }
919 }
920
921 public static SupplementalDataViewPart getSupplementalDataView() {
922 return (SupplementalDataViewPart) getView(SupplementalDataViewPart.ID,
923 false);
924 }
925
926 public static void reflowSupplementalViewer() {
927 if (getSupplementalDataView() != null) {
928 ((AbstractCdmDataViewer) getSupplementalDataView().getViewer())
929 .reflow();
930 }
931 }
932
933
934 /**
935 * Orders a Collection of {@link IEnumTerm}s according to the term
936 * hierarchy. <br>
937 * <br>
938 * The returned map will be be ordered primarily by root elements,
939 * secondarily by the child elements and their children resp., both ascending alphabetically. <br>
940 * @param terms
941 * A {@link Collection} of {@link IEnumTerm}s for which the term
942 * hierarchy should be created
943 * @return a map which holds the terms as keys and their string
944 * representation via {@link IEnumTerm#getMessage()} as values
945 */
946 public static <T extends IEnumTerm<T>> LinkedHashMap<T, String> orderTerms(Collection<T> terms) {
947 TreeSet<TermNode<T>> parentElements = new TreeSet<TermNode<T>>();
948 parentElements.addAll(getTermHierarchy(terms));
949
950 // create list according to the type hierarchy (root elements alphabetically with recursive children also alphabetically)
951 LinkedHashMap<T, String> result = new LinkedHashMap<T, String>();
952 parseTermTree(parentElements, result, -1);
953 return result;
954 }
955
956 private static<T extends IEnumTerm<T>> void parseTermTree(Collection<TermNode<T>> children, LinkedHashMap<T, String> result, int depth){
957 depth++;
958 for(TermNode<T> node:children){
959 String indentString = "";
960 for(int i=0;i<depth;i++){
961 indentString += " ";
962 }
963 if(depth>0){
964 indentString += "- ";
965 }
966 result.put(node.term, indentString + node.term.getMessage());
967 parseTermTree(node.children, result, depth);
968 }
969 }
970
971 private static<T extends IEnumTerm<T>> void addToParents(List<TermNode<T>> parents, Collection<T> terms){
972 List<TermNode<T>> hasChildrenList = new ArrayList<TermNode<T>>();
973 for(T term:terms){
974 // only terms with parents
975 if(term.getKindOf()!=null){
976 TermNode<T> parentNode = new TermNode<T>(term.getKindOf());
977 TermNode<T> childNode = new TermNode<T>(term);
978 if(parents.contains(parentNode)){
979 // parent found in parent list -> add this term to parent's child list
980 parents.get(parents.indexOf(parentNode)).addChild(childNode);
981 if(!term.getGeneralizationOf().isEmpty()){
982 // has more children -> add to list which will be the parent for the next recursion
983 hasChildrenList.add(childNode);
984 }
985 }
986 }
987 }
988 if(!hasChildrenList.isEmpty()){
989 addToParents(hasChildrenList, terms);
990 }
991 }
992
993 private static<T extends IEnumTerm<T>> List<TermNode<T>> getTermHierarchy(Collection<T> terms){
994 List<TermNode<T>> parents = new ArrayList<TermNode<T>>();
995 // get root elements
996 for(T term:terms){
997 T parentTerm = term.getKindOf();
998 if(parentTerm==null){
999 // root element
1000 parents.add(new TermNode<T>(term));
1001 }
1002 }
1003 addToParents(parents, terms);
1004 return parents;
1005 }
1006
1007 @SuppressWarnings("unchecked")
1008 /**
1009 * Recursively iterates over all term parents until no more parent is found i.e. the root node
1010 * @param term The term for which the parent should be found
1011 * @return the root terms of the term hierarchy
1012 */
1013 private static<T extends IEnumTerm<T>> T getParentFor(T term){
1014 // PP: cast should be safe. Why is Eclipse complaining??
1015 T parent = term.getKindOf();
1016 if(parent==null){
1017 return term;
1018 }
1019 else{
1020 return getParentFor(term.getKindOf());
1021 }
1022 }
1023
1024 public static void dialogForAbortedOperation(Exception e, final Object source, String operationlabel, String hint) {
1025 MultiStatus info = null;
1026 String title = null;
1027
1028 // FIXME cannot access TaxonomicEditorPlugin.PLUGIN_ID from here
1029 // String PID = TaxonomicEditorPlugin.PLUGIN_ID;
1030 String PID = "eu.etaxonomy.taxeditor.application";
1031
1032 RuntimeException securityRuntimeException = SecurityExceptionUtils.findSecurityRuntimeException(e);
1033
1034 if(securityRuntimeException != null){
1035 title = "Your changes could not be saved!";
1036 info = new MultiStatus(PID, 1, String.format("You are missing sufficient permissions for the operation \"%s\". %s", operationlabel, hint), null);
1037 info.add(new Status(IStatus.WARNING, PID, 1, securityRuntimeException.getMessage(), null));
1038
1039 } else {
1040 title = "Error executing operation";
1041 info = new MultiStatus(PID, 1, String.format("An error occured while executing %s. %s", operationlabel, hint), null);
1042 Writer writer = new StringWriter();
1043 PrintWriter printWriter = new PrintWriter(writer);
1044 e.printStackTrace(printWriter);
1045 info.add(new Status(IStatus.ERROR, PID, 1, writer.toString(), null));
1046 }
1047
1048 errorDialog(title, source, info);
1049 }
1050
1051 private static class TermNode<T extends IEnumTerm<T>> implements Comparable<TermNode<T>>{
1052 private final T term;
1053 private final TreeSet<TermNode<T>> children;
1054
1055 /**
1056 * @param term
1057 * @param children
1058 */
1059 public TermNode(T term) {
1060 super();
1061 this.term = term;
1062 this.children = new TreeSet<TermNode<T>>();
1063 }
1064
1065 public void addChild(TermNode<T> child){
1066 this.children.add(child);
1067 }
1068
1069 /**
1070 * @return the children
1071 */
1072 public TreeSet<TermNode<T>> getChildren() {
1073 return children;
1074 }
1075
1076 /**
1077 * @return the term
1078 */
1079 public T getTerm() {
1080 return term;
1081 }
1082
1083 /* (non-Javadoc)
1084 * @see java.lang.Object#hashCode()
1085 */
1086 @Override
1087 public int hashCode() {
1088 final int prime = 31;
1089 int result = 1;
1090 result = prime * result + ((term == null) ? 0 : term.hashCode());
1091 return result;
1092 }
1093
1094 /* (non-Javadoc)
1095 * @see java.lang.Object#equals(java.lang.Object)
1096 */
1097 @Override
1098 public boolean equals(Object obj) {
1099 if (this == obj) {
1100 return true;
1101 }
1102 if (obj == null) {
1103 return false;
1104 }
1105 if (getClass() != obj.getClass()) {
1106 return false;
1107 }
1108 TermNode other = (TermNode) obj;
1109 if (term == null) {
1110 if (other.term != null) {
1111 return false;
1112 }
1113 } else if (!term.equals(other.term)) {
1114 return false;
1115 }
1116 return true;
1117 }
1118
1119 /* (non-Javadoc)
1120 * @see java.lang.Comparable#compareTo(java.lang.Object)
1121 */
1122 @Override
1123 public int compareTo(TermNode<T> that) {
1124 return this.term.getMessage().compareTo(that.term.getMessage());
1125 }
1126 }
1127
1128 }