- changed indention marker #3736
[taxeditor.git] / eu.etaxonomy.taxeditor.store / src / main / java / eu / etaxonomy / taxeditor / model / AbstractUtility.java
index 7b53cb8364a35792a04dac7f55b2dc9df8330049..7dcf587ef3c66e94f1da8b1620338c3672b0799d 100644 (file)
@@ -1,9 +1,9 @@
 // $Id$
 /**
  * Copyright (C) 2007 EDIT
- * European Distributed Institute of Taxonomy 
+ * 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,20 +54,19 @@ import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
 import org.eclipse.ui.themes.ITheme;
 import org.eclipse.ui.themes.IThemeManager;
 
-import eu.etaxonomy.cdm.model.common.TermBase;
+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;
 import eu.etaxonomy.taxeditor.view.AbstractCdmDataViewer;
 import eu.etaxonomy.taxeditor.view.detail.DetailsViewPart;
 import eu.etaxonomy.taxeditor.view.supplementaldata.SupplementalDataViewPart;
-import eu.etaxonomy.taxeditor.view.userecords.UseRecordsViewPart;
 
 /**
  * <p>
  * Abstract AbstractUtility class.
  * </p>
- * 
+ *
  * @author n.hoffmann
  * @created 11.05.2009
  * @version 1.0
@@ -76,7 +80,7 @@ public abstract class AbstractUtility {
         * <p>
         * closeAll
         * </p>
-        * 
+        *
         * @return a boolean.
         */
        public static boolean closeAll() {
@@ -85,7 +89,7 @@ public abstract class AbstractUtility {
 
        /**
         * Close the given editor.
-        * 
+        *
         * @param editor
         *            The <tt>MultipageTaxonEditor</tt> to close.
         * @return <tt>true</tt> on success
@@ -98,7 +102,7 @@ public abstract class AbstractUtility {
         * <p>
         * getShell
         * </p>
-        * 
+        *
         * @return a {@link org.eclipse.swt.widgets.Shell} object.
         */
        public static Shell getShell() {
@@ -111,7 +115,7 @@ public abstract class AbstractUtility {
         * <p>
         * getActivePage
         * </p>
-        * 
+        *
         * @return a {@link org.eclipse.ui.IWorkbenchPage} object.
         */
        public static IWorkbenchPage getActivePage() {
@@ -124,7 +128,7 @@ public abstract class AbstractUtility {
         * <p>
         * getActivePart
         * </p>
-        * 
+        *
         * @return a {@link org.eclipse.ui.IWorkbenchPart} object.
         */
        public static IWorkbenchPart getActivePart() {
@@ -139,7 +143,7 @@ public abstract class AbstractUtility {
         * <p>
         * getWorkbenchWindow
         * </p>
-        * 
+        *
         * @return a {@link org.eclipse.jface.window.ApplicationWindow} object.
         */
        public static ApplicationWindow getWorkbenchWindow() {
@@ -153,7 +157,7 @@ public abstract class AbstractUtility {
         * <p>
         * showView
         * </p>
-        * 
+        *
         * @param id
         *            a {@link java.lang.String} object.
         * @return a {@link org.eclipse.ui.IViewPart} object.
@@ -173,7 +177,7 @@ public abstract class AbstractUtility {
         * <p>
         * hideView
         * </p>
-        * 
+        *
         * @param view
         *            a {@link org.eclipse.ui.IViewPart} object.
         */
@@ -186,7 +190,7 @@ public abstract class AbstractUtility {
         * <p>
         * getView
         * </p>
-        * 
+        *
         * @param id
         *            a {@link java.lang.String} object.
         * @param restore
@@ -208,7 +212,7 @@ public abstract class AbstractUtility {
         * <p>
         * getService
         * </p>
-        * 
+        *
         * @param api
         *            a {@link java.lang.Class} object.
         * @return a {@link java.lang.Object} object.
@@ -221,7 +225,7 @@ public abstract class AbstractUtility {
         * <p>
         * getCurrentTheme
         * </p>
-        * 
+        *
         * @return a {@link org.eclipse.ui.themes.ITheme} object.
         */
        public static ITheme getCurrentTheme() {
@@ -234,7 +238,7 @@ public abstract class AbstractUtility {
         * 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() {
@@ -245,7 +249,7 @@ public abstract class AbstractUtility {
         * <p>
         * getFont
         * </p>
-        * 
+        *
         * @param symbolicName
         *            a {@link java.lang.String} object.
         * @return a {@link org.eclipse.swt.graphics.Font} object.
@@ -258,7 +262,7 @@ public abstract class AbstractUtility {
         * 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() {
@@ -269,7 +273,7 @@ public abstract class AbstractUtility {
         * <p>
         * getColor
         * </p>
-        * 
+        *
         * @param symbolicName
         *            a {@link java.lang.String} object.
         * @return a {@link org.eclipse.swt.graphics.Color} object.
@@ -281,7 +285,7 @@ public abstract class AbstractUtility {
        /**
         * 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.
         */
@@ -294,7 +298,7 @@ public abstract class AbstractUtility {
         * <p>
         * informationDialog
         * </p>
-        * 
+        *
         * @param title
         *            a {@link java.lang.String} object.
         * @param message
@@ -304,7 +308,8 @@ public abstract class AbstractUtility {
                        final String message) {
                Display.getDefault().asyncExec(new Runnable() {
 
-                       public void run() {
+                       @Override
+            public void run() {
                                MessageDialog.openInformation(getShell(), title, message);
                        }
                });
@@ -314,12 +319,12 @@ public abstract class AbstractUtility {
                        final IStatus status) {
                informationDialog(title, status.getMessage());
        }
-       
+
        /**
         * <p>
         * warningDialog
         * </p>
-        * 
+        *
         * @param title
         *            The dialogs title
         * @param source
@@ -331,7 +336,8 @@ public abstract class AbstractUtility {
                        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;
@@ -339,7 +345,7 @@ public abstract class AbstractUtility {
                        }
                });
        }
-       
+
        /**
         * @param title
         * @param termBase
@@ -354,7 +360,7 @@ public abstract class AbstractUtility {
         * <p>
         * errorDialog
         * </p>
-        * 
+        *
         * @param title
         *            The dialogs title
         * @param source
@@ -370,7 +376,8 @@ public abstract class AbstractUtility {
                        final String message, final Throwable t) {
                Display.getDefault().asyncExec(new Runnable() {
 
-                       public void run() {
+                       @Override
+            public void run() {
                                MessageDialog.openError(getShell(), title, message + getCauseRecursively(t));
                                Class<? extends Object> clazz = source != null ? source
                                                .getClass() : this.getClass();
@@ -381,7 +388,7 @@ public abstract class AbstractUtility {
                                if(t == null){
                                        return null;
                                }
-                               
+
                                if(t.getCause() != null){
                                        return getCauseRecursively(t.getCause());
                                }else{
@@ -391,7 +398,7 @@ public abstract class AbstractUtility {
                        }
                });
        }
-       
+
        public static void errorDialog(final String title, final Object source,
                        final String message){
                errorDialog(title, source, message, null);
@@ -401,7 +408,7 @@ public abstract class AbstractUtility {
         * <p>
         * errorDialog
         * </p>
-        * 
+        *
         * @param title
         *            a {@link java.lang.String} object.
         * @param source
@@ -413,7 +420,8 @@ public abstract class AbstractUtility {
                        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();
@@ -426,7 +434,7 @@ public abstract class AbstractUtility {
         * <p>
         * confirmDialog
         * </p>
-        * 
+        *
         * @param title
         *            a {@link java.lang.String} object.
         * @param message
@@ -441,7 +449,7 @@ public abstract class AbstractUtility {
         * <p>
         * executeOperation
         * </p>
-        * 
+        *
         * @param operation
         *            a
         *            {@link eu.etaxonomy.taxeditor.operation.AbstractPostOperation}
@@ -459,7 +467,8 @@ public abstract class AbstractUtility {
 
                IRunnableWithProgress runnable = new IRunnableWithProgress() {
 
-                       public void run(IProgressMonitor monitor)
+                       @Override
+            public void run(IProgressMonitor monitor)
                                        throws InvocationTargetException, InterruptedException {
                                monitor.beginTask(operation.getLabel(), 100);
                                IStatus status = Status.CANCEL_STATUS;
@@ -472,7 +481,7 @@ public abstract class AbstractUtility {
                                } finally {
                                        monitor.done();
                                }
-                               
+
                                String statusString = status.equals(Status.OK_STATUS) ? "completed"
                                                : "cancelled";
                                setStatusLine(operation.getLabel() + " " + statusString + ".");
@@ -529,7 +538,7 @@ public abstract class AbstractUtility {
         * <p>
         * getOperationHistory
         * </p>
-        * 
+        *
         * @return a {@link org.eclipse.core.commands.operations.IOperationHistory}
         *         object.
         */
@@ -541,14 +550,15 @@ public abstract class AbstractUtility {
         * <p>
         * setStatusLine
         * </p>
-        * 
+        *
         * @param message
         *            a {@link java.lang.String} object.
         */
        public static void setStatusLine(final String message) {
                Display.getDefault().asyncExec(new Runnable() {
 
-                       public void run() {
+                       @Override
+            public void run() {
                                statusLineManager.setMessage(message);
                        }
 
@@ -560,7 +570,7 @@ public abstract class AbstractUtility {
         * <p>
         * getMonitor
         * </p>
-        * 
+        *
         * @return a {@link org.eclipse.core.runtime.IProgressMonitor} object.
         */
        public static IProgressMonitor getMonitor() {
@@ -571,7 +581,7 @@ public abstract class AbstractUtility {
        /**
         * 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.
@@ -596,7 +606,7 @@ public abstract class AbstractUtility {
         * 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.
@@ -621,7 +631,7 @@ public abstract class AbstractUtility {
        /**
         * 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
@@ -638,7 +648,7 @@ 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
@@ -655,7 +665,7 @@ public abstract class AbstractUtility {
         * <p>
         * runInUI
         * </p>
-        * 
+        *
         * @see {@link IProgressService#runInUI(org.eclipse.jface.operation.IRunnableContext, IRunnableWithProgress, ISchedulingRule)}
         * @param runnable
         *            a {@link org.eclipse.jface.operation.IRunnableWithProgress}
@@ -678,7 +688,7 @@ public abstract class AbstractUtility {
         * <p>
         * run
         * </p>
-        * 
+        *
         * @param fork
         *            a boolean.
         * @param cancelable
@@ -701,7 +711,7 @@ public abstract class AbstractUtility {
         * <p>
         * getProgressService
         * </p>
-        * 
+        *
         * @return a {@link org.eclipse.ui.progress.IProgressService} object.
         */
        public static IProgressService getProgressService() {
@@ -713,7 +723,7 @@ public abstract class AbstractUtility {
         * <p>
         * getProgressService2
         * </p>
-        * 
+        *
         * @return a {@link org.eclipse.ui.progress.IWorkbenchSiteProgressService}
         *         object.
         */
@@ -725,7 +735,7 @@ public abstract class AbstractUtility {
         * <p>
         * info
         * </p>
-        * 
+        *
         * @param message
         *            a {@link java.lang.String} object.
         */
@@ -738,7 +748,7 @@ public abstract class AbstractUtility {
         * <p>
         * info
         * </p>
-        * 
+        *
         * @param status
         *            a {@link org.eclipse.core.runtime.IStatus} object.
         */
@@ -750,7 +760,7 @@ public abstract class AbstractUtility {
         * <p>
         * warn
         * </p>
-        * 
+        *
         * @param source
         *            a {@link java.lang.Class} object.
         * @param message
@@ -761,12 +771,12 @@ public abstract class AbstractUtility {
                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);
@@ -777,7 +787,7 @@ public abstract class AbstractUtility {
         * <p>
         * error
         * </p>
-        * 
+        *
         * @param source
         *            a {@link java.lang.Class} object.
         * @param t
@@ -791,7 +801,7 @@ public abstract class AbstractUtility {
         * <p>
         * error
         * </p>
-        * 
+        *
         * @param source
         *            a {@link java.lang.Class} object.
         * @param message
@@ -808,7 +818,7 @@ public abstract class AbstractUtility {
         * <p>
         * error
         * </p>
-        * 
+        *
         * @param source
         *            a {@link java.lang.Class} object.
         * @param status
@@ -824,7 +834,7 @@ public abstract class AbstractUtility {
         * <p>
         * getLog4JLogger
         * </p>
-        * 
+        *
         * @param clazz
         *            a {@link java.lang.Class} object.
         * @return a {@link org.apache.log4j.Logger} object.
@@ -835,7 +845,7 @@ public abstract class AbstractUtility {
 
        /**
         * @see {@link ILog#log(IStatus)}
-        * 
+        *
         * @param status
         */
        private static void log(IStatus status) {
@@ -846,7 +856,7 @@ public abstract class AbstractUtility {
         * <p>
         * getPluginId
         * </p>
-        * 
+        *
         * @return a {@link java.lang.String} object.
         */
        public static String getPluginId() {
@@ -857,7 +867,7 @@ public abstract class AbstractUtility {
         * <p>
         * getActiveEditor
         * </p>
-        * 
+        *
         * @return a {@link org.eclipse.ui.IEditorPart} object.
         */
        public static IEditorPart getActiveEditor() {
@@ -869,7 +879,7 @@ public abstract class AbstractUtility {
         * <p>
         * getDetailsView
         * </p>
-        * 
+        *
         * @return a {@link eu.etaxonomy.taxeditor.view.detail.DetailsViewPart}
         *         object.
         */
@@ -910,30 +920,191 @@ public abstract class AbstractUtility {
                                        .reflow();
                }
        }
-       
-       public static UseRecordsViewPart getUseRecordsView() {
-               return (UseRecordsViewPart) getView(UseRecordsViewPart.ID, false);
-       }
 
-       /**
-        * <p>
-        * refreshUseRecordsViewer
-        * </p>
-        */
-       public static void refreshUseRecordsViewer() {
-               if (getUseRecordsView() != null) {
-                       ((AbstractCdmDataViewer) getUseRecordsView().getViewer()).refresh();
-               }
-       }
 
-       /**
-        * <p>
-        * reflowUseRecordsViewer
-        * </p>
-        */
-       public static void reflowUseRecordsViewer() {
-               if (getUseRecordsView() != null) {
-                       ((AbstractCdmDataViewer) getUseRecordsView().getViewer()).reflow();
-               }
-       }
+    /**
+     * Orders a Collection of {@link IEnumTerm}s according to the term
+     * hierarchy. The hierarchy will be reduced to two layers: one layer being
+     * the root elements (that have no parents) and the other being their
+     * children and children's children recursively.<br>
+     * The returned map will be be ordered primarily by root elements and
+     * secondarily by the child elements, both ascending alphabetically. <br>
+     * <br>
+     * The reduced hierarchy could look like this:<br>
+     * <ul>
+     * <li>Root1
+     *  <ul>
+     *   <li>child1
+     *   <li>child2
+     *   <li>childOfChild2
+     *  </ul>
+     * <li>root2
+     * <ul><li>child4</ul>
+     * </ul>
+     *
+     * @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) {
+//        Comparator<TermNode<T>> comparator = new Comparator<TermNode<T>>() {
+//            @Override
+//            public int compare(TermNode<T> t1, TermNode<T> t2) {
+//                return t1.getTerm().getMessage().compareTo(t2.getTerm().getMessage());
+//            }
+//        };
+
+        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 += "- ";
+            }
+            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());
+        }
+    }
+
 }