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