001 package org.LiveGraph.settings;
002
003 import static org.LiveGraph.settings.SettingsEvent.*;
004
005 import java.awt.Color;
006 import java.io.FileInputStream;
007 import java.io.FileOutputStream;
008 import java.io.IOException;
009 import java.util.Properties;
010
011 import org.LiveGraph.LiveGraph;
012 import org.LiveGraph.events.Event;
013
014 import com.softnetConsult.utils.math.MathTools;
015 import com.softnetConsult.utils.string.StringTools;
016
017 /**
018 * Encapsulates settings concerned with the data graphs and the plot canvas.
019 *
020 * <p style="font-size:smaller;">This product includes software developed by the
021 * <strong>LiveGraph</strong> project and its contributors.<br />
022 * (<a href="http://www.live-graph.org" target="_blank">http://www.live-graph.org</a>)<br />
023 * Copyright (c) 2007-2008 G. Paperin.<br />
024 * All rights reserved.
025 * </p>
026 * <p style="font-size:smaller;">File: GraphSettings.java</p>
027 * <p style="font-size:smaller;">Redistribution and use in source and binary forms, with or
028 * without modification, are permitted provided that the following terms and conditions are met:
029 * </p>
030 * <p style="font-size:smaller;">1. Redistributions of source code must retain the above
031 * acknowledgement of the LiveGraph project and its web-site, the above copyright notice,
032 * this list of conditions and the following disclaimer.<br />
033 * 2. Redistributions in binary form must reproduce the above acknowledgement of the
034 * LiveGraph project and its web-site, the above copyright notice, this list of conditions
035 * and the following disclaimer in the documentation and/or other materials provided with
036 * the distribution.<br />
037 * 3. All advertising materials mentioning features or use of this software or any derived
038 * software must display the following acknowledgement:<br />
039 * <em>This product includes software developed by the LiveGraph project and its
040 * contributors.<br />(http://www.live-graph.org)</em><br />
041 * 4. All advertising materials distributed in form of HTML pages or any other technology
042 * permitting active hyper-links that mention features or use of this software or any
043 * derived software must display the acknowledgment specified in condition 3 of this
044 * agreement, and in addition, include a visible and working hyper-link to the LiveGraph
045 * homepage (http://www.live-graph.org).
046 * </p>
047 * <p style="font-size:smaller;">THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY
048 * OF ANY KIND, EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
049 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
050 * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
051 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
052 * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
053 * </p>
054 *
055 * @author Greg Paperin (<a href="http://www.paperin.org" target="_blank">http://www.paperin.org</a>)
056 * @version {@value org.LiveGraph.LiveGraph#version}
057 */
058 public class GraphSettings extends ObservableSettings {
059
060 /**
061 * Standard file extension.
062 */
063 public static final String preferredFileExtension = ".lggs";
064
065 /**
066 * Possible types for the vertical grid.
067 */
068 public static enum VGridType {
069 /**
070 * No vertical grid.
071 */
072 VGrid_None,
073
074 /**
075 * Vertical grid is based on dataset indices.
076 */
077 VGrid_DSNumAligned,
078
079 /**
080 * Vertical grid is based on X data values.
081 */
082 VGrid_XAUnitAligned
083 };
084
085 /**
086 * Possible types for the horizontal grid.
087 */
088 public static enum HGridType {
089 /**
090 * No horisontal grid.
091 */
092 HGrid_None,
093
094 /**
095 * Horisontal grid is based on Y data values.
096 */
097 HGrid_Simple
098 };
099
100 /**
101 * Possible types for the x-axis.
102 */
103 public static enum XAxisType {
104 /**
105 * Use dataset numbers as x-axis units.
106 */
107 XAxis_DSNum,
108
109 /**
110 * Plot against a specified data series
111 * (use the values of a specified data series as x-axis values).
112 */
113 XAxis_DataValSimple,
114
115 /**
116 * Plot against a specified data series transformed into the unit interval
117 * (use the values of a specified data series linearly transformed into the
118 * interval [0..1] as x-axis values).
119 */
120 XAxis_DataValTrans0to1,
121
122 /**
123 * Plot against a specified data series scaled by a specified constant
124 * (use the values of a specified data series multiplied by a specified value as x-axis values).
125 */
126 XAxis_DataValScaleBySetVal,
127
128 /**
129 * Plot against the logarithm of a specified data series to a specified base
130 * (use the values of logarithms of a specified data series taken to a specified base as x-axis values).
131 */
132 XAxis_DataValLogToSetBase,
133
134 /**
135 * Plot against time
136 * (assume that the values of a specified data series represent seconds taken to a specified power
137 * of 10 (e.g. if {@code -3} is specified, the values represent milliseconds); plot against
138 * that axis while appropriately formatting the time (e.g. {@code hhh:mm:ss.xxx}).
139 */
140 XAxis_DataValSecsToSetPower
141 };
142
143
144 /**
145 * Bottom edge of the visible data area.
146 * Default value: {@code Double.NaN} ({@code Auto}).
147 */
148 private double minY = Double.NaN;
149
150 /**
151 * Top edge of the visible data area.
152 * Default value: {@code Double.NaN} ({@code Auto}).
153 */
154 private double maxY = Double.NaN;
155
156 /**
157 * Left edge of the visible data area.
158 * Default value: {@code Double.NaN} ({@code Auto}).
159 */
160 private double minX = Double.NaN;
161
162 /**
163 * Right edge of the visible data area.
164 * Default value: {@code Double.NaN} ({@code Auto}).
165 */
166 private double maxX = Double.NaN;
167
168 /**
169 * Type of the vertical grid.
170 * Default value: {@code VGridType.VGrid_None}.
171 */
172 private VGridType vGridType = VGridType.VGrid_None;
173
174 /**
175 * Spacing of the vertical grid in data coordinates.
176 * Default value: {@code 50}.
177 */
178 private double vGridSize = 50.0;
179
180 /**
181 * Color of the vertical grid.
182 * Default value: {@code #C0C0C0}.
183 */
184 private Color vGridColour = new Color(Integer.parseInt("C0", 16),
185 Integer.parseInt("C0", 16),
186 Integer.parseInt("C0", 16));
187
188 /**
189 * Type of the horisontal grid.
190 * Default value: {@code HGridType.HGrid_None}.
191 */
192 private HGridType hGridType = HGridType.HGrid_None;
193
194 /**
195 * Spacing of the horisontal grid in data coordinates.
196 * Default value: {@code 50}.
197 */
198 private double hGridSize = 50.0;
199
200 /**
201 * Color of the horisontal grid.
202 * Default value: {@code #C0C0C0}.
203 */
204 private Color hGridColour = new Color(Integer.parseInt("C0", 16),
205 Integer.parseInt("C0", 16),
206 Integer.parseInt("C0", 16));
207
208 /**
209 * Against what to plot the values.
210 * Default value: {@code XAxisType.XAxis_DSNum}.
211 */
212 private XAxisType xAxisType = XAxisType.XAxis_DSNum;
213
214 /**
215 * Against which data series to plot (index).
216 * Default value: {@code 0}.
217 */
218 private int xAxisSeriesIndex = 0;
219
220 /**
221 * Parameter for transformation of x-values.
222 * Default value: {@code 1}.
223 */
224 private double xAxisParamValue = 1.0;
225
226 /**
227 * Whether to highlight data points as mouse is moved over the graph.
228 * Default value: {@code true}.
229 */
230 private boolean highlightDataPoints = true;
231
232
233 /**
234 * Creates a new graph settings object with the default settings.
235 */
236 public GraphSettings() {
237 super();
238 checkDisableHighlightingForOldJava();
239 }
240
241 /**
242 * Creates a new graph settings object and loads the settings from the specified file.
243 *
244 * @param fileName File to load the settigs from.
245 */
246 public GraphSettings(String fileName) {
247 this();
248 load(fileName);
249 }
250
251 /**
252 * Loads the settings from the specified file.
253 *
254 * @param fileName File to load the settigs from.
255 * @return {@code true} if the settings were loaded, {@code false} if an exception occured.
256 */
257 public boolean load(String fileName) {
258
259 // Check observers:
260 Event<? extends SettingsEvent> actionEvent = checkObservers(GS_Load, fileName);
261 if (null == actionEvent)
262 return false;
263
264 // Used for loading:
265 Properties values = new Properties();
266
267 // Read from file:
268 try {
269 FileInputStream in = new FileInputStream(fileName);
270 try {
271 values.loadFromXML(in);
272 } finally {
273 in.close();
274 }
275 } catch(IOException e) {
276 e.printStackTrace();
277 return false;
278 }
279
280 // Parse values and set:
281
282 String s = values.getProperty("MinY", "Auto");
283 if ("Auto".equalsIgnoreCase(s)) {
284 minY = Double.NaN;
285 } else {
286 try {
287 minY = StringTools.parseDouble(s);
288 } catch (NumberFormatException e) {
289 minY = Double.parseDouble(s);
290 }
291 }
292
293
294 s = values.getProperty("MaxY", "Auto");
295 if ("Auto".equalsIgnoreCase(s)) {
296 maxY = Double.NaN;
297 } else {
298 try {
299 maxY = StringTools.parseDouble(s);
300 } catch (NumberFormatException e) {
301 maxY = Double.parseDouble(s);
302 }
303 }
304
305
306 s = values.getProperty("MinX", "Auto");
307 if ("Auto".equalsIgnoreCase(s)) {
308 minX = Double.NaN;
309 } else {
310 try {
311 minX = StringTools.parseDouble(s);
312 } catch (NumberFormatException e) {
313 minX = Double.parseDouble(s);
314 }
315 }
316
317
318 s = values.getProperty("MaxX", "Auto");
319 if ("Auto".equalsIgnoreCase(s)) {
320 maxX = Double.NaN;
321 } else {
322 try {
323 maxX = StringTools.parseDouble(s);
324 } catch (NumberFormatException e) {
325 maxX = Double.parseDouble(s);
326 }
327 }
328
329
330 s = values.getProperty("VGridType", "VGrid_None");
331 vGridType = VGridType.VGrid_None;
332 for (VGridType t : VGridType.values()) {
333 if (t.name().equalsIgnoreCase(s)) {
334 vGridType = t;
335 break;
336 }
337 }
338
339
340 s = values.getProperty("VGridSize", "50");
341 try {
342 vGridSize = StringTools.parseDouble(s);
343 } catch (NumberFormatException e) {
344 vGridSize = Double.parseDouble(s);
345 }
346 if (Double.isNaN(vGridSize) || Double.isInfinite(vGridSize) || 0.0 > vGridSize)
347 vGridSize = 0.0;
348
349
350 s = values.getProperty("VGridColour", "C0C0C0");
351 int r, g, b;
352 try { r = Integer.parseInt(s.substring(0, 2), 16); } catch(NumberFormatException e) { r = 0; }
353 try { g = Integer.parseInt(s.substring(2, 4), 16); } catch(NumberFormatException e) { g = 0; }
354 try { b = Integer.parseInt(s.substring(4, 6), 16); } catch(NumberFormatException e) { b = 0; }
355 vGridColour = new Color(r, g, b);
356
357
358 s = values.getProperty("HGridType", "HGrid_None");
359 hGridType = HGridType.HGrid_None;
360 for (HGridType t : HGridType.values()) {
361 if (t.name().equalsIgnoreCase(s)) {
362 hGridType = t;
363 break;
364 }
365 }
366
367
368 s = values.getProperty("HGridSize", "50");
369 try {
370 hGridSize = StringTools.parseDouble(s);
371 } catch (NumberFormatException e) {
372 hGridSize = Double.parseDouble(s);
373 }
374 if (Double.isNaN(hGridSize) || Double.isInfinite(hGridSize) || 0.0 > hGridSize)
375 hGridSize = 0.0;
376
377
378 s = values.getProperty("HGridColour", "C0C0C0");
379 try { r = Integer.parseInt(s.substring(0, 2), 16); } catch(NumberFormatException e) { r = 0; }
380 try { g = Integer.parseInt(s.substring(2, 4), 16); } catch(NumberFormatException e) { g = 0; }
381 try { b = Integer.parseInt(s.substring(4, 6), 16); } catch(NumberFormatException e) { b = 0; }
382 hGridColour = new Color(r, g, b);
383
384
385 s = values.getProperty("XAxisType", "XAxis_DSNum");
386 xAxisType = XAxisType.XAxis_DSNum;
387 for (XAxisType t : XAxisType.values()) {
388 if (t.name().equalsIgnoreCase(s)) {
389 xAxisType = t;
390 break;
391 }
392 }
393 if (s.equalsIgnoreCase("XAxis_DataValScaledSet")) // Support ver 1.1.2 and prev:
394 xAxisType = XAxisType.XAxis_DataValScaleBySetVal;
395
396
397 s = values.getProperty("XAxisSeriesIndex", "0");
398 xAxisSeriesIndex = Integer.parseInt(values.getProperty("XAxisSeriesIndex"));
399 if (0 > xAxisSeriesIndex)
400 xAxisSeriesIndex = 0;
401
402
403 s = values.getProperty("XAxisParamValue");
404 if (null == s) // Compatibility with version 1.1.2 and before:
405 values.getProperty("XAxisScaleValue");
406 if (null == s)
407 s = "1";
408 try {
409 xAxisParamValue = StringTools.parseDouble(s);
410 } catch (NumberFormatException e) {
411 xAxisParamValue = Double.parseDouble(s);
412 }
413 if (Double.isNaN(xAxisParamValue) || Double.isInfinite(xAxisParamValue))
414 xAxisParamValue = 1.0;
415 xAxisParamValue = ensureGoodXAxisParameter(xAxisType, xAxisParamValue);
416
417
418 s = values.getProperty("HighlightDataPoints", "1");
419 highlightDataPoints = "1".equalsIgnoreCase(s);
420 if (values.containsKey("SavedWithIncompatibleJavaVersion")
421 && "1".equalsIgnoreCase(values.getProperty("SavedWithIncompatibleJavaVersion"))
422 && !highlightDataPoints
423 && LiveGraph.application().runsCorrectJavaVersion()) {
424 highlightDataPoints = true;
425 }
426 checkDisableHighlightingForOldJava();
427
428
429 notifyObservers(actionEvent);
430 return true;
431 }
432
433 /**
434 * Saves the settings to a specified file.
435 *
436 * @param fileName The file to save the settings to.
437 * @return {@code true} if the settings were saved, {@code false} if an exception occured.
438 */
439 public boolean save(String fileName) {
440
441 Event<? extends SettingsEvent> actionEvent = checkObservers(GS_Save, fileName);
442 if (null == actionEvent)
443 return false;
444
445 Properties values = new Properties();
446
447 if(!LiveGraph.application().runsCorrectJavaVersion())
448 values.setProperty("SavedWithIncompatibleJavaVersion", "1");
449
450 values.setProperty("MinY", Double.isNaN(getMinY()) ? "Auto" : StringTools.toString(getMinY()));
451 values.setProperty("MaxY", Double.isNaN(getMaxY()) ? "Auto" : StringTools.toString(getMaxY()));
452 values.setProperty("MinX", Double.isNaN(getMinX()) ? "Auto" : StringTools.toString(getMinX()));
453 values.setProperty("MaxX", Double.isNaN(getMaxX()) ? "Auto" : StringTools.toString(getMaxX()));
454
455 values.setProperty("VGridType", getVGridType().name());
456 values.setProperty("VGridSize", StringTools.toString(getVGridSize()));
457 values.setProperty("VGridColour", String.format("%02x%02x%02x",
458 getVGridColour().getRed(),
459 getVGridColour().getGreen(),
460 getVGridColour().getBlue()));
461
462 values.setProperty("HGridType", getHGridType().name());
463 values.setProperty("HGridSize", StringTools.toString(getHGridSize()));
464 values.setProperty("HGridColour", String.format("%02x%02x%02x",
465 getHGridColour().getRed(),
466 getHGridColour().getGreen(),
467 getHGridColour().getBlue()));
468
469 values.setProperty("XAxisType", getXAxisType().name());
470 values.setProperty("XAxisSeriesIndex", Integer.toString(getXAxisSeriesIndex()));
471 values.setProperty("XAxisParamValue", StringTools.toString(getXAxisParamValue()));
472
473 values.setProperty("HighlightDataPoints", getHighlightDataPoints() ? "1" : "0");
474
475 try {
476
477 FileOutputStream out = new FileOutputStream(fileName);
478 try {
479 values.storeToXML(out, "LiveGraph version " + LiveGraph.version + ". GraphSettings.");
480 } finally {
481 out.close();
482 }
483
484 notifyObservers(actionEvent);
485 return true;
486
487 } catch(IOException e) {
488 e.printStackTrace();
489 return false;
490 }
491 }
492
493 /**
494 * Gets the minimum Y value for the plot viewport.
495 *
496 * @return The minimum value along the Y axis for the graph view
497 * or {@code java.lang.Double.NaN} if the current global minimum of all data series
498 * should be used instead.
499 */
500 public double getMinY() {
501 return minY;
502 }
503
504 /**
505 * Sets the minimum Y value for the plot viewport.
506 *
507 * @param v The minimum value along the Y axis for the graph view
508 * or {@code java.lang.Double.NaN} if the global minimum of all data series
509 * should be used at all times.
510 */
511 public void setMinY(double v) {
512
513 if (v == getMinY())
514 return;
515
516 Event<? extends SettingsEvent> actionEvent = checkObservers(GS_MinY, v);
517 if (null == actionEvent)
518 return;
519
520 minY = v;
521 notifyObservers(actionEvent);
522 }
523
524 /**
525 * Gets the maximum Y value for the plot viewport.
526 *
527 * @return The maximum value along the Y axis for the graph view
528 * or {@code java.lang.Double.NaN} if the current global maximum of all data series
529 * should be used instead.
530 */
531 public double getMaxY() {
532 return maxY;
533 }
534
535 /**
536 * Sets the maximum Y value for the plot viewport.
537 *
538 * @param v The maximum value along the Y axis for the graph view
539 * or {@code java.lang.Double.NaN} if the global maximum of all data series
540 * should be used at all times.
541 */
542 public void setMaxY(double v) {
543
544 if (v == getMaxY())
545 return;
546
547 Event<? extends SettingsEvent> actionEvent = checkObservers(GS_MaxY, v);
548 if (null == actionEvent)
549 return;
550
551 maxY = v;
552 notifyObservers(actionEvent);
553 }
554
555 /**
556 * Gets the minimum X value for the plot viewport.
557 *
558 * @return The minimum value along the X axis for the graph view
559 * or {@code java.lang.Double.NaN} if the currently smallest X value of all data series
560 * should be used instead.
561 */
562 public double getMinX() {
563 return minX;
564 }
565
566 /**
567 * Sets the minimum X value for the plot viewport.
568 *
569 * @param v The minimum value along the X axis for the graph view
570 * or {@code java.lang.Double.NaN} if the smallest X value of all data series
571 * should be used at all times.
572 */
573 public void setMinX(double v) {
574
575 if (v == getMinX())
576 return;
577
578 Event<? extends SettingsEvent> actionEvent = checkObservers(GS_MinX, v);
579 if (null == actionEvent)
580 return;
581
582 minX = v;
583 notifyObservers(actionEvent);
584 }
585
586 /**
587 * Gets the maximum X value for the plot viewport.
588 *
589 * @return The maximum value along the X axis for the graph view
590 * or {@code java.lang.Double.NaN} if the currently largest X value of all data series
591 * should be used instead.
592 */
593 public double getMaxX() {
594 return maxX;
595 }
596
597 /**
598 * Sets the maximum X value for the plot viewport.
599 *
600 * @param v The maximum value along the X axis for the graph view
601 * or {@code java.lang.Double.NaN} if the largest X value of all data series
602 * should be used at all times.
603 */
604 public void setMaxX(double v) {
605
606 if (v == getMaxX())
607 return;
608
609 Event<? extends SettingsEvent> actionEvent = checkObservers(GS_MaxX, v);
610 if (null == actionEvent)
611 return;
612
613 maxX = v;
614 notifyObservers(actionEvent);
615 }
616
617 /**
618 * Sets the vertical grid type.
619 *
620 * @return The vertical grid type.
621 */
622 public VGridType getVGridType() {
623 return vGridType;
624 }
625
626 /**
627 * Gets the vertical grid type.
628 *
629 * @param v The vertical grid type.
630 */
631 public void setVGridType(VGridType v) {
632
633 if (null == v)
634 v = VGridType.VGrid_None;
635
636 if (v == getVGridType())
637 return;
638
639 Event<? extends SettingsEvent> actionEvent = checkObservers(GS_VGridType, v);
640 if (null == actionEvent)
641 return;
642
643 vGridType = v;
644 notifyObservers(actionEvent);
645 }
646
647 /**
648 * Gets the interval between the vertical grid bars.
649 *
650 * @return The interval between the vertical grid bars.
651 */
652 public double getVGridSize() {
653 return vGridSize;
654 }
655
656 /**
657 * Sets the interval between the vertical grid bars.
658 *
659 * @param val The interval between the vertical grid bars.
660 */
661 public void setVGridSize(double val) {
662
663 if (Double.isNaN(val) || Double.isInfinite(val) || 0.0 > val)
664 val = 0.0;
665
666 if (val == getVGridSize())
667 return;
668
669 Event<? extends SettingsEvent> actionEvent = checkObservers(GS_VGridSize, val);
670 if (null == actionEvent)
671 return;
672
673
674 vGridSize = val;
675 notifyObservers(actionEvent);
676 }
677
678 /**
679 * Gets the colour to use for drawing the vertical grid bars.
680 *
681 * @return The colour to use for drawing the vertical grid bars.
682 */
683 public Color getVGridColour() {
684 return vGridColour;
685 }
686
687 /**
688 * Sets the colour to use for drawing the vertical grid bars.
689 * @param c The colour to use for drawing the vertical grid bars.
690 */
691 public void setVGridColour(Color c) {
692
693 if (null == c)
694 c = new Color(Integer.parseInt("C0", 16), Integer.parseInt("C0", 16), Integer.parseInt("C0", 16));
695
696 if (c == getVGridColour())
697 return;
698
699 Event<? extends SettingsEvent> actionEvent = checkObservers(GS_VGridColour, c);
700 if (null == actionEvent)
701 return;
702
703 vGridColour = c;
704 notifyObservers(actionEvent);
705 }
706
707 /**
708 * Gets the horizontal grid type.
709 * @return The horizontal grid type.
710 */
711 public HGridType getHGridType() {
712 return hGridType;
713 }
714
715 /**
716 * Sets the horizontal grid type.
717 * @param v The horizontal grid type.
718 */
719 public void setHGridType(HGridType v) {
720
721 if (null == v)
722 v = HGridType.HGrid_None;
723
724 if (v == getHGridType())
725 return;
726
727 Event<? extends SettingsEvent> actionEvent = checkObservers(GS_HGridType, v);
728 if (null == actionEvent)
729 return;
730
731 hGridType = v;
732 notifyObservers(actionEvent);
733 }
734
735 /**
736 * Gets the interval between the horizontal grib bars.
737 *
738 * @return The interval between the horizontal grib bars.
739 */
740 public double getHGridSize() {
741 return hGridSize;
742 }
743
744 /**
745 * Sets the interval between the horizontal grib bars.
746 * @param val The interval between the horizontal grib bars.
747 */
748 public void setHGridSize(double val) {
749
750 if (Double.isNaN(val) || Double.isInfinite(val) || 0.0 > val)
751 val = 0.0;
752
753 if (val == getHGridSize())
754 return;
755
756 Event<? extends SettingsEvent> actionEvent = checkObservers(GS_HGridSize, val);
757 if (null == actionEvent)
758 return;
759
760 hGridSize = val;
761 notifyObservers(actionEvent);
762 }
763
764
765 /**
766 * Gets the colour for drawing the horizontal grid bars.
767 *
768 * @return The colour for drawing the horizontal grid bars.
769 */
770 public Color getHGridColour() {
771 return hGridColour;
772 }
773
774 /**
775 * Sets the colour for drawing the horizontal grid bars.
776 *
777 * @param c The colour for drawing the horizontal grid bars.
778 */
779 public void setHGridColour(Color c) {
780
781 if (null == c)
782 c = new Color(Integer.parseInt("C0", 16), Integer.parseInt("C0", 16), Integer.parseInt("C0", 16));
783
784 if (c == getHGridColour())
785 return;
786
787 Event<? extends SettingsEvent> actionEvent = checkObservers(GS_HGridColour, c);
788 if (null == actionEvent)
789 return;
790
791 hGridColour = c;
792 notifyObservers(actionEvent);
793 }
794
795 /**
796 * Gets the type for the x-axis.
797 *
798 * @return The type for the x-axis.
799 */
800 public XAxisType getXAxisType() {
801 return xAxisType;
802 }
803
804 /**
805 * Sets the type for the x-axis.
806 *
807 * @param v The type for the x-axis.
808 */
809 public void setXAxisType(XAxisType v) {
810
811 if (null == v)
812 v = XAxisType.XAxis_DSNum;
813
814 if (v == getXAxisType())
815 return;
816
817 double p = getXAxisParamValue();
818 double np = ensureGoodXAxisParameter(v, p);
819
820 int xAxisSerInd = getXAxisSeriesIndex();
821
822 Event<? extends SettingsEvent> actionEvent = checkObservers(GS_XAxisType, false, xAxisSerInd, np, v);
823 if (null == actionEvent)
824 return;
825
826 if (p != np && null == checkObservers(GS_XAxisParamValue, false, xAxisSerInd, np, v))
827 return;
828
829 xAxisType = v;
830
831 if (p != np)
832 setXAxisParamValue(np);
833
834 notifyObservers(actionEvent);
835 }
836
837 /**
838 * Gets the index of the data series to use as the x-axis.
839 *
840 * @return The index of the data series to use as the x-axis.
841 */
842 public int getXAxisSeriesIndex() {
843 return xAxisSeriesIndex;
844 }
845
846 /**
847 * Sets the index of the data series to use as the x-axis.
848 *
849 * @param val The index of the data series to use as the x-axis.
850 */
851 public void setXAxisSeriesIndex(int val) {
852
853 if (0 > val)
854 val = 0;
855
856 if (val == getXAxisSeriesIndex())
857 return;
858
859 double axisParam = getXAxisParamValue();
860 XAxisType axisType = getXAxisType();
861
862 Event<? extends SettingsEvent> actionEvent = checkObservers(GS_XAxisSeriesIndex,
863 false, val, axisParam, axisType);
864 if (null == actionEvent)
865 return;
866
867 xAxisSeriesIndex = val;
868 notifyObservers(actionEvent);
869 }
870
871 /**
872 * Gets the x-axis transformation parameter.
873 *
874 * @return The x-axis transformation parameter.
875 */
876 public double getXAxisParamValue() {
877 return xAxisParamValue;
878 }
879
880 /**
881 * Sets x-axis transformation parameter.
882 *
883 * @param val x-axis transformation parameter.
884 */
885 public void setXAxisParamValue(double val) {
886
887 if (Double.isNaN(val) || Double.isInfinite(val))
888 val = 1.0;
889
890 if (val == getXAxisParamValue())
891 return;
892
893 XAxisType axisType = getXAxisType();
894
895 val = ensureGoodXAxisParameter(axisType, val);
896
897 int xAxisSeriesIndex = getXAxisSeriesIndex();
898 Event<? extends SettingsEvent> actionEvent = checkObservers(GS_XAxisParamValue,
899 false, xAxisSeriesIndex, val, axisType);
900 if (null == actionEvent)
901 return;
902
903 xAxisParamValue = val;
904 notifyObservers(actionEvent);
905 }
906
907 /**
908 * Gets whether the data points in the vicinity of the mouse cursor should be highlighted.
909 * (Note, this is a hidden setting and cannot be changes via the GUI.)
910 *
911 * @return {@code true} if the data points in the vicinity of the mouse cursor should be highlighted,
912 * {@code false} otherwise.
913 */
914 public boolean getHighlightDataPoints() {
915 return highlightDataPoints;
916 }
917
918 /**
919 * Gets whether the data points in the vicinity of the mouse cursor should be highlighted.
920 * (Note, this is a hidden setting and cannot be changes via the GUI.)
921 *
922 * @param v {@code true} if the data points in the vicinity of the mouse cursor are to be highlighted,
923 * {@code false} otherwise.
924 */
925 public void setHighlightDataPoints(boolean v) {
926
927 if (v == getHighlightDataPoints())
928 return;
929
930 Event<? extends SettingsEvent> actionEvent = checkObservers(GS_HighlightDataPoints, v);
931 if (null == actionEvent)
932 return;
933
934 boolean prev = highlightDataPoints;
935 highlightDataPoints = v;
936 checkDisableHighlightingForOldJava();
937
938 if (prev != highlightDataPoints)
939 notifyObservers(actionEvent);
940 }
941
942 /**
943 * If the Java version is too old, data point highlighting is disabled.
944 */
945 private void checkDisableHighlightingForOldJava() {
946 if (!LiveGraph.application().runsCorrectJavaVersion())
947 highlightDataPoints = false;
948 }
949
950 /**
951 * Ensure that the transformation parameter has a legal value for the given
952 * x-axis type. The transformation parameter must be a real number. In addition,
953 * if the x-axis type is {@code XAxis_DataValLogToSetBase}, it must be
954 * non-negative and not 1.
955 *
956 * @param xAxisType The x-axis type for which to verify the parameter.
957 * @param parameter The transfom parameter to check.
958 * @return The corrected transform parameter.
959 */
960 private double ensureGoodXAxisParameter(XAxisType xAxisType, double parameter) {
961
962 if (Double.isInfinite(parameter))
963 parameter = (parameter > 0. ? 1. : -1.);
964
965 if (Double.isNaN(parameter))
966 parameter = 0.;
967
968 if (xAxisType == XAxisType.XAxis_DataValLogToSetBase) {
969
970 double d = MathTools.log(parameter, 1.);
971 if (Double.isNaN(d) || Double.isInfinite(d)) {
972
973 if (0 > parameter)
974 parameter = -parameter;
975 if (1. == parameter)
976 parameter = 0.;
977 }
978 }
979
980 return parameter;
981 }
982
983 } // public class GraphSettings