merge-update from trunk
[taxeditor.git] / eu.etaxonomy.taxeditor.store / src / main / java / eu / etaxonomy / taxeditor / model / AbstractUtility.java
index 36f2d5197aa68b51e79a0825460cc44e5da36d9e..e335480a8e2e36e7c27b8e75f65ad902ced113ca 100644 (file)
@@ -1,16 +1,21 @@
 // $Id$
 /**
-* Copyright (C) 2007 EDIT
-* European Distributed Institute of Taxonomy 
-* http://www.e-taxonomy.eu
-* 
-* The contents of this file are subject to the Mozilla Public License Version 1.1
-* See LICENSE.TXT at the top of this package for the full license terms.
-*/
+ * Copyright (C) 2007 EDIT
+ * European Distributed Institute of Taxonomy
+ * http://www.e-taxonomy.eu
+ *
+ * The contents of this file are subject to the Mozilla Public License Version 1.1
+ * See LICENSE.TXT at the top of this package for the full license terms.
+ */
 
 package eu.etaxonomy.taxeditor.model;
 
 import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.TreeSet;
 
 import org.apache.log4j.Logger;
 import org.eclipse.core.commands.ExecutionException;
@@ -49,6 +54,7 @@ import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
 import org.eclipse.ui.themes.ITheme;
 import org.eclipse.ui.themes.IThemeManager;
 
+import eu.etaxonomy.cdm.model.common.IEnumTerm;
 import eu.etaxonomy.taxeditor.operation.AbstractPostOperation;
 import eu.etaxonomy.taxeditor.operation.IPostOperationEnabled;
 import eu.etaxonomy.taxeditor.store.internal.TaxeditorStorePlugin;
