Project

General

Profile

Download (28.5 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.jface.action.IStatusLineManager;
38
import org.eclipse.jface.operation.IRunnableWithProgress;
39
import org.eclipse.jface.resource.ColorRegistry;
40
import org.eclipse.jface.resource.FontRegistry;
41
import org.eclipse.jface.viewers.IStructuredSelection;
42
import org.eclipse.jface.viewers.SelectionChangedEvent;
43
import org.eclipse.swt.graphics.Color;
44
import org.eclipse.swt.graphics.Font;
45
import org.eclipse.swt.widgets.Display;
46
import org.eclipse.swt.widgets.Shell;
47
import org.eclipse.ui.IEditorPart;
48
import org.eclipse.ui.IViewPart;
49
import org.eclipse.ui.IViewReference;
50
import org.eclipse.ui.IWorkbench;
51
import org.eclipse.ui.IWorkbenchPage;
52
import org.eclipse.ui.IWorkbenchPart;
53
import org.eclipse.ui.IWorkbenchWindow;
54
import org.eclipse.ui.PartInitException;
55
import org.eclipse.ui.PlatformUI;
56
import org.eclipse.ui.handlers.IHandlerService;
57
import org.eclipse.ui.ide.undo.WorkspaceUndoUtil;
58
import org.eclipse.ui.part.EditorPart;
59
import org.eclipse.ui.progress.IProgressConstants;
60
import org.eclipse.ui.progress.IProgressService;
61
import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
62
import org.eclipse.ui.themes.ITheme;
63
import org.eclipse.ui.themes.IThemeManager;
64

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

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

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

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

    
95

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

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

    
114
    public static Shell getShell() {
115

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
246
        IRunnableWithProgress runnable = new IRunnableWithProgress() {
247

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

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

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

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

    
270
            }
271
        };
272

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

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

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

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

    
296
        IRunnableWithProgress runnable = new IRunnableWithProgress() {
297

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

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

    
321
            }
322
        };
323

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

    
330
        return Status.OK_STATUS;
331
    }
332

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

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

    
359
            Job job = new Job(label) {
360

    
361

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

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

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

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

    
417
        return Status.OK_STATUS;
418
    }
419

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

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

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

    
432
        });
433

    
434
    }
435

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

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

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

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

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

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

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

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

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

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

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

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

    
554
    public static Object getActiveE4Editor() {
555
        if(getActivePage()!=null){
556
            IEditorPart activeEditor = getActivePage().getActiveEditor();
557
            Object wrappedPart = WorkbenchUtility.getE4WrappedPart(getActivePage().getActivePart());
558
            return wrappedPart!=null?wrappedPart:activeEditor;
559
        }
560
        return null;
561
    }
562

    
563
    public static DetailsViewPart getDetailsView() {
564
        return (DetailsViewPart) getView(DetailsViewPart.ID, false);
565
    }
566

    
567
    public static void refreshDetailsViewer() {
568
        if (getDetailsView() != null) {
569
            ((AbstractCdmDataViewer) getDetailsView().getViewer()).refresh();
570
        }
571
    }
572

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

    
579
    public static SupplementalDataViewPart getSupplementalDataView() {
580
        return (SupplementalDataViewPart) getView(SupplementalDataViewPart.ID,
581
                false);
582
    }
583

    
584
    public static void reflowSupplementalViewer() {
585
        if (getSupplementalDataView() != null) {
586
            ((AbstractCdmDataViewer) getSupplementalDataView().getViewer())
587
            .reflow();
588
        }
589
    }
590

    
591

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

    
608
        // create list according to the type hierarchy (root elements alphabetically with recursive children also alphabetically)
609
        LinkedHashMap<T, String> result = new LinkedHashMap<T, String>();
610
        parseTermTree(parentElements, result, -1);
611
        return result;
612
    }
613

    
614
    private static<T extends IEnumTerm<T>> void parseTermTree(Collection<TermNode<T>> children, LinkedHashMap<T, String> result, int depth){
615
        depth++;
616
        for(TermNode<T> node:children){
617
            String indentString = "";
618
            for(int i=0;i<depth;i++){
619
                indentString += "  ";
620
            }
621
            if(depth>0){
622
                indentString += "- ";
623
            }
624
            result.put(node.term, indentString + node.term.getMessage());
625
            parseTermTree(node.children, result, depth);
626
        }
627
    }
628

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

    
651
    private static<T extends IEnumTerm<T>> List<TermNode<T>> getTermHierarchy(Collection<T> terms){
652
        List<TermNode<T>> parents = new ArrayList<TermNode<T>>();
653
        // get root elements
654
        for(T term:terms){
655
            T parentTerm = term.getKindOf();
656
            if(parentTerm==null){
657
                // root element
658
                parents.add(new TermNode<T>(term));
659
            }
660
        }
661
        addToParents(parents, terms);
662
        return parents;
663
    }
664

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

    
682
    private static class TermNode<T extends IEnumTerm<T>> implements Comparable<TermNode<T>>{
683
        private final T term;
684
        private final TreeSet<TermNode<T>> children;
685

    
686
        public TermNode(T term) {
687
            super();
688
            this.term = term;
689
            this.children = new TreeSet<TermNode<T>>();
690
        }
691

    
692
        public void addChild(TermNode<T> child){
693
            this.children.add(child);
694
        }
695

    
696
        public TreeSet<TermNode<T>> getChildren() {
697
            return children;
698
        }
699

    
700
        public T getTerm() {
701
            return term;
702
        }
703

    
704
        @Override
705
        public int hashCode() {
706
            final int prime = 31;
707
            int result = 1;
708
            result = prime * result + ((term == null) ? 0 : term.hashCode());
709
            return result;
710
        }
711

    
712
        @Override
713
        public boolean equals(Object obj) {
714
            if (this == obj) {
715
                return true;
716
            }
717
            if (obj == null) {
718
                return false;
719
            }
720
            if (getClass() != obj.getClass()) {
721
                return false;
722
            }
723
            TermNode other = (TermNode) obj;
724
            if (term == null) {
725
                if (other.term != null) {
726
                    return false;
727
                }
728
            } else if (!term.equals(other.term)) {
729
                return false;
730
            }
731
            return true;
732
        }
733

    
734
        @Override
735
        public int compareTo(TermNode<T> that) {
736
            return this.term.getMessage().compareTo(that.term.getMessage());
737
        }
738
    }
739

    
740

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

    
766
    /**
767
     * @param event
768
     * @return
769
     */
770
    public static Object getElementsFromSelectionChangedEvent(SelectionChangedEvent event) {
771
        IStructuredSelection selection = (IStructuredSelection) event.getSelection();
772
        Object selectionToSet;
773
        if(selection.size() == 1){
774
            selectionToSet = selection.getFirstElement();
775
        }
776
        else if(!selection.isEmpty()){
777
            selectionToSet = selection.toArray();
778
        }
779
        else{
780
            selectionToSet = selection;
781
        }
782
        return selectionToSet;
783
    }
784
}
(2-2/38)