From 032ffea7c87ffeaef0a73e797f343a1bf87b8421 Mon Sep 17 00:00:00 2001 From: Eyck Jentzsch Date: Thu, 22 Oct 2015 00:05:29 +0200 Subject: [PATCH] Initial version of E4 based SC Viewer application --- com.minres.scviewer.e4.application/.classpath | 7 + com.minres.scviewer.e4.application/.gitignore | 1 + com.minres.scviewer.e4.application/.project | 33 + .../.settings/org.eclipse.jdt.core.prefs | 7 + .../.settings/org.eclipse.pde.core.prefs | 3 + .../Application.e4xmi | 190 ++++++ .../META-INF/MANIFEST.MF | 29 + .../build.properties | 9 + ...com.minres.scviewer.e4.application.product | 130 ++++ .../css/default.css | 205 ++++++ .../icons/SCViewer.icns | Bin 0 -> 46830 bytes .../icons/SCViewer.ico | Bin 0 -> 216870 bytes .../icons/SCViewer_128x32.png | Bin 0 -> 6444 bytes .../icons/SCViewer_16x32.png | Bin 0 -> 3715 bytes .../icons/SCViewer_256x32.png | Bin 0 -> 8969 bytes .../icons/SCViewer_32x32.png | Bin 0 -> 4251 bytes .../icons/SCViewer_48x32.png | Bin 0 -> 4845 bytes .../icons/SCViewer_512.png | Bin 0 -> 12776 bytes .../icons/SCViewer_64x32.png | Bin 0 -> 5206 bytes .../icons/bullet_plus.png | Bin 0 -> 305 bytes .../icons/cross.png | Bin 0 -> 655 bytes .../icons/database.png | Bin 0 -> 390 bytes .../icons/down_blue.png | Bin 0 -> 760 bytes .../icons/folder.png | Bin 0 -> 537 bytes .../icons/folder_database.png | Bin 0 -> 687 bytes .../icons/play_blue.png | Bin 0 -> 407 bytes .../icons/play_green.png | Bin 0 -> 414 bytes .../icons/reverse_blue.png | Bin 0 -> 402 bytes .../icons/reverse_green.png | Bin 0 -> 406 bytes .../icons/save_edit.png | Bin 0 -> 933 bytes .../icons/scviewer.gif | Bin 0 -> 118 bytes .../icons/scviewer.png | Bin 0 -> 255 bytes .../icons/signal.png | Bin 0 -> 717 bytes .../icons/stream.png | Bin 0 -> 444 bytes .../icons/trash.png | Bin 0 -> 676 bytes .../icons/up_blue.png | Bin 0 -> 759 bytes .../icons/zoom.png | Bin 0 -> 692 bytes .../icons/zoom_in.png | Bin 0 -> 725 bytes .../icons/zoom_out.png | Bin 0 -> 708 bytes com.minres.scviewer.e4.application/plugin.xml | 22 + .../scviewer/e4/application/E4LifeCycle.java | 43 ++ .../e4/application/handlers/AboutHandler.java | 23 + .../handlers/DeleteWaveformHandler.java | 29 + .../handlers/MoveWaveformHandler.java | 38 ++ .../application/handlers/NavigateEvent.java | 40 ++ .../application/handlers/NavigateTrans.java | 37 ++ .../e4/application/handlers/OpenHandler.java | 61 ++ .../e4/application/handlers/QuitHandler.java | 28 + .../e4/application/handlers/SaveHandler.java | 32 + .../handlers/SelectAllHandler.java | 13 + .../e4/application/handlers/ZoomHandler.java | 40 ++ .../e4/application/internal/HeapStatus.java | 607 ++++++++++++++++++ .../internal/IHeapStatusConstants.java | 19 + .../internal/StatusBarControl.java | 209 ++++++ .../e4/application/internal/TrimUtil.java | 42 ++ .../internal/WaveStatusBarControl.java | 100 +++ .../e4/application/parts/DesignBrowser.java | 108 ++++ .../application/parts/TransactionDetails.java | 233 +++++++ .../application/parts/WaveformListPart.java | 170 +++++ .../application/parts/WaveformViewerPart.java | 369 +++++++++++ .../provider/TxDbContentProvider.java | 68 ++ .../provider/TxDbLabelProvider.java | 88 +++ .../provider/TxPropertiesContentProvider.java | 52 ++ .../provider/TxPropertiesLabelProvider.java | 72 +++ .../org/eclipse/wb/swt/ResourceManager.java | 415 ++++++++++++ .../eclipse/wb/swt/SWTResourceManager.java | 447 +++++++++++++ signal.xcf | Bin 0 -> 1420 bytes 67 files changed, 4019 insertions(+) create mode 100644 com.minres.scviewer.e4.application/.classpath create mode 100644 com.minres.scviewer.e4.application/.gitignore create mode 100644 com.minres.scviewer.e4.application/.project create mode 100644 com.minres.scviewer.e4.application/.settings/org.eclipse.jdt.core.prefs create mode 100644 com.minres.scviewer.e4.application/.settings/org.eclipse.pde.core.prefs create mode 100644 com.minres.scviewer.e4.application/Application.e4xmi create mode 100644 com.minres.scviewer.e4.application/META-INF/MANIFEST.MF create mode 100644 com.minres.scviewer.e4.application/build.properties create mode 100644 com.minres.scviewer.e4.application/com.minres.scviewer.e4.application.product create mode 100644 com.minres.scviewer.e4.application/css/default.css create mode 100644 com.minres.scviewer.e4.application/icons/SCViewer.icns create mode 100644 com.minres.scviewer.e4.application/icons/SCViewer.ico create mode 100644 com.minres.scviewer.e4.application/icons/SCViewer_128x32.png create mode 100644 com.minres.scviewer.e4.application/icons/SCViewer_16x32.png create mode 100644 com.minres.scviewer.e4.application/icons/SCViewer_256x32.png create mode 100644 com.minres.scviewer.e4.application/icons/SCViewer_32x32.png create mode 100644 com.minres.scviewer.e4.application/icons/SCViewer_48x32.png create mode 100644 com.minres.scviewer.e4.application/icons/SCViewer_512.png create mode 100644 com.minres.scviewer.e4.application/icons/SCViewer_64x32.png create mode 100644 com.minres.scviewer.e4.application/icons/bullet_plus.png create mode 100644 com.minres.scviewer.e4.application/icons/cross.png create mode 100755 com.minres.scviewer.e4.application/icons/database.png create mode 100644 com.minres.scviewer.e4.application/icons/down_blue.png create mode 100755 com.minres.scviewer.e4.application/icons/folder.png create mode 100644 com.minres.scviewer.e4.application/icons/folder_database.png create mode 100644 com.minres.scviewer.e4.application/icons/play_blue.png create mode 100644 com.minres.scviewer.e4.application/icons/play_green.png create mode 100644 com.minres.scviewer.e4.application/icons/reverse_blue.png create mode 100644 com.minres.scviewer.e4.application/icons/reverse_green.png create mode 100644 com.minres.scviewer.e4.application/icons/save_edit.png create mode 100644 com.minres.scviewer.e4.application/icons/scviewer.gif create mode 100644 com.minres.scviewer.e4.application/icons/scviewer.png create mode 100644 com.minres.scviewer.e4.application/icons/signal.png create mode 100755 com.minres.scviewer.e4.application/icons/stream.png create mode 100644 com.minres.scviewer.e4.application/icons/trash.png create mode 100644 com.minres.scviewer.e4.application/icons/up_blue.png create mode 100644 com.minres.scviewer.e4.application/icons/zoom.png create mode 100644 com.minres.scviewer.e4.application/icons/zoom_in.png create mode 100644 com.minres.scviewer.e4.application/icons/zoom_out.png create mode 100644 com.minres.scviewer.e4.application/plugin.xml create mode 100644 com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/E4LifeCycle.java create mode 100644 com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/AboutHandler.java create mode 100644 com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/DeleteWaveformHandler.java create mode 100644 com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/MoveWaveformHandler.java create mode 100644 com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/NavigateEvent.java create mode 100644 com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/NavigateTrans.java create mode 100644 com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/OpenHandler.java create mode 100644 com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/QuitHandler.java create mode 100644 com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/SaveHandler.java create mode 100644 com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/SelectAllHandler.java create mode 100644 com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/ZoomHandler.java create mode 100644 com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/internal/HeapStatus.java create mode 100644 com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/internal/IHeapStatusConstants.java create mode 100644 com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/internal/StatusBarControl.java create mode 100644 com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/internal/TrimUtil.java create mode 100644 com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/internal/WaveStatusBarControl.java create mode 100644 com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/DesignBrowser.java create mode 100644 com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/TransactionDetails.java create mode 100644 com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/WaveformListPart.java create mode 100644 com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/WaveformViewerPart.java create mode 100644 com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/provider/TxDbContentProvider.java create mode 100644 com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/provider/TxDbLabelProvider.java create mode 100644 com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/provider/TxPropertiesContentProvider.java create mode 100644 com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/provider/TxPropertiesLabelProvider.java create mode 100644 com.minres.scviewer.e4.application/src/org/eclipse/wb/swt/ResourceManager.java create mode 100644 com.minres.scviewer.e4.application/src/org/eclipse/wb/swt/SWTResourceManager.java create mode 100644 signal.xcf diff --git a/com.minres.scviewer.e4.application/.classpath b/com.minres.scviewer.e4.application/.classpath new file mode 100644 index 0000000..098194c --- /dev/null +++ b/com.minres.scviewer.e4.application/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/com.minres.scviewer.e4.application/.gitignore b/com.minres.scviewer.e4.application/.gitignore new file mode 100644 index 0000000..ae3c172 --- /dev/null +++ b/com.minres.scviewer.e4.application/.gitignore @@ -0,0 +1 @@ +/bin/ diff --git a/com.minres.scviewer.e4.application/.project b/com.minres.scviewer.e4.application/.project new file mode 100644 index 0000000..5c5d8a7 --- /dev/null +++ b/com.minres.scviewer.e4.application/.project @@ -0,0 +1,33 @@ + + + com.minres.scviewer.e4.application + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + org.eclipse.pde.ds.core.builder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/com.minres.scviewer.e4.application/.settings/org.eclipse.jdt.core.prefs b/com.minres.scviewer.e4.application/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..f42de36 --- /dev/null +++ b/com.minres.scviewer.e4.application/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 +org.eclipse.jdt.core.compiler.compliance=1.7 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.7 diff --git a/com.minres.scviewer.e4.application/.settings/org.eclipse.pde.core.prefs b/com.minres.scviewer.e4.application/.settings/org.eclipse.pde.core.prefs new file mode 100644 index 0000000..f29e940 --- /dev/null +++ b/com.minres.scviewer.e4.application/.settings/org.eclipse.pde.core.prefs @@ -0,0 +1,3 @@ +eclipse.preferences.version=1 +pluginProject.extensions=false +resolve.requirebundle=false diff --git a/com.minres.scviewer.e4.application/Application.e4xmi b/com.minres.scviewer.e4.application/Application.e4xmi new file mode 100644 index 0000000..3dd80be --- /dev/null +++ b/com.minres.scviewer.e4.application/Application.e4xmi @@ -0,0 +1,190 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + glue + move_after:PerspectiveSpacer + SHOW_RESTORE_MENU + + + + + + + + + + + + + + + + + + + + + + categoryTag:General + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/com.minres.scviewer.e4.application/META-INF/MANIFEST.MF b/com.minres.scviewer.e4.application/META-INF/MANIFEST.MF new file mode 100644 index 0000000..5d29a8c --- /dev/null +++ b/com.minres.scviewer.e4.application/META-INF/MANIFEST.MF @@ -0,0 +1,29 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Application +Bundle-SymbolicName: com.minres.scviewer.e4.application;singleton:=true +Bundle-Version: 1.0.0.qualifier +Bundle-Vendor: MINRES Technologies GmbH +Require-Bundle: javax.inject;bundle-version="1.0.0", + org.eclipse.core.runtime;bundle-version="3.11.1", + org.eclipse.swt;bundle-version="3.104.1", + org.eclipse.e4.ui.model.workbench;bundle-version="1.1.100", + org.eclipse.jface;bundle-version="3.11.0", + org.eclipse.e4.ui.services;bundle-version="1.2.0", + org.eclipse.e4.ui.workbench;bundle-version="1.3.0", + org.eclipse.e4.core.di;bundle-version="1.5.0", + org.eclipse.e4.ui.di;bundle-version="1.1.0", + org.eclipse.e4.core.contexts;bundle-version="1.4.0", + com.minres.scviewer.database.swt;bundle-version="1.0.0", + com.minres.scviewer.database;bundle-version="1.0.0", + org.eclipse.equinox.ds;bundle-version="1.4.300", + org.eclipse.equinox.util;bundle-version="1.0.500", + org.eclipse.osgi.services;bundle-version="3.5.0", + org.eclipse.e4.core.services;bundle-version="2.0.0", + org.eclipse.osgi.services;bundle-version="3.5.0", + org.eclipse.core.jobs, + org.eclipse.osgi, + org.eclipse.wb.core.lib +Bundle-RequiredExecutionEnvironment: JavaSE-1.7 +Import-Package: com.minres.scviewer.database, + javax.inject;version="1.0.0" diff --git a/com.minres.scviewer.e4.application/build.properties b/com.minres.scviewer.e4.application/build.properties new file mode 100644 index 0000000..d21f19d --- /dev/null +++ b/com.minres.scviewer.e4.application/build.properties @@ -0,0 +1,9 @@ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml,\ + plugin.xml,\ + Application.e4xmi,\ + icons/,\ + css/default.css +source.. = src/ diff --git a/com.minres.scviewer.e4.application/com.minres.scviewer.e4.application.product b/com.minres.scviewer.e4.application/com.minres.scviewer.e4.application.product new file mode 100644 index 0000000..7537fca --- /dev/null +++ b/com.minres.scviewer.e4.application/com.minres.scviewer.e4.application.product @@ -0,0 +1,130 @@ + + + + + + + + + + + -clearPersistedState + + -XstartOnFirstThread -Dorg.eclipse.swt.internal.carbon.smallFonts + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/com.minres.scviewer.e4.application/css/default.css b/com.minres.scviewer.e4.application/css/default.css new file mode 100644 index 0000000..857a2b4 --- /dev/null +++ b/com.minres.scviewer.e4.application/css/default.css @@ -0,0 +1,205 @@ +/******************************************************************************* + * Copyright (c) 2010, 2014 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Lars Vogel - Bug 420836 + *******************************************************************************/ + +/* New ColorDefinitions for the E4 default theme */ +ThemesExtension { color-definition: + '#org-eclipse-ui-workbench-INACTIVE_UNSELECTED_TABS_COLOR_START', + '#org-eclipse-ui-workbench-INACTIVE_UNSELECTED_TABS_COLOR_END', + '#org-eclipse-ui-workbench-INACTIVE_TAB_OUTER_KEYLINE_COLOR', + '#org-eclipse-ui-workbench-INACTIVE_TAB_INNER_KEYLINE_COLOR', + '#org-eclipse-ui-workbench-INACTIVE_TAB_OUTLINE_COLOR', + '#org-eclipse-ui-workbench-ACTIVE_UNSELECTED_TABS_COLOR_START', + '#org-eclipse-ui-workbench-ACTIVE_UNSELECTED_TABS_COLOR_END', + '#org-eclipse-ui-workbench-ACTIVE_TAB_OUTER_KEYLINE_COLOR', + '#org-eclipse-ui-workbench-ACTIVE_TAB_INNER_KEYLINE_COLOR', + '#org-eclipse-ui-workbench-ACTIVE_TAB_OUTLINE_COLOR'; +} + +ColorDefinition#org-eclipse-ui-workbench-INACTIVE_UNSELECTED_TABS_COLOR_START { + color: #FFFFFF; + category: '#org-eclipse-ui-presentation-default'; + label: url('platform:/plugin/org.eclipse.ui.themes?message=INACTIVE_UNSELECTED_TABS_COLOR_START') +} + +ColorDefinition#org-eclipse-ui-workbench-INACTIVE_UNSELECTED_TABS_COLOR_END { + color: #FFFFFF; + category: '#org-eclipse-ui-presentation-default'; + label: url('platform:/plugin/org.eclipse.ui.themes?message=INACTIVE_UNSELECTED_TABS_COLOR_END'); +} + +ColorDefinition#org-eclipse-ui-workbench-INACTIVE_TAB_OUTER_KEYLINE_COLOR { + color: #FFFFFF; + category: '#org-eclipse-ui-presentation-default'; + label: url('platform:/plugin/org.eclipse.ui.themes?message=INACTIVE_TAB_OUTER_KEYLINE_COLOR'); +} + +ColorDefinition#org-eclipse-ui-workbench-INACTIVE_TAB_INNER_KEYLINE_COLOR { + color: #FFFFFF; + category: '#org-eclipse-ui-presentation-default'; + label: url('platform:/plugin/org.eclipse.ui.themes?message=INACTIVE_TAB_INNER_KEYLINE_COLOR'); +} + +ColorDefinition#org-eclipse-ui-workbench-INACTIVE_TAB_OUTLINE_COLOR { + color: #B6BCCC; + category: '#org-eclipse-ui-presentation-default'; + label: url('platform:/plugin/org.eclipse.ui.themes?message=INACTIVE_TAB_OUTLINE_COLOR'); +} + +ColorDefinition#org-eclipse-ui-workbench-ACTIVE_UNSELECTED_TABS_COLOR_START { + color: #FFFFFF; + category: '#org-eclipse-ui-presentation-default'; + label: url('platform:/plugin/org.eclipse.ui.themes?message=ACTIVE_UNSELECTED_TABS_COLOR_START'); +} + +ColorDefinition#org-eclipse-ui-workbench-ACTIVE_UNSELECTED_TABS_COLOR_END { + color: #FFFFFF; + category: '#org-eclipse-ui-presentation-default'; + label: url('platform:/plugin/org.eclipse.ui.themes?message=ACTIVE_UNSELECTED_TABS_COLOR_END'); +} + +ColorDefinition#org-eclipse-ui-workbench-ACTIVE_TAB_OUTER_KEYLINE_COLOR { + color: #CCCCCC; + category: '#org-eclipse-ui-presentation-default'; + label: url('platform:/plugin/org.eclipse.ui.themes?message=ACTIVE_TAB_OUTER_KEYLINE_COLOR'); +} + +ColorDefinition#org-eclipse-ui-workbench-ACTIVE_TAB_INNER_KEYLINE_COLOR { + color: #FFFFFF; + category: '#org-eclipse-ui-presentation-default'; + label: url('platform:/plugin/org.eclipse.ui.themes?message=ACTIVE_TAB_INNER_KEYLINE_COLOR'); +} + +ColorDefinition#org-eclipse-ui-workbench-ACTIVE_TAB_OUTLINE_COLOR { + color: #B6BCCC; + category: '#org-eclipse-ui-presentation-default'; + label: url('platform:/plugin/org.eclipse.ui.themes?message=ACTIVE_TAB_OUTLINE_COLOR'); +} + +/* Already existing ColorDefinitions overridden for the E4 default theme */ +ColorDefinition#org-eclipse-ui-workbench-INACTIVE_TAB_BG_START { + color: #dddfe5; +} + +ColorDefinition#org-eclipse-ui-workbench-INACTIVE_TAB_BG_END { + color: #FFFFFF; +} + +ColorDefinition#org-eclipse-ui-workbench-ACTIVE_TAB_BG_START{ + color: #FFFFFF; +} + +ColorDefinition#org-eclipse-ui-workbench-ACTIVE_TAB_BG_END { + color: #FFFFFF; +} + +ColorDefinition#org-eclipse-ui-workbench-ACTIVE_NOFOCUS_TAB_BG_START { + color: #FFFFFF; +} + +ColorDefinition#org-eclipse-ui-workbench-ACTIVE_NOFOCUS_TAB_BG_END { + color: #FFFFFF; +} + +ColorDefinition#org-eclipse-ui-workbench-ACTIVE_NOFOCUS_TAB_TEXT_COLOR { + color: #000000; +} + +.MTrimmedWindow.topLevel { + margin-top: 3px; + margin-bottom: 3px; + margin-left: 3px; + margin-right: 3px; +} + +.MPart.busy { + font-style: italic; +} + +.MPart.highlighted { + font-weight: bold; +} + +.MPartStack, .MPart { + font-family: '#org-eclipse-ui-workbench-TAB_TEXT_FONT'; +} + +CTabItem:selected { + color: '#org-eclipse-ui-workbench-ACTIVE_TAB_TEXT_COLOR'; +} + +.MPartStack { + swt-tab-renderer: url('bundleclass://org.eclipse.e4.ui.workbench.renderers.swt/org.eclipse.e4.ui.workbench.renderers.swt.CTabRendering'); + swt-selected-tab-fill: '#org-eclipse-ui-workbench-INACTIVE_TAB_BG_START' '#org-eclipse-ui-workbench-INACTIVE_TAB_BG_END' 100% 100%; + swt-unselected-tabs-color: '#org-eclipse-ui-workbench-INACTIVE_UNSELECTED_TABS_COLOR_START' '#org-eclipse-ui-workbench-INACTIVE_UNSELECTED_TABS_COLOR_END' 100% 100%; + swt-outer-keyline-color: '#org-eclipse-ui-workbench-INACTIVE_TAB_OUTER_KEYLINE_COLOR'; + swt-inner-keyline-color: '#org-eclipse-ui-workbench-INACTIVE_TAB_INNER_KEYLINE_COLOR'; + swt-tab-outline: '#org-eclipse-ui-workbench-INACTIVE_TAB_OUTLINE_COLOR'; + padding: 0px 2px 2px; + swt-shadow-visible: false; + swt-mru-visible: false; + color: '#org-eclipse-ui-workbench-INACTIVE_TAB_TEXT_COLOR'; +} + +.MPartStack.active { + swt-selected-tab-fill: '#org-eclipse-ui-workbench-ACTIVE_TAB_BG_START' '#org-eclipse-ui-workbench-ACTIVE_TAB_BG_END' 100% 100%; + swt-unselected-tabs-color: '#org-eclipse-ui-workbench-ACTIVE_UNSELECTED_TABS_COLOR_START' '#org-eclipse-ui-workbench-ACTIVE_UNSELECTED_TABS_COLOR_END' 100% 100%; + swt-outer-keyline-color: '#org-eclipse-ui-workbench-ACTIVE_TAB_OUTER_KEYLINE_COLOR'; + swt-inner-keyline-color: '#org-eclipse-ui-workbench-ACTIVE_TAB_INNER_KEYLINE_COLOR'; + swt-tab-outline: '#org-eclipse-ui-workbench-ACTIVE_TAB_OUTLINE_COLOR'; + swt-shadow-visible: false; +} + +.MPartStack.active.noFocus { + swt-selected-tab-fill: '#org-eclipse-ui-workbench-ACTIVE_NOFOCUS_TAB_BG_START' '#org-eclipse-ui-workbench-ACTIVE_NOFOCUS_TAB_BG_END' 100% 100%; +} + +.MPartStack.active.noFocus > CTabItem:selected { + color: '#org-eclipse-ui-workbench-ACTIVE_NOFOCUS_TAB_TEXT_COLOR'; +} + +#PerspectiveSwitcher { + eclipse-perspective-keyline-color: #AAB0BF #AAB0BF; +} + +.MToolControl.TrimStack { + frame-image: url(./winXPTSFrame.png); + handle-image: url(./winXPHandle.png); + frame-cuts: 5px 1px 5px 16px; +} + +.MToolBar.Draggable { + handle-image: url(./dragHandle.png); +} + +.MToolControl.Draggable { + handle-image: url(./dragHandle.png); +} + +.DragFeedback { + background-color: COLOR-WIDGET-NORMAL-SHADOW; +} + +.ModifiedDragFeedback { + background-color: #A0A000; +} + +.MPartStack > Composite { + background-color: '#org-eclipse-ui-workbench-INACTIVE_TAB_BG_END'; +} + +.MPartStack.active > Composite { + background-color: '#org-eclipse-ui-workbench-ACTIVE_TAB_BG_END'; +} + +.MPartStack.active.noFocus > Composite { + background-color: '#org-eclipse-ui-workbench-ACTIVE_NOFOCUS_TAB_BG_END'; +} diff --git a/com.minres.scviewer.e4.application/icons/SCViewer.icns b/com.minres.scviewer.e4.application/icons/SCViewer.icns new file mode 100644 index 0000000000000000000000000000000000000000..c4727f86ccebc61d8f50e4eda0db95029ad1c33f GIT binary patch literal 46830 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 literal 0 HcmV?d00001 diff --git a/com.minres.scviewer.e4.application/icons/SCViewer_128x32.png b/com.minres.scviewer.e4.application/icons/SCViewer_128x32.png new file mode 100644 index 0000000000000000000000000000000000000000..f7fb7fc3a8f9e2887ba04292696b7fabf68789e2 GIT binary patch literal 6444 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 TDIkNf00000NkvXXu0mjfY_Xoq literal 0 HcmV?d00001 diff --git a/com.minres.scviewer.e4.application/icons/SCViewer_512.png b/com.minres.scviewer.e4.application/icons/SCViewer_512.png new file mode 100644 index 0000000000000000000000000000000000000000..ba03ec8801b8a9a73430b9f3c40db4216ea9f92e GIT binary patch literal 12776 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 literal 0 HcmV?d00001 diff --git a/com.minres.scviewer.e4.application/icons/SCViewer_64x32.png b/com.minres.scviewer.e4.application/icons/SCViewer_64x32.png new file mode 100644 index 0000000000000000000000000000000000000000..304cd77db1185c03a7c4438e8408c3dfd3ab314a GIT binary patch literal 5206 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 literal 0 HcmV?d00001 diff --git a/com.minres.scviewer.e4.application/icons/bullet_plus.png b/com.minres.scviewer.e4.application/icons/bullet_plus.png new file mode 100644 index 0000000000000000000000000000000000000000..cd52e3c20b16a941284c8a3d84239b822aaa1308 GIT binary patch literal 305 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`>?NMQuI$&j+4y*6eUq-I0EIXU zJR*x37~~FuFyrCOkYJ!7OS+@4BLl<6e(pbstU&$&PZ!6Kid)GE60AKtRJgvS{rmsx zvGC#b^84#`c;b$Bddmvyb)LU(XJFB}%DCqLujXbI@h5N3{rUg%bv0XIm>ip`onYH% ze>sCYwf|&ZOp1TcA0jKR^rESM{yn3JZVjUo1s{!Te*J58oHc*?!4OZmCqj-ndI^r= z3IEQX-SG5QC7Ys|ADg6NUE6B@`35#szocZuR9F`|&wg6ZoSNBoI6cpB&f9%0!LsKZ w{(PU@`tZR@X`VOs|NlhC=dCuEoyT++I zn$b9r%cFfhHe2K68PkBu*@^<$y+7xQ$wJ~;c5aBx$R=xq*41Wo zhwQus_VOgm0hughj}MhOvs#{>Vg09Y8WxjWUJY5YW zJ?&8eG!59Cz=|E%Ns@013KLWOLV)CObIIj_5{>{#k%TEAMs_GbdDV`x-iYsGH z#=Z{USAQA>NY(}X7=3{K8#;1k*-!zk~CMF9Bv_3(^PCOq;!lvI6;>1s;*b z3=DFIK$tP_La7}C17l=nNJL45ua8x7ey(0(N`6wRUPW#JP&EUCO@$SZnVVXYs8Erc zlUHn2VXFjIVFhG^g!Ppaz)DK8ZIvQ?0~DO|i&7O#^-S~(l1A zfjnEKjFOT9D}DX)@^Za$W4-*MbbUihOG|wNBYh(yU7!lx;>x^|#0uTKVr7USFmqf| zi<65o3raHc^AtelCMM;Vme?vOfh>Xph&xL%(-1c06+^uR^q@XSM&D4+Kp$>4P^%3{ z)XKjoGZknv$b36P8?Z_gF{nK@`XI}Z90TzwSQO}0J1!f2c(B=V`5aP@1O~FHr;B5V zguReY99c`V;%|Np;n!6rk) z9Q!|W9v-^6nA<)^%cnu|08etmi@(vozH3P@|4{$)*Y%*78IvELE?@9$|9{CH77-F< za<%6QUOxJH^!>T#N0eVX7Bc!Mt@&}uCX;iW3$LqP+k5-Qb9P^P9{ySSdUc#!KWF>O z#)}cW44zTP=fo)KpB4Sf`l9vn^LOiN>r7NwmT}HJmdW5Tao6>K?(zF;cmHU4SfX&a ivCaO3l>5yP9!3W7Zxh^l&!3Y7rA1FyKbLh*2~7YDy(fAA literal 0 HcmV?d00001 diff --git a/com.minres.scviewer.e4.application/icons/folder.png b/com.minres.scviewer.e4.application/icons/folder.png new file mode 100755 index 0000000000000000000000000000000000000000..784e8fa48234f4f64b6922a6758f254ee0ca08ec GIT binary patch literal 537 zcmV+!0_OdRP)x(K@^6+>g^d@v4;gkbWsEoXE%32*i1tcpTNXd5CcIl)ECgqz|2rE6EW}s7R?kl za1q`0GCkMruC6-2LANtwVlsgzsp4?{@7$`KBv!G66>Vie3h?3OmEEkjwdLG0PgLVi z`!N((f$A@n17Ldj#`};0I3@iHJ5M{#IZz|UIYRm4(!uV7eYIYIwQf&}_2J~}>pQ^n z6o8--^T(=hkBNQ_k{-_GWE;FMW7!p}f{NG3nHZ{D5<3d8&tLh%a4AqqnjMkr3m&fkMdECD3N5}Unig5wy40;>lo4j~k+e}v)` zR6)J8Mk*u=SpB`p6o)7j?S0T@9?bz#m@l>gc*zk__|*!FMcHwP!gwLJvS~9c0px8E zWl`516uN0Cy%QCn*#P zN4+?XnV6U$gm4+)tOVYBPqW#iR4O4NG#U+RwHhG=0M1IFaU5fYPBd9i&QF= zBOt%>{_2-vWqR6}e=Q|zuYC{Uu?29>0nqF9j!t;*`+!k9HF4uzWQ+mrU&a`G`uoz? z#gBS;ID~+64r9zo0Iw1eXI_!I(0|i?-!<9Z@v?#tyr}>L)YYlM;xxzWB zci)1-?#>Q-`)#}rhzPl%F?4Yb=iJRf0!x1A0_U$k1q4)4Y2){ok#wD5&4{9uo~C&1 zQXYT84`6>h%AjLt$N-1h{%&j_q^YWt>=;P1=igr4zlL%fL;19?jRI!bA-Ztb`U~VH VYY-ljn{ogE002ovPDHLkV1lweE*Ss- literal 0 HcmV?d00001 diff --git a/com.minres.scviewer.e4.application/icons/play_blue.png b/com.minres.scviewer.e4.application/icons/play_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..cb75b58bb2ea8fe03c2447040129713fbb73a404 GIT binary patch literal 407 zcmV;I0cie-P)rW=u!wO3)t0x+dfZNog%}3>`t^@NUsHflREVRZ zpzC%Y$p(D=@rU96zyAy}5*!R-f*gfm#h2%iWWeVyzZt&$_{;F_<8KC41wIBDNv=ej z*po|e8Nh-r@DXUh&!7Jo-n{?Gz{JGJprOde@bb;~XbtZJc0g%4f(Cs0{2T0zZ{Pkf zFflWN#lCz4@xNUp$_4K}{s4O655pf|RPeH~Fzh(=jN#&y`)j{{c^pBM0bjlXZTtS0 zfs>7iVf*2y441FmTJ_>sR5(bEk+G1l0Utj7WcUdT#62foFkHEOe(~$mX>o+25(UUQ zZ2fN&d*Z)kHe}DaBcy!@2!;70=7av)EKMr3k zV7lPPKZXZqKQTPN@pa+x)ejOFNCmbrivP_5vo^05J!c+rU2uw zU;h|LG9aw@@;os?jzSp;4u=2#{xf|2@rQT=Y+_F?k&)y|R8`<(c=z!)!?z!Q89smc zjiHVOn`RB~1CNY#MPxM;`52zP{?70ZXgdcRGs8zL24Ho;w{PDre);x?;rq|O4Bx*0 z0rLNVo&V`Gkp_Hze=G3xxw~t39D2sU4z&3XFbci_4S4tQ2XS6_f1v;rS|Jiv%U1sR z_b<%VQUd6bzYJf#k`Ra>@Zwlh_=WT57H>cNoZ%-h5I=nSNt_Fi!Rym$ae@XD{{8u5 w84nB_LdqckTT9*L`R%ZkegGd%zJ033)MEL;q~zWyW51;2m%zxez6KZYN_zBBy#`J3U_ zkKYVmfiC#@jYuzieg8Y~+4V1L@11$iz|6|T@bBM$hVQ?=F#Pz88HiZDaD4RxkjfDI zIHi^U|NRe>GvsCX{_`6H$W AWdHyG literal 0 HcmV?d00001 diff --git a/com.minres.scviewer.e4.application/icons/save_edit.png b/com.minres.scviewer.e4.application/icons/save_edit.png new file mode 100644 index 0000000000000000000000000000000000000000..2c598e5aef10055fd508a52964ecac7ad00ef2a2 GIT binary patch literal 933 zcmV;W16urvP)u-})9LJv*F1{ejHrkmuH!p|^iHwD$_&@NHS7;!bkjOHl@dY|yD$2Nsfx$K)s4=Bo zuj_7YN4u_F*?R9NtXsRacD?UupZ00Hc5M-GPrn}aq6R(5C%=>L`ToA=cXB9-td|-Z zsK(}9uk37UZsN7Hv^Dei?ae&ie`(vr=eP6t{MJ{SnsyTZj_17;ujRGI@2_5;85B#| z+cL$5_WnF(oo<+23;)C9bYawBtPyX1KrCgtd(I3|dpkN0jhU@r^F^#BXy`3gJp218 zs()4MR32CG^w|^Siv>)P3)qbkBFPl431y&m@B2`oG|X?6t53F~G*eU0-bb-qK{!d* z2_@E%%&?%dEGCTRTCx1N#^g%1zT3hr60lz&(OHlyR=Hq|hH82SY^jQLzEmfbDJ7*g%7~})`017i)H{3k3q(^EF!>7SUrR!!)gzWI;bAaZ=RqI>Uo3@{cp4JT zJ<#kX!s|KwFeC=`_6Hq;Kh##NXUp7TFagno1_^fK1>)HP=)xv^(FBBJYQ&i$f^inT zH-nt>$zfqNjjykeZ)_t0{W3cq{+Z=G!7QBq zG`<}$;HxWIeABNZ=<(f6Bf2h3;+n((Z#YN1EF8WRzPv04^~Rn9f?p(dxKLk=|7 zHGJMTi6t^kfK20DPC=?$!n7m0tvgpTa0jxO_tNOTNCH~l?G#+PYln3y#X0;LOwN;l z3mOQgV;D9ia6{$CXFpD0aBKx%T-K7tH0(YGCQlM4&nrN^zPs~KpU_dWcvGC+m%;d4 z2wj&n&@H54^0JT^*U+a#?MK!ec81(K0l%^m~oL7T-c}HWzkyFDn$9q*c-aE2& ztak*ToKfOvk9?btPs@p}*xo&`!)6P~MeBrN|<`&wylVxt#8>Si4*TwDS`pD$L5bbbKL@C=XoSmO} zf>McRO7DrB9ac|D8qS)f_!^jP+9htF-|)w%gpr}1-TrWq_mftjCm1|k{an^LB{Ts5 Dv!GxA literal 0 HcmV?d00001 diff --git a/com.minres.scviewer.e4.application/icons/signal.png b/com.minres.scviewer.e4.application/icons/signal.png new file mode 100644 index 0000000000000000000000000000000000000000..9c96af95917ea9920a4fe3bca87aee23915c06be GIT binary patch literal 717 zcmV;;0y6!HP)`3o;bUGzb6y048Zv zSad^gZEa<4bN~PV002XBWnpw>WFU8GbZ8()Nlj27Z*CxAAWdOomE>Pr0006gNkl1gh6otR}v$Map*Bd#C;wTQ;nrBEGx>P&{Jw=4*Xi`DVEARkRd5=gGC=yDn z$l2Y|{tg9rNdz>x(i9`zbLZT1&WO{~Qyv~3u+~!7HC@-yG!0Tpgb*mDFvbvuAz>Jj zrYZaT`y3n`uv)FqMNyFFIaO8BGz|bv)8L##2!Yo6$$dN?ljk{QSz@h4TWe|Cmb$KK znuf0H==&b$9L5-`szND+Qi`G|@H`J|EltxZ9{M_-(y1BVQWLZX@=hSsg+qSfA zig5>iTuQVOm0@YELkxRg?iMk7X}5uWD( z5Cj3z_kD~pPk>6PAp=rMfB_su5!2}u0N?i!pW&~a-%O{%IX5u-@Z-lnb$M}hCB)g; z8FzPgY&ILpvK+$XoI`7kF$UlFnayVG?(TAQbVQbAtX3-y4-XL+7Z=aY0e}X?dc9`7 zUbES3u+|Pa*a|kE&q>pi<#Nelv0%Aek|YW9`5b+6a>DKHEwkB-q9}$yZTFAkn8{?q zVzD4i)8QmZ!p_bP`uO;mBuTixzo#gQC%@72Jc1x#GMNxX5lNB|$1!mn{{m}`xW2xo zEKAC=q^c^~wq@(U;~`-f;&~pv?=v2c2YY`4BiQuO6o?xi00000NkvXXu0mjfa>F-E literal 0 HcmV?d00001 diff --git a/com.minres.scviewer.e4.application/icons/stream.png b/com.minres.scviewer.e4.application/icons/stream.png new file mode 100755 index 0000000000000000000000000000000000000000..c32d25c16f8b399f0cf5681651d2871a48207627 GIT binary patch literal 444 zcmV;t0YmF_A89qTKGV%LqLqA&{k|D2>yV7qLmg~*x1@cbjz3zP!z2FhV16<-TNNz zuIz$fLNt0{xWmll%$dUkM1*+|PHJ2ZGvdmC35A3UoF6R(-~DS$BH+@Xy#VYsLyQ>z zxq>v8$ny|FSR~0W2u4ic`k5mcbEIiLksz4Y#KyE{9LLn}_oq&%6$}Oga?Zh83$3-^ zU4V1$eaMkz85m>bTh*c{3ch%tltQ=L4Q7$u>-Ff*JP6K)r(~Ul_41v6uR1rSij#*! zl14&E?hS3Iagod#Oo#p}d7WbijUO{Mqc5?@<$>unxw*22 z?bQuGkPsSMOgEm)qR1=cLLyZOm>T65_V?)|o0p=i_uUiST44Cz-W mqJp!8r`H!$*8T4x&4Leh&Epbde3h>N0000;sim6oT0$&Sj1IZ%>K3QDHZx`2bC^51q5yxU9FY78Dx2n+4xAy>))$Ha) z*AyzdVz3Pf@J{w2G~bEXM-IaKPSE1oJ}lrS8-cQh-N>)<9Q+5sEvXF5PHBBGRdzR! zI&ERn=j?3yyn{`bHTiJX#>sl2*}EfN_94HDE7<#t`wyWXn1CxD#wofHb6>i!l;lC& zCJ2lDXdfQ|p{q0JgWPL@DHI1aHH=cqij_4M>l;3h#}IIz`0`b&k0W`G1JQ#;J zAp+VRSY7wy=OzW>aA0Dk2mToW7PXFSOh1Xtw?imHM!=(J6vX}@3qY*6>+Br#FDFo9q2yff;z3E5qLT7Mnw;4ImpbNgt7`^F z%?#|37@V)8GN3_-qp~Lf($Jb2pincr7hDUt^86i&^gOhEQ*vEMfQs&ET&3rrxZ~c< z2vBNR=P`5WclpzK9Ig%En*S|saI-StvS$`28vA}J3{*UGM_H{04r$p@DH4U2O%>^b zTSbQ8mO{g9OIm@J8&(>;dHZ%|u8zyi)A-L6Xy|gurMaa2Z|@(FWPmT{K*44J0000< KMNUMnLSTYKb~Y^l literal 0 HcmV?d00001 diff --git a/com.minres.scviewer.e4.application/icons/up_blue.png b/com.minres.scviewer.e4.application/icons/up_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..642d2f9caf705e32a165d8ea2f2629c5fd88ad48 GIT binary patch literal 759 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6;>1s;*b z3=DFIK$tP_La7}C17l=nNJL45ua8x7ey(0(N`6wRUPW#JP&EUCO@$SZnVVXYs8Erc zlUHn2VXFjIVFhG^g!Ppaz)DK8ZIvQ?0~DO|i&7O#^-S~(l1A zfjnEKjFOT9D}DX)@^Za$W4-*MbbUihOG|wNBYh(yU7!lx;>x^|#0uTKVr7USFmqf| zi<65o3raHc^AtelCMM;Vme?vOfh>Xph&xL%(-1c06+^uR^q@XSM&D4+Kp$>4P^%3{ z)XKjoGZknv$b36P8?Z_gF{nK@`XI}Z90TzwSQO}0J1!f2c(B=V`5aP@1O~E+r;B5V zg_y3*v zXS;m!BTHsy4zsOiZm=Bg(m#7S$_%zq`wejq^*RHF-zP4cXaRY_@ zkJILF(#c=8uTA0bZ~y%g`)dCmUa;)M@eeQAXMa;y6MmY1e%l&%GnS(b%Vzf97F|;5 zbycKN!mj@J;SZuKeqLW+&tqTrKQ$oy0jt!Z#s449pZ2JKy0!TMo<`{l+h0UlYikGZ zoTeqOY%HwIY;3H|Y|hTj%&uaDKo=-w|c;?q}O4R&Wt@Ziy*Li0ZoF8m7 zNPPKO-@(rO#Ig1E{|svWeVYAHS)l&cpV<%Z9+&5d-}f)^$A_2dhqve7m#C|)KmFlT hicF0D8B^t{Yz+U+O3n&im(v0zMNd~hmvv4FO#qfP8XEur literal 0 HcmV?d00001 diff --git a/com.minres.scviewer.e4.application/icons/zoom.png b/com.minres.scviewer.e4.application/icons/zoom.png new file mode 100644 index 0000000000000000000000000000000000000000..908612e394525fc2e52a7e9b94689c25ce167381 GIT binary patch literal 692 zcmV;l0!#ggP)m+BBgry{~j2fHLegbHP( zrgXNbr0}2;^nywdjLjZe?uxtrd3D(pZH@fFFc0{BW_~jxoO1w7-VX;6vK@ROA$$R6 zEmo;Ht-Mj|>5jUy{bQ^V5@53LRI8AgLpUm|m+15sqcz@QtVSo|oz7ArM8?pIn+>gN z0b=4_b5O|4A*;Q+vc9Vqr~%3V155*NV~@gTz}KSUiKB-uJzjMZ>5%Q#n24H!V{ zTY(LLAE*NAHZ}C#wnj%Bw5OFIkRhkkAW#kDC3j9Wm0YXRaXlyyp>#mVfYG)eC;@ab zDb=T-BCAY4LI(Z@GOTr2V_A{pRwSmz+8Be>CjAw(=gnbVWAeguvZa93JmL(EDxv1m z0OP4q=fpAK1Mq!C2`OkEn37o;m#wF#(t(8Pu#S?2f#x<~4EO{@fmm`p9veD6RZ_jp z@Au4};q&`XuKEYgIiB4((kgxOs#YdqJw0fY>9^K_agEu5+$#k;w#%I2N>n_?)YIqu z`tq&#_^p?-%K*U0^}|7+9U(&k0?s;=r=uCZ%)H9_edH8wK}gB(nUB1FFk+2Ol%BXV zHoFY`D~2x|2m%7v+TE=2L@ zAc44q=tejYU5HLZGooZ=NXsV%)bU*sTokj@jZSo^9&w{ke7#VNQ*1zG!rIRk_@ zCqOr;g6B6CM1oPv1(~U4k@Gd+5tN0(j@GA*K*busv3Lb0UyXuowiRkTRZ#85JN!eC z_8ZVW>+upx5C#N|BTv2dK_EW@%(@F6yu1sZv>T3gm&*mIkvej1R4=RyYw#mS zx}c)#2z<)=VQ1|=ux>5PwjVE+J!Q84EQyG-j9SFYV*6AQj$Gb(7!KJE!k5iQ@O3K$ z@0NQZ)>b7&TaFd~Ciolk*Q(7cL+9cB`Y;G@rr`tk5Hdjv+))zSdlF#gI!>6`zB<@i zaKYP!9!Pl&5VMjydlq1x&}37{RQY+SSBXX-w?kCLKK%bXFYU6{?d+nH00000NkvXX Hu0mjfTSP*+ literal 0 HcmV?d00001 diff --git a/com.minres.scviewer.e4.application/icons/zoom_out.png b/com.minres.scviewer.e4.application/icons/zoom_out.png new file mode 100644 index 0000000000000000000000000000000000000000..07bf98a79cfea526e250703356dbefdb6b80d166 GIT binary patch literal 708 zcmV;#0z3VQP)TNkCP1&*^7LC~A?iZQEu_hKZoQoXI zA7tfTv}|~Fb8b^XuP>qvDk=)P)vYKtT12;}bKn-mwHWl`1Bb)&{XXC4IY$Nnvj5@N zfekg1Y}gcI!)Cq|u?lR+A{2&=d~S$}&0ei1|7pO6jkZ$6%&{R8TNpk>=dV#j&aWqO zgE~4pNU_-giktFkY-J5_XDlv`7+j?n3mXtxgadILp+c<9cr~t!x1LM6m69Z~V#pLL z22Cs~BoIdtZHTjo7Q|_U0a2OmSF=gCGFB$RVZIP(pixmBqE!^15yd!#9Z{Wh)zB%o zikBFa!WJPvMB(noe(U;k1e~Y|r$}@wh*Ymykd6>E3t69z5DT&Jq-fSG-dPdU{SG;i zbSb3<`RfKgJD|lQC`6(Cdut1PbDV&$M=Y?U)x)A(0iQN+gAeOBg2Z6fr$_Is!%M70 z=n*z7{*s%3rO7yazIO)}qa&~o@WZ=R>!b#mOSR zlCR8M*iRy2j7!PmWiiegA>Og~W1?FLk0*NI^}`$RW + + + + + + + + + + + + diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/E4LifeCycle.java b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/E4LifeCycle.java new file mode 100644 index 0000000..36b07fa --- /dev/null +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/E4LifeCycle.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2014 TwelveTone LLC and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Steven Spungin - initial API and implementation + *******************************************************************************/ +package com.minres.scviewer.e4.application; + +import org.eclipse.e4.core.contexts.IEclipseContext; +import org.eclipse.e4.ui.workbench.lifecycle.PostContextCreate; +import org.eclipse.e4.ui.workbench.lifecycle.PreSave; +import org.eclipse.e4.ui.workbench.lifecycle.ProcessAdditions; +import org.eclipse.e4.ui.workbench.lifecycle.ProcessRemovals; + +/** + * This is a stub implementation containing e4 LifeCycle annotated methods.
+ * There is a corresponding entry in plugin.xml (under the + * org.eclipse.core.runtime.products' extension point) that references + * this class. + **/ +@SuppressWarnings("restriction") +public class E4LifeCycle { + + @PostContextCreate + void postContextCreate(IEclipseContext workbenchContext) { + } + + @PreSave + void preSave(IEclipseContext workbenchContext) { + } + + @ProcessAdditions + void processAdditions(IEclipseContext workbenchContext) { + } + + @ProcessRemovals + void processRemovals(IEclipseContext workbenchContext) { + } +} diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/AboutHandler.java b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/AboutHandler.java new file mode 100644 index 0000000..4404732 --- /dev/null +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/AboutHandler.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2010 - 2013 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Lars Vogel - Bug 419770 + *******************************************************************************/ +package com.minres.scviewer.e4.application.handlers; + +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.swt.widgets.Shell; + +public class AboutHandler { + @Execute + public void execute(Shell shell) { + MessageDialog.openInformation(shell, "About", "Eclipse 4 Application example."); + } +} diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/DeleteWaveformHandler.java b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/DeleteWaveformHandler.java new file mode 100644 index 0000000..ec88eed --- /dev/null +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/DeleteWaveformHandler.java @@ -0,0 +1,29 @@ + +package com.minres.scviewer.e4.application.handlers; + +import org.eclipse.e4.core.di.annotations.CanExecute; +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.e4.ui.model.application.ui.basic.MPart; +import org.eclipse.e4.ui.workbench.modeling.ESelectionService; + +import com.minres.scviewer.database.IWaveform; +import com.minres.scviewer.e4.application.parts.WaveformViewerPart; + +public class DeleteWaveformHandler { + + @CanExecute + public Boolean canExecute(ESelectionService selectionService){ + Object o = selectionService.getSelection(); + return o instanceof IWaveform; + } + + @Execute + public void execute(ESelectionService selectionService, MPart activePart) { + Object o = activePart.getObject(); + Object sel = selectionService.getSelection(); + if(o instanceof WaveformViewerPart && sel instanceof IWaveform){ + ((WaveformViewerPart)o).removeStreamFromList((IWaveform) sel); + } + } + +} \ No newline at end of file diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/MoveWaveformHandler.java b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/MoveWaveformHandler.java new file mode 100644 index 0000000..67ba167 --- /dev/null +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/MoveWaveformHandler.java @@ -0,0 +1,38 @@ + +package com.minres.scviewer.e4.application.handlers; + +import javax.inject.Named; + +import org.eclipse.e4.core.di.annotations.CanExecute; +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.e4.ui.model.application.ui.basic.MPart; +import org.eclipse.e4.ui.workbench.modeling.EPartService; +import org.eclipse.e4.ui.workbench.modeling.ESelectionService; + +import com.minres.scviewer.database.ITx; +import com.minres.scviewer.database.IWaveform; +import com.minres.scviewer.e4.application.parts.WaveformViewerPart; + +public class MoveWaveformHandler { + + static final String PARAMETER_ID="com.minres.scviewer.e4.application.command.movewaveformupCommand.parameter.dir"; + + @CanExecute + public Boolean canExecute(ESelectionService selectionService){ + Object o = selectionService.getSelection(); + return o instanceof IWaveform || o instanceof ITx; + } + + @Execute + public void execute(@Named(PARAMETER_ID) String param, EPartService partService) { + MPart part = partService.getActivePart(); + Object obj = part.getObject(); + if(obj instanceof WaveformViewerPart){ + if("up".equalsIgnoreCase(param)) + ((WaveformViewerPart)obj).moveSelected(-1); + else if("down".equalsIgnoreCase(param)) + ((WaveformViewerPart)obj).moveSelected(1); + } + } + +} \ No newline at end of file diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/NavigateEvent.java b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/NavigateEvent.java new file mode 100644 index 0000000..579dfe5 --- /dev/null +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/NavigateEvent.java @@ -0,0 +1,40 @@ + +package com.minres.scviewer.e4.application.handlers; + +import javax.inject.Named; + +import org.eclipse.e4.core.di.annotations.CanExecute; +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.e4.ui.model.application.ui.basic.MPart; +import org.eclipse.e4.ui.workbench.modeling.EPartService; +import org.eclipse.e4.ui.workbench.modeling.ESelectionService; + +import com.minres.scviewer.database.ITx; +import com.minres.scviewer.database.IWaveform; +import com.minres.scviewer.database.swt.GotoDirection; +import com.minres.scviewer.e4.application.parts.WaveformViewerPart; + +public class NavigateEvent { + + final static String PARAMTER_ID="com.minres.scviewer.e4.application.command.navigateEventCommand.parameter.dir"; + + @CanExecute + public Boolean canExecute(ESelectionService selectionService){ + Object o = selectionService.getSelection(); + return o instanceof IWaveform || o instanceof ITx; + } + + @Execute + public void execute(@Named(PARAMTER_ID) String param, EPartService partService) { +// public void execute(EPartService partService) { +// String param="next"; + MPart part = partService.getActivePart(); + Object obj = part.getObject(); + if(obj instanceof WaveformViewerPart){ + if("next".equalsIgnoreCase(param)) + ((WaveformViewerPart)obj).moveCursor(GotoDirection.NEXT); + else if("prev".equalsIgnoreCase(param)) + ((WaveformViewerPart)obj).moveCursor(GotoDirection.PREV); + } + } +} \ No newline at end of file diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/NavigateTrans.java b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/NavigateTrans.java new file mode 100644 index 0000000..5d1bc0c --- /dev/null +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/NavigateTrans.java @@ -0,0 +1,37 @@ + +package com.minres.scviewer.e4.application.handlers; + +import javax.inject.Named; + +import org.eclipse.e4.core.di.annotations.CanExecute; +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.e4.ui.model.application.ui.basic.MPart; +import org.eclipse.e4.ui.workbench.modeling.EPartService; +import org.eclipse.e4.ui.workbench.modeling.ESelectionService; + +import com.minres.scviewer.database.ITx; +import com.minres.scviewer.database.swt.GotoDirection; +import com.minres.scviewer.e4.application.parts.WaveformViewerPart; + +public class NavigateTrans { + + final static String PARAMTER_ID="com.minres.scviewer.e4.application.command.navigateTransCommand.parameter.dir"; + + @CanExecute + public Boolean canExecute(ESelectionService selectionService){ + Object o = selectionService.getSelection(); + return o instanceof ITx; + } + + @Execute + public void execute(@Named(PARAMTER_ID) String param, EPartService partService) { + MPart part = partService.getActivePart(); + Object obj = part.getObject(); + if(obj instanceof WaveformViewerPart){ + if("next".equalsIgnoreCase(param)) + ((WaveformViewerPart)obj).moveSelection(GotoDirection.NEXT); + else if("prev".equalsIgnoreCase(param)) + ((WaveformViewerPart)obj).moveSelection(GotoDirection.PREV); + } + } +} \ No newline at end of file diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/OpenHandler.java b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/OpenHandler.java new file mode 100644 index 0000000..95c3362 --- /dev/null +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/OpenHandler.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2010 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Lars Vogel - Bug 419770 + *******************************************************************************/ +package com.minres.scviewer.e4.application.handlers; + +import java.io.File; + +import org.eclipse.e4.core.contexts.IEclipseContext; +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.e4.ui.model.application.MApplication; +import org.eclipse.e4.ui.model.application.ui.basic.MPart; +import org.eclipse.e4.ui.model.application.ui.basic.MPartStack; +import org.eclipse.e4.ui.workbench.modeling.EModelService; +import org.eclipse.e4.ui.workbench.modeling.EPartService; +import org.eclipse.e4.ui.workbench.modeling.EPartService.PartState; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.FileDialog; +import org.eclipse.swt.widgets.Shell; +public class OpenHandler { + + @Execute + public void execute(Shell shell, MApplication app, EModelService modelService, EPartService partService){ + FileDialog dialog = new FileDialog(shell, SWT.MULTI); + dialog.setFilterExtensions (new String []{"vcd", "txdb", "txlog"}); + dialog.open(); + String path = dialog.getFilterPath(); + for(String fileName: dialog.getFileNames()){ + File file = new File(path+File.separator+fileName); + if(file.exists()){ +// MPart part = MBasicFactory.INSTANCE.createPart(); +// part.setLabel(fileName); +// part.setContributionURI("bundleclass://com.minres.scviewer.e4.application/"+ +// WaveformViewerPart.class.getName()); + MPart part = partService .createPart("com.minres.scviewer.e4.application.partdescriptor.waveformviewer"); + part.setLabel(fileName); + + + MPartStack partStack = (MPartStack)modelService.find("org.eclipse.editorss", app); + partStack.getChildren().add(part); + partService.showPart(part, PartState.ACTIVATE); +// Object o = part.getObject(); +// if(o instanceof WaveformViewerPart) +// ((WaveformViewerPart)o).setPartInput(file); + IEclipseContext ctx=part.getContext(); + ctx.modify("input", file); + ctx.declareModifiable("input"); + + + } + } + } + +} diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/QuitHandler.java b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/QuitHandler.java new file mode 100644 index 0000000..55b7296 --- /dev/null +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/QuitHandler.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2010 - 2013 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Lars Vogel - Bug 419770 + *******************************************************************************/ +package com.minres.scviewer.e4.application.handlers; + +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.e4.ui.workbench.IWorkbench; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.swt.widgets.Shell; + + +public class QuitHandler { + @Execute + public void execute(IWorkbench workbench, Shell shell){ + if (MessageDialog.openConfirm(shell, "Confirmation", + "Do you want to exit?")) { + workbench.close(); + } + } +} diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/SaveHandler.java b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/SaveHandler.java new file mode 100644 index 0000000..fb51ee4 --- /dev/null +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/SaveHandler.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2010 - 2013 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Lars Vogel - Bug 419770 + *******************************************************************************/ +package com.minres.scviewer.e4.application.handlers; + +import org.eclipse.e4.core.di.annotations.CanExecute; +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.e4.ui.workbench.modeling.EPartService; + +public class SaveHandler { + + @CanExecute + public boolean canExecute(EPartService partService) { + if (partService != null) { + return !partService.getDirtyParts().isEmpty(); + } + return false; + } + + @Execute + public void execute(EPartService partService) { + partService.saveAll(false); + } +} \ No newline at end of file diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/SelectAllHandler.java b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/SelectAllHandler.java new file mode 100644 index 0000000..78043d7 --- /dev/null +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/SelectAllHandler.java @@ -0,0 +1,13 @@ + +package com.minres.scviewer.e4.application.handlers; + +import org.eclipse.e4.core.di.annotations.Execute; + +public class SelectAllHandler { + + @Execute + public void execute() { + + } + +} \ No newline at end of file diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/ZoomHandler.java b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/ZoomHandler.java new file mode 100644 index 0000000..2b98314 --- /dev/null +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/handlers/ZoomHandler.java @@ -0,0 +1,40 @@ + +package com.minres.scviewer.e4.application.handlers; + +import javax.inject.Named; + +import org.eclipse.e4.core.di.annotations.CanExecute; +import org.eclipse.e4.core.di.annotations.Execute; +import org.eclipse.e4.ui.model.application.ui.basic.MPart; +import org.eclipse.e4.ui.workbench.modeling.EPartService; + +import com.minres.scviewer.e4.application.parts.WaveformViewerPart; + +public class ZoomHandler { + + final static String PARAMTER_ID="com.minres.scviewer.e4.application.command.zoomcommand.parameter.level"; + + @CanExecute + public boolean canExecute(EPartService partService) { + return true; + } + + @Execute + public void execute(@Named(PARAMTER_ID) String level, EPartService partService) { + MPart part = partService.getActivePart(); + Object obj = part.getObject(); + if(obj instanceof WaveformViewerPart){ + WaveformViewerPart waveformViewerPart = (WaveformViewerPart) obj; + int zoomLevel = waveformViewerPart.getZoomLevel(); + if("in".equalsIgnoreCase(level)) + waveformViewerPart.setZoomLevel(zoomLevel-1); + else if("out".equalsIgnoreCase(level)) + waveformViewerPart.setZoomLevel(zoomLevel+1); + else if("fit".equalsIgnoreCase(level)) + waveformViewerPart.setZoomFit(); + } + + } + + +} \ No newline at end of file diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/internal/HeapStatus.java b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/internal/HeapStatus.java new file mode 100644 index 0000000..580c7f8 --- /dev/null +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/internal/HeapStatus.java @@ -0,0 +1,607 @@ +package com.minres.scviewer.e4.application.internal; +import java.lang.reflect.Method; + +import org.eclipse.core.runtime.preferences.IEclipsePreferences; +import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener; +import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent; +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.action.IMenuListener; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Canvas; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.wb.swt.ResourceManager; + +/** + * The Heap Status control, which shows the heap usage statistics in the window trim. + * + * @since 3.1 + */ +public class HeapStatus extends Composite { + + private boolean armed; + private Image gcImage; + private Image disabledGcImage; + private Color bgCol, usedMemCol, lowMemCol, freeMemCol, topLeftCol, bottomRightCol, sepCol, textCol, markCol, armCol; + private Canvas button; + private IEclipsePreferences prefStore; + private int updateInterval; + private boolean showMax; + private long totalMem; + private long prevTotalMem = -1L; + private long prevUsedMem = -1L; + private boolean hasChanged; + private long usedMem; + private long mark = -1; + // start with 12x12 + private Rectangle imgBounds = new Rectangle(0,0,12,12); + private long maxMem = Long.MAX_VALUE; + private boolean maxMemKnown; + private float lowMemThreshold = 0.05f; + private boolean showLowMemThreshold = true; + private boolean updateTooltip = false; + + protected volatile boolean isInGC = false; + + private final Runnable timer = new Runnable() { + @Override + public void run() { + if (!isDisposed()) { + updateStats(); + if (hasChanged) { + if (updateTooltip) { + updateToolTip(); + } + redraw(); + hasChanged = false; + } + getDisplay().timerExec(updateInterval, this); + } + } + }; + + private final IPreferenceChangeListener prefListener = new IPreferenceChangeListener() { + @Override + public void preferenceChange(PreferenceChangeEvent event) { + if (IHeapStatusConstants.PREF_UPDATE_INTERVAL.equals(event.getKey())) { + setUpdateIntervalInMS(prefStore.getInt(IHeapStatusConstants.PREF_UPDATE_INTERVAL, 100)); + } + else if (IHeapStatusConstants.PREF_SHOW_MAX.equals(event.getKey())) { + showMax = prefStore.getBoolean(IHeapStatusConstants.PREF_SHOW_MAX, true); + } + + } + }; + + /** + * Creates a new heap status control with the given parent, and using + * the given preference store to obtain settings such as the refresh + * interval. + * + * @param parent the parent composite + * @param preferences the preference store + */ + public HeapStatus(Composite parent, IEclipsePreferences preferences) { + super(parent, SWT.NONE); + + maxMem = getMaxMem(); + maxMemKnown = maxMem != Long.MAX_VALUE; + + this.prefStore = preferences; + preferences.addPreferenceChangeListener(prefListener); + + setUpdateIntervalInMS(preferences.getInt(IHeapStatusConstants.PREF_UPDATE_INTERVAL, 100)); + showMax = preferences.getBoolean(IHeapStatusConstants.PREF_SHOW_MAX, true); + + button = new Canvas(this, SWT.NONE); + button.setToolTipText("Run Garbage Collection"); + + ImageDescriptor imageDesc = ResourceManager.getPluginImageDescriptor("com.minres.scviewer.e4.application", "icons/trash.png"); //$NON-NLS-1$ + Display display = getDisplay(); + gcImage = imageDesc.createImage(); + if (gcImage != null) { + imgBounds = gcImage.getBounds(); + disabledGcImage = new Image(display, gcImage, SWT.IMAGE_DISABLE); + } + usedMemCol = display.getSystemColor(SWT.COLOR_INFO_BACKGROUND); + lowMemCol = new Color(display, 255, 70, 70); // medium red + freeMemCol = new Color(display, 255, 190, 125); // light orange + bgCol = display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND); + sepCol = topLeftCol = armCol = display.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW); + bottomRightCol = display.getSystemColor(SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW); + markCol = textCol = display.getSystemColor(SWT.COLOR_INFO_FOREGROUND); + + createContextMenu(); + + Listener listener = new Listener() { + + @Override + public void handleEvent(Event event) { + switch (event.type) { + case SWT.Dispose: + doDispose(); + break; + case SWT.Resize: + Rectangle rect = getClientArea(); + button.setBounds(rect.width - imgBounds.width - 1, 1, imgBounds.width, rect.height - 2); + break; + case SWT.Paint: + if (event.widget == HeapStatus.this) { + paintComposite(event.gc); + } + else if (event.widget == button) { + paintButton(event.gc); + } + break; + case SWT.MouseUp: + if (event.button == 1) { + if (!isInGC) { + arm(false); + gc(); + } + } + break; + case SWT.MouseDown: + if (event.button == 1) { + if (event.widget == HeapStatus.this) { + setMark(); + } else if (event.widget == button) { + if (!isInGC) + arm(true); + } + } + break; + case SWT.MouseEnter: + HeapStatus.this.updateTooltip = true; + updateToolTip(); + break; + case SWT.MouseExit: + if (event.widget == HeapStatus.this) { + HeapStatus.this.updateTooltip = false; + } else if (event.widget == button) { + arm(false); + } + break; + } + } + + }; + addListener(SWT.Dispose, listener); + addListener(SWT.MouseDown, listener); + addListener(SWT.Paint, listener); + addListener(SWT.Resize, listener); + addListener(SWT.MouseEnter, listener); + addListener(SWT.MouseExit, listener); + button.addListener(SWT.MouseDown, listener); + button.addListener(SWT.MouseExit, listener); + button.addListener(SWT.MouseUp, listener); + button.addListener(SWT.Paint, listener); + + // make sure stats are updated before first paint + updateStats(); + + getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + if (!isDisposed()) { + getDisplay().timerExec(updateInterval, timer); + } + } + }); + } + + @Override + public void setBackground(Color color) { + bgCol = color; + button.redraw(); + button.update(); + } + + @Override + public void setForeground(Color color) { + if (color == null) { + usedMemCol = getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND); + } else { + usedMemCol = color; + } + + button.redraw(); + button.update(); + } + + @Override + public Color getForeground() { + if (usedMemCol != null) { + return usedMemCol; + } + return getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND); + } + + /** + * Returns the maximum memory limit, or Long.MAX_VALUE if the max is not known. + */ + private long getMaxMem() { + long max = Long.MAX_VALUE; + try { + // Must use reflect to allow compilation against JCL/Foundation + Method maxMemMethod = Runtime.class.getMethod("maxMemory", new Class[0]); //$NON-NLS-1$ + Object o = maxMemMethod.invoke(Runtime.getRuntime(), new Object[0]); + if (o instanceof Long) { + max = ((Long) o).longValue(); + } + } + catch (Exception e) { + // ignore if method missing or if there are other failures trying to determine the max + } + return max; + } + + private void setUpdateIntervalInMS(int interval) { + updateInterval = Math.max(100, interval); + } + + private void doDispose() { + prefStore.removePreferenceChangeListener(prefListener); + if (gcImage != null) { + gcImage.dispose(); + } + if (disabledGcImage != null) { + disabledGcImage.dispose(); + } + + if (lowMemCol != null) { + lowMemCol.dispose(); + } + if (freeMemCol != null) { + freeMemCol.dispose(); + } + } + + @Override + public Point computeSize(int wHint, int hHint, boolean changed) { + GC gc = new GC(this); + Point p = gc.textExtent("MMMMMMMMMMMM"); + int height = imgBounds.height; + // choose the largest of + // - Text height + margins + // - Image height + margins + // - Default Trim heightin + height = Math.max(height, p.y) + 4; + height = Math.max(TrimUtil.TRIM_DEFAULT_HEIGHT, height); + gc.dispose(); + return new Point(p.x + 15, height); + } + + private void arm(boolean armed) { + if (this.armed == armed) { + return; + } + this.armed = armed; + button.redraw(); + button.update(); + } + + private void gcRunning(boolean isInGC) { + if (this.isInGC == isInGC) { + return; + } + this.isInGC = isInGC; + button.redraw(); + button.update(); + } + + /** + * Creates the context menu + */ + private void createContextMenu() { + MenuManager menuMgr = new MenuManager(); + menuMgr.setRemoveAllWhenShown(true); + menuMgr.addMenuListener(new IMenuListener() { + @Override + public void menuAboutToShow(IMenuManager menuMgr) { + fillMenu(menuMgr); + } + }); + Menu menu = menuMgr.createContextMenu(this); + setMenu(menu); + } + + private void fillMenu(IMenuManager menuMgr) { + menuMgr.add(new SetMarkAction()); + menuMgr.add(new ClearMarkAction()); + menuMgr.add(new ShowMaxAction()); + menuMgr.add(new CloseHeapStatusAction()); +// if (isKyrsoftViewAvailable()) { +// menuMgr.add(new ShowKyrsoftViewAction()); +// } + } + + /** + * Sets the mark to the current usedMem level. + */ + private void setMark() { + updateStats(); // get up-to-date stats before taking the mark + mark = usedMem; + hasChanged = true; + redraw(); + } + + /** + * Clears the mark. + */ + private void clearMark() { + mark = -1; + hasChanged = true; + redraw(); + } + + private void gc() { + gcRunning(true); + Thread t = new Thread() { + @Override + public void run() { + busyGC(); + getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + if (!isDisposed()) { + gcRunning(false); + } + } + }); + } + }; + t.start(); + } + + private void busyGC() { + for (int i = 0; i < 2; ++i) { + System.gc(); + System.runFinalization(); + } + } + + private void paintButton(GC gc) { + Rectangle rect = button.getClientArea(); + if (isInGC) { + if (disabledGcImage != null) { + int buttonY = (rect.height - imgBounds.height) / 2 + rect.y; + gc.drawImage(disabledGcImage, rect.x, buttonY); + } + return; + } + if (armed) { + gc.setBackground(armCol); + gc.fillRectangle(rect.x, rect.y, rect.width, rect.height); + } + if (gcImage != null) { + int by = (rect.height - imgBounds.height) / 2 + rect.y; // button y + gc.drawImage(gcImage, rect.x, by); + } + } + + private void paintComposite(GC gc) { + if (showMax && maxMemKnown) { + paintCompositeMaxKnown(gc); + } else { + paintCompositeMaxUnknown(gc); + } + } + + private void paintCompositeMaxUnknown(GC gc) { + Rectangle rect = getClientArea(); + int x = rect.x; + int y = rect.y; + int w = rect.width; + int h = rect.height; + int bw = imgBounds.width; // button width + int dx = x + w - bw - 2; // divider x + int sw = w - bw - 3; // status width + int uw = (int) (sw * usedMem / totalMem); // used mem width + int ux = x + 1 + uw; // used mem right edge + if (bgCol != null) { + gc.setBackground(bgCol); + } + gc.fillRectangle(rect); + gc.setForeground(sepCol); + gc.drawLine(dx, y, dx, y + h); + gc.drawLine(ux, y, ux, y + h); + gc.setForeground(topLeftCol); + gc.drawLine(x, y, x+w, y); + gc.drawLine(x, y, x, y+h); + gc.setForeground(bottomRightCol); + gc.drawLine(x+w-1, y, x+w-1, y+h); + gc.drawLine(x, y+h-1, x+w, y+h-1); + + gc.setBackground(usedMemCol); + gc.fillRectangle(x + 1, y + 1, uw, h - 2); + + String s = convertToMegString(usedMem)+" of "+ convertToMegString(totalMem); + Point p = gc.textExtent(s); + int sx = (rect.width - 15 - p.x) / 2 + rect.x + 1; + int sy = (rect.height - 2 - p.y) / 2 + rect.y + 1; + gc.setForeground(textCol); + gc.drawString(s, sx, sy, true); + + // draw an I-shaped bar in the foreground colour for the mark (if present) + if (mark != -1) { + int ssx = (int) (sw * mark / totalMem) + x + 1; + paintMark(gc, ssx, y, h); + } + } + + private void paintCompositeMaxKnown(GC gc) { + Rectangle rect = getClientArea(); + int x = rect.x; + int y = rect.y; + int w = rect.width; + int h = rect.height; + int bw = imgBounds.width; // button width + int dx = x + w - bw - 2; // divider x + int sw = w - bw - 3; // status width + int uw = (int) (sw * usedMem / maxMem); // used mem width + int ux = x + 1 + uw; // used mem right edge + int tw = (int) (sw * totalMem / maxMem); // current total mem width + int tx = x + 1 + tw; // current total mem right edge + + gc.setBackground(bgCol); + gc.fillRectangle(rect); + gc.setForeground(sepCol); + gc.drawLine(dx, y, dx, y + h); + gc.drawLine(ux, y, ux, y + h); + gc.drawLine(tx, y, tx, y + h); + gc.setForeground(topLeftCol); + gc.drawLine(x, y, x+w, y); + gc.drawLine(x, y, x, y+h); + gc.setForeground(bottomRightCol); + gc.drawLine(x+w-1, y, x+w-1, y+h); + gc.drawLine(x, y+h-1, x+w, y+h-1); + + if (lowMemThreshold != 0 && ((double)(maxMem - usedMem) / (double)maxMem < lowMemThreshold)) { + gc.setBackground(lowMemCol); + } else { + gc.setBackground(usedMemCol); + } + gc.fillRectangle(x + 1, y + 1, uw, h - 2); + + gc.setBackground(freeMemCol); + gc.fillRectangle(ux + 1, y + 1, tx - (ux + 1), h - 2); + + // paint line for low memory threshold + if (showLowMemThreshold && lowMemThreshold != 0) { + gc.setForeground(lowMemCol); + int thresholdX = x + 1 + (int) (sw * (1.0 - lowMemThreshold)); + gc.drawLine(thresholdX, y + 1, thresholdX, y + h - 2); + } + + String s = convertToMegString(usedMem)+" of "+convertToMegString(totalMem); + Point p = gc.textExtent(s); + int sx = (rect.width - 15 - p.x) / 2 + rect.x + 1; + int sy = (rect.height - 2 - p.y) / 2 + rect.y + 1; + gc.setForeground(textCol); + gc.drawString(s, sx, sy, true); + + // draw an I-shaped bar in the foreground colour for the mark (if present) + if (mark != -1) { + int ssx = (int) (sw * mark / maxMem) + x + 1; + paintMark(gc, ssx, y, h); + } + } + + private void paintMark(GC gc, int x, int y, int h) { + gc.setForeground(markCol); + gc.drawLine(x, y+1, x, y+h-2); + gc.drawLine(x-1, y+1, x+1, y+1); + gc.drawLine(x-1, y+h-2, x+1, y+h-2); + } + + private void updateStats() { + Runtime runtime = Runtime.getRuntime(); + totalMem = runtime.totalMemory(); + long freeMem = runtime.freeMemory(); + usedMem = totalMem - freeMem; + + if (convertToMeg(prevUsedMem) != convertToMeg(usedMem)) { + prevUsedMem = usedMem; + this.hasChanged = true; + } + + if (prevTotalMem != totalMem) { + prevTotalMem = totalMem; + this.hasChanged = true; + } + } + + private void updateToolTip() { + String usedStr = convertToMegString(usedMem); + String totalStr = convertToMegString(totalMem); + String maxStr = maxMemKnown ? convertToMegString(maxMem) : ""; + String markStr = mark == -1 ? "" : convertToMegString(mark); + String toolTip = "Heap size: "+usedStr+" of total: "+totalStr+" max: "+maxStr+" mark: "+markStr; + if (!toolTip.equals(getToolTipText())) { + setToolTipText(toolTip); + } + } + + /** + * Converts the given number of bytes to a printable number of megabytes (rounded up). + */ + private String convertToMegString(long numBytes) { + return new Long(convertToMeg(numBytes)).toString()+"M"; + } + + /** + * Converts the given number of bytes to the corresponding number of megabytes (rounded up). + */ + private long convertToMeg(long numBytes) { + return (numBytes + (512 * 1024)) / (1024 * 1024); + } + + + class SetMarkAction extends Action { + SetMarkAction() { + super("&Set Mark"); + } + + @Override + public void run() { + setMark(); + } + } + + class ClearMarkAction extends Action { + ClearMarkAction() { + super("&Clear Mark"); + } + + @Override + public void run() { + clearMark(); + } + } + + class ShowMaxAction extends Action { + ShowMaxAction() { + super("Show &Max Heap", IAction.AS_CHECK_BOX); + setEnabled(maxMemKnown); + setChecked(showMax); + } + + @Override + public void run() { + prefStore.putBoolean(IHeapStatusConstants.PREF_SHOW_MAX, isChecked()); + redraw(); + } + } + + class CloseHeapStatusAction extends Action{ + + CloseHeapStatusAction(){ + super("&Close"); + } + + @Override + public void run(){ +// WorkbenchWindow wbw = (WorkbenchWindow) PlatformUI.getWorkbench() +// .getActiveWorkbenchWindow(); +// if (wbw != null) { +// wbw.showHeapStatus(false); +// } + System.out.println("NYI"); + } + } + +} + diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/internal/IHeapStatusConstants.java b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/internal/IHeapStatusConstants.java new file mode 100644 index 0000000..c17c256 --- /dev/null +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/internal/IHeapStatusConstants.java @@ -0,0 +1,19 @@ +package com.minres.scviewer.e4.application.internal; +/** + * Preference constants for the heap status. + * + * @since 3.1 + */ +public interface IHeapStatusConstants { + + /** + * Preference key for the update interval (value in milliseconds). + */ + String PREF_UPDATE_INTERVAL = "HeapStatus.updateInterval"; //$NON-NLS-1$ + + /** + * Preference key for whether to show max heap, if available (value is boolean). + */ + String PREF_SHOW_MAX = "HeapStatus.showMax"; //$NON-NLS-1$ + +} diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/internal/StatusBarControl.java b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/internal/StatusBarControl.java new file mode 100644 index 0000000..c1fedad --- /dev/null +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/internal/StatusBarControl.java @@ -0,0 +1,209 @@ +package com.minres.scviewer.e4.application.internal; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import javax.inject.Inject; + +import org.eclipse.core.internal.preferences.BundleDefaultPreferences; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.jobs.IJobChangeEvent; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.core.runtime.jobs.JobChangeAdapter; +import org.eclipse.core.runtime.jobs.ProgressProvider; +import org.eclipse.core.runtime.preferences.IEclipsePreferences; +import org.eclipse.e4.core.di.annotations.Optional; +import org.eclipse.e4.ui.di.UIEventTopic; +import org.eclipse.e4.ui.di.UISynchronize; +import org.eclipse.e4.ui.model.application.ui.menu.MToolControl; +import org.eclipse.e4.ui.workbench.modeling.EModelService; +import org.eclipse.jface.action.StatusLineManager; +import org.eclipse.swt.widgets.Composite; + +public class StatusBarControl { + + public static final String STATUS_UPDATE="StatusUpdate"; + public static final String ZOOM_LEVEL="ZoomLevelUpdate"; + public static final String CURSOR_TIME="CursorPosUpdate"; + + @Inject EModelService modelService; + @Inject @Optional IEclipsePreferences preferences; + private final UISynchronize sync; + + protected StatusLineManager manager; + + private SyncedProgressMonitor monitor; + + @Inject + public StatusBarControl(UISynchronize sync) { + this.sync=sync; + manager = new StatusLineManager(); + manager.update(true); + } + + @PostConstruct + void createWidget(Composite parent, MToolControl toolControl) { + if (toolControl.getElementId().equals("org.eclipse.ui.StatusLine")) { //$NON-NLS-1$ + createStatusLine(parent, toolControl); + } else if (toolControl.getElementId().equals("org.eclipse.ui.HeapStatus")) { //$NON-NLS-1$ + createHeapStatus(parent, toolControl); + } else if (toolControl.getElementId().equals("org.eclipse.ui.ProgressBar")) { //$NON-NLS-1$ + createProgressBar(parent, toolControl); + } + } + + @PreDestroy + void destroy() { + if (manager != null) { + manager.dispose(); + manager = null; + } + } + + /** + * @param parent + * @param toolControl + */ + private void createProgressBar(Composite parent, MToolControl toolControl) { + manager.createControl(parent); + monitor=new SyncedProgressMonitor(manager.getProgressMonitor()); + Job.getJobManager().setProgressProvider(new ProgressProvider() { + @Override + public IProgressMonitor createMonitor(Job job) { + return monitor.addJob(job); + } + }); + } + + /** + * @param parent + * @param toolControl + */ + private void createHeapStatus(Composite parent, MToolControl toolControl) { + if(preferences==null){ + preferences=new BundleDefaultPreferences(); + preferences.putInt(IHeapStatusConstants.PREF_UPDATE_INTERVAL, 100); + preferences.putBoolean(IHeapStatusConstants.PREF_SHOW_MAX, true); + } + new HeapStatus(parent, preferences); + } + + /** + * @param parent + * @param toolControl + */ + private void createStatusLine(Composite parent, MToolControl toolControl) { + // IEclipseContext context = modelService.getContainingContext(toolControl); + manager.createControl(parent); + } + + @Inject @Optional + public void getStatusEvent(@UIEventTopic(STATUS_UPDATE) String text) { + if(manager!=null ){ + manager.setMessage(text); + } + } + + private final class SyncedProgressMonitor implements IProgressMonitor { + + IProgressMonitor delegate; + private boolean cancelled; + + SyncedProgressMonitor(IProgressMonitor delegate){ + this.delegate=delegate; + } + + public IProgressMonitor addJob(Job job){ + if(job != null){ + job.addJobChangeListener(new JobChangeAdapter() { + @Override + public void done(IJobChangeEvent event) { + // clean-up + event.getJob().removeJobChangeListener(this); + } + }); + } + return this; + } + + @Override + public void beginTask(final String name, final int totalWork) { + sync.syncExec(new Runnable() { + @Override + public void run() { + delegate.beginTask(name, totalWork); + } + }); + } + + @Override + public void worked(final int work) { + sync.syncExec(new Runnable() { + @Override + public void run() { + delegate.worked(work); + } + }); + } + + @Override + public void done() { + sync.syncExec(new Runnable() { + @Override + public void run() { + delegate.done(); + } + }); + } + + @Override + public void internalWorked(final double work) { + sync.syncExec(new Runnable() { + @Override + public void run() { + delegate.internalWorked(work); + } + }); + } + + @Override + public boolean isCanceled() { + sync.syncExec(new Runnable() { + @Override + public void run() { + cancelled=delegate.isCanceled(); + } + }); + return cancelled; + } + + @Override + public void setCanceled(final boolean value) { + sync.syncExec(new Runnable() { + @Override + public void run() { + delegate.setCanceled(value); + } + }); + } + + @Override + public void setTaskName(final String name) { + sync.syncExec(new Runnable() { + @Override + public void run() { + delegate.setTaskName(name); + } + }); + } + + @Override + public void subTask(final String name) { + sync.syncExec(new Runnable() { + @Override + public void run() { + delegate.subTask(name); + } + }); + } + } +} \ No newline at end of file diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/internal/TrimUtil.java b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/internal/TrimUtil.java new file mode 100644 index 0000000..f67ac3b --- /dev/null +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/internal/TrimUtil.java @@ -0,0 +1,42 @@ +package com.minres.scviewer.e4.application.internal; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.ToolBar; +import org.eclipse.swt.widgets.ToolItem; + +/** + * Simple class to provide some common internal Trim support. + * + * @since 3.2 + * + */ +public class TrimUtil { + + /** + * Default height for workbench trim. + */ + public static final int TRIM_DEFAULT_HEIGHT; + static { + Shell s = new Shell(Display.getCurrent(), SWT.NONE); + s.setLayout(new GridLayout()); + ToolBar t = new ToolBar(s, SWT.NONE); + t.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + ToolItem ti = new ToolItem(t, SWT.PUSH); + ti.setImage(JFaceResources.getImageRegistry().get(Dialog.DLG_IMG_MESSAGE_INFO)); + s.layout(); + int toolItemHeight = t.computeSize(SWT.DEFAULT, SWT.DEFAULT).y; + GC gc = new GC(s); + Point fontSize = gc.textExtent("Wg"); //$NON-NLS-1$ + gc.dispose(); + TRIM_DEFAULT_HEIGHT = Math.max(toolItemHeight, fontSize.y); + s.dispose(); + + } +} diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/internal/WaveStatusBarControl.java b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/internal/WaveStatusBarControl.java new file mode 100644 index 0000000..b83196f --- /dev/null +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/internal/WaveStatusBarControl.java @@ -0,0 +1,100 @@ +package com.minres.scviewer.e4.application.internal; + +import java.util.List; + +import javax.inject.Inject; +import javax.inject.Named; + +import org.eclipse.e4.core.di.annotations.Optional; +import org.eclipse.e4.ui.di.UIEventTopic; +import org.eclipse.e4.ui.di.UISynchronize; +import org.eclipse.e4.ui.services.IServiceConstants; +import org.eclipse.e4.ui.workbench.modeling.EModelService; +import org.eclipse.jface.action.ContributionItem; +import org.eclipse.jface.action.StatusLineManager; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.CLabel; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; + +public class WaveStatusBarControl extends StatusBarControl { + + public static final String STATUS_UPDATE="StatusUpdate"; + public static final String ZOOM_LEVEL="ZoomLevelUpdate"; + public static final String CURSOR_TIME="CursorPosUpdate"; + + @Inject + EModelService modelService; + + class TextContributionItem extends ContributionItem { + + final String labelString; + final int width; + CLabel label, text; + private String content; + + public TextContributionItem(String labelString, int width) { + super(); + this.labelString = labelString; + this.width=width; + content=""; + } + + @Override + public void fill(Composite parent) { + Composite box=new Composite(parent, SWT.NONE); + box.setLayout(new GridLayout(2, false)); + label=new CLabel(box, SWT.SHADOW_NONE); + label.setText(labelString); + text=new CLabel(box, SWT.SHADOW_IN); + GridData layoutData=new GridData(SWT.DEFAULT, SWT.DEFAULT, true, false); + layoutData.minimumWidth=width; + text.setLayoutData(layoutData); + } + + @Override + public boolean isDynamic() { + return true; + } + + public void setText(String message){ + this.content=message; + if(text!=null && !text.isDisposed()) text.setText(content); + } + + } + + TextContributionItem zoomContribution, cursorContribution; + + @Inject + public WaveStatusBarControl(UISynchronize sync) { + super(sync); + zoomContribution = new TextContributionItem("Z:", 150); + cursorContribution = new TextContributionItem("C:", 120); + manager.appendToGroup(StatusLineManager.BEGIN_GROUP,cursorContribution); + manager.appendToGroup(StatusLineManager.MIDDLE_GROUP, zoomContribution); + } + + @Inject + public void setSelection(@Named(IServiceConstants.ACTIVE_SELECTION)@Optional Object obj){ + // if(status!=null ) status.setText(obj==null?"":obj.toString()); + if(manager!=null ){ + if(obj instanceof List){ + manager.setMessage(""+((List)obj).size()+" Elements"); + } else + manager.setMessage(obj==null?"":obj.getClass().getSimpleName()+" selected"); + } + } + + @Inject @Optional + public void getZoomEvent(@UIEventTopic(ZOOM_LEVEL) String text) { + zoomContribution.setText(text); + } + + @Inject @Optional + public void getCursorEvent(@UIEventTopic(CURSOR_TIME) String text) { + cursorContribution.setText(text); + } + +} \ No newline at end of file diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/DesignBrowser.java b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/DesignBrowser.java new file mode 100644 index 0000000..dad8f31 --- /dev/null +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/DesignBrowser.java @@ -0,0 +1,108 @@ +package com.minres.scviewer.e4.application.parts; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.Arrays; +import java.util.List; + +import javax.annotation.PostConstruct; +import javax.inject.Inject; + +import org.eclipse.e4.core.di.annotations.Optional; +import org.eclipse.e4.core.services.events.IEventBroker; +import org.eclipse.e4.ui.di.Focus; +import org.eclipse.e4.ui.di.UIEventTopic; +import org.eclipse.e4.ui.workbench.modeling.ESelectionService; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; + +import com.minres.scviewer.database.IWaveformDb; +import com.minres.scviewer.e4.application.provider.TxDbContentProvider; +import com.minres.scviewer.e4.application.provider.TxDbLabelProvider; + +public class DesignBrowser implements ISelectionChangedListener { + + @Inject IEventBroker eventBroker; + + @Inject ESelectionService selectionService; + + private TreeViewer contentOutlineViewer; + + private PropertyChangeListener l = new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + if("CHILDS".equals(evt.getPropertyName())){ + contentOutlineViewer.getTree().getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + contentOutlineViewer.refresh(); + } + }); + } + } + }; + + @PostConstruct + public void createComposite(Composite parent) { + parent.setLayout(new GridLayout(1, false)); + contentOutlineViewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); + contentOutlineViewer.addSelectionChangedListener(this); + contentOutlineViewer.getTree().setLayoutData(new GridData(GridData.FILL_BOTH)); + contentOutlineViewer.setContentProvider(new TxDbContentProvider()); + contentOutlineViewer.setLabelProvider(new TxDbLabelProvider()); + contentOutlineViewer.setUseHashlookup(true); + } + + @Focus + public void setFocus() { + contentOutlineViewer.getTree().setFocus(); + setSelection(contentOutlineViewer.getSelection()); + } + + @Override + public void selectionChanged(SelectionChangedEvent event) { + setSelection(event.getSelection()); + } + + protected void setSelection(ISelection iSelection) { + IStructuredSelection selection = (IStructuredSelection)iSelection; + switch(selection.size()){ + case 0: + eventBroker.post(WaveformViewerPart.ACTIVE_NODE, null); + break; + case 1: + eventBroker.post(WaveformViewerPart.ACTIVE_NODE, selection.getFirstElement()); + selectionService.setSelection(selection.getFirstElement()); + break; + default: + eventBroker.post(WaveformViewerPart.ACTIVE_NODE, selection.getFirstElement()); + selectionService.setSelection(selection.toList()); + break; + } + } + + @SuppressWarnings("unchecked") + @Inject @Optional + public void getStatusEvent(@UIEventTopic(WaveformViewerPart.ACTIVE_DATABASE) IWaveformDb database) { + Object input = contentOutlineViewer.getInput(); + if(input!=null && input instanceof List) + ((List)input).get(0).removePropertyChangeListener(l); + contentOutlineViewer.setInput(Arrays.asList(new IWaveformDb[]{database})); + // Set up the tree viewer + database.addPropertyChangeListener(l); + } +/* + * TODO: needs top be implemented + @Inject @Optional + public void getStatusEvent(@UIEventTopic(WaveformViewerPart.ACTIVE_NODE_PATH) String path) { + + } +*/ +}; \ No newline at end of file diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/TransactionDetails.java b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/TransactionDetails.java new file mode 100644 index 0000000..ccdb2a0 --- /dev/null +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/TransactionDetails.java @@ -0,0 +1,233 @@ +package com.minres.scviewer.e4.application.parts; + +import javax.annotation.PostConstruct; +import javax.inject.Inject; +import javax.inject.Named; + +import org.eclipse.e4.core.di.annotations.Optional; +import org.eclipse.e4.core.services.events.IEventBroker; +import org.eclipse.e4.ui.di.Focus; +import org.eclipse.e4.ui.services.IServiceConstants; +import org.eclipse.e4.ui.workbench.modeling.ESelectionService; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerFilter; +import org.eclipse.jface.viewers.ViewerSorter; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ControlAdapter; +import org.eclipse.swt.events.ControlEvent; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.Text; + +import com.minres.scviewer.database.ITx; +import com.minres.scviewer.database.ITxAttribute; +import com.minres.scviewer.e4.application.provider.TxPropertiesContentProvider; +import com.minres.scviewer.e4.application.provider.TxPropertiesLabelProvider; + +public class TransactionDetails { + + // Column constants + public static final int COLUMN_FIRST = 0; + + public static final int COLUMN_SECOND = 1; + + @Inject IEventBroker eventBroker; + + @Inject ESelectionService selectionService; + + private Text nameFilter; + private TableViewer txTableViewer; + private TableColumn col1, col2; + TxAttributeFilter attributeFilter; + + + @PostConstruct + public void createComposite(final Composite parent) { + parent.setLayout(new GridLayout(1, false)); + + nameFilter = new Text(parent, SWT.BORDER); + nameFilter.setMessage("Enter text to filter"); + nameFilter.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + attributeFilter.setSearchText(((Text) e.widget).getText()); + txTableViewer.refresh(); + } + }); + nameFilter.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + + attributeFilter = new TxAttributeFilter(); + + txTableViewer = new TableViewer(parent); + txTableViewer.setContentProvider(new TxPropertiesContentProvider()); + txTableViewer.setLabelProvider(new TxPropertiesLabelProvider()); + txTableViewer.getTable().setLayoutData(new GridData(GridData.FILL_BOTH)); + txTableViewer.addFilter(attributeFilter); + + // Set up the table + Table table = txTableViewer.getTable(); + table.setLayoutData(new GridData(GridData.FILL_BOTH)); + + // Add the first name column + col1 = new TableColumn(table, SWT.LEFT); + col1.setText("Name"); + col1.setResizable(true); + col1.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent event) { + ((TxAttributeViewerSorter) txTableViewer.getSorter()).doSort(COLUMN_FIRST); + txTableViewer.refresh(); + } + }); + + // Add the last name column + col2 = new TableColumn(table, SWT.LEFT); + col2.setText("Value"); + col2.setResizable(true); + col2.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent event) { + ((TxAttributeViewerSorter) txTableViewer.getSorter()).doSort(COLUMN_SECOND); + txTableViewer.refresh(); + } + }); + + // Pack the columns + for (int i = 0, n = table.getColumnCount(); i < n; i++) { + table.getColumn(i).pack(); + } + + // Turn on the header and the lines + table.setHeaderVisible(true); + table.setLinesVisible(true); + + parent.addControlListener(new ControlAdapter() { + public void controlResized(ControlEvent e) { + Table table = txTableViewer.getTable(); + Rectangle area = parent.getClientArea(); + Point preferredSize = table.computeSize(SWT.DEFAULT, SWT.DEFAULT); + int width = area.width - 2*table.getBorderWidth(); + if (preferredSize.y > area.height + table.getHeaderHeight()) { + // Subtract the scrollbar width from the total column width + // if a vertical scrollbar will be required + Point vBarSize = table.getVerticalBar().getSize(); + width -= vBarSize.x; + } + Point oldSize = table.getSize(); + if (oldSize.x > area.width) { + // table is getting smaller so make the columns + // smaller first and then resize the table to + // match the client area width + col1.setWidth(width/3); + col2.setWidth(width - col1.getWidth()); + table.setSize(area.width, area.height); + } else { + // table is getting bigger so make the table + // bigger first and then make the columns wider + // to match the client area width + table.setSize(area.width, area.height); + col1.setWidth(width/3); + col2.setWidth(width - col1.getWidth()); + } + } + }); + } + + @Focus + public void setFocus() { + txTableViewer.getTable().setFocus(); + } + + @Inject + public void setSelection(@Named(IServiceConstants.ACTIVE_SELECTION) @Optional Object object){ + if(txTableViewer!=null && !txTableViewer.getTable().isDisposed()) + if(object instanceof ITx){ + txTableViewer.setInput(object); + } else { + txTableViewer.setInput(null); + } + } + + class TxAttributeViewerSorter extends ViewerSorter { + private static final int ASCENDING = 0; + + private static final int DESCENDING = 1; + + private int column; + + private int direction; + + /** + * Does the sort. If it's a different column from the previous sort, do an + * ascending sort. If it's the same column as the last sort, toggle the sort + * direction. + * + * @param column + */ + public void doSort(int column) { + if (column == this.column) { + // Same column as last sort; toggle the direction + direction = 1 - direction; + } else { + // New column; do an ascending sort + this.column = column; + direction = ASCENDING; + } + } + + /** + * Compares the object for sorting + */ + @SuppressWarnings("unchecked") + public int compare(Viewer viewer, Object e1, Object e2) { + int rc = 0; + ITxAttribute p1 = (ITxAttribute) e1; + ITxAttribute p2 = (ITxAttribute) e2; + + // Determine which column and do the appropriate sort + switch (column) { + case COLUMN_FIRST: + rc = getComparator().compare(p1.getName(), p2.getName()); + break; + case COLUMN_SECOND: + rc = getComparator().compare(p1.getValue(), p2.getValue()); + break; + } + + // If descending order, flip the direction + if (direction == DESCENDING) + rc = -rc; + + return rc; + } + } + + public class TxAttributeFilter extends ViewerFilter { + + private String searchString; + + public void setSearchText(String s) { + this.searchString = ".*" + s + ".*"; + } + + @Override + public boolean select(Viewer viewer, Object parentElement, Object element) { + if (searchString == null || searchString.length() == 0) { + return true; + } + ITxAttribute p = (ITxAttribute) element; + if (p.getName().matches(searchString)) { + return true; + } + return false; + } + } +} \ No newline at end of file diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/WaveformListPart.java b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/WaveformListPart.java new file mode 100644 index 0000000..0b5abec --- /dev/null +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/WaveformListPart.java @@ -0,0 +1,170 @@ +package com.minres.scviewer.e4.application.parts; + +import javax.annotation.PostConstruct; +import javax.inject.Inject; +import javax.inject.Named; + +import org.eclipse.e4.core.di.annotations.Optional; +import org.eclipse.e4.core.services.events.IEventBroker; +import org.eclipse.e4.ui.di.Focus; +import org.eclipse.e4.ui.di.UIEventTopic; +import org.eclipse.e4.ui.services.IServiceConstants; +import org.eclipse.e4.ui.workbench.modeling.ESelectionService; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerFilter; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Text; +import org.eclipse.swt.widgets.ToolBar; +import org.eclipse.swt.widgets.ToolItem; +import org.eclipse.wb.swt.ResourceManager; + +import com.minres.scviewer.database.ITx; +import com.minres.scviewer.database.IWaveform; +import com.minres.scviewer.e4.application.provider.TxDbContentProvider; +import com.minres.scviewer.e4.application.provider.TxDbLabelProvider; + +public class WaveformListPart implements ISelectionChangedListener { + + @Inject IEventBroker eventBroker; + + @Inject ESelectionService selectionService; + + private Text nameFilter; + private TableViewer txTableViewer; + ToolItem appendItem, insertItem; + WaveformAttributeFilter attributeFilter; + + @PostConstruct + public void createComposite(Composite parent) { + parent.setLayout(new GridLayout(1, false)); + + nameFilter = new Text(parent, SWT.BORDER); + nameFilter.setMessage("Enter text to filter waveforms"); + nameFilter.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + attributeFilter.setSearchText(((Text) e.widget).getText()); + txTableViewer.refresh(); + } + }); + nameFilter.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + + attributeFilter = new WaveformAttributeFilter(); + + txTableViewer = new TableViewer(parent); + txTableViewer.setContentProvider(new TxDbContentProvider()); + txTableViewer.setLabelProvider(new TxDbLabelProvider()); + txTableViewer.getTable().setLayoutData(new GridData(GridData.FILL_BOTH)); + txTableViewer.addSelectionChangedListener(this); + txTableViewer.addFilter(attributeFilter); + + ToolBar toolBar = new ToolBar(parent, SWT.FLAT | SWT.RIGHT); + toolBar.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1)); + toolBar.setBounds(0, 0, 87, 20); + + insertItem = new ToolItem(toolBar, SWT.NONE); + insertItem.setImage(ResourceManager.getPluginImage("com.minres.scviewer.e4.application", "icons/bullet_plus.png")); + insertItem.setText("Insert"); + insertItem.setEnabled(false); + insertItem.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + eventBroker.post(WaveformViewerPart.ADD_WAVEFORM, + ((IStructuredSelection)txTableViewer.getSelection()).toList()); + + } + }); + appendItem = new ToolItem(toolBar, SWT.NONE); + appendItem.setImage(ResourceManager.getPluginImage("com.minres.scviewer.e4.application", "icons/bullet_plus.png")); + appendItem.setText("Append"); + appendItem.setEnabled(false); + appendItem.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + eventBroker.post(WaveformViewerPart.ADD_WAVEFORM, + ((IStructuredSelection)txTableViewer.getSelection()).toList()); + + } + }); + } + + @Focus + public void setFocus() { + txTableViewer.getTable().setFocus(); + setSelection(txTableViewer.getSelection()); + } + + @Inject @Optional + public void getStatusEvent(@UIEventTopic(WaveformViewerPart.ACTIVE_NODE) Object o) { + txTableViewer.setInput(o); + } + + @Override + public void selectionChanged(SelectionChangedEvent event) { + setSelection(event.getSelection()); + } + + protected void setSelection(ISelection iSelection) { + IStructuredSelection selection = (IStructuredSelection)iSelection; + switch(selection.size()){ + case 0: + appendItem.setEnabled(false); + insertItem.setEnabled(false); + break; + case 1: + selectionService.setSelection(selection.getFirstElement()); + appendItem.setEnabled(true); + break; + default: + selectionService.setSelection(selection.toList()); + appendItem.setEnabled(true); + break; + } + } + + @Inject + public void setSelection(@Named(IServiceConstants.ACTIVE_SELECTION) @Optional Object object){ + if(txTableViewer!=null && !insertItem.isDisposed() && !appendItem.isDisposed()) + if(object instanceof ITx && appendItem.isEnabled()){ + insertItem.setEnabled(true); + } else if(object instanceof IWaveform && appendItem.isEnabled()){ + insertItem.setEnabled(true); + } else { + insertItem.setEnabled(false); + } + } + + public class WaveformAttributeFilter extends ViewerFilter { + + private String searchString; + + public void setSearchText(String s) { + this.searchString = ".*" + s + ".*"; + } + + @Override + public boolean select(Viewer viewer, Object parentElement, Object element) { + if (searchString == null || searchString.length() == 0) { + return true; + } + IWaveform p = (IWaveform) element; + if (p.getName().matches(searchString)) { + return true; + } + return false; + } + } + +} \ No newline at end of file diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/WaveformViewerPart.java b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/WaveformViewerPart.java new file mode 100644 index 0000000..ee056a7 --- /dev/null +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/parts/WaveformViewerPart.java @@ -0,0 +1,369 @@ +package com.minres.scviewer.e4.application.parts; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.annotation.PostConstruct; +import javax.inject.Inject; +import javax.inject.Named; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.core.runtime.jobs.IJobChangeEvent; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.core.runtime.jobs.JobChangeAdapter; +import org.eclipse.e4.core.di.annotations.Optional; +import org.eclipse.e4.core.services.events.IEventBroker; +import org.eclipse.e4.ui.di.Focus; +import org.eclipse.e4.ui.di.PersistState; +import org.eclipse.e4.ui.di.UIEventTopic; +import org.eclipse.e4.ui.model.application.ui.basic.MPart; +import org.eclipse.e4.ui.services.EMenuService; +import org.eclipse.e4.ui.workbench.modeling.ESelectionService; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.swt.widgets.Composite; + +import com.minres.scviewer.database.IHierNode; +import com.minres.scviewer.database.ITx; +import com.minres.scviewer.database.IWaveform; +import com.minres.scviewer.database.IWaveformDb; +import com.minres.scviewer.database.IWaveformDbFactory; +import com.minres.scviewer.database.IWaveformEvent; +import com.minres.scviewer.database.swt.GotoDirection; +import com.minres.scviewer.database.swt.TxDisplay; +import com.minres.scviewer.e4.application.internal.StatusBarControl; + +public class WaveformViewerPart { + + public static final String ACTIVE_DATABASE="Active_Database"; + public static final String ACTIVE_NODE="ActiveNode"; + public static final String ACTIVE_NODE_PATH="ActiveNodePath"; + public static final String ADD_WAVEFORM="AddWaveform"; + + protected static final String DATABASE_FILE = "DATABASE_FILE"; + protected static final String SHOWN_WAVEFORM = "SHOWN_WAVEFORM"; + + private final static String[] zoomLevel={ + "1fs", "10fs", "100fs", + "1ps", "10ps", "100ps", + "1ns", "10ns", "100ns", + "1µs", "10µs", "10µs", + "1ms", "10ms", "100ms", "1s"}; + + public static final String ID = "com.minres.scviewer.ui.TxEditorPart"; //$NON-NLS-1$ + + public static final String WAVE_ACTION_ID = "com.minres.scviewer.ui.action.AddToWave"; + + private TxDisplay txDisplay; + + @Inject private IEventBroker eventBroker; + + @Inject EMenuService menuService; + + @Inject ESelectionService selectionService; + + private IWaveformDb database; + + private IHierNode activeNode; + + private Composite myParent; + + ArrayList filesToLoad; + + Map persistedState; + + + @PostConstruct + public void createComposite(MPart part, Composite parent, IWaveformDbFactory dbFactory) { + myParent=parent; + database=dbFactory.getDatabase(); + database.addPropertyChangeListener(new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + if("WAVEFORMS".equals(evt.getPropertyName())) { + myParent.getDisplay().syncExec(new Runnable() { + @Override + public void run() { + txDisplay.setMaxTime(database.getMaxTime()); + } + }); + } + } + }); + txDisplay = new TxDisplay(parent); + txDisplay.setMaxTime(0); + txDisplay.addPropertyChangeListener(TxDisplay.CURSOR_PROPERTY, new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + Long time = (Long) evt.getNewValue(); + eventBroker.post(StatusBarControl.CURSOR_TIME, ""+ time/1000000+"ns"); + + } + }); + txDisplay.addSelectionChangedListener(new ISelectionChangedListener() { + @Override + public void selectionChanged(SelectionChangedEvent event) { + if(event.getSelection() instanceof IStructuredSelection) + for(Object o:((IStructuredSelection)event.getSelection()).toList()){ + if(o instanceof ITx || o instanceof IWaveform){ + selectionService.setSelection(o); + return; + } + } + } + }); + filesToLoad=new ArrayList(); + persistedState = part.getPersistedState(); + Integer files = persistedState.containsKey(DATABASE_FILE+"S")?Integer.parseInt(persistedState.get(DATABASE_FILE+"S")):0; + for(int i=0; i0) + loadDatabase(); + eventBroker.post(StatusBarControl.ZOOM_LEVEL, zoomLevel[txDisplay.getZoomLevel()]); + menuService.registerContextMenu(txDisplay.getNameControl(), "com.minres.scviewer.e4.application.popupmenu.namecontext"); + menuService.registerContextMenu(txDisplay.getValueControl(), "com.minres.scviewer.e4.application.popupmenu.namecontext"); + menuService.registerContextMenu(txDisplay.getWaveformControl(), "com.minres.scviewer.e4.application.popupmenu.wavecontext"); + } + + protected void loadDatabase() { + Job job = new Job(" My Job") { + @Override + protected IStatus run( IProgressMonitor monitor) { + // convert to SubMonitor and set total number of work units + SubMonitor subMonitor = SubMonitor.convert(monitor, filesToLoad.size()); + try { + for(File file: filesToLoad){ +// TimeUnit.SECONDS.sleep(20); + database.load(file); + database.addPropertyChangeListener(txDisplay); + subMonitor.worked(1); + if(monitor.isCanceled()) return Status.CANCEL_STATUS; + } + // sleep a second + } catch (Exception e) { + database=null; + e.printStackTrace(); + return Status.CANCEL_STATUS; + } + return Status.OK_STATUS; + } + }; + job.addJobChangeListener(new JobChangeAdapter(){ + @Override + public void done(IJobChangeEvent event) { + if(event.getResult()==Status.OK_STATUS) + myParent.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + txDisplay.setMaxTime(database.getMaxTime()); + restoreState(); + } + }); + } + }); + job.schedule(0); + } + + @Inject + @Optional + public void setPartInput( @Named( "input" ) Object partInput ) { + if(partInput instanceof File){ + filesToLoad=new ArrayList(); + File file = (File) partInput; + if(file.exists()){ + filesToLoad.add(file); + try { + String ext = getFileExtension(file.getName()); + if("vcd".equals(ext.toLowerCase())){ + if(askIfToLoad(new File(renameFileExtension(file.getCanonicalPath(), "txdb")))){ + filesToLoad.add(new File(renameFileExtension(file.getCanonicalPath(), "txdb"))); + }else if(askIfToLoad(new File(renameFileExtension(file.getCanonicalPath(), "txlog")))){ + filesToLoad.add(new File(renameFileExtension(file.getCanonicalPath(), "txlog"))); + } + } else if("txdb".equals(ext.toLowerCase()) || "txlog".equals(ext.toLowerCase())){ + if(askIfToLoad(new File(renameFileExtension(file.getCanonicalPath(), "vcd")))){ + filesToLoad.add(new File(renameFileExtension(file.getCanonicalPath(), "vcd"))); + } + } + } catch (IOException e) { // silently ignore any error + } + } + if(filesToLoad.size()>0) + loadDatabase(); + } + } + + @Focus + public void setFocus() { + myParent.setFocus(); + updateAll(); + } + + @PersistState + public void saveState(MPart part) { + // save changes + Map persistedState = part.getPersistedState(); + persistedState.put(DATABASE_FILE+"S", Integer.toString(filesToLoad.size())); + Integer index=0; + for(File file:filesToLoad){ + persistedState.put(DATABASE_FILE+index, file.getAbsolutePath()); + index++; + } + if(activeNode!=null) + persistedState.put(ACTIVE_NODE_PATH, activeNode.getFullName()); + persistedState.put(SHOWN_WAVEFORM+"S", Integer.toString(txDisplay.getStreamList().size())); + index=0; + for(IWaveform waveform:txDisplay.getStreamList()){ + persistedState.put(SHOWN_WAVEFORM+index, waveform.getFullName()); + index++; + } + } + + protected void restoreState() { + updateAll(); + String hierName = persistedState.get(ACTIVE_NODE_PATH); + if(hierName!=null) eventBroker.post(ACTIVE_NODE_PATH, hierName); + Integer waves = persistedState.containsKey(SHOWN_WAVEFORM+"S")?Integer.parseInt(persistedState.get(SHOWN_WAVEFORM+"S")):0; + List> res = new LinkedList<>(); + for(int i=0; i waveform = database.getStreamByName(persistedState.get(SHOWN_WAVEFORM+i)); + if(waveform!=null) res.add(waveform); + } + if(res.size()>0) txDisplay.getStreamList().addAll(res); + } + + private void updateAll() { + eventBroker.post(ACTIVE_DATABASE, database); + eventBroker.post(StatusBarControl.ZOOM_LEVEL, zoomLevel[txDisplay.getZoomLevel()]); + eventBroker.post(StatusBarControl.CURSOR_TIME, Long.toString(txDisplay.getCursorTime()/1000000)+"ns"); + } + + @Inject @Optional + public void getActiveNodeEvent(@UIEventTopic(WaveformViewerPart.ACTIVE_NODE) Object o, MPart activePart) { + if(o instanceof IHierNode){ + activeNode=(IHierNode) o; + } + } + + @Inject @Optional + public void getAddWaveformEvent(@UIEventTopic(WaveformViewerPart.ADD_WAVEFORM) Object o) { + Object sel = selectionService.getSelection(); + if(sel instanceof List) + for(Object el:((List)sel)){ + if(el instanceof IWaveform) + addStreamToList((IWaveform) el); + } + else if(sel instanceof IWaveform ) + addStreamToList((IWaveform) sel); + } + +/* + @Inject + public void setWaveform(@Optional @Named( IServiceConstants.ACTIVE_SELECTION) IWaveform waveform, + @Optional @Named( IServiceConstants.ACTIVE_PART) MPart part) { + if (txDisplay!= null && part.getObject()!=this) { + txDisplay.setSelection(waveform==null?new StructuredSelection():new StructuredSelection(waveform)); + } + } +*/ + protected boolean askIfToLoad(File txFile) { + if(txFile.exists() && + MessageDialog.openQuestion(myParent.getDisplay().getActiveShell(), "Database open", + "Would you like to open the adjacent database "+txFile.getName()+" as well?")){ + return true; + } + return false; + } + + protected static String renameFileExtension(String source, String newExt) { + String target; + String currentExt = getFileExtension(source); + if (currentExt.equals("")){ + target=source+"."+newExt; + } else { + target=source.replaceFirst(Pattern.quote("."+currentExt)+"$", Matcher.quoteReplacement("."+newExt)); + } + return target; + } + + protected static String getFileExtension(String f) { + String ext = ""; + int i = f.lastIndexOf('.'); + if (i > 0 && i < f.length() - 1) { + ext = f.substring(i + 1); + } + return ext; + } + + public IWaveformDb getModel() { + return database; + } + public IWaveformDb getDatabase() { + return database; + } + + public void addStreamToList(IWaveform obj){ + txDisplay.getStreamList().add(obj); + } + + public void addStreamsToList(IWaveform[] iWaveforms){ + for(IWaveform stream:iWaveforms) + addStreamToList(stream); + } + + public void removeStreamFromList(IWaveform obj){ + txDisplay.getStreamList().remove(obj); + } + + public void removeStreamsFromList(IWaveform[] iWaveforms){ + for(IWaveform stream:iWaveforms) + removeStreamFromList(stream); + } + + public List> getStreamList(){ + return txDisplay.getStreamList(); + } + + public void moveSelected(int i) { + txDisplay.moveSelected(i); + } + + public void moveSelection(GotoDirection direction) { + txDisplay.moveSelection(direction); + } + + public void moveCursor(GotoDirection direction) { + txDisplay.moveCursor(direction); } + + public void setZoomLevel(Integer level) { + if(level<0) level=0; + if(level>zoomLevel.length-1) level=zoomLevel.length-1; + txDisplay.setZoomLevel(level); + eventBroker.post(StatusBarControl.ZOOM_LEVEL, zoomLevel[txDisplay.getZoomLevel()]); + } + + public void setZoomFit() { + txDisplay.setZoomLevel(6); + eventBroker.post(StatusBarControl.ZOOM_LEVEL, zoomLevel[txDisplay.getZoomLevel()]); + } + + public int getZoomLevel() { + return txDisplay.getZoomLevel(); + } + +} + \ No newline at end of file diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/provider/TxDbContentProvider.java b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/provider/TxDbContentProvider.java new file mode 100644 index 0000000..21a5752 --- /dev/null +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/provider/TxDbContentProvider.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright (c) 2014, 2015 MINRES Technologies GmbH and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * MINRES Technologies GmbH - initial API and implementation + *******************************************************************************/ +package com.minres.scviewer.e4.application.provider; + +import java.util.List; + +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.Viewer; + +import com.google.common.base.Predicate; +import com.google.common.collect.Collections2; +import com.minres.scviewer.database.IHierNode; +import com.minres.scviewer.database.IWaveform; + +public class TxDbContentProvider implements ITreeContentProvider { + + // private List nodes; + private boolean showNodes=false; + + @Override + public void dispose() { } + + @Override + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + showNodes=!(newInput instanceof IHierNode); + } + + @Override + public Object[] getElements(Object inputElement) { + if(inputElement instanceof IHierNode){ + return Collections2.filter(((IHierNode)inputElement).getChildNodes(), new Predicate(){ + @Override + public boolean apply(IHierNode arg0) { + return (arg0 instanceof IWaveform)!=showNodes; + } + }).toArray(); + }else if(inputElement instanceof List) + return ((List)inputElement).toArray(); + else + return null; + } + + @Override + public Object[] getChildren(Object parentElement) { + return getElements(parentElement); + } + + @Override + public Object getParent(Object element) { + return null; + } + + @Override + public boolean hasChildren(Object element) { + // Object[] obj = getChildren(element); + Object[] obj = getElements(element); + return obj == null ? false : obj.length > 0; + } + +} diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/provider/TxDbLabelProvider.java b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/provider/TxDbLabelProvider.java new file mode 100644 index 0000000..8b821da --- /dev/null +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/provider/TxDbLabelProvider.java @@ -0,0 +1,88 @@ +/******************************************************************************* + * Copyright (c) 2014, 2015 MINRES Technologies GmbH and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * MINRES Technologies GmbH - initial API and implementation + *******************************************************************************/ +package com.minres.scviewer.e4.application.provider; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jface.viewers.ILabelProvider; +import org.eclipse.jface.viewers.ILabelProviderListener; +import org.eclipse.swt.graphics.Image; +import org.eclipse.wb.swt.ResourceManager; + +import com.minres.scviewer.database.IHierNode; +import com.minres.scviewer.database.ISignal; +import com.minres.scviewer.database.ITxStream; +import com.minres.scviewer.database.IWaveformDb; + +public class TxDbLabelProvider implements ILabelProvider { + + private List listeners = new ArrayList(); + + private Image database; + private Image stream; + private Image signal; + private Image folder; + + + public TxDbLabelProvider() { + super(); + database=ResourceManager.getPluginImage("com.minres.scviewer.e4.application", "icons/database.png"); + stream=ResourceManager.getPluginImage("com.minres.scviewer.e4.application", "icons/stream.png"); + folder=ResourceManager.getPluginImage("com.minres.scviewer.e4.application", "icons/folder.png"); + signal=ResourceManager.getPluginImage("com.minres.scviewer.e4.application", "icons/signal.png"); + } + + @Override + public void addListener(ILabelProviderListener listener) { + listeners.add(listener); + } + + @Override + public void dispose() { + if(database!=null) database.dispose(); + if(stream!=null) stream.dispose(); + if(folder!=null) folder.dispose(); + if(signal!=null) signal.dispose(); + } + + @Override + public boolean isLabelProperty(Object element, String property) { + return false; + } + + @Override + public void removeListener(ILabelProviderListener listener) { + listeners.remove(listener); + } + + @Override + public Image getImage(Object element) { + if(element instanceof IWaveformDb){ + return database; + }else if(element instanceof ITxStream){ + return stream; + }else if(element instanceof ISignal){ + return signal; + }else if(element instanceof IHierNode){ + return folder; + } else + return null; + } + + @Override + public String getText(Object element) { + return ((IHierNode)element).getName(); + } + +} + + diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/provider/TxPropertiesContentProvider.java b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/provider/TxPropertiesContentProvider.java new file mode 100644 index 0000000..465db5b --- /dev/null +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/provider/TxPropertiesContentProvider.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2014, 2015 MINRES Technologies GmbH and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * MINRES Technologies GmbH - initial API and implementation + *******************************************************************************/ +package com.minres.scviewer.e4.application.provider; + +import java.util.List; + +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.Viewer; + +import com.google.common.base.Predicate; +import com.google.common.collect.Collections2; +import com.minres.scviewer.database.IHierNode; +import com.minres.scviewer.database.ITx; +import com.minres.scviewer.database.ITxAttribute; + +public class TxPropertiesContentProvider implements IStructuredContentProvider { + + // private List nodes; + private boolean showNodes=false; + + @Override + public void dispose() { } + + @Override + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + showNodes=!(newInput instanceof IHierNode); + } + + @Override + public Object[] getElements(Object inputElement) { + if(inputElement instanceof ITx){ + return Collections2.filter(((ITx)inputElement).getAttributes(), new Predicate(){ + @Override + public boolean apply(ITxAttribute arg0) { + return (arg0 instanceof ITx)!=showNodes; + } + }).toArray(); + }else if(inputElement instanceof List) + return ((List)inputElement).toArray(); + else + return null; + } + +} diff --git a/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/provider/TxPropertiesLabelProvider.java b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/provider/TxPropertiesLabelProvider.java new file mode 100644 index 0000000..8822b83 --- /dev/null +++ b/com.minres.scviewer.e4.application/src/com/minres/scviewer/e4/application/provider/TxPropertiesLabelProvider.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * Copyright (c) 2014, 2015 MINRES Technologies GmbH and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * MINRES Technologies GmbH - initial API and implementation + *******************************************************************************/ +package com.minres.scviewer.e4.application.provider; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jface.viewers.ILabelProviderListener; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.swt.graphics.Image; + +import com.minres.scviewer.database.ITxAttribute; +import com.minres.scviewer.e4.application.parts.TransactionDetails; + +public class TxPropertiesLabelProvider implements ITableLabelProvider { + + private List listeners = new ArrayList(); + + public TxPropertiesLabelProvider() { + super(); + } + + @Override + public void dispose() { + } + + @Override + public void addListener(ILabelProviderListener listener) { + listeners.add(listener); + } + + @Override + public void removeListener(ILabelProviderListener listener) { + listeners.remove(listener); + } + + @Override + public boolean isLabelProperty(Object element, String property) { + return false; + } + + @Override + public Image getColumnImage(Object element, int columnIndex) { + return null; + } + + @Override + public String getColumnText(Object element, int columnIndex) { + ITxAttribute attribute = (ITxAttribute) element; + String text = ""; + switch (columnIndex) { + case TransactionDetails.COLUMN_FIRST: + text = attribute.getName(); + break; + case TransactionDetails.COLUMN_SECOND: + text = attribute.getValue().toString(); + break; + } + return text; + } + +} + + diff --git a/com.minres.scviewer.e4.application/src/org/eclipse/wb/swt/ResourceManager.java b/com.minres.scviewer.e4.application/src/org/eclipse/wb/swt/ResourceManager.java new file mode 100644 index 0000000..4bfbc6b --- /dev/null +++ b/com.minres.scviewer.e4.application/src/org/eclipse/wb/swt/ResourceManager.java @@ -0,0 +1,415 @@ +/******************************************************************************* + * Copyright (c) 2011 Google, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Google, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.wb.swt; + +import java.io.File; +import java.io.InputStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.eclipse.core.runtime.Platform; +import org.eclipse.jface.resource.CompositeImageDescriptor; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.osgi.framework.Bundle; + +/** + * Utility class for managing OS resources associated with SWT/JFace controls such as colors, fonts, images, + * etc. + * + * !!! IMPORTANT !!! Application code must explicitly invoke the dispose() method to release the + * operating system resources managed by cached objects when those objects and OS resources are no longer + * needed (e.g. on application shutdown) + * + * This class may be freely distributed as part of any application or plugin. + *

+ * + * @author scheglov_ke + * @author Dan Rubel + */ +public class ResourceManager extends SWTResourceManager { + //////////////////////////////////////////////////////////////////////////// + // + // Image + // + //////////////////////////////////////////////////////////////////////////// + private static Map m_descriptorImageMap = new HashMap(); + /** + * Returns an {@link ImageDescriptor} stored in the file at the specified path relative to the specified + * class. + * + * @param clazz + * the {@link Class} relative to which to find the image descriptor. + * @param path + * the path to the image file. + * @return the {@link ImageDescriptor} stored in the file at the specified path. + */ + public static ImageDescriptor getImageDescriptor(Class clazz, String path) { + return ImageDescriptor.createFromFile(clazz, path); + } + /** + * Returns an {@link ImageDescriptor} stored in the file at the specified path. + * + * @param path + * the path to the image file. + * @return the {@link ImageDescriptor} stored in the file at the specified path. + */ + public static ImageDescriptor getImageDescriptor(String path) { + try { + return ImageDescriptor.createFromURL(new File(path).toURI().toURL()); + } catch (MalformedURLException e) { + return null; + } + } + /** + * Returns an {@link Image} based on the specified {@link ImageDescriptor}. + * + * @param descriptor + * the {@link ImageDescriptor} for the {@link Image}. + * @return the {@link Image} based on the specified {@link ImageDescriptor}. + */ + public static Image getImage(ImageDescriptor descriptor) { + if (descriptor == null) { + return null; + } + Image image = m_descriptorImageMap.get(descriptor); + if (image == null) { + image = descriptor.createImage(); + m_descriptorImageMap.put(descriptor, image); + } + return image; + } + /** + * Maps images to decorated images. + */ + @SuppressWarnings("unchecked") + private static Map>[] m_decoratedImageMap = new Map[LAST_CORNER_KEY]; + /** + * Returns an {@link Image} composed of a base image decorated by another image. + * + * @param baseImage + * the base {@link Image} that should be decorated. + * @param decorator + * the {@link Image} to decorate the base image. + * @return {@link Image} The resulting decorated image. + */ + public static Image decorateImage(Image baseImage, Image decorator) { + return decorateImage(baseImage, decorator, BOTTOM_RIGHT); + } + /** + * Returns an {@link Image} composed of a base image decorated by another image. + * + * @param baseImage + * the base {@link Image} that should be decorated. + * @param decorator + * the {@link Image} to decorate the base image. + * @param corner + * the corner to place decorator image. + * @return the resulting decorated {@link Image}. + */ + public static Image decorateImage(final Image baseImage, final Image decorator, final int corner) { + if (corner <= 0 || corner >= LAST_CORNER_KEY) { + throw new IllegalArgumentException("Wrong decorate corner"); + } + Map> cornerDecoratedImageMap = m_decoratedImageMap[corner]; + if (cornerDecoratedImageMap == null) { + cornerDecoratedImageMap = new HashMap>(); + m_decoratedImageMap[corner] = cornerDecoratedImageMap; + } + Map decoratedMap = cornerDecoratedImageMap.get(baseImage); + if (decoratedMap == null) { + decoratedMap = new HashMap(); + cornerDecoratedImageMap.put(baseImage, decoratedMap); + } + // + Image result = decoratedMap.get(decorator); + if (result == null) { + final Rectangle bib = baseImage.getBounds(); + final Rectangle dib = decorator.getBounds(); + final Point baseImageSize = new Point(bib.width, bib.height); + CompositeImageDescriptor compositImageDesc = new CompositeImageDescriptor() { + @Override + protected void drawCompositeImage(int width, int height) { + drawImage(baseImage.getImageData(), 0, 0); + if (corner == TOP_LEFT) { + drawImage(decorator.getImageData(), 0, 0); + } else if (corner == TOP_RIGHT) { + drawImage(decorator.getImageData(), bib.width - dib.width, 0); + } else if (corner == BOTTOM_LEFT) { + drawImage(decorator.getImageData(), 0, bib.height - dib.height); + } else if (corner == BOTTOM_RIGHT) { + drawImage(decorator.getImageData(), bib.width - dib.width, bib.height - dib.height); + } + } + @Override + protected Point getSize() { + return baseImageSize; + } + }; + // + result = compositImageDesc.createImage(); + decoratedMap.put(decorator, result); + } + return result; + } + /** + * Dispose all of the cached images. + */ + public static void disposeImages() { + SWTResourceManager.disposeImages(); + // dispose ImageDescriptor images + { + for (Iterator I = m_descriptorImageMap.values().iterator(); I.hasNext();) { + I.next().dispose(); + } + m_descriptorImageMap.clear(); + } + // dispose decorated images + for (int i = 0; i < m_decoratedImageMap.length; i++) { + Map> cornerDecoratedImageMap = m_decoratedImageMap[i]; + if (cornerDecoratedImageMap != null) { + for (Map decoratedMap : cornerDecoratedImageMap.values()) { + for (Image image : decoratedMap.values()) { + image.dispose(); + } + decoratedMap.clear(); + } + cornerDecoratedImageMap.clear(); + } + } + // dispose plugin images + { + for (Iterator I = m_URLImageMap.values().iterator(); I.hasNext();) { + I.next().dispose(); + } + m_URLImageMap.clear(); + } + } + //////////////////////////////////////////////////////////////////////////// + // + // Plugin images support + // + //////////////////////////////////////////////////////////////////////////// + /** + * Maps URL to images. + */ + private static Map m_URLImageMap = new HashMap(); + /** + * Provider for plugin resources, used by WindowBuilder at design time. + */ + public interface PluginResourceProvider { + URL getEntry(String symbolicName, String path); + } + /** + * Instance of {@link PluginResourceProvider}, used by WindowBuilder at design time. + */ + private static PluginResourceProvider m_designTimePluginResourceProvider = null; + /** + * Returns an {@link Image} based on a plugin and file path. + * + * @param plugin + * the plugin {@link Object} containing the image + * @param name + * the path to the image within the plugin + * @return the {@link Image} stored in the file at the specified path + * + * @deprecated Use {@link #getPluginImage(String, String)} instead. + */ + @Deprecated + public static Image getPluginImage(Object plugin, String name) { + try { + URL url = getPluginImageURL(plugin, name); + if (url != null) { + return getPluginImageFromUrl(url); + } + } catch (Throwable e) { + // Ignore any exceptions + } + return null; + } + /** + * Returns an {@link Image} based on a {@link Bundle} and resource entry path. + * + * @param symbolicName + * the symbolic name of the {@link Bundle}. + * @param path + * the path of the resource entry. + * @return the {@link Image} stored in the file at the specified path. + */ + public static Image getPluginImage(String symbolicName, String path) { + try { + URL url = getPluginImageURL(symbolicName, path); + if (url != null) { + return getPluginImageFromUrl(url); + } + } catch (Throwable e) { + // Ignore any exceptions + } + return null; + } + /** + * Returns an {@link Image} based on given {@link URL}. + */ + private static Image getPluginImageFromUrl(URL url) { + try { + try { + String key = url.toExternalForm(); + Image image = m_URLImageMap.get(key); + if (image == null) { + InputStream stream = url.openStream(); + try { + image = getImage(stream); + m_URLImageMap.put(key, image); + } finally { + stream.close(); + } + } + return image; + } catch (Throwable e) { + // Ignore any exceptions + } + } catch (Throwable e) { + // Ignore any exceptions + } + return null; + } + /** + * Returns an {@link ImageDescriptor} based on a plugin and file path. + * + * @param plugin + * the plugin {@link Object} containing the image. + * @param name + * the path to th eimage within the plugin. + * @return the {@link ImageDescriptor} stored in the file at the specified path. + * + * @deprecated Use {@link #getPluginImageDescriptor(String, String)} instead. + */ + @Deprecated + public static ImageDescriptor getPluginImageDescriptor(Object plugin, String name) { + try { + try { + URL url = getPluginImageURL(plugin, name); + return ImageDescriptor.createFromURL(url); + } catch (Throwable e) { + // Ignore any exceptions + } + } catch (Throwable e) { + // Ignore any exceptions + } + return null; + } + /** + * Returns an {@link ImageDescriptor} based on a {@link Bundle} and resource entry path. + * + * @param symbolicName + * the symbolic name of the {@link Bundle}. + * @param path + * the path of the resource entry. + * @return the {@link ImageDescriptor} based on a {@link Bundle} and resource entry path. + */ + public static ImageDescriptor getPluginImageDescriptor(String symbolicName, String path) { + try { + URL url = getPluginImageURL(symbolicName, path); + if (url != null) { + return ImageDescriptor.createFromURL(url); + } + } catch (Throwable e) { + // Ignore any exceptions + } + return null; + } + /** + * Returns an {@link URL} based on a {@link Bundle} and resource entry path. + */ + private static URL getPluginImageURL(String symbolicName, String path) { + // try runtime plugins + { + Bundle bundle = Platform.getBundle(symbolicName); + if (bundle != null) { + return bundle.getEntry(path); + } + } + // try design time provider + if (m_designTimePluginResourceProvider != null) { + return m_designTimePluginResourceProvider.getEntry(symbolicName, path); + } + // no such resource + return null; + } + /** + * Returns an {@link URL} based on a plugin and file path. + * + * @param plugin + * the plugin {@link Object} containing the file path. + * @param name + * the file path. + * @return the {@link URL} representing the file at the specified path. + * @throws Exception + */ + private static URL getPluginImageURL(Object plugin, String name) throws Exception { + // try to work with 'plugin' as with OSGI BundleContext + try { + Class BundleClass = Class.forName("org.osgi.framework.Bundle"); //$NON-NLS-1$ + Class BundleContextClass = Class.forName("org.osgi.framework.BundleContext"); //$NON-NLS-1$ + if (BundleContextClass.isAssignableFrom(plugin.getClass())) { + Method getBundleMethod = BundleContextClass.getMethod("getBundle", new Class[0]); //$NON-NLS-1$ + Object bundle = getBundleMethod.invoke(plugin, new Object[0]); + // + Class PathClass = Class.forName("org.eclipse.core.runtime.Path"); //$NON-NLS-1$ + Constructor pathConstructor = PathClass.getConstructor(new Class[]{String.class}); + Object path = pathConstructor.newInstance(new Object[]{name}); + // + Class IPathClass = Class.forName("org.eclipse.core.runtime.IPath"); //$NON-NLS-1$ + Class PlatformClass = Class.forName("org.eclipse.core.runtime.Platform"); //$NON-NLS-1$ + Method findMethod = PlatformClass.getMethod("find", new Class[]{BundleClass, IPathClass}); //$NON-NLS-1$ + return (URL) findMethod.invoke(null, new Object[]{bundle, path}); + } + } catch (Throwable e) { + // Ignore any exceptions + } + // else work with 'plugin' as with usual Eclipse plugin + { + Class PluginClass = Class.forName("org.eclipse.core.runtime.Plugin"); //$NON-NLS-1$ + if (PluginClass.isAssignableFrom(plugin.getClass())) { + // + Class PathClass = Class.forName("org.eclipse.core.runtime.Path"); //$NON-NLS-1$ + Constructor pathConstructor = PathClass.getConstructor(new Class[]{String.class}); + Object path = pathConstructor.newInstance(new Object[]{name}); + // + Class IPathClass = Class.forName("org.eclipse.core.runtime.IPath"); //$NON-NLS-1$ + Method findMethod = PluginClass.getMethod("find", new Class[]{IPathClass}); //$NON-NLS-1$ + return (URL) findMethod.invoke(plugin, new Object[]{path}); + } + } + return null; + } + //////////////////////////////////////////////////////////////////////////// + // + // General + // + //////////////////////////////////////////////////////////////////////////// + /** + * Dispose of cached objects and their underlying OS resources. This should only be called when the cached + * objects are no longer needed (e.g. on application shutdown). + */ + public static void dispose() { + disposeColors(); + disposeFonts(); + disposeImages(); + } +} \ No newline at end of file diff --git a/com.minres.scviewer.e4.application/src/org/eclipse/wb/swt/SWTResourceManager.java b/com.minres.scviewer.e4.application/src/org/eclipse/wb/swt/SWTResourceManager.java new file mode 100644 index 0000000..53472ad --- /dev/null +++ b/com.minres.scviewer.e4.application/src/org/eclipse/wb/swt/SWTResourceManager.java @@ -0,0 +1,447 @@ +/******************************************************************************* + * Copyright (c) 2014, 2015 MINRES Technologies GmbH and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * MINRES Technologies GmbH - initial API and implementation + *******************************************************************************/ +package org.eclipse.wb.swt; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Cursor; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.FontData; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Display; + +/** + * Utility class for managing OS resources associated with SWT controls such as colors, fonts, images, etc. + *

+ * !!! IMPORTANT !!! Application code must explicitly invoke the dispose() method to release the + * operating system resources managed by cached objects when those objects and OS resources are no longer + * needed (e.g. on application shutdown) + *

+ * This class may be freely distributed as part of any application or plugin. + *

+ * @author scheglov_ke + * @author Dan Rubel + */ +public class SWTResourceManager { + //////////////////////////////////////////////////////////////////////////// + // + // Color + // + //////////////////////////////////////////////////////////////////////////// + private static Map m_colorMap = new HashMap(); + /** + * Returns the system {@link Color} matching the specific ID. + * + * @param systemColorID + * the ID value for the color + * @return the system {@link Color} matching the specific ID + */ + public static Color getColor(int systemColorID) { + Display display = Display.getCurrent(); + return display.getSystemColor(systemColorID); + } + /** + * Returns a {@link Color} given its red, green and blue component values. + * + * @param r + * the red component of the color + * @param g + * the green component of the color + * @param b + * the blue component of the color + * @return the {@link Color} matching the given red, green and blue component values + */ + public static Color getColor(int r, int g, int b) { + return getColor(new RGB(r, g, b)); + } + /** + * Returns a {@link Color} given its RGB value. + * + * @param rgb + * the {@link RGB} value of the color + * @return the {@link Color} matching the RGB value + */ + public static Color getColor(RGB rgb) { + Color color = m_colorMap.get(rgb); + if (color == null) { + Display display = Display.getCurrent(); + color = new Color(display, rgb); + m_colorMap.put(rgb, color); + } + return color; + } + /** + * Dispose of all the cached {@link Color}'s. + */ + public static void disposeColors() { + for (Color color : m_colorMap.values()) { + color.dispose(); + } + m_colorMap.clear(); + } + //////////////////////////////////////////////////////////////////////////// + // + // Image + // + //////////////////////////////////////////////////////////////////////////// + /** + * Maps image paths to images. + */ + private static Map m_imageMap = new HashMap(); + /** + * Returns an {@link Image} encoded by the specified {@link InputStream}. + * + * @param stream + * the {@link InputStream} encoding the image data + * @return the {@link Image} encoded by the specified input stream + */ + protected static Image getImage(InputStream stream) throws IOException { + try { + Display display = Display.getCurrent(); + ImageData data = new ImageData(stream); + if (data.transparentPixel > 0) { + return new Image(display, data, data.getTransparencyMask()); + } + return new Image(display, data); + } finally { + stream.close(); + } + } + /** + * Returns an {@link Image} stored in the file at the specified path. + * + * @param path + * the path to the image file + * @return the {@link Image} stored in the file at the specified path + */ + public static Image getImage(String path) { + Image image = m_imageMap.get(path); + if (image == null) { + try { + image = getImage(new FileInputStream(path)); + m_imageMap.put(path, image); + } catch (Exception e) { + image = getMissingImage(); + m_imageMap.put(path, image); + } + } + return image; + } + /** + * Returns an {@link Image} stored in the file at the specified path relative to the specified class. + * + * @param clazz + * the {@link Class} relative to which to find the image + * @param path + * the path to the image file, if starts with '/' + * @return the {@link Image} stored in the file at the specified path + */ + public static Image getImage(Class clazz, String path) { + String key = clazz.getName() + '|' + path; + Image image = m_imageMap.get(key); + if (image == null) { + try { + image = getImage(clazz.getResourceAsStream(path)); + m_imageMap.put(key, image); + } catch (Exception e) { + image = getMissingImage(); + m_imageMap.put(key, image); + } + } + return image; + } + private static final int MISSING_IMAGE_SIZE = 10; + /** + * @return the small {@link Image} that can be used as placeholder for missing image. + */ + private static Image getMissingImage() { + Image image = new Image(Display.getCurrent(), MISSING_IMAGE_SIZE, MISSING_IMAGE_SIZE); + // + GC gc = new GC(image); + gc.setBackground(getColor(SWT.COLOR_RED)); + gc.fillRectangle(0, 0, MISSING_IMAGE_SIZE, MISSING_IMAGE_SIZE); + gc.dispose(); + // + return image; + } + /** + * Style constant for placing decorator image in top left corner of base image. + */ + public static final int TOP_LEFT = 1; + /** + * Style constant for placing decorator image in top right corner of base image. + */ + public static final int TOP_RIGHT = 2; + /** + * Style constant for placing decorator image in bottom left corner of base image. + */ + public static final int BOTTOM_LEFT = 3; + /** + * Style constant for placing decorator image in bottom right corner of base image. + */ + public static final int BOTTOM_RIGHT = 4; + /** + * Internal value. + */ + protected static final int LAST_CORNER_KEY = 5; + /** + * Maps images to decorated images. + */ + @SuppressWarnings("unchecked") + private static Map>[] m_decoratedImageMap = new Map[LAST_CORNER_KEY]; + /** + * Returns an {@link Image} composed of a base image decorated by another image. + * + * @param baseImage + * the base {@link Image} that should be decorated + * @param decorator + * the {@link Image} to decorate the base image + * @return {@link Image} The resulting decorated image + */ + public static Image decorateImage(Image baseImage, Image decorator) { + return decorateImage(baseImage, decorator, BOTTOM_RIGHT); + } + /** + * Returns an {@link Image} composed of a base image decorated by another image. + * + * @param baseImage + * the base {@link Image} that should be decorated + * @param decorator + * the {@link Image} to decorate the base image + * @param corner + * the corner to place decorator image + * @return the resulting decorated {@link Image} + */ + public static Image decorateImage(final Image baseImage, final Image decorator, final int corner) { + if (corner <= 0 || corner >= LAST_CORNER_KEY) { + throw new IllegalArgumentException("Wrong decorate corner"); + } + Map> cornerDecoratedImageMap = m_decoratedImageMap[corner]; + if (cornerDecoratedImageMap == null) { + cornerDecoratedImageMap = new HashMap>(); + m_decoratedImageMap[corner] = cornerDecoratedImageMap; + } + Map decoratedMap = cornerDecoratedImageMap.get(baseImage); + if (decoratedMap == null) { + decoratedMap = new HashMap(); + cornerDecoratedImageMap.put(baseImage, decoratedMap); + } + // + Image result = decoratedMap.get(decorator); + if (result == null) { + Rectangle bib = baseImage.getBounds(); + Rectangle dib = decorator.getBounds(); + // + result = new Image(Display.getCurrent(), bib.width, bib.height); + // + GC gc = new GC(result); + gc.drawImage(baseImage, 0, 0); + if (corner == TOP_LEFT) { + gc.drawImage(decorator, 0, 0); + } else if (corner == TOP_RIGHT) { + gc.drawImage(decorator, bib.width - dib.width, 0); + } else if (corner == BOTTOM_LEFT) { + gc.drawImage(decorator, 0, bib.height - dib.height); + } else if (corner == BOTTOM_RIGHT) { + gc.drawImage(decorator, bib.width - dib.width, bib.height - dib.height); + } + gc.dispose(); + // + decoratedMap.put(decorator, result); + } + return result; + } + /** + * Dispose all of the cached {@link Image}'s. + */ + public static void disposeImages() { + // dispose loaded images + { + for (Image image : m_imageMap.values()) { + image.dispose(); + } + m_imageMap.clear(); + } + // dispose decorated images + for (int i = 0; i < m_decoratedImageMap.length; i++) { + Map> cornerDecoratedImageMap = m_decoratedImageMap[i]; + if (cornerDecoratedImageMap != null) { + for (Map decoratedMap : cornerDecoratedImageMap.values()) { + for (Image image : decoratedMap.values()) { + image.dispose(); + } + decoratedMap.clear(); + } + cornerDecoratedImageMap.clear(); + } + } + } + //////////////////////////////////////////////////////////////////////////// + // + // Font + // + //////////////////////////////////////////////////////////////////////////// + /** + * Maps font names to fonts. + */ + private static Map m_fontMap = new HashMap(); + /** + * Maps fonts to their bold versions. + */ + private static Map m_fontToBoldFontMap = new HashMap(); + /** + * Returns a {@link Font} based on its name, height and style. + * + * @param name + * the name of the font + * @param height + * the height of the font + * @param style + * the style of the font + * @return {@link Font} The font matching the name, height and style + */ + public static Font getFont(String name, int height, int style) { + return getFont(name, height, style, false, false); + } + /** + * Returns a {@link Font} based on its name, height and style. Windows-specific strikeout and underline + * flags are also supported. + * + * @param name + * the name of the font + * @param size + * the size of the font + * @param style + * the style of the font + * @param strikeout + * the strikeout flag (warning: Windows only) + * @param underline + * the underline flag (warning: Windows only) + * @return {@link Font} The font matching the name, height, style, strikeout and underline + */ + public static Font getFont(String name, int size, int style, boolean strikeout, boolean underline) { + String fontName = name + '|' + size + '|' + style + '|' + strikeout + '|' + underline; + Font font = m_fontMap.get(fontName); + if (font == null) { + FontData fontData = new FontData(name, size, style); + if (strikeout || underline) { + try { + Class logFontClass = Class.forName("org.eclipse.swt.internal.win32.LOGFONT"); //$NON-NLS-1$ + Object logFont = FontData.class.getField("data").get(fontData); //$NON-NLS-1$ + if (logFont != null && logFontClass != null) { + if (strikeout) { + logFontClass.getField("lfStrikeOut").set(logFont, Byte.valueOf((byte) 1)); //$NON-NLS-1$ + } + if (underline) { + logFontClass.getField("lfUnderline").set(logFont, Byte.valueOf((byte) 1)); //$NON-NLS-1$ + } + } + } catch (Throwable e) { + System.err.println("Unable to set underline or strikeout" + " (probably on a non-Windows platform). " + e); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + font = new Font(Display.getCurrent(), fontData); + m_fontMap.put(fontName, font); + } + return font; + } + /** + * Returns a bold version of the given {@link Font}. + * + * @param baseFont + * the {@link Font} for which a bold version is desired + * @return the bold version of the given {@link Font} + */ + public static Font getBoldFont(Font baseFont) { + Font font = m_fontToBoldFontMap.get(baseFont); + if (font == null) { + FontData fontDatas[] = baseFont.getFontData(); + FontData data = fontDatas[0]; + font = new Font(Display.getCurrent(), data.getName(), data.getHeight(), SWT.BOLD); + m_fontToBoldFontMap.put(baseFont, font); + } + return font; + } + /** + * Dispose all of the cached {@link Font}'s. + */ + public static void disposeFonts() { + // clear fonts + for (Font font : m_fontMap.values()) { + font.dispose(); + } + m_fontMap.clear(); + // clear bold fonts + for (Font font : m_fontToBoldFontMap.values()) { + font.dispose(); + } + m_fontToBoldFontMap.clear(); + } + //////////////////////////////////////////////////////////////////////////// + // + // Cursor + // + //////////////////////////////////////////////////////////////////////////// + /** + * Maps IDs to cursors. + */ + private static Map m_idToCursorMap = new HashMap(); + /** + * Returns the system cursor matching the specific ID. + * + * @param id + * int The ID value for the cursor + * @return Cursor The system cursor matching the specific ID + */ + public static Cursor getCursor(int id) { + Integer key = Integer.valueOf(id); + Cursor cursor = m_idToCursorMap.get(key); + if (cursor == null) { + cursor = new Cursor(Display.getDefault(), id); + m_idToCursorMap.put(key, cursor); + } + return cursor; + } + /** + * Dispose all of the cached cursors. + */ + public static void disposeCursors() { + for (Cursor cursor : m_idToCursorMap.values()) { + cursor.dispose(); + } + m_idToCursorMap.clear(); + } + //////////////////////////////////////////////////////////////////////////// + // + // General + // + //////////////////////////////////////////////////////////////////////////// + /** + * Dispose of cached objects and their underlying OS resources. This should only be called when the cached + * objects are no longer needed (e.g. on application shutdown). + */ + public static void dispose() { + disposeColors(); + disposeImages(); + disposeFonts(); + disposeCursors(); + } +} \ No newline at end of file diff --git a/signal.xcf b/signal.xcf new file mode 100644 index 0000000000000000000000000000000000000000..c145f8f48f7055e2ccee27ad241a3ef3d7e68271 GIT binary patch literal 1420 zcmYe#%q>u;NKR8o%gjk-00IFh2C)T!n2`}k2m>*P(*y5+I)eBq{A&l$uzQnxasiS(2gP?&%w#ke{cJsNkEJ3{oNh z){~i=n4YSeUX+;v5(8>uWY8!ssmw`LD9+ExOwr`hNJ~%7&&e-R&;V1qMd?Y23I=)x zV1R{T2$j+VYE8nT6(+BMn*q{VQCyIioSB!dU6oU*Bn+u7}jl||bV)G)g`GIVZxiG*EWPt1g0pv6S5n*5|hB9Do z2dZUiM-^k54&tA8G|^U7l9g9b)-Z7h$?IBerlBY!BQ7Q`EvIhkp46~NS4CP(SWrMz zL|jqJF0y(?JzxE6RY_rfZeAX49ziiB6Q9CqDiVS`3s@ICRW$Nnus~T{fKQo&laohT zRLL|@d7i422%j=1Bj*D6>9gWBr+X9~bx673XH=6x8)D*>UE< zr(Z|6E}b=f(v-O?wja6nx