Compare commits
	
		
			95 Commits
		
	
	
		
			2.13.0
			...
			feature/cu
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 7dbcffe95d | |||
| 20934a9f47 | |||
| 24890f9bbb | |||
| bd0629301b | |||
| 71da420d86 | |||
| f9be6758e2 | |||
| 93a8c067fc | |||
| 5a372d0f90 | |||
| 806000c4cc | |||
| c32d46cdc0 | |||
| 5736279e8d | |||
| e3f4dc6616 | |||
| a64e06ff7a | |||
| a42b786835 | |||
| e76000d87b | |||
| 60ead71029 | |||
| 4c48fda5ad | |||
| 6a591f2dbc | |||
| 86c30ad948 | |||
| 0ae055b486 | |||
| efcd4f5ab8 | |||
| 232d2d4275 | |||
| 44f96e5383 | |||
| 44812310b0 | |||
| 6ef91bb5e7 | |||
| aa459b0ea6 | |||
| a2adf66618 | |||
| 3405e90df9 | |||
| 9a59947e67 | |||
| 9384d3278c | |||
| 1af3171b2e | |||
| 03fd9e154b | |||
| 3572f683e3 | |||
| 524ffb189c | |||
| 7fac6c8f74 | |||
| 037c645075 | |||
| 2f9bd29dc8 | |||
| 92662c546a | |||
| efa6544623 | |||
| 52cf9daeec | |||
| 4a315722b1 | |||
| a52efd1a12 | |||
| 535df30ada | |||
| bad34dd1d1 | |||
| 5ac7f05f57 | |||
| 8353b59a27 | |||
| 2c6ca6c376 | |||
| f4b03cb0e6 | |||
| c7858997c0 | |||
| bd99ab3992 | |||
| 66f365d38d | |||
| 59987f262d | |||
| 452a28362e | |||
| d6805f383b | |||
| 076611eec7 | |||
| e0fa55e2c0 | |||
| 9ea1994228 | |||
| 36f628c365 | |||
| ff87e72510 | |||
| aef1e29a53 | |||
| 1ebf9ba382 | |||
| 929408d08c | |||
| f57fb93525 | |||
| 788065e456 | |||
| 22b46e0525 | |||
| b75018239a | |||
| 598bb8eec7 | |||
| 869265fc13 | |||
| 5ad813527a | |||
| 73f8d3d50a | |||
| da1701195d | |||
| 9b6334509e | |||
| ac4acc34a4 | |||
| b6963f38d6 | |||
| 182a036ade | |||
| 97f2182290 | |||
| 1986a8c9c3 | |||
| 6905d96329 | |||
| 818f786b1d | |||
| 2948c1bd33 | |||
| 78faab404c | |||
| 64b10970a8 | |||
| 6ab8fd232e | |||
| f337a94112 | |||
| 0135631a3e | |||
| d0e1e8801f | |||
| d1b3a91979 | |||
| 45c1396e0e | |||
| b7301733f0 | |||
| 5df91dbaa8 | |||
| 68918689e7 | |||
| c41dd646da | |||
| a077389b83 | |||
| 25545dac51 | |||
| 4ee2e8bc68 | 
| @@ -12,7 +12,8 @@ | ||||
|     <booleanAttribute key="M2_UPDATE_SNAPSHOTS" value="false"/> | ||||
|     <stringAttribute key="M2_USER_SETTINGS" value=""/> | ||||
|     <booleanAttribute key="M2_WORKSPACE_RESOLUTION" value="true"/> | ||||
|     <booleanAttribute key="org.eclipse.jdt.launching.ATTR_ATTR_USE_ARGFILE" value="false"/> | ||||
|     <booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_CLASSPATH_ONLY_JAR" value="false"/> | ||||
|     <booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/> | ||||
|     <stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.launching.macosx.MacOSXType/AdoptOpenJDK 8 [1.8.0_232]"/> | ||||
|     <stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${project_loc:com.minres.scviewer.parent}"/> | ||||
| </launchConfiguration> | ||||
|   | ||||
							
								
								
									
										61
									
								
								README.md
									
									
									
									
									
								
							
							
						
						| @@ -18,14 +18,55 @@ The viewer has the following features | ||||
|  - sqlite based  | ||||
|  - visualization of transaction relations | ||||
|  | ||||
| To build the plugins the Eclipse SDK or PDE can be used. In both cases the Groovy | ||||
| eclipse plugin (http://groovy.codehaus.org/Eclipse+Plugin or Market) has to be | ||||
| installed. | ||||
| To build the plugins the Eclipse SDK or PDE can be used. | ||||
|  | ||||
| Key Shortcuts | ||||
| ============= | ||||
|  | ||||
| Legend: | ||||
|  | ||||
| * Left Mouse Button: LMB | ||||
| * Middle Mouse Button: MMB | ||||
| * Mouse Scroll wheel: MScrl | ||||
| * Context any means Name List, Value List or Waveform | ||||
|  | ||||
| | Input      | Modifier | Context  | Action                            | | ||||
| |------------|----------|----------|-----------------------------------| | ||||
| | LMB click  |          | any      | select                            | | ||||
| | LMB click  | Shift    | Waveform | move selected marker to position  | | ||||
| | LMB click  | Control  | Waveform | move cursor to position           | | ||||
| | LMB drag   |          | Waveform | zoom to range                     | | ||||
| | MMB click  |          | Waveform | move selected marker to position  | | ||||
| | MScrl      |          | any      | scroll window up/down             | | ||||
| | MScrl      | Shift    | any      | scroll window left/right          | | ||||
| | MScrl      | Control  | Waveform | zoom in/out                       | | ||||
| | Key left   |          | Waveform | scroll window to the left (slow)  | | ||||
| | Key right  |          | Waveform | scroll window to the right (slow) | | ||||
| | Key left   | Shift    | Waveform | scroll window to the left (fast)  | | ||||
| | Key right  | Shift    | Waveform | scroll window to the right (fast) | | ||||
| | Key up     |          | Waveform | move selection up                 | | ||||
| | Key down   |          | Waveform | move selection down               | | ||||
| | Key up     | Control  | Waveform | move selected track up            | | ||||
| | Key down   | Control  | Waveform | move selected track down          | | ||||
| | Key +      | Control  | Waveform | zoom in                           | | ||||
| | Key -      | Control  | Waveform | zoom out                          | | ||||
| | Key Pos1   |          | Waveform | jump to selected marker           | | ||||
| | Key End    |          | Waveform | jump to cursor                    | | ||||
| | Key Del    |          | any      | delete selected entries           | | ||||
| | LMB click  |          | ZoomBar  | increment/decrement 1 page        | | ||||
| | LMB drag   |          | ZoomBar  | drag both markers (pan)           | | ||||
| | LMB drag   | Control  | ZoomBar  | drag one marker (zoom)            | | ||||
| | MMB drag   |          | ZoomBar  | drag one marker (zoom)            | | ||||
| | xMB dclick |          | ZoomBar  | pan to position                   | | ||||
| | MScrl      |          | ZoomBar  | scroll window left/right          | | ||||
| | MScrl      | Shift    | ZoomBar  | scroll window left/right double speed | | ||||
| | MScrl      | Control  | ZoomBar  | zoom in/out                       | | ||||
| | Key left   |          | ZoomBar  | scroll window to the left (slow)  | | ||||
| | Key right  |          | ZoomBar  | scroll window to the right (slow) | | ||||
| | Key up     |          | ZoomBar  | scroll window to the left (slow)  | | ||||
| | Key down   |          | ZoomBar  | scroll window to the right (slow) | | ||||
| | Key PgUp   |          | ZoomBar  | scroll window to the left (fast)  | | ||||
| | Key PgDown |          | ZoomBar  | scroll window to the right (fast) | | ||||
| | Key Pos1   |          | ZoomBar  | scroll to begin                   | | ||||
| | Key End    |          | ZoomBar  | scroll to end                     | | ||||
|  | ||||
| TODO | ||||
| ==== | ||||
| - add more tests | ||||
| - move to feature based product to allow automatic updates | ||||
| - improve graphics | ||||
| - catch-up e3 plugin to functionality of e4 product | ||||
| - add calculated traces | ||||
|   | ||||
| @@ -27,12 +27,12 @@ http://www.eclipse.org/legal/epl-v10.html | ||||
|    </url> | ||||
|  | ||||
|    <requires> | ||||
|       <import plugin="org.codehaus.groovy" version="2.5.8" match="greaterOrEqual"/> | ||||
|       <import plugin="org.eclipse.osgi.services" version="3.4.0" match="greaterOrEqual"/> | ||||
|       <import plugin="com.google.guava" version="15.0.0" match="greaterOrEqual"/> | ||||
|       <import plugin="org.eclipse.osgi"/> | ||||
|       <import plugin="com.minres.scviewer.database" version="1.0.0" match="greaterOrEqual"/> | ||||
|       <import plugin="org.eclipse.core.runtime"/> | ||||
|       <import feature="org.eclipse.collections.feature" version="10.4.0.v20200820-2049"/> | ||||
|    </requires> | ||||
|  | ||||
|    <plugin | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
|   <parent> | ||||
|   	<groupId>com.minres.scviewer</groupId> | ||||
|   	<artifactId>com.minres.scviewer.parent</artifactId> | ||||
|   	<version>2.13.0</version> | ||||
|   	<version>2.15.1</version> | ||||
| 	<relativePath>../..</relativePath> | ||||
|   </parent> | ||||
|   <version>3.0.0-SNAPSHOT</version> | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
|   <parent> | ||||
|   	<groupId>com.minres.scviewer</groupId> | ||||
|   	<artifactId>com.minres.scviewer.parent</artifactId> | ||||
|   	<version>2.13.0</version> | ||||
|   	<version>2.15.1</version> | ||||
| 	<relativePath>../..</relativePath> | ||||
|   </parent> | ||||
|   <version>1.1.0-SNAPSHOT</version> | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
|   <parent> | ||||
|   	<groupId>com.minres.scviewer</groupId> | ||||
|   	<artifactId>com.minres.scviewer.parent</artifactId> | ||||
|   	<version>2.13.0</version> | ||||
|   	<version>2.15.1</version> | ||||
| 	<relativePath>../..</relativePath> | ||||
|   </parent> | ||||
|   <version>1.0.0-SNAPSHOT</version> | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
|   <parent> | ||||
|   	<groupId>com.minres.scviewer</groupId> | ||||
|   	<artifactId>com.minres.scviewer.parent</artifactId> | ||||
|   	<version>2.13.0</version> | ||||
|   	<version>2.15.1</version> | ||||
| 	<relativePath>../..</relativePath> | ||||
|   </parent> | ||||
|   <version>1.1.0-SNAPSHOT</version> | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
|   <parent> | ||||
|   	<groupId>com.minres.scviewer</groupId> | ||||
|   	<artifactId>com.minres.scviewer.parent</artifactId> | ||||
|   	<version>2.13.0</version> | ||||
|   	<version>2.15.1</version> | ||||
| 	<relativePath>../..</relativePath> | ||||
|   </parent> | ||||
|   <version>1.1.0-SNAPSHOT</version> | ||||
|   | ||||
| @@ -4,7 +4,7 @@ | ||||
|   <parent> | ||||
|   	<groupId>com.minres.scviewer</groupId> | ||||
|   	<artifactId>com.minres.scviewer.parent</artifactId> | ||||
|   	<version>2.13.0</version> | ||||
|   	<version>2.15.1</version> | ||||
| 	<relativePath>../..</relativePath> | ||||
|   </parent> | ||||
|   <packaging>eclipse-plugin</packaging> | ||||
|   | ||||
| @@ -2,12 +2,12 @@ | ||||
| <classpath> | ||||
| 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"/> | ||||
| 	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> | ||||
| 	<classpathentry kind="src" path="src/"/> | ||||
| 	<classpathentry exported="true" kind="lib" path="lib/mapdb-3.0.7.jar" sourcepath="lib/mapdb-3.0.7-sources.jar"> | ||||
| 		<attributes> | ||||
| 			<attribute name="javadoc_location" value="jar:platform:/resource/com.minres.scviewer.database.text/lib/mapdb-3.0.7-javadoc.jar!/"/> | ||||
| 		</attributes> | ||||
| 	</classpathentry> | ||||
| 	<classpathentry kind="src" path="src"/> | ||||
| 	<classpathentry exported="true" kind="lib" path="lib/kotlin-stdlib-1.2.42.jar"/> | ||||
| 	<classpathentry exported="true" kind="lib" path="lib/lz4-1.3.0.jar"/> | ||||
| 	<classpathentry exported="true" kind="lib" path="lib/elsa-3.0.0-M5.jar"/> | ||||
|   | ||||
| @@ -2,7 +2,7 @@ Manifest-Version: 1.0 | ||||
| Bundle-ManifestVersion: 2 | ||||
| Bundle-Name: Textual transaction database | ||||
| Bundle-SymbolicName: com.minres.scviewer.database.text | ||||
| Bundle-Version: 4.0.0.qualifier | ||||
| Bundle-Version: 4.0.1.qualifier | ||||
| Bundle-Vendor: MINRES Technologies GmbH | ||||
| Bundle-RequiredExecutionEnvironment: JavaSE-11 | ||||
| Import-Package: org.osgi.framework;version="1.3.0" | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="TextDbLoader"> | ||||
|    <implementation class="com.minres.scviewer.database.text.TextDbLoader"/> | ||||
| <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="TextDbLoaderFactory"> | ||||
|    <implementation class="com.minres.scviewer.database.text.TextDbLoaderFactory"/> | ||||
|    <service> | ||||
|       <provide interface="com.minres.scviewer.database.IWaveformDbLoader"/> | ||||
|       <provide interface="com.minres.scviewer.database.IWaveformDbLoaderFactory"/> | ||||
|    </service> | ||||
| </scr:component> | ||||
|   | ||||
| @@ -2,11 +2,11 @@ | ||||
| 	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||||
| 	<modelVersion>4.0.0</modelVersion> | ||||
| 	<artifactId>com.minres.scviewer.database.text</artifactId> | ||||
| 	<version>4.0.0-SNAPSHOT</version> | ||||
| 	<version>4.0.1-SNAPSHOT</version> | ||||
| 	<parent> | ||||
| 		<groupId>com.minres.scviewer</groupId> | ||||
| 		<artifactId>com.minres.scviewer.parent</artifactId> | ||||
| 		<version>2.13.0</version> | ||||
| 		<version>2.15.1</version> | ||||
| 		<relativePath>../..</relativePath> | ||||
| 	</parent> | ||||
| 	<packaging>eclipse-plugin</packaging> | ||||
|   | ||||
| @@ -345,10 +345,10 @@ public class TextDbLoader implements IWaveformDbLoader { | ||||
| 			String curLine = reader.readLine(); | ||||
| 			String nextLine = null; | ||||
| 			while ((nextLine = reader.readLine()) != null && curLine != null) { | ||||
| 				curLine = parseLine(curLine, nextLine); | ||||
| 				curLine = parseLine(curLine, nextLine, false); | ||||
| 			} | ||||
| 			if (curLine != null) | ||||
| 				parseLine(curLine, nextLine); | ||||
| 				parseLine(curLine, nextLine, true); | ||||
| 			for(Entry<Long, ScvTx> e: transactionById.entrySet()) { | ||||
| 				ScvTx scvTx = e.getValue(); | ||||
| 				scvTx.endTime=loader.maxTime; | ||||
| @@ -385,16 +385,16 @@ public class TextDbLoader implements IWaveformDbLoader { | ||||
| 		 * @throws IOException Signals that an I/O exception has occurred. | ||||
| 		 * @throws InputFormatException Signals that the input format is wrong | ||||
| 		 */ | ||||
| 		private String parseLine(String curLine, String nextLine) throws IOException, InputFormatException { | ||||
| 		private String parseLine(String curLine, String nextLine, boolean last) throws IOException, InputFormatException { | ||||
| 			String[] tokens = curLine.split("\\s+"); | ||||
| 			if ("tx_record_attribute".equals(tokens[0])) { | ||||
| 			if ("tx_record_attribute".equals(tokens[0]) && tokens.length>4) { | ||||
| 				Long id = Long.parseLong(tokens[1]); | ||||
| 				String name = tokens[2].substring(1, tokens[2].length()-1); | ||||
| 				DataType type = DataType.valueOf(tokens[3]); | ||||
| 				String remaining = tokens.length > 5 ? String.join(" ", Arrays.copyOfRange(tokens, 5, tokens.length)) : ""; | ||||
| 				TxAttributeType attrType = getAttrType(name, type, AssociationType.RECORD); | ||||
| 				transactionById.get(id).attributes.add(new TxAttribute(attrType, getAttrString(attrType, remaining))); | ||||
| 			} else if ("tx_begin".equals(tokens[0])) { | ||||
| 			} else if ("tx_begin".equals(tokens[0]) && tokens.length>4) { | ||||
| 				Long id = Long.parseLong(tokens[1]); | ||||
| 				Long genId = Long.parseLong(tokens[2]); | ||||
| 				TxGenerator gen = loader.txGenerators.get(genId); | ||||
| @@ -413,7 +413,7 @@ public class TextDbLoader implements IWaveformDbLoader { | ||||
| 					} | ||||
| 				} | ||||
| 				transactionById.put(id, scvTx); | ||||
| 			} else if ("tx_end".equals(tokens[0])) { | ||||
| 			} else if ("tx_end".equals(tokens[0]) && tokens.length>4) { | ||||
| 				Long id = Long.parseLong(tokens[1]); | ||||
| 				ScvTx scvTx = transactionById.get(id); | ||||
| 				assert Long.parseLong(tokens[2]) == scvTx.generatorId; | ||||
| @@ -443,7 +443,7 @@ public class TextDbLoader implements IWaveformDbLoader { | ||||
| 				} | ||||
| 				txSink.put(scvTx.getId(), scvTx); | ||||
| 				transactionById.remove(id); | ||||
| 			} else if ("tx_relation".equals(tokens[0])) { | ||||
| 			} else if ("tx_relation".equals(tokens[0]) && tokens.length>3) { | ||||
| 				Long tr2 = Long.parseLong(tokens[2]); | ||||
| 				Long tr1 = Long.parseLong(tokens[3]); | ||||
| 				String relType = tokens[1].substring(1, tokens[1].length() - 1); | ||||
| @@ -483,7 +483,7 @@ public class TextDbLoader implements IWaveformDbLoader { | ||||
| 				} | ||||
| 			} else if (")".equals(tokens[0])) { | ||||
| 				generator = null; | ||||
| 			} else | ||||
| 			} else if(!last)			 | ||||
| 				throw new InputFormatException("Don't know what to do with: '" + curLine + "'"); | ||||
| 			return nextLine; | ||||
| 		} | ||||
|   | ||||
| @@ -0,0 +1,77 @@ | ||||
| /******************************************************************************* | ||||
|  * Copyright (c) 2012 IT Just working. | ||||
|  * Copyright (c) 2020 MINRES Technologies GmbH | ||||
|  * 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: | ||||
|  *     IT Just working - initial API and implementation | ||||
|  *******************************************************************************/ | ||||
| package com.minres.scviewer.database.text; | ||||
|  | ||||
| import java.io.File; | ||||
| import java.io.FileInputStream; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.util.zip.GZIPInputStream; | ||||
|  | ||||
| import com.minres.scviewer.database.IWaveformDbLoader; | ||||
| import com.minres.scviewer.database.IWaveformDbLoaderFactory; | ||||
|  | ||||
| /** | ||||
|  * The Class TextDbLoader. | ||||
|  */ | ||||
| public class TextDbLoaderFactory implements IWaveformDbLoaderFactory { | ||||
|  | ||||
| 	/** The Constant x. */ | ||||
| 	static final byte[] x = "scv_tr_stream".getBytes(); | ||||
|  | ||||
| 	/** | ||||
| 	 * Checks if f is gzipped. | ||||
| 	 * | ||||
| 	 * @param f the f | ||||
| 	 * @return true, if is gzipped | ||||
| 	 */ | ||||
| 	private static boolean isGzipped(File f) { | ||||
| 		try (InputStream is = new FileInputStream(f)) { | ||||
| 			byte[] signature = new byte[2]; | ||||
| 			int nread = is.read(signature); // read the gzip signature | ||||
| 			return nread == 2 && signature[0] == (byte) 0x1f && signature[1] == (byte) 0x8b; | ||||
| 		} catch (IOException e) { | ||||
| 			return false; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Can load. | ||||
| 	 * | ||||
| 	 * @param inputFile the input file | ||||
| 	 * @return true, if successful | ||||
| 	 */ | ||||
| 	@Override | ||||
| 	public boolean canLoad(File inputFile) { | ||||
| 		if (!inputFile.isDirectory() && inputFile.exists()) { | ||||
| 			boolean gzipped = isGzipped(inputFile); | ||||
| 			try(InputStream stream = gzipped ? new GZIPInputStream(new FileInputStream(inputFile)) : new FileInputStream(inputFile)){ | ||||
| 				byte[] buffer = new byte[x.length]; | ||||
| 				int readCnt = stream.read(buffer, 0, x.length); | ||||
| 				if (readCnt == x.length) { | ||||
| 					for (int i = 0; i < x.length; i++) | ||||
| 						if (buffer[i] != x[i]) | ||||
| 							return false; | ||||
| 				} | ||||
| 				return true; | ||||
| 			} catch (Exception e) { | ||||
| 				return false; | ||||
| 			} | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public IWaveformDbLoader getLoader() { | ||||
| 		return new TextDbLoader(); | ||||
| 	} | ||||
| } | ||||
| @@ -5,7 +5,7 @@ | ||||
|   <parent> | ||||
|   	<groupId>com.minres.scviewer</groupId> | ||||
|   	<artifactId>com.minres.scviewer.parent</artifactId> | ||||
|   	<version>2.13.0</version> | ||||
|   	<version>2.15.1</version> | ||||
| 	<relativePath>../..</relativePath> | ||||
|   </parent> | ||||
|   <version>4.0.0-SNAPSHOT</version> | ||||
|   | ||||
| @@ -27,10 +27,14 @@ import com.minres.scviewer.database.tx.ITx; | ||||
|  | ||||
| public interface IWaveformView extends PropertyChangeListener, ISelectionProvider{ | ||||
|  | ||||
| 	String CURSOR_PROPERTY = "cursor_time"; | ||||
| 	static final String CURSOR_PROPERTY = "cursor_time"; | ||||
| 	 | ||||
| 	String MARKER_PROPERTY = "marker_time"; | ||||
| 	static final String MARKER_PROPERTY = "marker_time"; | ||||
| 	 | ||||
| 	static final int CURSOR_POS = 0; | ||||
| 	 | ||||
| 	static final int MARKER_POS = 1; | ||||
|  | ||||
| 	public static final RelationType NEXT_PREV_IN_STREAM = RelationTypeFactory.create("Prev/Next in stream");  | ||||
|  | ||||
| 	public void addSelectionChangedListener(ISelectionChangedListener listener); | ||||
| @@ -75,23 +79,17 @@ public interface IWaveformView extends PropertyChangeListener, ISelectionProvide | ||||
| 	 | ||||
|     public void setHighliteRelation(RelationType relationType); | ||||
|  | ||||
| 	public long getMaxTime(); | ||||
|  | ||||
| 	public void setMaxTime(long maxTime); | ||||
|  | ||||
| 	public void setZoomLevel(int scale); | ||||
|  | ||||
| 	public int getZoomLevel(); | ||||
|  | ||||
| 	public void setCursorTime(long time); | ||||
|  | ||||
| 	public void setMarkerTime(long time, int index); | ||||
| 	public void setMarkerTime(int marker, long time); | ||||
|  | ||||
| 	public long getCursorTime(); | ||||
|  | ||||
| 	public int getSelectedMarkerId(); | ||||
| 	public int getSelectedMarker(); | ||||
|  | ||||
| 	public long getMarkerTime(int index); | ||||
| 	public long getMarkerTime(int marker); | ||||
|  | ||||
| 	public void addPropertyChangeListener(PropertyChangeListener listener); | ||||
|  | ||||
| @@ -101,21 +99,18 @@ public interface IWaveformView extends PropertyChangeListener, ISelectionProvide | ||||
|  | ||||
| 	public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener); | ||||
|  | ||||
| 	public String getScaledTime(long time); | ||||
|  | ||||
| 	public String[] getZoomLevels(); | ||||
|  | ||||
| 	public List<ICursor> getCursorList(); | ||||
|  | ||||
| 	public long getBaselineTime(); | ||||
|  | ||||
| 	public void setBaselineTime(Long scale); | ||||
| 	 | ||||
| 	public void scrollHorizontal(int percent); | ||||
| 	 | ||||
| 	public void scrollTo(int pos); | ||||
| 	 | ||||
| 	public void addDisposeListener( DisposeListener listener ); | ||||
|  | ||||
| 	public void deleteSelectedTracks(); | ||||
|  | ||||
| 	public TrackEntry addWaveform(IWaveform waveform, int pos); | ||||
|  | ||||
| 	public IWaveformZoom getWaveformZoom(); | ||||
| 	 | ||||
| } | ||||
| @@ -0,0 +1,24 @@ | ||||
| package com.minres.scviewer.database.ui; | ||||
|  | ||||
| public interface IWaveformZoom { | ||||
| 	 | ||||
| 	long getMaxVisibleTime(); | ||||
|  | ||||
| 	long getMinVisibleTime(); | ||||
|  | ||||
| 	void setMinVisibleTime(long scale); | ||||
|  | ||||
| 	long getMaxTime(); | ||||
|  | ||||
| 	long getScale(); | ||||
|  | ||||
| 	void setScale(long factor); | ||||
|  | ||||
| 	void setVisibleRange(long startTime, long endTime); | ||||
| 	 | ||||
| 	void centerAt(long time); | ||||
| 	 | ||||
| 	void zoom(ZoomKind kind); | ||||
|  | ||||
| 	String timeToString(long time); | ||||
| } | ||||
| @@ -0,0 +1,3 @@ | ||||
| package com.minres.scviewer.database.ui; | ||||
|  | ||||
| public enum ZoomKind {IN, OUT, FIT, FULL} | ||||
| @@ -1,14 +1,49 @@ | ||||
| package com.minres.scviewer.database.ui.swt; | ||||
|  | ||||
| import java.text.DecimalFormat; | ||||
|  | ||||
| public class Constants { | ||||
|  | ||||
| 	public static final String[] UNIT_STRING={"fs", "ps", "ns", "us", "ms"};//, "s"}; | ||||
|      | ||||
|     public static final int[] UNIT_MULTIPLIER={1, 3, 10, 30, 100, 300}; | ||||
| 	public static final String[] UNIT_STRING={"fs", "ps", "ns", "us", "ms", "s"}; | ||||
| 	public static final long[]   UNIT_MULTIPLIER={1l, 1000l, 1000l*1000, 1000l*1000*1000, 1000l*1000*1000*1000, 1000l*1000*1000*1000*1000 }; | ||||
|  | ||||
|     //public static final int[] UNIT_MULTIPLIER={1, 3, 10, 30, 100, 300}; | ||||
|     public static final long[] SCALE_MULTIPLIER={1, 2, 5, 10, 20, 50, 100, 200, 500}; | ||||
|  | ||||
| 	public static final String CONTENT_PROVIDER_TAG = "TOOLTIP_CONTENT_PROVIDER"; | ||||
| 	public static final String HELP_PROVIDER_TAG = "TOOLTIP_HELP_PROVIDER"; | ||||
| 	 | ||||
| 	public static final DecimalFormat TIME_FORMAT_FS  = new DecimalFormat("#");  | ||||
| 	public static final DecimalFormat TIME_FORMAT_PS  = new DecimalFormat("#");  | ||||
| 	public static final DecimalFormat TIME_FORMAT_NS  = new DecimalFormat("#.0##");  | ||||
| 	public static final DecimalFormat TIME_FORMAT_UMS = new DecimalFormat("#.0#####");  | ||||
| 	public static final long[] POWERS_OF_TEN = { | ||||
| 			1L, | ||||
| 			10L, | ||||
| 			100L, | ||||
| 			1_000L, | ||||
| 			10_000L, | ||||
| 			100_000L, | ||||
| 			1_000_000L, | ||||
| 			10_000_000L, | ||||
| 			100_000_000L, | ||||
| 			1_000_000_000L, | ||||
| 			10_000_000_000L, | ||||
| 			100_000_000_000L, | ||||
| 			1_000_000_000_000L, | ||||
| 			10_000_000_000_000L, | ||||
| 			100_000_000_000_000L, | ||||
| 			1_000_000_000_000_000L}; | ||||
|  | ||||
| 	public static  DecimalFormat getTimeFormatForLevel(int idx) { | ||||
| 		switch(idx) { | ||||
| 		case 0:	return TIME_FORMAT_FS; | ||||
| 		case 1:	return TIME_FORMAT_PS; | ||||
| 		case 2:	return TIME_FORMAT_NS; | ||||
| 		default: | ||||
| 			return TIME_FORMAT_UMS; | ||||
| 		} | ||||
| 	} | ||||
| 	private Constants() {} | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -13,6 +13,7 @@ package com.minres.scviewer.database.ui.swt; | ||||
| import org.eclipse.core.runtime.IStatus; | ||||
| import org.eclipse.core.runtime.Plugin; | ||||
| import org.eclipse.core.runtime.Status; | ||||
| import org.eclipse.wb.swt.SWTResourceManager; | ||||
| import org.osgi.framework.BundleContext; | ||||
|  | ||||
| public class DatabaseUiPlugin extends Plugin { | ||||
| @@ -24,6 +25,7 @@ public class DatabaseUiPlugin extends Plugin { | ||||
|  | ||||
| 	@Override | ||||
| 	public void stop(BundleContext context) throws Exception { | ||||
| 		SWTResourceManager.dispose(); | ||||
| 		getLog().log(new Status(IStatus.OK, "org.eclipse.e4.core", "Stopping org.eclipse.e4.core bundle...")); | ||||
| 	} | ||||
| } | ||||
| @@ -24,7 +24,6 @@ import org.eclipse.swt.graphics.Rectangle; | ||||
| import org.eclipse.swt.widgets.Display; | ||||
|  | ||||
| import com.minres.scviewer.database.IEvent; | ||||
| import com.minres.scviewer.database.IHierNode; | ||||
| import com.minres.scviewer.database.IWaveform; | ||||
| import com.minres.scviewer.database.RelationType; | ||||
| import com.minres.scviewer.database.tx.ITx; | ||||
| @@ -76,7 +75,7 @@ public class ArrowPainter implements IPainter { | ||||
| 		this.tx = newTx; | ||||
| 		iRect = new LinkedList<>(); | ||||
| 		oRect = new LinkedList<>(); | ||||
| 		scaleFactor = waveCanvas.getScaleFactor(); | ||||
| 		scaleFactor = waveCanvas.getScale(); | ||||
| 		if (tx != null) { | ||||
| 			calculateGeometries(); | ||||
| 		} | ||||
| @@ -110,48 +109,23 @@ public class ArrowPainter implements IPainter { | ||||
| 	protected void deriveGeom(Collection<ITxRelation> relations, List<LinkEntry> res, boolean useTarget) { | ||||
| 		for (ITxRelation iTxRelation : relations) { | ||||
| 			ITx otherTx = useTarget ? iTxRelation.getTarget() : iTxRelation.getSource(); | ||||
| 			Rectangle bb = createLinkEntry(otherTx, otherTx.getStream()); | ||||
| 			if(bb!=null){ | ||||
| 				res.add(new LinkEntry(bb, iTxRelation.getRelationType())); | ||||
| 				return; | ||||
| 			} else { | ||||
| 				for(IHierNode gen:otherTx.getStream().getChildNodes()) { | ||||
| 					if(gen instanceof IWaveform) { | ||||
| 						bb = createLinkEntry(otherTx, (IWaveform) gen); | ||||
| 						if(bb!=null){ | ||||
| 							res.add(new LinkEntry(bb, iTxRelation.getRelationType())); | ||||
| 							return; | ||||
| 						} | ||||
| 			for(IWaveform iWaveform: new IWaveform[]{otherTx.getStream(), otherTx.getGenerator()}) { | ||||
| 				if (waveCanvas.wave2painterMap.containsKey(iWaveform)) { | ||||
| 					IWaveformPainter painter = waveCanvas.wave2painterMap.get(iWaveform); | ||||
| 					if(painter!=null) { | ||||
| 						int height = waveCanvas.styleProvider.getTrackHeight(); | ||||
| 						Rectangle bb = new Rectangle( | ||||
| 								(int) (otherTx.getBeginTime() / scaleFactor), | ||||
| 								waveCanvas.rulerHeight + painter.getVerticalOffset() + height * getConcurrencyIndex(otherTx), | ||||
| 								(int) ((otherTx.getEndTime() - otherTx.getBeginTime()) / scaleFactor), | ||||
| 								height); | ||||
| 						res.add(new LinkEntry(bb, iTxRelation.getRelationType()));				 | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	private Rectangle createLinkEntry(ITx otherTx, IWaveform iWaveform) { | ||||
| 		if (waveCanvas.wave2painterMap.containsKey(iWaveform)) { | ||||
| 			IWaveformPainter painter = waveCanvas.wave2painterMap.get(otherTx.getStream()); | ||||
| 			if(painter==null) { | ||||
| 				for(IHierNode gen:otherTx.getStream().getChildNodes()) { | ||||
| 					if(gen instanceof IWaveform) { | ||||
| 						 painter = waveCanvas.wave2painterMap.get(gen); | ||||
| 						 if(painter!=null) | ||||
| 							 break; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			if(painter!=null) { | ||||
| 				int height = waveCanvas.styleProvider.getTrackHeight(); | ||||
| 				return new Rectangle( | ||||
| 						(int) (otherTx.getBeginTime() / scaleFactor), | ||||
| 						waveCanvas.rulerHeight + painter.getVerticalOffset() + height * getConcurrencyIndex(otherTx), | ||||
| 						(int) ((otherTx.getEndTime() - otherTx.getBeginTime()) / scaleFactor), | ||||
| 						height); | ||||
| 			} | ||||
| 		} | ||||
| 		return null; | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public void paintArea(Projection proj, Rectangle clientRect) { | ||||
| 		yCtrlOffset = waveCanvas.styleProvider.getTrackHeight()/2; | ||||
| @@ -159,7 +133,7 @@ public class ArrowPainter implements IPainter { | ||||
| 		Color highliteColor = waveCanvas.styleProvider.getColor(WaveformColors.REL_ARROW_HIGHLITE); | ||||
|  | ||||
| 		if(tx==null) return; | ||||
| 		scaleFactor = waveCanvas.getScaleFactor(); | ||||
| 		scaleFactor = waveCanvas.getScale(); | ||||
| 		if(calculateGeometries()) | ||||
| 			return; | ||||
| 		int correctionValue = (int)(selectionOffset); | ||||
|   | ||||
| @@ -65,7 +65,7 @@ public class CursorPainter implements IPainter, ICursor { | ||||
| 		Rectangle area = proj.unProject(clientRect); | ||||
| 		if(!waveCanvas.painterList.isEmpty()){ | ||||
| 			 | ||||
| 			long scaleFactor=waveCanvas.getScaleFactor(); | ||||
| 			long scaleFactor=waveCanvas.getScale(); | ||||
| 			long beginPos = area.x; | ||||
| 			 | ||||
| 			maxPosX = area.x + area.width; | ||||
| @@ -83,8 +83,7 @@ public class CursorPainter implements IPainter, ICursor { | ||||
| 				proj.drawLine(x, top, x, area.y+area.height); | ||||
| 				proj.setBackground(drawColor); | ||||
| 				proj.setForeground(textColor); | ||||
| 				double dTime=time; | ||||
| 				proj.drawText((dTime/waveCanvas.getScaleFactorPow10())+waveCanvas.getUnitStr(), x+1, top); | ||||
| 				proj.drawText(waveCanvas.timeToString(time), x+1, top); | ||||
| 			} | ||||
| 		} | ||||
| 	}	 | ||||
|   | ||||
| @@ -10,22 +10,21 @@ | ||||
|  *******************************************************************************/ | ||||
| package com.minres.scviewer.database.ui.swt.internal; | ||||
|  | ||||
| import java.text.DecimalFormat; | ||||
|  | ||||
| import org.eclipse.swt.SWT; | ||||
| import org.eclipse.swt.graphics.Color; | ||||
| import org.eclipse.swt.graphics.GC; | ||||
| import org.eclipse.swt.graphics.Point; | ||||
| import org.eclipse.swt.graphics.Rectangle; | ||||
| import org.eclipse.wb.swt.SWTResourceManager; | ||||
|  | ||||
| import com.minres.scviewer.database.ui.swt.Constants; | ||||
|  | ||||
| public class RulerPainter implements IPainter { | ||||
|     protected final WaveformCanvas waveCanvas; | ||||
|      | ||||
|     static final int RULER_TICK_MINOR = 10; | ||||
|     static final int RULER_TICK_MAJOR = 100; | ||||
|         | ||||
| 	static final DecimalFormat df = new DecimalFormat("#.00####");  | ||||
|  | ||||
|     public RulerPainter(WaveformCanvas waveCanvas) { | ||||
|         this.waveCanvas=waveCanvas; | ||||
|     } | ||||
| @@ -39,26 +38,26 @@ public class RulerPainter implements IPainter { | ||||
|     	Color headerBgColor = waveCanvas.getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND); | ||||
|     	if(headerBgColor.isDisposed()) | ||||
|     		headerBgColor=SWTResourceManager.getColor(255,255,255); | ||||
|         String unit=waveCanvas.getUnitStr(); | ||||
|         int unitMultiplier=waveCanvas.getUnitMultiplier(); | ||||
|         long scaleFactor=waveCanvas.getScaleFactor(); | ||||
|  | ||||
|         long startPos=area.x*scaleFactor;  | ||||
|         long startVal=startPos - proj.getTranslation().x*scaleFactor; | ||||
|         long endPos=startPos+area.width*scaleFactor; | ||||
|  | ||||
|         long rulerTickMinor = RULER_TICK_MINOR*scaleFactor; | ||||
|         long rulerTickMajor = RULER_TICK_MAJOR*scaleFactor; | ||||
|     	 | ||||
|         long scaleFactor=waveCanvas.getScale(); | ||||
|         long startTime=waveCanvas.getMinVisibleTime();  | ||||
|         long endTime=waveCanvas.getMaxVisibleTime(); | ||||
|  | ||||
|         long multiplier = Constants.POWERS_OF_TEN[waveCanvas.getScaleMagnitude()]; | ||||
|         long rulerTickMinor = RULER_TICK_MINOR*multiplier; | ||||
|         long rulerTickMajor = RULER_TICK_MAJOR*multiplier; | ||||
|         if((endTime-startTime)/rulerTickMinor>area.width/5) { | ||||
|         	rulerTickMinor*=10; | ||||
|         	rulerTickMajor*=10; | ||||
|         } | ||||
|         int minorTickY = waveCanvas.rulerHeight-5; | ||||
|         int majorTickY = waveCanvas.rulerHeight-15; | ||||
|         int textY=waveCanvas.rulerHeight-20; | ||||
|         int textY=waveCanvas.rulerHeight-30; | ||||
|         int baselineY=waveCanvas.rulerHeight - 1; | ||||
|         int bottom=waveCanvas.rulerHeight - 2; | ||||
|  | ||||
|         long modulo = startVal % rulerTickMinor; | ||||
|         long startMinorIncrPos = startPos+rulerTickMinor-modulo; | ||||
|         long startMinorIncrVal = startVal+rulerTickMinor-modulo; | ||||
|         long startTickTime = startTime+rulerTickMinor-(startTime % rulerTickMinor); | ||||
|         long majorTickDist = rulerTickMajor/scaleFactor; | ||||
|          | ||||
|         gc.setBackground(waveCanvas.getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND)); | ||||
|         gc.fillRectangle(new Rectangle(area.x, area.y, area.width, waveCanvas.rulerHeight)); | ||||
| @@ -66,13 +65,22 @@ public class RulerPainter implements IPainter { | ||||
|         gc.fillRectangle(new Rectangle(area.x, area.y, area.width, baselineY)); | ||||
|         gc.setForeground(headerFgColor); | ||||
|         gc.drawLine(area.x, area.y+bottom, area.x+area.width, area.y+bottom); | ||||
|          | ||||
|         for (long pos = startMinorIncrPos, tick = startMinorIncrVal; pos < endPos; pos+= rulerTickMinor, tick += rulerTickMinor) { | ||||
|             int x0Pos = (int) (pos/scaleFactor); | ||||
|             long x0Val = tick/scaleFactor; | ||||
|             if ((tick % rulerTickMajor) == 0) { | ||||
|                 gc.drawText(df.format(x0Val*unitMultiplier)+unit, x0Pos, area.y+textY); | ||||
|         int maxTextLength=0; | ||||
|         for (long tickTime = startTickTime; tickTime < endTime; tickTime+= rulerTickMinor) { | ||||
|             if ((tickTime % rulerTickMajor) == 0) { | ||||
|             	Point textSize = gc.textExtent(waveCanvas.timeToString(tickTime)); | ||||
|             	maxTextLength=textSize.x>maxTextLength?textSize.x:maxTextLength; | ||||
|             } | ||||
|         } | ||||
|         boolean drawEvery = majorTickDist>maxTextLength; | ||||
|         boolean drawText=true; | ||||
|         for (long tickTime = startTickTime; tickTime < endTime; tickTime+= rulerTickMinor) { | ||||
|             int x0Pos = (int) (tickTime/scaleFactor) + proj.getTranslation().x; | ||||
|             if ((tickTime % rulerTickMajor) == 0) { | ||||
|             	if(drawEvery ||  drawText) | ||||
|             		gc.drawText(waveCanvas.timeToString(tickTime), x0Pos, area.y+textY); | ||||
|                 gc.drawLine(x0Pos, area.y+majorTickY, x0Pos,area.y+ bottom); | ||||
|                 drawText=!drawText; | ||||
|             } else { | ||||
|                 gc.drawLine(x0Pos, area.y+minorTickY, x0Pos, area.y+bottom); | ||||
|             } | ||||
|   | ||||
| @@ -82,7 +82,7 @@ public class SignalPainter extends TrackPainter { | ||||
| 	} | ||||
|  | ||||
| 	private int getXPosEnd(long time) { | ||||
| 		long ltmp = time / this.waveCanvas.getScaleFactor(); | ||||
| 		long ltmp = time / this.waveCanvas.getScale(); | ||||
| 		return ltmp > maxPosX ? maxPosX : (int) ltmp; | ||||
| 	} | ||||
| 	 | ||||
| @@ -95,7 +95,7 @@ public class SignalPainter extends TrackPainter { | ||||
| 		proj.setFillRule(SWT.FILL_EVEN_ODD); | ||||
| 		proj.fillRectangle(area); | ||||
|  | ||||
| 		long scaleFactor = this.waveCanvas.getScaleFactor(); | ||||
| 		long scaleFactor = this.waveCanvas.getScale(); | ||||
| 		long beginPos = area.x; | ||||
| 		long beginTime = beginPos*scaleFactor; | ||||
|         long endTime = beginTime + area.width*scaleFactor; | ||||
| @@ -114,7 +114,7 @@ public class SignalPainter extends TrackPainter { | ||||
| 		yOffsetT = this.waveCanvas.styleProvider.getTrackHeight() / 5 + area.y; | ||||
| 		yOffsetM = this.waveCanvas.styleProvider.getTrackHeight() / 2 + area.y; | ||||
| 		yOffsetB = 4 * this.waveCanvas.styleProvider.getTrackHeight() / 5 + area.y; | ||||
| 		int xSigChangeBeginVal = Math.max(area.x, (int) (left.time / this.waveCanvas.getScaleFactor())); | ||||
| 		int xSigChangeBeginVal = Math.max(area.x, (int) (left.time / this.waveCanvas.getScale())); | ||||
| 		int xSigChangeBeginPos = area.x; | ||||
| 		int xSigChangeEndPos = Math.max(area.x, getXPosEnd(right.time)); | ||||
| 		 | ||||
| @@ -127,7 +127,7 @@ public class SignalPainter extends TrackPainter { | ||||
| 				right.time = endTime; | ||||
| 			} else { | ||||
| 				multiple = true; | ||||
| 				long eTime = (xSigChangeBeginVal + 1) * this.waveCanvas.getScaleFactor(); | ||||
| 				long eTime = (xSigChangeBeginVal + 1) * this.waveCanvas.getScale(); | ||||
| 				right.set(entries.floorEntry(eTime), endTime); | ||||
| 				right.time = eTime; | ||||
| 			} | ||||
| @@ -147,7 +147,7 @@ public class SignalPainter extends TrackPainter { | ||||
| 			multiple = false; | ||||
| 			if (xSigChangeEndPos == xSigChangeBeginPos) { | ||||
| 				multiple = true; | ||||
| 				long eTime = (xSigChangeBeginPos + 1) * this.waveCanvas.getScaleFactor(); | ||||
| 				long eTime = (xSigChangeBeginPos + 1) * this.waveCanvas.getScale(); | ||||
| 				EventEntry entry = entries.floorEntry(eTime); | ||||
| 				if(entry!=null && entry.timestamp> right.time) | ||||
| 					right.set(entry, endTime); | ||||
|   | ||||
| @@ -67,7 +67,7 @@ public class StreamPainter extends TrackPainter{ | ||||
| 		proj.setFillRule(SWT.FILL_EVEN_ODD); | ||||
| 		proj.fillRectangle(area); | ||||
|  | ||||
| 		long scaleFactor = this.waveCanvas.getScaleFactor(); | ||||
| 		long scaleFactor = this.waveCanvas.getScale(); | ||||
| 		long beginPos = area.x; | ||||
| 		long beginTime = beginPos*scaleFactor; | ||||
| 		long endTime = beginTime + area.width*scaleFactor; | ||||
| @@ -130,8 +130,8 @@ public class StreamPainter extends TrackPainter{ | ||||
|  | ||||
| 		int offset = concurrencyIndex*this.waveCanvas.styleProvider.getTrackHeight(); | ||||
| 		Rectangle bb = new Rectangle( | ||||
| 				(int)(tx.getBeginTime()/this.waveCanvas.getScaleFactor()), area.y+offset+txBase, | ||||
| 				(int)((tx.getEndTime()-tx.getBeginTime())/this.waveCanvas.getScaleFactor()), txHeight); | ||||
| 				(int)(tx.getBeginTime()/this.waveCanvas.getScale()), area.y+offset+txBase, | ||||
| 				(int)((tx.getEndTime()-tx.getBeginTime())/this.waveCanvas.getScale()), txHeight); | ||||
|  | ||||
| 		if(bb.x+bb.width<area.x || bb.x>area.x+area.width) return; | ||||
| 		if(bb.width==0){ | ||||
| @@ -155,7 +155,7 @@ public class StreamPainter extends TrackPainter{ | ||||
|  | ||||
| 	public ITx getClicked(Point point) { | ||||
| 		int lane=point.y/waveCanvas.styleProvider.getTrackHeight(); | ||||
| 		EventEntry firstTx=stream.getEvents().floorEntry(point.x*waveCanvas.getScaleFactor()); | ||||
| 		EventEntry firstTx=stream.getEvents().floorEntry(point.x*waveCanvas.getScale()); | ||||
| 		if(firstTx!=null){ | ||||
| 			do { | ||||
| 				ITx tx = getTxFromEntry(lane, point.x, firstTx.events); | ||||
| @@ -175,9 +175,9 @@ public class StreamPainter extends TrackPainter{ | ||||
| 	} | ||||
|  | ||||
| 	protected ITx getTxFromEntry(int lane, int offset, IEvent[] firstTx) { | ||||
| 		long timePoint=offset*waveCanvas.getScaleFactor(); | ||||
| 		long timePointLow=(offset-5)*waveCanvas.getScaleFactor(); | ||||
| 		long timePointHigh=(offset+5)*waveCanvas.getScaleFactor(); | ||||
| 		long timePoint=offset*waveCanvas.getScale(); | ||||
| 		long timePointLow=(offset-5)*waveCanvas.getScale(); | ||||
| 		long timePointHigh=(offset+5)*waveCanvas.getScale(); | ||||
| 		for(IEvent e:firstTx){ | ||||
| 			if(e instanceof ITxEvent) { | ||||
| 				ITxEvent evt = (ITxEvent) e; | ||||
|   | ||||
| @@ -19,7 +19,7 @@ import org.eclipse.swt.graphics.Rectangle; | ||||
| import com.minres.scviewer.database.ui.WaveformColors; | ||||
|  | ||||
| public class TrackAreaPainter implements IPainter { | ||||
| 	 | ||||
|  | ||||
| 	/** | ||||
| 	 *  | ||||
| 	 */ | ||||
| @@ -35,14 +35,15 @@ public class TrackAreaPainter implements IPainter { | ||||
| 	} | ||||
|  | ||||
| 	public void paintArea(Projection proj, Rectangle a) { | ||||
| 	    Rectangle area = proj.unProject(new Rectangle(a.x, a.y+waveCanvas.rulerHeight, a.width, a.height-waveCanvas.rulerHeight)); | ||||
| 	    proj.setBackground(this.waveCanvas.styleProvider.getColor(WaveformColors.TRACK_BG_EVEN)); | ||||
| 	    proj.setFillRule(SWT.FILL_EVEN_ODD); | ||||
| 	    proj.fillRectangle(area); | ||||
| 		Rectangle area = proj.unProject(new Rectangle(a.x, a.y+waveCanvas.rulerHeight, a.width, a.height-waveCanvas.rulerHeight)); | ||||
| 		proj.setBackground(this.waveCanvas.styleProvider.getColor(WaveformColors.TRACK_BG_EVEN)); | ||||
| 		proj.setFillRule(SWT.FILL_EVEN_ODD); | ||||
| 		proj.fillRectangle(area); | ||||
| 		if(trackVerticalOffset.size()>0){ | ||||
| 			Integer firstKey=trackVerticalOffset.floorKey(area.y); | ||||
| 			if(firstKey==null) firstKey=trackVerticalOffset.firstKey(); | ||||
| 			Integer lastKey = trackVerticalOffset.floorKey(area.y+area.height); | ||||
| 			//if(lastKey==null) lastKey= trackVerticalOffset.lastKey(); | ||||
| 			Rectangle subArea = new Rectangle(area.x, 0, area.width, 0); | ||||
| 			if(lastKey.equals(firstKey)){ | ||||
| 				subArea.y=firstKey; | ||||
| @@ -61,9 +62,9 @@ public class TrackAreaPainter implements IPainter { | ||||
|  | ||||
| 	public void addTrackPainter(IWaveformPainter trackPainter){ | ||||
| 		trackVerticalOffset.put(trackPainter.getVerticalOffset()+waveCanvas.rulerHeight, trackPainter); | ||||
| 		 | ||||
|  | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	public int getHeight(){ | ||||
| 		if(trackVerticalOffset.size()==0) return 1; | ||||
| 		return trackVerticalOffset.lastKey() + trackVerticalOffset.lastEntry().getValue().getHeight(); | ||||
|   | ||||
| @@ -42,32 +42,39 @@ import com.minres.scviewer.database.tx.ITx; | ||||
| import com.minres.scviewer.database.tx.ITxEvent; | ||||
| import com.minres.scviewer.database.ui.IWaveformStyleProvider; | ||||
| import com.minres.scviewer.database.ui.IWaveformView; | ||||
| import com.minres.scviewer.database.ui.IWaveformZoom; | ||||
| import com.minres.scviewer.database.ui.TrackEntry; | ||||
| import com.minres.scviewer.database.ui.ZoomKind; | ||||
| import com.minres.scviewer.database.ui.swt.Constants; | ||||
| import com.minres.scviewer.database.ui.swt.internal.slider.ZoomBar; | ||||
|  | ||||
| public class WaveformCanvas extends Canvas { | ||||
| public class WaveformCanvas extends Canvas implements IWaveformZoom{ | ||||
|  | ||||
| 	public static final long ZOOM_FIT = -2; | ||||
|  | ||||
| 	public static final long ZOOM_FULL = -1; | ||||
|  | ||||
| 	private static final int INITIAL_ZOOM_BAR_MAX = 1000; | ||||
| 	 | ||||
|     private boolean doubleBuffering = true; | ||||
|     	 | ||||
|     IWaveformStyleProvider styleProvider; | ||||
|          | ||||
|     private long scaleFactor = 1000000L; // 1ns | ||||
|      | ||||
|     String unit="ns"; | ||||
|      | ||||
|     private int level = 12; | ||||
|          | ||||
|     private long maxTime; | ||||
|      | ||||
|     protected Point origin; /* original size */ | ||||
|          | ||||
|     protected int rulerHeight=40; | ||||
|      | ||||
|     protected List<IPainter> painterList; | ||||
|      | ||||
|     ITx currentSelection; | ||||
|      | ||||
|     private List<SelectionAdapter> selectionListeners; | ||||
| 	private boolean doubleBuffering = true; | ||||
|  | ||||
| 	IWaveformStyleProvider styleProvider; | ||||
|  | ||||
| 	private int scaleMagnitude = 6; | ||||
|  | ||||
| 	private long scaleFactor = Constants.POWERS_OF_TEN[scaleMagnitude]; | ||||
|  | ||||
| 	private long maxTime; | ||||
|  | ||||
| 	protected Point origin; /* original size */ | ||||
|  | ||||
| 	protected int rulerHeight=40; | ||||
|  | ||||
| 	protected List<IPainter> painterList; | ||||
|  | ||||
| 	ITx currentSelection; | ||||
|  | ||||
| 	private List<SelectionAdapter> selectionListeners; | ||||
|  | ||||
| 	private RulerPainter rulerPainter; | ||||
|  | ||||
| @@ -77,446 +84,525 @@ public class WaveformCanvas extends Canvas { | ||||
|  | ||||
| 	private List<CursorPainter> cursorPainters; | ||||
|  | ||||
| 	private ZoomBar horizontal; | ||||
|  | ||||
| 	private int[] lastHorSelection; | ||||
| 	 | ||||
| 	private long sliderScaleFactor = 1; | ||||
| 	 | ||||
| 	private ScrollBar vertical; | ||||
|  | ||||
| 	HashMap<IWaveform, IWaveformPainter> wave2painterMap; | ||||
|     /** | ||||
|      * Constructor for ScrollableCanvas. | ||||
|      *  | ||||
|      * @param parent | ||||
|      *            the parent of this control.super(parent, style | SWT.DOUBLE_BUFFERED | SWT.NO_BACKGROUND | SWT.NO_REDRAW_RESIZE | SWT.V_SCROLL | SWT.H_SCROLL); | ||||
|      * @param style | ||||
|      *            the style of this control. | ||||
|      */ | ||||
|     public WaveformCanvas(final Composite parent, int style, IWaveformStyleProvider styleProvider) { | ||||
|         super(parent, style | SWT.DOUBLE_BUFFERED | SWT.NO_BACKGROUND | SWT.V_SCROLL | SWT.H_SCROLL); | ||||
|         this.styleProvider=styleProvider; | ||||
|     	addControlListener(new ControlAdapter() { /* resize listener. */ | ||||
|  | ||||
| 	public WaveformCanvas(final Composite parent, int style, IWaveformStyleProvider styleProvider, ZoomBar.IProvider scrollbarProvider) { | ||||
| 		super(parent, (style & ~SWT.H_SCROLL) | SWT.DOUBLE_BUFFERED | SWT.NO_BACKGROUND | SWT.V_SCROLL ); | ||||
| 		this.styleProvider=styleProvider; | ||||
| 		addControlListener(new ControlAdapter() { /* resize listener. */ | ||||
| 			@Override | ||||
| 			public void controlResized(ControlEvent event) { | ||||
|                 syncScrollBars(); | ||||
|             } | ||||
|         }); | ||||
|         addPaintListener((final PaintEvent event) -> paint(event.gc)); | ||||
|         painterList = new LinkedList<>(); | ||||
|         origin = new Point(0, 0); | ||||
|         selectionListeners = new LinkedList<>(); | ||||
|         cursorPainters= new ArrayList<>(); | ||||
|         wave2painterMap=new HashMap<>(); | ||||
|          | ||||
|         initScrollBars(); | ||||
| 				syncSb(); | ||||
| 			} | ||||
| 		}); | ||||
| 		addPaintListener((final PaintEvent event) -> paint(event.gc)); | ||||
| 		painterList = new LinkedList<>(); | ||||
| 		origin = new Point(0, 0); | ||||
| 		selectionListeners = new LinkedList<>(); | ||||
| 		cursorPainters= new ArrayList<>(); | ||||
| 		wave2painterMap=new HashMap<>(); | ||||
|  | ||||
| 		horizontal = scrollbarProvider.getScrollBar(); | ||||
| 		vertical = getVerticalBar(); | ||||
| 		initScrollBars(); | ||||
| 		// order is important: it is bottom to top | ||||
|         trackAreaPainter=new TrackAreaPainter(this); | ||||
|         painterList.add(trackAreaPainter); | ||||
|         arrowPainter=new ArrowPainter(this, IWaveformView.NEXT_PREV_IN_STREAM); | ||||
|         painterList.add(arrowPainter); | ||||
|         rulerPainter=new RulerPainter(this); | ||||
|         painterList.add(rulerPainter); | ||||
| 		CursorPainter cp = new CursorPainter(this, scaleFactor * 10, cursorPainters.size()-1); | ||||
| 		trackAreaPainter=new TrackAreaPainter(this); | ||||
| 		painterList.add(trackAreaPainter); | ||||
| 		arrowPainter=new ArrowPainter(this, IWaveformView.NEXT_PREV_IN_STREAM); | ||||
| 		painterList.add(arrowPainter); | ||||
| 		rulerPainter=new RulerPainter(this); | ||||
| 		painterList.add(rulerPainter); | ||||
| 		CursorPainter cp = new CursorPainter(this, getScale() * 10, cursorPainters.size()-1); | ||||
| 		painterList.add(cp); | ||||
| 		cursorPainters.add(cp); | ||||
| 		CursorPainter marker = new CursorPainter(this, scaleFactor * 100, cursorPainters.size()-1); | ||||
| 		CursorPainter marker = new CursorPainter(this, getScale() * 100, cursorPainters.size()-1); | ||||
| 		painterList.add(marker); | ||||
| 		cursorPainters.add(marker); | ||||
| 		wave2painterMap=new HashMap<>(); | ||||
|     } | ||||
|      | ||||
| 	} | ||||
|  | ||||
| 	public void addCursoPainter(CursorPainter cursorPainter){ | ||||
| 		painterList.add(cursorPainter); | ||||
| 		cursorPainters.add(cursorPainter); | ||||
| 	} | ||||
| 	 | ||||
|     public void setHighliteRelation(RelationType relationType){ | ||||
|     	if(arrowPainter!=null){ | ||||
|     		boolean redraw = arrowPainter.getHighlightType()!=relationType;  | ||||
|     		arrowPainter.setHighlightType(relationType); | ||||
|     		if(redraw) redraw(); | ||||
|     	} | ||||
|     } | ||||
|      | ||||
|     public Point getOrigin() { | ||||
|         return origin; | ||||
|     } | ||||
|  | ||||
|     public int getWidth() { | ||||
|     	return getClientArea().width;  | ||||
|     } | ||||
|     public void setOrigin(Point origin) { | ||||
|         setOrigin(origin.x, origin.y); | ||||
|     } | ||||
| 	public void setHighliteRelation(RelationType relationType){ | ||||
| 		if(arrowPainter!=null){ | ||||
| 			boolean redraw = arrowPainter.getHighlightType()!=relationType;  | ||||
| 			arrowPainter.setHighlightType(relationType); | ||||
| 			if(redraw) redraw(); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|     public void setOrigin(int x, int y) { | ||||
|         checkWidget(); | ||||
|         ScrollBar hBar = getHorizontalBar(); | ||||
|         hBar.setSelection(-x); | ||||
|         x = -hBar.getSelection(); | ||||
|         ScrollBar vBar = getVerticalBar(); | ||||
|         vBar.setSelection(-y); | ||||
|         y = -vBar.getSelection(); | ||||
|         origin.x = x; | ||||
|         origin.y = y; | ||||
|         syncScrollBars(); | ||||
|     } | ||||
| 	public Point getOrigin() { | ||||
| 		return origin; | ||||
| 	} | ||||
|  | ||||
|     public long getMaxTime() { | ||||
|         return maxTime; | ||||
|     } | ||||
| 	public int getWidth() { | ||||
| 		return getClientArea().width;  | ||||
| 	} | ||||
| 	public void setOrigin(Point origin) { | ||||
| 		setOrigin(origin.x, origin.y); | ||||
| 	} | ||||
|  | ||||
|     public void setMaxTime(long maxTime) { | ||||
|         this.maxTime = maxTime; | ||||
|         syncScrollBars(); | ||||
|     } | ||||
| 	public void setOrigin(int x, int y) { | ||||
| 		checkWidget(); | ||||
| 		origin.x = x; | ||||
| 		origin.y = y; | ||||
| 		syncSb(); | ||||
| 	} | ||||
|  | ||||
|     public int getZoomLevel() { | ||||
|         return level; | ||||
|     } | ||||
|      | ||||
|     public int getMaxZoomLevel(){ | ||||
|     	return Constants.UNIT_MULTIPLIER.length*Constants.UNIT_STRING.length-1; | ||||
|     } | ||||
| 	@Override | ||||
| 	public long getMaxTime() { | ||||
| 		return maxTime; | ||||
| 	} | ||||
|  | ||||
|     public void setZoomLevel(int level) { | ||||
| 		long tc=cursorPainters.get(0).getTime(); // cursor time | ||||
| 		setZoomLevel(level, tc); | ||||
|     } | ||||
| 	public void setMaxTime(long maxTime) { | ||||
| 		this.maxTime = maxTime; | ||||
| 		if(maxTime>INITIAL_ZOOM_BAR_MAX) { | ||||
| 			long maxBarTime = maxTime; | ||||
| 			while(maxBarTime>Integer.MAX_VALUE)	maxBarTime/=1000; | ||||
| 			horizontal.setMaximum((int) maxBarTime); | ||||
| 		} | ||||
| 		sliderScaleFactor = maxTime/horizontal.getMaximum(); | ||||
| 		syncSb(); | ||||
| 	} | ||||
|  | ||||
|     public void setZoomLevel(int level, long centerTime) { | ||||
|     	//FIXME: keep center if zoom-out and cursor is not in view | ||||
|     	if(level<0) level = 0; | ||||
| 		long xc=centerTime/this.scaleFactor; // cursor total x-offset | ||||
|     	if(level<Constants.UNIT_MULTIPLIER.length*Constants.UNIT_STRING.length){ | ||||
|     		this.scaleFactor = (long) Math.pow(10, level>>1); | ||||
|     		if(level%2==1) this.scaleFactor*=3; | ||||
|     		ITx tx = arrowPainter.getTx(); | ||||
|     		arrowPainter.setTx(null); | ||||
|     		/* | ||||
|     		 * xc = tc/oldScaleFactor | ||||
|     		 * xoffs = xc+origin.x | ||||
|     		 * xcn = tc/newScaleFactor | ||||
|     		 * t0n = (xcn-xoffs)*scaleFactor | ||||
|     		 */ | ||||
| 			long xoffs=xc+origin.x; // cursor offset relative to left border | ||||
| 			long xcn=centerTime/scaleFactor; // new total x-offset | ||||
| 	@Override | ||||
| 	public long getScale() { | ||||
| 		return scaleFactor; | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public void setScale(long factor) { | ||||
| 		setScalingFactor(factor, (getMaxVisibleTime()+getMinVisibleTime())/2); | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public void setVisibleRange(long startTime, long endTime) { | ||||
| 		assert(startTime<endTime); | ||||
| 		long time_diff = endTime-startTime; | ||||
| 		long factor = (time_diff*11/10)/getClientArea().width; | ||||
| 		setScalingFactor(factor, startTime+time_diff/2); | ||||
| 	} | ||||
|  | ||||
| 	//@Override | ||||
| 	public void setScalingFactor(long factor, long centerTime) { | ||||
| 		Rectangle clientArea = getClientArea(); | ||||
| 		long clientAreaWidth = clientArea.width; | ||||
| 		long maxFactor=maxTime/clientAreaWidth; | ||||
| 		if(factor<0) { | ||||
| 			if(factor== ZOOM_FIT) { | ||||
| 				long cTime = getCursorPainters().get(0).getTime(); | ||||
| 				long time_diff = centerTime>cTime?centerTime-cTime:cTime-centerTime; | ||||
| 				centerTime = (centerTime>cTime?cTime:centerTime)+time_diff/2; | ||||
| 				factor = (time_diff*11/10)/clientAreaWidth; | ||||
| 			} else if(factor== ZOOM_FULL) | ||||
| 				factor = maxFactor; | ||||
| 		}  | ||||
| 		if(factor==0) | ||||
| 			factor=1; | ||||
| 		else if(factor>maxFactor) | ||||
| 			factor=maxFactor; | ||||
| 		if(factor!=getScale() || (getMaxVisibleTime()+getMinVisibleTime()/2) != centerTime) { | ||||
| 			updateScaleFactor(factor); | ||||
| 			ITx tx = arrowPainter.getTx(); | ||||
| 			arrowPainter.setTx(null); | ||||
| 			/* | ||||
| 			 * xc = tc/oldScaleFactor | ||||
| 			 * xoffs = xc+origin.x | ||||
| 			 * xcn = tc/newScaleFactor | ||||
| 			 * t0n = (xcn-xoffs)*getScale() | ||||
| 			 */ | ||||
| 			long xoffs = clientAreaWidth/2; | ||||
| 			long xcn=centerTime/getScale(); // new total x-offset | ||||
| 			long originX=xcn-xoffs; | ||||
| 			if(originX>0) { | ||||
| 				origin.x=(int) -originX; // new cursor time offset relative to left border | ||||
| 			}else { | ||||
| 				origin.x=0; | ||||
| 			} | ||||
|     		syncScrollBars(); | ||||
|     		arrowPainter.setTx(tx);    		 | ||||
|     		redraw(); | ||||
|     		this.level = level; | ||||
|     	} | ||||
|     } | ||||
| 			syncSb(); | ||||
| 			arrowPainter.setTx(tx);    		 | ||||
| 			redraw(); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|     public long getScaleFactor() { | ||||
|         return scaleFactor; | ||||
|     } | ||||
| 	private void updateScaleFactor(long factor) { | ||||
| 		scaleFactor = factor; | ||||
| 		scaleMagnitude = 0; | ||||
| 		for(int i=Constants.POWERS_OF_TEN.length-1; i>0; i--) { | ||||
| 			if(scaleFactor>=Constants.POWERS_OF_TEN[i]) { | ||||
| 				scaleMagnitude = i; | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|     public long getScaleFactorPow10() { | ||||
|     	int scale = level/Constants.UNIT_MULTIPLIER.length; | ||||
|     	double res = Math.pow(1000, scale); | ||||
|     	return (long) res; | ||||
|     } | ||||
| 	@Override | ||||
| 	public String timeToString(long time) { | ||||
| 		int idx = scaleMagnitude/3; | ||||
| 		double fTime = (double)time/Constants.UNIT_MULTIPLIER[idx]; | ||||
| 		return Constants.getTimeFormatForLevel(idx).format(fTime)+Constants.UNIT_STRING[idx]; | ||||
| 	} | ||||
|  | ||||
|     public String getUnitStr(){ | ||||
|         return Constants.UNIT_STRING[level/Constants.UNIT_MULTIPLIER.length]; | ||||
|     } | ||||
|       | ||||
|     public int getUnitMultiplier(){ | ||||
|         return Constants.UNIT_MULTIPLIER[level%Constants.UNIT_MULTIPLIER.length]; | ||||
|     } | ||||
|      | ||||
|     public long getTimeForOffset(int xOffset){ | ||||
|         return (xOffset-origin.x) * scaleFactor; | ||||
|     } | ||||
|      | ||||
|     public void addPainter(IPainter painter) { | ||||
|         painterList.add(painter); | ||||
|         redraw(); | ||||
|     } | ||||
| 	public long getTimeForOffset(int xOffset){ | ||||
| 		return (xOffset-origin.x) * getScale(); | ||||
| 	} | ||||
|  | ||||
|     public void removePainter(IPainter painter) { | ||||
|         painterList.remove(painter); | ||||
|         redraw(); | ||||
|     } | ||||
| 	public void addPainter(IPainter painter) { | ||||
| 		painterList.add(painter); | ||||
| 		redraw(); | ||||
| 	} | ||||
|  | ||||
|     public void clearAllWaveformPainter() { | ||||
|     	clearAllWaveformPainter(true); | ||||
|     } | ||||
|      | ||||
|     void clearAllWaveformPainter(boolean update) { | ||||
|         trackAreaPainter.trackVerticalOffset.clear(); | ||||
|         wave2painterMap.clear(); | ||||
|         if(update) syncScrollBars(); | ||||
|     } | ||||
| 	public void removePainter(IPainter painter) { | ||||
| 		painterList.remove(painter); | ||||
| 		redraw(); | ||||
| 	} | ||||
|  | ||||
|     public void addWaveformPainter(IWaveformPainter painter) { | ||||
|     	addWaveformPainter(painter, true); | ||||
|     } | ||||
|      | ||||
|     void addWaveformPainter(IWaveformPainter painter, boolean update) { | ||||
|         trackAreaPainter.addTrackPainter(painter); | ||||
|         wave2painterMap.put(painter.getTrackEntry().waveform, painter); | ||||
|         if(update) syncScrollBars(); | ||||
|     } | ||||
| 	public void clearAllWaveformPainter() { | ||||
| 		clearAllWaveformPainter(true); | ||||
| 	} | ||||
|  | ||||
|     public List<CursorPainter> getCursorPainters() { | ||||
| 	void clearAllWaveformPainter(boolean update) { | ||||
| 		trackAreaPainter.trackVerticalOffset.clear(); | ||||
| 		wave2painterMap.clear(); | ||||
| 		if(update) syncSb(); | ||||
| 	} | ||||
|  | ||||
| 	public void addWaveformPainter(IWaveformPainter painter) { | ||||
| 		addWaveformPainter(painter, true); | ||||
| 	} | ||||
|  | ||||
| 	void addWaveformPainter(IWaveformPainter painter, boolean update) { | ||||
| 		trackAreaPainter.addTrackPainter(painter); | ||||
| 		wave2painterMap.put(painter.getTrackEntry().waveform, painter); | ||||
| 		if(update) syncSb(); | ||||
| 	} | ||||
|  | ||||
| 	public List<CursorPainter> getCursorPainters() { | ||||
| 		return cursorPainters; | ||||
| 	} | ||||
|  | ||||
|     /* Initialize the scrollbar and register listeners. */ | ||||
|     private void initScrollBars() { | ||||
|         ScrollBar horizontal = getHorizontalBar(); | ||||
|         horizontal.setEnabled(false); | ||||
|         horizontal.setVisible(true); | ||||
|         horizontal.addSelectionListener(new SelectionAdapter() { | ||||
| 	/* Initialize the scrollbar and register listeners. */ | ||||
| 	private void initScrollBars() { | ||||
| 		horizontal.setEnabled(false); | ||||
| 		horizontal.setVisible(true); | ||||
| 		horizontal.addSelectionListener(new SelectionAdapter() { | ||||
| 			@Override | ||||
|             public void widgetSelected(SelectionEvent event) { | ||||
|                 if (painterList.isEmpty()) | ||||
|                     return; | ||||
|                 setOrigin(-((ScrollBar) event.widget).getSelection(), origin.y); | ||||
|             } | ||||
|         }); | ||||
|         ScrollBar vertical = getVerticalBar(); | ||||
|         vertical.setEnabled(false); | ||||
|         vertical.setVisible(true); | ||||
|         vertical.addSelectionListener(new SelectionAdapter() { | ||||
| 			public void widgetSelected(SelectionEvent event) { | ||||
| 				if (!painterList.isEmpty()) { | ||||
| 					int[] sel = horizontal.getSelection(); | ||||
| 					long lowerTime = sel[0]*sliderScaleFactor; | ||||
| 					long upperTime = sel[1]*sliderScaleFactor; | ||||
| 					if(sel[1]-sel[0] != lastHorSelection[1]-lastHorSelection[0]) { | ||||
| 						long time_diff = upperTime-lowerTime; | ||||
| 						long factor = time_diff/getClientArea().width; | ||||
| 						setScalingFactor(factor, lowerTime+time_diff/2); | ||||
| 					} else { | ||||
| 						origin.x = -(int) (lowerTime/getScale()); | ||||
| 						WaveformCanvas.this.getDisplay().asyncExec(() -> {redraw();}); | ||||
| 					} | ||||
| 					lastHorSelection=sel; | ||||
| 				} | ||||
| 			} | ||||
| 		}); | ||||
| 		horizontal.setMinimum(0); | ||||
| 		horizontal.setMaximum(INITIAL_ZOOM_BAR_MAX); | ||||
| 		lastHorSelection = horizontal.getSelection(); | ||||
| 		 | ||||
| 		vertical.setEnabled(false); | ||||
| 		vertical.setVisible(true); | ||||
| 		vertical.addSelectionListener(new SelectionAdapter() { | ||||
| 			@Override | ||||
|             public void widgetSelected(SelectionEvent event) { | ||||
|                 if (painterList.isEmpty()) | ||||
|                     return; | ||||
|                 setOrigin(origin.x, -((ScrollBar) event.widget).getSelection()); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Synchronize the scrollbar with the image. If the transform is out of | ||||
|      * range, it will correct it. This function considers only following factors | ||||
|      * :<b> transform, image size, client area</b>. | ||||
|      */ | ||||
|     public void syncScrollBars() { | ||||
|         if (painterList.isEmpty()) { | ||||
|             redraw(); | ||||
|             return; | ||||
|         } | ||||
|         int height = trackAreaPainter.getHeight(); // incl. Ruler | ||||
|         long width = maxTime / scaleFactor; | ||||
|         Rectangle clientArea=getClientArea(); | ||||
|         ScrollBar horizontal = getHorizontalBar(); | ||||
|         horizontal.setIncrement(getClientArea().width / 100); | ||||
|         horizontal.setPageIncrement(getClientArea().width); | ||||
|         int clientWidthw = clientArea.width; | ||||
|         if (width > clientWidthw) { /* image is wider than client area */ | ||||
|         	horizontal.setMinimum(0); | ||||
|             horizontal.setMaximum((int)width); | ||||
|             horizontal.setEnabled(true); | ||||
|             if (-origin.x > horizontal.getMaximum() - clientWidthw) { | ||||
|                 origin.x = -horizontal.getMaximum() + clientWidthw; | ||||
|             } | ||||
|         } else { /* image is narrower than client area */ | ||||
|             horizontal.setEnabled(false); | ||||
|         } | ||||
|         horizontal.setThumb(clientWidthw); | ||||
|         horizontal.setSelection(-origin.x); | ||||
|  | ||||
|         ScrollBar vertical = getVerticalBar(); | ||||
|         vertical.setIncrement(getClientArea().height / 100); | ||||
|         vertical.setPageIncrement(getClientArea().height); | ||||
|         int clientHeighth = clientArea.height; | ||||
|         if (height > clientHeighth) { /* image is higher than client area */ | ||||
|             vertical.setMinimum(0); | ||||
|             vertical.setMaximum(height); | ||||
|             vertical.setEnabled(true); | ||||
|             if ( -origin.y > vertical.getMaximum() - clientHeighth) { | ||||
|                 origin.y = -vertical.getMaximum() + clientHeighth; | ||||
|             } | ||||
|         } else { /* image is less higher than client area */ | ||||
|             vertical.setMaximum(clientHeighth); | ||||
|             vertical.setEnabled(false); | ||||
|         } | ||||
|         vertical.setThumb(clientHeighth); | ||||
|         vertical.setSelection(-origin.y); | ||||
|         redraw(); | ||||
|         fireSelectionEvent(); | ||||
|     } | ||||
|  | ||||
|     /* Paint function */ | ||||
|     private void paint(GC gc) { | ||||
|         Point pt = getSize(); | ||||
|         if(pt.x==0  || pt.y==0) return; | ||||
|         Rectangle clientRect = getClientArea(); /* Canvas' painting area */ | ||||
|         GC thisGc = gc; | ||||
|         Image dBackingImg = null; | ||||
|         if(doubleBuffering) { | ||||
|         	dBackingImg = new Image(getDisplay(), pt.x, pt.y); | ||||
|             thisGc = new GC(dBackingImg); | ||||
|             thisGc.setBackground(gc.getBackground()); | ||||
|             thisGc.setForeground(gc.getForeground()); | ||||
|             thisGc.setFont(gc.getFont()); | ||||
|              | ||||
|         } | ||||
|         Projection p = new Projection(thisGc); | ||||
|         p.setTranslation(origin); | ||||
|         if (!painterList.isEmpty() ) { | ||||
|             for (IPainter painter : painterList) | ||||
|                 painter.paintArea(p, clientRect); | ||||
|         } else { | ||||
|             gc.fillRectangle(clientRect); | ||||
|             initScrollBars(); | ||||
|         } | ||||
|         if(doubleBuffering) { | ||||
|             gc.drawImage(dBackingImg, 0, 0); | ||||
|             if(dBackingImg!=null) dBackingImg.dispose(); | ||||
|             thisGc.dispose(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public List<Object> getElementsAt(Point point) { | ||||
|     	LinkedList<Object> result=new LinkedList<>(); | ||||
|         for (IPainter p : Lists.reverse(painterList)) { | ||||
|             if (p instanceof TrackAreaPainter) { | ||||
|                 int y = point.y - origin.y; | ||||
|                 int x = point.x - origin.x; | ||||
|                 Entry<Integer, IWaveformPainter> entry = trackAreaPainter.trackVerticalOffset.floorEntry(y); | ||||
|                 if (entry != null) { | ||||
|                     if (entry.getValue() instanceof StreamPainter) { | ||||
|                     	ITx tx = ((StreamPainter) entry.getValue()).getClicked(new Point(x, y - entry.getKey())); | ||||
|                     	if(tx!=null) | ||||
|                     		result.add(tx); | ||||
|                     }  | ||||
|                     result.add(entry.getValue().getTrackEntry()); | ||||
|                 } | ||||
|             } else if (p instanceof CursorPainter) { | ||||
|                 if (Math.abs(point.x - origin.x - ((CursorPainter) p).getTime()/scaleFactor) < 2) { | ||||
|                 	result.add(p); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return result; | ||||
|     } | ||||
|  | ||||
|     public List<Object> getEntriesAtPosition(IWaveform iWaveform, int i) { | ||||
|     	LinkedList<Object> result=new LinkedList<>(); | ||||
|         int x = i - origin.x; | ||||
|         for(IWaveformPainter p: wave2painterMap.values()){ | ||||
|         	if (p instanceof StreamPainter && ((StreamPainter)p).getStream()==iWaveform) { | ||||
|         		result.add(((StreamPainter) p).getClicked(new Point(x, styleProvider.getTrackHeight()/2))); | ||||
|         	} | ||||
|         } | ||||
|         return result; | ||||
|     } | ||||
|  | ||||
|     public void setSelected(ITx currentSelection) { | ||||
|         this.currentSelection = currentSelection; | ||||
|         if (currentSelection != null) | ||||
|             reveal(currentSelection); | ||||
|         arrowPainter.setTx(currentSelection); | ||||
|         redraw(); | ||||
|     } | ||||
|  | ||||
|     public void reveal(ITx tx) { | ||||
|         int lower = (int) (tx.getBeginTime() / scaleFactor); | ||||
|         int higher = (int) (tx.getEndTime() / scaleFactor); | ||||
|         Point size = getSize(); | ||||
|         size.x -= getVerticalBar().getSize().x + 2; | ||||
|         size.y -= getHorizontalBar().getSize().y; | ||||
|         if (lower < -origin.x) { | ||||
|             setOrigin(-lower, origin.y); | ||||
|         } else if (higher > (size.x - origin.x)) { | ||||
|             setOrigin(size.x - higher, origin.y); | ||||
|         } | ||||
|         for (IWaveformPainter painter : wave2painterMap.values()) { | ||||
|             if (painter instanceof StreamPainter && ((StreamPainter) painter).getStream() == tx.getStream()) { | ||||
|             	EventEntry entry = tx.getStream().getEvents().floorEntry(tx.getBeginTime()); | ||||
|             	Optional<IEvent> res = Arrays.stream(entry.events).filter(e -> ((ITxEvent)e).getTransaction().equals(tx)).findFirst(); | ||||
|             	if(res.isPresent()) { | ||||
|                     int top = painter.getVerticalOffset() + styleProvider.getTrackHeight() * ((ITxEvent)res.get()).getRowIndex(); | ||||
|                     int bottom = top + styleProvider.getTrackHeight(); | ||||
|                     if (top < -origin.y) { | ||||
|                         setOrigin(origin.x, -(top-styleProvider.getTrackHeight())); | ||||
|                     } else if (bottom > (size.y - origin.y)) { | ||||
|                         setOrigin(origin.x, size.y - bottom); | ||||
|                     } | ||||
|             	} | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|      | ||||
| 	public void reveal(IWaveform waveform) { | ||||
|         for (IWaveformPainter painter : wave2painterMap.values()) { | ||||
|         	TrackEntry te = painter.getTrackEntry(); | ||||
|         	if(te.waveform == waveform) { | ||||
|                 Point size = getSize(); | ||||
|                 size.y -=+rulerHeight; | ||||
|                 ScrollBar sb = getHorizontalBar(); | ||||
|                 if((sb.getStyle()&SWT.SCROLLBAR_OVERLAY)!=0 && sb.isVisible()) | ||||
|                 	size.y-=  getHorizontalBar().getSize().y; | ||||
|                 int top = te.vOffset; | ||||
|                 int bottom = top + styleProvider.getTrackHeight(); | ||||
|                 if (top < -origin.y) { | ||||
|                     setOrigin(origin.x, -(top-styleProvider.getTrackHeight())); | ||||
|                 } else if (bottom > (size.y - origin.y)) { | ||||
|                     setOrigin(origin.x, size.y - bottom); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 			public void widgetSelected(SelectionEvent event) { | ||||
| 				if (!painterList.isEmpty()) { | ||||
| 					origin.y=-vertical.getSelection(); | ||||
| 					fireSelectionEvent(); | ||||
| 					WaveformCanvas.this.getDisplay().asyncExec(() -> {redraw();}); | ||||
| 				} | ||||
| 			} | ||||
| 		}); | ||||
| 	} | ||||
|  | ||||
|     public void reveal(long time) { | ||||
|         int scaledTime = (int) (time / scaleFactor); | ||||
|         Point size = getSize(); | ||||
|         size.x -= getVerticalBar().getSize().x + 2; | ||||
|         size.y -= getHorizontalBar().getSize().y; | ||||
|         if (scaledTime < -origin.x) { | ||||
|             setOrigin(-scaledTime+10, origin.y); | ||||
|         } else if (scaledTime > (size.x - origin.x)) { | ||||
|             setOrigin(size.x - scaledTime-30, origin.y); | ||||
|         } | ||||
|     } | ||||
| 	/** | ||||
| 	 * Synchronize the scrollbar with the image. If the transform is out of | ||||
| 	 * range, it will correct it. This function considers only following factors | ||||
| 	 * :<b> transform, image size, client area</b>. | ||||
| 	 */ | ||||
| 	public void syncSb() { | ||||
| 		if (!painterList.isEmpty()) { | ||||
| 			syncHSb(); | ||||
| 			syncVSb(); | ||||
| 			fireSelectionEvent(); | ||||
| 		} | ||||
| 		redraw(); | ||||
| 	} | ||||
|  | ||||
|     public int getRulerHeight() { | ||||
|         return rulerHeight; | ||||
|     } | ||||
| 	private void syncVSb() { | ||||
| 		Rectangle clientArea=getClientArea(); | ||||
| 		int height = trackAreaPainter.getHeight(); // incl. Ruler | ||||
| 		int clientHeight = clientArea.height; | ||||
| 		vertical.setIncrement(clientHeight / 100); | ||||
| 		vertical.setPageIncrement(clientHeight/2); | ||||
| 		if (height > clientHeight) { /* image is higher than client area */ | ||||
| 			vertical.setMinimum(0); | ||||
| 			vertical.setMaximum(height); | ||||
| 			vertical.setEnabled(true); | ||||
| 			if ( -origin.y > vertical.getMaximum() - clientHeight) { | ||||
| 				origin.y = -vertical.getMaximum() + clientHeight; | ||||
| 			} | ||||
| 		} else { /* image is less higher than client area */ | ||||
| 			vertical.setMaximum(clientHeight); | ||||
| 			vertical.setEnabled(false); | ||||
| 		} | ||||
| 		vertical.setThumb(clientHeight); | ||||
| 		vertical.setSelection(-origin.y); | ||||
| 	} | ||||
|  | ||||
|     public void setRulerHeight(int rulerHeight) { | ||||
|         this.rulerHeight = rulerHeight; | ||||
|     } | ||||
| 	private void syncHSb() { | ||||
| 		horizontal.setEnabled(wave2painterMap.size()>0); | ||||
| 		Rectangle clientArea=getClientArea(); | ||||
| 		int clientWidth = clientArea.width; | ||||
| 		if(sliderScaleFactor>0) { | ||||
| 			int lower = (int) ( (           -origin.x  * getScale()) / sliderScaleFactor); | ||||
| 			int upper = (int) (((clientWidth-origin.x) * getScale()) / sliderScaleFactor); | ||||
| 			lastHorSelection = new int[] {Math.max(lower,0), Math.min(upper, horizontal.getMaximum())}; | ||||
| 			horizontal.setSelection(lastHorSelection); | ||||
| 		} | ||||
| 		long width = maxTime / getScale(); | ||||
| 		horizontal.setButtonsEnabled(width > clientWidth); | ||||
| 	} | ||||
|  | ||||
|     public void addSelectionListener(SelectionAdapter selectionAdapter) { | ||||
|         selectionListeners.add(selectionAdapter); | ||||
|     } | ||||
| 	/* Paint function */ | ||||
| 	private void paint(GC gc) { | ||||
| 		Point pt = getSize(); | ||||
| 		if(pt.x==0  || pt.y==0) return; | ||||
| 		Rectangle clientRect = getClientArea(); /* Canvas' painting area */ | ||||
| 		GC thisGc = gc; | ||||
| 		Image dBackingImg = null; | ||||
| 		if(doubleBuffering) { | ||||
| 			dBackingImg = new Image(getDisplay(), pt.x, pt.y); | ||||
| 			thisGc = new GC(dBackingImg); | ||||
| 			thisGc.setBackground(gc.getBackground()); | ||||
| 			thisGc.setForeground(gc.getForeground()); | ||||
| 			thisGc.setFont(gc.getFont()); | ||||
|  | ||||
|     public void removeSelectionListener(SelectionAdapter selectionAdapter) { | ||||
|         selectionListeners.remove(selectionAdapter); | ||||
|     } | ||||
| 		} | ||||
| 		Projection p = new Projection(thisGc); | ||||
| 		p.setTranslation(origin); | ||||
| 		if (!painterList.isEmpty() ) { | ||||
| 			for (IPainter painter : painterList) | ||||
| 				painter.paintArea(p, clientRect); | ||||
| 		} else { | ||||
| 			gc.fillRectangle(clientRect); | ||||
| 			initScrollBars(); | ||||
| 		} | ||||
| 		if(doubleBuffering) { | ||||
| 			gc.drawImage(dBackingImg, 0, 0); | ||||
| 			if(dBackingImg!=null) dBackingImg.dispose(); | ||||
| 			thisGc.dispose(); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|     /** | ||||
|      *  | ||||
|      */ | ||||
|     protected void fireSelectionEvent() { | ||||
|         Event e = new Event(); | ||||
|         e.widget = this; | ||||
|         e.detail=SWT.SELECTED; | ||||
|         e.type=SWT.Selection; | ||||
|         SelectionEvent ev = new SelectionEvent(e); | ||||
|         ev.x = origin.x; | ||||
|         ev.y = origin.y; | ||||
|         for (SelectionAdapter a : selectionListeners) { | ||||
|             a.widgetSelected(ev); | ||||
|         } | ||||
|     } | ||||
| 	public List<Object> getElementsAt(Point point) { | ||||
| 		LinkedList<Object> result=new LinkedList<>(); | ||||
| 		for (IPainter p : Lists.reverse(painterList)) { | ||||
| 			if (p instanceof TrackAreaPainter) { | ||||
| 				int y = point.y - origin.y; | ||||
| 				int x = point.x - origin.x; | ||||
| 				Entry<Integer, IWaveformPainter> entry = trackAreaPainter.trackVerticalOffset.floorEntry(y); | ||||
| 				if (entry != null) { | ||||
| 					if (entry.getValue() instanceof StreamPainter) { | ||||
| 						ITx tx = ((StreamPainter) entry.getValue()).getClicked(new Point(x, y - entry.getKey())); | ||||
| 						if(tx!=null) | ||||
| 							result.add(tx); | ||||
| 					}  | ||||
| 					result.add(entry.getValue().getTrackEntry()); | ||||
| 				} | ||||
| 			} else if (p instanceof CursorPainter) { | ||||
| 				if (Math.abs(point.x - origin.x - ((CursorPainter) p).getTime()/getScale()) < 2) { | ||||
| 					result.add(p); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
|     long getMaxVisibleTime() { | ||||
|     	return (getClientArea().width+origin.x)*scaleFactor; | ||||
|     } | ||||
| 	public List<Object> getEntriesAtPosition(IWaveform iWaveform, int i) { | ||||
| 		LinkedList<Object> result=new LinkedList<>(); | ||||
| 		int x = i - origin.x; | ||||
| 		for(IWaveformPainter p: wave2painterMap.values()){ | ||||
| 			if (p instanceof StreamPainter && ((StreamPainter)p).getStream()==iWaveform) { | ||||
| 				result.add(((StreamPainter) p).getClicked(new Point(x, styleProvider.getTrackHeight()/2))); | ||||
| 			} | ||||
| 		} | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
|     long getMinVisibleTime() { | ||||
|     	return origin.x * scaleFactor; | ||||
|     } | ||||
| 	public void setSelected(ITx currentSelection) { | ||||
| 		this.currentSelection = currentSelection; | ||||
| 		if (currentSelection != null) | ||||
| 			reveal(currentSelection); | ||||
| 		arrowPainter.setTx(currentSelection); | ||||
| 		redraw(); | ||||
| 	} | ||||
|  | ||||
| 	public void reveal(ITx tx) { | ||||
| 		int lower = (int) (tx.getBeginTime() / getScale()); | ||||
| 		int higher = (int) (tx.getEndTime() / getScale()); | ||||
| 		Point size = getSize(); | ||||
| 		size.x -= vertical.getSize().x + 2; | ||||
| 		size.y -= horizontal.getSize().y; | ||||
| 		if (lower < -origin.x) { | ||||
| 			setOrigin(-lower, origin.y); | ||||
| 		} else if (higher > (size.x - origin.x)) { | ||||
| 			setOrigin(size.x - higher, origin.y); | ||||
| 		} | ||||
| 		for (IWaveformPainter painter : wave2painterMap.values()) { | ||||
| 			if (painter instanceof StreamPainter && ((StreamPainter) painter).getStream() == tx.getStream()) { | ||||
| 				EventEntry entry = tx.getStream().getEvents().floorEntry(tx.getBeginTime()); | ||||
| 				Optional<IEvent> res = Arrays.stream(entry.events).filter(e -> ((ITxEvent)e).getTransaction().equals(tx)).findFirst(); | ||||
| 				if(res.isPresent()) { | ||||
| 					int top = painter.getVerticalOffset() + styleProvider.getTrackHeight() * ((ITxEvent)res.get()).getRowIndex(); | ||||
| 					int bottom = top + styleProvider.getTrackHeight(); | ||||
| 					if (top < -origin.y) { | ||||
| 						setOrigin(origin.x, -(top-styleProvider.getTrackHeight())); | ||||
| 					} else if (bottom > (size.y - origin.y)) { | ||||
| 						setOrigin(origin.x, size.y - bottom); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	public void reveal(IWaveform waveform) { | ||||
| 		for (IWaveformPainter painter : wave2painterMap.values()) { | ||||
| 			TrackEntry te = painter.getTrackEntry(); | ||||
| 			if(te.waveform == waveform) { | ||||
| 				Point size = getSize(); | ||||
| 				size.y -=+rulerHeight; | ||||
| 				if((horizontal.getStyle()&SWT.SCROLLBAR_OVERLAY)!=0 && horizontal.isVisible()) | ||||
| 					size.y-=  horizontal.getSize().y; | ||||
| 				int top = te.vOffset; | ||||
| 				int bottom = top + styleProvider.getTrackHeight(); | ||||
| 				if (top < -origin.y) { | ||||
| 					setOrigin(origin.x, -(top-styleProvider.getTrackHeight())); | ||||
| 				} else if (bottom > (size.y - origin.y)) { | ||||
| 					setOrigin(origin.x, size.y - bottom); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	public void reveal(long time) { | ||||
| 		int scaledTime = (int) (time / getScale()); | ||||
| 		Point size = getSize(); | ||||
| 		size.x -= vertical.getSize().x + 2; | ||||
| 		size.y -= horizontal.getSize().y; | ||||
| 		if (scaledTime < -origin.x) { | ||||
| 			setOrigin(-scaledTime+10, origin.y); | ||||
| 		} else if (scaledTime > (size.x - origin.x)) { | ||||
| 			setOrigin(size.x - scaledTime-30, origin.y); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public void centerAt(long time) { | ||||
| 		int scaledTime = (int) (time / getScale()); | ||||
| 		int newX = -scaledTime+getWidth()/2; | ||||
| 		setOrigin(newX>0?0:newX, origin.y); | ||||
| 	} | ||||
|  | ||||
| 	public int getRulerHeight() { | ||||
| 		return rulerHeight; | ||||
| 	} | ||||
|  | ||||
| 	public void setRulerHeight(int rulerHeight) { | ||||
| 		this.rulerHeight = rulerHeight; | ||||
| 	} | ||||
|  | ||||
| 	public void addSelectionListener(SelectionAdapter selectionAdapter) { | ||||
| 		selectionListeners.add(selectionAdapter); | ||||
| 	} | ||||
|  | ||||
| 	public void removeSelectionListener(SelectionAdapter selectionAdapter) { | ||||
| 		selectionListeners.remove(selectionAdapter); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 *  | ||||
| 	 */ | ||||
| 	protected void fireSelectionEvent() { | ||||
| 		Event e = new Event(); | ||||
| 		e.widget = this; | ||||
| 		e.detail=SWT.SELECTED; | ||||
| 		e.type=SWT.Selection; | ||||
| 		SelectionEvent ev = new SelectionEvent(e); | ||||
| 		ev.x = origin.x; | ||||
| 		ev.y = origin.y; | ||||
| 		for (SelectionAdapter a : selectionListeners) { | ||||
| 			a.widgetSelected(ev); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	@Override | ||||
| 	public long getMaxVisibleTime() { | ||||
| 		return (getClientArea().width-origin.x)*getScale(); | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public long getMinVisibleTime() { | ||||
| 		return -origin.x * getScale(); | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public void setMinVisibleTime(long time) { | ||||
| 		long duration = getMaxVisibleTime()-getMinVisibleTime(); | ||||
| 		if(time>0) { | ||||
| 			if((time+duration)<getMaxTime()) { | ||||
| 				int scaledTime = (int) (time / getScale()); | ||||
| 				setOrigin(-scaledTime, origin.y); | ||||
| 			} | ||||
| 		} else { | ||||
| 			setOrigin(0, origin.y); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public void zoom(ZoomKind kind) { | ||||
| 		switch(kind) { | ||||
| 		case IN: | ||||
| 			setScale(getScale()/2); | ||||
| 			break; | ||||
| 		case OUT: | ||||
| 			setScale(getScale()*2);			 | ||||
| 			break; | ||||
| 		case FIT: | ||||
| 			setScalingFactor(WaveformCanvas.ZOOM_FIT, cursorPainters.get(1).getTime()); | ||||
| 			break; | ||||
| 		case FULL: | ||||
| 			setScale(WaveformCanvas.ZOOM_FULL); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	public void setStyleProvider(IWaveformStyleProvider styleProvider) { | ||||
| 		this.styleProvider=styleProvider; | ||||
| 		redraw(); | ||||
| 	} | ||||
|  | ||||
| 	public int getScaleMagnitude() { | ||||
| 		return scaleMagnitude; | ||||
| 	} | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -13,7 +13,6 @@ package com.minres.scviewer.database.ui.swt.internal; | ||||
| import java.beans.PropertyChangeEvent; | ||||
| import java.beans.PropertyChangeListener; | ||||
| import java.beans.PropertyChangeSupport; | ||||
| import java.text.DecimalFormat; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Arrays; | ||||
| import java.util.Collection; | ||||
| @@ -90,8 +89,9 @@ import com.minres.scviewer.database.ui.GotoDirection; | ||||
| import com.minres.scviewer.database.ui.ICursor; | ||||
| import com.minres.scviewer.database.ui.IWaveformStyleProvider; | ||||
| import com.minres.scviewer.database.ui.IWaveformView; | ||||
| import com.minres.scviewer.database.ui.IWaveformZoom; | ||||
| import com.minres.scviewer.database.ui.TrackEntry; | ||||
| import com.minres.scviewer.database.ui.swt.Constants; | ||||
| import com.minres.scviewer.database.ui.swt.internal.slider.ZoomBar; | ||||
|  | ||||
| public class WaveformView implements IWaveformView { | ||||
|  | ||||
| @@ -99,8 +99,6 @@ public class WaveformView implements IWaveformView { | ||||
|  | ||||
| 	private PropertyChangeSupport pcs; | ||||
|  | ||||
| 	static final DecimalFormat df = new DecimalFormat("#0.00####"); | ||||
|  | ||||
| 	private ITx currentTxSelection; | ||||
|  | ||||
| 	private ArrayList<TrackEntry> currentWaveformSelection = new ArrayList<>(); | ||||
| @@ -115,6 +113,10 @@ public class WaveformView implements IWaveformView { | ||||
|  | ||||
| 	private final Canvas valueList; | ||||
|  | ||||
| 	private final Control nameFill; | ||||
| 	 | ||||
| 	private final Control valueFill; | ||||
|  | ||||
| 	final WaveformCanvas waveformCanvas; | ||||
|  | ||||
| 	final ToolTipHandler toolTipHandler; | ||||
| @@ -163,8 +165,7 @@ public class WaveformView implements IWaveformView { | ||||
| 									: streams.subList(firstIdx, lastIdx + 1); | ||||
| 							setSelection(new StructuredSelection(res), (e.stateMask & SWT.CTRL) != 0, false); | ||||
| 						} else | ||||
| 							setSelection(new StructuredSelection(entry.getValue()), (e.stateMask & SWT.CTRL) != 0, | ||||
| 									false); | ||||
| 							setSelection(new StructuredSelection(entry.getValue()), (e.stateMask & SWT.CTRL) != 0, false); | ||||
| 					} else { | ||||
| 						setSelection(new StructuredSelection(entry.getValue()), (e.stateMask & SWT.CTRL) != 0, false); | ||||
| 					} | ||||
| @@ -197,64 +198,45 @@ public class WaveformView implements IWaveformView { | ||||
| 			down = false; | ||||
| 			if (start == null) | ||||
| 				return; | ||||
| 			if ((e.stateMask & SWT.MODIFIER_MASK & ~SWT.SHIFT) != 0) | ||||
| 				return; // don't react on modifier except shift | ||||
| 			if (e.button == 1 && Math.abs(e.x - start.x) > 3) { | ||||
| 				asyncUpdate(e.widget); | ||||
| 				long startTime = waveformCanvas.getTimeForOffset(start.x); | ||||
| 				long endTime = waveformCanvas.getTimeForOffset(end.x); | ||||
| 				long targetTimeRange = endTime - startTime; | ||||
| 				long currentTimeRange = waveformCanvas.getMaxVisibleTime() - waveformCanvas.getMinVisibleTime(); | ||||
| 				if (targetTimeRange == 0) | ||||
| 					return; | ||||
| 				long relation = currentTimeRange / targetTimeRange; | ||||
| 				long i = 1; | ||||
| 				int level = 0; | ||||
| 				do { | ||||
| 					if (relation < 0) { | ||||
| 						if (-relation < i) { | ||||
| 							break; | ||||
| 						} | ||||
| 						level--; | ||||
| 						if (-relation < i * 3) { | ||||
| 							break; | ||||
| 						} | ||||
| 						level--; | ||||
| 					} else { | ||||
| 						if (relation < i) { | ||||
| 							break; | ||||
| 						} | ||||
| 						level++; | ||||
| 						if (relation < i * 3) { | ||||
| 							break; | ||||
| 						} | ||||
| 						level++; | ||||
| 					} | ||||
| 					i = i * 10; | ||||
| 				} while (i < 10000); | ||||
| 				if (i < 10000) { | ||||
| 					int curLevel = waveformCanvas.getZoomLevel(); | ||||
| 					waveformCanvas.setZoomLevel(curLevel - level, (startTime + endTime) / 2); | ||||
| 				} | ||||
| 			} else if (e.button == 1 && ((e.stateMask & SWT.SHIFT) == 0)) { | ||||
| 				// set cursor (button 1 and no shift) | ||||
| 				if (Math.abs(e.x - start.x) < 3 && Math.abs(e.y - start.y) < 3) { | ||||
| 					// first set cursor time | ||||
| 					setCursorTime(snapOffsetToEvent(start)); | ||||
| 					// then set selection and reveal | ||||
| 					setSelection(new StructuredSelection(initialSelected)); | ||||
| 			if ((e.stateMask & SWT.MODIFIER_MASK & ~(SWT.SHIFT | SWT.CTRL)) != 0) | ||||
| 				return; // don't react on modifier except shift and control | ||||
| 			boolean isCtrl = (e.stateMask & SWT.CTRL)!=0; | ||||
| 			boolean isShift = (e.stateMask & SWT.SHIFT)!=0; | ||||
| 			if (e.button == 1) { | ||||
| 				if (Math.abs(e.x - start.x) > 3) { // was drag event | ||||
| 					asyncUpdate(e.widget); | ||||
| 					long startTime = waveformCanvas.getTimeForOffset(start.x); | ||||
| 					long endTime = waveformCanvas.getTimeForOffset(end.x); | ||||
| 					if(startTime<endTime) { | ||||
| 						waveformCanvas.setVisibleRange(startTime, endTime); | ||||
| 					} else if(start.x!=end.x){ | ||||
| 						long targetTimeRange = startTime-endTime; | ||||
| 						long currentTimeRange = waveformCanvas.getMaxVisibleTime() - waveformCanvas.getMinVisibleTime(); | ||||
| 						long factor = currentTimeRange/targetTimeRange *waveformCanvas.getScale(); | ||||
| 						waveformCanvas.setScalingFactor(factor, (startTime+endTime)/2); | ||||
| 												 | ||||
| 					} | ||||
| 				} else if( isShift) { // set marker (button 1 and shift) | ||||
| 					setMarkerTime(selectedMarker, snapOffsetToEvent(start)); | ||||
| 				} else if(isCtrl) {	// set cursor (button 1 and ctrl) | ||||
| 					setCursorTime(snapOffsetToEvent(start)); | ||||
| 				} else { // set cursor (button 1 only) | ||||
| 					if (Math.abs(e.y - start.y) < 3) { | ||||
| 						// first set cursor time | ||||
| 						setCursorTime(snapOffsetToEvent(start)); | ||||
| 						// then set selection and reveal | ||||
| 						setSelection(new StructuredSelection(initialSelected)); | ||||
| 					} | ||||
| 				} | ||||
| 			} else if (e.button == 2 || (e.button == 1 && (e.stateMask & SWT.SHIFT) != 0)) { | ||||
| 				// set marker (button 1 and shift) | ||||
| 				setMarkerTime(snapOffsetToEvent(start), selectedMarker); | ||||
| 				asyncUpdate(e.widget); | ||||
| 			} else if (e.button == 2) { // set marker (button 2) | ||||
| 				setMarkerTime(selectedMarker, snapOffsetToEvent(start)); | ||||
| 			} | ||||
| 			asyncUpdate(e.widget); | ||||
| 		} | ||||
|  | ||||
| 		protected long snapOffsetToEvent(Point p) { | ||||
| 			long time = waveformCanvas.getTimeForOffset(p.x); | ||||
| 			long scaling = 5 * waveformCanvas.getScaleFactor(); | ||||
| 			long scaling = 5 * waveformCanvas.getScale(); | ||||
| 			for (Object o : waveformCanvas.getElementsAt(p)) { | ||||
| 				EventEntry floorEntry = null; | ||||
| 				EventEntry ceilEntry = null; | ||||
| @@ -288,6 +270,25 @@ public class WaveformView implements IWaveformView { | ||||
| 		public void handleEvent(Event e) { | ||||
| 			switch (e.type) { | ||||
| 			case SWT.MouseWheel: | ||||
| 				if((e.stateMask & SWT.CTRL) != 0) { | ||||
| 					if(e.count<0) // up scroll | ||||
| 						waveformCanvas.setScale(waveformCanvas.getScale()*11/10); | ||||
| 					else // down scroll | ||||
| 						waveformCanvas.setScale(waveformCanvas.getScale()*10/11); | ||||
| 					e.doit=false; | ||||
| 				} else if((e.stateMask & SWT.SHIFT) != 0) { | ||||
| 					long upper = waveformCanvas.getMaxVisibleTime(); | ||||
| 					long lower = waveformCanvas.getMinVisibleTime(); | ||||
| 					long duration = upper-lower; | ||||
| 					if(e.count<0) { // up scroll | ||||
| 						long newLower = Math.min(waveformCanvas.getMaxTime()-duration, lower+duration/10); | ||||
| 						waveformCanvas.setMinVisibleTime(newLower); | ||||
| 					} else {// down scroll | ||||
| 						long newLower = Math.max(0, lower-duration/10); | ||||
| 						waveformCanvas.setMinVisibleTime(newLower); | ||||
| 					} | ||||
| 					e.doit=false; | ||||
| 				} | ||||
| 				break; | ||||
| 			case SWT.MouseDown: | ||||
| 				start = new Point(e.x, e.y); | ||||
| @@ -347,8 +348,26 @@ public class WaveformView implements IWaveformView { | ||||
| 		rightSash.setBackground(SWTResourceManager.getColor(SWT.COLOR_GRAY)); | ||||
|  | ||||
| 		Composite valuePane = new Composite(rightSash, SWT.NONE); | ||||
| 		waveformCanvas = new WaveformCanvas(rightSash, SWT.NONE, styleProvider); | ||||
|  | ||||
| 		 | ||||
| 		Composite waveformPane = new Composite(rightSash, SWT.NONE); | ||||
| 		GridLayout gl_waveformPane = new GridLayout(1, false); | ||||
| 		gl_waveformPane.verticalSpacing = 0; | ||||
| 		gl_waveformPane.marginWidth = 0; | ||||
| 		gl_waveformPane.marginHeight = 0; | ||||
| 		waveformPane.setLayout(gl_waveformPane); | ||||
| 		 | ||||
| 		waveformCanvas = new WaveformCanvas(waveformPane, SWT.NONE | SWT.V_SCROLL /*| SWT.H_SCROLL*/, styleProvider, new ZoomBar.IProvider() { | ||||
| 			 | ||||
| 			@Override | ||||
| 			public ZoomBar getScrollBar() { | ||||
| 				ZoomBar timeSliderPane = new ZoomBar(waveformPane, SWT.NONE); | ||||
| 				GridData gd_timeSliderPane = new GridData(SWT.FILL, SWT.BOTTOM, false, false, 1, 1); | ||||
| 				timeSliderPane.setLayoutData(gd_timeSliderPane); | ||||
| 				return timeSliderPane; | ||||
| 			} | ||||
| 		}); | ||||
| 		waveformCanvas.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1)); | ||||
| 		 | ||||
| 		// create the name pane | ||||
| 		createTextPane(namePane, "Name"); | ||||
|  | ||||
| @@ -364,7 +383,10 @@ public class WaveformView implements IWaveformView { | ||||
| 			@Override | ||||
| 			public void controlResized(ControlEvent e) { | ||||
| 				nameListScrolled.getVerticalBar().setVisible(false); | ||||
|  | ||||
| 				if(nameListScrolled.getSize().y == nameList.getSize().y) { | ||||
| 					((GridData)nameFill.getLayoutData()).heightHint=18; | ||||
| 					namePane.layout(); | ||||
| 				} | ||||
| 			} | ||||
| 		}); | ||||
| 		nameList = new Canvas(nameListScrolled, SWT.NONE) { | ||||
| @@ -383,7 +405,8 @@ public class WaveformView implements IWaveformView { | ||||
| 		}); | ||||
| 		nameList.addMouseListener(nameValueMouseListener); | ||||
| 		nameListScrolled.setContent(nameList); | ||||
|  | ||||
| 		nameFill = createFill(namePane); | ||||
| 		 | ||||
| 		createTextPane(valuePane, "Value"); | ||||
|  | ||||
| 		valuePane.setBackground(SWTResourceManager.getColor(SWT.COLOR_WIDGET_BACKGROUND)); | ||||
| @@ -396,7 +419,10 @@ public class WaveformView implements IWaveformView { | ||||
| 			@Override | ||||
| 			public void controlResized(ControlEvent e) { | ||||
| 				valueListScrolled.getVerticalBar().setVisible(false); | ||||
|  | ||||
| 				if(valueListScrolled.getSize().y == valueList.getSize().y) { | ||||
| 					((GridData)valueFill.getLayoutData()).heightHint=18; | ||||
| 					valuePane.layout(); | ||||
| 				} | ||||
| 			} | ||||
| 		}); | ||||
| 		valueList = new Canvas(valueListScrolled, SWT.NONE) { | ||||
| @@ -415,6 +441,7 @@ public class WaveformView implements IWaveformView { | ||||
| 		}); | ||||
| 		valueList.addMouseListener(nameValueMouseListener); | ||||
| 		valueListScrolled.setContent(valueList); | ||||
| 		valueFill = createFill(valuePane); | ||||
|  | ||||
| 		waveformCanvas.setMaxTime(1); | ||||
| 		waveformCanvas.addPaintListener(waveformMouseListener); | ||||
| @@ -461,6 +488,26 @@ public class WaveformView implements IWaveformView { | ||||
|  | ||||
| 		toolTipHandler = new ToolTipHandler(parent.getShell()); | ||||
| 		toolTipHandler.activateHoverHelp(waveformCanvas); | ||||
| 	    // This is the filter that prevents the default handling of mouse wheel in waveformCanvas | ||||
| 	    getControl().getDisplay().addFilter(SWT.MouseWheel, new Listener() { | ||||
| 	        @Override | ||||
| 	        public void handleEvent(Event e) { | ||||
| 	            // Check if it's the correct widget | ||||
| 	            if(e.widget.equals(waveformCanvas) && (e.stateMask & SWT.CTRL) != 0) { | ||||
| 	            	waveformMouseListener.handleEvent(e); | ||||
| 	                e.doit = false; | ||||
| 	            } | ||||
| 	        } | ||||
| 	    }); | ||||
| 	} | ||||
|  | ||||
| 	private Control createFill(Composite pane) { | ||||
| 		Label cLabel = new Label(pane, SWT.NONE); | ||||
| 		cLabel.setBackground(SWTResourceManager.getColor(SWT.COLOR_WIDGET_BACKGROUND)); | ||||
| 		GridData gd_cLabel = new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1); | ||||
| 		gd_cLabel.heightHint = 0; | ||||
| 		cLabel.setLayoutData(gd_cLabel); | ||||
| 		return cLabel; | ||||
| 	} | ||||
|  | ||||
| 	private void createTextPane(Composite namePane, String text) { | ||||
| @@ -528,7 +575,7 @@ public class WaveformView implements IWaveformView { | ||||
| 			tracksVerticalHeight += streamEntry.height; | ||||
| 			even = !even; | ||||
| 		} | ||||
| 		waveformCanvas.syncScrollBars(); | ||||
| 		waveformCanvas.syncSb(); | ||||
| 		nameList.setSize(nameMaxWidth + 15, tracksVerticalHeight); | ||||
| 		nameListScrolled.setMinSize(nameMaxWidth + 15, tracksVerticalHeight); | ||||
| 		nameList.redraw(); | ||||
| @@ -752,27 +799,30 @@ public class WaveformView implements IWaveformView { | ||||
| 				if (!add) | ||||
| 					currentWaveformSelection.clear(); | ||||
| 				List<?> selList = sel.toList(); | ||||
| 				if (selList.get(0) instanceof ITx) { | ||||
| 					ITx txSel = (ITx) selList.get(0); | ||||
| 					TrackEntry trackEntry = selList.size() == 2 && selList.get(1) instanceof TrackEntry | ||||
| 							? (TrackEntry) selList.get(1) | ||||
| 							: null; | ||||
| 					if (trackEntry == null) { | ||||
| 						trackEntry = getEntryFor(txSel); | ||||
| 						if (trackEntry == null && addIfNeeded) { | ||||
| 							trackEntry = new TrackEntry(txSel.getStream(), styleProvider); | ||||
| 							streams.add(trackEntry); | ||||
| 				for(Object o: selList) { | ||||
| 					if (o instanceof ITx) { | ||||
| 						ITx txSel = (ITx) o; | ||||
| 						TrackEntry trackEntry = selList.size() == 2 && selList.get(1) instanceof TrackEntry | ||||
| 								? (TrackEntry) selList.get(1) | ||||
| 										: null; | ||||
| 						if (trackEntry == null) { | ||||
| 							trackEntry = getEntryFor(txSel); | ||||
| 							if (trackEntry == null && addIfNeeded) { | ||||
| 								trackEntry = new TrackEntry(txSel.getStream(), styleProvider); | ||||
| 								streams.add(trackEntry); | ||||
| 							} | ||||
| 						} | ||||
| 						currentTxSelection = txSel; | ||||
| 						currentWaveformSelection.clear(); | ||||
| 						currentWaveformSelection.add(trackEntry); | ||||
| 						selectionChanged = true; | ||||
| 					} else if (o instanceof TrackEntry) { | ||||
| 						TrackEntry e = (TrackEntry)o; | ||||
| 						if(!currentWaveformSelection.contains(e)) | ||||
| 							currentWaveformSelection.add(e); | ||||
| 						selectionChanged = true; | ||||
| 					} | ||||
| 					currentTxSelection = txSel; | ||||
| 					currentWaveformSelection.clear(); | ||||
| 					currentWaveformSelection.add(trackEntry); | ||||
| 					selectionChanged = true; | ||||
| 				} else if (selList.size() == 1 && selList.get(0) instanceof TrackEntry) { | ||||
| 					currentWaveformSelection.add((TrackEntry) selList.get(0)); | ||||
| 					if (currentTxSelection != null) | ||||
| 						currentTxSelection = null; | ||||
| 					selectionChanged = true; | ||||
| 					 | ||||
| 				} | ||||
| 			} | ||||
| 		} else { | ||||
| @@ -930,7 +980,7 @@ public class WaveformView implements IWaveformView { | ||||
| 			return candidates.get(0); | ||||
| 		default: | ||||
| 			ArrayList<ITxRelation> visibleCandidates = candidates.stream().filter(this::streamsVisible) | ||||
| 					.collect(Collectors.toCollection(ArrayList::new)); | ||||
| 			.collect(Collectors.toCollection(ArrayList::new)); | ||||
| 			if (visibleCandidates.isEmpty()) { | ||||
| 				return new RelSelectionDialog(waveformCanvas.getShell(), candidates, target).open(); | ||||
| 			} else if (visibleCandidates.size() == 1) { | ||||
| @@ -1115,16 +1165,6 @@ public class WaveformView implements IWaveformView { | ||||
| 		this.waveformCanvas.setHighliteRelation(relationType); | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * (non-Javadoc) | ||||
| 	 *  | ||||
| 	 * @see com.minres.scviewer.database.swt.IWaveformPanel#getMaxTime() | ||||
| 	 */ | ||||
| 	@Override | ||||
| 	public long getMaxTime() { | ||||
| 		return waveformCanvas.getMaxTime(); | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * (non-Javadoc) | ||||
| 	 *  | ||||
| @@ -1135,27 +1175,6 @@ public class WaveformView implements IWaveformView { | ||||
| 		this.waveformCanvas.setMaxTime(maxTime); | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * (non-Javadoc) | ||||
| 	 *  | ||||
| 	 * @see com.minres.scviewer.database.swt.IWaveformPanel#setZoomLevel(int) | ||||
| 	 */ | ||||
| 	@Override | ||||
| 	public void setZoomLevel(int scale) { | ||||
| 		waveformCanvas.setZoomLevel(scale); | ||||
| 		waveformCanvas.reveal(getCursorTime()); | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * (non-Javadoc) | ||||
| 	 *  | ||||
| 	 * @see com.minres.scviewer.database.swt.IWaveformPanel#getZoomLevel() | ||||
| 	 */ | ||||
| 	@Override | ||||
| 	public int getZoomLevel() { | ||||
| 		return waveformCanvas.getZoomLevel(); | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * (non-Javadoc) | ||||
| 	 *  | ||||
| @@ -1174,10 +1193,10 @@ public class WaveformView implements IWaveformView { | ||||
| 	 * @see com.minres.scviewer.database.swt.IWaveformPanel#setMarkerTime(long, int) | ||||
| 	 */ | ||||
| 	@Override | ||||
| 	public void setMarkerTime(long time, int index) { | ||||
| 		if (waveformCanvas.getCursorPainters().size() > index + 1) { | ||||
| 			final Long oldVal = waveformCanvas.getCursorPainters().get(1 + index).getTime(); | ||||
| 			waveformCanvas.getCursorPainters().get(1 + index).setTime(time); | ||||
| 	public void setMarkerTime(int marker, long time) { | ||||
| 		if (waveformCanvas.getCursorPainters().size() > marker + 1) { | ||||
| 			final Long oldVal = waveformCanvas.getCursorPainters().get(1 + marker).getTime(); | ||||
| 			waveformCanvas.getCursorPainters().get(1 + marker).setTime(time); | ||||
| 			pcs.firePropertyChange(MARKER_PROPERTY, oldVal, time); | ||||
| 		} | ||||
| 	} | ||||
| @@ -1198,7 +1217,7 @@ public class WaveformView implements IWaveformView { | ||||
| 	 * @see com.minres.scviewer.database.swt.IWaveformPanel#getActMarkerTime() | ||||
| 	 */ | ||||
| 	@Override | ||||
| 	public int getSelectedMarkerId() { | ||||
| 	public int getSelectedMarker() { | ||||
| 		return selectedMarker; | ||||
| 	} | ||||
|  | ||||
| @@ -1230,7 +1249,7 @@ public class WaveformView implements IWaveformView { | ||||
| 				if (event.y < tracksVerticalHeight) { | ||||
| 					event.doit = true; | ||||
| 					LocalSelectionTransfer.getTransfer() | ||||
| 							.setSelection(new StructuredSelection(currentWaveformSelection)); | ||||
| 					.setSelection(new StructuredSelection(currentWaveformSelection)); | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| @@ -1450,58 +1469,32 @@ public class WaveformView implements IWaveformView { | ||||
| 		return this.pcs.hasListeners(propertyName); | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * (non-Javadoc) | ||||
| 	 *  | ||||
| 	 * @see com.minres.scviewer.database.swt.IWaveformPanel#getScaledTime(long) | ||||
| 	 */ | ||||
| 	@Override | ||||
| 	public String getScaledTime(long time) { | ||||
| 		StringBuilder sb = new StringBuilder(); | ||||
| 		double dTime = time; | ||||
| 		double scaledTime = dTime / waveformCanvas.getScaleFactorPow10(); | ||||
| 		return sb.append(df.format(scaledTime)).append(waveformCanvas.getUnitStr()).toString(); | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * (non-Javadoc) | ||||
| 	 *  | ||||
| 	 * @see com.minres.scviewer.database.swt.IWaveformPanel#getZoomLevels() | ||||
| 	 */ | ||||
| 	@Override | ||||
| 	public String[] getZoomLevels() { | ||||
| 		String[] res = new String[Constants.UNIT_MULTIPLIER.length * Constants.UNIT_STRING.length]; | ||||
| 		int index = 0; | ||||
| 		for (String unit : Constants.UNIT_STRING) { | ||||
| 			for (int factor : Constants.UNIT_MULTIPLIER) { | ||||
| 				res[index++] = Integer.toString(factor) + unit; | ||||
| 			} | ||||
| 		} | ||||
| 		return res; | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public long getBaselineTime() { | ||||
| 		return -waveformCanvas.getScaleFactorPow10() * waveformCanvas.getOrigin().x; | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public void setBaselineTime(Long time) { | ||||
| 		Point origin = waveformCanvas.getOrigin(); | ||||
| 		origin.x = (int) (-time / waveformCanvas.getScaleFactorPow10()); | ||||
| 		waveformCanvas.setOrigin(origin); | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public void scrollHorizontal(int percent) { | ||||
| 		if (percent < -100) | ||||
| 			percent = -100; | ||||
| 		if (percent > 100) | ||||
| 			percent = 100; | ||||
| 		int diff = (waveformCanvas.getWidth() * percent) / 100; | ||||
| 		Point o = waveformCanvas.getOrigin(); | ||||
| 		waveformCanvas.setOrigin(o.x - diff, o.y); | ||||
| 		waveformCanvas.redraw(); | ||||
| 		long minTime = waveformCanvas.getMinVisibleTime(); | ||||
| 		long duration = waveformCanvas.getMaxVisibleTime()-minTime; | ||||
| 		long diff = (duration * percent) / 100; | ||||
| 		waveformCanvas.setMinVisibleTime(minTime+diff); | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public void scrollTo(int pos) { | ||||
| 		long time = 0; | ||||
| 		switch(pos) { | ||||
| 		case IWaveformView.CURSOR_POS: | ||||
| 			time = getCursorTime(); | ||||
| 			break; | ||||
| 		case IWaveformView.MARKER_POS: | ||||
| 			time = getMarkerTime(selectedMarker); | ||||
| 			break; | ||||
| 		default: | ||||
| 			break; | ||||
| 		} | ||||
| 		waveformCanvas.centerAt(time); | ||||
| 	} | ||||
|  | ||||
| 	public void asyncUpdate(Widget widget) { | ||||
| @@ -1533,5 +1526,13 @@ public class WaveformView implements IWaveformView { | ||||
| 			getStreamList().add(idx, e); | ||||
| 		return e; | ||||
| 	} | ||||
| 	 | ||||
| 	public boolean waveformsContainsTx() { | ||||
| 		return  streams.stream().filter(e -> e.waveform.getType() == WaveformType.TRANSACTION).findFirst().isPresent(); | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public IWaveformZoom getWaveformZoom() { | ||||
| 		return waveformCanvas; | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,35 @@ | ||||
| package com.minres.scviewer.database.ui.swt.internal.slider; | ||||
|  | ||||
| import org.eclipse.swt.widgets.Display; | ||||
|  | ||||
| public class ActionTimer implements Runnable { | ||||
|  | ||||
| 	public static final int INITIAL_DELAY = 300; | ||||
| 	public static final int FAST_DELAY = 50; | ||||
|  | ||||
| 	private final Display display; | ||||
| 	private final TimerAction timerAction; | ||||
|  | ||||
| 	public interface TimerAction extends Runnable { | ||||
| 		boolean isEnabled(); | ||||
| 	} | ||||
|  | ||||
| 	public ActionTimer( TimerAction timerAction, Display display ) { | ||||
| 		this.display = display; | ||||
| 		this.timerAction = timerAction; | ||||
| 	} | ||||
|  | ||||
| 	public void activate() { | ||||
| 		if( timerAction.isEnabled() ) { | ||||
| 			display.timerExec( INITIAL_DELAY, this ); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public void run() { | ||||
| 		if( timerAction.isEnabled() ) { | ||||
| 			timerAction.run(); | ||||
| 			display.timerExec( FAST_DELAY, this ); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -0,0 +1,192 @@ | ||||
| package com.minres.scviewer.database.ui.swt.internal.slider; | ||||
|  | ||||
| import org.eclipse.swt.SWT; | ||||
| import org.eclipse.swt.SWTException; | ||||
| import org.eclipse.swt.events.MouseAdapter; | ||||
| import org.eclipse.swt.events.MouseEvent; | ||||
| import org.eclipse.swt.events.MouseTrackAdapter; | ||||
| import org.eclipse.swt.events.SelectionListener; | ||||
| import org.eclipse.swt.graphics.GC; | ||||
| import org.eclipse.swt.graphics.Image; | ||||
| import org.eclipse.swt.graphics.Point; | ||||
| import org.eclipse.swt.widgets.Composite; | ||||
| import org.eclipse.swt.widgets.Display; | ||||
| import org.eclipse.swt.widgets.Event; | ||||
|  | ||||
| public class ImageButton extends Composite | ||||
| { | ||||
| 	private Image   hoverImage; | ||||
| 	private Image   normalImage; | ||||
| 	private Image   pressedImage; | ||||
| 	private Image   disabledImage; | ||||
| 	private int     width; | ||||
| 	private int     height; | ||||
| 	private boolean hover; | ||||
| 	private boolean pressed; | ||||
| 	private boolean autoFire; | ||||
| 	private ActionTimer actionTimer; | ||||
| 	private ActionTimer.TimerAction timerAction; | ||||
|  | ||||
| 	public ImageButton(Composite parent, int style)	{ | ||||
| 		super(parent, style);		 | ||||
| 		timerAction = new ActionTimer.TimerAction() { | ||||
| 			@Override | ||||
| 			public void run() { | ||||
| 				notifyListeners(); | ||||
| 			} | ||||
| 			@Override | ||||
| 			public boolean isEnabled() { | ||||
| 				return pressed; | ||||
| 			} | ||||
| 		}; | ||||
| 		actionTimer = new ActionTimer(timerAction, this.getDisplay() ); | ||||
| 		addListener(SWT.Dispose, event ->  { | ||||
| 			if (hoverImage != null)	hoverImage.dispose(); | ||||
| 			if (normalImage != null) normalImage.dispose(); | ||||
| 			if (pressedImage != null) pressedImage.dispose(); | ||||
| 			if (disabledImage != null) disabledImage.dispose(); | ||||
| 		}); | ||||
| 		addListener(SWT.Paint, event -> { | ||||
| 			paintControl(event); | ||||
| 		}); | ||||
| 		addMouseTrackListener(new MouseTrackAdapter() { | ||||
| 			public void mouseEnter(MouseEvent arg0) { | ||||
| 				if(isEnabled()) { | ||||
| 					hover=true; | ||||
| 					redraw(); | ||||
| 				} | ||||
| 			} | ||||
| 			public void mouseExit(MouseEvent arg0) { | ||||
| 				if(isEnabled()) { | ||||
| 					hover=false; | ||||
| 					redraw(); | ||||
| 				} | ||||
| 			} | ||||
| 		}); | ||||
| 		addMouseListener(new MouseAdapter() { | ||||
| 			@Override | ||||
| 			public void mouseDown(MouseEvent e) { | ||||
| 				if(isEnabled()) { | ||||
| 					pressed=true; | ||||
| 					notifyListeners(); | ||||
| 					if(autoFire) actionTimer.activate(); | ||||
| 					redraw(); | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			@Override | ||||
| 			public void mouseUp(MouseEvent e) { | ||||
| 				pressed=false; | ||||
| 				redraw(); | ||||
| 			} | ||||
| 		}); | ||||
| 	} | ||||
|  | ||||
| 	private void paintControl(Event event) {  | ||||
| 		GC gc = event.gc; | ||||
| 		if (hoverImage != null)	{ | ||||
| 			if(pressed) | ||||
| 				gc.drawImage(pressedImage, 1, 1); | ||||
| 			else if(hover) { | ||||
| 				gc.drawImage(hoverImage, 1, 1); | ||||
| 			} else if(isEnabled()){ | ||||
| 				gc.drawImage(normalImage, 1, 1); | ||||
| 			} else | ||||
| 				gc.drawImage(disabledImage, 1, 1); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	public void setImage(Image[] imgs) { | ||||
| 		assert(imgs.length==3); | ||||
| 		Display d = Display.getDefault(); | ||||
| 		normalImage =   new Image(d, imgs[0], SWT.IMAGE_COPY); | ||||
| 		hoverImage =    new Image(d, imgs[1], SWT.IMAGE_COPY); | ||||
| 		pressedImage =  new Image(d, imgs[2], SWT.IMAGE_COPY); | ||||
| 		disabledImage = new Image(d, imgs[0], SWT.IMAGE_DISABLE); | ||||
| 		width = imgs[0].getBounds().width; | ||||
| 		height = imgs[0].getBounds().height; | ||||
| 		redraw(); | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public Point computeSize(int wHint, int hHint, boolean changed) { | ||||
| 		int overallWidth = width; | ||||
| 		int overallHeight = height; | ||||
| 		if (wHint != SWT.DEFAULT && wHint < overallWidth) | ||||
| 			overallWidth = wHint; | ||||
| 		if (hHint != SWT.DEFAULT && hHint < overallHeight) | ||||
| 			overallHeight = hHint; | ||||
| 		return new Point(overallWidth + 2, overallHeight + 2); | ||||
| 	} | ||||
| 	/** | ||||
| 	 * Adds the listener to the collection of listeners who will be notified when | ||||
| 	 * the user changes the receiver's value, by sending it one of the messages | ||||
| 	 * defined in the <code>SelectionListener</code> interface. | ||||
| 	 * <p> | ||||
| 	 * <code>widgetSelected</code> is called when the user changes the receiver's | ||||
| 	 * value. <code>widgetDefaultSelected</code> is not called. | ||||
| 	 * </p> | ||||
| 	 * | ||||
| 	 * @param listener the listener which should be notified | ||||
| 	 * | ||||
| 	 * @exception IllegalArgumentException | ||||
| 	 *                <ul> | ||||
| 	 *                <li>ERROR_NULL_ARGUMENT - if the listener is null</li> | ||||
| 	 *                </ul> | ||||
| 	 * @exception SWTException | ||||
| 	 *                <ul> | ||||
| 	 *                <li>ERROR_WIDGET_DISPOSED - if the receiver has been | ||||
| 	 *                disposed</li> | ||||
| 	 *                <li>ERROR_THREAD_INVALID_ACCESS - if not called from the | ||||
| 	 *                thread that created the receiver</li> | ||||
| 	 *                </ul> | ||||
| 	 * | ||||
| 	 * @see SelectionListener | ||||
| 	 * @see #removeSelectionListener | ||||
| 	 */ | ||||
| 	public void addSelectionListener(final SelectionListener listener) { | ||||
| 		checkWidget(); | ||||
| 		SelectionListenerUtil.addSelectionListener(this, listener); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Removes the listener from the collection of listeners who will be notified | ||||
| 	 * when the user changes the receiver's value. | ||||
| 	 * | ||||
| 	 * @param listener the listener which should no longer be notified | ||||
| 	 * | ||||
| 	 * @exception IllegalArgumentException | ||||
| 	 *                <ul> | ||||
| 	 *                <li>ERROR_NULL_ARGUMENT - if the listener is null</li> | ||||
| 	 *                </ul> | ||||
| 	 * @exception SWTException | ||||
| 	 *                <ul> | ||||
| 	 *                <li>ERROR_WIDGET_DISPOSED - if the receiver has been | ||||
| 	 *                disposed</li> | ||||
| 	 *                <li>ERROR_THREAD_INVALID_ACCESS - if not called from the | ||||
| 	 *                thread that created the receiver</li> | ||||
| 	 *                </ul> | ||||
| 	 * | ||||
| 	 * @see SelectionListener | ||||
| 	 * @see #addSelectionListener | ||||
| 	 */ | ||||
| 	public void removeSelectionListener(final SelectionListener listener) { | ||||
| 		checkWidget(); | ||||
| 		SelectionListenerUtil.removeSelectionListener(this, listener); | ||||
| 	} | ||||
|  | ||||
| 	private void notifyListeners() { | ||||
| 		Event e = new Event(); | ||||
| 		e.widget=this; | ||||
| 		e.type=SWT.Selection; | ||||
| 		SelectionListenerUtil.fireSelectionListeners(this,e); | ||||
| 	} | ||||
|  | ||||
| 	public boolean isAutoFire() { | ||||
| 		return autoFire; | ||||
| 	} | ||||
|  | ||||
| 	public void setAutoFire(boolean autoFire) { | ||||
| 		this.autoFire = autoFire; | ||||
| 	} | ||||
| } | ||||
| @@ -0,0 +1,631 @@ | ||||
| package com.minres.scviewer.database.ui.swt.internal.slider; | ||||
|  | ||||
| import java.text.Format; | ||||
|  | ||||
| import org.eclipse.swt.SWT; | ||||
| import org.eclipse.swt.events.MouseEvent; | ||||
| import org.eclipse.swt.events.MouseTrackAdapter; | ||||
| import org.eclipse.swt.events.PaintEvent; | ||||
| import org.eclipse.swt.events.SelectionListener; | ||||
| 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.Event; | ||||
| import org.eclipse.wb.swt.SWTResourceManager; | ||||
|  | ||||
| public class RangeSlider extends Canvas { | ||||
|  | ||||
| 	private static final int NONE = 0; | ||||
| 	private static final int UPPER = 1 << 0; | ||||
| 	private static final int LOWER = 1 << 1; | ||||
| 	private static final int BOTH = UPPER | LOWER; | ||||
|  | ||||
| 	private final int minHeight; | ||||
| 	private final int markerWidth; | ||||
| 	private final int thumbWidth = 0; | ||||
| 	private final Image[] slider, sliderHover, sliderDrag; | ||||
| 	 | ||||
| 	private int minimum; | ||||
| 	private int maximum; | ||||
| 	private int lowerValue; | ||||
| 	private int upperValue; | ||||
| 	 | ||||
| 	private int increment; | ||||
| 	private int pageIncrement; | ||||
| 	private int selectedElement; | ||||
| 	private boolean upperHover, lowerHover; | ||||
| 	private int previousUpperValue, previousLowerValue; | ||||
| 	private int startDragUpperValue, startDragLowerValue; | ||||
| 	private Point startDragPoint; | ||||
| 	private final boolean isFullSelection=false; | ||||
| 	private final boolean isHighQuality; | ||||
| 	private final boolean isOn; | ||||
| 	private Format toolTipFormatter; | ||||
| 	private String clientToolTipText; | ||||
| 	private StringBuffer toolTip; | ||||
| 	private Point coordUpper; | ||||
| 	private Point coordLower; | ||||
|  | ||||
| 	public RangeSlider(final Composite parent, final int style) { | ||||
| 		super(parent, SWT.DOUBLE_BUFFERED | ((style & SWT.BORDER) == SWT.BORDER ? SWT.BORDER : SWT.NONE)); | ||||
| 		slider = new Image[] { | ||||
| 				SWTResourceManager.getImage(this.getClass(), "marker_l.png"), | ||||
| 				SWTResourceManager.getImage(this.getClass(), "marker_r.png")}; | ||||
| 		sliderHover = new Image[] { | ||||
| 				SWTResourceManager.getImage(this.getClass(), "marker_l_hover.png"), | ||||
| 				SWTResourceManager.getImage(this.getClass(), "marker_r_hover.png")}; | ||||
| 		sliderDrag = new Image[] { | ||||
| 				SWTResourceManager.getImage(this.getClass(), "marker_l_pressed.png"), | ||||
| 				SWTResourceManager.getImage(this.getClass(), "marker_r_pressed.png")}; | ||||
| 		Rectangle imgSize = slider[0].getBounds(); | ||||
| 		minHeight =imgSize.height+2; | ||||
| 		markerWidth = imgSize.width; | ||||
| 		minimum = lowerValue = 0; | ||||
| 		maximum = upperValue = 100; | ||||
| 		increment = 1; | ||||
| 		pageIncrement = 10; | ||||
| 		isHighQuality = (style & SWT.HIGH) == SWT.HIGH; | ||||
| 		isOn = (style & SWT.ON) == SWT.ON; | ||||
| 		selectedElement = NONE; | ||||
|  | ||||
| 		addMouseListeners(); | ||||
| 		addListener(SWT.Resize, event -> { | ||||
| 		}); | ||||
| 		addListener(SWT.KeyDown, event -> { | ||||
| 			handleKeyDown(event); | ||||
| 		}); | ||||
| 		addPaintListener(event -> { | ||||
| 			drawWidget(event); | ||||
| 		}); | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public int getStyle() { | ||||
| 		return super.getStyle() | // | ||||
| 				(isOn ? SWT.ON : SWT.NONE) | // | ||||
| 				(isFullSelection ? SWT.CONTROL : SWT.NONE) | // | ||||
| 				(isHighQuality ? SWT.HIGH : SWT.NONE); | ||||
| 	} | ||||
|  | ||||
| 	private void addMouseListeners() { | ||||
| 		addListener(SWT.MouseDown, e -> { | ||||
| 			if (e.button == 1 || e.button == 2) { | ||||
| 				selectKnobs(e); | ||||
| 				selectedElement = (lowerHover ? LOWER : NONE) | (upperHover ? UPPER : NONE); | ||||
| 				if (selectedElement!=NONE) { | ||||
| 					if((e.stateMask & SWT.CTRL)==0 && e.button != 2) | ||||
| 						selectedElement=BOTH; | ||||
| 					startDragLowerValue = previousLowerValue = lowerValue; | ||||
| 					startDragUpperValue = previousUpperValue = upperValue; | ||||
| 					startDragPoint = new Point(e.x, e.y); | ||||
| 				} | ||||
| 			} | ||||
| 		}); | ||||
|  | ||||
| 		addListener(SWT.MouseUp, e -> { | ||||
| 			if (selectedElement!=NONE) { | ||||
| 				startDragPoint = null; | ||||
| 				validateNewValues(e); | ||||
| 				super.setToolTipText(clientToolTipText); | ||||
| 				selectedElement=NONE; | ||||
| 				redraw(); | ||||
| 			} else if (e.button == 1) { | ||||
| 				if(e.x<coordLower.x) { | ||||
| 					translateValues(-pageIncrement); | ||||
| 					validateNewValues(e); | ||||
| 					redraw(); | ||||
| 				} else if(e.x>coordUpper.x+markerWidth) { | ||||
| 					translateValues(pageIncrement); | ||||
| 					validateNewValues(e); | ||||
| 					redraw(); | ||||
| 				} | ||||
| 			} | ||||
| 		}); | ||||
|  | ||||
| 		addListener(SWT.MouseDoubleClick, event -> { | ||||
| 			handleMouseDoubleClick(event); | ||||
| 		}); | ||||
|  | ||||
| 		addListener(SWT.MouseMove, event -> { | ||||
| 			handleMouseMove(event); | ||||
| 		}); | ||||
|  | ||||
| 		addListener(SWT.MouseWheel, event -> { | ||||
| 			handleMouseWheel(event); | ||||
| 		}); | ||||
|  | ||||
| 		addListener(SWT.MouseHover, event -> { | ||||
| 			handleMouseHover(event); | ||||
| 		}); | ||||
|  | ||||
| 		addMouseTrackListener(new MouseTrackAdapter() { | ||||
| 			public void mouseExit(MouseEvent event) { | ||||
| 				lowerHover = upperHover = false; | ||||
| 				redraw(); | ||||
| 			} | ||||
| 		}); | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	private void validateNewValues(final Event e) { | ||||
| 		if (upperValue != previousUpperValue || lowerValue != previousLowerValue) { | ||||
| 			if (!SelectionListenerUtil.fireSelectionListeners(this,e)) { | ||||
| 				upperValue = previousUpperValue; | ||||
| 				lowerValue = previousLowerValue; | ||||
| 			} | ||||
| 			previousUpperValue = upperValue; | ||||
| 			previousLowerValue = lowerValue; | ||||
| 			increment = Math.max(1,  (upperValue-lowerValue)/100); | ||||
| 			pageIncrement = Math.max(1, (upperValue-lowerValue)/2); | ||||
| 			redraw(); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	private boolean busy = false; | ||||
| 	 | ||||
| 	private void handleMouseMove(final Event e) { | ||||
| 		if (selectedElement==NONE) { | ||||
| 			final boolean wasUpper = upperHover; | ||||
| 			final boolean wasLower = lowerHover; | ||||
| 			selectKnobs(e); | ||||
| 			if (wasUpper != upperHover || wasLower != lowerHover) { | ||||
| 				redraw(); | ||||
| 			} | ||||
| 		} else { // dragInProgress | ||||
| 			final int x = e.x; | ||||
| 			if (selectedElement == BOTH) { | ||||
| 				final int diff = (int) ((startDragPoint.x - x) / computePixelSizeForSlider()) + minimum; | ||||
| 				int newUpper = startDragUpperValue - diff; | ||||
| 				int newLower = startDragLowerValue - diff; | ||||
| 				if (newUpper > maximum) { | ||||
| 					newUpper = maximum; | ||||
| 					newLower = maximum - (startDragUpperValue - startDragLowerValue); | ||||
| 				} else if (newLower < minimum) { | ||||
| 					newLower = minimum; | ||||
| 					newUpper = minimum + startDragUpperValue - startDragLowerValue; | ||||
| 				} | ||||
| 				upperValue = newUpper; | ||||
| 				lowerValue = newLower; | ||||
| 				handleToolTip(lowerValue, upperValue); | ||||
| 			} else if (selectedElement == UPPER) { | ||||
| 				upperValue = (int) Math.round((double)(x - markerWidth) / computePixelSizeForSlider()) + minimum; | ||||
| 				checkUpperValue(); | ||||
| 				handleToolTip(upperValue); | ||||
| 			} else if (selectedElement == LOWER){ | ||||
| 				lowerValue = (int) Math.round((double)(x - markerWidth) / computePixelSizeForSlider()) + minimum; | ||||
| 				checkLowerValue(); | ||||
| 				handleToolTip(lowerValue); | ||||
| 			} | ||||
| 			if (isOn && !busy) { | ||||
| 				validateNewValues(e); | ||||
| 				busy=true; | ||||
| 				getDisplay().timerExec(50, ()->{busy=false;}); | ||||
| 			} else { | ||||
| 				redraw(); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	private boolean isBetweenKnobs(int x, int y) { | ||||
| 		return x < coordUpper.x && x > coordLower.x && y >= minHeight/3 && y <= minHeight/3 + getClientArea().height - 2*minHeight/3; | ||||
| 	} | ||||
|  | ||||
| 	private void selectKnobs(final Event e) { | ||||
| 		if (coordLower != null) { | ||||
| 			final Rectangle imgBounds = slider[0].getBounds(); | ||||
| 			final int x = e.x, y = e.y; | ||||
| 			lowerHover = x >= coordLower.x && x <= coordLower.x + imgBounds.width && y >= coordLower.y && y <= coordLower.y + imgBounds.height; | ||||
| 			upperHover = ((e.stateMask & (SWT.CTRL | SWT.SHIFT)) != 0 || !lowerHover) && // | ||||
| 					x >= coordUpper.x && x <= coordUpper.x + imgBounds.width && // | ||||
| 					y >= coordUpper.y && y <= coordUpper.y + imgBounds.height; | ||||
| 					lowerHover &= (e.stateMask & SWT.CTRL) != 0 || !upperHover; | ||||
| 			if (!lowerHover && !upperHover && isBetweenKnobs(x, y)) { | ||||
| 				lowerHover = upperHover = true; | ||||
| 			}		 | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	private int getCursorValue(int x, int y) { | ||||
| 		int value = -1; | ||||
| 		final Rectangle clientArea = getClientArea(); | ||||
| 		if (x < clientArea.width - 2*markerWidth && x >= markerWidth && y >= minHeight/3 && y <=  clientArea.height - minHeight/3) { | ||||
| 			value = (int) Math.round((x - 9d) / computePixelSizeForSlider()) + minimum; | ||||
| 		} | ||||
| 		return value; | ||||
| 	} | ||||
|  | ||||
| 	private void handleMouseDoubleClick(final Event e) { | ||||
| 		final int value = getCursorValue(e.x, e.y); | ||||
| 		if (value >= 0) { | ||||
| 			if (value > upperValue) { | ||||
| 				translateValues(value-upperValue); | ||||
| 			} else if (value < lowerValue) { | ||||
| 				translateValues(value-lowerValue); | ||||
| 			} | ||||
| 			validateNewValues(e); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	private void handleToolTip(int... values) { | ||||
| 		if (toolTipFormatter != null) { | ||||
| 			try { | ||||
| 				if (values.length == 1) { | ||||
| 					toolTip.setLength(0); | ||||
| 					toolTipFormatter.format(values[0], toolTip, null); | ||||
| 					super.setToolTipText(toolTip.toString()); | ||||
| 				} else if (values.length == 2) { | ||||
| 					toolTip.setLength(0); | ||||
| 					toolTipFormatter.format(values[0], toolTip, null); | ||||
| 					toolTip.append(" \u2194 "); // LEFT RIGHT ARROW | ||||
| 					toolTipFormatter.format(values[1], toolTip, null); | ||||
| 					super.setToolTipText(toolTip.toString()); | ||||
| 				} | ||||
| 			} catch (final IllegalArgumentException ex) { | ||||
| 				super.setToolTipText(clientToolTipText); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	private void handleMouseHover(final Event e) { | ||||
| 		if (selectedElement!=NONE && toolTipFormatter != null) { | ||||
| 			final int value = getCursorValue(e.x, e.y); | ||||
| 			if (value >= 0) { | ||||
| 				try { | ||||
| 					toolTip.setLength(0); | ||||
| 					toolTipFormatter.format(value, toolTip, null); | ||||
| 					super.setToolTipText(toolTip.toString()); | ||||
| 				} catch (final IllegalArgumentException ex) { | ||||
| 					super.setToolTipText(clientToolTipText); | ||||
| 				} | ||||
| 			} else { | ||||
| 				super.setToolTipText(clientToolTipText); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	public void setToolTipFormatter(Format formatter) { | ||||
| 		toolTip = formatter != null ? new StringBuffer() : null; | ||||
| 		toolTipFormatter = formatter; | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public void setToolTipText(String string) { | ||||
| 		super.setToolTipText(clientToolTipText = string); | ||||
| 	} | ||||
|  | ||||
| 	private void handleMouseWheel(final Event e) { | ||||
| 		previousLowerValue = lowerValue; | ||||
| 		previousUpperValue = upperValue; | ||||
| 		final int amount = Math.max(1, ((e.stateMask & SWT.SHIFT) != 0 ? (upperValue-lowerValue)/6 : (upperValue-lowerValue)/15)); | ||||
| 		if ((e.stateMask&SWT.CTRL)==0) { | ||||
| 			int newLower = lowerValue + e.count * amount; | ||||
| 			int newUpper = upperValue + e.count * amount; | ||||
| 			if (newUpper > maximum) { | ||||
| 				newUpper = maximum; | ||||
| 				newLower = maximum - (upperValue - lowerValue); | ||||
| 			} else if (newLower < minimum) { | ||||
| 				newLower = minimum; | ||||
| 				newUpper = minimum + upperValue - lowerValue; | ||||
| 			} | ||||
| 			upperValue = newUpper; | ||||
| 			lowerValue = newLower; | ||||
| 		} else { | ||||
| 			int newLower = lowerValue + e.count * amount/2; | ||||
| 			int newUpper = upperValue - e.count * amount/2; | ||||
| 			int dist = newUpper - newLower; | ||||
| 			if (newUpper > maximum) { | ||||
| 				newUpper = maximum; | ||||
| 				newLower = maximum - dist; | ||||
| 			} else if (newLower < minimum) { | ||||
| 				newLower = minimum; | ||||
| 				newUpper = minimum + dist; | ||||
| 			} | ||||
| 			if(newUpper<=newLower) { | ||||
| 				newLower=lowerValue + (upperValue - lowerValue)/2; | ||||
| 				newUpper=newLower+1; | ||||
| 			} | ||||
| 			upperValue = newUpper; | ||||
| 			lowerValue = newLower; | ||||
| 		} | ||||
| 		validateNewValues(e); | ||||
| 		e.doit = false; // we are consuming this event | ||||
| 	} | ||||
|  | ||||
| 	private void checkLowerValue() { | ||||
| 		if (lowerValue < minimum) { | ||||
| 			lowerValue = minimum; | ||||
| 		} else if (lowerValue > (upperValue-thumbWidth)) { | ||||
| 			lowerValue = (upperValue-thumbWidth); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	private void checkUpperValue() { | ||||
| 		if (upperValue > maximum) { | ||||
| 			upperValue = maximum; | ||||
| 		} else if (upperValue < (lowerValue+thumbWidth)) { | ||||
| 			upperValue = lowerValue+thumbWidth; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	private float computePixelSizeForSlider() { | ||||
| 		return (getClientArea().width - 2.0f*markerWidth) / (maximum - minimum); | ||||
| 	} | ||||
|  | ||||
| 	private void drawWidget(final PaintEvent e) { | ||||
| 		final Rectangle rect = getClientArea(); | ||||
| 		if (rect.width == 0 || rect.height == 0) { | ||||
| 			return; | ||||
| 		} | ||||
| 		e.gc.setAdvanced(true); | ||||
| 		e.gc.setAntialias(SWT.ON); | ||||
| 		drawBackground(e.gc); | ||||
| 		if (lowerHover || (selectedElement & LOWER) != 0) { | ||||
| 			coordUpper = drawMarker(e.gc, upperValue, true); | ||||
| 			coordLower = drawMarker(e.gc, lowerValue, false); | ||||
| 		} else { | ||||
| 			coordLower = drawMarker(e.gc, lowerValue, false); | ||||
| 			coordUpper = drawMarker(e.gc, upperValue, true); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	private void drawBackground(final GC gc) { | ||||
| 		final Rectangle clientArea = getClientArea(); | ||||
| 		gc.setBackground(getBackground()); | ||||
| 		gc.fillRectangle(clientArea); | ||||
| 		if (isEnabled()) { | ||||
| 			gc.setForeground(getForeground()); | ||||
| 		} else { | ||||
| 			gc.setForeground(getDisplay().getSystemColor(SWT.COLOR_GRAY)); | ||||
| 		} | ||||
| 		gc.drawRoundRectangle(markerWidth, minHeight/3, clientArea.width - 2*markerWidth, clientArea.height -  2*minHeight/3, 3, 3); | ||||
|  | ||||
| 		final float pixelSize = computePixelSizeForSlider(); | ||||
| 		final int startX = (int) (pixelSize * lowerValue); | ||||
| 		final int endX = (int) (pixelSize * upperValue); | ||||
| 		if (isEnabled()) { | ||||
| 			gc.setBackground(getForeground()); | ||||
| 		} else { | ||||
| 			gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_GRAY)); | ||||
| 		} | ||||
| 		gc.fillRectangle(markerWidth+startX, minHeight/3, endX - startX, clientArea.height - 2*minHeight/3); | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	private Point drawMarker(final GC gc, final int value, final boolean upper) { | ||||
| 		final float pixelSize = computePixelSizeForSlider(); | ||||
| 		int x = (int) (pixelSize * value); | ||||
| 		final int idx = upper?1:0; | ||||
| 		Image image; | ||||
| 		if (upper) { | ||||
| 			if (upperHover) { | ||||
| 				image = (selectedElement & UPPER) != 0 ? sliderDrag[idx] : sliderHover[idx]; | ||||
| 			} else { | ||||
| 				image = slider[idx]; | ||||
| 			} | ||||
| 		} else { | ||||
| 			if (lowerHover) { | ||||
| 				image = (selectedElement & LOWER) != 0 ? sliderDrag[idx] : sliderHover[idx]; | ||||
| 			} else { | ||||
| 				image = slider[idx]; | ||||
| 			} | ||||
| 		} | ||||
| 		if(upper) | ||||
| 			x+=slider[idx].getBounds().width; | ||||
| 		if (isEnabled()) { | ||||
| 			gc.drawImage(image, x, getClientArea().height / 2 - slider[idx].getBounds().height / 2); | ||||
| 		} else { | ||||
| 			final Image temp = new Image(getDisplay(), image, SWT.IMAGE_DISABLE); | ||||
| 			gc.drawImage(temp, x, getClientArea().height / 2 - slider[idx].getBounds().height / 2); | ||||
| 			temp.dispose(); | ||||
| 		} | ||||
| 		return new Point(x, getClientArea().height / 2 - slider[idx].getBounds().height / 2); | ||||
| 	} | ||||
|  | ||||
| 	private void moveCursorPosition(int xDelta, int yDelta) { | ||||
| 		final Point cursorPosition = getDisplay().getCursorLocation(); | ||||
| 		cursorPosition.x += xDelta; | ||||
| 		cursorPosition.y += yDelta; | ||||
| 		getDisplay().setCursorLocation(cursorPosition); | ||||
| 	} | ||||
|  | ||||
| 	private void handleKeyDown(final Event event) { | ||||
| 		int accelerator = (event.stateMask & SWT.SHIFT) != 0 ? 10 : (event.stateMask & SWT.CTRL) != 0 ? 2 : 1; | ||||
| 		if (selectedElement != NONE) { | ||||
| 			switch (event.keyCode) { | ||||
| 			case SWT.ESC: | ||||
| 				startDragPoint = null; | ||||
| 				upperValue = startDragUpperValue; | ||||
| 				lowerValue = startDragLowerValue; | ||||
| 				validateNewValues(event); | ||||
| 				selectedElement = NONE; | ||||
| 				if (!isOn) { | ||||
| 					redraw(); | ||||
| 				} | ||||
| 				event.doit = false; | ||||
| 				break; | ||||
| 			case SWT.ARROW_UP: | ||||
| 				accelerator = -accelerator; | ||||
| 			case SWT.ARROW_LEFT: | ||||
| 				moveCursorPosition(-accelerator, 0); | ||||
| 				event.doit = false; | ||||
| 				break; | ||||
| 			case SWT.ARROW_DOWN: | ||||
| 				accelerator = -accelerator; | ||||
| 			case SWT.ARROW_RIGHT: | ||||
| 				moveCursorPosition(accelerator, 0); | ||||
| 				event.doit = false; | ||||
| 				break; | ||||
| 			} | ||||
| 			return; | ||||
| 		} | ||||
| 		previousLowerValue = lowerValue; | ||||
| 		previousUpperValue = upperValue; | ||||
|  | ||||
| 		switch (event.keyCode) { | ||||
| 		case SWT.HOME: | ||||
| 			if ((event.stateMask & (SWT.SHIFT| SWT.CTRL)) == 0) { | ||||
| 				upperValue = minimum + upperValue - lowerValue; | ||||
| 				lowerValue = minimum; | ||||
| 			} | ||||
| 			break; | ||||
| 		case SWT.END: | ||||
| 			if ((event.stateMask & (SWT.SHIFT| SWT.CTRL)) == 0) { | ||||
| 				lowerValue = maximum - (upperValue - lowerValue); | ||||
| 				upperValue = maximum; | ||||
| 			} | ||||
| 			break; | ||||
| 		case SWT.PAGE_UP: | ||||
| 			translateValues(-accelerator * pageIncrement); | ||||
| 			break; | ||||
| 		case SWT.PAGE_DOWN: | ||||
| 			translateValues( accelerator * pageIncrement); | ||||
| 			break; | ||||
| 		case SWT.ARROW_DOWN: | ||||
| 		case SWT.ARROW_RIGHT: | ||||
| 			translateValues( accelerator * increment); | ||||
| 			break; | ||||
| 		case SWT.ARROW_UP: | ||||
| 		case SWT.ARROW_LEFT: | ||||
| 			translateValues(-accelerator * increment); | ||||
| 			break; | ||||
| 		} | ||||
| 		if (previousLowerValue != lowerValue || previousUpperValue != upperValue) { | ||||
| 			checkLowerValue(); | ||||
| 			checkUpperValue(); | ||||
| 			validateNewValues(event); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	private void translateValues(int amount) { | ||||
| 		int newLower = lowerValue + amount; | ||||
| 		int newUpper = upperValue + amount; | ||||
| 		if (newUpper > maximum) { | ||||
| 			newUpper = maximum; | ||||
| 			newLower = maximum - (upperValue - lowerValue); | ||||
| 		} else if (newLower < minimum) { | ||||
| 			newLower = minimum; | ||||
| 			newUpper = minimum + upperValue - lowerValue; | ||||
| 		} | ||||
| 		upperValue = newUpper; | ||||
| 		lowerValue = newLower; | ||||
| 	} | ||||
|  | ||||
| 	public void addSelectionListener(final SelectionListener listener) { | ||||
| 		checkWidget(); | ||||
| 		SelectionListenerUtil.addSelectionListener(this, listener); | ||||
| 	} | ||||
|  | ||||
| 	public void removeSelectionListener(final SelectionListener listener) { | ||||
| 		checkWidget(); | ||||
| 		SelectionListenerUtil.removeSelectionListener(this, listener); | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public Point computeSize(final int wHint, final int hHint, final boolean changed) { | ||||
| 		checkWidget(); | ||||
| 		final int width = Math.max(2*markerWidth+100, wHint); | ||||
| 		final int height = Math.max(minHeight, hHint); | ||||
| 		return new Point(width, height); | ||||
| 	} | ||||
|  | ||||
| 	public int[] getSelection() { | ||||
| 		checkWidget(); | ||||
| 		return new int[] {lowerValue, upperValue}; | ||||
| 	} | ||||
|  | ||||
| 	public int getIncrement() { | ||||
| 		checkWidget(); | ||||
| 		return increment; | ||||
| 	} | ||||
|  | ||||
| 	public int getMaximum() { | ||||
| 		checkWidget(); | ||||
| 		return maximum; | ||||
| 	} | ||||
|  | ||||
| 	public int getMinimum() { | ||||
| 		checkWidget(); | ||||
| 		return minimum; | ||||
| 	} | ||||
|  | ||||
| 	public int getPageIncrement() { | ||||
| 		checkWidget(); | ||||
| 		return pageIncrement; | ||||
| 	} | ||||
|  | ||||
| 	public void setMaximum(final int value) { | ||||
| 		setLimits(minimum, value); | ||||
| 	} | ||||
|  | ||||
| 	public void setMinimum(final int value) { | ||||
| 		setLimits(value, maximum); | ||||
| 	} | ||||
|  | ||||
| 	public void setLimits(final int min, final int max) { | ||||
| 		checkWidget(); | ||||
| 		if (min >= 0 && min < max && (min != minimum || max != maximum)) { | ||||
| 			minimum = min; | ||||
| 			maximum = max; | ||||
| 			if (lowerValue < minimum) { | ||||
| 				lowerValue = minimum; | ||||
| 			} else if (lowerValue > maximum) { | ||||
| 				lowerValue = maximum; | ||||
| 			} | ||||
| 			if (upperValue < minimum) { | ||||
| 				upperValue = minimum; | ||||
| 			} else if (upperValue > maximum) { | ||||
| 				upperValue = maximum; | ||||
| 			} | ||||
| 			redraw(); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	public int getUpperValue() { | ||||
| 		checkWidget(); | ||||
| 		return upperValue; | ||||
| 	} | ||||
|  | ||||
| 	public void setUpperValue(final int value) { | ||||
| 		setValues(lowerValue, value); | ||||
| 	} | ||||
|  | ||||
| 	public int getLowerValue() { | ||||
| 		checkWidget(); | ||||
| 		return lowerValue; | ||||
| 	} | ||||
|  | ||||
| 	public void setLowerValue(final int value) { | ||||
| 		setValues(value, upperValue); | ||||
| 	} | ||||
|  | ||||
| 	public void setValues(final int[] values) { | ||||
| 		if (values.length == 2) { | ||||
| 			setValues(values[0], values[1]); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	public void setValues(final int lowerValue, final int upperValue) { | ||||
| 		setValues(lowerValue, upperValue, false); | ||||
| 	} | ||||
|  | ||||
| 	public void setValues(final int lowerValue, final int upperValue, boolean update) { | ||||
| 		checkWidget(); | ||||
| 		if (lowerValue <= upperValue && lowerValue >= minimum && upperValue <= maximum && (this.lowerValue != lowerValue || this.upperValue != upperValue)) { | ||||
| 			this.lowerValue = lowerValue; | ||||
| 			this.upperValue = upperValue; | ||||
| 			if(update) { | ||||
| 				Event e = new Event(); | ||||
| 				e.type=SWT.Selection; | ||||
| 				e.doit=true; | ||||
| 				validateNewValues(e);			 | ||||
| 			} else { | ||||
| 				increment = Math.max(1,  (upperValue-lowerValue)/100); | ||||
| 				pageIncrement = Math.max(1, (upperValue-lowerValue)/2); | ||||
| 			} | ||||
| 			redraw(); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -0,0 +1,48 @@ | ||||
| package com.minres.scviewer.database.ui.swt.internal.slider; | ||||
| import java.lang.reflect.InvocationTargetException; | ||||
| import java.lang.reflect.Method; | ||||
|  | ||||
| public class ReflectionUtils { | ||||
| 	/** | ||||
| 	 * Call a method using introspection (so ones can call a private or protected method) | ||||
| 	 * @param object object on which the method will be called | ||||
| 	 * @param methodName method name | ||||
| 	 * @param args arguments of this method (can be null) | ||||
| 	 * @return the value returned by this method (if this method returns a value) | ||||
| 	 */ | ||||
| 	public static Object callMethod(final Object object, final String methodName, final Object... args) { | ||||
| 		if (object == null) { | ||||
| 			return null; | ||||
| 		} | ||||
| 		final Class<?>[] array = new Class<?>[args == null ? 0 : args.length]; | ||||
| 		int index = 0; | ||||
| 		if (args != null) { | ||||
| 			for (final Object o : args) { | ||||
| 				array[index++] = o == null ? Object.class : o.getClass(); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		return callMethodWithClassType(object, methodName, array, args); | ||||
| 	} | ||||
|  | ||||
| 	private static Object callMethodWithClassType(final Object object, final String methodName, final Class<?>[] array, final Object... args) { | ||||
| 		Class<?> currentClass = object.getClass(); | ||||
| 		Method method = null; | ||||
| 		while (currentClass != null) { | ||||
| 			try { | ||||
| 				method = currentClass.getDeclaredMethod(methodName, array); | ||||
| 				break; | ||||
| 			} catch (final NoSuchMethodException nsme) { | ||||
| 				currentClass = currentClass.getSuperclass(); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		try { | ||||
| 			method.setAccessible(true); | ||||
| 			return method.invoke(object, args); | ||||
| 		} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { | ||||
| 			e.printStackTrace(); | ||||
| 			return null; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -0,0 +1,74 @@ | ||||
| package com.minres.scviewer.database.ui.swt.internal.slider; | ||||
| import org.eclipse.swt.SWT; | ||||
| import org.eclipse.swt.events.SelectionListener; | ||||
| import org.eclipse.swt.widgets.Control; | ||||
| import org.eclipse.swt.widgets.Event; | ||||
| import org.eclipse.swt.widgets.Listener; | ||||
| import org.eclipse.swt.widgets.TypedListener; | ||||
|  | ||||
| public class SelectionListenerUtil { | ||||
| 	/** | ||||
| 	 * Add a <code>SelectionListener</code> to a given Control | ||||
| 	 *  | ||||
| 	 * @param control control on which the selection listener is added | ||||
| 	 * @param listener listener to add | ||||
| 	 */ | ||||
| 	public static void addSelectionListener(final Control control, final SelectionListener listener) { | ||||
| 		if (listener == null) { | ||||
| 			SWT.error(SWT.ERROR_NULL_ARGUMENT); | ||||
| 		} | ||||
| 		TypedListener typedListener = new TypedListener(listener); | ||||
| 		control.addListener(SWT.Selection, typedListener); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Remove a <code>SelectionListener</code> of a given Control | ||||
| 	 *  | ||||
| 	 * @param control control on which the selection listener is removed | ||||
| 	 * @param listener listener to remove | ||||
| 	 */ | ||||
| 	public static void removeSelectionListener(final Control control, final SelectionListener listener) { | ||||
| 		if (listener == null) { | ||||
| 			SWT.error(SWT.ERROR_NULL_ARGUMENT); | ||||
| 		} | ||||
| 		final Listener[] listeners = control.getListeners(SWT.Selection); | ||||
| 		for (Listener l : listeners) { | ||||
| 			if (l instanceof TypedListener) { | ||||
| 				TypedListener typedListener = (TypedListener) l; | ||||
| 				if (typedListener.getEventListener() == listener) { | ||||
| 					ReflectionUtils.callMethod(control, "removeListener", SWT.Selection, ((TypedListener) l).getEventListener()); | ||||
| 					return; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Fire the selection listeners of a given control | ||||
| 	 * | ||||
| 	 * @param control the control that fires the event | ||||
| 	 * @param sourceEvent mouse event | ||||
| 	 * @return true if the selection could be changed, false otherwise | ||||
| 	 */ | ||||
| 	public static boolean fireSelectionListeners(final Control control, final Event sourceEvent) { | ||||
| 		for (final Listener listener : control.getListeners(SWT.Selection)) { | ||||
| 			final Event event = new Event(); | ||||
|  | ||||
| 			event.button = sourceEvent==null?1:sourceEvent.button; | ||||
| 			event.display = control.getDisplay(); | ||||
| 			event.item = null; | ||||
| 			event.widget = control; | ||||
| 			event.data = sourceEvent == null ? null : sourceEvent.data; | ||||
| 			event.time = sourceEvent == null ? 0 : sourceEvent.time; | ||||
| 			event.x = sourceEvent == null ? 0 : sourceEvent.x; | ||||
| 			event.y = sourceEvent == null ? 0 : sourceEvent.y; | ||||
| 			event.type = SWT.Selection; | ||||
|  | ||||
| 			listener.handleEvent(event); | ||||
| 			if (!event.doit) { | ||||
| 				return false; | ||||
| 			} | ||||
| 		} | ||||
| 		return true; | ||||
| 	} | ||||
| } | ||||
| @@ -0,0 +1,127 @@ | ||||
| package com.minres.scviewer.database.ui.swt.internal.slider; | ||||
|  | ||||
| import java.text.Format; | ||||
|  | ||||
| import org.eclipse.swt.SWT; | ||||
| import org.eclipse.swt.events.SelectionAdapter; | ||||
| import org.eclipse.swt.events.SelectionEvent; | ||||
| import org.eclipse.swt.events.SelectionListener; | ||||
| import org.eclipse.swt.graphics.Image; | ||||
| import org.eclipse.swt.layout.GridData; | ||||
| import org.eclipse.swt.layout.GridLayout; | ||||
| import org.eclipse.swt.widgets.Composite; | ||||
| import org.eclipse.wb.swt.SWTResourceManager; | ||||
|  | ||||
| public class ZoomBar extends Composite { | ||||
| 	 | ||||
| 	static public interface IProvider { | ||||
| 		ZoomBar getScrollBar(); | ||||
| 	} | ||||
|  | ||||
| 	final RangeSlider timeSlider; | ||||
| 	final ImageButton leftButton; | ||||
| 	final ImageButton rightButton; | ||||
| 	/** | ||||
| 	 * Create the composite. | ||||
| 	 * @param parent | ||||
| 	 * @param style | ||||
| 	 */ | ||||
| 	public ZoomBar(Composite parent, int style) { | ||||
| 		super(parent, SWT.NO_FOCUS); | ||||
| 		GridLayout gridLayout = new GridLayout(3, false); | ||||
| 		gridLayout.horizontalSpacing = 0; | ||||
| 		gridLayout.verticalSpacing = 0; | ||||
| 		gridLayout.marginWidth = 0; | ||||
| 		gridLayout.marginHeight = 0; | ||||
| 		setLayout(gridLayout); | ||||
|  | ||||
| 		leftButton = new ImageButton(this, SWT.NONE); | ||||
| 		GridData gd_leftButton = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1); | ||||
| 		gd_leftButton.widthHint=14; | ||||
| 		gd_leftButton.heightHint=18; | ||||
| 		leftButton.setLayoutData(gd_leftButton); | ||||
| 		leftButton.setImage(new Image[] { | ||||
| 				SWTResourceManager.getImage(this.getClass(), "arrow_left.png"), | ||||
| 				SWTResourceManager.getImage(this.getClass(), "arrow_left_hover.png"), | ||||
| 				SWTResourceManager.getImage(this.getClass(), "arrow_left_pressed.png")}); | ||||
| 		leftButton.setAutoFire(true); | ||||
| 		 | ||||
| 		timeSlider = new RangeSlider(this, SWT.ON|SWT.HIGH|SWT.SMOOTH|SWT.CONTROL); | ||||
| 		timeSlider.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); | ||||
|  | ||||
| 		rightButton = new ImageButton(this, SWT.NONE); | ||||
| 		GridData gd_rightButton = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1); | ||||
| 		gd_rightButton.widthHint=18; | ||||
| 		gd_rightButton.heightHint=18; | ||||
| 		rightButton.setLayoutData(gd_rightButton); | ||||
| 		rightButton.setImage(new Image[] { | ||||
| 				SWTResourceManager.getImage(this.getClass(), "arrow_right.png"), | ||||
| 				SWTResourceManager.getImage(this.getClass(), "arrow_right_hover.png"), | ||||
| 				SWTResourceManager.getImage(this.getClass(), "arrow_right_pressed.png")}); | ||||
| 		rightButton.setAutoFire(true); | ||||
| 		 | ||||
| 		leftButton.addSelectionListener(new SelectionAdapter() { | ||||
| 			@Override | ||||
| 			public void widgetSelected(SelectionEvent e) { | ||||
| 				int[] value = timeSlider.getSelection(); | ||||
| 				int incr=timeSlider.getIncrement(); | ||||
| 				int lower = Math.max(timeSlider.getMinimum(), value[0]-incr); | ||||
| 				timeSlider.setValues(lower, lower + (value[1]-value[0]), true); | ||||
| 			} | ||||
| 		}); | ||||
| 		rightButton.addSelectionListener(new SelectionAdapter() { | ||||
| 			@Override | ||||
| 			public void widgetSelected(SelectionEvent e) { | ||||
| 				int[] value = timeSlider.getSelection(); | ||||
| 				int incr=timeSlider.getIncrement(); | ||||
| 				int upper = Math.min(timeSlider.getMaximum(), value[1]+incr); | ||||
| 				timeSlider.setValues(upper - (value[1]-value[0]), upper, true); | ||||
| 			} | ||||
| 		}); | ||||
|  | ||||
| 	} | ||||
| 	@Override | ||||
| 	public void setEnabled (boolean enabled) { | ||||
| 		timeSlider.setEnabled(enabled); | ||||
| 		leftButton.setEnabled(enabled); | ||||
| 		rightButton.setEnabled(enabled); | ||||
| 		super.setEnabled(enabled); | ||||
| 		redraw(); | ||||
| 	} | ||||
| 	public void setButtonsEnabled (boolean enabled) { | ||||
| 		leftButton.setEnabled(enabled); | ||||
| 		rightButton.setEnabled(enabled); | ||||
| 		redraw(); | ||||
| 	} | ||||
| 	public void setToolTipFormatter(Format formatter){ | ||||
| 		timeSlider.setToolTipFormatter(formatter); | ||||
| 	} | ||||
| 	public void setToolTipText(String string) { | ||||
| 		timeSlider.setToolTipText(string); | ||||
| 	} | ||||
| 	public void setSelection(int sel) { | ||||
| 		timeSlider.setLowerValue(sel); | ||||
| 	} | ||||
| 	public void setSelection(int[] sel) { | ||||
| 		assert(sel.length==2); | ||||
| 		timeSlider.setValues(sel[0], sel[1]); | ||||
| 	} | ||||
| 	public int[] getSelection() { | ||||
| 		return timeSlider.getSelection(); | ||||
| 	} | ||||
| 	public void addSelectionListener(SelectionListener selectionListener) { | ||||
| 		timeSlider.addSelectionListener(selectionListener);	 | ||||
| 	} | ||||
| 	public void setMinimum(int value) { | ||||
| 		timeSlider.setMinimum(value);	 | ||||
| 	} | ||||
| 	public void setMaximum(int value) { | ||||
| 		timeSlider.setMaximum(value);	 | ||||
| 	} | ||||
| 	public int getMaximum() { | ||||
| 		return timeSlider.getMaximum(); | ||||
| 	} | ||||
| 	public int getMinimum() { | ||||
| 		return timeSlider.getMinimum(); | ||||
| 	} | ||||
| } | ||||
| After Width: | Height: | Size: 352 B | 
| After Width: | Height: | Size: 326 B | 
| After Width: | Height: | Size: 352 B | 
| After Width: | Height: | Size: 305 B | 
| After Width: | Height: | Size: 302 B | 
| After Width: | Height: | Size: 339 B | 
| After Width: | Height: | Size: 350 B | 
| After Width: | Height: | Size: 336 B | 
| After Width: | Height: | Size: 352 B | 
| After Width: | Height: | Size: 329 B | 
| After Width: | Height: | Size: 326 B | 
| After Width: | Height: | Size: 349 B | 
| @@ -0,0 +1,18 @@ | ||||
| package com.minres.scviewer.database.ui.swt.sb; | ||||
|  | ||||
| import org.eclipse.swt.widgets.Display; | ||||
|  | ||||
| public class ActionScheduler { | ||||
|  | ||||
|   private final Display display; | ||||
|   private final Runnable action; | ||||
|  | ||||
|   public ActionScheduler( Display display, Runnable action ) { | ||||
|     this.display = display; | ||||
|     this.action = action; | ||||
|   } | ||||
|  | ||||
|   public void schedule( int delay ) { | ||||
|     display.timerExec( delay, action ); | ||||
|   } | ||||
| } | ||||
| @@ -0,0 +1,45 @@ | ||||
| package com.minres.scviewer.database.ui.swt.sb; | ||||
|  | ||||
| import org.eclipse.swt.events.MouseEvent; | ||||
| import org.eclipse.swt.graphics.Point; | ||||
| import org.eclipse.swt.widgets.Control; | ||||
|  | ||||
| public class ButtonClick { | ||||
|  | ||||
|   public static final int LEFT_BUTTON = 1; | ||||
|  | ||||
|   private boolean armed; | ||||
|  | ||||
|   public boolean isArmed() { | ||||
|     return armed; | ||||
|   } | ||||
|  | ||||
|   public void arm( MouseEvent event ) { | ||||
|     if( event.button == LEFT_BUTTON ) { | ||||
|       armed = true; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   public void disarm() { | ||||
|     armed = false; | ||||
|   } | ||||
|  | ||||
|   public void trigger( MouseEvent event, Runnable action ) { | ||||
|     try { | ||||
|       doTrigger( event, action ); | ||||
|     } finally { | ||||
|       disarm(); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   private void doTrigger( MouseEvent event, Runnable action ) { | ||||
|     if( armed && inRange( event ) ) { | ||||
|       action.run(); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   private static boolean inRange( MouseEvent event ) { | ||||
|     Point size = ( ( Control )event.widget ).getSize(); | ||||
|     return event.x >= 0 && event.x <= size.x && event.y >= 0 && event.y <= size.y; | ||||
|   } | ||||
| } | ||||
| @@ -0,0 +1,98 @@ | ||||
| package com.minres.scviewer.database.ui.swt.sb; | ||||
|  | ||||
| import org.eclipse.swt.SWT; | ||||
| import org.eclipse.swt.events.ControlAdapter; | ||||
| import org.eclipse.swt.events.ControlEvent; | ||||
| import org.eclipse.swt.events.MouseEvent; | ||||
| import org.eclipse.swt.events.MouseListener; | ||||
| import org.eclipse.swt.events.MouseTrackListener; | ||||
| import org.eclipse.swt.graphics.Color; | ||||
| import org.eclipse.swt.widgets.Composite; | ||||
| import org.eclipse.swt.widgets.Label; | ||||
|  | ||||
|  | ||||
| class ClickControl extends ControlAdapter implements ViewComponent, MouseDownActionTimer.TimerAction, MouseListener, MouseTrackListener { | ||||
|  | ||||
|   private final MouseDownActionTimer mouseDownActionTimer; | ||||
|   private final ClickAction clickAction; | ||||
|   private final ButtonClick buttonClick; | ||||
|   private final Label control; | ||||
|   private final ImageUpdate imageUpdate; | ||||
|  | ||||
|   public interface ClickAction extends Runnable { | ||||
|     void setCoordinates( int x, int y ); | ||||
|   } | ||||
|  | ||||
|   ClickControl( Composite parent, ClickAction clickAction, int maxExtension  ) { | ||||
|     this.control = new Label( parent, SWT.NONE ); | ||||
|     this.imageUpdate = new ImageUpdate( control, maxExtension ); | ||||
|     this.buttonClick = new ButtonClick(); | ||||
|     this.mouseDownActionTimer = new MouseDownActionTimer( this, buttonClick, control.getDisplay() ); | ||||
|     this.clickAction = clickAction; | ||||
|     this.control.addMouseTrackListener( this ); | ||||
|     this.control.addMouseListener( this ); | ||||
|     this.control.addControlListener( this ); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void controlResized( ControlEvent event ) { | ||||
|     imageUpdate.update(); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public Label getControl() { | ||||
|     return control; | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void mouseDown( MouseEvent event ) { | ||||
|     buttonClick.arm( event ); | ||||
|     clickAction.setCoordinates( event.x, event.y ); | ||||
|     mouseDownActionTimer.activate(); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void mouseUp( MouseEvent event ) { | ||||
|     buttonClick.trigger( event, clickAction ); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void run() { | ||||
|     clickAction.run(); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public boolean isEnabled() { | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void mouseExit( MouseEvent event ) { | ||||
|     buttonClick.disarm(); | ||||
|   } | ||||
|  | ||||
|   void setForeground( Color color ) { | ||||
|     imageUpdate.setForeground( color ); | ||||
|   } | ||||
|  | ||||
|   Color getForeground() { | ||||
|     return imageUpdate.getForeground(); | ||||
|   } | ||||
|  | ||||
|   void setBackground( Color color ) { | ||||
|     imageUpdate.setBackground( color ); | ||||
|   } | ||||
|  | ||||
|   Color getBackground() { | ||||
|     return imageUpdate.getBackground(); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void mouseEnter( MouseEvent event ) {} | ||||
|  | ||||
|   @Override | ||||
|   public void mouseHover( MouseEvent event ) {} | ||||
|  | ||||
|   @Override | ||||
|   public void mouseDoubleClick( MouseEvent event ) {} | ||||
| } | ||||
| @@ -0,0 +1,105 @@ | ||||
| package com.minres.scviewer.database.ui.swt.sb; | ||||
|  | ||||
| import static java.lang.Math.max; | ||||
|  | ||||
| import java.math.BigDecimal; | ||||
| import java.math.RoundingMode; | ||||
|  | ||||
| class ComponentDistribution { | ||||
|  | ||||
|   private static final int MIN_DRAG_LENGTH = 17; | ||||
|  | ||||
|   final int upFastLength; | ||||
|   final int dragStart; | ||||
|   final int dragLength; | ||||
|   final int downFastStart; | ||||
|   final int downFastLength; | ||||
|   final int downStart; | ||||
|   final int buttonLen; | ||||
|  | ||||
|   ComponentDistribution( int buttonLen, int len, int range, int pos, int thumb ) { | ||||
|     int slideLen = slideLen( buttonLen, len ); | ||||
|     int relDragLen = relDragLen( slideLen, range, thumb ); | ||||
|     int minDragLength = max( MIN_DRAG_LENGTH, buttonLen ); | ||||
|     int interval = interval( range, relDragLen, minDragLength ); | ||||
|     this.dragLength = dragLen( minDragLength, relDragLen ); | ||||
|     this.upFastLength = upFastLen( minDragLength, interval, pos, slideLen, relDragLen, dragLength ); | ||||
|     this.downStart = downStart( buttonLen, len ); | ||||
|     this.downFastStart = downFastStart( buttonLen, upFastLength, dragLength ); | ||||
|     this.dragStart = dragStart( buttonLen, upFastLength ); | ||||
|     this.downFastLength = downFastLen( minDragLength, interval, pos, slideLen, relDragLen, dragLength, upFastLength ); | ||||
|     this.buttonLen = buttonLen; | ||||
|   } | ||||
|  | ||||
|   private static int slideLen( int buttonLen, int len ) { | ||||
|     return len - buttonLen * 2; | ||||
|   } | ||||
|  | ||||
|   private static int relDragLen( int slideLen, int range, int thumb ) { | ||||
|     return divide( slideLen * thumb, range ); | ||||
|   } | ||||
|  | ||||
|   private static int interval( int range, int relDragLen, int minDragLength ) { | ||||
|     int result = range; | ||||
|     if( useMinDragLen( minDragLength, relDragLen ) ) { | ||||
|       result += minDragLength - relDragLen / 2; | ||||
|     } | ||||
|     return result; | ||||
|   } | ||||
|  | ||||
|   private static int dragLen( int buttonLen, int relDragLen   ) { | ||||
|     return max( relDragLen, buttonLen ); | ||||
|   } | ||||
|  | ||||
|   private static int upFastLen( int buttonLen, int range, int pos, int slideLen, int relDragLen, int dragLen ) { | ||||
|     int result = slideLen * pos / range; | ||||
|     if( useMinDragLen( buttonLen, relDragLen ) ) { | ||||
|       result -= divide( ( dragLen - relDragLen ) * pos, range ); | ||||
|     } | ||||
|     return result; | ||||
|   } | ||||
|  | ||||
|   private static int downStart( int buttonLen, int len ) { | ||||
|     return len - buttonLen; | ||||
|   } | ||||
|  | ||||
|   private static int downFastStart( int buttonLen, int upFastLength, int dragLength ) { | ||||
|     return buttonLen + upFastLength + dragLength; | ||||
|   } | ||||
|  | ||||
|   private static int dragStart( int buttonLen, int upFastLen ) { | ||||
|     return buttonLen + upFastLen; | ||||
|   } | ||||
|  | ||||
|   private static int downFastLen( | ||||
|     int buttonLen, int range, int pos, int slideLen, int relDragLen, int dragLen, int upFastLen ) | ||||
|   { | ||||
|     int result = divide( slideLen * ( range - pos ), range ) - dragLen; | ||||
|     if( useMinDragLen( buttonLen, relDragLen ) ) { | ||||
|       result += divide( ( dragLen - relDragLen ) * pos, range ); | ||||
|     } | ||||
|     return adjustDownFastLen( result, slideLen, dragLen, upFastLen ); | ||||
|   } | ||||
|  | ||||
|   private static boolean useMinDragLen( int buttonLen, int relDragLen ) { | ||||
|     return relDragLen < buttonLen; | ||||
|   } | ||||
|  | ||||
|   static int divide( int dividend, int divisor ) { | ||||
|     BigDecimal bigDividend = new BigDecimal( dividend ); | ||||
|     BigDecimal bigDivisor = new BigDecimal( divisor ); | ||||
|     return bigDividend .divide( bigDivisor, 0, RoundingMode.HALF_EVEN ) .intValue(); | ||||
|   } | ||||
|  | ||||
|   private static int adjustDownFastLen( int tentative, int slideLen, int dragLen, int upFastLen ) { | ||||
|     // TODO [fappel]: Without this there is a flickering of the downFast label of one pixel. | ||||
|     //                Check whether this can be resolved by better rounding or whatsoever. | ||||
|     int result = tentative; | ||||
|     if( slideLen < upFastLen + dragLen + result ) { | ||||
|       result--; | ||||
|     } else if( slideLen > upFastLen + dragLen + result ) { | ||||
|       result++; | ||||
|     } | ||||
|     return result; | ||||
|   } | ||||
| } | ||||
| @@ -0,0 +1,24 @@ | ||||
| package com.minres.scviewer.database.ui.swt.sb; | ||||
|  | ||||
| import org.eclipse.swt.SWT; | ||||
|  | ||||
| import com.minres.scviewer.database.ui.swt.sb.ClickControl.ClickAction; | ||||
|  | ||||
| class Decrementer implements ClickAction { | ||||
|  | ||||
|   private final FlatScrollBar scrollBar; | ||||
|  | ||||
|   Decrementer( FlatScrollBar scrollBar ) { | ||||
|     this.scrollBar = scrollBar; | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void run() { | ||||
|     int selection = scrollBar.getSelection() - scrollBar.getIncrement(); | ||||
|     scrollBar.setSelectionInternal( selection, SWT.ARROW_UP ); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void setCoordinates( int x, int y ) { | ||||
|   } | ||||
| } | ||||
| @@ -0,0 +1,203 @@ | ||||
| package com.minres.scviewer.database.ui.swt.sb; | ||||
|  | ||||
| import static com.minres.scviewer.database.ui.swt.sb.FlatScrollBar.BAR_BREADTH; | ||||
| import static java.lang.Math.max; | ||||
|  | ||||
| import org.eclipse.swt.SWT; | ||||
| import org.eclipse.swt.graphics.Point; | ||||
| import org.eclipse.swt.graphics.Rectangle; | ||||
| import org.eclipse.swt.widgets.Composite; | ||||
| import org.eclipse.swt.widgets.Control; | ||||
|  | ||||
| enum Direction { | ||||
|  | ||||
|   HORIZONTAL( SWT.HORIZONTAL ) { | ||||
|  | ||||
|     @Override | ||||
|     protected void layout( FlatScrollBar scrollBar, int buttonLength  ) { | ||||
|       ComponentDistribution distribution = calculateComponentDistribution( scrollBar, buttonLength ); | ||||
|       Rectangle[] componentBounds = calculateComponentBounds( distribution, scrollBar ); | ||||
|       applyComponentBounds( scrollBar, componentBounds ); | ||||
|     } | ||||
|  | ||||
|     private ComponentDistribution calculateComponentDistribution( FlatScrollBar scrollBar, int buttonLength  ) { | ||||
|       return calculateComponentDistribution( scrollBar, buttonLength, getControlBounds( scrollBar ).width ); | ||||
|     } | ||||
|  | ||||
|     private Rectangle[] calculateComponentBounds( ComponentDistribution distribution, FlatScrollBar scrollBar ) { | ||||
|       int width = getControlBounds( scrollBar ).width; | ||||
|       int height = getControlBounds( scrollBar ).height - FlatScrollBar.BAR_BREADTH + 1; | ||||
|       int balance = getRoundingBalance( distribution, scrollBar ); | ||||
|       return new Rectangle[] { | ||||
|         calcButtons( distribution, width, $( 0, CLEARANCE, distribution.buttonLen, height ) ), | ||||
|         $( distribution.buttonLen, CLEARANCE, distribution.upFastLength, height ), | ||||
|         calcDrag( distribution, $( distribution.dragStart, CLEARANCE, distribution.dragLength + balance, height ) ), | ||||
|         $( distribution.downFastStart, CLEARANCE, distribution.downFastLength - balance, height ), | ||||
|         calcButtons( distribution, width, $( distribution.downStart, CLEARANCE, distribution.buttonLen, height ) ) | ||||
|       }; | ||||
|     } | ||||
|  | ||||
|     private Rectangle calcButtons( ComponentDistribution distribution, int length, Rectangle bounds ) { | ||||
|       Rectangle result = bounds; | ||||
|       if( length <= distribution.buttonLen* 2 ) { | ||||
|         int downStart = calcDownStartForSmallLength( bounds.x, length ); | ||||
|         result = $( downStart, CLEARANCE, length / 2, bounds.height ); | ||||
|       } | ||||
|       return result; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void setDefaultSize( Control control ) { | ||||
|       Point size = control.getSize(); | ||||
|       control.setSize( size.x, FlatScrollBar.BAR_BREADTH ); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected Point computeSize( Composite composite, int wHint, int hHint, boolean changed ) { | ||||
|       int x = wHint == SWT.DEFAULT ? composite.getParent().getClientArea().width : wHint; | ||||
|       return new Point( x, FlatScrollBar.BAR_BREADTH ); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void expand( Control control, int maxExpansion ) { | ||||
|       Rectangle bounds = control.getBounds(); | ||||
|       int expand = expand( bounds.height, maxExpansion ); | ||||
|       control.setBounds( bounds.x, bounds.y - expand, bounds.width, bounds.height + expand ); | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   VERTICAL( SWT.VERTICAL ) { | ||||
|  | ||||
|     @Override | ||||
|     protected void layout( FlatScrollBar scrollBar, int buttonLength ) { | ||||
|       ComponentDistribution calculation = calculateComponentDistribution( scrollBar, buttonLength ); | ||||
|       applyComponentBounds( scrollBar, calculateComponentBounds( calculation, scrollBar ) ); | ||||
|     } | ||||
|  | ||||
|     private ComponentDistribution calculateComponentDistribution( FlatScrollBar scrollBar, int buttonLength ) { | ||||
|       return calculateComponentDistribution( scrollBar, buttonLength, getControlBounds( scrollBar ).height ); | ||||
|     } | ||||
|  | ||||
|     private Rectangle[] calculateComponentBounds( ComponentDistribution distribution, FlatScrollBar scrollBar ) { | ||||
|       int width = getControlBounds( scrollBar ).width - FlatScrollBar.BAR_BREADTH + 1; | ||||
|       int height = getControlBounds( scrollBar ).height; | ||||
|       int balance = getRoundingBalance( distribution, scrollBar ); | ||||
|       return new Rectangle[] { | ||||
|         calculateButtons( distribution, height, $( CLEARANCE, 0, width, distribution.buttonLen ) ), | ||||
|         $( CLEARANCE, distribution.buttonLen, width, distribution.upFastLength ), | ||||
|         calcDrag( distribution, $( CLEARANCE, distribution.dragStart, width, distribution.dragLength + balance ) ), | ||||
|         $( CLEARANCE, distribution.downFastStart, width, distribution.downFastLength - balance ), | ||||
|         calculateButtons( distribution, height, $( CLEARANCE, distribution.downStart, width, distribution.buttonLen ) ) | ||||
|       }; | ||||
|     } | ||||
|  | ||||
|     private Rectangle calculateButtons( ComponentDistribution distribution, int length, Rectangle bounds ) { | ||||
|       Rectangle result = bounds; | ||||
|       if( length <= distribution.buttonLen * 2 ) { | ||||
|         int downStart = calcDownStartForSmallLength( bounds.y, length ); | ||||
|         result = $( CLEARANCE, downStart, bounds.width, length / 2 ); | ||||
|       } | ||||
|       return result; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void setDefaultSize( Control control ) { | ||||
|       Point size = control.getSize(); | ||||
|       control.setSize( FlatScrollBar.BAR_BREADTH, size.y ); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected Point computeSize( Composite composite, int wHint, int hHint, boolean changed ) { | ||||
|       int y = hHint == SWT.DEFAULT ? composite.getParent().getClientArea().height : hHint; | ||||
|       return new Point( FlatScrollBar.BAR_BREADTH, y ); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void expand( Control control, int maxExpansion ) { | ||||
|       Rectangle bounds = control.getBounds(); | ||||
|       int expand = expand( bounds.width, maxExpansion ); | ||||
|       control.setBounds( bounds.x - expand, bounds.y, bounds.width + expand, bounds.height ); | ||||
|     } | ||||
|   }; | ||||
|  | ||||
|   static final Rectangle EMPTY_RECTANGLE = $( 0, 0, 0, 0 ); | ||||
|   static final int CLEARANCE = BAR_BREADTH - 2; | ||||
|  | ||||
|   private final int value; | ||||
|  | ||||
|   protected abstract void layout( FlatScrollBar scrollBar, int buttonLength ); | ||||
|   protected abstract void setDefaultSize( Control control ); | ||||
|   protected abstract Point computeSize( Composite comp, int wHint, int hHint, boolean changed ); | ||||
|   protected abstract void expand( Control control, int maxExpansion  ); | ||||
|  | ||||
|   Direction( int value ) { | ||||
|     this.value = value; | ||||
|   } | ||||
|  | ||||
|   public int value() { | ||||
|     return value; | ||||
|   } | ||||
|  | ||||
|   private static ComponentDistribution calculateComponentDistribution( | ||||
|     FlatScrollBar scrollBar , int buttonLength , int length  ) | ||||
|   { | ||||
|     int range = scrollBar.getMaximum() - scrollBar.getMinimum(); | ||||
|     int position = scrollBar.getSelection() - scrollBar.getMinimum(); | ||||
|     int thumb = scrollBar.getThumb(); | ||||
|     return new ComponentDistribution( buttonLength, length, range, position, thumb ); | ||||
|   } | ||||
|  | ||||
|   private static Rectangle getControlBounds( FlatScrollBar scrollBar ) { | ||||
|     return scrollBar.getClientArea(); | ||||
|   } | ||||
|  | ||||
|   private static void applyComponentBounds( FlatScrollBar scrollBar, Rectangle[] bounds ) { | ||||
|     scrollBar.up.getControl().setBounds( bounds[ 0 ] ); | ||||
|     scrollBar.upFast.getControl().setBounds( bounds[ 1 ] ); | ||||
|     scrollBar.drag.getControl().setBounds( bounds[ 2 ] ); | ||||
|     scrollBar.downFast.getControl().setBounds( bounds[ 3 ] ); | ||||
|     scrollBar.down.getControl().setBounds( bounds[ 4 ] ); | ||||
|   } | ||||
|  | ||||
|   // TODO [fappel]: There is a 1 pixel rounding problem at the seam of drag/downFast with down. | ||||
|   //                Seems to work but I would prefer a better solution if possible | ||||
|   private static int getRoundingBalance( ComponentDistribution calculation, FlatScrollBar scrollBar ) { | ||||
|     int result = 0; | ||||
|     int maximumSelection = scrollBar.getMaximum() - scrollBar.getThumb(); | ||||
|     if( scrollBar.getSelection() == maximumSelection && 0 != calculation.downFastLength ) { | ||||
|       result = 1; | ||||
|     } | ||||
|     return result; | ||||
|   } | ||||
|  | ||||
|   private static int expand( int toExpand, int maxExpansion ) { | ||||
|     return max( 0, FlatScrollBar.BAR_BREADTH + maxExpansion - max( FlatScrollBar.BAR_BREADTH, toExpand ) ); | ||||
|   } | ||||
|  | ||||
|   private static Rectangle calcDrag( ComponentDistribution distribution, Rectangle bounds ) { | ||||
|     Rectangle result = bounds; | ||||
|     if( isUndercutOfDragVisibility( distribution ) ) { | ||||
|       result = EMPTY_RECTANGLE; | ||||
|     } | ||||
|     return result; | ||||
|   } | ||||
|  | ||||
|   private static boolean isUndercutOfDragVisibility( ComponentDistribution distribution ) { | ||||
|     return distribution.dragLength + distribution.buttonLen >= distribution.downStart; | ||||
|   } | ||||
|  | ||||
|   private static int calcDownStartForSmallLength( int position, int length ) { | ||||
|     int result = position; | ||||
|     if( isDownStartPosition( position ) ) { | ||||
|       result = length / 2; | ||||
|     } | ||||
|     return result; | ||||
|   } | ||||
|   private static boolean isDownStartPosition( int position ) { | ||||
|     return position > 0 || position < 0; | ||||
|   } | ||||
|  | ||||
|   private static Rectangle $( int x, int y, int width, int height ) { | ||||
|     return new Rectangle( x, y , width , height ); | ||||
|   } | ||||
| } | ||||
| @@ -0,0 +1,105 @@ | ||||
| package com.minres.scviewer.database.ui.swt.sb; | ||||
|  | ||||
| import org.eclipse.swt.SWT; | ||||
| import org.eclipse.swt.events.ControlAdapter; | ||||
| import org.eclipse.swt.events.ControlEvent; | ||||
| import org.eclipse.swt.events.DragDetectEvent; | ||||
| import org.eclipse.swt.events.DragDetectListener; | ||||
| import org.eclipse.swt.events.MouseEvent; | ||||
| import org.eclipse.swt.events.MouseListener; | ||||
| import org.eclipse.swt.events.MouseMoveListener; | ||||
| import org.eclipse.swt.graphics.Color; | ||||
| import org.eclipse.swt.graphics.Point; | ||||
| import org.eclipse.swt.widgets.Composite; | ||||
| import org.eclipse.swt.widgets.Label; | ||||
|  | ||||
|  | ||||
| class DragControl | ||||
|   extends ControlAdapter | ||||
|   implements ViewComponent, DragDetectListener, MouseListener, MouseMoveListener | ||||
| { | ||||
|  | ||||
|   private final DragDetector dragDetector; | ||||
|   private final ImageUpdate imageUpdate; | ||||
|   private final DragAction dragAction; | ||||
|   private final Label control; | ||||
|  | ||||
|   private Point startingPosition; | ||||
|  | ||||
|   public interface DragAction { | ||||
|     void start(); | ||||
|     void run( int startX, int startY, int currentX, int currentY ); | ||||
|     void end(); | ||||
|   } | ||||
|  | ||||
|   DragControl( Composite parent, DragAction dragAction, int maxExpansion ) { | ||||
|     this.control = new Label( parent, SWT.NONE ); | ||||
|     this.imageUpdate = new ImageUpdate( control, maxExpansion ); | ||||
|     this.dragDetector = new DragDetector( control, 0 ); | ||||
|     this.dragAction = dragAction; | ||||
|     initializeControl(); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public Label getControl() { | ||||
|     return control; | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void dragDetected( DragDetectEvent event ) { | ||||
|     if( startingPosition != null ) { | ||||
|       dragAction.run( startingPosition.x, startingPosition.y, event.x, event.y ); | ||||
|     } | ||||
|     dragDetector.dragHandled(); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void mouseDown( MouseEvent event ) { | ||||
|     startingPosition = new Point( event.x, event.y ); | ||||
|     dragAction.start(); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void mouseUp( MouseEvent event ) { | ||||
|     if( startingPosition != null ) { | ||||
|       dragAction.end(); | ||||
|     } | ||||
|     startingPosition = null; | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void mouseMove( MouseEvent event ) { | ||||
|     dragDetector.mouseMove( event ); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void controlResized( ControlEvent event ) { | ||||
|     imageUpdate.update(); | ||||
|   } | ||||
|  | ||||
|   void setForeground( Color color ) { | ||||
|     imageUpdate.setForeground( color ); | ||||
|   } | ||||
|  | ||||
|   Color getForeground() { | ||||
|     return imageUpdate.getForeground(); | ||||
|   } | ||||
|  | ||||
|   Color getBackground() { | ||||
|     return imageUpdate.getBackground(); | ||||
|   } | ||||
|  | ||||
|   void setBackground( Color color ) { | ||||
|     imageUpdate.setBackground( color ); | ||||
|   } | ||||
|  | ||||
|   private void initializeControl( ) { | ||||
|     control.addMouseListener( this ); | ||||
|     control.addMouseMoveListener( this ); | ||||
|     control.addControlListener( this ); | ||||
|     control.addDragDetectListener( this ); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void mouseDoubleClick( MouseEvent event ) {} | ||||
| } | ||||
| @@ -0,0 +1,60 @@ | ||||
| package com.minres.scviewer.database.ui.swt.sb; | ||||
|  | ||||
| import org.eclipse.swt.SWT; | ||||
| import org.eclipse.swt.events.MouseEvent; | ||||
| import org.eclipse.swt.widgets.Control; | ||||
| import org.eclipse.swt.widgets.Event; | ||||
|  | ||||
| // TODO [fappel]: This is a workaround for a problem described here: | ||||
| // http://stackoverflow.com/questions/3908290/mousedown-events-are-not-delivered-until-mouseup-when-a-drag-source-is-present | ||||
| // This seems to be related to https://bugs.eclipse.org/bugs/show_bug.cgi?id=328396 | ||||
| // which is resolved. As it did not work on my setup I adapted the workaround of the last | ||||
| // stackoverflow answer. | ||||
|  | ||||
| public class DragDetector { | ||||
|  | ||||
|   int lastMouseX; | ||||
|   int lastMouseY; | ||||
|   boolean dragEventGenerated; | ||||
|  | ||||
|   private final Control control; | ||||
|   private final int sensibility; | ||||
|  | ||||
|   public DragDetector( Control control, int sensibility ) { | ||||
|     this.control = control; | ||||
|     this.sensibility = sensibility; | ||||
|     this.control.setDragDetect( false ); | ||||
|   } | ||||
|  | ||||
|   public void mouseMove( MouseEvent e ) { | ||||
|     if( ( e.stateMask & SWT.BUTTON1 ) > 0 ) { | ||||
|       int deltaX = lastMouseX - e.x; | ||||
|       int deltaY = lastMouseY - e.y; | ||||
|       int dragDistance = deltaX * deltaX + deltaY * deltaY; | ||||
|       if( !dragEventGenerated && dragDistance > sensibility ) { | ||||
|         dragEventGenerated = true; | ||||
|         Event event = createDragEvent( e ); | ||||
|         control.notifyListeners( SWT.DragDetect, event ); | ||||
|       } | ||||
|       lastMouseX = e.x; | ||||
|       lastMouseY = e.y; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   public void dragHandled() { | ||||
|     dragEventGenerated = false; | ||||
|   } | ||||
|  | ||||
|   private Event createDragEvent( MouseEvent e ) { | ||||
|     Event event = new Event(); | ||||
|     event.type = SWT.DragDetect; | ||||
|     event.display = control.getDisplay(); | ||||
|     event.widget = control; | ||||
|     event.button = e.button; | ||||
|     event.stateMask = e.stateMask; | ||||
|     event.time = e.time; | ||||
|     event.x = e.x; | ||||
|     event.y = e.y; | ||||
|     return event; | ||||
|   } | ||||
| } | ||||
| @@ -0,0 +1,59 @@ | ||||
| package com.minres.scviewer.database.ui.swt.sb; | ||||
|  | ||||
| import static com.minres.scviewer.database.ui.swt.sb.Direction.HORIZONTAL; | ||||
| import static com.minres.scviewer.database.ui.swt.sb.ShiftData.calculateSelectionRange; | ||||
|  | ||||
| import org.eclipse.swt.SWT; | ||||
| import org.eclipse.swt.graphics.Point; | ||||
|  | ||||
| import com.minres.scviewer.database.ui.swt.sb.DragControl.DragAction; | ||||
|  | ||||
| final class DragShifter implements DragAction { | ||||
|  | ||||
|   private final FlatScrollBar scrollBar; | ||||
|   private final int buttonLength; | ||||
|  | ||||
|   public DragShifter( FlatScrollBar scrollBar, int buttonLength ) { | ||||
|     this.scrollBar = scrollBar; | ||||
|     this.buttonLength = buttonLength; | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void start() { | ||||
|     scrollBar.notifyListeners( SWT.DRAG ); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void run( int startX, int startY, int currentX, int currentY ) { | ||||
|     ShiftData shiftData = newShiftData( startX, startY, currentX, currentY ); | ||||
|     if( shiftData.canShift() ) { | ||||
|       int selectionRange = calculateSelectionRange( scrollBar ); | ||||
|       int selectionDelta = shiftData.calculateSelectionDelta( selectionRange ); | ||||
|       int selection = scrollBar.getSelection() + selectionDelta; | ||||
|       scrollBar.setSelectionInternal( selection, SWT.DRAG ); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void end() { | ||||
|     scrollBar.notifyListeners( SWT.NONE ); | ||||
|   } | ||||
|  | ||||
|   private ShiftData newShiftData( int startX, int startY, int currentX, int currentY ) { | ||||
|     ShiftData result; | ||||
|     if( scrollBar.direction == HORIZONTAL ) { | ||||
|       result = new ShiftData( buttonLength, getScrollBarSize().x, getDragSize().x, currentX - startX ); | ||||
|     } else { | ||||
|       result = new ShiftData( buttonLength, getScrollBarSize().y, getDragSize().y, currentY - startY ); | ||||
|     } | ||||
|     return result; | ||||
|   } | ||||
|  | ||||
|   private Point getScrollBarSize() { | ||||
|     return scrollBar.getSize(); | ||||
|   } | ||||
|  | ||||
|   private Point getDragSize() { | ||||
|     return scrollBar.drag.getControl().getSize(); | ||||
|   } | ||||
| } | ||||
| @@ -0,0 +1,49 @@ | ||||
| package com.minres.scviewer.database.ui.swt.sb; | ||||
|  | ||||
| import org.eclipse.swt.SWT; | ||||
| import org.eclipse.swt.graphics.Point; | ||||
| import org.eclipse.swt.graphics.Rectangle; | ||||
| import org.eclipse.swt.widgets.Display; | ||||
|  | ||||
| import com.minres.scviewer.database.ui.swt.sb.ClickControl.ClickAction; | ||||
|  | ||||
| class FastDecrementer implements ClickAction { | ||||
|  | ||||
|   private final FlatScrollBar scrollBar; | ||||
|  | ||||
|   private int x; | ||||
|   private int y; | ||||
|  | ||||
|   FastDecrementer( FlatScrollBar scrollBar ) { | ||||
|     this.scrollBar = scrollBar; | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void run() { | ||||
|     Rectangle drag = getDragBounds(); | ||||
|     Point mouse = getMouseLocation(); | ||||
|     if( mouse.x <= drag.x || mouse.y <= drag.y ) { | ||||
|       int selection = scrollBar.getSelection() - scrollBar.getPageIncrement(); | ||||
|       scrollBar.setSelectionInternal( selection, SWT.PAGE_UP ); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void setCoordinates( int x, int y ) { | ||||
|     this.x = x; | ||||
|     this.y = y; | ||||
|   } | ||||
|  | ||||
|   private Point getMouseLocation() { | ||||
|     return getDisplay().map( scrollBar.upFast.getControl(), null, x, y ); | ||||
|   } | ||||
|  | ||||
|   private Rectangle getDragBounds() { | ||||
|     Rectangle dragBounds = scrollBar.drag.getControl().getBounds(); | ||||
|     return getDisplay().map( scrollBar, null, dragBounds ); | ||||
|   } | ||||
|  | ||||
|   private Display getDisplay() { | ||||
|     return scrollBar.getDisplay(); | ||||
|   } | ||||
| } | ||||
| @@ -0,0 +1,42 @@ | ||||
| package com.minres.scviewer.database.ui.swt.sb; | ||||
|  | ||||
| import org.eclipse.swt.SWT; | ||||
| import org.eclipse.swt.graphics.Point; | ||||
| import org.eclipse.swt.graphics.Rectangle; | ||||
| import org.eclipse.swt.widgets.Display; | ||||
|  | ||||
| import com.minres.scviewer.database.ui.swt.sb.ClickControl.ClickAction; | ||||
|  | ||||
| class FastIncrementer implements ClickAction { | ||||
|  | ||||
|   private final FlatScrollBar scrollBar; | ||||
|  | ||||
|   private Point mouse; | ||||
|  | ||||
|   FastIncrementer( FlatScrollBar scrollBar ) { | ||||
|     this.scrollBar = scrollBar; | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void run() { | ||||
|     Rectangle drag = getDragBounds(); | ||||
|     if( mouse.x > drag.x + drag.width || mouse.y > drag.y + drag.height ) { | ||||
|       int selection = scrollBar.getSelection() + scrollBar.getPageIncrement(); | ||||
|       scrollBar.setSelectionInternal( selection, SWT.PAGE_DOWN ); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void setCoordinates( int x, int y ) { | ||||
|     mouse = getMouseLocation( x, y ); | ||||
|   } | ||||
|  | ||||
|   private Point getMouseLocation(int x, int y) { | ||||
|     return Display.getCurrent().map( scrollBar.downFast.getControl(), null, x, y ); | ||||
|   } | ||||
|  | ||||
|   private Rectangle getDragBounds() { | ||||
|     Rectangle dragBounds = scrollBar.drag.getControl().getBounds(); | ||||
|     return Display.getCurrent().map( scrollBar, null, dragBounds ); | ||||
|   } | ||||
| } | ||||
| @@ -0,0 +1,295 @@ | ||||
| package com.minres.scviewer.database.ui.swt.sb; | ||||
|  | ||||
| import static com.minres.scviewer.database.ui.swt.sb.UntypedSelectionAdapter.lookup; | ||||
|  | ||||
| import java.util.Collection; | ||||
| import java.util.HashSet; | ||||
|  | ||||
| import org.eclipse.swt.SWT; | ||||
| import org.eclipse.swt.events.SelectionEvent; | ||||
| import org.eclipse.swt.events.SelectionListener; | ||||
| import org.eclipse.swt.graphics.Color; | ||||
| import org.eclipse.swt.widgets.Composite; | ||||
| import org.eclipse.swt.widgets.Display; | ||||
| import org.eclipse.swt.widgets.Event; | ||||
| import org.eclipse.swt.widgets.Layout; | ||||
| import org.eclipse.swt.widgets.Listener; | ||||
|  | ||||
| public class FlatScrollBar extends Composite { | ||||
|  | ||||
|   public static final int BAR_BREADTH = 6; | ||||
|  | ||||
|   static final int DEFAULT_MINIMUM = 0; | ||||
|   static final int DEFAULT_MAXIMUM = 100; | ||||
|   static final int DEFAULT_INCREMENT = 1; | ||||
|   static final int DEFAULT_THUMB = 10; | ||||
|   static final int DEFAULT_PAGE_INCREMENT = DEFAULT_THUMB; | ||||
|   static final int DEFAULT_SELECTION = 0; | ||||
|   static final int DEFAULT_BUTTON_LENGTH = 0; | ||||
|   static final int DEFAULT_MAX_EXPANSION = Direction.CLEARANCE + 2; | ||||
|  | ||||
|   final ClickControl up; | ||||
|   final ClickControl upFast; | ||||
|   final DragControl drag; | ||||
|   final ClickControl downFast; | ||||
|   final ClickControl down; | ||||
|   final Direction direction; | ||||
|   final MouseWheelShifter mouseWheelHandler; | ||||
|   final Collection<SelectionListener> listeners; | ||||
|  | ||||
|   private int minimum; | ||||
|   private int maximum; | ||||
|   private int increment; | ||||
|   private int pageIncrement; | ||||
|   private int thumb; | ||||
|   private int selection; | ||||
|   private boolean onDrag; | ||||
|   private int buttonLength; | ||||
|  | ||||
|   public FlatScrollBar( final Composite parent, int style ) { | ||||
|     this( parent, style, DEFAULT_BUTTON_LENGTH, DEFAULT_MAX_EXPANSION ); | ||||
|   } | ||||
|  | ||||
|   FlatScrollBar( Composite parent, int style, int buttonLength, int maxExpansion ) { | ||||
|     super( parent, SWT.NONE ); | ||||
|     super.setLayout( new FlatScrollBarLayout( getDirection( style ) ) ); | ||||
|     this.minimum = DEFAULT_MINIMUM; | ||||
|     this.maximum = DEFAULT_MAXIMUM; | ||||
|     this.increment = DEFAULT_INCREMENT; | ||||
|     this.pageIncrement = DEFAULT_PAGE_INCREMENT; | ||||
|     this.thumb = DEFAULT_THUMB; | ||||
|     this.selection = DEFAULT_SELECTION; | ||||
|     this.buttonLength = buttonLength; | ||||
|     this.direction = getDirection( style ); | ||||
|     this.direction.setDefaultSize( this ); | ||||
|     this.up = new ClickControl( this, new Decrementer( this ), maxExpansion ); | ||||
|     this.upFast = new ClickControl( this, new FastDecrementer( this ), maxExpansion ); | ||||
|     this.drag = new DragControl( this, new DragShifter( this, buttonLength ), maxExpansion ); | ||||
|     this.downFast = new ClickControl( this, new FastIncrementer( this ), maxExpansion ); | ||||
|     this.down = new ClickControl( this, new Incrementer( this ), maxExpansion ); | ||||
|     this.mouseWheelHandler = new MouseWheelShifter( this, parent, buttonLength ); | ||||
|     this.listeners = new HashSet<SelectionListener>(); | ||||
|     addMouseTrackListener( new MouseTracker( this, maxExpansion ) ); | ||||
|     addControlListener( new ResizeObserver( this ) ); | ||||
|     setDefaultColorScheme(); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void setLayout( Layout layout ) { | ||||
|     throw new UnsupportedOperationException( FlatScrollBar.class.getName() + " does not allow to change layout." ); | ||||
|   }; | ||||
|  | ||||
|   @Override | ||||
|   public int getStyle() { | ||||
|     return direction != null ? super.getStyle() | direction.value() : super.getStyle(); | ||||
|   }; | ||||
|  | ||||
|   Direction getDirection() { | ||||
|     return direction; | ||||
|   } | ||||
|  | ||||
|   public void setMinimum( int minimum ) { | ||||
|     if( this.minimum != minimum && minimum >= 0 && minimum < maximum ) { | ||||
|       this.minimum = minimum; | ||||
|       adjustThumb(); | ||||
|       adjustSelection(); | ||||
|       layout(); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   public int getMinimum() { | ||||
|     return minimum; | ||||
|   } | ||||
|  | ||||
|   public void setMaximum( int maximum ) { | ||||
|     if( this.maximum != maximum && maximum >= 0 && maximum > minimum ) { | ||||
|       this.maximum = maximum; | ||||
|       adjustThumb(); | ||||
|       adjustSelection(); | ||||
|       layout(); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   public int getMaximum() { | ||||
|     return maximum; | ||||
|   } | ||||
|  | ||||
|   public void setThumb( int thumb ) { | ||||
|     if( this.thumb != thumb && thumb >= 1 ) { | ||||
|       this.thumb = thumb; | ||||
|       adjustThumb(); | ||||
|       adjustSelection(); | ||||
|       layout(); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   public int getThumb() { | ||||
|     return thumb; | ||||
|   } | ||||
|  | ||||
|   public void setIncrement( int increment ) { | ||||
|     if( this.increment != increment ) { | ||||
|       this.increment = increment; | ||||
|       layout(); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   public int getIncrement() { | ||||
|     return increment; | ||||
|   } | ||||
|  | ||||
|   public void setPageIncrement( int pageIncrement ) { | ||||
|     this.pageIncrement = pageIncrement; | ||||
|   } | ||||
|  | ||||
|   public int getPageIncrement() { | ||||
|     return pageIncrement; | ||||
|   } | ||||
|  | ||||
|   public void setSelection( int selection ) { | ||||
|     if( !onDrag ) { | ||||
|       updateSelection( selection ); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   public int getSelection() { | ||||
|     return selection; | ||||
|   } | ||||
|  | ||||
|   public void addSelectionListener( SelectionListener selectionListener ) { | ||||
|     listeners.add( selectionListener ); | ||||
|   } | ||||
|  | ||||
|   public void removeSelectionListener( SelectionListener selectionListener ) { | ||||
|     listeners.remove( selectionListener ); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void addListener( int eventType, final Listener listener ) { | ||||
|     if( eventType == SWT.Selection ) { | ||||
|       addSelectionListener( new UntypedSelectionAdapter( listener ) ); | ||||
|     } else { | ||||
|       super.addListener( eventType, listener ); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void removeListener( int eventType, Listener listener ) { | ||||
|     if( eventType == SWT.Selection ) { | ||||
|       removeSelectionListener( lookup( listeners, listener ) ); | ||||
|     } else { | ||||
|       super.removeListener( eventType, listener ); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void layout() { | ||||
|     direction.layout( this, buttonLength ); | ||||
|     update(); | ||||
|   } | ||||
|  | ||||
|   public void setIncrementButtonLength( int length ) { | ||||
|     this.buttonLength = length; | ||||
|     layout(); | ||||
|   } | ||||
|  | ||||
|   public int getIncrementButtonLength() { | ||||
|     return buttonLength; | ||||
|   } | ||||
|  | ||||
|   public void setIncrementColor( Color color ) { | ||||
|     up.setForeground( color ); | ||||
|     down.setForeground( color ); | ||||
|   } | ||||
|  | ||||
|   public Color getIncrementColor() { | ||||
|     return up.getForeground(); | ||||
|   } | ||||
|  | ||||
|   public void setPageIncrementColor( Color color ) { | ||||
|     upFast.setForeground( color ); | ||||
|     downFast.setForeground( color ); | ||||
|   } | ||||
|  | ||||
|   public Color getPageIncrementColor() { | ||||
|     return upFast.getForeground(); | ||||
|   } | ||||
|  | ||||
|   public void setThumbColor( Color color ) { | ||||
|     drag.setForeground( color ); | ||||
|   } | ||||
|  | ||||
|   public Color getThumbColor() { | ||||
|     return drag.getForeground(); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void setBackground( Color color ) { | ||||
|     up.setBackground( color ); | ||||
|     upFast.setBackground( color ); | ||||
|     drag.setBackground( color ); | ||||
|     downFast.setBackground( color ); | ||||
|     down.setBackground( color ); | ||||
|     super.setBackground( color ); | ||||
|   } | ||||
|  | ||||
|   protected void setSelectionInternal( int selection, int detail ) { | ||||
|     int oldSelection = this.selection; | ||||
|     updateSelection( selection ); | ||||
|     if( oldSelection != this.selection ) { | ||||
|       notifyListeners( detail ); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   private void updateSelection( int selection ) { | ||||
|     if( this.selection != selection ) { | ||||
|       this.selection = selection; | ||||
|       adjustSelection(); | ||||
|       layout(); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   public void notifyListeners( int detail ) { | ||||
|     updateOnDrag( detail ); | ||||
|     SelectionEvent selectionEvent = createEvent( detail ); | ||||
|     for( SelectionListener listener : listeners ) { | ||||
|       listener.widgetSelected( selectionEvent ); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   private void updateOnDrag( int detail ) { | ||||
|     onDrag = ( onDrag || ( SWT.DRAG & detail ) > 0 ) && ( SWT.NONE != detail ); | ||||
|   } | ||||
|  | ||||
|   private SelectionEvent createEvent( int detail ) { | ||||
|     Event event = new Event(); | ||||
|     event.widget = this; | ||||
|     event.detail = detail; | ||||
|     return new SelectionEvent( event ); | ||||
|   } | ||||
|  | ||||
|   private void adjustThumb() { | ||||
|     if( thumb > maximum - minimum ) { | ||||
|       thumb = Math.min( maximum - minimum, thumb ); | ||||
|       thumb = Math.max( 1, thumb ); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   private void adjustSelection() { | ||||
|     selection = Math.min( selection, maximum - thumb ); | ||||
|     selection = Math.max( selection, minimum ); | ||||
|   } | ||||
|  | ||||
|   private static Direction getDirection( int style ) { | ||||
|     return ( style & SWT.HORIZONTAL ) > 0 ? Direction.HORIZONTAL : Direction.VERTICAL; | ||||
|   } | ||||
|  | ||||
|   private void setDefaultColorScheme() { | ||||
|     up.setForeground( Display.getCurrent().getSystemColor( SWT.COLOR_WIDGET_NORMAL_SHADOW ) ); | ||||
|     upFast.setForeground( Display.getCurrent().getSystemColor( SWT.COLOR_WIDGET_BACKGROUND ) ); | ||||
|     drag.setForeground( Display.getCurrent().getSystemColor( SWT.COLOR_WIDGET_FOREGROUND ) ); | ||||
|     downFast.setForeground( Display.getCurrent().getSystemColor( SWT.COLOR_WIDGET_BACKGROUND ) ); | ||||
|     down.setForeground( Display.getCurrent().getSystemColor( SWT.COLOR_WIDGET_NORMAL_SHADOW ) ); | ||||
|     setBackground( getBackground() ); | ||||
|   } | ||||
| } | ||||
| @@ -0,0 +1,23 @@ | ||||
| package com.minres.scviewer.database.ui.swt.sb; | ||||
|  | ||||
| import org.eclipse.swt.graphics.Point; | ||||
| import org.eclipse.swt.widgets.Composite; | ||||
| import org.eclipse.swt.widgets.Layout; | ||||
|  | ||||
| class FlatScrollBarLayout extends Layout { | ||||
|  | ||||
|   private final Direction direction; | ||||
|  | ||||
|   public FlatScrollBarLayout( Direction orientation ) { | ||||
|     this.direction = orientation; | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   protected void layout( Composite composite, boolean flushCache ) { | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   protected Point computeSize( Composite composite, int wHint, int hHint, boolean flushCache ) { | ||||
|     return direction.computeSize( composite, wHint, hHint, flushCache ); | ||||
|   } | ||||
| } | ||||
| @@ -0,0 +1,109 @@ | ||||
| package com.minres.scviewer.database.ui.swt.sb; | ||||
|  | ||||
| import static java.lang.Math.min; | ||||
|  | ||||
| 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.widgets.Display; | ||||
|  | ||||
| class ImageDrawer { | ||||
|  | ||||
|   static final String IMAGE_DRAWER_IS_DISPOSED = "ImageDrawer is disposed."; | ||||
|  | ||||
|   private final int maxExpansion; | ||||
|  | ||||
|   private Color background; | ||||
|   private Color foreground; | ||||
|  | ||||
|   ImageDrawer( int expansion  ) { | ||||
|     this( expansion, getSystemColor( SWT.COLOR_WIDGET_DARK_SHADOW ), getSystemColor( SWT.COLOR_LIST_BACKGROUND ) ); | ||||
|   } | ||||
|  | ||||
|   ImageDrawer( int expansion, Color background, Color foreground ) { | ||||
|     this.maxExpansion = expansion; | ||||
|     this.foreground = defensiveCopy( background ); | ||||
|     this.background = defensiveCopy( foreground ); | ||||
|   } | ||||
|  | ||||
|   void setForeground( Color foreground ) { | ||||
|     checkDisposed(); | ||||
|     if( foreground != null ) { | ||||
|       this.foreground = prepareColorAttribute( this.foreground, foreground ); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   Color getForeground() { | ||||
|     checkDisposed(); | ||||
|     return foreground; | ||||
|   } | ||||
|  | ||||
|   void setBackground( Color background ) { | ||||
|     checkDisposed(); | ||||
|     if( background != null ) { | ||||
|       this.background = prepareColorAttribute( this.background, background ); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   Color getBackground() { | ||||
|     checkDisposed(); | ||||
|     return background; | ||||
|   } | ||||
|  | ||||
|   Image draw( int width, int height ) { | ||||
|     checkDisposed(); | ||||
|     Image result = new Image( getDisplay(), width, height ); | ||||
|     GC gc = new GC( result ); | ||||
|     try { | ||||
|       draw( gc, width, height ); | ||||
|     } finally { | ||||
|       gc.dispose(); | ||||
|     } | ||||
|     return result; | ||||
|   } | ||||
|  | ||||
|   boolean isDisposed() { | ||||
|     return background.isDisposed(); | ||||
|   } | ||||
|  | ||||
|   void dispose() { | ||||
|     if( !isDisposed() ) { | ||||
|       this.background.dispose(); | ||||
|       this.foreground.dispose(); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   private void draw( GC gc, int width, int height ) { | ||||
|     gc.setBackground( background ); | ||||
|     gc.fillRectangle( 0, 0, width, height ); | ||||
|     gc.setBackground( foreground ); | ||||
|     gc.setAdvanced( true ); | ||||
|     gc.setAntialias( SWT.ON ); | ||||
|     int arc = min( width, height ) == 1 ? 1 : maxExpansion + 2; | ||||
|     gc.fillRoundRectangle( 0, 0, width, height, arc, arc ); | ||||
|   } | ||||
|  | ||||
|   private void checkDisposed() { | ||||
|     if( isDisposed() ) { | ||||
|       throw new IllegalStateException( IMAGE_DRAWER_IS_DISPOSED ); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   private static Color getSystemColor( int colorCode ) { | ||||
|     return getDisplay().getSystemColor( colorCode ); | ||||
|   } | ||||
|  | ||||
|   private static Color prepareColorAttribute( Color oldColor, Color newColor ) { | ||||
|     oldColor.dispose(); | ||||
|     return defensiveCopy( newColor ); | ||||
|   } | ||||
|  | ||||
|   private static Color defensiveCopy( Color background ) { | ||||
|     return new Color( getDisplay(), background.getRGB() ); | ||||
|   } | ||||
|  | ||||
|   private static Display getDisplay() { | ||||
|     return Display.getCurrent(); | ||||
|   } | ||||
| } | ||||
| @@ -0,0 +1,46 @@ | ||||
| package com.minres.scviewer.database.ui.swt.sb; | ||||
|  | ||||
| import org.eclipse.swt.SWT; | ||||
| import org.eclipse.swt.graphics.Color; | ||||
| import org.eclipse.swt.graphics.Point; | ||||
| import org.eclipse.swt.widgets.Label; | ||||
|  | ||||
| class ImageUpdate { | ||||
|  | ||||
|   private final ImageDrawer imageDrawer; | ||||
|   private final Label control; | ||||
|  | ||||
|   ImageUpdate( Label control, int maxExpansion ) { | ||||
|     this.imageDrawer = new ImageDrawer( maxExpansion ); | ||||
|     this.control = control; | ||||
|     this.control.addListener( SWT.Dispose, evt -> imageDrawer.dispose() ); | ||||
|   } | ||||
|  | ||||
|   void setForeground( Color color ) { | ||||
|     imageDrawer.setForeground( color ); | ||||
|   } | ||||
|  | ||||
|   Color getForeground() { | ||||
|     return imageDrawer.getForeground(); | ||||
|   } | ||||
|  | ||||
|   void setBackground( Color color ) { | ||||
|     imageDrawer.setBackground( color ); | ||||
|   } | ||||
|  | ||||
|   Color getBackground() { | ||||
|     return imageDrawer.getBackground(); | ||||
|   } | ||||
|  | ||||
|   void update() { | ||||
|     if( !control.isDisposed() ) { | ||||
|       if( control.getImage() != null ) { | ||||
|         control.getImage().dispose(); | ||||
|       } | ||||
|       Point size = control.getSize(); | ||||
|       if( size.x > 0 && size.y > 0 ) { | ||||
|         control.setImage( imageDrawer.draw( size.x, size.y ) ); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @@ -0,0 +1,24 @@ | ||||
| package com.minres.scviewer.database.ui.swt.sb; | ||||
|  | ||||
| import org.eclipse.swt.SWT; | ||||
|  | ||||
| import com.minres.scviewer.database.ui.swt.sb.ClickControl.ClickAction; | ||||
|  | ||||
| class Incrementer implements ClickAction { | ||||
|  | ||||
|   private final FlatScrollBar scrollBar; | ||||
|  | ||||
|   Incrementer( FlatScrollBar scrollBar ) { | ||||
|     this.scrollBar = scrollBar; | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void run() { | ||||
|     int selection = scrollBar.getSelection() + scrollBar.getIncrement(); | ||||
|     scrollBar.setSelectionInternal( selection, SWT.ARROW_DOWN ); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void setCoordinates( int x, int y ) { | ||||
|   } | ||||
| } | ||||
| @@ -0,0 +1,37 @@ | ||||
| package com.minres.scviewer.database.ui.swt.sb; | ||||
|  | ||||
| import org.eclipse.swt.widgets.Display; | ||||
|  | ||||
| public class MouseDownActionTimer implements Runnable { | ||||
|  | ||||
|   public static final int INITIAL_DELAY = 300; | ||||
|   public static final int FAST_DELAY = 50; | ||||
|  | ||||
|   private final ActionScheduler scheduler; | ||||
|   private final TimerAction timerAction; | ||||
|   private final ButtonClick mouseClick; | ||||
|  | ||||
|   public interface TimerAction extends Runnable { | ||||
|     boolean isEnabled(); | ||||
|   } | ||||
|  | ||||
|   public MouseDownActionTimer( TimerAction timerAction, ButtonClick mouseClick, Display display ) { | ||||
|     this.scheduler = new ActionScheduler( display, this ); | ||||
|     this.timerAction = timerAction; | ||||
|     this.mouseClick = mouseClick; | ||||
|   } | ||||
|  | ||||
|   public void activate() { | ||||
|     if( timerAction.isEnabled() ) { | ||||
|       scheduler.schedule( INITIAL_DELAY ); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void run() { | ||||
|     if( mouseClick.isArmed() && timerAction.isEnabled() ) { | ||||
|       timerAction.run(); | ||||
|       scheduler.schedule( FAST_DELAY ); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @@ -0,0 +1,66 @@ | ||||
| package com.minres.scviewer.database.ui.swt.sb; | ||||
|  | ||||
| import org.eclipse.swt.events.DisposeEvent; | ||||
| import org.eclipse.swt.events.DisposeListener; | ||||
| import org.eclipse.swt.events.MouseEvent; | ||||
| import org.eclipse.swt.events.MouseTrackAdapter; | ||||
| import org.eclipse.swt.graphics.Rectangle; | ||||
| import org.eclipse.swt.widgets.Display; | ||||
|  | ||||
| class MouseTracker extends MouseTrackAdapter implements Runnable, DisposeListener { | ||||
|  | ||||
|   static final int DELAY = 500; | ||||
|  | ||||
|   private final FlatScrollBar scrollBar; | ||||
|   private final int maxExpansion; | ||||
|  | ||||
|   private Rectangle expandedBounds; | ||||
|   private Rectangle originBounds; | ||||
|   private boolean mouseOver; | ||||
|   private boolean disposed; | ||||
|  | ||||
|   MouseTracker( FlatScrollBar scrollBar, int maxExpansion  ) { | ||||
|     this.scrollBar = scrollBar; | ||||
|     this.maxExpansion = maxExpansion; | ||||
|     this.scrollBar.addDisposeListener( this ); | ||||
|     this.scrollBar.up.getControl().addMouseTrackListener( this ); | ||||
|     this.scrollBar.upFast.getControl().addMouseTrackListener( this ); | ||||
|     this.scrollBar.drag.getControl().addMouseTrackListener( this ); | ||||
|     this.scrollBar.downFast.getControl().addMouseTrackListener( this ); | ||||
|     this.scrollBar.down.getControl().addMouseTrackListener( this ); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void mouseEnter( MouseEvent event ) { | ||||
|     mouseOver = true; | ||||
|     if( !disposed && originBounds == null ) { | ||||
|       originBounds = scrollBar.getBounds(); | ||||
|       scrollBar.getDirection().expand( scrollBar, maxExpansion ); | ||||
|       expandedBounds = scrollBar.getBounds(); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void mouseExit( MouseEvent event ) { | ||||
|     mouseOver = false; | ||||
|     if( !disposed ) { | ||||
|       Display.getCurrent().timerExec( DELAY, this ); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void run() { | ||||
|     if( !disposed && !mouseOver ) { | ||||
|       if( scrollBar.getBounds().equals( expandedBounds ) ) { | ||||
|         scrollBar.setBounds( originBounds ); | ||||
|       } | ||||
|       originBounds = null; | ||||
|       expandedBounds = null; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void widgetDisposed( DisposeEvent e ) { | ||||
|     disposed = true; | ||||
|   } | ||||
| } | ||||
| @@ -0,0 +1,69 @@ | ||||
| package com.minres.scviewer.database.ui.swt.sb; | ||||
|  | ||||
| import static com.minres.scviewer.database.ui.swt.sb.Direction.HORIZONTAL; | ||||
| import static com.minres.scviewer.database.ui.swt.sb.ShiftData.calculateSelectionRange; | ||||
|  | ||||
| import org.eclipse.swt.SWT; | ||||
| import org.eclipse.swt.events.DisposeEvent; | ||||
| import org.eclipse.swt.events.DisposeListener; | ||||
| import org.eclipse.swt.graphics.Point; | ||||
| import org.eclipse.swt.widgets.Composite; | ||||
| import org.eclipse.swt.widgets.Event; | ||||
| import org.eclipse.swt.widgets.Listener; | ||||
|  | ||||
| public class MouseWheelShifter implements Listener, DisposeListener { | ||||
|  | ||||
|   private final FlatScrollBar scrollBar; | ||||
|   private final Composite parent; | ||||
|   private final int buttonLength; | ||||
|  | ||||
|   MouseWheelShifter( FlatScrollBar scrollBar, Composite parent, int buttonLength ) { | ||||
|     this.scrollBar = scrollBar; | ||||
|     this.parent = parent; | ||||
|     this.buttonLength = buttonLength; | ||||
|     parent.addListener( getListenerType(), this ); | ||||
|     scrollBar.addDisposeListener( this ); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void handleEvent( Event event ) { | ||||
|     handleMouseWheelScroll( event ); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void widgetDisposed( DisposeEvent e ) { | ||||
|     parent.removeListener( getListenerType(), this ); | ||||
|   } | ||||
|  | ||||
|   private void handleMouseWheelScroll( Event event ) { | ||||
|     ShiftData shiftData = newShiftData( event.count ); | ||||
|     if( shiftData.canShift() ) { | ||||
|       int selectionRange = calculateSelectionRange( scrollBar ); | ||||
|       int selectionDelta = shiftData.calculateSelectionDelta( selectionRange ); | ||||
|       int selection = scrollBar.getSelection() - selectionDelta; | ||||
|       scrollBar.setSelectionInternal( selection, scrollBar.direction.value() ); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   private ShiftData newShiftData( int delta ) { | ||||
|     ShiftData result; | ||||
|     if( scrollBar.direction == Direction.HORIZONTAL ) { | ||||
|       result = new ShiftData( buttonLength, getScrollBarSize().x, getDragSize().x, delta ); | ||||
|     } else { | ||||
|       result = new ShiftData( buttonLength, getScrollBarSize().y, getDragSize().y, delta ); | ||||
|     } | ||||
|     return result; | ||||
|   } | ||||
|  | ||||
|   private Point getScrollBarSize() { | ||||
|     return scrollBar.getSize(); | ||||
|   } | ||||
|  | ||||
|   private Point getDragSize() { | ||||
|     return scrollBar.drag.getControl().getSize(); | ||||
|   } | ||||
|  | ||||
|   private int getListenerType() { | ||||
|     return scrollBar.direction == HORIZONTAL ? SWT.MouseHorizontalWheel: SWT.MouseVerticalWheel; | ||||
|   } | ||||
| } | ||||
| @@ -0,0 +1,19 @@ | ||||
| package com.minres.scviewer.database.ui.swt.sb; | ||||
|  | ||||
| import org.eclipse.swt.events.ControlAdapter; | ||||
| import org.eclipse.swt.events.ControlEvent; | ||||
|  | ||||
| class ResizeObserver extends ControlAdapter { | ||||
|  | ||||
|   private final FlatScrollBar flatScrollBar; | ||||
|  | ||||
|   public ResizeObserver( FlatScrollBar flatScrollBar ) { | ||||
|     this.flatScrollBar = flatScrollBar; | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void controlResized( ControlEvent event ) { | ||||
|     flatScrollBar.layout(); | ||||
|     flatScrollBar.moveAbove( null ); | ||||
|   } | ||||
| } | ||||
| @@ -0,0 +1,32 @@ | ||||
| package com.minres.scviewer.database.ui.swt.sb; | ||||
|  | ||||
| import static com.minres.scviewer.database.ui.swt.sb.ComponentDistribution.divide; | ||||
|  | ||||
| class ShiftData { | ||||
|  | ||||
|   private final int slidePixels; | ||||
|   private final int movedPixels; | ||||
|   private final int buttonLength; | ||||
|  | ||||
|   ShiftData( int buttonLength, int scrollBarPixels, int dragPixels, int movedPixels ) { | ||||
|     this.buttonLength = buttonLength; | ||||
|     this.slidePixels = calculateSlidePixels( scrollBarPixels, dragPixels ); | ||||
|     this.movedPixels = movedPixels; | ||||
|   } | ||||
|  | ||||
|   boolean canShift( ) { | ||||
|     return slidePixels > 0; | ||||
|   } | ||||
|  | ||||
|   int calculateSelectionDelta( int selectionRange ) { | ||||
|     return divide( movedPixels * selectionRange, slidePixels ); | ||||
|   } | ||||
|  | ||||
|   static int calculateSelectionRange( FlatScrollBar scrollBar ) { | ||||
|     return scrollBar.getMaximum() - scrollBar.getMinimum() - scrollBar.getThumb(); | ||||
|   } | ||||
|  | ||||
|   private int calculateSlidePixels( int scrollBarPixels, int dragPixels ) { | ||||
|     return scrollBarPixels - 2 * buttonLength - dragPixels; | ||||
|   } | ||||
| } | ||||
| @@ -0,0 +1,43 @@ | ||||
| package com.minres.scviewer.database.ui.swt.sb; | ||||
|  | ||||
| import java.util.Collection; | ||||
|  | ||||
| import org.eclipse.swt.events.SelectionAdapter; | ||||
| import org.eclipse.swt.events.SelectionEvent; | ||||
| import org.eclipse.swt.events.SelectionListener; | ||||
| import org.eclipse.swt.widgets.Event; | ||||
| import org.eclipse.swt.widgets.Listener; | ||||
|  | ||||
| class UntypedSelectionAdapter extends SelectionAdapter { | ||||
|  | ||||
|   final Listener listener; | ||||
|  | ||||
|   UntypedSelectionAdapter( Listener listener ) { | ||||
|     this.listener = listener; | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public void widgetSelected( SelectionEvent selectionEvent ) { | ||||
|     Event event = new Event(); | ||||
|     event.widget = selectionEvent.widget; | ||||
|     event.detail = selectionEvent.detail; | ||||
|     listener.handleEvent( event ); | ||||
|   } | ||||
|  | ||||
|   static SelectionListener lookup( Collection<SelectionListener> listeners, Listener untypedListener ) { | ||||
|     for( SelectionListener listener : listeners ) { | ||||
|       if( isAdapterType( listener ) && matches( untypedListener, listener ) ) { | ||||
|         return listener; | ||||
|       } | ||||
|     } | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|   private static boolean isAdapterType( SelectionListener listener ) { | ||||
|     return listener instanceof UntypedSelectionAdapter; | ||||
|   } | ||||
|  | ||||
|   private static boolean matches( Listener untypedListener, SelectionListener listener ) { | ||||
|     return ( ( UntypedSelectionAdapter )listener ).listener == untypedListener; | ||||
|   } | ||||
| } | ||||
| @@ -0,0 +1,7 @@ | ||||
| package com.minres.scviewer.database.ui.swt.sb; | ||||
|  | ||||
| import org.eclipse.swt.widgets.Control; | ||||
|  | ||||
| public interface ViewComponent { | ||||
|   Control getControl(); | ||||
| } | ||||
| @@ -29,17 +29,14 @@ 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. | ||||
|  * Utility class for managing OS resources associated with SWT controls such as colors, fonts, images, etc. | ||||
|  * <p> | ||||
|  * !!! IMPORTANT !!! Application code must explicitly invoke the | ||||
|  * <code>dispose()</code> method to release the operating system resources | ||||
|  * managed by cached objects when those objects and OS resources are no longer | ||||
|  * !!! IMPORTANT !!! Application code must explicitly invoke the <code>dispose()</code> 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) | ||||
|  * <p> | ||||
|  * This class may be freely distributed as part of any application or plugin. | ||||
|  * <p> | ||||
|  *  | ||||
|  * @author scheglov_ke | ||||
|  * @author Dan Rubel | ||||
|  */ | ||||
| @@ -49,54 +46,57 @@ public class SWTResourceManager { | ||||
| 	// Color | ||||
| 	// | ||||
| 	//////////////////////////////////////////////////////////////////////////// | ||||
| 	private static Map<RGB, Color> colorMap = new HashMap<>(); | ||||
|  | ||||
| 	private SWTResourceManager() {} | ||||
| 	 | ||||
| 	private static Map<RGB, Color> m_colorMap = new HashMap<RGB, Color>(); | ||||
| 	/** | ||||
| 	 * Returns the system {@link Color} matching the specific ID. | ||||
| 	 *  | ||||
| 	 * @param systemColorID the ID value for the color | ||||
| 	 * @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 | ||||
| 	 * @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 | ||||
| 	 * @param rgb | ||||
| 	 *            the {@link RGB} value of the color | ||||
| 	 * @return the {@link Color} matching the RGB value | ||||
| 	 */ | ||||
| 	public static Color getColor(RGB rgb) { | ||||
| 		return colorMap.computeIfAbsent(rgb, k -> new Color(Display.getCurrent(), 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 : colorMap.values()) { | ||||
| 		for (Color color : m_colorMap.values()) { | ||||
| 			color.dispose(); | ||||
| 		} | ||||
| 		colorMap.clear(); | ||||
| 		m_colorMap.clear(); | ||||
| 	} | ||||
|  | ||||
| 	//////////////////////////////////////////////////////////////////////////// | ||||
| 	// | ||||
| 	// Image | ||||
| @@ -105,12 +105,12 @@ public class SWTResourceManager { | ||||
| 	/** | ||||
| 	 * Maps image paths to images. | ||||
| 	 */ | ||||
| 	private static Map<String, Image> imageMap = new HashMap<>(); | ||||
|  | ||||
| 	private static Map<String, Image> m_imageMap = new HashMap<String, Image>(); | ||||
| 	/** | ||||
| 	 * Returns an {@link Image} encoded by the specified {@link InputStream}. | ||||
| 	 *  | ||||
| 	 * @param stream the {@link InputStream} encoding the image data | ||||
| 	 * @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 { | ||||
| @@ -125,55 +125,52 @@ public class SWTResourceManager { | ||||
| 			stream.close(); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Returns an {@link Image} stored in the file at the specified path. | ||||
| 	 *  | ||||
| 	 * @param path the path to the image file | ||||
| 	 * @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 = imageMap.get(path); | ||||
| 		Image image = m_imageMap.get(path); | ||||
| 		if (image == null) { | ||||
| 			try { | ||||
| 				image = getImage(new FileInputStream(path)); | ||||
| 				imageMap.put(path, image); | ||||
| 				m_imageMap.put(path, image); | ||||
| 			} catch (Exception e) { | ||||
| 				image = getMissingImage(); | ||||
| 				imageMap.put(path, image); | ||||
| 				m_imageMap.put(path, image); | ||||
| 			} | ||||
| 		} | ||||
| 		return image; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Returns an {@link Image} stored in the file at the specified path relative to | ||||
| 	 * the specified class. | ||||
| 	 * 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 <code>'/'</code> | ||||
| 	 * @param clazz | ||||
| 	 *            the {@link Class} relative to which to find the image | ||||
| 	 * @param path | ||||
| 	 *            the path to the image file, if starts with <code>'/'</code> | ||||
| 	 * @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 = imageMap.get(key); | ||||
| 		Image image = m_imageMap.get(key); | ||||
| 		if (image == null) { | ||||
| 			try { | ||||
| 				image = getImage(clazz.getResourceAsStream(path)); | ||||
| 				imageMap.put(key, image); | ||||
| 				m_imageMap.put(key, image); | ||||
| 			} catch (Exception e) { | ||||
| 				image = getMissingImage(); | ||||
| 				imageMap.put(key, image); | ||||
| 				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. | ||||
| 	 * @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); | ||||
| @@ -185,7 +182,6 @@ public class SWTResourceManager { | ||||
| 		// | ||||
| 		return image; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Style constant for placing decorator image in top left corner of base image. | ||||
| 	 */ | ||||
| @@ -195,13 +191,11 @@ public class SWTResourceManager { | ||||
| 	 */ | ||||
| 	public static final int TOP_RIGHT = 2; | ||||
| 	/** | ||||
| 	 * Style constant for placing decorator image in bottom left corner of base | ||||
| 	 * image. | ||||
| 	 * 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. | ||||
| 	 * Style constant for placing decorator image in bottom right corner of base image. | ||||
| 	 */ | ||||
| 	public static final int BOTTOM_RIGHT = 4; | ||||
| 	/** | ||||
| @@ -212,77 +206,83 @@ public class SWTResourceManager { | ||||
| 	 * Maps images to decorated images. | ||||
| 	 */ | ||||
| 	@SuppressWarnings("unchecked") | ||||
| 	private static Map<Image, Map<Image, Image>>[] decoratedImageMap = new Map[LAST_CORNER_KEY]; | ||||
|  | ||||
| 	private static Map<Image, Map<Image, Image>>[] 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 | ||||
| 	 * @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 | ||||
| 	 * @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<Image, Map<Image, Image>> cornerDecoratedImageMap = decoratedImageMap[corner]; | ||||
| 		Map<Image, Map<Image, Image>> cornerDecoratedImageMap = m_decoratedImageMap[corner]; | ||||
| 		if (cornerDecoratedImageMap == null) { | ||||
| 			cornerDecoratedImageMap = new HashMap<>(); | ||||
| 			decoratedImageMap[corner] = cornerDecoratedImageMap; | ||||
| 			cornerDecoratedImageMap = new HashMap<Image, Map<Image, Image>>(); | ||||
| 			m_decoratedImageMap[corner] = cornerDecoratedImageMap; | ||||
| 		} | ||||
| 		Map<Image, Image> decoratedMap = cornerDecoratedImageMap.computeIfAbsent(baseImage, | ||||
| 				k -> new HashMap<Image, Image>()); | ||||
| 		return decoratedMap.computeIfAbsent(decorator, k -> { | ||||
| 		Map<Image, Image> decoratedMap = cornerDecoratedImageMap.get(baseImage); | ||||
| 		if (decoratedMap == null) { | ||||
| 			decoratedMap = new HashMap<Image, Image>(); | ||||
| 			cornerDecoratedImageMap.put(baseImage, decoratedMap); | ||||
| 		} | ||||
| 		// | ||||
| 		Image result = decoratedMap.get(decorator); | ||||
| 		if (result == null) { | ||||
| 			Rectangle bib = baseImage.getBounds(); | ||||
| 			Rectangle dib = decorator.getBounds(); | ||||
| 			Image result = new Image(Display.getCurrent(), bib.width, bib.height); | ||||
| 			// | ||||
| 			result = new Image(Display.getCurrent(), bib.width, bib.height); | ||||
| 			// | ||||
| 			GC gc = new GC(result); | ||||
| 			gc.drawImage(baseImage, 0, 0); | ||||
| 			switch (corner) { | ||||
| 			case TOP_LEFT: | ||||
| 			if (corner == TOP_LEFT) { | ||||
| 				gc.drawImage(decorator, 0, 0); | ||||
| 				break; | ||||
| 			case TOP_RIGHT: | ||||
| 			} else if (corner == TOP_RIGHT) { | ||||
| 				gc.drawImage(decorator, bib.width - dib.width, 0); | ||||
| 				break; | ||||
| 			case BOTTOM_LEFT: | ||||
| 			} else if (corner == BOTTOM_LEFT) { | ||||
| 				gc.drawImage(decorator, 0, bib.height - dib.height); | ||||
| 				break; | ||||
| 			case BOTTOM_RIGHT: | ||||
| 			} else if (corner == BOTTOM_RIGHT) { | ||||
| 				gc.drawImage(decorator, bib.width - dib.width, bib.height - dib.height); | ||||
| 				break; | ||||
| 			default: | ||||
| 				// do nothing | ||||
| 			} | ||||
| 			gc.dispose(); | ||||
| 			return result; | ||||
| 		}); | ||||
| 			// | ||||
| 			decoratedMap.put(decorator, result); | ||||
| 		} | ||||
| 		return result; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Dispose all of the cached {@link Image}'s. | ||||
| 	 */ | ||||
| 	public static void disposeImages() { | ||||
| 		// dispose loaded images | ||||
| 		for (Image image : imageMap.values()) { | ||||
| 			image.dispose(); | ||||
| 		{ | ||||
| 			for (Image image : m_imageMap.values()) { | ||||
| 				image.dispose(); | ||||
| 			} | ||||
| 			m_imageMap.clear(); | ||||
| 		} | ||||
| 		imageMap.clear(); | ||||
| 		// dispose decorated images | ||||
| 		for (int i = 0; i < decoratedImageMap.length; i++) { | ||||
| 			Map<Image, Map<Image, Image>> cornerDecoratedImageMap = decoratedImageMap[i]; | ||||
| 		for (int i = 0; i < m_decoratedImageMap.length; i++) { | ||||
| 			Map<Image, Map<Image, Image>> cornerDecoratedImageMap = m_decoratedImageMap[i]; | ||||
| 			if (cornerDecoratedImageMap != null) { | ||||
| 				for (Map<Image, Image> decoratedMap : cornerDecoratedImageMap.values()) { | ||||
| 					for (Image image : decoratedMap.values()) { | ||||
| @@ -294,7 +294,6 @@ public class SWTResourceManager { | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	//////////////////////////////////////////////////////////////////////////// | ||||
| 	// | ||||
| 	// Font | ||||
| @@ -303,39 +302,45 @@ public class SWTResourceManager { | ||||
| 	/** | ||||
| 	 * Maps font names to fonts. | ||||
| 	 */ | ||||
| 	private static Map<String, Font> fontMap = new HashMap<>(); | ||||
| 	private static Map<String, Font> m_fontMap = new HashMap<String, Font>(); | ||||
| 	/** | ||||
| 	 * Maps fonts to their bold versions. | ||||
| 	 */ | ||||
| 	private static Map<Font, Font> fontToBoldFontMap = new HashMap<>(); | ||||
|  | ||||
| 	private static Map<Font, Font> m_fontToBoldFontMap = new HashMap<Font, Font>(); | ||||
| 	/** | ||||
| 	 * 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 | ||||
| 	 * @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. | ||||
| 	 * 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 | ||||
| 	 * @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; | ||||
| 		return fontMap.computeIfAbsent(fontName, k -> { | ||||
| 		Font font = m_fontMap.get(fontName); | ||||
| 		if (font == null) { | ||||
| 			FontData fontData = new FontData(name, size, style); | ||||
| 			if (strikeout || underline) { | ||||
| 				try { | ||||
| @@ -349,45 +354,47 @@ public class SWTResourceManager { | ||||
| 							logFontClass.getField("lfUnderline").set(logFont, Byte.valueOf((byte) 1)); //$NON-NLS-1$ | ||||
| 						} | ||||
| 					} | ||||
| 				} catch (Exception e) { | ||||
| 				} 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$ | ||||
| 				} | ||||
| 			} | ||||
| 			return new Font(Display.getCurrent(), fontData); | ||||
|  | ||||
| 		}); | ||||
|  | ||||
| 			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 | ||||
| 	 * @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) { | ||||
| 		return fontToBoldFontMap.computeIfAbsent(baseFont, k -> { | ||||
| 			FontData[] fontDatas = baseFont.getFontData(); | ||||
| 		Font font = m_fontToBoldFontMap.get(baseFont); | ||||
| 		if (font == null) { | ||||
| 			FontData fontDatas[] = baseFont.getFontData(); | ||||
| 			FontData data = fontDatas[0]; | ||||
| 			return new Font(Display.getCurrent(), data.getName(), data.getHeight(), SWT.BOLD); | ||||
| 		}); | ||||
| 			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 : fontMap.values()) { | ||||
| 		for (Font font : m_fontMap.values()) { | ||||
| 			font.dispose(); | ||||
| 		} | ||||
| 		fontMap.clear(); | ||||
| 		m_fontMap.clear(); | ||||
| 		// clear bold fonts | ||||
| 		for (Font font : fontToBoldFontMap.values()) { | ||||
| 		for (Font font : m_fontToBoldFontMap.values()) { | ||||
| 			font.dispose(); | ||||
| 		} | ||||
| 		fontToBoldFontMap.clear(); | ||||
| 		m_fontToBoldFontMap.clear(); | ||||
| 	} | ||||
|  | ||||
| 	//////////////////////////////////////////////////////////////////////////// | ||||
| 	// | ||||
| 	// Cursor | ||||
| @@ -396,38 +403,40 @@ public class SWTResourceManager { | ||||
| 	/** | ||||
| 	 * Maps IDs to cursors. | ||||
| 	 */ | ||||
| 	private static Map<Integer, Cursor> idToCursorMap = new HashMap<>(); | ||||
|  | ||||
| 	private static Map<Integer, Cursor> m_idToCursorMap = new HashMap<Integer, Cursor>(); | ||||
| 	/** | ||||
| 	 * Returns the system cursor matching the specific ID. | ||||
| 	 *  | ||||
| 	 * @param id int The ID value for the cursor | ||||
| 	 * @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); | ||||
| 		return idToCursorMap.computeIfAbsent(key, k -> new Cursor(Display.getDefault(), 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 : idToCursorMap.values()) { | ||||
| 		for (Cursor cursor : m_idToCursorMap.values()) { | ||||
| 			cursor.dispose(); | ||||
| 		} | ||||
| 		idToCursorMap.clear(); | ||||
| 		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). | ||||
| 	 * 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(); | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="VCDDbLoader"> | ||||
|    <implementation class="com.minres.scviewer.database.vcd.VCDDbLoader"/> | ||||
| <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="VCDDbLoaderFactory"> | ||||
|    <implementation class="com.minres.scviewer.database.vcd.VCDDbLoaderFactory"/> | ||||
|    <service> | ||||
|       <provide interface="com.minres.scviewer.database.IWaveformDbLoader"/> | ||||
|       <provide interface="com.minres.scviewer.database.IWaveformDbLoaderFactory"/> | ||||
|    </service> | ||||
| </scr:component> | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
|   <parent> | ||||
|   	<groupId>com.minres.scviewer</groupId> | ||||
|   	<artifactId>com.minres.scviewer.parent</artifactId> | ||||
|   	<version>2.13.0</version> | ||||
|   	<version>2.15.1</version> | ||||
| 	<relativePath>../..</relativePath> | ||||
|   </parent> | ||||
|   <packaging>eclipse-plugin</packaging> | ||||
|   | ||||
| @@ -164,7 +164,8 @@ public class VCDDbLoader implements IWaveformDbLoader, IVCDDatabaseBuilder { | ||||
| 	@Override | ||||
| 	public void enterModule(String tokenString) { | ||||
| 		if(moduleStack.isEmpty()) { | ||||
| 			if("SystemC".compareTo(tokenString)!=0) moduleStack.push(tokenString); | ||||
| 			if("SystemC".compareTo(tokenString)!=0) | ||||
| 				moduleStack.push(tokenString); | ||||
| 		} else | ||||
| 			moduleStack.push(moduleStack.peek()+"."+tokenString); | ||||
|  | ||||
|   | ||||
| @@ -0,0 +1,77 @@ | ||||
| /******************************************************************************* | ||||
|  * Copyright (c) 2015-2021 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.database.vcd; | ||||
|  | ||||
| import java.io.File; | ||||
| import java.io.FileInputStream; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.util.zip.GZIPInputStream; | ||||
|  | ||||
| import com.minres.scviewer.database.IWaveformDbLoader; | ||||
| import com.minres.scviewer.database.IWaveformDbLoaderFactory; | ||||
|  | ||||
| /** | ||||
|  * The Class VCDDb. | ||||
|  */ | ||||
| public class VCDDbLoaderFactory implements IWaveformDbLoaderFactory { | ||||
| 	/** | ||||
| 	 * Checks if is gzipped. | ||||
| 	 * | ||||
| 	 * @param f the f | ||||
| 	 * @return true, if is gzipped | ||||
| 	 */ | ||||
| 	private static boolean isGzipped(File f) { | ||||
| 		try (InputStream is = new FileInputStream(f)) { | ||||
| 			byte [] signature = new byte[2]; | ||||
| 			int nread = is.read( signature ); //read the gzip signature | ||||
| 			return nread == 2 && signature[ 0 ] == (byte) 0x1f && signature[ 1 ] == (byte) 0x8b; | ||||
| 		} | ||||
| 		catch (IOException e) { | ||||
| 			return false; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	/** | ||||
| 	 * Can load. | ||||
| 	 * | ||||
| 	 * @param inputFile the input file | ||||
| 	 * @return true, if successful | ||||
| 	 */ | ||||
| 	@Override | ||||
| 	public boolean canLoad(File inputFile) { | ||||
| 		if(!inputFile.isDirectory() || inputFile.exists()) { | ||||
| 			String name = inputFile.getName(); | ||||
| 			if(!(name.endsWith(".vcd") || | ||||
| 					name.endsWith(".vcdz") || | ||||
| 					name.endsWith(".vcdgz")  || | ||||
| 					name.endsWith(".vcd.gz")) ) | ||||
| 				return false; | ||||
| 			boolean gzipped = isGzipped(inputFile); | ||||
| 			try(InputStream stream = gzipped ? new GZIPInputStream(new FileInputStream(inputFile)) : new FileInputStream(inputFile)){ | ||||
| 				byte[] buffer = new byte[8]; | ||||
| 				if (stream.read(buffer, 0, buffer.length) == buffer.length) { | ||||
| 					return buffer[0]=='$'; | ||||
| 				} | ||||
| 			} catch (Exception e) { | ||||
| 				return false; | ||||
| 			} | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	@Override | ||||
| 	public IWaveformDbLoader getLoader() { | ||||
| 		return new VCDDbLoader(); | ||||
| 	} | ||||
| } | ||||
| @@ -12,5 +12,5 @@ org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled | ||||
| org.eclipse.jdt.core.compiler.problem.enumIdentifier=error | ||||
| org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning | ||||
| org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning | ||||
| org.eclipse.jdt.core.compiler.release=disabled | ||||
| org.eclipse.jdt.core.compiler.release=enabled | ||||
| org.eclipse.jdt.core.compiler.source=11 | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="com.minres.scviewer.database.loader"> | ||||
|    <implementation class="com.minres.scviewer.database.internal.WaveformDb"/> | ||||
|    <reference bind="bind" cardinality="1..n" interface="com.minres.scviewer.database.IWaveformDbLoader" name="IWaveformDbLoader" policy="dynamic" unbind="unbind"/> | ||||
|    <reference bind="bind" cardinality="1..n" interface="com.minres.scviewer.database.IWaveformDbLoaderFactory" name="IWaveformDbLoaderFactory" policy="dynamic" unbind="unbind"/> | ||||
| </scr:component> | ||||
|   | ||||
| @@ -4,7 +4,7 @@ | ||||
|   <parent> | ||||
|   	<groupId>com.minres.scviewer</groupId> | ||||
|   	<artifactId>com.minres.scviewer.parent</artifactId> | ||||
|   	<version>2.13.0</version> | ||||
|   	<version>2.15.1</version> | ||||
| 	<relativePath>../..</relativePath> | ||||
|   </parent> | ||||
|   <packaging>eclipse-plugin</packaging> | ||||
|   | ||||
| @@ -62,9 +62,4 @@ public interface IWaveformDb extends IHierNode { | ||||
| 	 */ | ||||
| 	public boolean isLoaded(); | ||||
|  | ||||
| 	/** | ||||
| 	 * Clear. | ||||
| 	 */ | ||||
| 	public void clear(); | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,33 @@ | ||||
| /******************************************************************************* | ||||
|  * Copyright (c) 2015-2021 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.database; | ||||
|  | ||||
| import java.io.File; | ||||
|  | ||||
| /** | ||||
|  * A factory for creating IWaveformDb objects. | ||||
|  */ | ||||
| public interface IWaveformDbLoaderFactory { | ||||
|  | ||||
| 	/** | ||||
| 	 * Check if the loader produced by this factory can load the given file. | ||||
| 	 * | ||||
| 	 * @param inputFile the input file | ||||
| 	 * @return true, if successful | ||||
| 	 */ | ||||
| 	public boolean canLoad(File inputFile); | ||||
| 	/** | ||||
| 	 * Gets the database. | ||||
| 	 * | ||||
| 	 * @return the database | ||||
| 	 */ | ||||
| 	IWaveformDbLoader getLoader(); | ||||
| } | ||||
| @@ -15,16 +15,17 @@ import java.beans.PropertyChangeListener; | ||||
| import java.io.File; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collections; | ||||
| import java.util.HashMap; | ||||
| import java.util.LinkedList; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| import java.util.concurrent.ConcurrentHashMap; | ||||
|  | ||||
| import com.minres.scviewer.database.HierNode; | ||||
| import com.minres.scviewer.database.IHierNode; | ||||
| import com.minres.scviewer.database.IWaveform; | ||||
| import com.minres.scviewer.database.IWaveformDb; | ||||
| import com.minres.scviewer.database.IWaveformDbLoader; | ||||
| import com.minres.scviewer.database.IWaveformDbLoaderFactory; | ||||
| import com.minres.scviewer.database.RelationType; | ||||
|  | ||||
| /** | ||||
| @@ -33,7 +34,7 @@ import com.minres.scviewer.database.RelationType; | ||||
| public class WaveformDb extends HierNode implements IWaveformDb, PropertyChangeListener { | ||||
|  | ||||
| 	/** The loaders. */ | ||||
| 	private static List<IWaveformDbLoader> loaders = new LinkedList<>(); | ||||
| 	private static List<IWaveformDbLoaderFactory> loaderFactories = new LinkedList<>(); | ||||
|  | ||||
| 	/** The loaded. */ | ||||
| 	private boolean loaded; | ||||
| @@ -52,8 +53,8 @@ public class WaveformDb extends HierNode implements IWaveformDb, PropertyChangeL | ||||
| 	 * | ||||
| 	 * @param loader the loader | ||||
| 	 */ | ||||
| 	public synchronized void bind(IWaveformDbLoader loader) { | ||||
| 		loaders.add(loader); | ||||
| 	public synchronized void bind(IWaveformDbLoaderFactory loader) { | ||||
| 		loaderFactories.add(loader); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| @@ -61,8 +62,8 @@ public class WaveformDb extends HierNode implements IWaveformDb, PropertyChangeL | ||||
| 	 * | ||||
| 	 * @param loader the loader | ||||
| 	 */ | ||||
| 	public synchronized void unbind(IWaveformDbLoader loader) { | ||||
| 		loaders.remove(loader); | ||||
| 	public synchronized void unbind(IWaveformDbLoaderFactory loader) { | ||||
| 		loaderFactories.remove(loader); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| @@ -70,8 +71,8 @@ public class WaveformDb extends HierNode implements IWaveformDb, PropertyChangeL | ||||
| 	 * | ||||
| 	 * @return the loaders | ||||
| 	 */ | ||||
| 	public static List<IWaveformDbLoader> getLoaders() { | ||||
| 		return Collections.unmodifiableList(loaders); | ||||
| 	public static List<IWaveformDbLoaderFactory> getLoaders() { | ||||
| 		return Collections.unmodifiableList(loaderFactories); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| @@ -79,7 +80,7 @@ public class WaveformDb extends HierNode implements IWaveformDb, PropertyChangeL | ||||
| 	 */ | ||||
| 	public WaveformDb() { | ||||
| 		super(); | ||||
| 		waveforms = new HashMap<>(); | ||||
| 		waveforms = new ConcurrentHashMap<>(); | ||||
| 		relationTypes = new ArrayList<>(); | ||||
| 		maxTime = 0L; | ||||
| 	} | ||||
| @@ -124,8 +125,9 @@ public class WaveformDb extends HierNode implements IWaveformDb, PropertyChangeL | ||||
| 	@Override | ||||
| 	public boolean load(File inp) { | ||||
| 		boolean retval = true; | ||||
| 		for (IWaveformDbLoader loader : loaders) { | ||||
| 			if (loader.canLoad(inp)) { | ||||
| 		for (IWaveformDbLoaderFactory loaderFactory : loaderFactories) { | ||||
| 			if (loaderFactory.canLoad(inp)) { | ||||
| 				IWaveformDbLoader loader = loaderFactory.getLoader(); | ||||
| 				loader.addPropertyChangeListener(this); | ||||
| 				try { | ||||
| 					loader.load(this, inp); | ||||
| @@ -165,16 +167,6 @@ public class WaveformDb extends HierNode implements IWaveformDb, PropertyChangeL | ||||
| 		return ext; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Clear. | ||||
| 	 */ | ||||
| 	@Override | ||||
| 	public void clear() { | ||||
| 		waveforms.clear(); | ||||
| 		childNodes.clear(); | ||||
| 		loaded = false; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Checks if is loaded. | ||||
| 	 * | ||||
| @@ -201,7 +193,7 @@ public class WaveformDb extends HierNode implements IWaveformDb, PropertyChangeL | ||||
| 	/** | ||||
| 	 * Builds the hierarchy nodes. | ||||
| 	 */ | ||||
| 	private void buildHierarchyNodes() { | ||||
| 	private synchronized void buildHierarchyNodes() { | ||||
| 		boolean needsSorting = false; | ||||
| 		for (IWaveform stream : getAllWaves()) { | ||||
| 			if (stream.getParent() == null) { | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <application:Application xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:advanced="http://www.eclipse.org/ui/2010/UIModel/application/ui/advanced" xmlns:application="http://www.eclipse.org/ui/2010/UIModel/application" xmlns:basic="http://www.eclipse.org/ui/2010/UIModel/application/ui/basic" xmlns:menu="http://www.eclipse.org/ui/2010/UIModel/application/ui/menu" xmlns:ui="http://www.eclipse.org/ui/2010/UIModel/application/ui" xmi:id="_95PfsHNmEeWBq8z1Dv39LA" elementId="org.eclipse.e4.ide.application" bindingContexts="_95PfuXNmEeWBq8z1Dv39LA"> | ||||
|   <children xsi:type="basic:TrimmedWindow" xmi:id="_95PfsXNmEeWBq8z1Dv39LA" label="SC Viewer" bindingContexts="_95PfunNmEeWBq8z1Dv39LA" width="1280" height="700"> | ||||
|   <children xsi:type="basic:TrimmedWindow" xmi:id="_95PfsXNmEeWBq8z1Dv39LA" elementId="com.minres.scviewer.e4.application.trimmedwindow.main" label="SC Viewer" bindingContexts="_95PfunNmEeWBq8z1Dv39LA" width="1280" height="700"> | ||||
|     <children xsi:type="advanced:PerspectiveStack" xmi:id="_95QGxnNmEeWBq8z1Dv39LA"> | ||||
|       <children xsi:type="advanced:Perspective" xmi:id="_95QGx3NmEeWBq8z1Dv39LA"> | ||||
|         <children xsi:type="basic:PartStack" xmi:id="_95QGyXNmEeWBq8z1Dv39LA" elementId="org.eclipse.editorss" containerData="7500"> | ||||
| @@ -9,20 +9,22 @@ | ||||
|       </children> | ||||
|     </children> | ||||
|     <children xsi:type="basic:Part" xmi:id="__VNlAIytEeWid7xO48ZBXw" elementId="com.minres.scviewer.e4.application.dialog.aboutscviewer" toBeRendered="false" visible="false" contributionURI="bundleclass://com.minres.scviewer.e4.application/com.minres.scviewer.e4.application.parts.AboutDialog" label="About SCViewer" bindingContexts="_95Pfu3NmEeWBq8z1Dv39LA"/> | ||||
|     <children xsi:type="basic:Part" xmi:id="_hXh-kEYFEeyPM8G0E2EYww" elementId="com.minres.scviewer.e4.application.dialog.onlinehelp" toBeRendered="false" visible="false" contributionURI="bundleclass://com.minres.scviewer.e4.application/com.minres.scviewer.e4.application.parts.HelpDialog" label="SCViewer Online Help" bindingContexts="_95Pfu3NmEeWBq8z1Dv39LA" closeable="true"/> | ||||
|     <mainMenu xmi:id="_95PfyXNmEeWBq8z1Dv39LA" elementId="menu:org.eclipse.ui.main.menu"> | ||||
|       <children xsi:type="menu:Menu" xmi:id="_95QGwHNmEeWBq8z1Dv39LA" elementId="com.minres.scviewer.e4.application.menu.file" label="File"> | ||||
|         <children xsi:type="menu:HandledMenuItem" xmi:id="_igsK0BkREeudD5MqrWoETQ" elementId="" label="Open Database" iconURI="platform:/plugin/com.minres.scviewer.e4.application/icons/folder_database.png" mnemonics="M1+O" command="_95PfwHNmEeWBq8z1Dv39LA"/> | ||||
|         <children xsi:type="menu:HandledMenuItem" xmi:id="_VJG3YHgvEeWwZ-9vrAR2UQ" elementId="" label="Re-load Database" iconURI="platform:/plugin/com.minres.scviewer.e4.application/icons/database_refresh.png" mnemonics="M1+R" command="_srACsBkREeudD5MqrWoETQ"/> | ||||
|         <children xsi:type="menu:HandledMenuItem" xmi:id="_igsK0BkREeudD5MqrWoETQ" elementId="" label="Open Database" iconURI="platform:/plugin/com.minres.scviewer.e4.application/icons/folder_database.png" mnemonics="" command="_95PfwHNmEeWBq8z1Dv39LA"/> | ||||
|         <children xsi:type="menu:HandledMenuItem" xmi:id="_VJG3YHgvEeWwZ-9vrAR2UQ" elementId="" label="Re-load Database" iconURI="platform:/plugin/com.minres.scviewer.e4.application/icons/database_refresh.png" mnemonics="" command="_srACsBkREeudD5MqrWoETQ"/> | ||||
|         <children xsi:type="menu:HandledMenuItem" xmi:id="_e7MOYJedEeW09eyIbHsdvg" elementId="" label="Load active tab settings" iconURI="platform:/plugin/com.minres.scviewer.e4.application/icons/folder_page.png" command="_7-AIMJebEeW09eyIbHsdvg"> | ||||
|           <parameters xmi:id="_4vtYgJehEeW09eyIbHsdvg" elementId="com.minres.scviewer.e4.application.parameter.30" name="com.minres.scviewer.e4.application.commandparameter.loadStore" value="load"/> | ||||
|         </children> | ||||
|         <children xsi:type="menu:HandledMenuItem" xmi:id="_95QGwnNmEeWBq8z1Dv39LA" label="Save active tab settings" iconURI="platform:/plugin/com.minres.scviewer.e4.application/icons/script_save.png" command="_7-AIMJebEeW09eyIbHsdvg"> | ||||
|         <children xsi:type="menu:HandledMenuItem" xmi:id="_95QGwnNmEeWBq8z1Dv39LA" label="Save active tab settings" iconURI="platform:/plugin/com.minres.scviewer.e4.application/icons/script_save.png" mnemonics="" command="_7-AIMJebEeW09eyIbHsdvg"> | ||||
|           <parameters xmi:id="_61QIsJehEeW09eyIbHsdvg" elementId="com.minres.scviewer.e4.application.parameter.31" name="com.minres.scviewer.e4.application.commandparameter.loadStore" value="store"/> | ||||
|         </children> | ||||
|         <children xsi:type="menu:HandledMenuItem" xmi:id="_95QGw3NmEeWBq8z1Dv39LA" label="Quit" command="_95PfvHNmEeWBq8z1Dv39LA"/> | ||||
|       </children> | ||||
|       <children xsi:type="menu:Menu" xmi:id="_ZyHC0HgvEeWwZ-9vrAR2UQ" elementId="" label="Edit"> | ||||
|         <children xsi:type="menu:HandledMenuItem" xmi:id="_cPlx4HgvEeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.handledmenuitem.delete" label="Delete" iconURI="platform:/plugin/com.minres.scviewer.e4.application/icons/cross.png" command="_WUZ2wHXHEeWwZ-9vrAR2UQ"/> | ||||
|         <children xsi:type="menu:HandledMenuItem" xmi:id="_FiwZcEhdEeyp3vLifEzGbQ" elementId="com.minres.scviewer.e4.application.handledmenuitem.delete" label="Delete" iconURI="platform:/plugin/com.minres.scviewer.e4.application/icons/cross.png" command="_WUZ2wHXHEeWwZ-9vrAR2UQ"/> | ||||
|         <children xsi:type="menu:HandledMenuItem" xmi:id="_cPlx4HgvEeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.handledmenuitem.delete" label="Select All" iconURI="" command="_bV-TMHXHEeWwZ-9vrAR2UQ"/> | ||||
|       </children> | ||||
|       <children xsi:type="menu:Menu" xmi:id="_XmZY4HchEeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.menu.navigate" label="Navigate"> | ||||
|         <children xsi:type="menu:Menu" xmi:id="_VCn_cHgwEeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.menu.waveform" label="Waveform ..."> | ||||
| @@ -55,7 +57,8 @@ | ||||
|       </children> | ||||
|       <children xsi:type="menu:Menu" xmi:id="_95QGxHNmEeWBq8z1Dv39LA" elementId="com.minres.scviewer.e4.application.menu.help" label="Help"> | ||||
|         <children xsi:type="menu:HandledMenuItem" xmi:id="_UQRi0B07EeuiP60JNw0iiA" elementId="com.minres.scviewer.e4.application.handledmenuitem.checkforupdate" visible="false" label="Check for Update" enabled="false" command="_-9ED4B06EeuiP60JNw0iiA"/> | ||||
|         <children xsi:type="menu:HandledMenuItem" xmi:id="_95QGxXNmEeWBq8z1Dv39LA" label="About" command="_95PfxnNmEeWBq8z1Dv39LA"/> | ||||
|         <children xsi:type="menu:HandledMenuItem" xmi:id="_95QGxXNmEeWBq8z1Dv39LA" label="Online Help" command="_lqjIYEYEEeyPM8G0E2EYww"/> | ||||
|         <children xsi:type="menu:HandledMenuItem" xmi:id="_4xtmgEYEEeyPM8G0E2EYww" label="About" command="_95PfxnNmEeWBq8z1Dv39LA"/> | ||||
|       </children> | ||||
|     </mainMenu> | ||||
|     <trimBars xmi:id="_95QGy3NmEeWBq8z1Dv39LA" elementId="org.eclipse.ui.main.toolbar"> | ||||
| @@ -78,41 +81,12 @@ | ||||
|         <children xsi:type="menu:HandledToolItem" xmi:id="_FrGmEHcjEeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.handledtoolitem.movestreamdown" label="Move Stream down" iconURI="platform:/plugin/com.minres.scviewer.e4.application/icons/down_blue.png" tooltip="Move stream/waveform in list down" command="_N_sOkHXHEeWwZ-9vrAR2UQ"> | ||||
|           <parameters xmi:id="_VA_yAHcjEeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.parameter.9" name="com.minres.scviewer.e4.application.command.movewaveformupCommand.parameter.dir" value="down"/> | ||||
|         </children> | ||||
|         <children xsi:type="menu:ToolBarSeparator" xmi:id="_srcD0HgwEeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.toolbarseparator.3"/> | ||||
|         <children xsi:type="menu:HandledToolItem" xmi:id="_GKi7IHcjEeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.handledtoolitem.previousevent" label="Previous Event" iconURI="platform:/plugin/com.minres.scviewer.e4.application/icons/reverse_blue.png" tooltip="Navigate to previous event in stream/waveform" command="_79rx4HabEeWwZ-9vrAR2UQ"> | ||||
|           <parameters xmi:id="_XS7YYHcjEeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.parameter.10" name="com.minres.scviewer.e4.application.command.navigateEventCommand.parameter.dir" value="prev"/> | ||||
|         </children> | ||||
|         <children xsi:type="menu:HandledToolItem" xmi:id="_GjlGMHcjEeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.handledtoolitem.nextevent" label="Next Event" iconURI="platform:/plugin/com.minres.scviewer.e4.application/icons/play_blue.png" tooltip="Navigate to next event in stream/waveform" command="_79rx4HabEeWwZ-9vrAR2UQ"> | ||||
|           <parameters xmi:id="_ZzTqcHcjEeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.parameter.11" name="com.minres.scviewer.e4.application.command.navigateEventCommand.parameter.dir" value="next"/> | ||||
|         </children> | ||||
|         <children xsi:type="menu:ToolBarSeparator" xmi:id="_tcxaIHgwEeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.toolbarseparator.4"/> | ||||
|         <children xsi:type="menu:HandledToolItem" xmi:id="_HdKZkHcjEeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.handledtoolitem.previoustransaction" label="Previous Transaction" iconURI="platform:/plugin/com.minres.scviewer.e4.application/icons/reverse_green.png" tooltip="Navigate to previous transaction" command="_Gn3lEHXKEeWwZ-9vrAR2UQ"> | ||||
|           <parameters xmi:id="_cuGAkHcjEeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.parameter.12" name="com.minres.scviewer.e4.application.command.navigateTransCommand.parameter.dir" value="prev"/> | ||||
|         </children> | ||||
|         <children xsi:type="menu:ToolControl" xmi:id="_LtQhcIuKEeWid7xO48ZBXw" elementId="com.minres.scviewer.e4.application.toolcontrol.0" contributionURI="bundleclass://com.minres.scviewer.e4.application/com.minres.scviewer.e4.application.elements.RelationTypeToolControl"/> | ||||
|         <children xsi:type="menu:DirectToolItem" xmi:id="_Z7ZQkIuJEeWid7xO48ZBXw" elementId="com.minres.scviewer.e4.application.directtoolitem.nextprevinstream" toBeRendered="false" visible="false" label="Next/Prev in stream"> | ||||
|           <menu xmi:id="_aPyMMIuJEeWid7xO48ZBXw" elementId="com.minres.scviewer.e4.application.menu.2"> | ||||
|             <children xsi:type="menu:DynamicMenuContribution" xmi:id="_cnNWkIuJEeWid7xO48ZBXw" elementId="com.minres.scviewer.e4.application.dynamicmenucontribution.2" contributionURI="bundleclass://com.minres.scviewer.e4.application/com.minres.scviewer.e4.application.parts.NavigateContribution"/> | ||||
|           </menu> | ||||
|         </children> | ||||
|         <children xsi:type="menu:HandledToolItem" xmi:id="_H7bp8HcjEeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.handledtoolitem.nexttransaction" label="Next Transaction" iconURI="platform:/plugin/com.minres.scviewer.e4.application/icons/play_green.png" tooltip="Navigate to next transaction" command="_Gn3lEHXKEeWwZ-9vrAR2UQ"> | ||||
|           <parameters xmi:id="_fiO8IHcjEeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.parameter.13" name="com.minres.scviewer.e4.application.command.navigateTransCommand.parameter.dir" value="next"/> | ||||
|         </children> | ||||
|       </children> | ||||
|       <children xsi:type="menu:ToolBar" xmi:id="_oQdMUHcqEeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.toolbar.1"> | ||||
|         <children xsi:type="menu:HandledToolItem" xmi:id="_5DrGQHf4EeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.handledtoolitem.zoomfit" label="Zoom out" iconURI="platform:/plugin/com.minres.scviewer.e4.application/icons/magnifier.png" tooltip="Restore default zoom level" command="_693GoHcqEeWwZ-9vrAR2UQ"> | ||||
|           <parameters xmi:id="_5DrGQXf4EeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.parameter.14" name="com.minres.scviewer.e4.application.command.zoomcommand.parameter.level" value="fit"/> | ||||
|         </children> | ||||
|         <children xsi:type="menu:ToolBarSeparator" xmi:id="_p1AvUHcqEeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.toolbarseparator.1"/> | ||||
|         <children xsi:type="menu:HandledToolItem" xmi:id="_XMQPAHcrEeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.handledtoolitem.zoomin" label="Zoom in" iconURI="platform:/plugin/com.minres.scviewer.e4.application/icons/magnifier_zoom_in.png" tooltip="Zoom in by a factor of 3" command="_693GoHcqEeWwZ-9vrAR2UQ"> | ||||
|           <parameters xmi:id="_fi5w4HcrEeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.parameter.15" name="com.minres.scviewer.e4.application.command.zoomcommand.parameter.level" value="in"/> | ||||
|         </children> | ||||
|         <children xsi:type="menu:HandledToolItem" xmi:id="_XqTc8HcrEeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.handledtoolitem.zoomout" label="Zoom out" iconURI="platform:/plugin/com.minres.scviewer.e4.application/icons/magifier_zoom_out.png" tooltip="Zoom out by a factor of 3" command="_693GoHcqEeWwZ-9vrAR2UQ"> | ||||
|           <parameters xmi:id="_d7OBYHcrEeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.parameter.14" name="com.minres.scviewer.e4.application.command.zoomcommand.parameter.level" value="out"/> | ||||
|         </children> | ||||
|       </children> | ||||
|       <children xsi:type="menu:ToolBar" xmi:id="_fwn8wGtTEeqmlpoaaMHoiw" elementId="com.minres.scviewer.e4.application.toolbar.2"> | ||||
|         <children xsi:type="menu:HandledToolItem" xmi:id="_j-XIgGtTEeqmlpoaaMHoiw" elementId="com.minres.scviewer.e4.application.handledtoolitem.hover" label="Hover" iconURI="platform:/plugin/com.minres.scviewer.e4.application/icons/lightbulb.png" tooltip="Enable hover window in waveform" selected="true" type="Check" command="_uyeyYGtTEeqmlpoaaMHoiw"> | ||||
|         <children xsi:type="menu:HandledToolItem" xmi:id="_j-XIgGtTEeqmlpoaaMHoiw" elementId="com.minres.scviewer.e4.application.handledtoolitem.txdetails" label="TX Details" iconURI="platform:/plugin/com.minres.scviewer.e4.application/icons/application_side_expand.png" tooltip="Show tx details parts" selected="true" type="Check" command="_Fj1gQEYoEeyKK_icsY7Xjg"> | ||||
|           <tags>EnableTxDetails</tags> | ||||
|         </children> | ||||
|         <children xsi:type="menu:HandledToolItem" xmi:id="_33tugEYnEeyKK_icsY7Xjg" elementId="com.minres.scviewer.e4.application.handledtoolitem.hover" label="Hover" iconURI="platform:/plugin/com.minres.scviewer.e4.application/icons/lightbulb.png" tooltip="Enable hover window in waveform" selected="true" type="Check" command="_uyeyYGtTEeqmlpoaaMHoiw"> | ||||
|           <tags>EnableHover</tags> | ||||
|         </children> | ||||
|       </children> | ||||
| @@ -135,24 +109,17 @@ | ||||
|   <handlers xmi:id="_UUnX8IoNEeWxJ_wPkM6yGQ" elementId="com.minres.scviewer.e4.application.handler.set_them" contributionURI="bundleclass://com.minres.scviewer.e4.application/com.minres.scviewer.e4.application.handlers.ThemeSetHandler" command="_KlGlsIoNEeWxJ_wPkM6yGQ"/> | ||||
|   <handlers xmi:id="_V4EscIuGEeWid7xO48ZBXw" elementId="com.minres.scviewer.e4.application.handler.setreleationtype" contributionURI="bundleclass://com.minres.scviewer.e4.application/com.minres.scviewer.e4.application.handlers.SetRelationTypeHandler" command="_E9lUgIt2EeWid7xO48ZBXw"/> | ||||
|   <handlers xmi:id="__99WoJebEeW09eyIbHsdvg" elementId="com.minres.scviewer.e4.application.handler.loadStoreSettings" contributionURI="bundleclass://com.minres.scviewer.e4.application/com.minres.scviewer.e4.application.handlers.LoadStoreSettingsHandler" command="_7-AIMJebEeW09eyIbHsdvg"/> | ||||
|   <handlers xmi:id="_x4pSEGtTEeqmlpoaaMHoiw" elementId="com.minres.scviewer.e4.application.handler.0" contributionURI="bundleclass://com.minres.scviewer.e4.application/com.minres.scviewer.e4.application.handlers.EnableHover" command="_uyeyYGtTEeqmlpoaaMHoiw"/> | ||||
|   <handlers xmi:id="_x4pSEGtTEeqmlpoaaMHoiw" elementId="com.minres.scviewer.e4.application.handler.enablehover" contributionURI="bundleclass://com.minres.scviewer.e4.application/com.minres.scviewer.e4.application.handlers.EnableHover" command="_uyeyYGtTEeqmlpoaaMHoiw"/> | ||||
|   <handlers xmi:id="_h3jU8BkWEeudD5MqrWoETQ" elementId="com.minres.scviewer.e4.application.handler.reloadCommand" contributionURI="bundleclass://com.minres.scviewer.e4.application/com.minres.scviewer.e4.application.handlers.ReloadHandler" command="_srACsBkREeudD5MqrWoETQ"/> | ||||
|   <handlers xmi:id="_gn_boBlEEeuiP60JNw0iiA" elementId="com.minres.scviewer.e4.application.handler.txSearch" contributionURI="bundleclass://com.minres.scviewer.e4.application/com.minres.scviewer.e4.application.handlers.SearchHandler" command="_XDxTYBlEEeuiP60JNw0iiA"/> | ||||
|   <handlers xmi:id="_CCEtAB07EeuiP60JNw0iiA" elementId="com.minres.scviewer.e4.application.handler.update" contributionURI="bundleclass://com.minres.scviewer.e4.application/com.minres.scviewer.e4.application.handlers.UpdateHandler" command="_-9ED4B06EeuiP60JNw0iiA"/> | ||||
|   <handlers xmi:id="_ru2NIEYEEeyPM8G0E2EYww" elementId="com.minres.scviewer.e4.application.handler.helpCommand" contributionURI="bundleclass://com.minres.scviewer.e4.application/com.minres.scviewer.e4.application.handlers.HelpHandler" command="_lqjIYEYEEeyPM8G0E2EYww"/> | ||||
|   <handlers xmi:id="_TwU0IEYoEeyKK_icsY7Xjg" elementId="com.minres.scviewer.e4.application.handler.enabletxdetails" contributionURI="bundleclass://com.minres.scviewer.e4.application/com.minres.scviewer.e4.application.handlers.EnableTxDetails" command="_Fj1gQEYoEeyKK_icsY7Xjg"/> | ||||
|   <bindingTables xmi:id="_95PfvnNmEeWBq8z1Dv39LA" bindingContext="_95PfuXNmEeWBq8z1Dv39LA"> | ||||
|     <bindings xmi:id="_95Pfv3NmEeWBq8z1Dv39LA" elementId="com.minres.scviewer.e4.application.keybinding.quit" keySequence="M1+Q" command="_95PfvHNmEeWBq8z1Dv39LA"> | ||||
|       <tags>type:user</tags> | ||||
|     </bindings> | ||||
|   </bindingTables> | ||||
|   <bindingTables xmi:id="_zZFy0GVNEeqSQM-A6dw9ig" elementId="com.minres.scviewer.e4.application.bindingtable.waveform" bindingContext="_q4VSsGVNEeqSQM-A6dw9ig"> | ||||
|     <bindings xmi:id="_1o3dEGVNEeqSQM-A6dw9ig" elementId="com.minres.scviewer.e4.application.keybinding.zoom_in" keySequence="M1++" command="_693GoHcqEeWwZ-9vrAR2UQ"> | ||||
|       <tags>type:user</tags> | ||||
|       <parameters xmi:id="_53UagGVNEeqSQM-A6dw9ig" elementId="com.minres.scviewer.e4.application.parameter.33" name="com.minres.scviewer.e4.application.command.zoomcommand.parameter.level" value="in"/> | ||||
|     </bindings> | ||||
|     <bindings xmi:id="_8i3awGVNEeqSQM-A6dw9ig" elementId="com.minres.scviewer.e4.application.keybinding.zoom_out" keySequence="M1+-" command="_693GoHcqEeWwZ-9vrAR2UQ"> | ||||
|       <tags>type:user</tags> | ||||
|       <parameters xmi:id="__UCh4GVNEeqSQM-A6dw9ig" elementId="com.minres.scviewer.e4.application.parameter.34" name="com.minres.scviewer.e4.application.command.zoomcommand.parameter.level" value="out"/> | ||||
|     </bindings> | ||||
|     <bindings xmi:id="_2-008EhnEeyp3vLifEzGbQ" elementId="com.minres.scviewer.e4.application.keybinding.help" keySequence="F1" command="_lqjIYEYEEeyPM8G0E2EYww"/> | ||||
|   </bindingTables> | ||||
|   <bindingTables xmi:id="_XullMGVOEeqSQM-A6dw9ig" elementId="com.minres.scviewer.e4.application.bindingtable.window" bindingContext="_95PfunNmEeWBq8z1Dv39LA"> | ||||
|     <bindings xmi:id="_95PfwnNmEeWBq8z1Dv39LA" elementId="com.minres.scviewer.e4.application.keybinding.load" keySequence="M1+L" command="_7-AIMJebEeW09eyIbHsdvg"> | ||||
| @@ -169,20 +136,22 @@ | ||||
|     <bindings xmi:id="_3PRIQGVPEeqSQM-A6dw9ig" elementId="com.minres.scviewer.e4.application.keybinding.open" keySequence="M1+O" command="_95PfwHNmEeWBq8z1Dv39LA"> | ||||
|       <tags>type:user</tags> | ||||
|     </bindings> | ||||
|   </bindingTables> | ||||
|   <bindingTables xmi:id="_mnMrUGVmEeqSQM-A6dw9ig" elementId="com.minres.scviewer.e4.application.bindingtable.0" bindingContext="_iQ3kQGVmEeqSQM-A6dw9ig"> | ||||
|     <bindings xmi:id="_n9yDwGVmEeqSQM-A6dw9ig" elementId="com.minres.scviewer.e4.application.keybinding.0" keySequence="M1+A" command="_bV-TMHXHEeWwZ-9vrAR2UQ"> | ||||
|     <bindings xmi:id="_QcOn8EheEeyp3vLifEzGbQ" elementId="com.minres.scviewer.e4.application.keybinding.1" keySequence="M1+A" command="_bV-TMHXHEeWwZ-9vrAR2UQ"/> | ||||
|     <bindings xmi:id="_1o3dEGVNEeqSQM-A6dw9ig" elementId="com.minres.scviewer.e4.application.keybinding.zoom_in" keySequence="M1++" command="_693GoHcqEeWwZ-9vrAR2UQ"> | ||||
|       <tags>type:user</tags> | ||||
|       <parameters xmi:id="_53UagGVNEeqSQM-A6dw9ig" elementId="com.minres.scviewer.e4.application.parameter.33" name="com.minres.scviewer.e4.application.command.zoomcommand.parameter.level" value="in"/> | ||||
|     </bindings> | ||||
|     <bindings xmi:id="_8i3awGVNEeqSQM-A6dw9ig" elementId="com.minres.scviewer.e4.application.keybinding.zoom_out" keySequence="M1+-" command="_693GoHcqEeWwZ-9vrAR2UQ"> | ||||
|       <tags>type:user</tags> | ||||
|       <parameters xmi:id="__UCh4GVNEeqSQM-A6dw9ig" elementId="com.minres.scviewer.e4.application.parameter.34" name="com.minres.scviewer.e4.application.command.zoomcommand.parameter.level" value="out"/> | ||||
|     </bindings> | ||||
|     <bindings xmi:id="_KjmnsEheEeyp3vLifEzGbQ" elementId="com.minres.scviewer.e4.application.keybinding.0" keySequence="M1+R" command="_srACsBkREeudD5MqrWoETQ"/> | ||||
|   </bindingTables> | ||||
|   <rootContext xmi:id="_95PfuXNmEeWBq8z1Dv39LA" elementId="org.eclipse.ui.contexts.dialogAndWindow" name="In Dialog and Windows"> | ||||
|     <children xmi:id="_95PfunNmEeWBq8z1Dv39LA" elementId="org.eclipse.ui.contexts.window" name="In Windows"> | ||||
|       <children xmi:id="_q4VSsGVNEeqSQM-A6dw9ig" elementId="com.minres.scviewer.e4.application.bindingcontext.waveform" name="In Waveform Part"/> | ||||
|       <children xmi:id="_iQ3kQGVmEeqSQM-A6dw9ig" elementId="com.minres.scviewer.e4.application.bindingcontext.indesignbrowser" name="In DesignBrowser"/> | ||||
|     </children> | ||||
|     <children xmi:id="_95PfunNmEeWBq8z1Dv39LA" elementId="org.eclipse.ui.contexts.window" name="In Windows"/> | ||||
|     <children xmi:id="_95Pfu3NmEeWBq8z1Dv39LA" elementId="org.eclipse.ui.contexts.dialog" name="In Dialogs"/> | ||||
|   </rootContext> | ||||
|   <descriptors xmi:id="_KicY0HRMEeWBq8z1Dv39LA" elementId="com.minres.scviewer.e4.application.partdescriptor.waveformviewer" label="SCViewer" iconURI="platform:/plugin/com.minres.scviewer.e4.application/icons/scviewer.png" bindingContexts="_q4VSsGVNEeqSQM-A6dw9ig" allowMultiple="true" category="General" closeable="true" contributionURI="bundleclass://com.minres.scviewer.e4.application/com.minres.scviewer.e4.application.parts.WaveformViewer"> | ||||
|   <descriptors xmi:id="_KicY0HRMEeWBq8z1Dv39LA" elementId="com.minres.scviewer.e4.application.partdescriptor.waveformviewer" label="SCViewer" iconURI="platform:/plugin/com.minres.scviewer.e4.application/icons/scviewer.png" allowMultiple="true" category="General" closeable="true" contributionURI="bundleclass://com.minres.scviewer.e4.application/com.minres.scviewer.e4.application.parts.WaveformViewer"> | ||||
|     <tags>categoryTag:General</tags> | ||||
|     <handlers xmi:id="_BSIuEHacEeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.handler.navigateEventCommand" contributionURI="bundleclass://com.minres.scviewer.e4.application/com.minres.scviewer.e4.application.handlers.NavigateEvent" command="_79rx4HabEeWwZ-9vrAR2UQ"/> | ||||
|     <handlers xmi:id="_JpdGwHXKEeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.handler.navigateTransCommand" contributionURI="bundleclass://com.minres.scviewer.e4.application/com.minres.scviewer.e4.application.handlers.NavigateTrans" command="_Gn3lEHXKEeWwZ-9vrAR2UQ"/> | ||||
| @@ -191,6 +160,7 @@ | ||||
|     <handlers xmi:id="_Du1NAHcrEeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.handler.zoomCommand" contributionURI="bundleclass://com.minres.scviewer.e4.application/com.minres.scviewer.e4.application.handlers.ZoomHandler" command="_693GoHcqEeWwZ-9vrAR2UQ"/> | ||||
|     <handlers xmi:id="_bxt4QM3rEei6rfTGo88R-w" elementId="com.minres.scviewer.e4.application.handler.changeWaveDisplay" contributionURI="bundleclass://com.minres.scviewer.e4.application/com.minres.scviewer.e4.application.handlers.ChangeWaveformDisplay" command="_FZunYM2PEei6rfTGo88R-w"/> | ||||
|     <handlers xmi:id="_bxw7kM3rEei6rfTGo88R-w" elementId="com.minres.scviewer.e4.application.handler.changeValueDisplay" contributionURI="bundleclass://com.minres.scviewer.e4.application/com.minres.scviewer.e4.application.handlers.ChangeValueDisplay" command="_4C_asM3ZEei6rfTGo88R-w"/> | ||||
|     <handlers xmi:id="_ZVHbYE-JEeyuGJbYVZjX8w" elementId="com.minres.scviewer.e4.application.handler.panCommand" contributionURI="bundleclass://com.minres.scviewer.e4.application/com.minres.scviewer.e4.application.handlers.PanHandler" command="_y2BUsE-HEeyuGJbYVZjX8w"/> | ||||
|     <menus xsi:type="menu:PopupMenu" xmi:id="_TwzrsHWSEeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.popupmenu.namecontext" label="Name Menu"> | ||||
|       <children xsi:type="menu:HandledMenuItem" xmi:id="_Vco7YHWSEeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.handledmenuitem.moveup" label="Move up" iconURI="platform:/plugin/com.minres.scviewer.e4.application/icons/up_blue.png" tooltip="Move stream/waveform in list up" command="_N_sOkHXHEeWwZ-9vrAR2UQ"> | ||||
|         <visibleWhen xsi:type="ui:CoreExpression" xmi:id="_elFdcHr_EeWVM_sKoXvptg" coreExpressionId="com.minres.scviewer.e4.application.oneWaveSeleted"/> | ||||
| @@ -237,7 +207,50 @@ | ||||
|         <visibleWhen xsi:type="ui:ImperativeExpression" xmi:id="_Se1voBlEEeuiP60JNw0iiA" contributionURI="bundleclass://com.minres.scviewer.e4.application/com.minres.scviewer.e4.application.handlers.SearchHandler"/> | ||||
|       </children> | ||||
|     </menus> | ||||
|     <toolbar xmi:id="_ReeeAE-DEeyuGJbYVZjX8w" elementId="com.minres.scviewer.e4.application.toolbar.3"> | ||||
|       <children xsi:type="menu:HandledToolItem" xmi:id="_GKi7IHcjEeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.handledtoolitem.previousevent" label="Previous Event" iconURI="platform:/plugin/com.minres.scviewer.e4.application/icons/previous-green.png" tooltip="Navigate to previous event in stream/waveform" command="_79rx4HabEeWwZ-9vrAR2UQ"> | ||||
|         <parameters xmi:id="_XS7YYHcjEeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.parameter.10" name="com.minres.scviewer.e4.application.command.navigateEventCommand.parameter.dir" value="prev"/> | ||||
|       </children> | ||||
|       <children xsi:type="menu:HandledToolItem" xmi:id="_GjlGMHcjEeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.handledtoolitem.nextevent" label="Next Event" iconURI="platform:/plugin/com.minres.scviewer.e4.application/icons/next-green.png" tooltip="Navigate to next event in stream/waveform" command="_79rx4HabEeWwZ-9vrAR2UQ"> | ||||
|         <parameters xmi:id="_ZzTqcHcjEeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.parameter.11" name="com.minres.scviewer.e4.application.command.navigateEventCommand.parameter.dir" value="next"/> | ||||
|       </children> | ||||
|       <children xsi:type="menu:ToolBarSeparator" xmi:id="_tcxaIHgwEeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.toolbarseparator.4"/> | ||||
|       <children xsi:type="menu:HandledToolItem" xmi:id="_HdKZkHcjEeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.handledtoolitem.previoustransaction" label="Previous Transaction" iconURI="platform:/plugin/com.minres.scviewer.e4.application/icons/reverse_green.png" tooltip="Navigate to previous transaction" command="_Gn3lEHXKEeWwZ-9vrAR2UQ"> | ||||
|         <parameters xmi:id="_cuGAkHcjEeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.parameter.12" name="com.minres.scviewer.e4.application.command.navigateTransCommand.parameter.dir" value="prev"/> | ||||
|       </children> | ||||
|       <children xsi:type="menu:ToolControl" xmi:id="_LtQhcIuKEeWid7xO48ZBXw" elementId="com.minres.scviewer.e4.application.toolcontrol.0" contributionURI="bundleclass://com.minres.scviewer.e4.application/com.minres.scviewer.e4.application.elements.RelationTypeToolControl"/> | ||||
|       <children xsi:type="menu:HandledToolItem" xmi:id="_H7bp8HcjEeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.handledtoolitem.nexttransaction" label="Next Transaction" iconURI="platform:/plugin/com.minres.scviewer.e4.application/icons/play_green.png" tooltip="Navigate to next transaction" command="_Gn3lEHXKEeWwZ-9vrAR2UQ"> | ||||
|         <parameters xmi:id="_fiO8IHcjEeWwZ-9vrAR2UQ" elementId="com.minres.scviewer.e4.application.parameter.13" name="com.minres.scviewer.e4.application.command.navigateTransCommand.parameter.dir" value="next"/> | ||||
|       </children> | ||||
|       <children xsi:type="menu:ToolBarSeparator" xmi:id="_dOLmYE-DEeyuGJbYVZjX8w" elementId="com.minres.scviewer.e4.application.toolbarseparator.0"/> | ||||
|       <children xsi:type="menu:HandledToolItem" xmi:id="_dPFBcE-HEeyuGJbYVZjX8w" elementId="com.minres.scviewer.e4.application.handledtoolitem.panleft" label="Pan left" iconURI="platform:/plugin/com.minres.scviewer.e4.application/icons/reverse_blue.png" tooltip="Pan left" command="_y2BUsE-HEeyuGJbYVZjX8w"> | ||||
|         <parameters xmi:id="_jkVBYE-JEeyuGJbYVZjX8w" elementId="com.minres.scviewer.e4.application.parameter.14" name="com.minres.scviewer.e4.application.command.pancommand.parameter.direction" value="left"/> | ||||
|       </children> | ||||
|       <children xsi:type="menu:HandledToolItem" xmi:id="_Z-blgE-GEeyuGJbYVZjX8w" elementId="com.minres.scviewer.e4.application.handledtoolitem.pancursor" label="Pan to cursor" iconURI="platform:/plugin/com.minres.scviewer.e4.application/icons/center_blue.png" tooltip="Center on cursor" command="_y2BUsE-HEeyuGJbYVZjX8w"> | ||||
|         <parameters xmi:id="_Z-blgU-GEeyuGJbYVZjX8w" elementId="com.minres.scviewer.e4.application.parameter.out" name="com.minres.scviewer.e4.application.command.pancommand.parameter.direction" value="cursor"/> | ||||
|       </children> | ||||
|       <children xsi:type="menu:HandledToolItem" xmi:id="_ejt5IE-HEeyuGJbYVZjX8w" elementId="com.minres.scviewer.e4.application.handledtoolitem.panright" label="Pan right" iconURI="platform:/plugin/com.minres.scviewer.e4.application/icons/play_blue.png" tooltip="Pan right" command="_y2BUsE-HEeyuGJbYVZjX8w"> | ||||
|         <parameters xmi:id="_f4awUE-JEeyuGJbYVZjX8w" elementId="com.minres.scviewer.e4.application.parameter.out" name="com.minres.scviewer.e4.application.command.pancommand.parameter.direction" value="right"/> | ||||
|       </children> | ||||
|       <children xsi:type="menu:ToolBarSeparator" xmi:id="_b7RFoE-GEeyuGJbYVZjX8w" elementId="com.minres.scviewer.e4.application.toolbarseparator.1"/> | ||||
|       <children xsi:type="menu:HandledToolItem" xmi:id="_qA5D4E-DEeyuGJbYVZjX8w" elementId="com.minres.scviewer.e4.application.handledtoolitem.zoomfull" label="Zoom full" iconURI="platform:/plugin/com.minres.scviewer.e4.application/icons/zoom_full.png" tooltip="Zoom full range" command="_693GoHcqEeWwZ-9vrAR2UQ"> | ||||
|         <parameters xmi:id="_qA5D4U-DEeyuGJbYVZjX8w" elementId="com.minres.scviewer.e4.application.parameter.full" name="com.minres.scviewer.e4.application.command.zoomcommand.parameter.level" value="full"/> | ||||
|       </children> | ||||
|       <children xsi:type="menu:HandledToolItem" xmi:id="_qA65EE-DEeyuGJbYVZjX8w" elementId="com.minres.scviewer.e4.application.handledtoolitem.zoomfit" label="Zoom fit" iconURI="platform:/plugin/com.minres.scviewer.e4.application/icons/zoom_fit.png" tooltip="Zoom between cursor and marker" command="_693GoHcqEeWwZ-9vrAR2UQ"> | ||||
|         <parameters xmi:id="_qA65EU-DEeyuGJbYVZjX8w" elementId="com.minres.scviewer.e4.application.parameter.fit" name="com.minres.scviewer.e4.application.command.zoomcommand.parameter.level" value="fit"/> | ||||
|       </children> | ||||
|       <children xsi:type="menu:ToolBarSeparator" xmi:id="_qA8HME-DEeyuGJbYVZjX8w" elementId="com.minres.scviewer.e4.application.toolbarseparator.1"/> | ||||
|       <children xsi:type="menu:HandledToolItem" xmi:id="_qA8uQE-DEeyuGJbYVZjX8w" elementId="com.minres.scviewer.e4.application.handledtoolitem.zoomin" label="Zoom in" iconURI="platform:/plugin/com.minres.scviewer.e4.application/icons/magnifier_zoom_in.png" tooltip="Zoom in" command="_693GoHcqEeWwZ-9vrAR2UQ"> | ||||
|         <parameters xmi:id="_qA8uQU-DEeyuGJbYVZjX8w" elementId="com.minres.scviewer.e4.application.parameter.in" name="com.minres.scviewer.e4.application.command.zoomcommand.parameter.level" value="in"/> | ||||
|       </children> | ||||
|       <children xsi:type="menu:HandledToolItem" xmi:id="_qA98YE-DEeyuGJbYVZjX8w" elementId="com.minres.scviewer.e4.application.handledtoolitem.zoomout" label="Zoom out" iconURI="platform:/plugin/com.minres.scviewer.e4.application/icons/magifier_zoom_out.png" tooltip="Zoom out" command="_693GoHcqEeWwZ-9vrAR2UQ"> | ||||
|         <parameters xmi:id="_qA98YU-DEeyuGJbYVZjX8w" elementId="com.minres.scviewer.e4.application.parameter.out" name="com.minres.scviewer.e4.application.command.zoomcommand.parameter.level" value="out"/> | ||||
|       </children> | ||||
|     </toolbar> | ||||
|   </descriptors> | ||||
|   <snippets xsi:type="basic:Window" xmi:id="_R8mJUEhwEeyp3vLifEzGbQ" elementId="com.minres.scviewer.e4.application.window.help" selectedElement="_R8mJUUhwEeyp3vLifEzGbQ" label="SC Viewer Help" width="800" height="600"> | ||||
|     <children xsi:type="basic:Part" xmi:id="_R8mJUUhwEeyp3vLifEzGbQ" elementId="com.minres.scviewer.e4.application.part.container" contributionURI="bundleclass://com.minres.scviewer.e4.application/com.minres.scviewer.e4.application.parts.help.HelpBrowser"/> | ||||
|   </snippets> | ||||
|   <commands xmi:id="_95PfvHNmEeWBq8z1Dv39LA" elementId="org.eclipse.ui.file.exit" commandName="Quit Command"/> | ||||
|   <commands xmi:id="_95PfwHNmEeWBq8z1Dv39LA" elementId="com.minres.scviewer.e4.application.open" commandName="Open Command"/> | ||||
|   <commands xmi:id="_95Pfw3NmEeWBq8z1Dv39LA" elementId="org.eclipse.ui.file.save" commandName="Save Command"/> | ||||
| @@ -280,6 +293,11 @@ | ||||
|   <commands xmi:id="_srACsBkREeudD5MqrWoETQ" elementId="com.minres.scviewer.e4.application.reload" commandName="Reload Command"/> | ||||
|   <commands xmi:id="_XDxTYBlEEeuiP60JNw0iiA" elementId="com.minres.scviewer.e4.application.txSearch" commandName="Search Command"/> | ||||
|   <commands xmi:id="_-9ED4B06EeuiP60JNw0iiA" elementId="com.minres.scviewer.e4.application.command.update" commandName="Update"/> | ||||
|   <commands xmi:id="_lqjIYEYEEeyPM8G0E2EYww" elementId="org.eclipse.ui.help.helpAction" commandName="Help Command"/> | ||||
|   <commands xmi:id="_Fj1gQEYoEeyKK_icsY7Xjg" elementId="com.minres.scviewer.e4.application.command.enabletxdetails" commandName="Enable Tx Details" description="Show tx details parts"/> | ||||
|   <commands xmi:id="_y2BUsE-HEeyuGJbYVZjX8w" elementId="com.minres.scviewer.e4.application.command.pancommand" commandName="Pan Command"> | ||||
|     <parameters xmi:id="_y2BUsU-HEeyuGJbYVZjX8w" elementId="com.minres.scviewer.e4.application.command.pancommand.parameter.direction" name="direction" optional="false"/> | ||||
|   </commands> | ||||
|   <addons xmi:id="_95PfsnNmEeWBq8z1Dv39LA" elementId="org.eclipse.e4.core.commands.service" contributionURI="bundleclass://org.eclipse.e4.core.commands/org.eclipse.e4.core.commands.CommandServiceAddon"/> | ||||
|   <addons xmi:id="_95Pfs3NmEeWBq8z1Dv39LA" elementId="org.eclipse.e4.ui.contexts.service" contributionURI="bundleclass://org.eclipse.e4.ui.services/org.eclipse.e4.ui.services.ContextServiceAddon"/> | ||||
|   <addons xmi:id="_95PftHNmEeWBq8z1Dv39LA" elementId="org.eclipse.e4.ui.bindings.service" contributionURI="bundleclass://org.eclipse.e4.ui.bindings/org.eclipse.e4.ui.bindings.BindingServiceAddon"/> | ||||
|   | ||||
| @@ -2,7 +2,7 @@ Manifest-Version: 1.0 | ||||
| Bundle-ManifestVersion: 2 | ||||
| Bundle-Name: %Bundle-Name | ||||
| Bundle-SymbolicName: com.minres.scviewer.e4.application;singleton:=true | ||||
| Bundle-Version: 2.13.0 | ||||
| Bundle-Version: 2.15.1 | ||||
| Bundle-Vendor: %Bundle-Vendor | ||||
| Require-Bundle: javax.inject;bundle-version="1.0.0", | ||||
|  org.eclipse.core.runtime;bundle-version="3.11.1", | ||||
| @@ -38,5 +38,6 @@ Require-Bundle: javax.inject;bundle-version="1.0.0", | ||||
|  org.eclipse.equinox.p2.metadata.repository;bundle-version="1.3.400" | ||||
| Bundle-RequiredExecutionEnvironment: JavaSE-11 | ||||
| Import-Package: com.minres.scviewer.database, | ||||
|  javax.annotation;version="1.0.0";resolution:=optional, | ||||
|  javax.inject;version="1.0.0" | ||||
| Automatic-Module-Name: com.minres.scviewer.e4.application | ||||
|   | ||||
							
								
								
									
										
											BIN
										
									
								
								plugins/com.minres.scviewer.e4.application/icons/accept.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 781 B | 
| After Width: | Height: | Size: 547 B | 
| After Width: | Height: | Size: 581 B | 
							
								
								
									
										
											BIN
										
									
								
								plugins/com.minres.scviewer.e4.application/icons/arrow_redo.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 625 B | 
| After Width: | Height: | Size: 685 B | 
							
								
								
									
										
											BIN
										
									
								
								plugins/com.minres.scviewer.e4.application/icons/arrow_undo.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 631 B | 
							
								
								
									
										
											BIN
										
									
								
								plugins/com.minres.scviewer.e4.application/icons/center_blue.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 600 B | 
							
								
								
									
										
											BIN
										
									
								
								plugins/com.minres.scviewer.e4.application/icons/next-green.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 519 B | 
| After Width: | Height: | Size: 524 B | 
							
								
								
									
										
											BIN
										
									
								
								plugins/com.minres.scviewer.e4.application/icons/zoom_fit.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 6.0 KiB | 
							
								
								
									
										
											BIN
										
									
								
								plugins/com.minres.scviewer.e4.application/icons/zoom_full.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 6.2 KiB | 
| @@ -6,8 +6,8 @@ | ||||
| 	<parent> | ||||
| 		<groupId>com.minres.scviewer</groupId> | ||||
| 		<artifactId>com.minres.scviewer.parent</artifactId> | ||||
| 		<version>2.13.0</version> | ||||
| 		<version>2.15.1</version> | ||||
| 		<relativePath>../..</relativePath> | ||||
| 	</parent> | ||||
| 	<packaging>eclipse-plugin</packaging> | ||||
| </project> | ||||
| </project> | ||||
|   | ||||
| @@ -24,6 +24,7 @@ public class Messages extends NLS { | ||||
| 	public static String SCViewerPreferencesPage_0; | ||||
| 	public static String SCViewerPreferencesPage_1; | ||||
| 	public static String SCViewerPreferencesPage_2; | ||||
| 	public static String SCViewerPreferencesPage_3; | ||||
| 	public static String StatusBarControl_1; | ||||
| 	public static String StatusBarControl_2; | ||||
| 	public static String StatusBarControl_3; | ||||
| @@ -82,6 +83,16 @@ public class Messages extends NLS { | ||||
| 	public static String cursor; | ||||
| 	public static String cursor_drag; | ||||
| 	public static String cursor_text; | ||||
| 	public static String HelpBrowser_7; | ||||
| 	public static String HelpBrowser_8; | ||||
| 	public static String HelpDialog_0; | ||||
| 	public static String HelpDialog_1; | ||||
| 	public static String HelpDialog_2; | ||||
| 	public static String HelpDialog_3; | ||||
| 	public static String HelpDialog_4; | ||||
| 	public static String HelpDialog_5; | ||||
| 	public static String HelpDialog_6; | ||||
| 	public static String HelpDialog_7; | ||||
| 	public static String marker; | ||||
| 	public static String marker_text; | ||||
| 	public static String rel_arrow; | ||||
|   | ||||
| @@ -0,0 +1,57 @@ | ||||
|  | ||||
| package com.minres.scviewer.e4.application.handlers; | ||||
|  | ||||
| import java.util.LinkedList; | ||||
| import java.util.List; | ||||
|  | ||||
| import javax.inject.Inject; | ||||
|  | ||||
| import org.eclipse.core.runtime.preferences.IEclipsePreferences; | ||||
| import org.eclipse.e4.core.di.annotations.Execute; | ||||
| import org.eclipse.e4.core.di.annotations.Optional; | ||||
| import org.eclipse.e4.core.di.extensions.Preference; | ||||
| import org.eclipse.e4.ui.model.application.MApplication; | ||||
| import org.eclipse.e4.ui.model.application.ui.menu.MHandledItem; | ||||
| import org.eclipse.e4.ui.workbench.modeling.EModelService; | ||||
| import org.eclipse.e4.ui.workbench.modeling.EPartService; | ||||
| import org.osgi.service.prefs.BackingStoreException; | ||||
|  | ||||
| import com.minres.scviewer.e4.application.preferences.PreferenceConstants; | ||||
|  | ||||
| @SuppressWarnings("restriction") | ||||
| public class EnableTxDetails { | ||||
| 	static final String TAG_NAME = "EnableTxDetails"; //$NON-NLS-1$ | ||||
|  | ||||
| 	static final String ICON_DISABLED = "platform:/plugin/com.minres.scviewer.e4.application/icons/application_side_expand.png"; //$NON-NLS-1$ | ||||
| 	static final String ICON_ENABLED = "platform:/plugin/com.minres.scviewer.e4.application/icons/application_side_contract.png"; //$NON-NLS-1$ | ||||
| 	static final String TOOLTIP_DISABLED = "Show tx details parts"; | ||||
| 	static final String TOOLTIP_ENABLED = "Hide tx details parts"; | ||||
| 	 | ||||
| 	@Inject | ||||
| 	MApplication application; | ||||
|  | ||||
| 	@Inject | ||||
| 	EPartService partService; | ||||
|  | ||||
| 	@Inject | ||||
| 	@Optional | ||||
| 	public void reactOnShowHoverChange(EModelService modelService, @Preference(value = PreferenceConstants.SHOW_TX_DETAILS) Boolean show) { | ||||
| 		List<String> tags = new LinkedList<>(); | ||||
| 		tags.add(TAG_NAME); | ||||
| 		List<MHandledItem> elements = modelService.findElements(application, null, MHandledItem.class, tags ); | ||||
| 		for( MHandledItem hi : elements ){ | ||||
| 			hi.setSelected(show); | ||||
| 			hi.setIconURI(show?ICON_ENABLED:ICON_DISABLED); | ||||
| 			hi.setTooltip(show?TOOLTIP_ENABLED:TOOLTIP_DISABLED); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	@Execute | ||||
| 	public void execute(MHandledItem handledItem, @Preference(nodePath = PreferenceConstants.PREFERENCES_SCOPE) IEclipsePreferences prefs ) { | ||||
| 		try { | ||||
| 			prefs.putBoolean(PreferenceConstants.SHOW_TX_DETAILS, handledItem.isSelected()); | ||||
| 			prefs.flush(); | ||||
| 		} catch (BackingStoreException e) {} | ||||
| 	} | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,33 @@ | ||||
| /******************************************************************************* | ||||
|  * Copyright (c) 2015-2021 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.handlers; | ||||
|  | ||||
| import org.eclipse.e4.core.di.annotations.CanExecute; | ||||
| 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.MWindow; | ||||
| import org.eclipse.e4.ui.workbench.modeling.EModelService; | ||||
|  | ||||
| public class HelpHandler { | ||||
|  | ||||
| 	static final String WINDOW_ID="com.minres.scviewer.e4.application.window.help"; //$NON-NLS-1$ | ||||
| 	@CanExecute | ||||
| 	public boolean canExecute(MApplication app) { | ||||
| 		return !app.getChildren().stream().filter(e -> e.getElementId().equals(WINDOW_ID)).findFirst().isPresent(); | ||||
| 	} | ||||
| 	 | ||||
| 	@Execute | ||||
| 	public void execute(MApplication app, MWindow window, EModelService modelService /*@Named("mdialog01.dialog.0") MDialog dialog*/) { | ||||
| 		MWindow newWin = (MWindow)modelService.cloneSnippet(app, WINDOW_ID, null); | ||||
| 		app.getChildren().add(newWin); | ||||
| 	} | ||||
|  | ||||
| } | ||||
| @@ -17,7 +17,6 @@ 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 org.eclipse.jface.viewers.IStructuredSelection; | ||||
|  | ||||
| import com.minres.scviewer.database.IWaveform; | ||||
| @@ -29,21 +28,25 @@ import com.minres.scviewer.e4.application.parts.WaveformViewer; | ||||
| public class NavigateEvent { | ||||
|  | ||||
| 	final static String PARAMTER_ID="com.minres.scviewer.e4.application.command.navigateEventCommand.parameter.dir"; //$NON-NLS-1$ | ||||
| 	 | ||||
|  | ||||
| 	@CanExecute | ||||
| 	public Boolean canExecute(ESelectionService selectionService){ | ||||
| 		Object sel = selectionService.getSelection(); | ||||
| 		if( sel instanceof IStructuredSelection) { | ||||
| 			Object o= ((IStructuredSelection)sel).getFirstElement(); | ||||
| 			return o instanceof IWaveform || o instanceof ITx || o instanceof TrackEntry; | ||||
| 	public Boolean canExecute(EPartService partService){ | ||||
| 		MPart part = partService.getActivePart(); | ||||
| 		if(part.getObject() instanceof WaveformViewer){ | ||||
| 			Object sel = ((WaveformViewer)part.getObject()).getSelection(); | ||||
| 			if( sel instanceof IStructuredSelection) { | ||||
| 				if(((IStructuredSelection)sel).isEmpty()) return false; | ||||
| 				Object o= ((IStructuredSelection)sel).getFirstElement(); | ||||
| 				return o instanceof IWaveform || o instanceof ITx || o instanceof TrackEntry; | ||||
| 			} | ||||
| 		} | ||||
| 		return false; | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	@Execute | ||||
| 	public void execute(@Named(PARAMTER_ID) String param, EPartService partService) { | ||||
| //	public void execute(EPartService partService) { | ||||
| //		String param="next"; | ||||
| 		//	public void execute(EPartService partService) { | ||||
| 		//		String param="next"; | ||||
| 		MPart part = partService.getActivePart(); | ||||
| 		Object obj = part.getObject(); | ||||
| 		if(obj instanceof WaveformViewer){ | ||||
|   | ||||