Project

General

Profile

Download (28.8 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
 * Copyright (C) 2007 EDIT
3
 * European Distributed Institute of Taxonomy
4
 * http://www.e-taxonomy.eu
5
 *
6
 * The contents of this file are subject to the Mozilla Public License Version 1.1
7
 * See LICENSE.TXT at the top of this package for the full license terms.
8
 */
9

    
10
package eu.etaxonomy.taxeditor.model;
11

    
12
import java.lang.reflect.InvocationTargetException;
13
import java.util.ArrayList;
14
import java.util.Collection;
15
import java.util.LinkedHashMap;
16
import java.util.List;
17
import java.util.TreeSet;
18
import java.util.UUID;
19

    
20
import org.apache.commons.lang.StringUtils;
21
import org.apache.log4j.Logger;
22
import org.eclipse.core.commands.ExecutionException;
23
import org.eclipse.core.commands.NotEnabledException;
24
import org.eclipse.core.commands.NotHandledException;
25
import org.eclipse.core.commands.common.NotDefinedException;
26
import org.eclipse.core.commands.operations.AbstractOperation;
27
import org.eclipse.core.commands.operations.IOperationHistory;
28
import org.eclipse.core.runtime.IAdaptable;
29
import org.eclipse.core.runtime.IProgressMonitor;
30
import org.eclipse.core.runtime.IStatus;
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.core.runtime.jobs.Job;
37
import org.eclipse.e4.ui.workbench.modeling.EPartService;
38
import org.eclipse.jface.action.IStatusLineManager;
39
import org.eclipse.jface.operation.IRunnableWithProgress;
40
import org.eclipse.jface.resource.ColorRegistry;
41
import org.eclipse.jface.resource.FontRegistry;
42
import org.eclipse.jface.viewers.IStructuredSelection;
43
import org.eclipse.jface.viewers.SelectionChangedEvent;
44
import org.eclipse.swt.graphics.Color;
45
import org.eclipse.swt.graphics.Font;
46
import org.eclipse.swt.widgets.Display;
47
import org.eclipse.swt.widgets.Shell;
48
import org.eclipse.ui.IEditorPart;
49
import org.eclipse.ui.IViewPart;
50
import org.eclipse.ui.IViewReference;
51
import org.eclipse.ui.IWorkbench;
52
import org.eclipse.ui.IWorkbenchPage;
53
import org.eclipse.ui.IWorkbenchPart;
54
import org.eclipse.ui.IWorkbenchWindow;
55
import org.eclipse.ui.PartInitException;
56
import org.eclipse.ui.PlatformUI;
57
import org.eclipse.ui.handlers.IHandlerService;
58
import org.eclipse.ui.ide.undo.WorkspaceUndoUtil;
59
import org.eclipse.ui.part.EditorPart;
60
import org.eclipse.ui.progress.IProgressConstants;
61
import org.eclipse.ui.progress.IProgressService;
62
import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
63
import org.eclipse.ui.themes.ITheme;
64
import org.eclipse.ui.themes.IThemeManager;
65

    
66
import eu.etaxonomy.cdm.api.application.CdmApplicationState;
67
import eu.etaxonomy.cdm.api.service.IProgressMonitorService;
68
import eu.etaxonomy.cdm.common.monitor.IRemotingProgressMonitor;
69
import eu.etaxonomy.cdm.model.common.IEnumTerm;
70
import eu.etaxonomy.taxeditor.operation.AbstractPostOperation;
71
import eu.etaxonomy.taxeditor.operation.IFeedbackGenerator;
72
import eu.etaxonomy.taxeditor.operation.IPostMoniteredOperationEnabled;
73
import eu.etaxonomy.taxeditor.operation.IPostOperationEnabled;
74
import eu.etaxonomy.taxeditor.operation.RemotingCdmHandler;
75
import eu.etaxonomy.taxeditor.store.CdmStore;
76
import eu.etaxonomy.taxeditor.store.internal.TaxeditorStorePlugin;
77
import eu.etaxonomy.taxeditor.ui.dialog.ReportTextDialog;
78
import eu.etaxonomy.taxeditor.view.AbstractCdmDataViewer;
79
import eu.etaxonomy.taxeditor.view.detail.DetailsViewPart;
80
import eu.etaxonomy.taxeditor.view.supplementaldata.SupplementalDataViewPart;
81
import eu.etaxonomy.taxeditor.workbench.WorkbenchUtility;
82

    
83
/**
84
 *
85
 * @author n.hoffmann
86
 * @created 11.05.2009
87
 * @version 1.0
88
 */
89
public abstract class AbstractUtility {
90

    
91
    private static final Logger logger = Logger.getLogger(AbstractUtility.class);
92

    
93
    /** Constant <code>statusLineManager</code> */
94
    protected static IStatusLineManager statusLineManager;
95

    
96

    
97
    public static boolean closeAll() {
98
        if(getActivePage()!=null){
99
            return getActivePage().closeAllEditors(true);
100
        }
101
        return false;
102
    }
103

    
104
    /**
105
     * Close the given editor.
106
     *
107
     * @param editor
108
     *            The <tt>MultipageTaxonEditor</tt> to close.
109
     * @return <tt>true</tt> on success
110
     */
111
    public static boolean close(EditorPart editor) {
112
        return getActivePage() != null ? getActivePage().closeEditor(editor, true):false;
113
    }
114

    
115
    public static Shell getShell() {
116

    
117
        return TaxeditorStorePlugin.getDefault().getWorkbench()
118
                .getActiveWorkbenchWindow().getShell();
119
    }
120

    
121
    public static IWorkbenchPage getActivePage() {
122
        try{
123
            return TaxeditorStorePlugin.getDefault().getWorkbench()
124
                    .getActiveWorkbenchWindow().getActivePage();
125
        } catch(NullPointerException npe){
126
            return null;
127
        }
128
    }
129

    
130
    public static IWorkbenchPart getActiveWorkbenchPart() {
131
        IWorkbenchPage activePage = getActivePage();
132
        if(activePage!=null){
133
            IWorkbenchPart activePart = activePage.getActivePart();
134
            if(activePart!=null){
135
                return activePart;
136
            }
137
        }
138
        return null;
139
    }
140

    
141
    public static Object getActiveE4Part() {
142
        IWorkbenchPage activePage = getActivePage();
143
        if(activePage!=null){
144
            IWorkbenchPart activePart = activePage.getActivePart();
145
            Object e4WrappedPart = WorkbenchUtility.getE4WrappedPart(activePart);
146
            return e4WrappedPart!=null?e4WrappedPart:activePart;
147
        }
148
        return null;
149
    }
150

    
151
    public static IWorkbench getWorkbench() {
152
        return TaxeditorStorePlugin.getDefault().getWorkbench();
153
    }
154

    
155
    public static IWorkbenchWindow getWorkbenchWindow() {
156
        if (getWorkbench().getWorkbenchWindowCount() > 1) {
157
            throw new IllegalStateException("More than one workbench window");
158
        }
159
        return getWorkbench().getWorkbenchWindows()[0];
160
    }
161

    
162
    public static IViewPart showView(String id) {
163
        try {
164
            return PlatformUI.getWorkbench().getActiveWorkbenchWindow()
165
                    .getActivePage()
166
                    .showView(id, null, IWorkbenchPage.VIEW_VISIBLE);
167
        } catch (PartInitException e) {
168
            MessagingUtils.messageDialog("Error opening view", AbstractUtility.class, "Could not open view: " + id, e);
169
            return null;
170
        }
171
    }
172

    
173
    public static void hideView(IViewPart view) {
174
        PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
175
        .hideView(view);
176
    }
177

    
178
    public static IViewPart getView(String id, boolean restore) {
179
    	IWorkbench workbench = PlatformUI.getWorkbench();
180
        IWorkbenchWindow activeWorkbenchWindow = workbench.getActiveWorkbenchWindow();
181
    	IViewReference[] references = null;
182
    	if(activeWorkbenchWindow!=null && activeWorkbenchWindow.getActivePage()!=null){
183
    	    references = activeWorkbenchWindow.getActivePage().getViewReferences();
184
    	}
185
    	else if(workbench.getWorkbenchWindows().length>0 && workbench.getWorkbenchWindows()[0].getActivePage()!=null){
186
    		references = workbench.getWorkbenchWindows()[0].getActivePage().getViewReferences();
187
    	}
188
    	if(references!=null){
189
    		for (IViewReference reference : references) {
190
    			if (reference.getId().equals(id)) {
191
    				return reference.getView(restore);
192
    			}
193
    		}
194
    	}
195
        return null;
196
    }
197

    
198
    public static Object getService(Class api) {
199
        return TaxeditorStorePlugin.getDefault().getWorkbench().getService(api);
200
    }
201

    
202
    public static ITheme getCurrentTheme() {
203
        IThemeManager themeManager = TaxeditorStorePlugin.getDefault()
204
                .getWorkbench().getThemeManager();
205
        return themeManager.getCurrentTheme();
206
    }
207

    
208
    /**
209
     * Fonts registered to the plugin may be obtained with the Eclipse themeing
210
     * functionality. Thus fonts are chooseable by the user via
211
     * Preferences->General->Appearance->Colors and Fonts
212
     *
213
     * @return the FontRegistry for the current theme
214
     */
215
    public static FontRegistry getFontRegistry() {
216
        return getCurrentTheme().getFontRegistry();
217
    }
218

    
219
    public static Font getFont(String symbolicName) {
220
        return getFontRegistry().get(symbolicName);
221
    }
222

    
223
    /**
224
     * Color registered to the plugin may be obtained with the Eclipse themeing
225
     * functionality. Thus colors are editable by the user via
226
     * Preferences->General->Appearance->Colors and Fonts
227
     *
228
     * @return the ColorRegistry for the current theme
229
     */
230
    public static ColorRegistry getColorRegistry() {
231
        return getCurrentTheme().getColorRegistry();
232
    }
233

    
234
    public static Color getColor(String symbolicName) {
235
        return getColorRegistry().get(symbolicName);
236
    }
237

    
238
    public static IStatus executeOperation(final AbstractPostOperation operation) {
239
        if (getOperationHistory() == null) {
240
            throw new IllegalArgumentException(
241
                    "There is no operation history for this context");
242
        }
243

    
244
        final IAdaptable uiInfoAdapter = WorkspaceUndoUtil
245
                .getUIInfoAdapter(getShell());
246

    
247
        IRunnableWithProgress runnable = new IRunnableWithProgress() {
248

    
249
            @Override
250
            public void run(IProgressMonitor monitor)
251
                    throws InvocationTargetException, InterruptedException {
252
                String operationlabel = operation.getLabel();
253
                monitor.beginTask(operationlabel, 100);
254
                IStatus status = Status.CANCEL_STATUS;
255
                try {
256
                    operation.addContext(IOperationHistory.GLOBAL_UNDO_CONTEXT);
257
                    status = getOperationHistory().execute(operation, monitor,
258
                            uiInfoAdapter);
259
                } catch (ExecutionException e) {
260

    
261
                    MessagingUtils.operationDialog(this, e, TaxeditorStorePlugin.PLUGIN_ID, operationlabel, null);
262

    
263
                } finally {
264
                    monitor.done();
265
                }
266

    
267
                String statusString = status.equals(Status.OK_STATUS) ? "completed"
268
                        : "cancelled";
269
                setStatusLine(operationlabel + " " + statusString + ".");
270

    
271
            }
272
        };
273

    
274
        try {
275
            runInUI(runnable, null);
276
        } catch (Exception e) {
277
            MessagingUtils.messageDialog("Error executing operation", AbstractUtility.class, "An error occured while executing " + operation.getLabel(), e);
278
        }
279

    
280
        IPostOperationEnabled postOperationEnabled = operation
281
                .getPostOperationEnabled();
282
        if (postOperationEnabled != null) {
283
            postOperationEnabled.onComplete();
284
        }
285
        return Status.OK_STATUS;
286
    }
287

    
288
    public static IStatus executeOperation(final AbstractOperation operation, final RemotingCdmHandler handler) {
289
        if (getOperationHistory() == null) {
290
            throw new IllegalArgumentException(
291
                    "There is no operation history for this context");
292
        }
293

    
294
        final IAdaptable uiInfoAdapter = WorkspaceUndoUtil
295
                .getUIInfoAdapter(getShell());
296

    
297
        IRunnableWithProgress runnable = new IRunnableWithProgress() {
298

    
299
            @Override
300
            public void run(IProgressMonitor monitor)
301
                    throws InvocationTargetException, InterruptedException {
302
                String operationlabel = operation.getLabel();
303
                monitor.beginTask(operationlabel, 100);
304
                IStatus status = Status.CANCEL_STATUS;
305
                try {
306
                    operation.addContext(IOperationHistory.GLOBAL_UNDO_CONTEXT);
307
                    status = getOperationHistory().execute(operation, monitor,
308
                            uiInfoAdapter);
309
                    if(handler != null) {
310
                        handler.postOperation(status);
311
                    }
312
                } catch (ExecutionException e) {
313
                    MessagingUtils.operationDialog(this, e, TaxeditorStorePlugin.PLUGIN_ID, operationlabel, null);
314
                } finally {
315
                    monitor.done();
316
                }
317

    
318
                String statusString = status.equals(Status.OK_STATUS) ? "completed"
319
                        : "cancelled";
320
                setStatusLine(operationlabel + " " + statusString + ".");
321

    
322
            }
323
        };
324

    
325
        try {
326
            runInUI(runnable, null);
327
        } catch (Exception e) {
328
            MessagingUtils.messageDialog("Error executing operation", AbstractUtility.class, "An error occured while executing " + operation.getLabel(), e);
329
        }
330

    
331
        return Status.OK_STATUS;
332
    }
333

    
334
    /**
335
     * Executes a remoting monitored operation
336
     *
337
     * @param label for the operation
338
     * @param uuid of the remoting monitor already started on the server
339
     * @param pollInterval in milliseconds
340
     * @param cancelable flag which determines whether the operation can be cancelled
341
     * @param postOp callback for running post operation logic
342
     * @return
343
     */
344
    public static IStatus executeMoniteredOperation(final String label,
345
            final UUID uuid,
346
            final int pollInterval,
347
            final boolean cancelable,
348
            final IPostMoniteredOperationEnabled postOp,
349
            final IFeedbackGenerator feedbackGenerator) {
350

    
351
        try {
352
            // get the remoting monitor the first time to make sure that the
353
            // operation is valid
354
            final IProgressMonitorService progressMonitorService = CdmApplicationState.getCurrentAppConfig().getProgressMonitorService();
355
            final IRemotingProgressMonitor firstRemotingMonitor = progressMonitorService.getRemotingMonitor(uuid);
356
            if(firstRemotingMonitor == null) {
357
                throw new IllegalStateException("Remoting progress monitor is null");
358
            }
359

    
360
            Job job = new Job(label) {
361

    
362

    
363
                @Override
364
                public IStatus run(IProgressMonitor monitor) {
365
                    // run the monitor until the operation is finished
366
                    IRemotingProgressMonitor remotingMonitor;
367
                    try {
368
                        remotingMonitor = CdmStore.getProgressMonitorClientManager().pollMonitor(label,
369
                                uuid,
370
                                pollInterval,
371
                                postOp,
372
                                feedbackGenerator,
373
                                monitor);
374
                    } catch (Exception ex) {
375
                        return new Status(Status.ERROR, TaxeditorStorePlugin.PLUGIN_ID, "Operation Interrupted", ex);
376
                    }
377
                    final StringBuilder reportSb = new StringBuilder();
378
                    // collect reports
379
                    for(String report : remotingMonitor.getReports()) {
380
                        reportSb.append(report);
381
                    }
382
                    if(!StringUtils.isBlank(reportSb.toString())) {
383
                        Display.getDefault().asyncExec(new Runnable() {
384
                            @Override
385
                            public void run() {
386
                                // display reports with possibility to save
387
                                ReportTextDialog dialog = new ReportTextDialog(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell());
388
                                dialog.setTitle(label + " Report");
389
                                dialog.setReportText(reportSb.toString());
390
                                dialog.open();
391
                            }
392
                        });
393
                    }
394
                    return Status.OK_STATUS;
395
                }
396

    
397
                @Override
398
                protected void canceling() {
399
                    CdmStore.getCurrentApplicationConfiguration().getProgressMonitorService().cancel(uuid);
400
                }
401
            };
402

    
403
            // configure the job
404
            job.setProperty(IProgressConstants.KEEP_PROPERTY, true);
405
            job.setUser(true);
406
            // schedule job
407
            job.schedule();
408

    
409
        } catch (Exception e) {
410
            MessagingUtils.errorDialog("Error executing operation",
411
                    AbstractUtility.class,
412
                    "An error occured while executing " + label,
413
                    TaxeditorStorePlugin.PLUGIN_ID,
414
                    e,
415
                    true);
416
        }
417

    
418
        return Status.OK_STATUS;
419
    }
420

    
421
    public static IOperationHistory getOperationHistory() {
422
        return getWorkbench().getOperationSupport().getOperationHistory();
423
    }
424

    
425
    public static void setStatusLine(final String message) {
426
        Display.getDefault().asyncExec(new Runnable() {
427

    
428
            @Override
429
            public void run() {
430
                statusLineManager.setMessage(message);
431
            }
432

    
433
        });
434

    
435
    }
436

    
437
    public static IProgressMonitor getMonitor() {
438
        statusLineManager.setCancelEnabled(false);
439
        return statusLineManager.getProgressMonitor();
440
    }
441

    
442
    /**
443
     * Starts either the given {@link IProgressMonitor} if it's not
444
     * <code>null</code> or a new {@link NullProgressMonitor}.
445
     *
446
     * @param progressMonitor
447
     *            The {@link IProgressMonitor} or <code>null</code> if no
448
     *            progress should be reported.
449
     * @param taskName
450
     *            The name of the main task.
451
     * @param steps
452
     *            The number of steps this task is subdivided into.
453
     * @return The {@link IProgressMonitor}.
454
     */
455
    public static IProgressMonitor startMainMonitor(
456
            IProgressMonitor progressMonitor, String taskName, int steps) {
457
        IProgressMonitor newMonitor = progressMonitor;
458
        if (newMonitor == null) {
459
            newMonitor = new NullProgressMonitor();
460
        }
461
        newMonitor.beginTask(taskName == null ? "" : taskName, steps);
462
        newMonitor.subTask(" ");
463
        return newMonitor;
464
    }
465

    
466
    /**
467
     * Creates a {@link SubProgressMonitor} if the given
468
     * {@link IProgressMonitor} is not <code>null</code> and not a
469
     * {@link NullProgressMonitor}.
470
     *
471
     * @param progressMonitor
472
     *            The parent {@link IProgressMonitor} of the
473
     *            {@link SubProgressMonitor} to be created.
474
     * @param ticks
475
     *            The number of steps this subtask is subdivided into. Must be a
476
     *            positive number and must not be
477
     *            {@link IProgressMonitor#UNKNOWN}.
478
     * @return The {@link IProgressMonitor}.
479
     */
480
    public static IProgressMonitor getSubProgressMonitor(
481
            IProgressMonitor progressMonitor, int ticks) {
482
        if (progressMonitor == null) {
483
            return new NullProgressMonitor();
484
        }
485
        if (progressMonitor instanceof NullProgressMonitor) {
486
            return progressMonitor;
487
        }
488

    
489
        return new SubProgressMonitor(progressMonitor, ticks);
490
    }
491

    
492
    /**
493
     * Checks whether the user canceled this operation. If not canceled, the
494
     * given number of steps are declared as done.
495
     *
496
     * @param newMonitor
497
     *            a {@link org.eclipse.core.runtime.IProgressMonitor} object.
498
     * @param steps
499
     *            a int.
500
     */
501
    public static void workedChecked(IProgressMonitor newMonitor, int steps) {
502
        // In case the progress monitor was canceled throw an exception.
503
        if (newMonitor.isCanceled()) {
504
            throw new OperationCanceledException();
505
        }
506
        // Otherwise declare this step as done.
507
        newMonitor.worked(steps);
508
    }
509

    
510
    /**
511
     * Present a progress dialog to the user. This dialog will block the UI
512
     *
513
     * @param runnable
514
     *            an implementation of {@link IRunnableWithProgress}
515
     * @throws java.lang.InterruptedException
516
     *             if any.
517
     * @throws java.lang.reflect.InvocationTargetException
518
     *             if any.
519
     */
520
    public static void busyCursorWhile(IRunnableWithProgress runnable)
521
            throws InvocationTargetException, InterruptedException {
522
        getProgressService().busyCursorWhile(runnable);
523
    }
524

    
525
    public static void runInUI(IRunnableWithProgress runnable,
526
            ISchedulingRule rule) throws InvocationTargetException,
527
            InterruptedException {
528
        getProgressService().runInUI(getWorkbenchWindow(), runnable, rule);
529
    }
530

    
531
    public static void run(boolean fork, boolean cancelable,
532
            IRunnableWithProgress runnable) throws InvocationTargetException,
533
            InterruptedException {
534
        getProgressService().run(fork, cancelable, runnable);
535
    }
536

    
537
    public static IProgressService getProgressService() {
538
        IWorkbench workbench = PlatformUI.getWorkbench();
539
        return workbench.getProgressService();
540
    }
541

    
542
    public static IWorkbenchSiteProgressService getProgressService2() {
543
        return (IWorkbenchSiteProgressService) getService(IWorkbenchSiteProgressService.class);
544
    }
545

    
546
    public static String getPluginId() {
547
        return "eu.taxeditor";
548
    }
549

    
550
    public static IEditorPart getActiveEditor() {
551
        return getActivePage() != null ? getActivePage().getActiveEditor()
552
                : null;
553
    }
554

    
555
    public static Object getActiveE4Editor() {
556
        //FIXME E4 this can be simplified/removed when fully migrated
557
        if(getActivePage()!=null){
558
            IEditorPart activeEditor = getActivePage().getActiveEditor();
559
            Object activePart = getActivePage().getActivePart();
560
            if(activeEditor==null){
561
                activePart = TaxeditorStorePlugin.getDefault().getWorkbench().getActiveWorkbenchWindow().getService(EPartService.class).getActivePart();
562
            }
563
            Object wrappedPart = WorkbenchUtility.getE4WrappedPart(activePart);
564
            return wrappedPart!=null?wrappedPart:activeEditor;
565
        }
566
        return null;
567
    }
568

    
569
    public static DetailsViewPart getDetailsView() {
570
        return (DetailsViewPart) getView(DetailsViewPart.ID, false);
571
    }
572

    
573
    public static void refreshDetailsViewer() {
574
        if (getDetailsView() != null) {
575
            ((AbstractCdmDataViewer) getDetailsView().getViewer()).refresh();
576
        }
577
    }
578

    
579
    public static void reflowDetailsViewer() {
580
        if (getDetailsView() != null) {
581
            ((AbstractCdmDataViewer) getDetailsView().getViewer()).reflow();
582
        }
583
    }
584

    
585
    public static SupplementalDataViewPart getSupplementalDataView() {
586
        return (SupplementalDataViewPart) getView(SupplementalDataViewPart.ID,
587
                false);
588
    }
589

    
590
    public static void reflowSupplementalViewer() {
591
        if (getSupplementalDataView() != null) {
592
            ((AbstractCdmDataViewer) getSupplementalDataView().getViewer())
593
            .reflow();
594
        }
595
    }
596

    
597

    
598
    /**
599
     * Orders a Collection of {@link IEnumTerm}s according to the term
600
     * hierarchy. <br>
601
     * <br>
602
     * The returned map will be be ordered primarily by root elements,
603
     * secondarily by the child elements and their children resp., both ascending alphabetically. <br>
604
     * @param terms
605
     *            A {@link Collection} of {@link IEnumTerm}s for which the term
606
     *            hierarchy should be created
607
     * @return a map which holds the terms as keys and their string
608
     *         representation via {@link IEnumTerm#getMessage()} as values
609
     */
610
    public static <T extends IEnumTerm<T>> LinkedHashMap<T, String> orderTerms(Collection<T> terms) {
611
        TreeSet<TermNode<T>> parentElements = new TreeSet<TermNode<T>>();
612
        parentElements.addAll(getTermHierarchy(terms));
613

    
614
        // create list according to the type hierarchy (root elements alphabetically with recursive children also alphabetically)
615
        LinkedHashMap<T, String> result = new LinkedHashMap<T, String>();
616
        parseTermTree(parentElements, result, -1);
617
        return result;
618
    }
619

    
620
    private static<T extends IEnumTerm<T>> void parseTermTree(Collection<TermNode<T>> children, LinkedHashMap<T, String> result, int depth){
621
        depth++;
622
        for(TermNode<T> node:children){
623
            String indentString = "";
624
            for(int i=0;i<depth;i++){
625
                indentString += "  ";
626
            }
627
            if(depth>0){
628
                indentString += "- ";
629
            }
630
            result.put(node.term, indentString + node.term.getMessage());
631
            parseTermTree(node.children, result, depth);
632
        }
633
    }
634

    
635
    private static<T extends IEnumTerm<T>> void addToParents(List<TermNode<T>> parents, Collection<T> terms){
636
        List<TermNode<T>> hasChildrenList = new ArrayList<TermNode<T>>();
637
        for(T term:terms){
638
            // only terms with parents
639
            if(term.getKindOf()!=null){
640
                TermNode<T> parentNode = new TermNode<T>(term.getKindOf());
641
                TermNode<T> childNode = new TermNode<T>(term);
642
                if(parents.contains(parentNode)){
643
                    // parent found in parent list -> add this term to parent's child list
644
                    parents.get(parents.indexOf(parentNode)).addChild(childNode);
645
                    if(!term.getGeneralizationOf().isEmpty()){
646
                        // has more children -> add to list which will be the parent for the next recursion
647
                        hasChildrenList.add(childNode);
648
                    }
649
                }
650
            }
651
        }
652
        if(!hasChildrenList.isEmpty()){
653
            addToParents(hasChildrenList, terms);
654
        }
655
    }
656

    
657
    private static<T extends IEnumTerm<T>> List<TermNode<T>> getTermHierarchy(Collection<T> terms){
658
        List<TermNode<T>> parents = new ArrayList<TermNode<T>>();
659
        // get root elements
660
        for(T term:terms){
661
            T parentTerm = term.getKindOf();
662
            if(parentTerm==null){
663
                // root element
664
                parents.add(new TermNode<T>(term));
665
            }
666
        }
667
        addToParents(parents, terms);
668
        return parents;
669
    }
670

    
671
    @SuppressWarnings("unchecked")
672
    /**
673
     * Recursively iterates over all term parents until no more parent is found i.e. the root node
674
     * @param term The term for which the parent should be found
675
     * @return the root terms of the term hierarchy
676
     */
677
    private static<T extends IEnumTerm<T>> T getParentFor(T term){
678
        // PP: cast should be safe. Why is Eclipse complaining??
679
        T parent = term.getKindOf();
680
        if(parent==null){
681
            return term;
682
        }
683
        else{
684
            return getParentFor(term.getKindOf());
685
        }
686
    }
687

    
688
    private static class TermNode<T extends IEnumTerm<T>> implements Comparable<TermNode<T>>{
689
        private final T term;
690
        private final TreeSet<TermNode<T>> children;
691

    
692
        public TermNode(T term) {
693
            super();
694
            this.term = term;
695
            this.children = new TreeSet<TermNode<T>>();
696
        }
697

    
698
        public void addChild(TermNode<T> child){
699
            this.children.add(child);
700
        }
701

    
702
        public TreeSet<TermNode<T>> getChildren() {
703
            return children;
704
        }
705

    
706
        public T getTerm() {
707
            return term;
708
        }
709

    
710
        @Override
711
        public int hashCode() {
712
            final int prime = 31;
713
            int result = 1;
714
            result = prime * result + ((term == null) ? 0 : term.hashCode());
715
            return result;
716
        }
717

    
718
        @Override
719
        public boolean equals(Object obj) {
720
            if (this == obj) {
721
                return true;
722
            }
723
            if (obj == null) {
724
                return false;
725
            }
726
            if (getClass() != obj.getClass()) {
727
                return false;
728
            }
729
            TermNode other = (TermNode) obj;
730
            if (term == null) {
731
                if (other.term != null) {
732
                    return false;
733
                }
734
            } else if (!term.equals(other.term)) {
735
                return false;
736
            }
737
            return true;
738
        }
739

    
740
        @Override
741
        public int compareTo(TermNode<T> that) {
742
            return this.term.getMessage().compareTo(that.term.getMessage());
743
        }
744
    }
745

    
746

    
747
    public static void executeCommand(String commandId, Object source, String pluginId) {
748
        IHandlerService handlerService = (IHandlerService) AbstractUtility.getService(IHandlerService.class);
749
        Exception exception = null;
750
        try {
751
            handlerService.executeCommand(commandId, null);
752
        } catch (ExecutionException e) {
753
            exception = e;
754
        } catch (NotDefinedException e) {
755
            exception = e;
756
        } catch (NotEnabledException e) {
757
            exception = e;
758
        } catch (NotHandledException e) {
759
            exception = e;
760
        } finally {
761
            if(exception != null) {
762
                MessagingUtils.errorDialog("Error executing command",
763
                        source,
764
                        "Could not execute command with id " + commandId ,
765
                        pluginId,
766
                        exception,
767
                        true);
768
            }
769
        }
770
    }
771

    
772
    public static Object getElementsFromSelectionChangedEvent(SelectionChangedEvent event) {
773
        IStructuredSelection selection = (IStructuredSelection) event.getSelection();
774
        Object selectionToSet = selection;
775
        if(selection.size() == 1){
776
            selectionToSet = selection.getFirstElement();
777
        }
778
        else if(!selection.isEmpty()){
779
            selectionToSet = selection.toArray();
780
        }
781
        return selectionToSet;
782
    }
783
}
(2-2/39)