Project

General

Profile

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

    
11
package eu.etaxonomy.taxeditor.model;
12

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

    
20
import org.apache.log4j.Logger;
21
import org.eclipse.core.commands.ExecutionException;
22
import org.eclipse.core.commands.operations.IOperationHistory;
23
import org.eclipse.core.runtime.IAdaptable;
24
import org.eclipse.core.runtime.ILog;
25
import org.eclipse.core.runtime.IProgressMonitor;
26
import org.eclipse.core.runtime.IStatus;
27
import org.eclipse.core.runtime.NullProgressMonitor;
28
import org.eclipse.core.runtime.OperationCanceledException;
29
import org.eclipse.core.runtime.Status;
30
import org.eclipse.core.runtime.SubProgressMonitor;
31
import org.eclipse.core.runtime.jobs.ISchedulingRule;
32
import org.eclipse.jface.action.IStatusLineManager;
33
import org.eclipse.jface.dialogs.MessageDialog;
34
import org.eclipse.jface.operation.IRunnableWithProgress;
35
import org.eclipse.jface.resource.ColorRegistry;
36
import org.eclipse.jface.resource.FontRegistry;
37
import org.eclipse.jface.window.ApplicationWindow;
38
import org.eclipse.swt.graphics.Color;
39
import org.eclipse.swt.graphics.Font;
40
import org.eclipse.swt.widgets.Display;
41
import org.eclipse.swt.widgets.Shell;
42
import org.eclipse.ui.IEditorPart;
43
import org.eclipse.ui.IViewPart;
44
import org.eclipse.ui.IViewReference;
45
import org.eclipse.ui.IWorkbench;
46
import org.eclipse.ui.IWorkbenchPage;
47
import org.eclipse.ui.IWorkbenchPart;
48
import org.eclipse.ui.PartInitException;
49
import org.eclipse.ui.PlatformUI;
50
import org.eclipse.ui.ide.undo.WorkspaceUndoUtil;
51
import org.eclipse.ui.part.EditorPart;
52
import org.eclipse.ui.progress.IProgressService;
53
import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
54
import org.eclipse.ui.themes.ITheme;
55
import org.eclipse.ui.themes.IThemeManager;
56

    
57
import eu.etaxonomy.cdm.model.common.IEnumTerm;
58
import eu.etaxonomy.taxeditor.operation.AbstractPostOperation;
59
import eu.etaxonomy.taxeditor.operation.IPostOperationEnabled;
60
import eu.etaxonomy.taxeditor.store.internal.TaxeditorStorePlugin;
61
import eu.etaxonomy.taxeditor.view.AbstractCdmDataViewer;
62
import eu.etaxonomy.taxeditor.view.detail.DetailsViewPart;
63
import eu.etaxonomy.taxeditor.view.supplementaldata.SupplementalDataViewPart;
64

    
65
/**
66
 * <p>
67
 * Abstract AbstractUtility class.
68
 * </p>
69
 *
70
 * @author n.hoffmann
71
 * @created 11.05.2009
72
 * @version 1.0
73
 */
