View Javadoc

1   /* Open Log Viewer
2    *
3    * Copyright 2011
4    *
5    * This file is part of the OpenLogViewer project.
6    *
7    * OpenLogViewer software is free software: you can redistribute it and/or modify
8    * it under the terms of the GNU General Public License as published by
9    * the Free Software Foundation, either version 3 of the License, or
10   * (at your option) any later version.
11   *
12   * OpenLogViewer software is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   * GNU General Public License for more details.
16   *
17   * You should have received a copy of the GNU General Public License
18   * along with any OpenLogViewer software.  If not, see http://www.gnu.org/licenses/
19   *
20   * I ask that if you make any changes to this file you fork the code on github.com!
21   *
22   */
23  package org.diyefi.openlogviewer.genericlog;
24  
25  import java.awt.Color;
26  import java.awt.datatransfer.DataFlavor;
27  import java.awt.datatransfer.Transferable;
28  import java.awt.datatransfer.UnsupportedFlavorException;
29  import java.beans.PropertyChangeListener;
30  import java.beans.PropertyChangeSupport;
31  import java.io.IOException;
32  import java.io.Serializable;
33  import java.util.Arrays;
34  
35  import org.diyefi.openlogviewer.Keys;
36  import org.diyefi.openlogviewer.coloring.InitialLineColoring;
37  
38  /**
39   * GenericDataElement is Comparable Serializable and Transferable and supports property change events
40   * it was built this way in order to be copy/pasteable later in the future
41   * when constructed this is the meat and potatoes of the program, the graphs and data
42   * displayed are pulled from these objects.
43   * @author Bryan Harris
44   */
45  public final class GenericDataElement implements Comparable<GenericDataElement>, Serializable, Transferable {
46  	private static final long serialVersionUID = 1L;
47  	private static final int NUM_DATA_FLAVORS = 3;
48  	private static final String UNSUPPORTED = "Unsupported";
49  
50  	private static int currentRecord;
51  
52  	/**
53  	 * The meat of this object! Previously in a slow fat ArrayList.
54  	 */
55  	private double[] values;
56  
57  	// These two fields belong here:
58  	private double minValue;
59  	private double maxValue;
60  	private boolean realMinAndMaxFound;
61  
62  	// These three do not - move them into some graphics object and keep the data separated from the look...
63  	private double displayMinValue;
64  	private double displayMaxValue;
65  	private Color displayColor;
66  	private boolean displayMinAndMaxSet;
67  
68  	/**
69  	 * GDE Header name
70  	 */
71  	private String name;
72  
73  	/**
74  	 * Division on the Graphing layer
75  	 */
76  	private int trackIndex;
77  	private final PropertyChangeSupport pcs;
78  	private DataFlavor[] dataFlavor;
79  
80  	/**
81  	 * Constructor brings the GDE up to speed, defaulting with an available 50,000 datapoints
82  	 * in order to reduce the number of times the Array list has to copy its contents
83  	 * in order to increase size.
84  	 */
85  	protected GenericDataElement(final int initialLength) {
86  		values = new double[initialLength];
87  
88  		pcs = new PropertyChangeSupport(this);
89  
90  		maxValue = -Double.MAX_VALUE;
91  		minValue = Double.MAX_VALUE;
92  
93  		trackIndex = 0;
94  		addFlavors();
95  	}
96  
97  	protected void increaseCapacity(final int ourLoadFactor) {
98  		values = Arrays.copyOf(values, (values.length * ourLoadFactor));
99  	}
100 
101 	protected static void incrementPosition() {
102 		currentRecord++;
103 	}
104 	protected static void resetPosition() {
105 		currentRecord = -1;
106 	}
107 
108 	/**
109 	 * Data type support for Transferable
110 	 */
111 	private void addFlavors() {
112 		dataFlavor = new DataFlavor[NUM_DATA_FLAVORS];
113 		final String supportedFlavour = DataFlavor.javaSerializedObjectMimeType + ";class=\"" + GenericDataElement.class.getName() + "\"";
114 		dataFlavor[0] = new DataFlavor(supportedFlavour, "OLV GenericDataElement");
115 		dataFlavor[1] = DataFlavor.stringFlavor;
116 		dataFlavor[2] = DataFlavor.getTextPlainUnicodeFlavor();
117 	}
118 
119 	/**
120 	 * override add(<T> t) of ArrayList to find min and max values before adding to the List
121 	 * @param value value to add to the array
122 	 */
123 	public void add(final double value) { //  TODO simplify the shit out of this, and/or remove it.
124 		values[currentRecord] = value;
125 	}
126 
127 	// TODO maybe make these a direct reference to the array for efficiency sake, and above ^
128 	public double get(final int index) {
129 		return values[index];
130 	}
131 	public int size() { // TODO ^
132 		return currentRecord; // was values.length; array length is longer than data in it.
133 	}
134 
135 	/**
136 	 * sets the splitNumber or division of the graph in the graphing screen and
137 	 * fires a property change event for other code to catch.
138 	 *
139 	 * @param newIndex
140 	 */
141 	public void setTrackIndex(final int newIndex) {
142 		final int oldIndex = trackIndex;
143 		trackIndex = newIndex;
144 		pcs.firePropertyChange(Keys.SPLIT, oldIndex, trackIndex);
145 	}
146 
147 	/**
148 	 * TODO move this into GUI space and out of this class!!
149 	 */
150 	public void reset() {
151 		displayMinValue = getMinValue();
152 		displayMaxValue = getMaxValue();
153 	}
154 
155 	public void addPropertyChangeListener(final String property, final PropertyChangeListener pcl) {
156 		pcs.addPropertyChangeListener(property, pcl);
157 	}
158 
159 	public void removePropertyChangeListener(final String property, final PropertyChangeListener pcl) {
160 		pcs.removePropertyChangeListener(property, pcl);
161 	}
162 
163 	@Override
164 	public String toString() {
165 		return this.name;
166 	}
167 
168 	@Override
169 	public int compareTo(final GenericDataElement otherGDE) {
170 		return this.getName().compareToIgnoreCase(otherGDE.getName());
171 	}
172 
173 	@Override
174 	public Object getTransferData(final DataFlavor flavor) throws UnsupportedFlavorException, IOException {
175 		if (flavor.equals(dataFlavor[0])) {
176 			return this;
177 		} else if (flavor.equals(dataFlavor[1])) {
178 			return UNSUPPORTED;
179 		} else if (flavor.equals(dataFlavor[2])) {
180 			return UNSUPPORTED;
181 		} else {
182 			throw new UnsupportedFlavorException(flavor);
183 		}
184 	}
185 
186 	@Override
187 	public DataFlavor[] getTransferDataFlavors() {
188 		return dataFlavor.clone();
189 	}
190 
191 	@Override
192 	public boolean isDataFlavorSupported(final DataFlavor flavor) {
193 		for (int i = 0; i < dataFlavor.length; i++) {
194 			if (flavor.equals(dataFlavor[i])) {
195 				return true;
196 			}
197 		}
198 		return false;
199 	}
200 
201 	/**
202 	 * set header name, called during GenericLog construction
203 	 * @param name
204 	 */
205 	public void setName(final String name) {
206 		this.name = name;
207 	}
208 	public String getName() {
209 		return name;
210 	}
211 
212 	public double getMaxValue() {
213 		findMinAndMaxValues();
214 		return maxValue;
215 	}
216 	public double getMinValue() {
217 		findMinAndMaxValues();
218 		return minValue;
219 	}
220 
221 	private void findMinAndMaxValues() {
222 		if (!realMinAndMaxFound) {
223 			for (int i = 0; i <= currentRecord; i++) {
224 				final double value = values[i];
225 				if (maxValue < value) {
226 					maxValue = value;
227 				}
228 				if (minValue > value) {
229 					minValue = value;
230 				}
231 			}
232 			// System.out.println("MinMaxFor: " + this.name); // Used to check for option pane running this code inappropriately...
233 
234 			realMinAndMaxFound = true;
235 		}
236 	}
237 
238 	public double getDisplayMinValue() {
239 		setDisplayMinAndMaxDefaultsIfRequired();
240 		return displayMinValue;
241 	}
242 	public double getDisplayMaxValue() {
243 		setDisplayMinAndMaxDefaultsIfRequired();
244 		return displayMaxValue;
245 	}
246 	private void setDisplayMinAndMaxDefaultsIfRequired() {
247 		if (!displayMinAndMaxSet) {
248 			displayMinValue = getMinValue();
249 			displayMaxValue = getMaxValue();
250 			displayMinAndMaxSet = true;
251 		}
252 	}
253 
254 	public void setDisplayMaxValue(final double highValue) {
255 		if (!displayMinAndMaxSet) {
256 			displayMinValue = getMinValue();
257 			displayMinAndMaxSet = true;
258 		}
259 		this.displayMaxValue = highValue;
260 	}
261 	public void setDisplayMinValue(final double lowValue) {
262 		if (!displayMinAndMaxSet) {
263 			displayMaxValue = getMaxValue();
264 			displayMinAndMaxSet = true;
265 		}
266 		this.displayMinValue = lowValue;
267 	}
268 
269 	public Color getDisplayColor() {
270 		if (displayColor == null) {
271 			displayColor = InitialLineColoring.INSTANCE.getBestAvailableColor();
272 		}
273 		return displayColor;
274 	}
275 	public void setDisplayColor(final Color c) {
276 		if (c == null) {
277 			InitialLineColoring.INSTANCE.giveBackColor(displayColor);
278 		}
279 		displayColor = c;
280 	}
281 	public int getTrackIndex() {
282 		return trackIndex;
283 	}
284 
285 	public void clearOut() {
286 		values = null;
287 	}
288 }