@@ -57,381 +63,513 @@ import eu.etaxonomy.taxeditor.view.detail.DetailsViewPart;
 import eu.etaxonomy.taxeditor.view.supplementaldata.SupplementalDataViewPart;
 
 /**
- * <p>Abstract AbstractUtility class.</p>
+ * <p>
+ * Abstract AbstractUtility class.
+ * </p>
  *
  * @author n.hoffmann
  * @created 11.05.2009
  * @version 1.0
  */
 public abstract class AbstractUtility {
-       
+
        /** Constant <code>statusLineManager</code> */
        protected static IStatusLineManager statusLineManager;
-       
-       
+
        /**
-        * <p>closeAll</p>
+        * <p>
+        * closeAll
+        * </p>
         *
         * @return a boolean.
         */
        public static boolean closeAll() {
                return getActivePage().closeAllEditors(true);
        }
-       
+
        /**
         * Close the given editor.
         *
-        * @param editor The <tt>MultipageTaxonEditor</tt> to close.
+        * @param editor
+        *            The <tt>MultipageTaxonEditor</tt> to close.
         * @return <tt>true</tt> on success
         */
        public static boolean close(EditorPart editor) {
                return getActivePage().closeEditor(editor, true);
        }
-       
+
        /**
-        * <p>getShell</p>
+        * <p>
+        * getShell
+        * </p>
         *
         * @return a {@link org.eclipse.swt.widgets.Shell} object.
         */
        public static Shell getShell() {
-               
+
                return TaxeditorStorePlugin.getDefault().getWorkbench()
                                .getActiveWorkbenchWindow().getShell();
        }
-       
+
        /**
-        * <p>getActivePage</p>
+        * <p>
+        * getActivePage
+        * </p>
         *
         * @return a {@link org.eclipse.ui.IWorkbenchPage} object.
         */
-       public static IWorkbenchPage getActivePage(){
-               
+       public static IWorkbenchPage getActivePage() {
+
                return TaxeditorStorePlugin.getDefault().getWorkbench()
-                       .getActiveWorkbenchWindow().getActivePage();
+                               .getActiveWorkbenchWindow().getActivePage();
        }
-       
+
        /**
-        * <p>getActivePart</p>
+        * <p>
+        * getActivePart
+        * </p>
         *
         * @return a {@link org.eclipse.ui.IWorkbenchPart} object.
         */
-       public static IWorkbenchPart getActivePart(){
+       public static IWorkbenchPart getActivePart() {
                return getActivePage() != null ? getActivePage().getActivePart() : null;
        }
-       
-       public static IWorkbench getWorkbench(){
+
+       public static IWorkbench getWorkbench() {
                return TaxeditorStorePlugin.getDefault().getWorkbench();
        }
-       
+
        /**
-        * <p>getWorkbenchWindow</p>
+        * <p>
+        * getWorkbenchWindow
+        * </p>
         *
         * @return a {@link org.eclipse.jface.window.ApplicationWindow} object.
         */
-       public static ApplicationWindow getWorkbenchWindow(){
-               if(getWorkbench().getWorkbenchWindowCount() > 1){
+       public static ApplicationWindow getWorkbenchWindow() {
+               if (getWorkbench().getWorkbenchWindowCount() > 1) {
                        throw new IllegalStateException("More than one workbench window");
                }
                return (ApplicationWindow) getWorkbench().getWorkbenchWindows()[0];
        }
-       
+
        /**
-        * <p>showView</p>
+        * <p>
+        * showView
+        * </p>
         *
-        * @param id a {@link java.lang.String} object.
+        * @param id
+        *            a {@link java.lang.String} object.
         * @return a {@link org.eclipse.ui.IViewPart} object.
         */
-       public static IViewPart showView(String id){
+       public static IViewPart showView(String id) {
                try {
-                       return PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().showView(id, null, IWorkbenchPage.VIEW_VISIBLE);
+                       return PlatformUI.getWorkbench().getActiveWorkbenchWindow()
+                                       .getActivePage()
+                                       .showView(id, null, IWorkbenchPage.VIEW_VISIBLE);
                } catch (PartInitException e) {
-                       error(AbstractUtility.class, "Could not open view: " + id, e);
-                       throw new RuntimeException(e);
+                       errorDialog("Error opening view", AbstractUtility.class, "Could not open view: " + id, e);
+                       return null;
                }
        }
-       
+
        /**
-        * <p>hideView</p>
+        * <p>
+        * hideView
+        * </p>
         *
-        * @param view a {@link org.eclipse.ui.IViewPart} object.
+        * @param view
+        *            a {@link org.eclipse.ui.IViewPart} object.
         */
-       public static void hideView(IViewPart view){
-               PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().hideView(view);
+       public static void hideView(IViewPart view) {
+               PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
+                               .hideView(view);
        }
-       
-       
+
        /**
-        * <p>getView</p>
+        * <p>
+        * getView
+        * </p>
         *
-        * @param id a {@link java.lang.String} object.
-        * @param restore a boolean.
+        * @param id
+        *            a {@link java.lang.String} object.
+        * @param restore
+        *            a boolean.
         * @return a {@link org.eclipse.ui.IViewPart} object.
         */
-       public static IViewPart getView(String id, boolean restore){
-               IViewReference[] references = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getViewReferences();
-               for (IViewReference reference : references){
-                       if(reference.getId().equals(id)){
+       public static IViewPart getView(String id, boolean restore) {
+               IViewReference[] references = PlatformUI.getWorkbench()
+                               .getActiveWorkbenchWindow().getActivePage().getViewReferences();
+               for (IViewReference reference : references) {
+                       if (reference.getId().equals(id)) {
                                return reference.getView(restore);
                        }
                }
                return null;
        }
-       
+
        /**
-        * <p>getService</p>
+        * <p>
+        * getService
+        * </p>
         *
-        * @param api a {@link java.lang.Class} object.
+        * @param api
+        *            a {@link java.lang.Class} object.
         * @return a {@link java.lang.Object} object.
         */
-       public static Object getService(Class api){
+       public static Object getService(Class api) {
                return TaxeditorStorePlugin.getDefault().getWorkbench().getService(api);
        }
-       
+
        /**
-        * <p>getCurrentTheme</p>
+        * <p>
+        * getCurrentTheme
+        * </p>
         *
         * @return a {@link org.eclipse.ui.themes.ITheme} object.
         */
-       public static ITheme getCurrentTheme(){
-               IThemeManager themeManager = TaxeditorStorePlugin.getDefault().getWorkbench().getThemeManager();
+       public static ITheme getCurrentTheme() {
+               IThemeManager themeManager = TaxeditorStorePlugin.getDefault()
+                               .getWorkbench().getThemeManager();
                return themeManager.getCurrentTheme();
        }
-       
+
        /**
-        * Fonts registered to the plugin may be obtained with the Eclipse themeing functionality.
-        * Thus fonts are chooseable by the user via Preferences->General->Appearance->Colors and Fonts
+        * Fonts registered to the plugin may be obtained with the Eclipse themeing
+        * functionality. Thus fonts are chooseable by the user via
+        * Preferences->General->Appearance->Colors and Fonts
         *
         * @return the FontRegistry for the current theme
         */
-       public static FontRegistry getFontRegistry(){
+       public static FontRegistry getFontRegistry() {
                return getCurrentTheme().getFontRegistry();
        }
-       
+
        /**
-        * <p>getFont</p>
+        * <p>
+        * getFont
+        * </p>
         *
-        * @param symbolicName a {@link java.lang.String} object.
+        * @param symbolicName
+        *            a {@link java.lang.String} object.
         * @return a {@link org.eclipse.swt.graphics.Font} object.
         */
-       public static Font getFont(String symbolicName){
+       public static Font getFont(String symbolicName) {
                return getFontRegistry().get(symbolicName);
        }
-       
+
        /**
-        * Color registered to the plugin may be obtained with the Eclipse themeing functionality.
-        * Thus colors are editable by the user via Preferences->General->Appearance->Colors and Fonts
+        * Color registered to the plugin may be obtained with the Eclipse themeing
+        * functionality. Thus colors are editable by the user via
+        * Preferences->General->Appearance->Colors and Fonts
         *
         * @return the ColorRegistry for the current theme
         */
-       public static ColorRegistry getColorRegistry(){
+       public static ColorRegistry getColorRegistry() {
                return getCurrentTheme().getColorRegistry();
        }
-       
+
        /**
-        * <p>getColor</p>
+        * <p>
+        * getColor
+        * </p>
         *
-        * @param symbolicName a {@link java.lang.String} object.
+        * @param symbolicName
+        *            a {@link java.lang.String} object.
         * @return a {@link org.eclipse.swt.graphics.Color} object.
         */
-       public static Color getColor(String symbolicName){
+       public static Color getColor(String symbolicName) {
                return getColorRegistry().get(symbolicName);
        }
-       
+
        /**
-        * Open a message box that informs the user about unimplemented functionality.
-        * This method is for developer convenience.
+        * Open a message box that informs the user about unimplemented
+        * functionality. This method is for developer convenience.
         *
-        * @param source a {@link java.lang.Object} object.
+        * @param source
+        *            a {@link java.lang.Object} object.
         */
-       public static void notImplementedMessage(Object source){
-               warningDialog("Not yet implemented", source, "This functionality is not yet implemented.");
+       public static void notImplementedMessage(Object source) {
+               warningDialog("Not yet implemented", source,
+                               "This functionality is not yet implemented.");
        }
-       
+
        /**
-        * <p>informationDialog</p>
+        * <p>
+        * informationDialog
+        * </p>
         *
-        * @param title a {@link java.lang.String} object.
-        * @param message a {@link java.lang.String} object.
+        * @param title
+        *            a {@link java.lang.String} object.
+        * @param message
+        *            a {@link java.lang.String} object.
         */
-       public static void informationDialog(final String title, final String message){
-               Display.getDefault().asyncExec(new Runnable(){
+       public static void informationDialog(final String title,
+                       final String message) {
+               Display.getDefault().asyncExec(new Runnable() {
 
-                       public void run() {
+                       @Override
+            public void run() {
                                MessageDialog.openInformation(getShell(), title, message);
                        }
                });
        }
-       
+
+       public static void informationDialog(final String title,
+                       final IStatus status) {
+               informationDialog(title, status.getMessage());
+       }
+
        /**
-        * <p>warningDialog</p>
+        * <p>
+        * warningDialog
+        * </p>
         *
-        * @param title The dialogs title
-        * @param source The object where the warning was generated (used by log4j)
-        * @param message An informative String to be presented to the user
+        * @param title
+        *            The dialogs title
+        * @param source
+        *            The object where the warning was generated (used by log4j)
+        * @param message
+        *            An informative String to be presented to the user
         */
-       public static void warningDialog(final String title, final Object source, final String message){
-               Display.getDefault().asyncExec(new Runnable(){
+       public static void warningDialog(final String title, final Object source,
+                       final String message) {
+               Display.getDefault().asyncExec(new Runnable() {
 
-                       public void run() {
+                       @Override
+            public void run() {
                                MessageDialog.openWarning(getShell(), title, message);
-                               Class<? extends Object> clazz = source != null ? source.getClass() : AbstractUtility.class;
+                               Class<? extends Object> clazz = source != null ? source
+                                               .getClass() : AbstractUtility.class;
                                warn(clazz, message);
                        }
                });
        }
-       
+
+       /**
+        * @param title
+        * @param termBase
+        * @param status
+        */
+       public static void warningDialog(String title, Object source,
+                       IStatus status) {
+               warningDialog(title, source, status.getMessage());
+       }
+
        /**
-        * <p>errorDialog</p>
+        * <p>
+        * errorDialog
+        * </p>
         *
-        * @param title The dialogs title
-        * @param source The object where the warning was generated (used by log4j)
-        * @param message An informative String to be presented to the user
-        * @param title The dialogs title
-        * @param t a Throwable if one exists or null
+        * @param title
+        *            The dialogs title
+        * @param source
+        *            The object where the warning was generated (used by log4j)
+        * @param message
+        *            An informative String to be presented to the user
+        * @param title
+        *            The dialogs title
+        * @param t
+        *            a Throwable if one exists or null
         */
-       public static void errorDialog(final String title, final Object source, final String message, final Throwable t){
-               Display.getDefault().asyncExec(new Runnable(){
+       public static void errorDialog(final String title, final Object source,
+                       final String message, final Throwable t) {
+               Display.getDefault().asyncExec(new Runnable() {
 
-                       public void run() {
-                               MessageDialog.openError(getShell(), title, message);
-                               Class<? extends Object> clazz = source != null ? source.getClass() : this.getClass();
+                       @Override
+            public void run() {
+                               MessageDialog.openError(getShell(), title, message + getCauseRecursively(t));
+                               Class<? extends Object> clazz = source != null ? source
+                                               .getClass() : this.getClass();
                                error(clazz, message, t);
                        }
+
+                       private String getCauseRecursively(Throwable t) {
+                               if(t == null){
+                                       return "";
+                               }
+
+                               if(t.getCause() != null){
+                                       return getCauseRecursively(t.getCause());
+                               }else{
+                                       return String.format("\n\nException: %s\nMessage: %s", t.getClass().getSimpleName(), t.getMessage());
+                               }
+
+                       }
                });
        }
-       
+
+       public static void errorDialog(final String title, final Object source,
+                       final String message){
+               errorDialog(title, source, message, null);
+       }
+
        /**
-        * <p>errorDialog</p>
+        * <p>
+        * errorDialog
+        * </p>
         *
-        * @param title a {@link java.lang.String} object.
-        * @param source a {@link java.lang.Object} object.
-        * @param status a {@link org.eclipse.core.runtime.IStatus} object.
+        * @param title
+        *            a {@link java.lang.String} object.
+        * @param source
+        *            a {@link java.lang.Object} object.
+        * @param status
+        *            a {@link org.eclipse.core.runtime.IStatus} object.
         */
-       public static void errorDialog(final String title, final Object source, final IStatus status){
-               Display.getDefault().asyncExec(new Runnable(){
+       public static void errorDialog(final String title, final Object source,
+                       final IStatus status) {
+               Display.getDefault().asyncExec(new Runnable() {
 
-                       public void run() {
+                       @Override
+            public void run() {
                                MessageDialog.openError(getShell(), title, status.getMessage());
-                               Class<? extends Object> clazz = source != null ? source.getClass() : this.getClass();
+                               Class<? extends Object> clazz = source != null ? source
+                                               .getClass() : this.getClass();
                                error(clazz, status.getMessage(), status.getException());
                        }
                });
        }
 
        /**
-        * <p>confirmDialog</p>
+        * <p>
+        * confirmDialog
+        * </p>
         *
-        * @param title a {@link java.lang.String} object.
-        * @param message a {@link java.lang.String} object.
+        * @param title
+        *            a {@link java.lang.String} object.
+        * @param message
+        *            a {@link java.lang.String} object.
         * @return a boolean.
         */
        public static boolean confirmDialog(String title, String message) {
                return MessageDialog.openQuestion(getShell(), title, message);
        }
-       
+
        /**
-        * <p>executeOperation</p>
+        * <p>
+        * executeOperation
+        * </p>
         *
-        * @param operation a {@link eu.etaxonomy.taxeditor.operation.AbstractPostOperation} object.
+        * @param operation
+        *            a
+        *            {@link eu.etaxonomy.taxeditor.operation.AbstractPostTaxonOperation}
+        *            object.
         * @return a {@link org.eclipse.core.runtime.IStatus} object.
         */
-       public static IStatus executeOperation(final AbstractPostOperation operation){
-               if(getOperationHistory() == null){
-                       throw new IllegalArgumentException("There is no operation history for this context");
+       public static IStatus executeOperation(final AbstractPostOperation operation) {
+               if (getOperationHistory() == null) {
+                       throw new IllegalArgumentException(
+                                       "There is no operation history for this context");
                }
-               
-               final IAdaptable uiInfoAdapter = WorkspaceUndoUtil.getUIInfoAdapter(getShell());
-               
-               
-               
+
+               final IAdaptable uiInfoAdapter = WorkspaceUndoUtil
+                               .getUIInfoAdapter(getShell());
+
                IRunnableWithProgress runnable = new IRunnableWithProgress() {
-                       
-                       public void run(IProgressMonitor monitor) throws InvocationTargetException,
-                                       InterruptedException {
+
+                       @Override
+            public void run(IProgressMonitor monitor)
+                                       throws InvocationTargetException, InterruptedException {
                                monitor.beginTask(operation.getLabel(), 100);
-                               IStatus status;
+                               IStatus status = Status.CANCEL_STATUS;
                                try {
-                                       status = getOperationHistory().execute(operation, monitor, uiInfoAdapter);
+                                       operation.addContext(IOperationHistory.GLOBAL_UNDO_CONTEXT);
+                                       status = getOperationHistory().execute(operation, monitor,
+                                                       uiInfoAdapter);
                                } catch (ExecutionException e) {
-                                       throw new RuntimeException(e);
+                                       errorDialog("Error executing operation", getClass(), String.format("An error occured while executing %s.", operation.getLabel()), e);
+                               } finally {
+                                       monitor.done();
                                }
-                               monitor.done();
-                       String statusString = status.equals(Status.OK_STATUS) ? "completed" : "cancelled";
+
+                               String statusString = status.equals(Status.OK_STATUS) ? "completed"
+                                               : "cancelled";
                                setStatusLine(operation.getLabel() + " " + statusString + ".");
-                               
+
                        }
                };
-               
+
                try {
                        runInUI(runnable, null);
-               } catch (InvocationTargetException e) {
-                       throw new RuntimeException(e);
-               } catch (InterruptedException e) {
-                       throw new RuntimeException(e);
+               } catch (Exception e) {
+                       errorDialog("Error executing operation", AbstractUtility.class, "An error occured while executing " + operation.getLabel(), e);
                }
-               
-//             // Start the main progress monitor.
-//        IProgressMonitor newMonitor = startMainMonitor(getMonitor(),operation.getLabel(), 100);
-//
-//             // Check whether operation was canceled and do some steps.
-//        workedChecked(newMonitor, 10);
-//
-//        try {
-//                     IStatus status = getOperationHistory().execute(operation, newMonitor,
-//                                     WorkspaceUndoUtil.getUIInfoAdapter(getShell()));
-//
-//                     // Check whether operation was canceled and do some steps.
-//                     workedChecked(newMonitor, 30);
-//
-//             String statusString = status.equals(Status.OK_STATUS) ? "completed" : "cancelled";
-//                     setStatusLine(operation.getLabel() + " " + statusString + ".");
-//
-//             return status;
-//             } catch (ExecutionException e) {
-//                     logger.error("Error executing operation: " + operation.getLabel(), e);
-//                     errorDialog("Error executing operation: " + operation.getLabel(), "Please refer to the error log.");
-//             }
-//        finally {
-//             
-//             // Stop the progress monitor.
-//            newMonitor.done();
-//        }
-               
-               IPostOperationEnabled postOperationEnabled = operation.getPostOperationEnabled();
-               if(postOperationEnabled != null){
+
+               // // Start the main progress monitor.
+               // IProgressMonitor newMonitor =
+               // startMainMonitor(getMonitor(),operation.getLabel(), 100);
+               //
+               // // Check whether operation was canceled and do some steps.
+               // workedChecked(newMonitor, 10);
+               //
+               // try {
+               // IStatus status = getOperationHistory().execute(operation, newMonitor,
+               // WorkspaceUndoUtil.getUIInfoAdapter(getShell()));
+               //
+               // // Check whether operation was canceled and do some steps.
+               // workedChecked(newMonitor, 30);
+               //
+               // String statusString = status.equals(Status.OK_STATUS) ? "completed" :
+               // "cancelled";
+               // setStatusLine(operation.getLabel() + " " + statusString + ".");
+               //
+               // return status;
+               // } catch (ExecutionException e) {
+               // logger.error("Error executing operation: " + operation.getLabel(),
+               // e);
+               // errorDialog("Error executing operation: " + operation.getLabel(),
+               // "Please refer to the error log.");
+               // }
+               // finally {
+               //
+               // // Stop the progress monitor.
+               // newMonitor.done();
+               // }
+
+               IPostOperationEnabled postOperationEnabled = operation
+                               .getPostOperationEnabled();
+               if (postOperationEnabled != null) {
                        postOperationEnabled.onComplete();
                }
                return Status.OK_STATUS;
        }
-       
+
        /**
-        * <p>getOperationHistory</p>
+        * <p>
+        * getOperationHistory
+        * </p>
         *
-        * @return a {@link org.eclipse.core.commands.operations.IOperationHistory} object.
+        * @return a {@link org.eclipse.core.commands.operations.IOperationHistory}
+        *         object.
         */
-       public static IOperationHistory getOperationHistory(){
-               return TaxeditorStorePlugin.getDefault().getWorkbench().
-                                                       getOperationSupport().getOperationHistory();
+       public static IOperationHistory getOperationHistory() {
+               return getWorkbench().getOperationSupport().getOperationHistory();
        }
-       
+
        /**
-        * <p>setStatusLine</p>
+        * <p>
+        * setStatusLine
+        * </p>
         *
-        * @param message a {@link java.lang.String} object.
+        * @param message
+        *            a {@link java.lang.String} object.
         */
        public static void setStatusLine(final String message) {
-               Display.getDefault().asyncExec(new Runnable(){
+               Display.getDefault().asyncExec(new Runnable() {
 
-                       public void run() {
+                       @Override
+            public void run() {
                                statusLineManager.setMessage(message);
                        }
-                       
+
                });
-               
+
        }
-       
+
        /**
-        * <p>getMonitor</p>
+        * <p>
+        * getMonitor
+        * </p>
         *
         * @return a {@link org.eclipse.core.runtime.IProgressMonitor} object.
         */
@@ -439,48 +577,65 @@ public abstract class AbstractUtility {
                statusLineManager.setCancelEnabled(false);
                return statusLineManager.getProgressMonitor();
        }
-       
-    /**
-     * Starts either the given {@link IProgressMonitor} if it's not <code>null</code> or a new {@link NullProgressMonitor}.
-     *
-     * @param progressMonitor The {@link IProgressMonitor} or <code>null</code> if no progress should be reported.
-     * @param taskName The name of the main task.
-     * @param steps The number of steps this task is subdivided into.
-     * @return The {@link IProgressMonitor}.
-     */
-    public static IProgressMonitor startMainMonitor(IProgressMonitor progressMonitor, String taskName, int steps) {
-        IProgressMonitor newMonitor = progressMonitor;
-        if (newMonitor == null) {
-            newMonitor = new NullProgressMonitor();
-        }
-        newMonitor.beginTask(taskName == null ? "" : taskName, steps);
-        newMonitor.subTask(" ");
-        return newMonitor;
-    }
 
-    /**
-     * Creates a {@link SubProgressMonitor} if the given {@link IProgressMonitor} is not <code>null</code> and not a {@link NullProgressMonitor}.
-     *
-     * @param progressMonitor The parent {@link IProgressMonitor} of the {@link SubProgressMonitor} to be created.
-     * @param ticks The number of steps this subtask is subdivided into. Must be a positive number and must not be {@link IProgressMonitor#UNKNOWN}.
-     * @return The {@link IProgressMonitor}.
-     */
-    public static IProgressMonitor getSubProgressMonitor(IProgressMonitor progressMonitor, int ticks) {
-        if (progressMonitor == null) {
-            return new NullProgressMonitor();
-        }
-        if (progressMonitor instanceof NullProgressMonitor) {
-            return progressMonitor;
-        }
-        
-        return new SubProgressMonitor(progressMonitor, ticks);
-    }
-    
        /**
-        * Checks whether the user canceled this operation. If not canceled, the given number of steps are declared as done.
+        * Starts either the given {@link IProgressMonitor} if it's not
+        * <code>null</code> or a new {@link NullProgressMonitor}.
         *
-        * @param newMonitor a {@link org.eclipse.core.runtime.IProgressMonitor} object.
-        * @param steps a int.
+        * @param progressMonitor
+        *            The {@link IProgressMonitor} or <code>null</code> if no
+        *            progress should be reported.
+        * @param taskName
+        *            The name of the main task.
+        * @param steps
+        *            The number of steps this task is subdivided into.
+        * @return The {@link IProgressMonitor}.
+        */
+       public static IProgressMonitor startMainMonitor(
+                       IProgressMonitor progressMonitor, String taskName, int steps) {
+               IProgressMonitor newMonitor = progressMonitor;
+               if (newMonitor == null) {
+                       newMonitor = new NullProgressMonitor();
+               }
+               newMonitor.beginTask(taskName == null ? "" : taskName, steps);
+               newMonitor.subTask(" ");
+               return newMonitor;
+       }
+
+       /**
+        * Creates a {@link SubProgressMonitor} if the given
+        * {@link IProgressMonitor} is not <code>null</code> and not a
+        * {@link NullProgressMonitor}.
+        *
+        * @param progressMonitor
+        *            The parent {@link IProgressMonitor} of the
+        *            {@link SubProgressMonitor} to be created.
+        * @param ticks
+        *            The number of steps this subtask is subdivided into. Must be a
+        *            positive number and must not be
+        *            {@link IProgressMonitor#UNKNOWN}.
+        * @return The {@link IProgressMonitor}.
+        */
+       public static IProgressMonitor getSubProgressMonitor(
+                       IProgressMonitor progressMonitor, int ticks) {
+               if (progressMonitor == null) {
+                       return new NullProgressMonitor();
+               }
+               if (progressMonitor instanceof NullProgressMonitor) {
+                       return progressMonitor;
+               }
+
+               return new SubProgressMonitor(progressMonitor, ticks);
+       }
+
+       /**
+        * Checks whether the user canceled this operation. If not canceled, the
+        * given number of steps are declared as done.
+        *
+        * @param newMonitor
+        *            a {@link org.eclipse.core.runtime.IProgressMonitor} object.
+        * @param steps
+        *            a int.
         */
        public static void workedChecked(IProgressMonitor newMonitor, int steps) {
                // In case the progress monitor was canceled throw an exception.
@@ -494,196 +649,444 @@ public abstract class AbstractUtility {
        /**
         * Present a progress dialog to the user. This dialog will block the UI
         *
-        * @param runnable an implementation of {@link IRunnableWithProgress}
-        * @throws java.lang.InterruptedException if any.
-        * @throws java.lang.reflect.InvocationTargetException if any.
+        * @param runnable
+        *            an implementation of {@link IRunnableWithProgress}
+        * @throws java.lang.InterruptedException
+        *             if any.
+        * @throws java.lang.reflect.InvocationTargetException
+        *             if any.
         */
-       public static void busyCursorWhile(IRunnableWithProgress runnable) throws InvocationTargetException, InterruptedException{
+       public static void busyCursorWhile(IRunnableWithProgress runnable)
+                       throws InvocationTargetException, InterruptedException {
                getProgressService().busyCursorWhile(runnable);
        }
-       
+
        /**
-        * <p>runInUI</p>
+        * <p>
+        * runInUI
+        * </p>
         *
         * @see {@link IProgressService#runInUI(org.eclipse.jface.operation.IRunnableContext, IRunnableWithProgress, ISchedulingRule)}
-        * @param runnable a {@link org.eclipse.jface.operation.IRunnableWithProgress} object.
-        * @param rule a {@link org.eclipse.core.runtime.jobs.ISchedulingRule} object.
-        * @throws java.lang.reflect.InvocationTargetException if any.
-        * @throws java.lang.InterruptedException if any.
+        * @param runnable
+        *            a {@link org.eclipse.jface.operation.IRunnableWithProgress}
+        *            object.
+        * @param rule
+        *            a {@link org.eclipse.core.runtime.jobs.ISchedulingRule}
+        *            object.
+        * @throws java.lang.reflect.InvocationTargetException
+        *             if any.
+        * @throws java.lang.InterruptedException
+        *             if any.
         */
-       public static void runInUI(IRunnableWithProgress runnable, ISchedulingRule rule) throws InvocationTargetException, InterruptedException{
-               getProgressService().runInUI(getWorkbenchWindow(), runnable, rule);             
+       public static void runInUI(IRunnableWithProgress runnable,
+                       ISchedulingRule rule) throws InvocationTargetException,
+                       InterruptedException {
+               getProgressService().runInUI(getWorkbenchWindow(), runnable, rule);
        }
-       
+
        /**
-        * <p>run</p>
+        * <p>
+        * run
+        * </p>
         *
-        * @param fork a boolean.
-        * @param cancelable a boolean.
-        * @param runnable a {@link org.eclipse.jface.operation.IRunnableWithProgress} object.
-        * @throws java.lang.reflect.InvocationTargetException if any.
-        * @throws java.lang.InterruptedException if any.
+        * @param fork
+        *            a boolean.
+        * @param cancelable
+        *            a boolean.
+        * @param runnable
+        *            a {@link org.eclipse.jface.operation.IRunnableWithProgress}
+        *            object.
+        * @throws java.lang.reflect.InvocationTargetException
+        *             if any.
+        * @throws java.lang.InterruptedException
+        *             if any.
         */
-       public static void run(boolean fork, boolean cancelable, IRunnableWithProgress runnable) throws InvocationTargetException, InterruptedException{
+       public static void run(boolean fork, boolean cancelable,
+                       IRunnableWithProgress runnable) throws InvocationTargetException,
+                       InterruptedException {
                getProgressService().run(fork, cancelable, runnable);
        }
-       
+
        /**
-        * <p>getProgressService</p>
+        * <p>
+        * getProgressService
+        * </p>
         *
         * @return a {@link org.eclipse.ui.progress.IProgressService} object.
         */
-       public static IProgressService getProgressService(){
+       public static IProgressService getProgressService() {
                IWorkbench workbench = PlatformUI.getWorkbench();
                return workbench.getProgressService();
        }
-       
+
        /**
-        * <p>getProgressService2</p>
+        * <p>
+        * getProgressService2
+        * </p>
         *
-        * @return a {@link org.eclipse.ui.progress.IWorkbenchSiteProgressService} object.
+        * @return a {@link org.eclipse.ui.progress.IWorkbenchSiteProgressService}
+        *         object.
         */
-       public static IWorkbenchSiteProgressService getProgressService2(){
+       public static IWorkbenchSiteProgressService getProgressService2() {
                return (IWorkbenchSiteProgressService) getService(IWorkbenchSiteProgressService.class);
        }
-               
+
        /**
-        * <p>info</p>
+        * <p>
+        * info
+        * </p>
         *
-        * @param message a {@link java.lang.String} object.
+        * @param message
+        *            a {@link java.lang.String} object.
         */
-       public static void info(String message){
+       public static void info(String message) {
                IStatus status = new Status(IStatus.INFO, getPluginId(), message);
                info(status);
        }
-       
+
        /**
-        * <p>info</p>
+        * <p>
+        * info
+        * </p>
         *
-        * @param status a {@link org.eclipse.core.runtime.IStatus} object.
+        * @param status
+        *            a {@link org.eclipse.core.runtime.IStatus} object.
         */
-       public static void info(IStatus status){
+       public static void info(IStatus status) {
                log(status);
        }
-       
+
        /**
-        * <p>warn</p>
+        * <p>
+        * warn
+        * </p>
         *
-        * @param source a {@link java.lang.Class} object.
-        * @param message a {@link java.lang.String} object.
+        * @param source
+        *            a {@link java.lang.Class} object.
+        * @param message
+        *            a {@link java.lang.String} object.
         */
-       public static void warn(Class source, String message){
+       public static void warn(Class source, String message) {
                IStatus status = new Status(IStatus.WARNING, getPluginId(), message);
                getLog4JLogger(source).warn(message);
                log(status);
        }
-       
+
+       public static void warn(Class source, IStatus status) {
+               getLog4JLogger(source).warn(status.getMessage(), status.getException());
+               log(status);
+       }
+
+       public static void warn(Class source, Throwable t) {
+               IStatus status = new Status(IStatus.WARNING, getPluginId(), t.getMessage(), t);
+               getLog4JLogger(source).warn(t);
+               log(status);
+       }
+
        /**
-        * <p>error</p>
+        * <p>
+        * error
+        * </p>
         *
-        * @param source a {@link java.lang.Class} object.
-        * @param t a {@link java.lang.Throwable} object.
+        * @param source
+        *            a {@link java.lang.Class} object.
+        * @param t
+        *            a {@link java.lang.Throwable} object.
         */
-       public static void error(Class source, Throwable t){
+       public static void error(Class source, Throwable t) {
                error(source.getClass(), t.getMessage(), t);
        }
-       
+
        /**
-        * <p>error</p>
+        * <p>
+        * error
+        * </p>
         *
-        * @param source a {@link java.lang.Class} object.
-        * @param message a {@link java.lang.String} object.
-        * @param t a {@link java.lang.Throwable} object.
+        * @param source
+        *            a {@link java.lang.Class} object.
+        * @param message
+        *            a {@link java.lang.String} object.
+        * @param t
+        *            a {@link java.lang.Throwable} object.
         */
-       public static void error(Class source, String message, Throwable t){
+       public static void error(Class source, String message, Throwable t) {
                IStatus status = new Status(IStatus.ERROR, getPluginId(), message, t);
                error(source, status);
        }
-       
+
        /**
-        * <p>error</p>
+        * <p>
+        * error
+        * </p>
         *
-        * @param source a {@link java.lang.Class} object.
-        * @param status a {@link org.eclipse.core.runtime.IStatus} object.
+        * @param source
+        *            a {@link java.lang.Class} object.
+        * @param status
+        *            a {@link org.eclipse.core.runtime.IStatus} object.
         */
-       public static void error(Class source, IStatus status){
-               getLog4JLogger(source).error(status.getMessage(), status.getException());
+       public static void error(Class source, IStatus status) {
+               getLog4JLogger(source)
+                               .error(status.getMessage(), status.getException());
                log(status);
        }
-       
 
        /**
-        * <p>getLog4JLogger</p>
+        * <p>
+        * getLog4JLogger
+        * </p>
         *
-        * @param clazz a {@link java.lang.Class} object.
+        * @param clazz
+        *            a {@link java.lang.Class} object.
         * @return a {@link org.apache.log4j.Logger} object.
         */
-       public static Logger getLog4JLogger(
-                       Class clazz) {
+       public static Logger getLog4JLogger(Class clazz) {
                return Logger.getLogger(clazz);
        }
-       
+
        /**
         * @see {@link ILog#log(IStatus)}
-        * 
+        *
         * @param status
         */
-       private static void log(IStatus status){
+       private static void log(IStatus status) {
                TaxeditorStorePlugin.getDefault().getLog().log(status);
        }
-       
+
        /**
-        * <p>getPluginId</p>
+        * <p>
+        * getPluginId
+        * </p>
         *
         * @return a {@link java.lang.String} object.
         */
-       protected static String getPluginId(){
+       public static String getPluginId() {
                return "eu.taxeditor";
        }
-       
+
        /**
-        * <p>getActiveEditor</p>
+        * <p>
+        * getActiveEditor
+        * </p>
         *
         * @return a {@link org.eclipse.ui.IEditorPart} object.
         */
-       public static IEditorPart getActiveEditor(){
-               return getActivePage() != null ? getActivePage().getActiveEditor() : null;
+       public static IEditorPart getActiveEditor() {
+               return getActivePage() != null ? getActivePage().getActiveEditor()
+                               : null;
        }
-       
+
        /**
-        * <p>getDetailsView</p>
+        * <p>
+        * getDetailsView
+        * </p>
         *
-        * @return a {@link eu.etaxonomy.taxeditor.view.detail.DetailsViewPart} object.
+        * @return a {@link eu.etaxonomy.taxeditor.view.detail.DetailsViewPart}
+        *         object.
         */
-       public static DetailsViewPart getDetailsView(){
-               return  (DetailsViewPart) getView(DetailsViewPart.ID, false);
+       public static DetailsViewPart getDetailsView() {
+               return (DetailsViewPart) getView(DetailsViewPart.ID, false);
        }
-       
+
        /**
-        * <p>refreshDetailsViewer</p>
+        * <p>
+        * refreshDetailsViewer
+        * </p>
         */
-       public static void refreshDetailsViewer(){
-               if(getDetailsView() != null){
+       public static void refreshDetailsViewer() {
+               if (getDetailsView() != null) {
                        ((AbstractCdmDataViewer) getDetailsView().getViewer()).refresh();
                }
        }
-       
+
        /**
-        * <p>reflowDetailsViewer</p>
+        * <p>
+        * reflowDetailsViewer
+        * </p>
         */
-       public static void reflowDetailsViewer(){
-               if(getDetailsView() != null){
+       public static void reflowDetailsViewer() {
+               if (getDetailsView() != null) {
                        ((AbstractCdmDataViewer) getDetailsView().getViewer()).reflow();
                }
        }
-       
-       public static SupplementalDataViewPart getSupplementalDataView(){
-               return (SupplementalDataViewPart) getView(SupplementalDataViewPart.ID, false);
+
+       public static SupplementalDataViewPart getSupplementalDataView() {
+               return (SupplementalDataViewPart) getView(SupplementalDataViewPart.ID,
+                               false);
        }
-       
-       public static void reflowSupplementalViewer(){
-               if(getSupplementalDataView() != null){
-                       ((AbstractCdmDataViewer) getSupplementalDataView().getViewer()).reflow();
+
+       public static void reflowSupplementalViewer() {
+               if (getSupplementalDataView() != null) {
+                       ((AbstractCdmDataViewer) getSupplementalDataView().getViewer())
+                                       .reflow();
                }
        }
+
+
+    /**
+     * Orders a Collection of {@link IEnumTerm}s according to the term
+     * hierarchy. <br>
+     * <br>
+     * The returned map will be be ordered primarily by root elements,
+     * secondarily by the child elements and their children resp., both ascending alphabetically. <br>
+     * @param terms
+     *            A {@link Collection} of {@link IEnumTerm}s for which the term
+     *            hierarchy should be created
+     * @return a map which holds the terms as keys and their string
+     *         representation via {@link IEnumTerm#getMessage()} as values
+     */
+    public static <T extends IEnumTerm<T>> LinkedHashMap<T, String> orderTerms(Collection<T> terms) {
+        TreeSet<TermNode<T>> parentElements = new TreeSet<TermNode<T>>();
+        parentElements.addAll(getTermHierarchy(terms));
+
+        // create list according to the type hierarchy (root elements alphabetically with recursive children also alphabetically)
+        LinkedHashMap<T, String> result = new LinkedHashMap<T, String>();
+        parseTermTree(parentElements, result, -1);
+        return result;
+    }
+
+    private static<T extends IEnumTerm<T>> void parseTermTree(Collection<TermNode<T>> children, LinkedHashMap<T, String> result, int depth){
+        depth++;
+        for(TermNode<T> node:children){
+            String indentString = "";
+            for(int i=0;i<depth;i++){
+                indentString += "  ";
+            }
+            if(depth>0){
+                indentString += "- ";
+            }
+            result.put(node.term, indentString + node.term.getMessage());
+            parseTermTree(node.children, result, depth);
+        }
+    }
+
+    private static<T extends IEnumTerm<T>> void addToParents(List<TermNode<T>> parents, Collection<T> terms){
+        List<TermNode<T>> hasChildrenList = new ArrayList<TermNode<T>>();
+        for(T term:terms){
+            // only terms with parents
+            if(term.getKindOf()!=null){
+                TermNode<T> parentNode = new TermNode<T>(term.getKindOf());
+                TermNode<T> childNode = new TermNode<T>(term);
+                if(parents.contains(parentNode)){
+                    // parent found in parent list -> add this term to parent's child list
+                    parents.get(parents.indexOf(parentNode)).addChild(childNode);
+                    if(!term.getGeneralizationOf().isEmpty()){
+                        // has more children -> add to list which will be the parent for the next recursion
+                        hasChildrenList.add(childNode);
+                    }
+                }
+            }
+        }
+        if(!hasChildrenList.isEmpty()){
+            addToParents(hasChildrenList, terms);
+        }
+    }
+
+    private static<T extends IEnumTerm<T>> List<TermNode<T>> getTermHierarchy(Collection<T> terms){
+        List<TermNode<T>> parents = new ArrayList<TermNode<T>>();
+        // get root elements
+        for(T term:terms){
+            T parentTerm = term.getKindOf();
+            if(parentTerm==null){
+                // root element
+                parents.add(new TermNode<T>(term));
+            }
+        }
+        addToParents(parents, terms);
+        return parents;
+    }
+
+    @SuppressWarnings("unchecked")
+    /**
+     * Recursively iterates over all term parents until no more parent is found i.e. the root node
+     * @param term The term for which the parent should be found
+     * @return the root terms of the term hierarchy
+     */
+    private static<T extends IEnumTerm<T>> T getParentFor(T term){
+        // PP: cast should be safe. Why is Eclipse complaining??
+        T parent = term.getKindOf();
+        if(parent==null){
+            return term;
+        }
+        else{
+            return getParentFor(term.getKindOf());
+        }
+    }
+
+    private static class TermNode<T extends IEnumTerm<T>> implements Comparable<TermNode<T>>{
+        private final T term;
+        private final TreeSet<TermNode<T>> children;
+
+        /**
+         * @param term
+         * @param children
+         */
+        public TermNode(T term) {
+            super();
+            this.term = term;
+            this.children = new TreeSet<TermNode<T>>();
+        }
+
+        public void addChild(TermNode<T> child){
+            this.children.add(child);
+        }
+
+        /**
+         * @return the children
+         */
+        public TreeSet<TermNode<T>> getChildren() {
+            return children;
+        }
+
+        /**
+         * @return the term
+         */
+        public T getTerm() {
+            return term;
+        }
+
+        /* (non-Javadoc)
+         * @see java.lang.Object#hashCode()
+         */
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((term == null) ? 0 : term.hashCode());
+            return result;
+        }
+
+        /* (non-Javadoc)
+         * @see java.lang.Object#equals(java.lang.Object)
+         */
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            TermNode other = (TermNode) obj;
+            if (term == null) {
+                if (other.term != null) {
+                    return false;
+                }
+            } else if (!term.equals(other.term)) {
+                return false;
+            }
+            return true;
+        }
+
+        /* (non-Javadoc)
+         * @see java.lang.Comparable#compareTo(java.lang.Object)
+         */
+        @Override
+        public int compareTo(TermNode<T> that) {
+            return this.term.getMessage().compareTo(that.term.getMessage());
+        }
+    }
+
 }