74
public abstract class AbstractUtility {
75

    
76
	/** Constant <code>statusLineManager</code> */
77
	protected static IStatusLineManager statusLineManager;
78

    
79
	/**
80
	 * <p>
81
	 * closeAll
82
	 * </p>
83
	 *
84
	 * @return a boolean.
85
	 */
86
	public static boolean closeAll() {
87
		return getActivePage().closeAllEditors(true);
88
	}
89

    
90
	/**
91
	 * Close the given editor.
92
	 *
93
	 * @param editor
94
	 *            The <tt>MultipageTaxonEditor</tt> to close.
95
	 * @return <tt>true</tt> on success
96
	 */
97
	public static boolean close(EditorPart editor) {
98
		return getActivePage().closeEditor(editor, true);
99
	}
100

    
101
	/**
102
	 * <p>
103
	 * getShell
104
	 * </p>
105
	 *
106
	 * @return a {@link org.eclipse.swt.widgets.Shell} object.
107
	 */
108
	public static Shell getShell() {
109

    
110
		return TaxeditorStorePlugin.getDefault().getWorkbench()
111
				.getActiveWorkbenchWindow().getShell();
112
	}
113

    
114
	/**
115
	 * <p>
116
	 * getActivePage
117
	 * </p>
118
	 *
119
	 * @return a {@link org.eclipse.ui.IWorkbenchPage} object.
120
	 */
121
	public static IWorkbenchPage getActivePage() {
122

    
123
		return TaxeditorStorePlugin.getDefault().getWorkbench()
124
				.getActiveWorkbenchWindow().getActivePage();
125
	}
126

    
127
	/**
128
	 * <p>
129
	 * getActivePart
130
	 * </p>
131
	 *
132
	 * @return a {@link org.eclipse.ui.IWorkbenchPart} object.
133
	 */
134
	public static IWorkbenchPart getActivePart() {
135
		return getActivePage() != null ? getActivePage().getActivePart() : null;
136
	}
137

    
138
	public static IWorkbench getWorkbench() {
139
		return TaxeditorStorePlugin.getDefault().getWorkbench();
140
	}
141

    
142
	/**
143
	 * <p>
144
	 * getWorkbenchWindow
145
	 * </p>
146
	 *
147
	 * @return a {@link org.eclipse.jface.window.ApplicationWindow} object.
148
	 */
149
	public static ApplicationWindow getWorkbenchWindow() {
150
		if (getWorkbench().getWorkbenchWindowCount() > 1) {
151
			throw new IllegalStateException("More than one workbench window");
152
		}
153
		return (ApplicationWindow) getWorkbench().getWorkbenchWindows()[0];
154
	}
155

    
156
	/**
157
	 * <p>
158
	 * showView
159
	 * </p>
160
	 *
161
	 * @param id
162
	 *            a {@link java.lang.String} object.
163
	 * @return a {@link org.eclipse.ui.IViewPart} object.
164
	 */
165
	public static IViewPart showView(String id) {
166
		try {
167
			return PlatformUI.getWorkbench().getActiveWorkbenchWindow()
168
					.getActivePage()
169
					.showView(id, null, IWorkbenchPage.VIEW_VISIBLE);
170
		} catch (PartInitException e) {
171
			errorDialog("Error opening view", AbstractUtility.class, "Could not open view: " + id, e);
172
			return null;
173
		}
174
	}
175

    
176
	/**
177
	 * <p>
178
	 * hideView
179
	 * </p>
180
	 *
181
	 * @param view
182
	 *            a {@link org.eclipse.ui.IViewPart} object.
183
	 */
184
	public static void hideView(IViewPart view) {
185
		PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
186
				.hideView(view);
187
	}
188

    
189
	/**
190
	 * <p>
191
	 * getView
192
	 * </p>
193
	 *
194
	 * @param id
195
	 *            a {@link java.lang.String} object.
196
	 * @param restore
197
	 *            a boolean.
198
	 * @return a {@link org.eclipse.ui.IViewPart} object.
199
	 */
200
	public static IViewPart getView(String id, boolean restore) {
201
		IViewReference[] references = PlatformUI.getWorkbench()
202
				.getActiveWorkbenchWindow().getActivePage().getViewReferences();
203
		for (IViewReference reference : references) {
204
			if (reference.getId().equals(id)) {
205
				return reference.getView(restore);
206
			}
207
		}
208
		return null;
209
	}
210

    
211
	/**
212
	 * <p>
213
	 * getService
214
	 * </p>
215
	 *
216
	 * @param api
217
	 *            a {@link java.lang.Class} object.
218
	 * @return a {@link java.lang.Object} object.
219
	 */
220
	public static Object getService(Class api) {
221
		return TaxeditorStorePlugin.getDefault().getWorkbench().getService(api);
222
	}
223

    
224
	/**
225
	 * <p>
226
	 * getCurrentTheme
227
	 * </p>
228
	 *
229
	 * @return a {@link org.eclipse.ui.themes.ITheme} object.
230
	 */
231
	public static ITheme getCurrentTheme() {
232
		IThemeManager themeManager = TaxeditorStorePlugin.getDefault()
233
				.getWorkbench().getThemeManager();
234
		return themeManager.getCurrentTheme();
235
	}
236

    
237
	/**
238
	 * Fonts registered to the plugin may be obtained with the Eclipse themeing
239
	 * functionality. Thus fonts are chooseable by the user via
240
	 * Preferences->General->Appearance->Colors and Fonts
241
	 *
242
	 * @return the FontRegistry for the current theme
243
	 */
244
	public static FontRegistry getFontRegistry() {
245
		return getCurrentTheme().getFontRegistry();
246
	}
247

    
248
	/**
249
	 * <p>
250
	 * getFont
251
	 * </p>
252
	 *
253
	 * @param symbolicName
254
	 *            a {@link java.lang.String} object.
255
	 * @return a {@link org.eclipse.swt.graphics.Font} object.
256
	 */
257
	public static Font getFont(String symbolicName) {
258
		return getFontRegistry().get(symbolicName);
259
	}
260

    
261
	/**
262
	 * Color registered to the plugin may be obtained with the Eclipse themeing
263
	 * functionality. Thus colors are editable by the user via
264
	 * Preferences->General->Appearance->Colors and Fonts
265
	 *
266
	 * @return the ColorRegistry for the current theme
267
	 */
268
	public static ColorRegistry getColorRegistry() {
269
		return getCurrentTheme().getColorRegistry();
270
	}
271

    
272
	/**
273
	 * <p>
274
	 * getColor
275
	 * </p>
276
	 *
277
	 * @param symbolicName
278
	 *            a {@link java.lang.String} object.
279
	 * @return a {@link org.eclipse.swt.graphics.Color} object.
280
	 */
281
	public static Color getColor(String symbolicName) {
282
		return getColorRegistry().get(symbolicName);
283
	}
284

    
285
	/**
286
	 * Open a message box that informs the user about unimplemented
287
	 * functionality. This method is for developer convenience.
288
	 *
289
	 * @param source
290
	 *            a {@link java.lang.Object} object.
291
	 */
292
	public static void notImplementedMessage(Object source) {
293
		warningDialog("Not yet implemented", source,
294
				"This functionality is not yet implemented.");
295
	}
296

    
297
	/**
298
	 * <p>
299
	 * informationDialog
300
	 * </p>
301
	 *
302
	 * @param title
303
	 *            a {@link java.lang.String} object.
304
	 * @param message
305
	 *            a {@link java.lang.String} object.
306
	 */
307
	public static void informationDialog(final String title,
308
			final String message) {
309
		Display.getDefault().asyncExec(new Runnable() {
310

    
311
			@Override
312
            public void run() {
313
				MessageDialog.openInformation(getShell(), title, message);
314
			}
315
		});
316
	}
317

    
318
	public static void informationDialog(final String title,
319
			final IStatus status) {
320
		informationDialog(title, status.getMessage());
321
	}
322

    
323
	/**
324
	 * <p>
325
	 * warningDialog
326
	 * </p>
327
	 *
328
	 * @param title
329
	 *            The dialogs title
330
	 * @param source
331
	 *            The object where the warning was generated (used by log4j)
332
	 * @param message
333
	 *            An informative String to be presented to the user
334
	 */
335
	public static void warningDialog(final String title, final Object source,
336
			final String message) {
337
		Display.getDefault().asyncExec(new Runnable() {
338

    
339
			@Override
340
            public void run() {
341
				MessageDialog.openWarning(getShell(), title, message);
342
				Class<? extends Object> clazz = source != null ? source
343
						.getClass() : AbstractUtility.class;
344
				warn(clazz, message);
345
			}
346
		});
347
	}
348

    
349
	/**
350
	 * @param title
351
	 * @param termBase
352
	 * @param status
353
	 */
354
	public static void warningDialog(String title, Object source,
355
			IStatus status) {
356
		warningDialog(title, source, status.getMessage());
357
	}
358

    
359
	/**
360
	 * <p>
361
	 * errorDialog
362
	 * </p>
363
	 *
364
	 * @param title
365
	 *            The dialogs title
366
	 * @param source
367
	 *            The object where the warning was generated (used by log4j)
368
	 * @param message
369
	 *            An informative String to be presented to the user
370
	 * @param title
371
	 *            The dialogs title
372
	 * @param t
373
	 *            a Throwable if one exists or null
374
	 */
375
	public static void errorDialog(final String title, final Object source,
376
			final String message, final Throwable t) {
377
		Display.getDefault().asyncExec(new Runnable() {
378

    
379
			@Override
380
            public void run() {
381
				MessageDialog.openError(getShell(), title, message + getCauseRecursively(t));
382
				Class<? extends Object> clazz = source != null ? source
383
						.getClass() : this.getClass();
384
				error(clazz, message, t);
385
			}
386

    
387
			private String getCauseRecursively(Throwable t) {
388
				if(t == null){
389
					return null;
390
				}
391

    
392
				if(t.getCause() != null){
393
					return getCauseRecursively(t.getCause());
394
				}else{
395
					return String.format("\n\nException: %s\nMessage: %s", t.getClass().getSimpleName(), t.getMessage());
396
				}
397

    
398
			}
399
		});
400
	}
401

    
402
	public static void errorDialog(final String title, final Object source,
403
			final String message){
404
		errorDialog(title, source, message, null);
405
	}
406

    
407
	/**
408
	 * <p>
409
	 * errorDialog
410
	 * </p>
411
	 *
412
	 * @param title
413
	 *            a {@link java.lang.String} object.
414
	 * @param source
415
	 *            a {@link java.lang.Object} object.
416
	 * @param status
417
	 *            a {@link org.eclipse.core.runtime.IStatus} object.
418
	 */
419
	public static void errorDialog(final String title, final Object source,
420
			final IStatus status) {
421
		Display.getDefault().asyncExec(new Runnable() {
422

    
423
			@Override
424
            public void run() {
425
				MessageDialog.openError(getShell(), title, status.getMessage());
426
				Class<? extends Object> clazz = source != null ? source
427
						.getClass() : this.getClass();
428
				error(clazz, status.getMessage(), status.getException());
429
			}
430
		});
431
	}
432

    
433
	/**
434
	 * <p>
435
	 * confirmDialog
436
	 * </p>
437
	 *
438
	 * @param title
439
	 *            a {@link java.lang.String} object.
440
	 * @param message
441
	 *            a {@link java.lang.String} object.
442
	 * @return a boolean.
443
	 */
444
	public static boolean confirmDialog(String title, String message) {
445
		return MessageDialog.openQuestion(getShell(), title, message);
446
	}
447

    
448
	/**
449
	 * <p>
450
	 * executeOperation
451
	 * </p>
452
	 *
453
	 * @param operation
454
	 *            a
455
	 *            {@link eu.etaxonomy.taxeditor.operation.AbstractPostOperation}
456
	 *            object.
457
	 * @return a {@link org.eclipse.core.runtime.IStatus} object.
458
	 */
459
	public static IStatus executeOperation(final AbstractPostOperation operation) {
460
		if (getOperationHistory() == null) {
461
			throw new IllegalArgumentException(
462
					"There is no operation history for this context");
463
		}
464

    
465
		final IAdaptable uiInfoAdapter = WorkspaceUndoUtil
466
				.getUIInfoAdapter(getShell());
467

    
468
		IRunnableWithProgress runnable = new IRunnableWithProgress() {
469

    
470
			@Override
471
            public void run(IProgressMonitor monitor)
472
					throws InvocationTargetException, InterruptedException {
473
				monitor.beginTask(operation.getLabel(), 100);
474
				IStatus status = Status.CANCEL_STATUS;
475
				try {
476
					operation.addContext(IOperationHistory.GLOBAL_UNDO_CONTEXT);
477
					status = getOperationHistory().execute(operation, monitor,
478
							uiInfoAdapter);
479
				} catch (ExecutionException e) {
480
					errorDialog("Error executing operation", getClass(), String.format("An error occured while executing %s.", operation.getLabel()), e);
481
				} finally {
482
					monitor.done();
483
				}
484

    
485
				String statusString = status.equals(Status.OK_STATUS) ? "completed"
486
						: "cancelled";
487
				setStatusLine(operation.getLabel() + " " + statusString + ".");
488

    
489
			}
490
		};
491

    
492
		try {
493
			runInUI(runnable, null);
494
		} catch (Exception e) {
495
			errorDialog("Error executing operation", AbstractUtility.class, "An error occured while executing " + operation.getLabel(), e);
496
		}
497

    
498
		// // Start the main progress monitor.
499
		// IProgressMonitor newMonitor =
500
		// startMainMonitor(getMonitor(),operation.getLabel(), 100);
501
		//
502
		// // Check whether operation was canceled and do some steps.
503
		// workedChecked(newMonitor, 10);
504
		//
505
		// try {
506
		// IStatus status = getOperationHistory().execute(operation, newMonitor,
507
		// WorkspaceUndoUtil.getUIInfoAdapter(getShell()));
508
		//
509
		// // Check whether operation was canceled and do some steps.
510
		// workedChecked(newMonitor, 30);
511
		//
512
		// String statusString = status.equals(Status.OK_STATUS) ? "completed" :
513
		// "cancelled";
514
		// setStatusLine(operation.getLabel() + " " + statusString + ".");
515
		//
516
		// return status;
517
		// } catch (ExecutionException e) {
518
		// logger.error("Error executing operation: " + operation.getLabel(),
519
		// e);
520
		// errorDialog("Error executing operation: " + operation.getLabel(),
521
		// "Please refer to the error log.");
522
		// }
523
		// finally {
524
		//
525
		// // Stop the progress monitor.
526
		// newMonitor.done();
527
		// }
528

    
529
		IPostOperationEnabled postOperationEnabled = operation
530
				.getPostOperationEnabled();
531
		if (postOperationEnabled != null) {
532
			postOperationEnabled.onComplete();
533
		}
534
		return Status.OK_STATUS;
535
	}
536

    
537
	/**
538
	 * <p>
539
	 * getOperationHistory
540
	 * </p>
541
	 *
542
	 * @return a {@link org.eclipse.core.commands.operations.IOperationHistory}
543
	 *         object.
544
	 */
545
	public static IOperationHistory getOperationHistory() {
546
		return getWorkbench().getOperationSupport().getOperationHistory();
547
	}
548

    
549
	/**
550
	 * <p>
551
	 * setStatusLine
552
	 * </p>
553
	 *
554
	 * @param message
555
	 *            a {@link java.lang.String} object.
556
	 */
557
	public static void setStatusLine(final String message) {
558
		Display.getDefault().asyncExec(new Runnable() {
559

    
560
			@Override
561
            public void run() {
562
				statusLineManager.setMessage(message);
563
			}
564

    
565
		});
566

    
567
	}
568

    
569
	/**
570
	 * <p>
571
	 * getMonitor
572
	 * </p>
573
	 *
574
	 * @return a {@link org.eclipse.core.runtime.IProgressMonitor} object.
575
	 */
576
	public static IProgressMonitor getMonitor() {
577
		statusLineManager.setCancelEnabled(false);
578
		return statusLineManager.getProgressMonitor();
579
	}
580

    
581
	/**
582
	 * Starts either the given {@link IProgressMonitor} if it's not
583
	 * <code>null</code> or a new {@link NullProgressMonitor}.
584
	 *
585
	 * @param progressMonitor
586
	 *            The {@link IProgressMonitor} or <code>null</code> if no
587
	 *            progress should be reported.
588
	 * @param taskName
589
	 *            The name of the main task.
590
	 * @param steps
591
	 *            The number of steps this task is subdivided into.
592
	 * @return The {@link IProgressMonitor}.
593
	 */
594
	public static IProgressMonitor startMainMonitor(
595
			IProgressMonitor progressMonitor, String taskName, int steps) {
596
		IProgressMonitor newMonitor = progressMonitor;
597
		if (newMonitor == null) {
598
			newMonitor = new NullProgressMonitor();
599
		}
600
		newMonitor.beginTask(taskName == null ? "" : taskName, steps);
601
		newMonitor.subTask(" ");
602
		return newMonitor;
603
	}
604

    
605
	/**
606
	 * Creates a {@link SubProgressMonitor} if the given
607
	 * {@link IProgressMonitor} is not <code>null</code> and not a
608
	 * {@link NullProgressMonitor}.
609
	 *
610
	 * @param progressMonitor
611
	 *            The parent {@link IProgressMonitor} of the
612
	 *            {@link SubProgressMonitor} to be created.
613
	 * @param ticks
614
	 *            The number of steps this subtask is subdivided into. Must be a
615
	 *            positive number and must not be
616
	 *            {@link IProgressMonitor#UNKNOWN}.
617
	 * @return The {@link IProgressMonitor}.
618
	 */
619
	public static IProgressMonitor getSubProgressMonitor(
620
			IProgressMonitor progressMonitor, int ticks) {
621
		if (progressMonitor == null) {
622
			return new NullProgressMonitor();
623
		}
624
		if (progressMonitor instanceof NullProgressMonitor) {
625
			return progressMonitor;
626
		}
627

    
628
		return new SubProgressMonitor(progressMonitor, ticks);
629
	}
630

    
631
	/**
632
	 * Checks whether the user canceled this operation. If not canceled, the
633
	 * given number of steps are declared as done.
634
	 *
635
	 * @param newMonitor
636
	 *            a {@link org.eclipse.core.runtime.IProgressMonitor} object.
637
	 * @param steps
638
	 *            a int.
639
	 */
640
	public static void workedChecked(IProgressMonitor newMonitor, int steps) {
641
		// In case the progress monitor was canceled throw an exception.
642
		if (newMonitor.isCanceled()) {
643
			throw new OperationCanceledException();
644
		}
645
		// Otherwise declare this step as done.
646
		newMonitor.worked(steps);
647
	}
648

    
649
	/**
650
	 * Present a progress dialog to the user. This dialog will block the UI
651
	 *
652
	 * @param runnable
653
	 *            an implementation of {@link IRunnableWithProgress}
654
	 * @throws java.lang.InterruptedException
655
	 *             if any.
656
	 * @throws java.lang.reflect.InvocationTargetException
657
	 *             if any.
658
	 */
659
	public static void busyCursorWhile(IRunnableWithProgress runnable)
660
			throws InvocationTargetException, InterruptedException {
661
		getProgressService().busyCursorWhile(runnable);
662
	}
663

    
664
	/**
665
	 * <p>
666
	 * runInUI
667
	 * </p>
668
	 *
669
	 * @see {@link IProgressService#runInUI(org.eclipse.jface.operation.IRunnableContext, IRunnableWithProgress, ISchedulingRule)}
670
	 * @param runnable
671
	 *            a {@link org.eclipse.jface.operation.IRunnableWithProgress}
672
	 *            object.
673
	 * @param rule
674
	 *            a {@link org.eclipse.core.runtime.jobs.ISchedulingRule}
675
	 *            object.
676
	 * @throws java.lang.reflect.InvocationTargetException
677
	 *             if any.
678
	 * @throws java.lang.InterruptedException
679
	 *             if any.
680
	 */
681
	public static void runInUI(IRunnableWithProgress runnable,
682
			ISchedulingRule rule) throws InvocationTargetException,
683
			InterruptedException {
684
		getProgressService().runInUI(getWorkbenchWindow(), runnable, rule);
685
	}
686

    
687
	/**
688
	 * <p>
689
	 * run
690
	 * </p>
691
	 *
692
	 * @param fork
693
	 *            a boolean.
694
	 * @param cancelable
695
	 *            a boolean.
696
	 * @param runnable
697
	 *            a {@link org.eclipse.jface.operation.IRunnableWithProgress}
698
	 *            object.
699
	 * @throws java.lang.reflect.InvocationTargetException
700
	 *             if any.
701
	 * @throws java.lang.InterruptedException
702
	 *             if any.
703
	 */
704
	public static void run(boolean fork, boolean cancelable,
705
			IRunnableWithProgress runnable) throws InvocationTargetException,
706
			InterruptedException {
707
		getProgressService().run(fork, cancelable, runnable);
708
	}
709

    
710
	/**
711
	 * <p>
712
	 * getProgressService
713
	 * </p>
714
	 *
715
	 * @return a {@link org.eclipse.ui.progress.IProgressService} object.
716
	 */
717
	public static IProgressService getProgressService() {
718
		IWorkbench workbench = PlatformUI.getWorkbench();
719
		return workbench.getProgressService();
720
	}
721

    
722
	/**
723
	 * <p>
724
	 * getProgressService2
725
	 * </p>
726
	 *
727
	 * @return a {@link org.eclipse.ui.progress.IWorkbenchSiteProgressService}
728
	 *         object.
729
	 */
730
	public static IWorkbenchSiteProgressService getProgressService2() {
731
		return (IWorkbenchSiteProgressService) getService(IWorkbenchSiteProgressService.class);
732
	}
733

    
734
	/**
735
	 * <p>
736
	 * info
737
	 * </p>
738
	 *
739
	 * @param message
740
	 *            a {@link java.lang.String} object.
741
	 */
742
	public static void info(String message) {
743
		IStatus status = new Status(IStatus.INFO, getPluginId(), message);
744
		info(status);
745
	}
746

    
747
	/**
748
	 * <p>
749
	 * info
750
	 * </p>
751
	 *
752
	 * @param status
753
	 *            a {@link org.eclipse.core.runtime.IStatus} object.
754
	 */
755
	public static void info(IStatus status) {
756
		log(status);
757
	}
758

    
759
	/**
760
	 * <p>
761
	 * warn
762
	 * </p>
763
	 *
764
	 * @param source
765
	 *            a {@link java.lang.Class} object.
766
	 * @param message
767
	 *            a {@link java.lang.String} object.
768
	 */
769
	public static void warn(Class source, String message) {
770
		IStatus status = new Status(IStatus.WARNING, getPluginId(), message);
771
		getLog4JLogger(source).warn(message);
772
		log(status);
773
	}
774

    
775
	public static void warn(Class source, IStatus status) {
776
		getLog4JLogger(source).warn(status.getMessage(), status.getException());
777
		log(status);
778
	}
779

    
780
	public static void warn(Class source, Throwable t) {
781
		IStatus status = new Status(IStatus.WARNING, getPluginId(), t.getMessage(), t);
782
		getLog4JLogger(source).warn(t);
783
		log(status);
784
	}
785

    
786
	/**
787
	 * <p>
788
	 * error
789
	 * </p>
790
	 *
791
	 * @param source
792
	 *            a {@link java.lang.Class} object.
793
	 * @param t
794
	 *            a {@link java.lang.Throwable} object.
795
	 */
796
	public static void error(Class source, Throwable t) {
797
		error(source.getClass(), t.getMessage(), t);
798
	}
799

    
800
	/**
801
	 * <p>
802
	 * error
803
	 * </p>
804
	 *
805
	 * @param source
806
	 *            a {@link java.lang.Class} object.
807
	 * @param message
808
	 *            a {@link java.lang.String} object.
809
	 * @param t
810
	 *            a {@link java.lang.Throwable} object.
811
	 */
812
	public static void error(Class source, String message, Throwable t) {
813
		IStatus status = new Status(IStatus.ERROR, getPluginId(), message, t);
814
		error(source, status);
815
	}
816

    
817
	/**
818
	 * <p>
819
	 * error
820
	 * </p>
821
	 *
822
	 * @param source
823
	 *            a {@link java.lang.Class} object.
824
	 * @param status
825
	 *            a {@link org.eclipse.core.runtime.IStatus} object.
826
	 */
827
	public static void error(Class source, IStatus status) {
828
		getLog4JLogger(source)
829
				.error(status.getMessage(), status.getException());
830
		log(status);
831
	}
832

    
833
	/**
834
	 * <p>
835
	 * getLog4JLogger
836
	 * </p>
837
	 *
838
	 * @param clazz
839
	 *            a {@link java.lang.Class} object.
840
	 * @return a {@link org.apache.log4j.Logger} object.
841
	 */
842
	public static Logger getLog4JLogger(Class clazz) {
843
		return Logger.getLogger(clazz);
844
	}
845

    
846
	/**
847
	 * @see {@link ILog#log(IStatus)}
848
	 *
849
	 * @param status
850
	 */
851
	private static void log(IStatus status) {
852
		TaxeditorStorePlugin.getDefault().getLog().log(status);
853
	}
854

    
855
	/**
856
	 * <p>
857
	 * getPluginId
858
	 * </p>
859
	 *
860
	 * @return a {@link java.lang.String} object.
861
	 */
862
	public static String getPluginId() {
863
		return "eu.taxeditor";
864
	}
865

    
866
	/**
867
	 * <p>
868
	 * getActiveEditor
869
	 * </p>
870
	 *
871
	 * @return a {@link org.eclipse.ui.IEditorPart} object.
872
	 */
873
	public static IEditorPart getActiveEditor() {
874
		return getActivePage() != null ? getActivePage().getActiveEditor()
875
				: null;
876
	}
877

    
878
	/**
879
	 * <p>
880
	 * getDetailsView
881
	 * </p>
882
	 *
883
	 * @return a {@link eu.etaxonomy.taxeditor.view.detail.DetailsViewPart}
884
	 *         object.
885
	 */
886
	public static DetailsViewPart getDetailsView() {
887
		return (DetailsViewPart) getView(DetailsViewPart.ID, false);
888
	}
889

    
890
	/**
891
	 * <p>
892
	 * refreshDetailsViewer
893
	 * </p>
894
	 */
895
	public static void refreshDetailsViewer() {
896
		if (getDetailsView() != null) {
897
			((AbstractCdmDataViewer) getDetailsView().getViewer()).refresh();
898
		}
899
	}
900

    
901
	/**
902
	 * <p>
903
	 * reflowDetailsViewer
904
	 * </p>
905
	 */
906
	public static void reflowDetailsViewer() {
907
		if (getDetailsView() != null) {
908
			((AbstractCdmDataViewer) getDetailsView().getViewer()).reflow();
909
		}
910
	}
911

    
912
	public static SupplementalDataViewPart getSupplementalDataView() {
913
		return (SupplementalDataViewPart) getView(SupplementalDataViewPart.ID,
914
				false);
915
	}
916

    
917
	public static void reflowSupplementalViewer() {
918
		if (getSupplementalDataView() != null) {
919
			((AbstractCdmDataViewer) getSupplementalDataView().getViewer())
920
					.reflow();
921
		}
922
	}
923

    
924

    
925
    /**
926
     * Orders a Collection of {@link IEnumTerm}s according to the term
927
     * hierarchy. The hierarchy will be reduced to two layers: one layer being
928
     * the root elements (that have no parents) and the other being their
929
     * children and children's children recursively.<br>
930
     * The returned map will be be ordered primarily by root elements and
931
     * secondarily by the child elements, both ascending alphabetically. <br>
932
     * <br>
933
     * The reduced hierarchy could look like this:<br>
934
     * <ul>
935
     * <li>Root1
936
     *  <ul>
937
     *   <li>child1
938
     *   <li>child2
939
     *   <li>childOfChild2
940
     *  </ul>
941
     * <li>root2
942
     * <ul><li>child4</ul>
943
     * </ul>
944
     *
945
     * @param terms
946
     *            A {@link Collection} of {@link IEnumTerm}s for which the term
947
     *            hierarchy should be created
948
     * @return a map which holds the terms as keys and their string
949
     *         representation via {@link IEnumTerm#getMessage()} as values
950
     */
951
    public static <T extends IEnumTerm<T>> LinkedHashMap<T, String> orderTerms(Collection<T> terms) {
952
//        Comparator<TermNode<T>> comparator = new Comparator<TermNode<T>>() {
953
//            @Override
954
//            public int compare(TermNode<T> t1, TermNode<T> t2) {
955
//                return t1.getTerm().getMessage().compareTo(t2.getTerm().getMessage());
956
//            }
957
//        };
958

    
959
        TreeSet<TermNode<T>> parentElements = new TreeSet<TermNode<T>>();
960
        parentElements.addAll(getTermHierarchy(terms));
961

    
962
        // create list according to the type hierarchy (root elements alphabetically with recursive children also alphabetically)
963
        LinkedHashMap<T, String> result = new LinkedHashMap<T, String>();
964
        parseTermTree(parentElements, result, -1);
965
        return result;
966
    }
967

    
968
    private static<T extends IEnumTerm<T>> void parseTermTree(Collection<TermNode<T>> children, LinkedHashMap<T, String> result, int depth){
969
        depth++;
970
        for(TermNode<T> node:children){
971
            String indentString = "";
972
            for(int i=0;i<depth;i++){
973
                indentString += "  ";
974
            }
975
            result.put(node.term, indentString + node.term.getMessage());
976
            parseTermTree(node.children, result, depth);
977
        }
978
    }
979

    
980
    private static<T extends IEnumTerm<T>> void addToParents(List<TermNode<T>> parents, Collection<T> terms){
981
        List<TermNode<T>> hasChildrenList = new ArrayList<TermNode<T>>();
982
        for(T term:terms){
983
            // only terms with parents
984
            if(term.getKindOf()!=null){
985
                TermNode<T> parentNode = new TermNode<T>(term.getKindOf());
986
                TermNode<T> childNode = new TermNode<T>(term);
987
                if(parents.contains(parentNode)){
988
                    // parent found in parent list -> add this term to parent's child list
989
                    parents.get(parents.indexOf(parentNode)).addChild(childNode);
990
                    if(!term.getGeneralizationOf().isEmpty()){
991
                        // has more children -> add to list which will be the parent for the next recursion
992
                        hasChildrenList.add(childNode);
993
                    }
994
                }
995
            }
996
        }
997
        if(!hasChildrenList.isEmpty()){
998
            addToParents(hasChildrenList, terms);
999
        }
1000
    }
1001

    
1002
    private static<T extends IEnumTerm<T>> List<TermNode<T>> getTermHierarchy(Collection<T> terms){
1003
        List<TermNode<T>> parents = new ArrayList<TermNode<T>>();
1004
        // get root elements
1005
        for(T term:terms){
1006
            T parentTerm = term.getKindOf();
1007
            if(parentTerm==null){
1008
                // root element
1009
                parents.add(new TermNode<T>(term));
1010
            }
1011
        }
1012
        addToParents(parents, terms);
1013
        return parents;
1014
    }
1015

    
1016
    @SuppressWarnings("unchecked")
1017
    /**
1018
     * Recursively iterates over all term parents until no more parent is found i.e. the root node
1019
     * @param term The term for which the parent should be found
1020
     * @return the root terms of the term hierarchy
1021
     */
1022
    private static<T extends IEnumTerm<T>> T getParentFor(T term){
1023
        // PP: cast should be safe. Why is Eclipse complaining??
1024
        T parent = term.getKindOf();
1025
        if(parent==null){
1026
            return term;
1027
        }
1028
        else{
1029
            return getParentFor(term.getKindOf());
1030
        }
1031
    }
1032

    
1033
    private static class TermNode<T extends IEnumTerm<T>> implements Comparable<TermNode<T>>{
1034
        private final T term;
1035
        private final TreeSet<TermNode<T>> children;
1036

    
1037
        /**
1038
         * @param term
1039
         * @param children
1040
         */
1041
        public TermNode(T term) {
1042
            super();
1043
            this.term = term;
1044
            this.children = new TreeSet<TermNode<T>>();
1045
        }
1046

    
1047
        public void addChild(TermNode<T> child){
1048
            this.children.add(child);
1049
        }
1050

    
1051
        /**
1052
         * @return the children
1053
         */
1054
        public TreeSet<TermNode<T>> getChildren() {
1055
            return children;
1056
        }
1057

    
1058
        /**
1059
         * @return the term
1060
         */
1061
        public T getTerm() {
1062
            return term;
1063
        }
1064

    
1065
        /* (non-Javadoc)
1066
         * @see java.lang.Object#hashCode()
1067
         */
1068
        @Override
1069
        public int hashCode() {
1070
            final int prime = 31;
1071
            int result = 1;
1072
            result = prime * result + ((term == null) ? 0 : term.hashCode());
1073
            return result;
1074
        }
1075

    
1076
        /* (non-Javadoc)
1077
         * @see java.lang.Object#equals(java.lang.Object)
1078
         */
1079
        @Override
1080
        public boolean equals(Object obj) {
1081
            if (this == obj) {
1082
                return true;
1083
            }
1084
            if (obj == null) {
1085
                return false;
1086
            }
1087
            if (getClass() != obj.getClass()) {
1088
                return false;
1089
            }
1090
            TermNode other = (TermNode) obj;
1091
            if (term == null) {
1092
                if (other.term != null) {
1093
                    return false;
1094
                }
1095
            } else if (!term.equals(other.term)) {
1096
                return false;
1097
            }
1098
            return true;
1099
        }
1100

    
1101
        /* (non-Javadoc)
1102
         * @see java.lang.Comparable#compareTo(java.lang.Object)
1103
         */
1104
        @Override
1105
        public int compareTo(TermNode<T> that) {
1106
            return this.term.getMessage().compareTo(that.term.getMessage());
1107
        }
1108
    }
1109

    
1110
}
(2-2/32)