1 package jspecview.common;
2 
3 
4 import java.util.Hashtable;
5 
6 import java.util.Map;
7 
8 //import javajs.J2SRequireImport;
9 import javajs.api.GenericColor;
10 import javajs.util.BS;
11 import javajs.util.DF;
12 import javajs.util.Lst;
13 
14 import org.jmol.api.GenericGraphics;
15 import org.jmol.util.Font;
16 import org.jmol.util.Logger;
17 import javajs.util.PT;
18 
19 import jspecview.api.AnnotationData;
20 import jspecview.api.JSVPanel;
21 import jspecview.api.VisibleInterface;
22 import jspecview.common.Annotation.AType;
23 import jspecview.common.PanelData.LinkMode;
24 import jspecview.common.Spectrum.IRMode;
25 import jspecview.dialog.JSVDialog;
26 
27 // should not be necessary, but "x.isDialog()" is requiring it.
28 
29 //@J2SRequireImport(jspecview.dialog.JSVDialog.class)
30 class GraphSet implements XYScaleConverter {
31 
32 	private final static int ARROW_RESET = -1;
33 	private final static int ARROW_HOME = 0;
34 	private final static int ARROW_LEFT  = 1;
35 	private final static int ARROW_RIGHT = 2;
36 	private final static int ARROW_UP    = 3;
37 	private final static int ARROW_DOWN  = 4;
38 
39 
40 	private GraphSet gs2dLinkedX;
41 	private GraphSet gs2dLinkedY;
42 	private boolean cur1D2Locked;
43 
44 	private Lst<Highlight> highlights = new Lst<Highlight>();
45 	Lst<Spectrum> spectra = new Lst<Spectrum>();
46 
47 	private boolean isSplittable = true;
48 	private boolean allowStacking = true; // not MS
49 
50 	private Lst<Annotation> annotations;
51 	private MeasurementData selectedSpectrumMeasurements;
52 	private MeasurementData selectedSpectrumIntegrals;
53 	private Annotation lastAnnotation;
54 	Measurement pendingMeasurement;
55 	private Integral pendingIntegral;
56 	private Lst<Spectrum> graphsTemp = new Lst<Spectrum>();
57 	private PlotWidget[] widgets;
58 	private boolean isLinked;
59 	private boolean haveSingleYScale;
60 
61 	final static double RT2 = Math.sqrt(2.0);
62   private static GenericColor veryLightGrey;
63 
GraphSet(PanelData pd)64   GraphSet(PanelData pd) {
65     this.pd = pd;
66     jsvp = pd.jsvp;
67     g2d = pd.g2d;
68   }
69 
70 	/**
71 	 * iSpectrumMovedTo
72 	 *
73 	 * -- indicates spectrum moved to by user
74 	 *
75 	 * -- originally 0
76 	 *
77 	 * -- set in mouseMovedEvent only when nSpectra > 1: to iSpecBold if iSpecBold
78 	 * >= 0 or to -1 if showAllStacked or to getSplitPoint(yPixel)
79 	 *
80 	 * -- used in doZoom to set spectrum number for the new View object int iSpec
81 	 * = (iSpecBold >= 0 ? iSpecBold : iSpectrumMovedTo);
82 	 *
83 	 * -- used in drawAll to set the frame with the purple boundary int iSpec =
84 	 * (nSpectra == 1 ? 0 : !showAllStacked ? iSpectrumMovedTo : iSpecBold >= 0 ?
85 	 * iSpecBold : iSpectrumSelected);
86 	 *
87 	 */
88 	/* very */private int iSpectrumMovedTo;
89 
setSpectrumMovedTo(int i)90 	private int setSpectrumMovedTo(int i) {
91 		return iSpectrumMovedTo = i;
92 	}
93 
94 	/**
95 	 * iSpectrumClicked
96 	 *
97 	 * -- indicates spectrum clicked on by user -- when set T/F, also sets
98 	 *    iSpectrumSelected T/F
99 	 *
100 	 * -- initially 0
101 	 *
102 	 * -- set in checkSpectrumClickEvent from PanelData.setCurrentGraphSet when
103 	 * nSplit == 1 && showAllStacked && isClick to spectrum number if on spectrum
104 	 * to -1 if click is not on a spectrum
105 	 *
106 	 * -- set in MouseClickEvent to previous spectrum clicked if it is a double
107 	 * click and the previous click was on a spectrum (also sets iSpectrumSelected
108 	 * in that case)
109 	 *
110 	 * -- set in processPendingMeasurement to index of previous pendingMeasurement
111 	 * when clickCount == 1
112 	 *
113 	 * -- used in mouseClickEvent if (iSpectrumClicked >= 0) {
114 	 * processPendingMeasurement(xPixel, yPixel, 2); }
115 	 *
116 	 * -- used in processPendingMeasurement pendingMeasurement = new
117 	 * Measurement(this, spectra.get(iSpectrumClicked)...
118 	 *
119 	 *
120 	 */
121 	/* very */private int iSpectrumClicked;
122 
setSpectrumClicked(int i)123 	private void setSpectrumClicked(int i) {
124 		stackSelected = showAllStacked;
125 		if (i < 0 || iSpectrumClicked != i) {
126 			lastClickX = Double.NaN;
127 			lastPixelX = Integer.MAX_VALUE;
128 		}
129 		iSpectrumClicked = setSpectrumSelected(setSpectrumMovedTo(i));
130 	}
131 
132 	/**
133 	 * iSpectrumSelected
134 	 *
135 	 * -- indicates current spectrum index selected -- by clicking Left/Right
136 	 * arrow -- by clicking on a spectrum --
137 	 *
138 	 * -- originally -1 -- [0,nSpectra) indicates selected by clicking or peak
139 	 * picking -- Integer.MIN_VALUE -- none selected (and display none)
140 	 *
141 	 * -- set in PanelData.setCurrentGraphSet to currentSplitPoint when gs.nSplit
142 	 * > 1 && !gs.showAllStacked
143 	 *
144 	 * -- set in checkArrowLeftRightClick to selected spectrum if LEFT or RIGHT,
145 	 * or to -1 if HOME circle
146 	 *
147 	 * -- set in checkSpectrumClickEvent to spectrum clicked on, or to -1 if
148 	 * clicked off-spectrum
149 	 *
150 	 * -- set in mouseClickEvent along with iSpectrumClicked to the previously
151 	 * clicked spectrum when there is a double click.
152 	 *
153 	 * -- set in selectSpectrum based on filePath, type, and model to -1 if
154 	 * nSpectra == 1, or to the selected spectrum index if there is a match, or to
155 	 * Integer.MIN_VALUE if this isn't the current graph set and there is a
156 	 * selected spectrum already ??
157 	 *
158 	 * -- used all over the place, in checkArrowLeftRightClick,
159 	 * checkArrowUpDownClick, checkSpectrum, doPlot, drawAll, drawPeakTabs,
160 	 * drawPlot, drawSpectrum, getFixedSelectedSpectrumIndex, isDrawNoSpectra, and
161 	 * selectSpectrum,
162 	 *
163 	 * -- used in doPlot to return true when a split is to be shown, or when
164 	 * showAllStacked is true, or when no spectrum is selected, or when this is
165 	 * the spectrum selected
166 	 *
167 	 */
168 
169 	/* very */private int iSpectrumSelected = -1;
170 
setSpectrumSelected(int i)171 	private int setSpectrumSelected(int i) {
172 		boolean isNew = (i != iSpectrumSelected);
173 		iSpectrumSelected = i;
174 		if (isNew) {
175 			//hideAllDialogsExceptCurrent();
176 			getCurrentView();
177 		}
178 		return iSpectrumSelected;
179 	}
180 
181 	private boolean stackSelected = false;
182 	private BS bsSelected = new BS();
183 
184 	// needed by PanelData
185 
186 	ViewData viewData;
187 	boolean reversePlot;
188 	int nSplit = 1;
189 	int yStackOffsetPercent = 0;
190 
191 	/**
192 	 * if nSplit > 1, then showAllStacked is false, but if nSplit == 1, then
193 	 * showAllStacked may be true or false
194 	 */
195 	boolean showAllStacked = true;
196 
197 	// needed by AwtGraphSet
198 
199 	Lst<ViewData> viewList;
200 	ImageView imageView;
201 	private PanelData pd;
202 	private boolean sticky2Dcursor;
203 	int nSpectra; // also needed by PanelData
204 
closeDialogsExcept(AType type)205 	void closeDialogsExcept(AType type) {
206 		if (dialogs != null)
207 			for (Map.Entry<String, AnnotationData> e : dialogs.entrySet()) {
208 				AnnotationData ad = e.getValue();
209 				if (ad.isDialog() && (type == AType.NONE || ad.getAType() != type))
210 					((JSVDialog) ad).setVisible(false);
211 			}
212 	}
213 
dispose()214 	void dispose() {
215 //		for (int i = 0; i < spectra.size(); i++)
216 //			spectra.get(i).dispose();
217 		spectra = null;
218 		viewData = null;
219 		viewList = null;
220 		annotations = null;
221 		lastAnnotation = null;
222 		pendingMeasurement = null;
223 		imageView = null;
224 		graphsTemp = null;
225 		widgets = null;
226 		disposeImage();
227 		if (dialogs != null)
228 			for (Map.Entry<String, AnnotationData> e : dialogs.entrySet()) {
229 				AnnotationData ad = e.getValue();
230 				if (ad.isDialog())
231 					((JSVDialog) ad).dispose();
232 			}
233 		dialogs = null;
234 	}
235 
236 	private double fracX = 1, fracY = 1, fX0 = 0, fY0 = 0; // take up full screen
237 
238 	private PlotWidget zoomBox1D, zoomBox2D, pin1Dx0, pin1Dx1, // ppm range --
239 			// horizontal bar
240 			// on 1D spectrum
241 			pin1Dy0, pin1Dy1, // y-scaling -- vertical bar on 1D spectrum and left of
242 			// 2D when no 1D
243 			pin1Dx01, pin1Dy01, // center pins for those
244 			pin2Dx0, pin2Dx1, // ppm range -- horizontal bar on 2D spectrum
245 			pin2Dy0, pin2Dy1, // subspectrum range -- vertical bar on 2D spectrum
246 			pin2Dx01, pin2Dy01, // center pins for those
247 			cur2Dx0, cur2Dx1, // 2D x cursors -- derived from pin1Dx0 and pin1Dx1
248 			// values
249 			cur1D2x1, cur1D2x2, // 1D cursors derived from 2D cursors
250 			cur2Dy; // 2D y cursor -- points to currently displayed 1D slice
251 
252 	// for the 1D plot area:
253 	private int xPixel0, yPixel0, xPixel1, yPixel1, xVArrows, xHArrows, yHArrows;
254 	// for the overall panel section:
255 	private int xPixel00, yPixel00, xPixel11, yPixel11, yPixel000;
256 	private int xPixels, yPixels;
257 	private int xPixel10, xPixels0;
258 
259 	private boolean allowStackedYScale = true;
260 	private boolean drawXAxisLeftToRight;
261 	private boolean xAxisLeftToRight = true;
262 	private int iPreviousSpectrumClicked = -1;
263 	private boolean haveSelectedSpectrum;
264 
265 	private boolean zoomEnabled;
266 	private int currentZoomIndex;
267 
268 	private double lastClickX = Double.NaN;
269 	private int lastPixelX = Integer.MAX_VALUE;
270 
isDrawNoSpectra()271 	private boolean isDrawNoSpectra() {
272 		return (iSpectrumSelected == Integer.MIN_VALUE);
273 	}
274 
275 	/**
276 	 *
277 	 * @return spectrum index selected by user from a peak pick, a spectrum pick
278 	 *         with showAllStacked, but set to 0 if out of range
279 	 */
280 
getFixedSelectedSpectrumIndex()281 	private int getFixedSelectedSpectrumIndex() {
282 		return Math.max(iSpectrumSelected, 0);
283 	}
284 
285 	private int height;
286 	private int width;
287 	private int right;
288 	private int top;
289 	private int left;
290 	private int bottom;
291 
292 	private PeakInfo piMouseOver;
293 	private final Coordinate coordTemp = new Coordinate();
294 	private final static int minNumOfPointsForZoom = 3;
295 
296 	final private int FONT_PLAIN = 0;
297 	final private int FONT_BOLD = 1;
298 	final private int FONT_ITALIC = 2;
299 
300 	private boolean is2DSpectrum;
301 
getSpectrum()302 	Spectrum getSpectrum() {
303 		// could be a 2D spectrum or a set of mass spectra
304 		return getSpectrumAt(getFixedSelectedSpectrumIndex())
305 				.getCurrentSubSpectrum();
306 	}
307 
308 	/**
309 	 * Returns the <code>Spectrum</code> at the specified index
310 	 *
311 	 * @param index
312 	 *          the index of the <code>Spectrum</code>
313 	 * @return the <code>Spectrum</code> at the specified index
314 	 */
getSpectrumAt(int index)315 	Spectrum getSpectrumAt(int index) {
316 		return spectra.get(index);
317 	}
318 
getSpectrumIndex(Spectrum spec)319 	int getSpectrumIndex(Spectrum spec) {
320 		for (int i = spectra.size(); --i >= 0;)
321 			if (spectra.get(i) == spec)
322 				return i;
323 		return -1;
324 	}
325 
addSpec(Spectrum spec)326 	private void addSpec(Spectrum spec) {
327 		spectra.addLast(spec);
328 		nSpectra++;
329 	}
330 
splitStack(boolean doSplit)331 	void splitStack(boolean doSplit) {
332 		if (doSplit && isSplittable) {
333 			nSplit = nSpectra;
334 			showAllStacked = false;
335 			setSpectrumClicked(iSpectrumSelected);
336 			pd.currentSplitPoint = iSpectrumSelected;
337 		} else {
338 			nSplit = 1;
339 			showAllStacked = allowStacking && !doSplit;
340 			setSpectrumClicked(iSpectrumSelected);
341 		}
342 		stackSelected = false;
343 		setFractionalPositions(pd, pd.graphSets, LinkMode.NONE);
344 		pd.setTaintedAll();
345 	}
346 
setPositionForFrame(int iSplit)347 	private void setPositionForFrame(int iSplit) {
348 		if (iSplit < 0)
349 			iSplit = 0;
350 		int marginalHeight = height - 50;
351 		xPixel00 = (int) (width * fX0);
352 		xPixel11 = (int) (xPixel00 + width * fracX - 1);
353 		xHArrows = xPixel00 + 25;
354 		xVArrows = xPixel11 - right / 2;
355 		xPixel0 = xPixel00 + (int) ( left * (1 - fX0));
356 		xPixel10 = xPixel1 = xPixel11 - right;
357 		xPixels0 = xPixels = xPixel1 - xPixel0 + 1;
358 		// only the very top spectrum needs an offset
359 		// -- to move it below the coordinate string
360 		yPixel000 = (fY0 == 0 ? 25 : 0) + (int) (height * fY0);
361 		yPixel00 = yPixel000 + (int) (marginalHeight * fracY * iSplit);
362 		yPixel11 = yPixel00 + (int) (marginalHeight * fracY) - 1;
363 		yHArrows = yPixel11 - 12;
364 		yPixel0 = yPixel00 + top / 2;
365 		yPixel1 = yPixel11 - bottom / 2;
366 		yPixels = yPixel1 - yPixel0 + 1;
367 		if (imageView != null && is2DSpectrum) {
368 			setImageWindow();
369 			if (pd.display1D) {
370 				double widthRatio = (pd.display1D ? 1.0
371 						* (xPixels0 - imageView.xPixels) / xPixels0 : 1);
372 				xPixels = (int) Math.floor(widthRatio * xPixels0 * 0.8);
373 				xPixel1 = xPixel0 + xPixels - 1;
374 			} else {
375 				xPixels = 0;
376 				xPixel1 = imageView.xPixel0 - 30;
377 			}
378 		}
379 	}
380 
hasPoint(int xPixel, int yPixel)381 	private boolean hasPoint(int xPixel, int yPixel) {
382 		return (xPixel >= xPixel00 && xPixel <= xPixel11 && yPixel >= yPixel000 && yPixel <= yPixel11
383 				* nSplit);
384 	}
385 
isInPlotRegion(int xPixel, int yPixel)386 	private boolean isInPlotRegion(int xPixel, int yPixel) {
387 		return (xPixel >= xPixel0 && xPixel <= xPixel1 && yPixel >= yPixel0 && yPixel <= yPixel1);
388 	}
389 
getSplitPoint(int yPixel)390 	int getSplitPoint(int yPixel) {
391 		return Math.max(0, Math.min(((yPixel - yPixel000) / (yPixel11 - yPixel00)),
392 				nSplit - 1));
393 	}
394 
isSplitWidget(int xPixel, int yPixel)395 	private boolean isSplitWidget(int xPixel, int yPixel) {
396 		return isFrameBox(xPixel,  yPixel, splitterX, splitterY);
397 	//	return (isSplittable && xPixel >= xPixel11 - 20 && yPixel >= yPixel00 + 1
398 				////&& xPixel <= xPixel11 - 10 && yPixel <= yPixel00 + 11);
399 	}
400 
isCloserWidget(int xPixel, int yPixel)401 	private boolean isCloserWidget(int xPixel, int yPixel) {
402 		return isFrameBox(xPixel, yPixel, closerX, closerY);
403 	}
404 
405 
406 
407 	/**
408 	 * Initializes the graph set
409 	 * @param startIndex
410 	 * @param endIndex
411 	 */
412 
initGraphSet(int startIndex, int endIndex)413 	private void initGraphSet(int startIndex, int endIndex) {
414 		if (veryLightGrey == null)
415 			veryLightGrey = g2d.getColor3(200, 200, 200);
416 		setPlotColors(ColorParameters.defaultPlotColors);
417 		xAxisLeftToRight = getSpectrumAt(0).shouldDisplayXAxisIncreasing();
418 		setDrawXAxis();
419 		int[] startIndices = new int[nSpectra];
420 		int[] endIndices = new int[nSpectra];
421 		bsSelected.setBits(0, nSpectra);
422 		// null means use standard offset spectrumOffsets = new int[nSpectra];
423 		allowStackedYScale = true;
424 		if (endIndex <= 0)
425 			endIndex = Integer.MAX_VALUE;
426 		isSplittable = (nSpectra > 1);// for now, could be:
427 		// getSpectrumAt(0).isSplitable();
428 		allowStacking = (spectra.get(0).isStackable());
429 		showAllStacked = allowStacking && (nSpectra > 1);
430 		for (int i = 0; i < nSpectra; i++) {
431 			int iLast = spectra.get(i).getXYCoords().length - 1;
432 			startIndices[i] = Coordinate.intoRange(startIndex, 0, iLast);
433 			endIndices[i] = Coordinate.intoRange(endIndex, 0, iLast);
434 			allowStackedYScale &= (spectra.get(i).getYUnits().equals(
435 					spectra.get(0).getYUnits())
436 					&& spectra.get(i).getUserYFactor() == spectra.get(0).getUserYFactor()
437 					);
438 		}
439 		getView(0, 0, 0, 0, startIndices, endIndices, null, null);
440 		viewList = new Lst<ViewData>();
441 		viewList.addLast(viewData);
442 	}
443 
getView(double x1, double x2, double y1, double y2, int[] startIndices, int[] endIndices, ScaleData[] viewScales, ScaleData[] yScales)444 	private synchronized void getView(double x1, double x2, double y1, double y2,
445 			int[] startIndices, int[] endIndices, ScaleData[] viewScales, ScaleData[] yScales) {
446 		Lst<Spectrum> graphs = (graphsTemp.size() == 0 ? spectra : graphsTemp);
447 		Lst<Spectrum> subspecs = getSpectrumAt(0).getSubSpectra();
448 		boolean dontUseSubspecs = (subspecs == null || subspecs.size() == 2
449 				&& subspecs.get(1).isImaginary());
450 		// NMR real/imaginary
451 		boolean is2D = !getSpectrumAt(0).is1D();
452 		boolean useFirstSubSpecOnly = false;
453 		if (is2D && useFirstSubSpecOnly || dontUseSubspecs && y1 == y2) {
454 			// 2D spectrum or startup
455 			graphs = spectra;
456 		} else if (y1 == y2) {
457 			// start up, forced subsets (too many spectra)
458 			viewData = new ViewData(subspecs, y1, y2, getSpectrum().isContinuous());
459 			graphs = null;
460 		}
461 		if (graphs != null) {
462 			viewData = new ViewData(graphs, y1, y2, startIndices, endIndices,
463 					getSpectrumAt(0).isContinuous(), is2D);
464 			if (x1 != x2)
465 				getScale().setXRange(x1, x2);
466 		}
467 		if (viewScales != null) {
468 			ScaleData.copyScaleFactors(viewScales, viewData.getScaleData());
469 			if (yScales != null)
470 				ScaleData.copyYScales(yScales, viewData.getScaleData());
471 			getCurrentView();
472 		}
473 	}
474 
isNearby(Coordinate a1, Coordinate a2, XYScaleConverter c, int range)475 	private boolean isNearby(Coordinate a1, Coordinate a2, XYScaleConverter c,
476 			int range) {
477 		double x = a1.getXVal();
478 		int xp1 = c.toPixelX(x);
479 		int yp1 = toPixelY(a1.getYVal());
480 		x = a2.getXVal();
481 		int xp2 = c.toPixelX(x);
482 		int yp2 = toPixelY(a2.getYVal());
483 		return (Math.abs(xp1 - xp2) + Math.abs(yp1 - yp2) < range);
484 	}
485 
486 	/**
487 	 * Displays plot in reverse if val is true
488 	 *
489 	 * @param val
490 	 *          true or false
491 	 */
setReversePlot(boolean val)492 	void setReversePlot(boolean val) {
493 		reversePlot = val;
494 		if (reversePlot)
495 			closeDialogsExcept(AType.NONE);
496 		setDrawXAxis();
497 	}
498 
setDrawXAxis()499 	private void setDrawXAxis() {
500 		drawXAxisLeftToRight = xAxisLeftToRight ^ reversePlot;
501 		for (int i = 0; i < spectra.size(); i++)
502 			(spectra.get(i)).setExportXAxisDirection(drawXAxisLeftToRight);
503 	}
504 
isInTopBar(int xPixel, int yPixel)505 	private boolean isInTopBar(int xPixel, int yPixel) {
506 		return (xPixel == fixX(xPixel) && yPixel > pin1Dx0.yPixel0 - 2 && yPixel < pin1Dx0.yPixel1);
507 	}
508 
isInTopBar2D(int xPixel, int yPixel)509 	private boolean isInTopBar2D(int xPixel, int yPixel) {
510 		return (imageView != null && xPixel == imageView.fixX(xPixel)
511 				&& yPixel > pin2Dx0.yPixel0 - 2 && yPixel < pin2Dx0.yPixel1);
512 	}
513 
isInRightBar(int xPixel, int yPixel)514 	private boolean isInRightBar(int xPixel, int yPixel) {
515 	 return (yPixel == fixY(yPixel) && xPixel > pin1Dy0.xPixel1 && xPixel <
516 	 pin1Dy0.xPixel0 + 2);
517  }
518 
isInRightBar2D(int xPixel, int yPixel)519 	private boolean isInRightBar2D(int xPixel, int yPixel) {
520 		return (imageView != null && yPixel == fixY(yPixel)
521 				&& xPixel > pin2Dy0.xPixel1 && xPixel < pin2Dy0.xPixel0 + 2);
522 	}
523 
toX0(int xPixel)524 	private double toX0(int xPixel) {
525 		return viewList.get(0).getScale().toX0(fixX(xPixel), xPixel0, xPixel1, drawXAxisLeftToRight);
526 	}
527 
toY0(int yPixel)528 	private double toY0(int yPixel) {
529 		return viewList.get(0).getScale().toY0(fixY(yPixel), yPixel0, yPixel1);
530 	}
531 
532   @Override
toX(int xPixel)533   public double toX(int xPixel) {
534 		if (imageView != null && imageView.isXWithinRange(xPixel))
535 			return imageView.toX(xPixel);
536 		return getScale().toX(fixX(xPixel), xPixel1, drawXAxisLeftToRight);
537 	}
538 
539 	@Override
toY(int yPixel)540 	public double toY(int yPixel) {
541 		return getScale().toY(yPixel, yPixel0);
542 	}
543 
544   @Override
toPixelX(double dx)545   public int toPixelX(double dx) {
546   	return getScale().toPixelX(dx, xPixel0, xPixel1, drawXAxisLeftToRight);
547 	}
548 
549 	@Override
toPixelY(double yVal)550 	public int toPixelY(double yVal) {
551 		return getScale().toPixelY(yVal, yPixel1);
552 	}
553 
toPixelX0(double x)554 	private int toPixelX0(double x) {
555 		return viewList.get(0).getScale().toPixelX0(x, xPixel0, xPixel1, drawXAxisLeftToRight);
556 	}
557 
toPixelY0(double y)558 	private int toPixelY0(double y) {
559 		return fixY(viewList.get(0).getScale().toPixelY0(y, yPixel0, yPixel1));
560 	}
561 
562 	@Override
fixX(int xPixel)563 	public int fixX(int xPixel) {
564 		return Coordinate.intoRange(xPixel, xPixel0, xPixel1);
565 	}
566 
567 	@Override
fixY(int yPixel)568 	public int fixY(int yPixel) {
569 		return Coordinate.intoRange(yPixel, yPixel0, yPixel1);
570 	}
571 
572   @Override
getXPixel0()573   public int getXPixel0() {
574   	return xPixel0;
575   }
576 
577   @Override
getXPixels()578 	public int getXPixels() {
579   	return xPixels;
580   }
581 
582   @Override
getYPixels()583   public int getYPixels() {
584   	return yPixels;
585   }
586 
587 	@Override
getScale()588 	public ScaleData getScale() {
589 		return viewData.getScale();
590 	}
591 
toPixelYint(double yVal)592 	private int toPixelYint(double yVal) {
593 		return yPixel1
594 				- (int) (Double.isNaN(yVal) ? Integer.MIN_VALUE : yPixels * yVal);
595 	}
596 
findAnnotation2D(Coordinate xy)597 	private Annotation findAnnotation2D(Coordinate xy) {
598 		for (int i = annotations.size(); --i >= 0;) {
599 			Annotation a = annotations.get(i);
600 			if (isNearby(a, xy, imageView, 10))
601 				return a;
602 		}
603 		return null;
604 	}
605 
addAnnotation(Annotation annotation, boolean isToggle)606 	private void addAnnotation(Annotation annotation, boolean isToggle) {
607 		if (annotations == null)
608 			annotations = new Lst<Annotation>();
609 		boolean removed = false;
610 		for (int i = annotations.size(); --i >= 0;)
611 			if (annotation.is2D ? isNearby(annotations.get(i), annotation, imageView,
612 					10) : annotation.equals(annotations.get(i))) {
613 				removed = true;
614 				annotations.removeItemAt(i);
615 			}
616 		if (annotation.text.length() > 0 && (!removed || !isToggle))
617 			annotations.addLast(annotation);
618 	}
619 
setImageWindow()620 	private void setImageWindow() {
621 		imageView.setPixelWidthHeight((int) ((pd.display1D ? 0.6 : 1) * xPixels0),
622 				yPixels);
623 		imageView.setXY0(getSpectrumAt(0), (int) Math.floor(xPixel10 - imageView.xPixels), yPixel0);
624 	}
625 
626 	private Measurement selectedMeasurement;
627 	private Integral selectedIntegral;
628 
629 	private double lastXMax = Double.NaN;
630 	private int lastSpecClicked = -1;
631 
632 //	private double getPeakCenter() {
633 //		if (nSpectra > 1 && iSpectrumClicked < 0 || Double.isNaN(lastClickX))
634 //			return Double.NaN;
635 //		return getSpectrum().findXForPeakNearest(lastClickX);
636 //	}
637 
findNearestMaxMin()638 	private boolean findNearestMaxMin() {
639 		if (nSpectra > 1 && iSpectrumClicked < 0)
640 			return false;
641 		xValueMovedTo = getSpectrum().findXForPeakNearest(xValueMovedTo);
642 		setXPixelMovedTo(xValueMovedTo, Double.MAX_VALUE, 0, 0);
643 		return !Double.isNaN(xValueMovedTo);
644 	}
645 
setXPixelMovedTo(double x1, double x2, int xPixel1, int xPixel2)646 	void setXPixelMovedTo(double x1, double x2, int xPixel1, int xPixel2) {
647 		if (x1 == Double.MAX_VALUE && x2 == Double.MAX_VALUE) {
648 			xPixelMovedTo = xPixel1;
649 			xPixelMovedTo2 = xPixel2;
650 			if (isLinked && sticky2Dcursor) {
651 				pd.setlinkedXMove(this, toX(xPixelMovedTo), false);
652 			}
653 			return;
654 		}
655 		if (x1 != Double.MAX_VALUE) {
656 			xPixelMovedTo = toPixelX(x1);
657 			if (fixX(xPixelMovedTo) != xPixelMovedTo)
658 				xPixelMovedTo = -1;
659 			xPixelMovedTo2 = -1;
660 			if (x1 != 1e10)
661 				setSpectrumClicked(getFixedSelectedSpectrumIndex());
662 		}
663 		if (x2 != Double.MAX_VALUE) {
664 			xPixelMovedTo2 = toPixelX(x2);
665 		}
666 	}
667 
processPendingMeasurement(int xPixel, int yPixel, int clickCount)668 	private void processPendingMeasurement(int xPixel, int yPixel, int clickCount) {
669 		if (!isInPlotRegion(xPixel, yPixel) || is2dClick(xPixel, yPixel)) {
670 			pendingMeasurement = null;
671 			return;
672 		}
673 		double x = toX(xPixel);
674 		double y = toY(yPixel);
675 		double x0 = x;
676 		Measurement m;
677 		switch (clickCount) {
678 		case 0: // move
679 			pendingMeasurement.setPt2(toX(xPixel), toY(yPixel));
680 			break;
681 		case 3: // ctrl-click
682 		case 2: // 1st double-click
683 			if (iSpectrumClicked < 0)
684 				return;
685 			Spectrum spec = spectra.get(iSpectrumClicked);
686 			setScale(iSpectrumClicked);
687 			if (clickCount == 3) {
688 			} else {
689 				m = findMeasurement(selectedSpectrumMeasurements, xPixel, yPixel, Measurement.PT_XY1);
690 				if (m != null) {
691 					x = m.getXVal();
692 					y = m.getYVal();
693 				} else if ((m = findMeasurement(selectedSpectrumMeasurements, xPixel,
694 						yPixel, Measurement.PT_XY2)) != null) {
695 					x = m.getXVal2();
696 					y = m.getYVal2();
697 				} else {
698 					x = getNearestPeak(spec, x, y);
699 				}
700 			}
701 			pendingMeasurement = new Measurement().setM1(x, y, spec);
702 			pendingMeasurement.setPt2(x0, y);
703 			pd.setTaintedAll();
704 			pd.repaint();
705 			break;
706 		case 1: // single click -- save and continue
707 		case -2: // second double-click -- save and quit
708 		case -3: // second ctrl-click
709 			boolean isOK = (pendingMeasurement != null && isVisible(getDialog(AType.Measurements, -1)));
710 			while (isOK) {
711 				setScale(getSpectrumIndex(pendingMeasurement.spec));
712 				if (clickCount != 3) {
713 					if (!findNearestMaxMin()) {
714 						isOK = false;
715 						break;
716 					}
717 					xPixel = xPixelMovedTo;
718 				}
719 				x = toX(xPixel);
720 				y = toY(yPixel);
721 				pendingMeasurement.setPt2(x, y);
722 				if (pendingMeasurement.text.length() == 0) {
723 					isOK = false;
724 					break;
725 				}
726 				setMeasurement(pendingMeasurement);
727 				if (clickCount != 1) {
728 					isOK = false;
729 					break;
730 				}
731 				setSpectrumClicked(getSpectrumIndex(pendingMeasurement.spec));
732 				pendingMeasurement = new Measurement().setM1(x, y,
733 						pendingMeasurement.spec);
734 				break;
735 			}
736 			if (!isOK)
737 				pendingMeasurement = null;
738 			pd.setTaintedAll();
739 			pd.repaint();
740 			break;
741 		case 5: // (old) control-click
742 			if (findNearestMaxMin()) {
743 				int iSpec = getFixedSelectedSpectrumIndex();
744 				if (Double.isNaN(lastXMax) || lastSpecClicked != iSpec
745 						|| pendingMeasurement == null) {
746 					lastXMax = xValueMovedTo;
747 					lastSpecClicked = iSpec;
748 					pendingMeasurement = new Measurement().setM1(xValueMovedTo,
749 							yValueMovedTo, spectra.get(iSpec));
750 				} else {
751 					pendingMeasurement.setPt2(xValueMovedTo, yValueMovedTo);
752 					if (pendingMeasurement.text.length() > 0)
753 						setMeasurement(pendingMeasurement);
754 					pendingMeasurement = null;
755 					lastXMax = Double.NaN;
756 				}
757 			} else {
758 				lastXMax = Double.NaN;
759 			}
760 			break;
761 		}
762 	}
763 
checkIntegralNormalizationClick(int xPixel, int yPixel)764 	private boolean checkIntegralNormalizationClick(int xPixel, int yPixel) {
765 		if (selectedSpectrumIntegrals == null)
766 			return false;
767 		Integral integral = (Integral) findMeasurement(selectedSpectrumIntegrals,
768 				xPixel, yPixel, Measurement.PT_INT_LABEL);
769 		if (integral == null)
770 			return false;
771 		selectedIntegral = integral;
772 		pd.normalizeIntegral();
773 		updateDialog(AType.Integration, -1);
774 		setSpectrumClicked(getSpectrumIndex(integral.spec));
775 		return true;
776 	}
777 
778 	/**
779 	 * search for the nearest peak above/below the given y value
780 	 *
781 	 * @param spec
782 	 *
783 	 * @param x
784 	 * @param y
785 	 * @return  nearest x value
786 	 */
getNearestPeak(Spectrum spec, double x, double y)787 	private double getNearestPeak(Spectrum spec, double x, double y) {
788 		double x0 = Coordinate.getNearestXWithYAbove(spec.getXYCoords(), x, y, spec
789 				.isInverted(), false);
790 		double x1 = Coordinate.getNearestXWithYAbove(spec.getXYCoords(), x, y, spec
791 				.isInverted(), true);
792 		return (Double.isNaN(x0) ? x1 : Double.isNaN(x1) ? x0
793 				: Math.abs(x0 - x) < Math.abs(x1 - x) ? x0 : x1);
794 	}
795 
findMeasurement(MeasurementData measurements, int xPixel, int yPixel, int iPt)796 	private Measurement findMeasurement(MeasurementData measurements, int xPixel,
797 			int yPixel, int iPt) {
798 		if (measurements == null || measurements.size() == 0)
799 			return null;
800 		if (iPt == Measurement.PT_ON_LINE) {
801 			Measurement m = findMeasurement(measurements, xPixel, yPixel, Measurement.PT_ON_LINE1);
802 			if (m != null || measurements.get(0) instanceof Integral)
803 				return m;
804 			return findMeasurement(measurements, xPixel, yPixel, Measurement.PT_ON_LINE2); // lower bar,
805 			// near baseline
806 		}
807 		for (int i = measurements.size(); --i >= 0;) {
808 			Measurement m = measurements.get(i);
809 			int x1, x2, y1, y2;
810 			if (m instanceof Integral) {
811 				x1 = x2 = toPixelX(m.getXVal2());
812 				y1 = toPixelYint(m.getYVal());
813 				y2 = toPixelYint(m.getYVal2());
814 			} else {
815 				x1 = toPixelX(m.getXVal());
816 				x2 = toPixelX(m.getXVal2());
817 				y1 = y2 = (iPt == -2 ? yPixel1 - 2 : toPixelY(m.getYVal()));
818 			}
819 			switch (iPt) {
820 			case Measurement.PT_XY1:
821 				if (Math.abs(xPixel - x1) + Math.abs(yPixel - y1) < 4)
822 					return m;
823 				break;
824 			case Measurement.PT_XY2:
825 				if (Math.abs(xPixel - x2) + Math.abs(yPixel - y2) < 4)
826 					return m;
827 				break;
828 			case Measurement.PT_INT_LABEL: // label for integral
829 				y1 = y2 = (y1 + y2) / 2;
830 				x2 = x1 + 20; // estimate only
831 				//$FALL-THROUGH$
832 			default:
833 			case Measurement.PT_ON_LINE1:
834 			case Measurement.PT_ON_LINE2:
835 				if (isOnLine(xPixel, yPixel, x1, y1, x2, y2))
836 					return m;
837 				break;
838 			}
839 
840 		}
841 		return null;
842 	}
843 
setMeasurement(Measurement m)844 	private void setMeasurement(Measurement m) {
845 		int iSpec = getSpectrumIndex(m.spec);
846 		AnnotationData ad = getDialog(AType.Measurements, iSpec);
847 		if (ad == null)
848 			addDialog(iSpec, AType.Measurements, ad = new MeasurementData(
849 					AType.Measurements, m.spec));
850 		ad.getData().addLast(m.copyM());
851 		updateDialog(AType.Measurements, -1);
852 	}
853 
checkArrowUpDownClick(int xPixel, int yPixel)854 	private boolean checkArrowUpDownClick(int xPixel, int yPixel) {
855 		boolean ok = false;
856 		double f = (isArrowClick(xPixel, yPixel, ARROW_UP) ? RT2
857 				: isArrowClick(xPixel, yPixel, ARROW_DOWN) ? 1 / RT2 : 0);
858 		if (f != 0) {
859 			if (nSplit > 1)
860 				setSpectrumSelected(iSpectrumMovedTo);
861 			if ((nSpectra == 1 || iSpectrumSelected >= 0)
862 					&& spectra.get(getFixedSelectedSpectrumIndex()).isTransmittance())
863 				f = 1 / f;
864 			viewData.scaleSpectrum(imageView == null ? iSpectrumSelected : -2, f);
865 			ok = true;
866 		} else if (isArrowClick(xPixel, yPixel, ARROW_RESET)) {
867 			resetViewCompletely();
868 			ok = true;
869 		}
870 
871 		if (ok) {
872 			if (imageView != null) {
873 				update2dImage(false);
874 				resetPinsFromView();
875 			}
876 			pd.setTaintedAll();
877 		}
878 		return ok;
879 	}
880 
resetViewCompletely()881 	void resetViewCompletely() {
882 		// reset button between up/down arrows;
883 		clearViews();
884 		if (showAllStacked && !stackSelected)
885 			closeDialogsExcept(AType.NONE);
886 		viewData.resetScaleFactors();
887 		// did not work: view.setScaleFactor(iSpectrumSelected, 1);
888 		updateDialogs();
889 	}
890 
checkArrowLeftRightClick(int xPixel, int yPixel)891   private boolean checkArrowLeftRightClick(int xPixel, int yPixel) {
892     if (haveLeftRightArrows) {
893       int dx = (isArrowClick(xPixel, yPixel, ARROW_LEFT) ? -1 : isArrowClick(
894           xPixel, yPixel, ARROW_RIGHT) ? 1 : 0);
895       if (dx != 0) {
896         int i = iSpectrumSelected + dx;
897         if (i < 0)
898           i = nSpectra - 1;
899         setSpectrumClicked(i % nSpectra);
900         return true;
901       }
902       if (isArrowClick(xPixel, yPixel, ARROW_HOME)) {
903         if (showAllStacked) {
904           showAllStacked = false;
905           setSpectrumClicked(getFixedSelectedSpectrumIndex());
906           return true;
907         }
908         showAllStacked = allowStacking;
909         setSpectrumSelected(-1); // better to stay with the one we have, not reset.
910         stackSelected = false;
911       }
912     }
913     return false;
914   }
915 
isArrowClick(int xPixel, int yPixel, int type)916 	private boolean isArrowClick(int xPixel, int yPixel, int type) {
917 		int pt;
918 		switch (type) {
919 		case ARROW_UP:
920 		case ARROW_DOWN:
921 		case ARROW_RESET:
922 			pt = (yPixel00 + yPixel11) / 2
923 					+ (type == ARROW_UP ? -1 : type == ARROW_DOWN ? 1 : 0) * 15;
924 			return (Math.abs(xVArrows - xPixel) < 10 && Math.abs(pt - yPixel) < 10);
925 		case ARROW_LEFT:
926 		case ARROW_RIGHT:
927 		case ARROW_HOME:
928 			pt = xHArrows
929 					+ (type == ARROW_LEFT ? -1 : type == ARROW_RIGHT ? 1 : 0)
930 					* 15;
931 			return (Math.abs(pt - xPixel) < 10 && Math.abs(yHArrows - yPixel) < 10);
932 		}
933 		return false;
934 	}
935 
936 	private static final int MIN_DRAG_PIXELS = 5;// fewer than this means no zoom
937 	// or reset
938 
939 	private boolean inPlotMove;
940 	private int xPixelMovedTo = -1;
941 	private int xPixelMovedTo2 = -1;
942 	private double yValueMovedTo;
943 	private double xValueMovedTo;
944 	private boolean haveLeftRightArrows;
945 	private int xPixelPlot1;
946 	private int xPixelPlot0;
947 	private int yPixelPlot0;
948 	private int yPixelPlot1;
949 	private Double nextClickForSetPeak;
950 	private int closerX, closerY, splitterX, splitterY;
951 
setWidgetValueByUser(PlotWidget pw)952 	private void setWidgetValueByUser(PlotWidget pw) {
953 		String sval;
954 		if (pw == cur2Dy)
955 			sval = "" + imageView.toSubspectrumIndex(pw.yPixel0);
956 		else if (pw == pin1Dx01)
957 			sval = "" + Math.min(pin1Dx0.getXVal(), pin1Dx1.getXVal()) + " - "
958 					+ Math.max(pin1Dx0.getXVal(), pin1Dx1.getXVal());
959 		else if (pw == pin1Dy01)
960 			sval = "" + Math.min(pin1Dy0.getYVal(), pin1Dy1.getYVal()) + " - "
961 					+ Math.max(pin1Dy0.getYVal(), pin1Dy1.getYVal());
962 		else if (pw == pin2Dx01)
963 			sval = "" + Math.min(pin2Dx0.getXVal(), pin2Dx1.getXVal()) + " - "
964 					+ Math.max(pin2Dx0.getXVal(), pin2Dx1.getXVal());
965 		else if (pw == pin2Dy01)
966 			sval = "" + (int) Math.min(pin2Dy0.getYVal(), pin2Dy1.getYVal()) + " - "
967 					+ (int) Math.max(pin2Dy0.getYVal(), pin2Dy1.getYVal());
968 		else
969 			sval = "" + pw.getValue();
970 		sval = pd.getInput("New value?", "Set Slider", sval);
971 		if (sval == null)
972 			return;
973 		sval = sval.trim();
974 		try {
975 			if (pw == pin1Dx01 || pw == pin1Dy01 || pw == pin2Dx01 || pw == pin2Dy01) {
976 				int pt = sval.indexOf("-", 1);
977 				if (pt < 0)
978 					return;
979 				double val1 = Double.valueOf(sval.substring(0, pt)).doubleValue();
980 				double val2 = Double.valueOf(sval.substring(pt + 1)).doubleValue();
981 				if (pw == pin1Dx01) {
982 					doZoom(val1, pin1Dy0.getYVal(), val2, pin1Dy1.getYVal(), true, false,
983 							false, true, true);
984 				} else if (pw == pin1Dy01) { // also for 2D Z-range zoom
985 					doZoom(pin1Dx0.getXVal(), val1, pin1Dx1.getXVal(), val2, imageView == null, imageView == null,
986 							false, false, true);
987 				} else if (pw == pin2Dx01) {
988 					imageView.setView0(imageView.toPixelX0(val1), pin2Dy0.yPixel0,
989 							imageView.toPixelX0(val2), pin2Dy1.yPixel0);
990 					doZoom(val1, pin1Dy0.getYVal(), val2, pin1Dy1.getYVal(), false, false,
991 							false, true, true);
992 				} else if (pw == pin2Dy01) {
993 					imageView.setView0(pin2Dx0.xPixel0, imageView.toPixelY0(val1),
994 							pin2Dx1.xPixel0, imageView.toPixelY0(val2));
995 					doZoom(imageView.toX(imageView.xPixel0), getScale().minY, imageView
996 							.toX(imageView.xPixel0 + imageView.xPixels - 1), getScale().maxY,
997 							false, false, false, false, true);
998 				}
999 			} else {
1000 				double val = Double.valueOf(sval).doubleValue();
1001 				if (pw.isXtype) {
1002 					double val2 = (pw == pin1Dx0 || pw == cur2Dx0 || pw == pin2Dx0 ? pin1Dx1
1003 							.getXVal()
1004 							: pin1Dx0.getXVal());
1005 					//
1006 					doZoom(val, 0, val2, 0, !pw.is2D, false,
1007 							false, true, true);
1008 				} else if (pw == cur2Dy) {
1009 					setCurrentSubSpectrum((int) val);
1010 					// pd.repaint();
1011 				} else if (pw == pin2Dy0 || pw == pin2Dy1) {
1012 					int val2 = (pw == pin2Dy0 ? pin2Dy1.yPixel0 : pin2Dy0.yPixel0);
1013 					imageView.setView0(pin2Dx0.xPixel0, imageView.subIndexToPixelY((int) val),
1014 							pin2Dx1.xPixel0, val2);
1015 					// pd.repaint();
1016 				} else {
1017 					// 1D y-zoom
1018 					double val2 = (pw == pin1Dy0 ? pin1Dy1.getYVal() : pin1Dy0.getYVal());
1019 					doZoom(pin1Dx0.getXVal(), val, pin1Dx1.getXVal(), val2, imageView == null, imageView == null,
1020 						 false, false, true);
1021 				}
1022 			}
1023 		} catch (Exception e) {
1024 		}
1025 	}
1026 
removeAllHighlights(Spectrum spec)1027 	private void removeAllHighlights(Spectrum spec) {
1028 		if (spec == null)
1029 			highlights.clear();
1030 		else
1031 			for (int i = highlights.size(); --i >= 0;)
1032 				if (highlights.get(i).spectrum == spec)
1033 					highlights.removeItemAt(i);
1034 	}
1035 
setCoordClicked(int xPixel, double x, double y)1036 	private Coordinate setCoordClicked(int xPixel, double x, double y) {
1037 		if (y == 0)
1038 			nextClickForSetPeak = null;
1039 		if (Double.isNaN(x)) {
1040 			pd.coordClicked = null;
1041 			pd.coordsClicked = null;
1042 			return null;
1043 		}
1044 		pd.coordClicked = new Coordinate().set(lastClickX = x, y);
1045 		pd.coordsClicked = getSpectrum().getXYCoords();
1046 		pd.xPixelClicked = (lastPixelX = xPixel);
1047 		return pd.coordClicked;
1048 	}
1049 
1050 	/**
1051 	 * PlotWidgets are zoom boxes and slider points that are draggable. Some are
1052 	 * derived from others (center points and the 2D subIndex pointer). The first
1053 	 * time through, we have to create new pins. When the frame is resized, we
1054 	 * need to reset their positions along the slider based on their values, and
1055 	 * we need to also move the sliders to the right place.
1056 	 * @param needNewPins
1057 	 * @param subIndex
1058 	 * @param doDraw1DObjects
1059 	 */
setWidgets(boolean needNewPins, int subIndex, boolean doDraw1DObjects)1060 	private void setWidgets(boolean needNewPins, int subIndex,
1061 			boolean doDraw1DObjects) {
1062 		if (needNewPins || pin1Dx0 == null) {
1063 			if (zoomBox1D == null)
1064 				newPins();
1065 			else
1066 				resetPinPositions();
1067 		}
1068 		setDerivedPins(subIndex);
1069 		setPinSliderPositions(doDraw1DObjects);
1070 	}
1071 
1072 	/**
1073 	 * Create new pins and set their default values. Note that we are making a
1074 	 * distinction between view.minY and view.minYOnScale. For X these are now the
1075 	 * same, but for Y they are not. This produces a nicer grid, but also an odd
1076 	 * jumpiness in the Y slider that is not totally predictable.
1077 	 *
1078 	 */
newPins()1079 	private void newPins() {
1080 		zoomBox1D = new PlotWidget("zoomBox1D");
1081 		pin1Dx0 = new PlotWidget("pin1Dx0");
1082 		pin1Dx1 = new PlotWidget("pin1Dx1");
1083 		pin1Dy0 = new PlotWidget("pin1Dy0");
1084 		pin1Dy1 = new PlotWidget("pin1Dy1");
1085 		pin1Dx01 = new PlotWidget("pin1Dx01");
1086 		pin1Dy01 = new PlotWidget("pin1Dy01");
1087 		cur1D2x1 = new PlotWidget("cur1D2x1");
1088 		cur1D2x1.color = ScriptToken.PEAKTABCOLOR;
1089 		cur1D2x2 = new PlotWidget("cur1D2x2");
1090 		cur1D2x2.color = ScriptToken.PEAKTABCOLOR;
1091 		if (imageView != null) {
1092 			zoomBox2D = new PlotWidget("zoomBox2D");
1093 			// these pins only present when no 1D is present
1094 			pin2Dx0 = new PlotWidget("pin2Dx0");
1095 			pin2Dx1 = new PlotWidget("pin2Dx1");
1096 			pin2Dy0 = new PlotWidget("pin2Dy0");
1097 			pin2Dy1 = new PlotWidget("pin2Dy1");
1098 			pin2Dx01 = new PlotWidget("pin2Dx01");
1099 			pin2Dy01 = new PlotWidget("pin2Dy01");
1100 			// these pins only present when 1D and 2D
1101 			cur2Dx0 = new PlotWidget("cur2Dx0");
1102 			// these pins only present whenever 2D present
1103 			cur2Dx1 = new PlotWidget("cur2Dx1");
1104 			cur2Dy = new PlotWidget("cur2Dy");
1105 			pin2Dy0.setY(0, imageView.toPixelY0(0));
1106 			int n = getSpectrumAt(0).getSubSpectra().size();
1107 			pin2Dy1.setY(n, imageView.toPixelY0(n));
1108 		}
1109 		setWidgetX(pin1Dx0, getScale().minX);
1110 		setWidgetX(pin1Dx1, getScale().maxX);
1111 		setWidgetY(pin1Dy0, getScale().minY);
1112 		setWidgetY(pin1Dy1, getScale().maxY);
1113 
1114 		widgets = new PlotWidget[] { zoomBox1D, zoomBox2D, pin1Dx0, pin1Dx01,
1115 				pin1Dx1, pin1Dy0, pin1Dy01, pin1Dy1, pin2Dx0, pin2Dx01, pin2Dx1,
1116 				pin2Dy0, pin2Dy01, pin2Dy1, cur2Dx0, cur2Dx1, cur2Dy, cur1D2x1, cur1D2x2 };
1117 	}
1118 
setWidgetX(PlotWidget pw, double x)1119 	private void setWidgetX(PlotWidget pw, double x) {
1120 		pw.setX(x, toPixelX0(x));
1121 	}
1122 
setWidgetY(PlotWidget pw, double y)1123 	private void setWidgetY(PlotWidget pw, double y) {
1124 		pw.setY(y, toPixelY0(y));
1125 	}
1126 
resetPinsFromView()1127 	private void resetPinsFromView() {
1128 		if (pin1Dx0 == null)
1129 			return;
1130 		setWidgetX(pin1Dx0, getScale().minXOnScale);
1131 		setWidgetX(pin1Dx1, getScale().maxXOnScale);
1132 		setWidgetY(pin1Dy0, getScale().minYOnScale);
1133 		setWidgetY(pin1Dy1, getScale().maxYOnScale);
1134 	}
1135 
1136 	/**
1137 	 * use the pin values to find their positions along the slider
1138 	 *
1139 	 */
resetPinPositions()1140 	private void resetPinPositions() {
1141 	  resetX(pin1Dx0);
1142 	  resetY(pin1Dy0);
1143 	  resetY(pin1Dy1);
1144 		if (imageView == null) {
1145 			if (gs2dLinkedX != null)
1146 				resetX(cur1D2x1);
1147 			if (gs2dLinkedY != null)
1148 				resetX(cur1D2x2);
1149 		} else {
1150 			pin2Dy0.setY(pin2Dy0.getYVal(), imageView.toPixelY0(pin2Dy0.getYVal()));
1151 			pin2Dy1.setY(pin2Dy1.getYVal(), imageView.toPixelY0(pin2Dy1.getYVal()));
1152 		}
1153 	}
1154 
resetX(PlotWidget p)1155 	private void resetX(PlotWidget p) {
1156 		setWidgetX(p, p.getXVal());
1157 	}
1158 
resetY(PlotWidget p)1159 	private void resetY(PlotWidget p) {
1160 		setWidgetY(p, p.getYVal());
1161 	}
1162 
1163 	/**
1164 	 * realign sliders to proper locations after resizing
1165 	 *
1166 	 * @param doDraw1DObjects
1167 	 *
1168 	 */
setPinSliderPositions(boolean doDraw1DObjects)1169 	private void setPinSliderPositions(boolean doDraw1DObjects) {
1170 		pin1Dx0.yPixel0 = pin1Dx1.yPixel0 = pin1Dx01.yPixel0 = yPixel0 - 5;
1171 		pin1Dx0.yPixel1 = pin1Dx1.yPixel1 = pin1Dx01.yPixel1 = yPixel0;
1172 		cur1D2x1.yPixel1 = cur1D2x2.yPixel1 = yPixel0 - 5;
1173 		cur1D2x1.yPixel0 = cur1D2x2.yPixel0 = yPixel1 + 6;
1174 		if (imageView == null) {
1175 			pin1Dy0.xPixel0 = pin1Dy1.xPixel0 = pin1Dy01.xPixel0 = xPixel1 + 5;
1176 			pin1Dy0.xPixel1 = pin1Dy1.xPixel1 = pin1Dy01.xPixel1 = xPixel1;
1177 		} else {
1178 			pin1Dy0.xPixel0 = pin1Dy1.xPixel0 = pin1Dy01.xPixel0 = imageView.xPixel1 + 15;
1179 			pin1Dy0.xPixel1 = pin1Dy1.xPixel1 = pin1Dy01.xPixel1 = imageView.xPixel1 + 10;
1180 			pin2Dx0.yPixel0 = pin2Dx1.yPixel0 = pin2Dx01.yPixel0 = yPixel0 - 5;
1181 			pin2Dx0.yPixel1 = pin2Dx1.yPixel1 = pin2Dx01.yPixel1 = yPixel0;
1182 			pin2Dy0.xPixel0 = pin2Dy1.xPixel0 = pin2Dy01.xPixel0 = imageView.xPixel1 + 5;
1183 			pin2Dy0.xPixel1 = pin2Dy1.xPixel1 = pin2Dy01.xPixel1 = imageView.xPixel1;
1184 			cur2Dx0.yPixel0 = cur2Dx1.yPixel0 = yPixel1 + 6;
1185 			cur2Dx0.yPixel1 = cur2Dx1.yPixel1 = yPixel0 - 5;
1186 			cur2Dx0.yPixel0 = cur2Dx1.yPixel0 = yPixel1 + 6;
1187 			cur2Dx1.yPixel1 = cur2Dx1.yPixel1 = yPixel0 - 5;
1188 			cur2Dy.xPixel0 = (doDraw1DObjects ? (xPixel1 + imageView.xPixel0) / 2
1189 					: imageView.xPixel0 - 6);
1190 			cur2Dy.xPixel1 = imageView.xPixel1 + 5;
1191 		}
1192 	}
1193 
1194 	/**
1195 	 * The center pins and the 2D subspectrum slider values are derived from other
1196 	 * data
1197 	 *
1198 	 * @param subIndex
1199 	 */
setDerivedPins(int subIndex)1200 	private void setDerivedPins(int subIndex) {
1201     widgetsAreSet = true;
1202 		if (gs2dLinkedX != null)
1203 			cur1D2x1.setX(cur1D2x1.getXVal(), toPixelX(cur1D2x1.getXVal()));
1204 		if (gs2dLinkedY != null)
1205 			cur1D2x2.setX(cur1D2x2.getXVal(), toPixelX(cur1D2x2.getXVal()));
1206 
1207 		pin1Dx01.setX(0, (pin1Dx0.xPixel0 + pin1Dx1.xPixel0) / 2);
1208 		pin1Dy01.setY(0, (pin1Dy0.yPixel0 + pin1Dy1.yPixel0) / 2);
1209 		pin1Dx01.setEnabled(Math.min(pin1Dx0.xPixel0, pin1Dx1.xPixel0) > xPixel0
1210 				|| Math.max(pin1Dx0.xPixel0, pin1Dx1.xPixel0) < xPixel1);
1211 		// note that toPixelY uses userYFactor, which is spectrum-dependent.
1212 		// in a stacked set, this will be wrong. Perhaps no showing this pin1Dy01
1213 		// then?
1214 		pin1Dy01.setEnabled(Math.min(pin1Dy0.yPixel0, pin1Dy1.yPixel0) > Math.min(
1215 				toPixelY(getScale().minY), toPixelY(getScale().maxY))
1216 				|| Math.max(pin1Dy0.yPixel0, pin1Dy1.yPixel0) < Math.max(
1217 						toPixelY(getScale().minY), toPixelY(getScale().maxY)));
1218 		if (imageView == null)
1219 			return;
1220 		double x = pin1Dx0.getXVal();
1221 		cur2Dx0.setX(x, imageView.toPixelX(x));
1222 		x = pin1Dx1.getXVal();
1223 		cur2Dx1.setX(x, imageView.toPixelX(x));
1224 
1225 		x = imageView.toX(imageView.xPixel0);
1226 		pin2Dx0.setX(x, imageView.toPixelX0(x));
1227 		x = imageView.toX(imageView.xPixel1);
1228 		pin2Dx1.setX(x, imageView.toPixelX0(x));
1229 		pin2Dx01.setX(0, (pin2Dx0.xPixel0 + pin2Dx1.xPixel0) / 2);
1230 
1231 		double y = imageView.imageHeight - 1 - imageView.yView1;
1232 		pin2Dy0.setY(y, imageView.toPixelY0(y));
1233 		y = imageView.imageHeight - 1 - imageView.yView2;
1234 		pin2Dy1.setY(y, imageView.toPixelY0(y));
1235 		pin2Dy01.setY(0, (pin2Dy0.yPixel0 + pin2Dy1.yPixel0) / 2);
1236 
1237 		cur2Dy.yPixel0 = cur2Dy.yPixel1 = imageView.subIndexToPixelY(subIndex);
1238 
1239 		pin2Dx01
1240 				.setEnabled(Math.min(pin2Dx0.xPixel0, pin2Dx1.xPixel0) != imageView.xPixel0
1241 						|| Math.max(pin2Dx0.xPixel0, pin2Dx1.xPixel1) != imageView.xPixel1);
1242 		pin2Dy01.setEnabled(Math.min(pin2Dy0.yPixel0, pin2Dy1.yPixel0) != yPixel0
1243 				|| Math.max(pin2Dy0.yPixel0, pin2Dy1.yPixel1) != yPixel1);
1244 	}
1245 
1246 	/**
1247 	 * Zooms the spectrum between two coordinates
1248 	 *
1249 	 * @param initX
1250 	 *          the X start coordinate of the zoom area
1251 	 * @param initY
1252 	 *          the Y start coordinate of the zoom area
1253 	 * @param finalX
1254 	 *          the X end coordinate of the zoom area
1255 	 * @param finalY
1256 	 *          the Y end coordinate of the zoom area
1257 	 * @param is1D
1258 	 *          TODO
1259 	 * @param is1DY TODO
1260 	 * @param checkRange
1261 	 * @param checkLinked TODO
1262 	 * @param addZoom
1263 	 */
1264 	synchronized void doZoom(double initX, double initY, double finalX,
1265 			double finalY, boolean is1D, boolean is1DY,
1266 			boolean checkRange, boolean checkLinked, boolean addZoom) {
1267 		if (initX == finalX) {
1268 			initX = getScale().minXOnScale;
1269 		  finalX = getScale().maxXOnScale;
1270 		} else if (isLinked && checkLinked)
1271 		  pd.doZoomLinked(this, initX, finalX, addZoom, checkRange, is1D);
1272 		if (initX > finalX) {
1273 			double tempX = initX;
1274 			initX = finalX;
1275 			finalX = tempX;
1276 		}
1277 		if (initY > finalY) {
1278 			double tempY = initY;
1279 			initY = finalY;
1280 			finalY = tempY;
1281 		}
1282 
1283 		boolean is2DGrayScaleChange = (!is1D && imageView != null && (imageView.minZ != initY || imageView.maxZ != finalY));
1284 
1285 		if (!zoomEnabled && !is2DGrayScaleChange)
1286 			return;
1287 
1288 		// determine if the range of the area selected for zooming is within the
1289 		// plot
1290 		// area and if not ensure that it is
1291 
1292 		if (checkRange) {
1293 			if (!getScale().isInRangeX(initX)
1294 					&& !getScale().isInRangeX(finalX))
1295 				return;
1296 			if (!getScale().isInRangeX(initX)) {
1297 				initX = getScale().minX;
1298 			} else if (!getScale().isInRangeX(finalX)) {
1299 				finalX = getScale().maxX;
1300 			}
1301 		} else {
1302 			//viewData = viewList.get(0);
1303 		}
1304 		pd.setTaintedAll();
1305 		ScaleData[] viewScales = viewData.getScaleData();
1306 		int[] startIndices = new int[nSpectra];
1307 		int[] endIndices = new int[nSpectra];
1308 		graphsTemp.clear();
1309 		Lst<Spectrum> subspecs = getSpectrumAt(0).getSubSpectra();
1310 		boolean dontUseSubspecs = (subspecs == null || subspecs.size() == 2);
1311 		// NMR real/imaginary
1312 		boolean is2D = !getSpectrumAt(0).is1D();
1313 		if (!is2D && !dontUseSubspecs) {
1314 			graphsTemp.addLast(getSpectrum());
1315 			if (!ScaleData.setDataPointIndices(graphsTemp, initX, finalX,
1316 					minNumOfPointsForZoom, startIndices, endIndices))
1317 				return;
1318 		} else {
1319 			if (!ScaleData.setDataPointIndices(spectra, initX, finalX,
1320         minNumOfPointsForZoom, startIndices, endIndices))
1321       return;
1322 		}
1323 		double y1 = initY;
1324 		double y2 = finalY;
1325 		boolean isXOnly = (y1 == y2);
1326 		if (isXOnly) {
1327 			double f = (!is2DGrayScaleChange && is1D ? f = getScale().spectrumScaleFactor : 1);
1328 			if (Math.abs(f - 1) < 0.0001) {
1329 				y1 = getScale().minYOnScale;
1330 			  y2 = getScale().maxYOnScale;
1331 			}
1332 		}
1333 		ScaleData[] yScales = null;
1334 		if (isXOnly || is1DY) {
1335 			getCurrentView();
1336 			yScales = viewData.getNewScales(iSpectrumSelected, isXOnly, y1, y2);
1337 		}
1338 		getView(initX, finalX, y1, y2, startIndices, endIndices, viewScales, yScales);
1339 		setXPixelMovedTo(1E10, Double.MAX_VALUE, 0, 0);
1340 		setWidgetX(pin1Dx0, initX);
1341 		setWidgetX(pin1Dx1, finalX);
1342 		setWidgetY(pin1Dy0, y1);
1343 		setWidgetY(pin1Dy1, y2);
1344 		if (imageView == null) {
1345 			updateDialogs();
1346 		} else {
1347 			int isub = getSpectrumAt(0).getSubIndex();
1348 			int ifix = imageView.fixSubIndex(isub);
1349 			if (ifix != isub)
1350 				setCurrentSubSpectrum(ifix);
1351 			if (is2DGrayScaleChange)
1352 				update2dImage(false);
1353 		}
1354 		if (addZoom)
1355 			addCurrentZoom();
1356 		// if (doRepaint)
1357 		// pd.repaint();
1358 	}
1359 
updateDialogs()1360 	private void updateDialogs() {
1361 		updateDialog(AType.PeakList, -1);
1362 		updateDialog(AType.Measurements, -1);
1363 	}
1364 
setCurrentSubSpectrum(int i)1365 	private void setCurrentSubSpectrum(int i) {
1366 		Spectrum spec0 = getSpectrumAt(0);
1367 		i = spec0.setCurrentSubSpectrum(i);
1368 		if (spec0.isForcedSubset())
1369 			viewData.setXRangeForSubSpectrum(getSpectrum().getXYCoords());
1370 		pd.notifySubSpectrumChange(i, getSpectrum());
1371 	}
1372 
addCurrentZoom()1373 	private void addCurrentZoom() {
1374 		// add to and clean the zoom list
1375 		if (viewList.size() > currentZoomIndex + 1)
1376 			for (int i = viewList.size() - 1; i > currentZoomIndex; i--)
1377 				viewList.removeItemAt(i);
1378 		viewList.addLast(viewData);
1379 		currentZoomIndex++;
1380 	}
1381 
setZoomTo(int i)1382 	private void setZoomTo(int i) {
1383 		//imageView = null;
1384 		currentZoomIndex = i;
1385 		viewData = viewList.get(i);
1386 		resetPinsFromView();
1387 	}
1388 
1389 	/**
1390 	 * Clears all views in the zoom list
1391 	 */
clearViews()1392 	void clearViews() {
1393 		if (isLinked) {
1394 			pd.clearLinkViews(this);
1395 		}
1396 		setZoom(0, 0, 0, 0);
1397 		// leave first zoom
1398 		for (int i = viewList.size(); --i >= 1;)
1399 			viewList.removeItemAt(i);
1400 	}
1401 
1402 	/**
1403 	 * Principal drawing method
1404 	 *
1405 	 * @param gMain
1406 	 * @param gFront
1407 	 * @param gBack
1408 	 * @param iSplit
1409 	 * @param needNewPins
1410 	 * @param doAll
1411 	 * @param pointsOnly
1412 	 */
drawAll(Object gMain, Object gFront, Object gBack, int iSplit, boolean needNewPins, boolean doAll, boolean pointsOnly)1413 	private void drawAll(Object gMain, Object gFront, Object gBack, int iSplit,
1414 			boolean needNewPins, boolean doAll, boolean pointsOnly) {
1415 		g2d = pd.g2d; // may change when printing and testing JsPdfCreator
1416 		this.gMain = gMain;
1417 		Spectrum spec0 = getSpectrumAt(0);
1418 		int subIndex = spec0.getSubIndex();
1419 		is2DSpectrum = (!spec0.is1D()
1420 				&& (isLinked || pd.getBoolean(ScriptToken.DISPLAY2D)) && (imageView != null || get2DImage(spec0)));
1421 		if (imageView != null && doAll) {
1422 			if (pd.isPrinting && g2d != pd.g2d0)
1423 				g2d.newGrayScaleImage(gMain, image2D, imageView.imageWidth,
1424 						imageView.imageHeight, imageView.getBuffer());
1425 			if (is2DSpectrum)
1426 				setPositionForFrame(iSplit);
1427 			draw2DImage();
1428 		}
1429 		int iSelected = (stackSelected || !showAllStacked ? iSpectrumSelected : -1);
1430 		boolean doYScale = (!showAllStacked || nSpectra == 1 || iSelected >= 0);
1431 		boolean doDraw1DObjects = (imageView == null || pd.display1D);
1432 		int n = (iSelected >= 0 ? 1 : 0);
1433 		int iSpectrumForScale = getFixedSelectedSpectrumIndex();
1434 		if (doDraw1DObjects && doAll) {
1435 			fillBox(gMain, xPixel0, yPixel0, xPixel1, yPixel1,
1436 					ScriptToken.PLOTAREACOLOR);
1437 			if (iSelected < 0) {
1438 				doYScale = true;
1439 				for (int i = 0; i < nSpectra; i++)
1440 					if (doPlot(i, iSplit)) {
1441 						if (n++ == 0)
1442 							continue;
1443 						doYScale &= viewData.areYScalesSame(i - 1, i);
1444 					}
1445 			}
1446 		}
1447 		int iSpecForFrame = (nSpectra == 1 ? 0 : !showAllStacked ? iSpectrumMovedTo
1448 				: iSpectrumSelected);
1449 		Object g2 = (gBack == gMain ? gFront : gBack);
1450 		if (doAll) {
1451 			boolean addCurrentBox = (pd.getCurrentGraphSet() == this && !isLinked // not if this is linked
1452 					&& (!isSplittable || (nSplit == 1 || pd.currentSplitPoint == iSplit)));
1453 			boolean drawUpDownArrows = (zoomEnabled // must have zoom enabled
1454 					&& !isDrawNoSpectra() // must be drawing spectrum
1455 					&& pd.isCurrentGraphSet(this) // must be current
1456 					&& spectra.get(0).isScalable() // must be scalable
1457 					&& (addCurrentBox || nSpectra == 1) // must have a box or be just one
1458 																							// spectrum
1459 			&& (nSplit == 1 || pd.currentSplitPoint == iSpectrumMovedTo) // must have
1460 																																		// one panel
1461 																																		// or be the
1462 																																		// spectrum
1463 																																		// moved to
1464 			);
1465 			boolean addSplitBox = isSplittable;
1466 			drawFrame(gMain, iSpecForFrame, addCurrentBox, addSplitBox,
1467 					drawUpDownArrows);
1468 		}
1469 		if (pd.isCurrentGraphSet(this) // is current set
1470 				&& iSplit == pd.currentSplitPoint && (n < 2 // just one spectrum to show
1471 				|| iSpectrumSelected >= 0 // stacked and selected
1472 				))
1473 			haveSelectedSpectrum = true;
1474 		haveSingleYScale = (showAllStacked && nSpectra > 1 ? allowStackedYScale
1475 				&& doYScale : true);
1476 		if (doDraw1DObjects) {
1477 			int yOffsetPixels = (int) (yPixels * (yStackOffsetPercent / 100f));
1478 			haveLeftRightArrows = false;
1479 			for (int i = 0, offset = 0; i < nSpectra; i++) {
1480 				if (!doPlot(i, iSplit))
1481 					continue;
1482 				boolean isGrey = (stackSelected && iSpectrumSelected >= 0 && iSpectrumSelected != i);
1483 				IntegralData ig = (!reversePlot
1484 						&& getShowAnnotation(AType.Integration, i)
1485 						&& (!showAllStacked || iSpectrumSelected == i) ? (IntegralData) getDialog(
1486 						AType.Integration, i).getData()
1487 						: null);
1488 				setScale(i);
1489 				Spectrum spec = spectra.get(i);
1490 				if (nSplit > 1) {
1491 					iSpectrumForScale = i;
1492 				}
1493 				boolean doDrawWidgets = !isGrey
1494 						&& (nSplit == 1 || showAllStacked || iSpectrumSelected == iSplit);
1495 				boolean doDraw1DY = (doDrawWidgets && haveSelectedSpectrum && i == iSpectrumForScale);
1496 				if (doDrawWidgets) {
1497 					resetPinsFromView();
1498 					drawWidgets(gFront, g2, subIndex, needNewPins, doDraw1DObjects,
1499 							doDraw1DY, false);
1500 				}
1501 				if (haveSingleYScale && i == iSpectrumForScale && doAll) {
1502 					drawGrid(gMain);
1503 					if (pd.isPrinting && nSplit > 1)
1504 						drawSpectrumSource(gMain, i);
1505 				}
1506 				if (doDrawWidgets)
1507 					drawWidgets(gFront, g2, subIndex, false, doDraw1DObjects, doDraw1DY,
1508 							true);
1509 				if (!isDrawNoSpectra()
1510 						&& (nSpectra == 1 || iSpectrumSelected >= 0)
1511 						&& (haveSingleYScale && i == iSpectrumForScale
1512 						|| showAllStacked
1513 								&& stackSelected && i == iSpectrumSelected))
1514 					drawHighlightsAndPeakTabs(gFront, g2, i);
1515 				if (doAll) {
1516 					if (n == 1 && iSpectrumSelected < 0 || iSpectrumSelected == i
1517 							&& pd.isCurrentGraphSet(this)) {
1518 						if (pd.titleOn && !pd.titleDrawn) {
1519 							pd.drawTitle(gMain, height, width, pd.getDrawTitle(pd.isPrinting));
1520 							pd.titleDrawn = true;
1521 						}
1522 					}
1523 					if (haveSingleYScale && i == iSpectrumForScale) {
1524 						if (pd.getBoolean(ScriptToken.YSCALEON))
1525 							drawYScale(gMain, this);
1526 						if (pd.getBoolean(ScriptToken.YUNITSON))
1527 							drawYUnits(gMain);
1528 					}
1529 				}
1530 				boolean isContinuous = spec.isContinuous();
1531 				boolean onSpectrum = ((nSplit > 1 ? i == iSpectrumMovedTo : isLinked
1532 						|| i == iSpectrumForScale)
1533 						&& !pd.isPrinting && isContinuous);
1534 				boolean hasPendingIntegral = (!isGrey && pendingIntegral != null && spec == pendingIntegral.spec);
1535 				if (doAll || hasPendingIntegral) {
1536 					drawPlot(hasPendingIntegral && !doAll ? gFront : gMain, i, spec, isContinuous, offset, isGrey, null, onSpectrum, hasPendingIntegral, pointsOnly);
1537 				}
1538 				drawIntegration(gFront, i, offset, isGrey, ig, isContinuous, onSpectrum);
1539 				drawMeasurements(gFront, i);
1540 				if (pendingMeasurement != null && pendingMeasurement.spec == spec)
1541 					drawMeasurement(gFront, pendingMeasurement);
1542 				if (onSpectrum && xPixelMovedTo >= 0) {
1543 					drawSpectrumPointer(gFront, spec, offset, ig);
1544 				}
1545 				if (nSpectra > 1 && nSplit == 1 && pd.isCurrentGraphSet(this) && doAll) {
1546 					haveLeftRightArrows = true;
1547 					if (!pd.isPrinting) {
1548 						setScale(0);
1549 						iSpecForFrame = (iSpectrumSelected);
1550 						if (nSpectra != 2) {
1551 							setPlotColor(gMain, (iSpecForFrame + nSpectra - 1) % nSpectra);
1552 							fillArrow(gMain, ARROW_LEFT, yHArrows, xHArrows - 9, true);
1553 							setCurrentBoxColor(gMain);
1554 							fillArrow(gMain, ARROW_LEFT, yHArrows, xHArrows - 9, false);
1555 						}
1556 						if (iSpecForFrame >= 0) {
1557 							setPlotColor(gMain, iSpecForFrame);
1558 							fillCircle(gMain, xHArrows, yHArrows, true);
1559 						}
1560 						setCurrentBoxColor(gMain);
1561 						fillCircle(gMain, xHArrows, yHArrows, false);
1562 						setPlotColor(gMain, (iSpecForFrame + 1) % nSpectra);
1563 						fillArrow(gMain, ARROW_RIGHT, yHArrows, xHArrows + 9, true);
1564 						setCurrentBoxColor(gMain);
1565 						fillArrow(gMain, ARROW_RIGHT, yHArrows, xHArrows + 9, false);
1566 					}
1567 				}
1568 				offset -= yOffsetPixels;
1569 			}
1570 			if (doAll) {
1571 				if (pd.getBoolean(ScriptToken.XSCALEON))
1572 					drawXScale(gMain, this);
1573 				if (pd.getBoolean(ScriptToken.XUNITSON))
1574 					drawXUnits(gMain);
1575 			}
1576 		} else {
1577 			if (doAll) {
1578 				if (pd.getBoolean(ScriptToken.XSCALEON))
1579 					drawXScale(gMain, imageView);
1580 				if (pd.getBoolean(ScriptToken.YSCALEON))
1581 					drawYScale(gMain, imageView);
1582 				if (subIndex >= 0)
1583 					draw2DUnits(gMain);
1584 			}
1585 			drawWidgets(gFront, g2, subIndex, needNewPins, doDraw1DObjects, true,
1586 					false);
1587 			// no 2D grid?
1588 			drawWidgets(gFront, g2, subIndex, needNewPins, doDraw1DObjects, true,
1589 					true);
1590       widgetsAreSet = true;
1591 		}
1592 		if (annotations != null)
1593 			drawAnnotations(gFront, annotations, null);
1594 	}
1595 
drawSpectrumSource(Object g, int i)1596 	private void drawSpectrumSource(Object g, int i) {
1597 		pd.printFilePath(g, pd.thisWidth - pd.right, yPixel0, spectra.get(i).getFilePath());
1598 	}
1599 
doPlot(int i, int iSplit)1600 	private boolean doPlot(int i, int iSplit) {
1601 		boolean isGrey = (stackSelected && iSpectrumSelected >= 0 && iSpectrumSelected != i);
1602 		boolean ok = (showAllStacked || iSpectrumSelected == -1 || iSpectrumSelected == i);
1603 		return (nSplit > 1 ? i == iSplit : ok && (!pd.isPrinting || !isGrey));
1604 	}
1605 
1606 //	private void hideAllDialogsExceptCurrent() {
1607 //		if (dialogs == null)
1608 //			return;
1609 //		boolean getInt = false;
1610 //		boolean getMeas = false;
1611 //		boolean getPeak = false;
1612 //		AnnotationData ad;
1613 //
1614 //		for (Map.Entry<String, AnnotationData> e : dialogs.entrySet()) {
1615 //			ad = e.getValue();
1616 //			if (isVisible(ad)) {
1617 //				// ((AnnotationDialog) ad).setVisible(false);
1618 //				switch (ad.getAType()) {
1619 //				case Integration:
1620 //					getInt = true;
1621 //					break;
1622 //				case Measurements:
1623 //					getMeas = true;
1624 //					break;
1625 //				case PeakList:
1626 //					getPeak = true;
1627 //					break;
1628 //				case NONE:
1629 //				}
1630 //			}
1631 //		}
1632 //		if (getInt)
1633 //			ad = jsvp.showDialog(AType.Integration);
1634 //		if (getMeas)
1635 //			ad = jsvp.showDialog(AType.Measurements);
1636 //		if (getPeak)
1637 //			ad = jsvp.showDialog(AType.PeakList);
1638 //
1639 //	}
1640 
drawSpectrumPointer(Object gFront, Spectrum spec, int yOffset, IntegralData ig)1641 	private void drawSpectrumPointer(Object gFront, Spectrum spec,
1642 			int yOffset, IntegralData ig) {
1643 	  // short vertical cursor
1644 		setColorFromToken(gFront, ScriptToken.PEAKTABCOLOR);
1645 		int iHandle = pd.integralShiftMode;
1646 		if (ig != null) {
1647 			if ((!pd.ctrlPressed || pd.isIntegralDrag)
1648 					&& !isOnSpectrum(pd.mouseX, pd.mouseY, -1)) {
1649 				ig = null;
1650 			} else if (iHandle == 0) {
1651 				iHandle = getShiftMode(pd.mouseX, pd.mouseY);
1652 				if (iHandle == 0)
1653 				  iHandle = Integer.MAX_VALUE;
1654 			}
1655 		}
1656 		double y0 = yValueMovedTo;
1657 		yValueMovedTo = (ig == null ? spec.getYValueAt(xValueMovedTo) : ig
1658 				.getPercentYValueAt(xValueMovedTo));
1659 		setCoordStr(xValueMovedTo, yValueMovedTo);
1660 		if (iHandle != 0) {
1661       setPlotColor(gFront, iHandle == Integer.MAX_VALUE ? -1 : 0);
1662 		  if (iHandle < 0 || iHandle == Integer.MAX_VALUE) {
1663 		     drawHandle(gFront, xPixelPlot1, yPixelPlot0, 3, false);
1664 		  }
1665 		  if (iHandle > 0) {
1666         drawHandle(gFront, xPixelPlot0, yPixelPlot1, 3, false);
1667 		  }
1668 		  if (iHandle != Integer.MAX_VALUE)
1669 		  	return;
1670 		}
1671 		if (ig != null)
1672 		  g2d.setStrokeBold(gFront, true);
1673 
1674 		if (Double.isNaN(y0) || pendingMeasurement != null) {
1675 			g2d.drawLine(gFront, xPixelMovedTo, yPixel0, xPixelMovedTo, yPixel1);
1676 			if (xPixelMovedTo2 >= 0)
1677 				g2d.drawLine(gFront, xPixelMovedTo2, yPixel0, xPixelMovedTo2, yPixel1);
1678 			yValueMovedTo = Double.NaN;
1679 		} else {
1680 			int y = (ig == null ? yOffset + toPixelY(yValueMovedTo)
1681 					: toPixelYint(yValueMovedTo / 100));
1682 			if (y == fixY(y))
1683 				g2d.drawLine(gFront, xPixelMovedTo, y - 10, xPixelMovedTo, y + 10);
1684 		}
1685 		if (ig != null)
1686 			g2d.setStrokeBold(gFront, false);
1687 	}
1688 
setScale(int i)1689 	void setScale(int i) {
1690 		viewData.setScale(i, xPixels, yPixels, spectra.get(i).isInverted());
1691 	}
1692 
draw2DUnits(Object g)1693 	private void draw2DUnits(Object g) {
1694 		String nucleusX = getSpectrumAt(0).nucleusX;
1695 		String nucleusY = getSpectrumAt(0).nucleusY;
1696 		setColorFromToken(g, ScriptToken.PLOTCOLOR);
1697 		drawUnits(g, nucleusX, imageView.xPixel1 + 5 * pd.scalingFactor, yPixel1, 1, 1.0);
1698 		drawUnits(g, nucleusY, imageView.xPixel0 - 5 * pd.scalingFactor, yPixel0, 1, 0);
1699 	}
1700 
drawPeakTabs(Object gFront, Object g2, Spectrum spec)1701 	private void drawPeakTabs(Object gFront, Object g2, Spectrum spec) {
1702 		Lst<PeakInfo> list = (nSpectra == 1 || iSpectrumSelected >= 0 ? spec
1703 				.getPeakList() : null);
1704 		if (list != null && list.size() > 0) {
1705 			if (piMouseOver != null && piMouseOver.spectrum == spec && pd.isMouseUp()) {
1706 				g2d.setGraphicsColor(g2, g2d.getColor4(240, 240, 240, 140)); // very faint gray box
1707 				drawPeak(g2, piMouseOver, 0);
1708 				spec.setHighlightedPeak(piMouseOver);
1709 			} else {
1710 			  spec.setHighlightedPeak(null);
1711 			}
1712 			setColorFromToken(gFront, ScriptToken.PEAKTABCOLOR);
1713 			for (int i = list.size(); --i >= 0;) {
1714 				PeakInfo p = list.get(i);
1715 				drawPeak(gFront, p, p == spec.getSelectedPeak() ? 14 : 7);
1716 			}
1717 		}
1718 	}
1719 
drawPeak(Object g, PeakInfo pi, int tickSize)1720 	private void drawPeak(Object g, PeakInfo pi, int tickSize) {
1721 		if (pd.isPrinting)
1722 			return;
1723 		double xMin = pi.getXMin();
1724 		double xMax = pi.getXMax();
1725 		if (xMin == xMax)
1726 			return;
1727 		drawBar(g, pi, xMin, xMax, null, tickSize);
1728 	}
1729 
1730 	/**
1731 	 *
1732 	 * Draw sliders, pins, and zoom boxes (only one of which would ever be drawn)
1733 	 *
1734 	 * @param gFront
1735 	 * @param gBack
1736 	 * @param subIndex
1737 	 * @param needNewPins
1738 	 * @param doDraw1DObjects
1739 	 * @param doDraw1DY
1740 	 *          TODO
1741 	 * @param postGrid
1742 	 */
drawWidgets(Object gFront, Object gBack, int subIndex, boolean needNewPins, boolean doDraw1DObjects, boolean doDraw1DY, boolean postGrid)1743 	private void drawWidgets(Object gFront, Object gBack, int subIndex, boolean needNewPins,
1744 			boolean doDraw1DObjects, boolean doDraw1DY, boolean postGrid) {
1745 		setWidgets(needNewPins, subIndex, doDraw1DObjects);
1746 		if (pd.isPrinting && (imageView == null ? !cur1D2Locked : sticky2Dcursor))
1747 			return;
1748 		// boolean allowPin1y = true;//(nSplit > 1 || iSpectrumSelected < 0 ||
1749 		// nSpectra == 1 || nSplit == 1 && !stackSelected);
1750 		if (!pd.isPrinting && !postGrid) {
1751 			// top/side slider bar backgrounds
1752 			if (doDraw1DObjects) {
1753 				fillBox(gFront, xPixel0, pin1Dx0.yPixel1, xPixel1, pin1Dx1.yPixel1 + 2,
1754 						ScriptToken.GRIDCOLOR);
1755 				fillBox(gFront, pin1Dx0.xPixel0, pin1Dx0.yPixel1, pin1Dx1.xPixel0,
1756 						pin1Dx1.yPixel1 + 2, ScriptToken.PLOTCOLOR);
1757 			} else {
1758 
1759 				fillBox(gFront, imageView.xPixel0, pin2Dx0.yPixel1, imageView.xPixel1,
1760 						pin2Dx0.yPixel1 + 2, ScriptToken.GRIDCOLOR);
1761 				fillBox(gFront, pin2Dx0.xPixel0, pin2Dx0.yPixel1, pin2Dx1.xPixel0,
1762 						pin2Dx1.yPixel1 + 2, ScriptToken.PLOTCOLOR);
1763 				fillBox(gFront, pin2Dy0.xPixel1, yPixel1, pin2Dy1.xPixel1 + 2, yPixel0,
1764 						ScriptToken.GRIDCOLOR);
1765 				fillBox(gFront, pin2Dy0.xPixel1, pin2Dy0.yPixel1, pin2Dy1.xPixel1 + 2,
1766 						pin2Dy1.yPixel0, ScriptToken.PLOTCOLOR);
1767 			}
1768 			fillBox(gFront, pin1Dy0.xPixel1, yPixel1, pin1Dy1.xPixel1 + 2, yPixel0,
1769 					ScriptToken.GRIDCOLOR);
1770 			if (doDraw1DY)
1771 				fillBox(gFront, pin1Dy0.xPixel1, pin1Dy0.yPixel1, pin1Dy1.xPixel1 + 2,
1772 						pin1Dy1.yPixel0, ScriptToken.PLOTCOLOR);
1773 		}
1774 		for (int i = 0; i < widgets.length; i++) {
1775 			PlotWidget pw = widgets[i];
1776 			if (pw == null || !pw.isPinOrCursor && !zoomEnabled)
1777 				continue;
1778 			boolean isLockedCursor = (pw == cur1D2x1 || pw == cur1D2x2
1779 					|| pw == cur2Dx0 || pw == cur2Dx1 || pw == cur2Dy);
1780 			if ((pw.isPin || !pw.isPinOrCursor) == postGrid)
1781 				continue;
1782 			if (pw.is2D) {
1783 				if (pw == cur2Dx0 && !doDraw1DObjects)
1784 					continue;
1785 			} else {
1786 				boolean isPin1Dy = (pw == pin1Dy0 || pw == pin1Dy1 || pw == pin1Dy01);
1787 				if ((imageView != null && doDraw1DObjects == isPin1Dy)
1788 				|| isPin1Dy && !doDraw1DY
1789 				|| pw == cur1D2x1 && gs2dLinkedX == null
1790 				|| pw == cur1D2x2	&& gs2dLinkedY == null
1791 				|| pw == zoomBox1D && (pd.isIntegralDrag || pd.integralShiftMode != 0)
1792 				) {
1793 					if (!isLinked || imageView != null)
1794 						continue;
1795 				}
1796 			}
1797 			if (pd.isPrinting && !isLockedCursor)
1798 				continue;
1799 			if (pw.isPinOrCursor) {
1800 				setColorFromToken(gFront, pw.color);
1801 				g2d.drawLine(gFront, pw.xPixel0, pw.yPixel0, pw.xPixel1, pw.yPixel1);
1802 				pw.isVisible = true;
1803 				if (pw.isPin)
1804 					drawHandle(gFront, pw.xPixel0, pw.yPixel0, 2, !pw.isEnabled);
1805 			} else if (pw.xPixel1 != pw.xPixel0) {
1806 
1807 
1808 				fillBox(gBack, pw.xPixel0, pw.yPixel0, pw.xPixel1, pw.yPixel1,
1809 						pw == zoomBox1D && pd.shiftPressed ? ScriptToken.ZOOMBOXCOLOR2 : ScriptToken.ZOOMBOXCOLOR);
1810 			}
1811 		}
1812 	}
1813 
1814 
1815 	/**
1816 	 * draw a bar, but not necessarily full height
1817 	 *
1818 	 * @param g
1819 	 * @param pi
1820 	 * @param xMin
1821 	 *          units
1822 	 * @param xMax
1823 	 *          units
1824 	 * @param whatColor
1825 	 * @param tickSize
1826 	 */
1827 
drawBar(Object g, PeakInfo pi, double xMin, double xMax, ScriptToken whatColor, int tickSize)1828 	private void drawBar(Object g, PeakInfo pi, double xMin, double xMax,
1829 			ScriptToken whatColor, int tickSize) {
1830 
1831 		double r = xMax + xMin;
1832 		double d = Math.abs(xMax - xMin);
1833 		double range = Math.abs(toX(xPixel1) - toX(xPixel0));
1834 		if (false && tickSize > 0 && d > range / 20) {
1835 			d = range / 20;
1836 			xMin = r / 2 - d/2;
1837 			xMax = r / 2 + d/2;
1838 		}
1839 
1840 		int x1 = toPixelX(xMin);
1841 		int x2 = toPixelX(xMax);
1842 		if (x1 > x2) {
1843 			int tmp = x1;
1844 			x1 = x2;
1845 			x2 = tmp;
1846 		}
1847 		// if either pixel is outside of plot area
1848 		x1 = fixX(x1);
1849 		x2 = fixX(x2);
1850 		if (x2 - x1 < 3) {
1851 			x1 -= 2;
1852 			x2 += 2;
1853 		}
1854 		if (pi != null)
1855 			pi.setPixelRange(x1, x2);
1856 		if (tickSize == 0) {
1857 			fillBox(g, x1, yPixel0, x2, yPixel0 + yPixels, whatColor);
1858 		} else {
1859 			fillBox(g, x1, yPixel0+2, x2, yPixel0 + 5, whatColor);
1860 			if (pi != null) {
1861 				x1 = (x1 + x2) / 2;
1862 				fillBox(g, x1 - 1, yPixel0 + 2, x1 + 1, yPixel0 + 2 + tickSize, whatColor);
1863 			}
1864 		}
1865 
1866 	}
1867 
1868 	/**
1869 	 * Draws the plot on the Panel
1870 	 *
1871 	 * @param gFront
1872 	 *          the <code>Graphics</code> object
1873 	 * @param index
1874 	 *          the index of the Spectrum to draw
1875 	 * @param yOffset
1876 	 * @param isGrey
1877 	 * @param iData
1878 	 * @param isContinuous
1879 	 * @param isSelected
1880 	 */
drawIntegration(Object gFront, int index, int yOffset, boolean isGrey, IntegralData iData, boolean isContinuous, boolean isSelected)1881 	private void drawIntegration(Object gFront, int index, int yOffset, boolean isGrey,
1882 			IntegralData iData, boolean isContinuous, boolean isSelected) {
1883 		// Check if specInfo in null or xyCoords is null
1884 		if (iData != null) {
1885 			if (haveIntegralDisplayed(index))
1886 				drawPlot(gFront, index, spectra.get(index), true, yOffset, false, iData, true, false, false);
1887 			drawIntegralValues(gFront, index, yOffset);
1888 		}
1889 		Lst<Annotation> ratios = getIntegrationRatios(index);
1890 		if (ratios!= null)
1891 			drawAnnotations(gFront, ratios,
1892 					ScriptToken.INTEGRALPLOTCOLOR);
1893 	}
1894 
getMeasurements(AType type, int iSpec)1895 	private MeasurementData getMeasurements(AType type, int iSpec) {
1896 		AnnotationData ad = getDialog(type, iSpec);
1897 		return (ad == null || ad.getData().size() == 0 || !ad.getState() ? null : ad.getData());
1898 	}
1899 
drawPlot(Object g, int index, Spectrum spec, boolean isContinuous, int yOffset, boolean isGrey, IntegralData ig, boolean isSelected, boolean hasPendingIntegral, boolean pointsOnly)1900 	private void drawPlot(Object g, int index, Spectrum spec,
1901 			boolean isContinuous, int yOffset, boolean isGrey, IntegralData ig,
1902 			boolean isSelected, boolean hasPendingIntegral, boolean pointsOnly) {
1903 		Coordinate[] xyCoords = (ig == null ? spec.getXYCoords()
1904 				: getIntegrationGraph(index).getXYCoords());
1905 		boolean isIntegral = (ig != null);
1906 		BS bsDraw = (isIntegral ? ig.getBitSet() : null);
1907 		boolean fillPeaks = (hasPendingIntegral || spec.fillColor != null
1908 				&& isSelected);
1909 		int iColor = (isGrey ? COLOR_BLACK : isIntegral ? COLOR_INTEGRAL : !allowStacking ? 0 : index);
1910 		setPlotColor(g, iColor);
1911 		boolean plotOn = true;
1912 		int y0 = toPixelY(0);
1913 		if (isIntegral)
1914 			fillPeaks &= (y0 == fixY(y0));
1915 		else
1916 			y0 = fixY(y0);
1917 		GenericColor cInt = (isIntegral || fillPeaks ? pd
1918 				.getColor(ScriptToken.INTEGRALPLOTCOLOR) : null);
1919 		GenericColor cFill = (cInt == null || spec.fillColor == null ? cInt
1920 				: spec.fillColor);
1921 		int iFirst = viewData.getStartingPointIndex(index);
1922 		int iLast = viewData.getEndingPointIndex(index);
1923 		if (isContinuous && !pointsOnly) {
1924 			iLast--;
1925 			// all graphics can do line to for now
1926 			boolean doLineTo = (isIntegral || pendingIntegral != null)
1927 					&& g2d.canDoLineTo();
1928 			if (doLineTo)
1929 				g2d.doStroke(g, true);
1930 			boolean isDown = false;
1931 			for (int i = iFirst; i <= iLast; i++) {
1932 				Coordinate point1 = xyCoords[i];
1933 				Coordinate point2 = xyCoords[i + 1];
1934 				int y1 = (isIntegral ? toPixelYint(point1.getYVal()) : toPixelY(point1
1935 						.getYVal()));
1936 				if (y1 == Integer.MIN_VALUE)
1937 					continue;
1938 				int y2 = (isIntegral ? toPixelYint(point2.getYVal()) : toPixelY(point2
1939 						.getYVal()));
1940 				if (y2 == Integer.MIN_VALUE)
1941 					continue;
1942 				double xv1 = point1.getXVal();
1943 				double xv2 = point2.getXVal();
1944 				int x1 = toPixelX(xv1);
1945 				int x2 = toPixelX(xv2);
1946 				y1 = fixY(yOffset + y1);
1947 				y2 = fixY(yOffset + y2);
1948 				if (isIntegral) {
1949 					if (i == iFirst) {
1950 						xPixelPlot1 = x1;
1951 						yPixelPlot0 = y1;
1952 					}
1953 					xPixelPlot0 = x2;
1954 					yPixelPlot1 = y2;
1955 				}
1956 				if (x2 == x1 && y1 == y2)
1957 					continue;
1958 				if (fillPeaks && hasPendingIntegral
1959 						&& pendingIntegral.overlaps(xv1, xv2)) {
1960 					if (cFill != null) {
1961 						g2d.doStroke(g, false);
1962 						g2d.setGraphicsColor(g, cFill);
1963 					}
1964 					g2d.fillRect(g, Math.min(x1, x2), Math.min(y0, y1),
1965 							Math.max(1, Math.abs(x2 - x1)), Math.abs(y0 - y1));
1966 					if (cFill != null) {
1967 						g2d.doStroke(g, false);
1968 						g2d.doStroke(g, true);
1969 						isDown = false;
1970 						setPlotColor(g, iColor);
1971 					}
1972 					continue;
1973 				}
1974 				if (y1 == y2 && (y1 == yPixel0)) {
1975 					continue;
1976 				}
1977 				if (bsDraw != null && bsDraw.get(i) != plotOn) {
1978 					plotOn = bsDraw.get(i);
1979 					if (doLineTo && isDown) {
1980 						g2d.doStroke(g, false);
1981 						g2d.doStroke(g, true);
1982 						isDown = false;
1983 					}
1984 					if (!pd.isPrinting && pd.integralShiftMode != 0)
1985 						setPlotColor(g, 0);
1986 					else if (plotOn)
1987 						setColorFromToken(g, ScriptToken.INTEGRALPLOTCOLOR);
1988 					else
1989 						setPlotColor(g, COLOR_GREY);
1990 				}
1991 				if (pd.isPrinting && !plotOn)
1992 					continue;
1993 				if (isDown) {
1994 					g2d.lineTo(g, x2, y2);
1995 				} else {
1996 					g2d.drawLine(g, x1, y1, x2, y2);
1997 					isDown = doLineTo;
1998 				}
1999 			}
2000 			if (doLineTo)
2001 				g2d.doStroke(g, false);
2002 		} else {
2003 			for (int i = iFirst; i <= iLast; i++) {
2004 				Coordinate point = xyCoords[i];
2005 				int y2 = toPixelY(point.getYVal());
2006 				if (y2 == Integer.MIN_VALUE)
2007 					continue;
2008 				int x1 = toPixelX(point.getXVal());
2009 				int y1 = toPixelY(Math.max(getScale().minYOnScale, 0));
2010 				y1 = fixY(yOffset + y1);
2011 				y2 = fixY(yOffset + y2);
2012 				if (y1 == y2 && (y1 == yPixel0 || y1 == yPixel1))
2013 					continue;
2014 				if (pointsOnly)
2015           g2d.fillRect(g, x1-1, y2-1, 3, 3);
2016 				else
2017 				  g2d.drawLine(g, x1, y1, x1, y2);
2018 			}
2019 			if (!pointsOnly && getScale().isYZeroOnScale()) {
2020 				int y = yOffset + toPixelY(getScale().spectrumYRef);
2021 				if (y == fixY(y))
2022 					g2d.drawLine(g, xPixel1, y, xPixel0, y);
2023 			}
2024 		}
2025 	}
2026 
2027 	/**
2028 	 *
2029 	 * @param g
2030 	 * @param iSpec
2031 	 * @param addCurrentBox
2032 	 * @param addSplitBox
2033 	 * @param drawUpDownArrows
2034 	 */
drawFrame(Object g, int iSpec, boolean addCurrentBox, boolean addSplitBox, boolean drawUpDownArrows)2035 	private void drawFrame(Object g, int iSpec,
2036 			boolean addCurrentBox, boolean addSplitBox, boolean drawUpDownArrows) {
2037 		if (!pd.gridOn || pd.isPrinting) {
2038 			setColorFromToken(g, ScriptToken.GRIDCOLOR);
2039 			g2d.drawRect(g, xPixel0, yPixel0, xPixels, yPixels);
2040 			if (pd.isPrinting)
2041 				return;
2042 		}
2043 
2044 
2045 		setCurrentBoxColor(g);
2046 		if (drawUpDownArrows) {
2047 			if (iSpec >= 0) {
2048 				setPlotColor(g, iSpec);
2049 				fillArrow(g, ARROW_UP, xVArrows,
2050 						(yPixel00 + yPixel11) / 2 - 9, true);
2051 				fillArrow(g, ARROW_DOWN, xVArrows,
2052 						(yPixel00 + yPixel11) / 2 + 9, true);
2053 				setCurrentBoxColor(g);
2054 			}
2055 			fillArrow(g, ARROW_UP, xVArrows, (yPixel00 + yPixel11) / 2 - 9,
2056 					false);
2057 			fillCircle(g, xVArrows, (yPixel00 + yPixel11) / 2, false);
2058 			fillArrow(g, ARROW_DOWN, xVArrows,
2059 					(yPixel00 + yPixel11) / 2 + 9, false);
2060 		}
2061 
2062 		if (imageView != null)
2063 			return;
2064 		if (addCurrentBox) {
2065 			int x1 = xPixel00 + 10;
2066 			int x2 = xPixel11 - 10;
2067 			int y1 = yPixel00 + 1;
2068 			int y2 = yPixel11 - 2;
2069 			g2d.drawLine(g, x1, y1, x2, y1);
2070 			g2d.drawLine(g, x2, y1, x2, y2);
2071 			g2d.drawLine(g, x1, y2, x2, y2);
2072 			splitterX = closerX = Integer.MIN_VALUE;
2073 			drawBox(g, x2 - 10, y1, x2, y1 + 10, null);
2074 			g2d.drawLine(g, x2 - 10, y1 + 10, x2, y1);
2075 			g2d.drawLine(g, x2, y1 + 10, x2 - 10, y1);
2076 			closerX = x2 - 10;
2077 			closerY = y1;
2078 			if (addSplitBox) {
2079 				x2 -= 10;
2080 				fillBox(g, x2 - 10, y1, x2, y1 + 10, null);
2081 				splitterX = x2 - 10;
2082 				splitterY = y1;
2083 
2084 			}
2085 
2086 		}
2087 	}
2088 
2089 	/**
2090 	 * Draws the grid on the Panel
2091 	 *
2092 	 * @param g
2093 	 *          the <code>Graphics</code> object
2094 	 */
drawGrid(Object g)2095 	private void drawGrid(Object g) {
2096 		if (!pd.gridOn || imageView != null)
2097 			return;
2098 		setColorFromToken(g, ScriptToken.GRIDCOLOR);
2099 		double lastX;
2100 		if (Double.isNaN(getScale().firstX)) {
2101 			lastX = getScale().maxXOnScale + getScale().steps[0] / 2;
2102 			for (double val = getScale().minXOnScale; val < lastX; val += getScale().steps[0]) {
2103 				int x = toPixelX(val);
2104 				g2d.drawLine(g, x, yPixel0, x, yPixel1);
2105 			}
2106 		} else {
2107 			lastX = getScale().maxXOnScale * 1.0001;
2108 			for (double val = getScale().firstX; val <= lastX; val += getScale().steps[0]) {
2109 				int x = toPixelX(val);
2110 				g2d.drawLine(g, x, yPixel0, x, yPixel1);
2111 			}
2112 		}
2113 		for (double val = getScale().firstY; val < getScale().maxYOnScale
2114 				+ getScale().steps[1] / 2; val += getScale().steps[1]) {
2115 			int y = toPixelY(val);
2116 			if (y == fixY(y))
2117 				g2d.drawLine(g, xPixel0, y, xPixel1, y);
2118 		}
2119 	}
2120 
2121 	Map<Double, String> mapX = new Hashtable<Double, String>();
2122 
2123 	/**
2124 	 * Draws the x Scale
2125 	 *
2126 	 * @param g
2127 	 *          the <code>Graphics</code> object
2128 	 * @param c
2129 	 *          could be 'this' or imageView
2130 	 */
drawXScale(Object g, XYScaleConverter c)2131 	private void drawXScale(Object g, XYScaleConverter c) {
2132 
2133 		setColorFromToken(g, ScriptToken.SCALECOLOR);
2134 		if (pd.isPrinting)
2135 			g2d.drawLine(g, c.getXPixel0(), yPixel1, c.getXPixel0() + c.getXPixels() - 1, yPixel1);
2136 		int precision = getScale().precision[0];
2137 		Font font = pd.setFont(g, c.getXPixels(), FONT_PLAIN, pd.isPrinting ? 10 : 12, false);
2138 		int y1 = yPixel1;
2139 		int y2 = yPixel1 + 4 * pd.scalingFactor;
2140 		int y3 = yPixel1 + 2 * pd.scalingFactor;
2141 
2142 		int h = font.getHeight();
2143 		double dx = c.toPixelX(getScale().steps[0]) - c.toPixelX(0);
2144 		double maxWidth = Math.abs(dx * 0.95);
2145 		// we go overboard for ticks
2146 		double firstX = getScale().firstX - getScale().steps[0];
2147 		double lastX = (getScale().maxXOnScale + getScale().steps[0]) * 1.0001;
2148 		for (int pass = 0; pass < 2; pass++) {
2149 			if (pass == 1)
2150 				ScaleData.fixScale(mapX);
2151 			double prevX = 1e10;
2152 			for (double val = firstX; val <= lastX; val += getScale().steps[0]) {
2153 				int x = c.toPixelX(val);
2154 				Double d = Double.valueOf(val);
2155 				String s;
2156 				switch (pass) {
2157 				case 0:
2158 					s = DF.formatDecimalDbl(val, precision);
2159 					mapX.put(d, s);
2160 					drawTick(g, x, y1, y2, c);
2161 					dx = Math.abs(prevX - val);
2162 					int ntick = getScale().minorTickCounts[0];
2163 					if (ntick != 0) {
2164 						double step = dx / ntick;
2165 						for (int i = 1; i < ntick; i++) {
2166 							double x1 = val - i * step;
2167 							drawTick(g, c.toPixelX(x1), y1, y3, c);
2168 						}
2169 					}
2170 					prevX = val;
2171 					continue;
2172 				case 1:
2173 					s = mapX.get(d);
2174 					if (s == null || x != c.fixX(x))
2175 						continue;
2176 					int w = pd.getStringWidth(s);
2177 					int n = (x + w / 2 == c.fixX(x + w / 2) ? 2 : 0);
2178 					if (n > 0)
2179 						g2d.drawString(g, s, x - w / n, y2 + h);
2180 					val += Math.floor(w / maxWidth) * getScale().steps[0];
2181 					break;
2182 				}
2183 			}
2184 		}
2185 		mapX.clear();
2186 	}
2187 
drawTick(Object g, int x, int y1, int y2, XYScaleConverter c)2188 	private void drawTick(Object g, int x, int y1, int y2, XYScaleConverter c) {
2189 		if (x == c.fixX(x))
2190 			g2d.drawLine(g, x, y1, x, y2);
2191 	}
2192 
2193 	/**
2194 	 * Draws the y Scale
2195 	 *
2196 	 * @param g
2197 	 *          the <code>Graphics</code> object
2198 	 * @param c
2199 	 */
drawYScale(Object g, XYScaleConverter c)2200 	private void drawYScale(Object g, XYScaleConverter c) {
2201 
2202 		ScaleData sd = c.getScale();
2203 		int precision = sd.precision[1];
2204 		Font font = pd.setFont(g, c.getXPixels(), FONT_PLAIN, pd.isPrinting ? 10 : 12, false);
2205 		int h = font.getHeight();
2206 		double max = sd.maxYOnScale + sd.steps[1] / 2;
2207 		int yLast = Integer.MIN_VALUE;
2208 		setColorFromToken(g, ScriptToken.SCALECOLOR);
2209 		for (int pass = 0; pass < 2; pass++) {
2210 			if (pass == 1)
2211 				ScaleData.fixScale(mapX);
2212 			for (double val = sd.firstY; val < max; val += sd.steps[1]) {
2213 				Double d = Double.valueOf(val);
2214 				int x1 = c.getXPixel0();
2215 				int y = c.toPixelY(val);
2216 				if (y != c.fixY(y))
2217 					continue;
2218 				String s;
2219 				if (pass == 0)
2220 					g2d.drawLine(g, x1, y, x1 - 3 * pd.scalingFactor, y);
2221 				if (Math.abs(y - yLast) <= h)
2222 					continue;
2223 				yLast = y;
2224 				switch (pass) {
2225 				case 0:
2226 					s = DF.formatDecimalDbl(val, precision);
2227 					mapX.put(d, s);
2228 					break;
2229 				case 1:
2230 					s = mapX.get(d);
2231 					if (s == null)
2232 						continue;
2233 					if (s.startsWith("0") && s.contains("E"))
2234 						s = "0";
2235 					g2d.drawString(g, s, (x1 - 4 * pd.scalingFactor - pd.getStringWidth(s)), y + h / 3);
2236 					break;
2237 				}
2238 			}
2239 		}
2240 		mapX.clear();
2241 	}
2242 
2243 	/**
2244 	 * Draws the X Units
2245 	 *
2246 	 * @param g
2247 	 *          the <code>Graphics</code> object
2248 	 */
drawXUnits(Object g)2249 	private void drawXUnits(Object g) {
2250 		String units = spectra.get(0).getAxisLabel(true);
2251 		if (units != null)
2252 			drawUnits(g, units, xPixel1 + 25 * pd.scalingFactor, yPixel1 + 5 * pd.scalingFactor, 1, 1);
2253 	}
2254 
drawUnits(Object g, String s, int x, int y, double hOff, double vOff)2255 	private void drawUnits(Object g, String s, int x, int y, double hOff,
2256 			double vOff) {
2257 		setColorFromToken(g, ScriptToken.UNITSCOLOR);
2258 		pd.setFont(g, (imageView == null ? this : imageView).getXPixels(), FONT_ITALIC | FONT_BOLD, 10, false);
2259 		g2d.drawString(g, s, (int) (x - pd.getStringWidth(s) * hOff),
2260 				(int) (y + pd.getFontHeight() * vOff));
2261 
2262 	}
2263 
2264 	/**
2265 	 * Draws the Y Units
2266 	 *
2267 	 * @param g
2268 	 *          the <code>Graphics</code> object
2269 	 */
drawYUnits(Object g)2270 	private void drawYUnits(Object g) {
2271 		String units = spectra.get(0).getAxisLabel(false);
2272 		if (units != null)
2273 			drawUnits(g, units, (pd.isPrinting ? 30 : 5) * pd.scalingFactor, yPixel0 + (pd.isPrinting ? 0 : 5)  * pd.scalingFactor, 0, -1);
2274 	}
2275 
2276 	/**
2277 	 *
2278 	 * @param gFront graphics for peak tabs
2279 	 * @param gBack  graphics for highlight boxes
2280 	 * @param iSpec
2281 	 */
drawHighlightsAndPeakTabs(Object gFront, Object gBack, int iSpec)2282 	private void drawHighlightsAndPeakTabs(Object gFront, Object gBack, int iSpec) {
2283 		MeasurementData md = getMeasurements(AType.PeakList, iSpec);
2284 		Spectrum spec = spectra.get(iSpec);
2285 		if (pd.isPrinting) {
2286 			if (md != null) {
2287 				setColorFromToken(gFront, ScriptToken.PEAKTABCOLOR);
2288 				printPeakList(gFront, spec, (PeakData) md);
2289 			}
2290 			return;
2291 		}
2292 		if (md == null) {
2293 			for (int i = 0; i < highlights.size(); i++) {
2294 				Highlight hl = highlights.get(i);
2295 				if (hl.spectrum == spec) {
2296 					pd.setHighlightColor(hl.color);
2297 					drawBar(gBack, null, hl.x1, hl.x2, ScriptToken.HIGHLIGHTCOLOR, 0);
2298 				}
2299 			}
2300 			if (pd.peakTabsOn)
2301 				drawPeakTabs(gFront, gBack, spec);
2302 		}
2303 		int y;
2304 		if (md != null) {
2305 			y = (spec.isInverted() ? yPixel1 - 10 * pd.scalingFactor : yPixel0);
2306 			setColorFromToken(gFront, ScriptToken.PEAKTABCOLOR);
2307 			for (int i = md.size(); --i >= 0;) {
2308 				Measurement m = md.get(i);
2309 				int x = toPixelX(m.getXVal());
2310 				g2d.drawLine(gFront, x, y, x, y + 10 * pd.scalingFactor);
2311 			}
2312 			if (isVisible(getDialog(AType.PeakList, iSpec))) {
2313 				y = toPixelY(((PeakData) md).getThresh());
2314 				if (y == fixY(y) && !pd.isPrinting)
2315 					g2d.drawLine(gFront, xPixel0, y, xPixel1, y);
2316 			}
2317 		}
2318 	}
2319 
printPeakList(Object g, Spectrum spec, PeakData data)2320 	private void printPeakList(Object g, Spectrum spec, PeakData data) {
2321 		String[][] sdata = data.getMeasurementListArray(null);
2322 		if (sdata.length == 0)
2323 			return;
2324 		pd.setFont(g, xPixels, FONT_PLAIN, 8, false);
2325 		int h = pd.getFontHeight();
2326 		int[] xs = new int[data.size()];
2327 		int[] xs0 = new int[data.size()];
2328 		int dx = 0;
2329 		int s5 = 5 * pd.scalingFactor;
2330 		int s10 = 10 * pd.scalingFactor;
2331 		int s15 = 15 * pd.scalingFactor;
2332 		int s25 = 25 * pd.scalingFactor;
2333 		for (int i = 0; i < sdata.length; i++) {
2334 			xs0[i] = toPixelX(Double.parseDouble(sdata[i][1]));
2335 			if (i == 0) {
2336 				xs[i] = xs0[i];
2337 				continue;
2338 			}
2339 			xs[i] = Math.max(xs[i - 1] + h, xs0[i] + h);
2340 			dx += (xs[i] - xs0[i]);
2341 		}
2342 		dx /= 2 * sdata.length;
2343 		if (xs[0] - dx < xPixel0 + s25)
2344 			dx = xs[0] - (xPixel0 + s25);
2345 		for (int i = 0; i < sdata.length; i++)
2346 			xs[i] -= dx;
2347 
2348 		boolean inverted = spec.isInverted();
2349 		int y4 = pd.getStringWidth("99.9999");
2350 		int y2 = (sdata[0].length >= 6 ? pd.getStringWidth("99.99") : 0);
2351 		int f = (inverted ? -1 : 1);
2352 
2353 		int y = (inverted ? yPixel1 : yPixel0) + f * (y2 + y4 + s15);
2354 		for (int i = 0; i < sdata.length; i++) {
2355 			g2d.drawLine(g, xs[i], y, xs[i], y + s5 * f);
2356 			g2d.drawLine(g, xs[i], y + s5 * f, xs0[i], y + s10 * f);
2357 			g2d.drawLine(g, xs0[i], y + s10 * f, xs0[i], y + s15 * f);
2358 			if (y2 > 0 && sdata[i][4].length() > 0)
2359 				g2d.drawLine(g, (xs[i] + xs[i - 1]) / 2, y - y4 + s5,
2360 						(xs[i] + xs[i - 1]) / 2, y - y4 - s5);
2361 		}
2362 
2363 		y -= f * 2 * pd.scalingFactor;
2364 
2365 		if (y2 > 0) {
2366   		drawStringRotated(g, -90, xs[0] - s15, y, "  ppm");
2367 	  	drawStringRotated(g, -90, xs[0] - s15, y - y4 - s5, " Hz");
2368 		}
2369 		for (int i = data.size(); --i >= 0;) {
2370 			drawStringRotated(g, -90 * f, xs[i] + f * h / 3, y, sdata[i][1]);
2371 			if (y2 > 0 && sdata[i][4].length() > 0) {
2372 				int x = (xs[i] + xs[i - 1]) / 2 + h / 3;
2373 				drawStringRotated(g, -90, x, y - y4 - s5, sdata[i][4]);
2374 			}
2375 		}
2376 	}
2377 
drawStringRotated(Object g, int angle, int x, int y, String s)2378 	private void drawStringRotated(Object g, int angle, int x, int y, String s) {
2379 		g2d.drawStringRotated(g, s, x, y, angle);
2380 	}
2381 
2382 	// determine whether there are any ratio annotations to draw
drawAnnotations(Object g, Lst<Annotation> annotations, ScriptToken whatColor)2383 	private void drawAnnotations(Object g, Lst<Annotation> annotations,
2384 			ScriptToken whatColor) {
2385 		pd.setFont(g, xPixels, FONT_BOLD, 18, false);
2386 		for (int i = annotations.size(); --i >= 0;) {
2387 			Annotation note = annotations.get(i);
2388 			setAnnotationColor(g, note, whatColor);
2389 			XYScaleConverter c = (note.is2D ? imageView : this);
2390 			int x = c.toPixelX(note.getXVal());
2391 			int y = (note.isPixels() ? (int) (yPixel0 + 10 + 10 * pd.scalingFactor - note.getYVal())
2392 					: note.is2D ? imageView.subIndexToPixelY((int) note.getYVal())
2393 							: toPixelY(note.getYVal()));
2394 			g2d.drawString(g, note.text, x + note.offsetX * pd.scalingFactor, y - note.offsetY * pd.scalingFactor);
2395 		}
2396 	}
2397 
drawIntegralValues(Object g, int iSpec, int yOffset)2398 	private void drawIntegralValues(Object g, int iSpec, int yOffset) {
2399 		MeasurementData integrals = getMeasurements(AType.Integration, iSpec);
2400 		if (integrals != null) {
2401 			if (pd.isPrinting)
2402 				pd.setFont(g, xPixels, FONT_PLAIN, 8, false);
2403 			else
2404 				pd.setFont(g, xPixels, FONT_BOLD, 12, false);
2405 			setColorFromToken(g, ScriptToken.INTEGRALPLOTCOLOR);
2406 			int h = pd.getFontHeight();
2407 			g2d.setStrokeBold(g, true);
2408 			for (int i = integrals.size(); --i >= 0;) {
2409 				Measurement in = integrals.get(i);
2410 				if (in.getValue() == 0)
2411 					continue;
2412 				int x = toPixelX(in.getXVal2());
2413 				int y1 = yOffset * pd.scalingFactor + toPixelYint(in.getYVal());
2414 				int y2 = yOffset * pd.scalingFactor + toPixelYint(in.getYVal2());
2415 				if (x != fixX(x) || y1 != fixY(y1) || y2 != fixY(y2))
2416 					continue;
2417 
2418 				if (!pd.isPrinting)
2419 					g2d.drawLine(g, x, y1, x, y2);
2420 				String s = "  " + in.text;
2421 				g2d.drawString(g, s, x, (y1 + y2) / 2 + h / 3);
2422 			}
2423 			g2d.setStrokeBold(g, false);
2424 		}
2425 		if (iSpec == getFixedSelectedSpectrumIndex())
2426 			selectedSpectrumIntegrals = integrals;
2427 	}
2428 
drawMeasurements(Object g, int iSpec)2429 	private void drawMeasurements(Object g, int iSpec) {
2430 		MeasurementData md = getMeasurements(AType.Measurements, iSpec);
2431 		if (md != null)
2432 			for (int i = md.size(); --i >= 0;)
2433 				drawMeasurement(g, md.get(i));
2434 		if (iSpec == getFixedSelectedSpectrumIndex())
2435 			selectedSpectrumMeasurements = md;
2436 	}
2437 
drawMeasurement(Object g, Measurement m)2438 	private void drawMeasurement(Object g, Measurement m) {
2439 		if (m.text.length() == 0 && m != pendingMeasurement)
2440 			return;
2441 		pd.setFont(g, xPixels, FONT_BOLD, 12, false);
2442 		g2d.setGraphicsColor(g, (m == pendingMeasurement ? pd
2443 				.getColor(ScriptToken.PEAKTABCOLOR) : pd.BLACK));
2444 		int x1 = toPixelX(m.getXVal());
2445 		int y1 = toPixelY(m.getYVal());
2446 		int x2 = toPixelX(m.getXVal2());
2447 		if (Double.isNaN(m.getXVal()) || x1 != fixX(x1) || x2 != fixX(x2))
2448 			return;
2449 		boolean drawString = (Math.abs(x1 - x2) >= 2);
2450 		boolean drawBaseLine = getScale().isYZeroOnScale() && m.spec.isHNMR();
2451 		int x = (x1 + x2) / 2;
2452 		g2d.setStrokeBold(g, true);
2453 		if (drawString)
2454 			g2d.drawLine(g, x1, y1, x2, y1);
2455 		if (drawBaseLine)
2456 			g2d.drawLine(g, x1 + 1, yPixel1 - 1, x2, yPixel1 - 1);
2457 		g2d.setStrokeBold(g, false);
2458 		if (drawString)
2459 			g2d.drawString(g, m.text, x + m.offsetX, y1 - m.offsetY);
2460 		if (drawBaseLine) {
2461 			g2d.drawLine(g, x1, yPixel1, x1, yPixel1 - 6 * pd.scalingFactor);
2462 			g2d.drawLine(g, x2, yPixel1, x2, yPixel1 - 6 * pd.scalingFactor);
2463 		}
2464 	}
2465 
getPinSelected(int xPixel, int yPixel)2466 	private PlotWidget getPinSelected(int xPixel, int yPixel) {
2467 		if (widgets != null)
2468 			for (int i = 0; i < widgets.length; i++) {
2469 				if (widgets[i] != null && widgets[i].isPinOrCursor
2470 						&& widgets[i].selected(xPixel, yPixel)) {
2471 					return widgets[i];
2472 				}
2473 			}
2474 		return null;
2475 	}
2476 
set2DCrossHairs(int xPixel, int yPixel)2477   void set2DCrossHairs(int xPixel, int yPixel) {
2478   	double x;
2479 		if (xPixel == imageView.fixX(xPixel) && yPixel == fixY(yPixel)) {
2480 			pin1Dx1.setX(x = imageView.toX(xPixel), toPixelX(x));
2481 			cur2Dx1.setX(x, xPixel);
2482 			setCurrentSubSpectrum(imageView.toSubspectrumIndex(yPixel));
2483 		  if (isLinked) {
2484 		  	double y = imageView.toY(yPixel);
2485 		  	pd.set2DCrossHairsLinked(this, x, y, !sticky2Dcursor);
2486 		  }
2487 		}
2488 	}
2489 
reset2D(boolean isX)2490 	private void reset2D(boolean isX) {
2491 		if (isX) {
2492 			imageView.setView0(imageView.xPixel0, pin2Dy0.yPixel0, imageView.xPixel1,
2493 					pin2Dy1.yPixel0);
2494 			doZoom(0, getScale().minY, 0, getScale().maxY,
2495 					true, false, false, false, true);
2496 		} else {
2497 			imageView.setView0(pin2Dx0.xPixel0, imageView.yPixel0, pin2Dx1.xPixel0,
2498 					imageView.yPixel1);
2499 			// pd.repaint();
2500 		}
2501 	}
2502 
setAnnotationText(Annotation a)2503 	private boolean setAnnotationText(Annotation a) {
2504 		String sval = pd.getInput("New text?", "Set Label", a.text);
2505 		if (sval == null)
2506 			return false;
2507 		if (sval.length() == 0)
2508 			annotations.removeObj(a);
2509 		else
2510 			a.text = sval;
2511 		return true;
2512 	}
2513 
2514 	/**
2515 	 * @param x1 start of integral or NaN to clear
2516 	 * @param x2 end of (pending) integral or NaN to split
2517 	 * @param isFinal
2518 	 * @return true if successful
2519 	 *
2520 	 *
2521 	 *
2522 	 */
checkIntegral(double x1, double x2, boolean isFinal)2523 	private boolean checkIntegral(double x1, double x2, boolean isFinal) {
2524 		AnnotationData ad = getDialog(AType.Integration, -1);
2525 		if (ad == null)
2526 			return false;
2527 		Integral integral = ((IntegralData) ad.getData()).addIntegralRegion(x1, x2);
2528 		if (isFinal && ad.isDialog())
2529 			((JSVDialog) ad).update(null, 0, 0);
2530 
2531 		if (Double.isNaN(x2))
2532 		  return false;
2533 		pendingIntegral = (isFinal ? null : integral);
2534 		pd.isIntegralDrag = !isFinal;
2535 		selectedSpectrumIntegrals = null;
2536 		return true;
2537 	}
2538 
setToolTipForPixels(int xPixel, int yPixel)2539 	private void setToolTipForPixels(int xPixel, int yPixel) {
2540 
2541 
2542 		if (iSpectrumMovedTo != iSpectrumClicked || pd.getCurrentGraphSet() != this) {
2543 			pd.setToolTipText("click spectrum to activate");
2544 			return;
2545 		}
2546 		if (isSplitWidget(xPixel, yPixel)) {
2547 			pd.setToolTipText("click to " + (nSplit > 1 ? "combine" : "split"));
2548 			return;
2549 		}
2550 		if (isCloserWidget(xPixel, yPixel)) {
2551 			pd.setToolTipText("click to close");
2552 			return;
2553 		}
2554 
2555 		PlotWidget pw = getPinSelected(xPixel, yPixel);
2556 		int precisionX = getScale().precision[0];
2557 	  int precisionY = getScale().precision[1];
2558 
2559 		if (pw != null) {
2560 			if (setStartupPinTip())
2561 				return;
2562 			String s;
2563 			if (pw == pin1Dx01 || pw == pin2Dx01) {
2564 				s = DF.formatDecimalDbl(Math.min(pin1Dx0.getXVal(), pin1Dx1.getXVal()), precisionX)
2565 						+ " - "
2566 						+ DF.formatDecimalDbl(Math.max(pin1Dx0.getXVal(), pin1Dx1.getXVal()), precisionX);
2567 			} else if (pw == pin1Dy01) {
2568 				s = DF.formatDecimalDbl(Math.min(pin1Dy0.getYVal(), pin1Dy1.getYVal()), precisionY)
2569 						+ " - "
2570 						+ DF.formatDecimalDbl(Math.max(pin1Dy0.getYVal(), pin1Dy1.getYVal()), precisionY);
2571 			} else if (pw == cur2Dy) {
2572 				int isub = imageView.toSubspectrumIndex(pw.yPixel0);
2573 				s = get2DYLabel(isub, precisionX);
2574 			} else if (pw == pin2Dy01) {
2575 				s = "" + (int) Math.min(pin2Dy0.getYVal(), pin2Dy1.getYVal()) + " - "
2576 						+ (int) Math.max(pin2Dy0.getYVal(), pin2Dy1.getYVal());
2577 			} else if (pw.isXtype) {
2578 				s = DF.formatDecimalDbl(pw.getXVal(), precisionX);
2579 			} else if (pw.is2D) {
2580 				s = "" + (int) pw.getYVal();
2581 			} else {
2582 				s = DF.formatDecimalDbl(pw.getYVal(), precisionY);
2583 			}
2584 			pd.setToolTipText(s);
2585 			return;
2586 		}
2587 
2588 		double yPt;
2589 		if (imageView != null) {
2590 			if (imageView.fixX(xPixel) == xPixel && fixY(yPixel) == yPixel) {
2591 
2592 				int isub = imageView.toSubspectrumIndex(yPixel);
2593 				String s = "y=" + get2DYLabel(isub, precisionX) +
2594 							" / x=" + DF.formatDecimalDbl(imageView.toX(xPixel), precisionX) + " "
2595 						+ getSpectrum().getAxisLabel(true);
2596 				pd.setToolTipText(s);
2597 				pd.coordStr = s;
2598 				return;
2599 			}
2600 			if (!pd.display1D) {
2601 				pd.setToolTipText("");
2602 				pd.coordStr = "";
2603 				return;
2604 			}
2605 		}
2606 		double xPt = toX(fixX(xPixel));
2607 		yPt = (imageView != null && imageView.isXWithinRange(xPixel) ? imageView
2608 				.toSubspectrumIndex(fixY(yPixel)) : toY(fixY(yPixel)));
2609 		String xx = setCoordStr(xPt, yPt);
2610 		int iSpec = getFixedSelectedSpectrumIndex();
2611 		if (!isInPlotRegion(xPixel, yPixel)) {
2612 			yPt = Double.NaN;
2613 		} else if (nSpectra == 1) {
2614 			// I have no idea what I was thinking here...
2615 			// if (!getSpectrum().isHNMR()) {
2616 			// yPt = spectra[0].getPercentYValueAt(xPt);
2617 			// xx += ", " + formatterY.format(yPt);
2618 			// }
2619 		} else if (haveIntegralDisplayed(iSpec)) {
2620 			yPt = getIntegrationGraph(iSpec).getPercentYValueAt(xPt);
2621 			xx += ", " + DF.formatDecimalDbl(yPt, 1);
2622 		}
2623 		pd.setToolTipText(
2624 						(selectedIntegral != null  ? "click to set value" :
2625 							pendingMeasurement != null || selectedMeasurement != null ?
2626 								(pd.hasFocus() ? "Press ESC to delete "
2627 										+ (selectedIntegral != null ? "integral, DEL to delete all visible, or N to normalize"
2628 													: pendingMeasurement == null ? "\"" + selectedMeasurement.text + "\" or DEL to delete all visible"
2629 															: "measurement")
2630 						: "")
2631 						: Double.isNaN(yPt) ? null : xx)
2632 
2633 				// + " :" + iSpectrumSelected + " :" + iSpectrumMovedTo
2634 
2635 				);
2636 	}
2637 
isFrameBox(int xPixel, int yPixel, int boxX, int boxY)2638 	private boolean isFrameBox(int xPixel, int yPixel, int boxX, int boxY) {
2639 		return Math.abs(xPixel - (boxX + 5)) < 5 && Math.abs(yPixel - (boxY + 5)) < 5;
2640 	}
2641 
setCoordStr(double xPt, double yPt)2642 	private String setCoordStr(double xPt, double yPt) {
2643 		String xx = DF.formatDecimalDbl(xPt, getScale().precision[0]);
2644 		pd.coordStr = "("
2645 				+ xx
2646 				+ (haveSingleYScale || iSpectrumSelected >= 0 ? ", "
2647 						+ DF.formatDecimalDbl(yPt, getScale().precision[1]) : "") + ")";
2648 
2649 		return xx;
2650 	}
2651 
setStartupPinTip()2652 	private boolean setStartupPinTip() {
2653 		if (pd.startupPinTip == null)
2654 			return false;
2655 		pd.setToolTipText(pd.startupPinTip);
2656 		pd.startupPinTip = null;
2657 		return true;
2658 	}
2659 
get2DYLabel(int isub, int precision)2660 	private String get2DYLabel(int isub, int precision) {
2661 		Spectrum spec = getSpectrumAt(0).getSubSpectra().get(isub);
2662 			return DF.formatDecimalDbl(spec.getY2DPPM(), precision) + " PPM" +
2663 					(spec.y2DUnits.equals("HZ") ? " (" + DF.formatDecimalDbl(spec.getY2D(), precision)
2664 							+ " HZ) " : "");
2665 	}
2666 
isOnSpectrum(int xPixel, int yPixel, int index)2667 	private boolean isOnSpectrum(int xPixel, int yPixel, int index) {
2668 		Coordinate[] xyCoords = null;
2669 		boolean isContinuous = true;
2670 		boolean isIntegral = (index < 0);
2671 
2672 		// ONLY getSpectrumAt(0).is1D();
2673 		if (isIntegral) {
2674 			AnnotationData ad = getDialog(AType.Integration, -1);
2675 			if (ad == null)
2676 				return false;
2677 			xyCoords = ((IntegralData) ad.getData()).getXYCoords();
2678 			index = getFixedSelectedSpectrumIndex();
2679 		} else {
2680 			setScale(index);
2681 			Spectrum spec = spectra.get(index);
2682 			xyCoords = spec.xyCoords;
2683 			isContinuous = spec.isContinuous();
2684 		}
2685 		int yOffset = index * (int) (yPixels * (yStackOffsetPercent / 100f));
2686 
2687 		int ix0 = viewData.getStartingPointIndex(index);
2688 		int ix1 = viewData.getEndingPointIndex(index);
2689 		if (isContinuous) {
2690 			for (int i = ix0; i < ix1; i++) {
2691 				Coordinate point1 = xyCoords[i];
2692 				Coordinate point2 = xyCoords[i + 1];
2693 				int x1 = toPixelX(point1.getXVal());
2694 				int x2 = toPixelX(point2.getXVal());
2695 				int y1 = (isIntegral ? toPixelYint(point1.getYVal()) : toPixelY(point1
2696 						.getYVal()));
2697 				int y2 = (isIntegral ? toPixelYint(point2.getYVal()) : toPixelY(point2
2698 						.getYVal()));
2699 				if (y1 == Integer.MIN_VALUE || y2 == Integer.MIN_VALUE)
2700 					continue;
2701 				y1 = fixY(y1) - yOffset;
2702 				y2 = fixY(y2) - yOffset;
2703 				if (isOnLine(xPixel, yPixel, x1, y1, x2, y2))
2704 					return true;
2705 			}
2706 		} else {
2707 			for (int i = ix0; i <= ix1; i++) {
2708 				Coordinate point = xyCoords[i];
2709 				int y2 = toPixelY(point.getYVal());
2710 				if (y2 == Integer.MIN_VALUE)
2711 					continue;
2712 				int x1 = toPixelX(point.getXVal());
2713 				int y1 = toPixelY(Math.max(getScale().minYOnScale, 0));
2714 				y1 = fixY(y1);
2715 				y2 = fixY(y2);
2716 				if (y1 == y2 && (y1 == yPixel0 || y1 == yPixel1))
2717 					continue;
2718 				if (isOnLine(xPixel, yPixel, x1, y1, x1, y2))
2719 					return true;
2720 			}
2721 		}
2722 		return false;
2723 	}
2724 
2725 	// static methods
2726 
distance(int dx, int dy)2727 	private static double distance(int dx, int dy) {
2728 		return Math.sqrt(dx * dx + dy * dy);
2729 	}
2730 
findCompatibleGraphSet(Lst<GraphSet> graphSets, Spectrum spec)2731 	private static GraphSet findCompatibleGraphSet(Lst<GraphSet> graphSets,
2732 			Spectrum spec) {
2733 		for (int i = 0; i < graphSets.size(); i++)
2734 			if (Spectrum.areXScalesCompatible(spec, graphSets.get(i).getSpectrum(),
2735 					false, false))
2736 				return graphSets.get(i);
2737 		return null;
2738 	}
2739 
isGoodEvent(PlotWidget zOrP, PlotWidget p, boolean asX)2740 	private static boolean isGoodEvent(PlotWidget zOrP, PlotWidget p, boolean asX) {
2741 		return (p == null ? (Math.abs(zOrP.xPixel1 - zOrP.xPixel0) > MIN_DRAG_PIXELS && Math
2742 				.abs(zOrP.yPixel1 - zOrP.yPixel0) > MIN_DRAG_PIXELS)
2743 				: asX ? Math.abs(zOrP.xPixel0 - p.xPixel0) > MIN_DRAG_PIXELS : Math
2744 						.abs(zOrP.yPixel0 - p.yPixel0) > MIN_DRAG_PIXELS);
2745 	}
2746 
2747 	private final static int ONLINE_CUTOFF = 2;
2748 
isOnLine(int xPixel, int yPixel, int x1, int y1, int x2, int y2)2749 	private static boolean isOnLine(int xPixel, int yPixel, int x1, int y1,
2750 			int x2, int y2) {
2751 		// near a point
2752 		int dx1 = Math.abs(x1 - xPixel);
2753 		if (dx1 < ONLINE_CUTOFF && Math.abs(y1 - yPixel) < ONLINE_CUTOFF)
2754 			return true;
2755 		int dx2 = x2 - xPixel;
2756 		if (Math.abs(dx2) < ONLINE_CUTOFF && Math.abs(y2 - yPixel) < ONLINE_CUTOFF)
2757 			return true;
2758 		// between points
2759 		int dy12 = y1 - y2;
2760 		if (Math.abs(dy12) > ONLINE_CUTOFF && (y1 < yPixel) == (y2 < yPixel))
2761 			return false;
2762 		int dx12 = x1 - x2;
2763 		if (Math.abs(dx12) > ONLINE_CUTOFF && (x1 < xPixel) == (x2 < xPixel))
2764 			return false;
2765 		return (distance(dx1, y1 - yPixel) + distance(dx2, yPixel - y2) < distance(
2766 				dx12, dy12)
2767 				+ ONLINE_CUTOFF);
2768 	}
2769 
2770 	/**
2771 	 *
2772 	 * @param pd
2773 	 * @param graphSets
2774 	 * @param linkMode
2775 	 *            NONE   -   a vertical stack
2776 	 *            AB     -   a COSY, with 1H on left and 2D on right
2777 	 *            ABC    -   a HETCOR, with 1H and 13C on left, 2D on right
2778 	 *
2779 	 */
setFractionalPositions(PanelData pd, Lst<GraphSet> graphSets, LinkMode linkMode)2780 	private static void setFractionalPositions(PanelData pd, Lst<GraphSet> graphSets,
2781 			LinkMode linkMode) {
2782 
2783 		int n = graphSets.size();
2784 		double f = 0;
2785 		int n2d = 1;
2786 		GraphSet gs;
2787 		double y = 0;
2788 		pd.isLinked = (linkMode != LinkMode.NONE);
2789 		if (linkMode == LinkMode.NONE) {
2790 			// for now, just a vertical stack
2791 			for (int i = 0; i < n; i++) {
2792 				gs = graphSets.get(i);
2793 				f += (gs.getSpectrumAt(0).is1D() ? 1 : n2d) * gs.nSplit;
2794 			}
2795 			f = 1 / f;
2796 			for (int i = 0; i < n; i++) {
2797 				gs = graphSets.get(i);
2798 				gs.isLinked = false;
2799 				double g = (gs.getSpectrumAt(0).is1D() ? f : n2d * f);
2800 				gs.fX0 = 0;
2801 				gs.fY0 = y;
2802 				gs.fracX = 1;
2803 				gs.fracY = g;
2804 				y += g * gs.nSplit;
2805 			}
2806 		} else {
2807 			GraphSet gs2d = null;
2808 			int i2d = -1;
2809 			if (n == 2 || n == 3)
2810 				for (int i = 0; i < n; i++) {
2811 					gs = graphSets.get(i);
2812 					if (!gs.getSpectrum().is1D()) {
2813 						gs2d = gs;
2814 						if (i2d >= 0)
2815 							i = -2;
2816 						i2d = i;
2817 						break;
2818 					}
2819 				}
2820 			if (i2d == -2 || i2d == -1 && n != 2) {
2821 				setFractionalPositions(pd, graphSets, LinkMode.NONE);
2822 				return;
2823 			}
2824 			for (int i = 0; i < n; i++) {
2825 				gs = graphSets.get(i);
2826 				gs.isLinked = true;
2827 				Spectrum s1 = gs.getSpectrumAt(0);
2828 				boolean is1D = s1.is1D();
2829 				if (is1D) {
2830 					if (gs2d != null) {
2831 						Spectrum s2 = gs2d.getSpectrumAt(0);
2832 						if (Spectrum.areLinkableX(s1, s2))
2833   					  gs.gs2dLinkedX = gs2d;
2834 						if (Spectrum.areLinkableY(s1, s2))
2835 							gs.gs2dLinkedY = gs2d;
2836 					}
2837 					gs.fX0 = 0;
2838 					gs.fY0 = y;
2839 					gs.fracX = (gs2d == null ? 1 : 0.5);
2840 					gs.fracY = (n == 3 || gs2d == null ? 0.5 : 1);
2841 			  	y += 0.5;
2842 				} else {
2843 					gs.fX0 = 0.5;
2844 					gs.fY0 = 0;
2845 					gs.fracX = 0.5;
2846 					gs.fracY = 1;
2847 				}
2848 			}
2849 		}
2850 
2851 	}
2852 	// highlight class
2853 
2854 	/**
2855 	 * Private class to represent a Highlighted region of the spectrum display
2856 	 * <p>
2857 	 * Title: JSpecView
2858 	 * </p>
2859 	 * <p>
2860 	 * Description: JSpecView is a graphical viewer for chemical spectra specified
2861 	 * in the JCAMP-DX format
2862 	 * </p>
2863 	 * <p>
2864 	 * Copyright: Copyright (c) 2002
2865 	 * </p>
2866 	 * <p>
2867 	 * Company: Dept. of Chemistry, University of the West Indies, Mona Campus,
2868 	 * Jamaica
2869 	 * </p>
2870 	 *
2871 	 * @author Debbie-Ann Facey
2872 	 * @author Khari A. Bryan
2873 	 * @author Prof Robert.J. Lancashire
2874 	 * @version 1.0.017032006
2875 	 */
2876 	private class Highlight {
2877 		double x1;
2878 		double x2;
2879 		GenericColor color;
2880 		Spectrum spectrum;
2881 
2882 
2883 		@Override
toString()2884 		public String toString() {
2885 			return "highlight " + x1 + " " + x2 + " " + spectrum;
2886 		}
2887 
Highlight(double x1, double x2, Spectrum spec, GenericColor color)2888 		Highlight(double x1, double x2, Spectrum spec, GenericColor color) {
2889 			this.x1 = x1;
2890 			this.x2 = x2;
2891 			this.color = color;
2892 			spectrum = spec;
2893 		}
2894 
2895 		/**
2896 		 * Overides the equals method in class <code>Object</code>
2897 		 *
2898 		 * @param obj
2899 		 *          the object that this <code>Highlight<code> is compared to
2900 		 * @return true if equal
2901 		 */
2902 
2903 		@Override
equals(Object obj)2904 		public boolean equals(Object obj) {
2905 			if (!(obj instanceof Highlight))
2906 				return false;
2907 			Highlight hl = (Highlight) obj;
2908 			return ((hl.x1 == this.x1) && (hl.x2 == this.x2));
2909 		}
2910 	}
2911 
2912 	// called only by PanelData
2913 
addAnnotation(Lst<String> args, String title)2914 	String addAnnotation(Lst<String> args, String title) {
2915 		if (args.size() == 0 || args.size() == 1
2916 				&& args.get(0).equalsIgnoreCase("none")) {
2917 			annotations = null;
2918 			lastAnnotation = null;
2919 			return null;
2920 		}
2921 		if (args.size() < 4 && lastAnnotation == null)
2922 			lastAnnotation = getAnnotation(
2923 					(getScale().maxXOnScale + getScale().minXOnScale) / 2,
2924 					(getScale().maxYOnScale + getScale().minYOnScale) / 2, title, false,
2925 					false, 0, 0);
2926 		Annotation annotation = getAnnotation(args, lastAnnotation);
2927 		if (annotation == null)
2928 			return null;
2929 		if (annotations == null && args.size() == 1
2930 				&& args.get(0).charAt(0) == '\"') {
2931 			String s = annotation.text;
2932 			getSpectrum().setTitle(s);
2933 			return s;
2934 		}
2935 		lastAnnotation = annotation;
2936 		addAnnotation(annotation, false);
2937 		return null;
2938 	}
2939 
2940 	/**
2941 	 * Add information about a region of the displayed spectrum to be highlighted
2942 	 *
2943 	 * @param x1
2944 	 *          the x value of the coordinate where the highlight should start
2945 	 * @param x2
2946 	 *          the x value of the coordinate where the highlight should end
2947 	 * @param spec
2948 	 * @param color
2949 	 *          the color of the highlight
2950 	 */
addHighlight(double x1, double x2, Spectrum spec, GenericColor color)2951 	void addHighlight(double x1, double x2, Spectrum spec, GenericColor color) {
2952 		if (spec == null)
2953 			spec = getSpectrumAt(0);
2954 		Highlight hl = new Highlight(x1, x2, spec, (color == null ? pd
2955 				.getColor(ScriptToken.HIGHLIGHTCOLOR) : color));
2956 		if (!highlights.contains(hl))
2957 			highlights.addLast(hl);
2958 	}
2959 
addPeakHighlight(PeakInfo peakInfo)2960 	void addPeakHighlight(PeakInfo peakInfo) {
2961 		for (int i = spectra.size(); --i >= 0;) {
2962 			Spectrum spec = spectra.get(i);
2963 			removeAllHighlights(spec);
2964 			if (peakInfo == null || peakInfo.isClearAll()
2965 					|| spec != peakInfo.spectrum)
2966 				continue;
2967 			String peak = peakInfo.toString();
2968 			if (peak == null) {
2969 				continue;
2970 			}
2971 			String xMin = PT.getQuotedAttribute(peak, "xMin");
2972 			String xMax = PT.getQuotedAttribute(peak, "xMax");
2973 			if (xMin == null || xMax == null)
2974 				return;
2975 			float x1 = PT.parseFloat(xMin);
2976 			float x2 = PT.parseFloat(xMax);
2977 			if (Float.isNaN(x1) || Float.isNaN(x2))
2978 				return;
2979 			pd.addHighlight(this, x1, x2, spec, 200, 140, 140, 100);
2980 			spec.setSelectedPeak(peakInfo);
2981 			if (getScale().isInRangeX(x1)
2982 					|| getScale().isInRangeX(x2) || x1 < getScale().minX
2983 					&& getScale().maxX < x2) {
2984 			} else {
2985 				setZoomTo(0);
2986 			}
2987 		}
2988 	}
2989 
advanceSubSpectrum(int dir)2990 	void advanceSubSpectrum(int dir) {
2991 		Spectrum spec0 = getSpectrumAt(0);
2992 		int i = spec0.advanceSubSpectrum(dir);
2993 		if (spec0.isForcedSubset())
2994 			viewData.setXRangeForSubSpectrum(getSpectrum().getXYCoords());
2995 		pd.notifySubSpectrumChange(i, getSpectrum());
2996 	}
2997 
checkSpectrumClickedEvent(int xPixel, int yPixel, int clickCount)2998 	synchronized boolean checkSpectrumClickedEvent(int xPixel, int yPixel, int clickCount) {
2999 		if (nextClickForSetPeak != null)
3000 			return false;
3001 		//if (clickCount > 0 && checkArrowLeftRightClick(xPixel, yPixel))
3002 			//return true;
3003 		if (clickCount > 1 || pendingMeasurement != null
3004 				|| !isInPlotRegion(xPixel, yPixel))
3005 			return false;
3006 		// in the plot area
3007 
3008 		if (clickCount == 0) {
3009 			// pressed
3010 
3011 			boolean isOnIntegral = isOnSpectrum(xPixel, yPixel, -1);
3012 			pd.integralShiftMode = (isOnIntegral ? getShiftMode(xPixel, yPixel) : 0);
3013 			pd.isIntegralDrag = (pd.integralShiftMode == 0 && (isOnIntegral || haveIntegralDisplayed(-1)
3014 					&& findMeasurement(getIntegrationGraph(-1), xPixel, yPixel, Measurement.PT_ON_LINE) != null));
3015 			if (pd.integralShiftMode != 0)
3016 				return false;
3017 		}
3018 
3019 		if (!showAllStacked)
3020 			return false;
3021 		// in the stacked plot area
3022 
3023 		stackSelected = false;
3024 		for (int i = 0; i < nSpectra; i++) {
3025 			if (!isOnSpectrum(xPixel, yPixel, i))
3026 				continue;
3027 			//boolean isNew = (i != iSpectrumSelected);
3028 			setSpectrumClicked(iPreviousSpectrumClicked = i);
3029 			return false;
3030 		}
3031 		// but not on a spectrum
3032 		if (isDialogOpen())
3033 			return false;
3034 		setSpectrumClicked(-1);
3035 		return stackSelected = false;
3036 	}
3037 
getShiftMode(int xPixel, int yPixel)3038 	private int getShiftMode(int xPixel, int yPixel) {
3039 		return (isStartEndIntegral(xPixel, false) ? yPixel : isStartEndIntegral(
3040 				xPixel, true) ? -yPixel : 0);
3041 	}
3042 
isDialogOpen()3043 	private boolean isDialogOpen() {
3044 		return (isVisible(getDialog(AType.Integration, -1))
3045 				|| isVisible(getDialog(AType.Measurements, -1)) || isVisible(getDialog(
3046 				AType.PeakList, -1)));
3047 	}
3048 
isStartEndIntegral(int xPixel, boolean isEnd)3049 	private boolean isStartEndIntegral(int xPixel, boolean isEnd) {
3050 		return (isEnd ? xPixelPlot1 - xPixel < 20 : xPixel - xPixelPlot0 < 20);
3051 	}
3052 
3053 	private boolean widgetsAreSet = true;
3054 	private int lastIntDragX;
3055 	private int nextClickMode;
3056 
checkWidgetEvent(int xPixel, int yPixel, boolean isPress)3057 	synchronized boolean checkWidgetEvent(int xPixel, int yPixel, boolean isPress) {
3058 		if (!widgetsAreSet)
3059 			return false;
3060 		widgetsAreSet = false;
3061 		PlotWidget widget;
3062 		if (isPress) {
3063 			if (pd.clickCount == 2 && lastIntDragX != xPixel && !is2dClick(xPixel, yPixel)) {
3064 				if (pendingMeasurement == null) {
3065 					if (iSpectrumClicked == -1 && iPreviousSpectrumClicked >= 0) {
3066 						setSpectrumClicked(iPreviousSpectrumClicked);
3067 					}
3068 					processPendingMeasurement(xPixel, yPixel, 2);
3069 					return true;
3070 				}
3071 			} else if (!is2dClick(xPixel, yPixel)){
3072 				if (isOnSpectrum(xPixel, yPixel, -1)) {
3073 					// split
3074 					checkIntegral(toX(xPixel), Double.NaN, false);
3075 				}
3076 
3077 				if (lastIntDragX == xPixel) {
3078 					// restart
3079 					pd.isIntegralDrag = true;
3080 					if (!checkIntegral(toX(xPixel), toX(xPixel), false))
3081 						return false;
3082 				}
3083 			}
3084 			if (pendingMeasurement != null)
3085 				return true;
3086 
3087 			widget = getPinSelected(xPixel, yPixel);
3088 			if (widget == null) {
3089 				yPixel = fixY(yPixel);
3090 				if (xPixel < xPixel1) {
3091 					if (pd.shiftPressed)
3092 						setSpectrumClicked(iPreviousSpectrumClicked);
3093 					xPixel = fixX(xPixel);
3094 					if (zoomBox1D == null)
3095 						newPins();
3096 					zoomBox1D.setX(toX(xPixel), xPixel);
3097 					zoomBox1D.yPixel0 = yPixel;
3098 					widget = zoomBox1D;
3099 				} else if (imageView != null && xPixel < imageView.xPixel1) {
3100 					zoomBox2D.setX(imageView.toX(xPixel), imageView.fixX(xPixel));
3101 					zoomBox2D.yPixel0 = yPixel;
3102 					widget = zoomBox2D;
3103 				}
3104 			}
3105 			pd.thisWidget = widget;
3106 			return false;
3107 		}
3108 		nextClickForSetPeak = null;
3109 		widget = pd.thisWidget;
3110 		if (widget == null)
3111 			return false;
3112 		// mouse drag with widget
3113 		if (widget == zoomBox1D) {
3114 			zoomBox1D.xPixel1 = fixX(xPixel);
3115 			zoomBox1D.yPixel1 = fixY(yPixel);
3116 			if (pd.isIntegralDrag && zoomBox1D.xPixel0 != zoomBox1D.xPixel1) {
3117 				if ((lastIntDragX <= xPixel) != (zoomBox1D.xPixel0 <= xPixel)) {
3118 					// switched direction of integral drag
3119 					zoomBox1D.xPixel0 = lastIntDragX;
3120 					zoomBox1D.xPixel1 = xPixel;
3121 					zoomBox1D.setXVal(toX(zoomBox1D.xPixel0));
3122 				}
3123 				lastIntDragX = xPixel;
3124 				checkIntegral(zoomBox1D.getXVal(), toX(zoomBox1D.xPixel1), false);
3125 			}
3126 			return false;
3127 		}
3128 		if (!zoomEnabled)
3129 			return false;
3130 		if (widget == zoomBox2D) {
3131 			zoomBox2D.xPixel1 = imageView.fixX(xPixel);
3132 			zoomBox2D.yPixel1 = fixY(yPixel);
3133 			return true;
3134 		}
3135 		if (widget == cur2Dy) {
3136 			yPixel = fixY(yPixel);
3137 			cur2Dy.yPixel0 = cur2Dy.yPixel1 = yPixel;
3138 			setCurrentSubSpectrum(imageView.toSubspectrumIndex(yPixel));
3139 			return true;
3140 		}
3141 		if (widget == cur2Dx0 || widget == cur2Dx1) {
3142 			// xPixel = imageView.fixX(xPixel);
3143 			// widget.setX(imageView.toX(xPixel), xPixel);
3144 			// 2D x zoom change
3145 			// doZoom(cur2Dx0.getXVal(), getScale().minY, cur2Dx1.getXVal(),
3146 			// getScale().maxY, false, false, false, true);
3147 			return false;
3148 		}
3149 		if (widget == pin1Dx0 || widget == pin1Dx1 || widget == pin1Dx01) {
3150 			xPixel = fixX(xPixel);
3151 			widget.setX(toX0(xPixel), xPixel);
3152 			if (widget == pin1Dx01) {
3153 				int dp = xPixel - ((pin1Dx0.xPixel0 + pin1Dx1.xPixel0) / 2);
3154 				int dp1 = (dp < 0 ? dp : dp);
3155 				int dp2 = (dp < 0 ? dp : dp);
3156 				xPixel = pin1Dx0.xPixel0 + dp2;
3157 				int xPixel1 = pin1Dx1.xPixel0 + dp1;
3158 				if (dp == 0 || fixX(xPixel) != xPixel || fixX(xPixel1) != xPixel1)
3159 					return true;
3160 				pin1Dx0.setX(toX0(xPixel), xPixel);
3161 				pin1Dx1.setX(toX0(xPixel1), xPixel1);
3162 
3163 			}
3164 			// 1D x zoom change
3165 			doZoom(pin1Dx0.getXVal(), 0, pin1Dx1.getXVal(), 0, true, false, false,
3166 					true, false);
3167 			return true;
3168 		}
3169 		if (widget == pin1Dy0 || widget == pin1Dy1 || widget == pin1Dy01) {
3170 			yPixel = fixY(yPixel);
3171 			widget.setY(toY0(yPixel), yPixel);
3172 			if (widget == pin1Dy01) {
3173 				int dp = yPixel - (pin1Dy0.yPixel0 + pin1Dy1.yPixel0) / 2 + 1;
3174 				yPixel = pin1Dy0.yPixel0 + dp;
3175 				int yPixel1 = pin1Dy1.yPixel0 + dp;
3176 				double y0 = toY0(yPixel);
3177 				double y1 = toY0(yPixel1);
3178 				if (Math.min(y0, y1) == getScale().minY
3179 						|| Math.max(y0, y1) == getScale().maxY)
3180 					return true;
3181 				pin1Dy0.setY(y0, yPixel);
3182 				pin1Dy1.setY(y1, yPixel1);
3183 			}
3184 			// y-only zoom
3185 			doZoom(0, pin1Dy0.getYVal(), 0, pin1Dy1.getYVal(), imageView == null,
3186 					imageView == null, false, false, false);
3187 			return true;
3188 		}
3189 		if (widget == pin2Dx0 || widget == pin2Dx1 || widget == pin2Dx01) {
3190 			xPixel = imageView.fixX(xPixel);
3191 			widget.setX(imageView.toX0(xPixel), xPixel);
3192 			if (widget == pin2Dx01) {
3193 				int dp = xPixel - (pin2Dx0.xPixel0 + pin2Dx1.xPixel0) / 2 + 1;
3194 				xPixel = pin2Dx0.xPixel0 + dp;
3195 				int xPixel1 = pin2Dx1.xPixel0 + dp;
3196 				if (imageView.fixX(xPixel) != xPixel
3197 						|| imageView.fixX(xPixel1) != xPixel1)
3198 					return true;
3199 				pin2Dx0.setX(imageView.toX0(xPixel), xPixel);
3200 				pin2Dx1.setX(imageView.toX0(xPixel1), xPixel1);
3201 			}
3202 			if (!isGoodEvent(pin2Dx0, pin2Dx1, true)) {
3203 				reset2D(true);
3204 				return true;
3205 			}
3206 			imageView.setView0(pin2Dx0.xPixel0, pin2Dy0.yPixel0, pin2Dx1.xPixel0,
3207 					pin2Dy1.yPixel0);
3208 			// 2D x zoom
3209 			doZoom(pin2Dx0.getXVal(), getScale().minY, pin2Dx1.getXVal(),
3210 					getScale().maxY, false, false, false, true, false);
3211 			return true;
3212 		}
3213 		if (widget == pin2Dy0 || widget == pin2Dy1 || widget == pin2Dy01) {
3214 			yPixel = fixY(yPixel);
3215 			widget.setY(imageView.toSubspectrumIndex(yPixel), yPixel);
3216 			if (widget == pin2Dy01) {
3217 				int dp = yPixel - (pin2Dy0.yPixel0 + pin2Dy1.yPixel0) / 2 + 1;
3218 				yPixel = pin2Dy0.yPixel0 + dp;
3219 				int yPixel1 = pin2Dy1.yPixel0 + dp;
3220 				if (yPixel != fixY(yPixel) || yPixel1 != fixY(yPixel1))
3221 					return true;
3222 				pin2Dy0.setY(imageView.toSubspectrumIndex(yPixel), yPixel);
3223 				pin2Dy1.setY(imageView.toSubspectrumIndex(yPixel1), yPixel1);
3224 			}
3225 			if (!isGoodEvent(pin2Dy0, pin2Dy1, false)) {
3226 				reset2D(false);
3227 				return true;
3228 			}
3229 			imageView.setView0(pin2Dx0.xPixel0, pin2Dy0.yPixel0, pin2Dx1.xPixel1,
3230 					pin2Dy1.yPixel1);
3231 			// update2dImage(false);
3232 			return true;
3233 		}
3234 		return false;
3235 	}
3236 
clearIntegrals()3237 	void clearIntegrals() {
3238 		checkIntegral(Double.NaN, 0, false);
3239 	}
3240 
clearMeasurements()3241 	void clearMeasurements() {
3242 		removeDialog(getFixedSelectedSpectrumIndex(), AType.Measurements);
3243 	}
3244 
createGraphSetsAndSetLinkMode(PanelData pd, JSVPanel jsvp, Lst<Spectrum> spectra, int startIndex, int endIndex, LinkMode linkMode)3245 	static Lst<GraphSet> createGraphSetsAndSetLinkMode(PanelData pd, JSVPanel jsvp,
3246 		Lst<Spectrum> spectra, int startIndex, int endIndex, LinkMode linkMode) {
3247 		Lst<GraphSet> graphSets = new Lst<GraphSet>();
3248 		for (int i = 0; i < spectra.size(); i++) {
3249 			Spectrum spec = spectra.get(i);
3250 			GraphSet graphSet = (linkMode == LinkMode.NONE ? findCompatibleGraphSet(graphSets, spec) : null);
3251 			if (graphSet == null)
3252 				graphSets.addLast(graphSet = new GraphSet(jsvp.getPanelData()));
3253 			graphSet.addSpec(spec);
3254 		}
3255 		setFractionalPositions(pd, graphSets, linkMode);
3256 		for (int i = graphSets.size(); --i >= 0;) {
3257 			graphSets.get(i).initGraphSet(startIndex, endIndex);
3258 			Logger.info("JSVGraphSet " + (i + 1) + " nSpectra = "
3259 					+ graphSets.get(i).nSpectra);
3260 		}
3261 		return graphSets;
3262 	}
3263 
3264 	/**
3265 	 *
3266 	 * entry point for a repaint
3267 	 *
3268 	 * @param gMain primary canvas
3269 	 * @param gFront  front-pane (glass pane) canvas
3270 	 * @param gBack   back-pane canvas
3271 	 * @param width
3272 	 * @param height
3273 	 * @param left
3274 	 * @param right
3275 	 * @param top
3276 	 * @param bottom
3277 	 * @param isResized
3278 	 * @param taintedAll
3279 	 * @param pointsOnly
3280 	 */
drawGraphSet(Object gMain, Object gFront, Object gBack, int width, int height, int left, int right, int top, int bottom, boolean isResized, boolean taintedAll, boolean pointsOnly)3281 	synchronized void drawGraphSet(Object gMain, Object gFront, Object gBack,
3282 			int width, int height, int left, int right, int top, int bottom,
3283 			boolean isResized, boolean taintedAll, boolean pointsOnly) {
3284 
3285 		zoomEnabled = pd.getBoolean(ScriptToken.ENABLEZOOM);
3286 		this.height = height * pd.scalingFactor;
3287 		this.width = width * pd.scalingFactor;
3288 		this.left = left * pd.scalingFactor;
3289 		this.right = right * pd.scalingFactor;
3290 		this.top = top * pd.scalingFactor;
3291 		this.bottom = bottom * pd.scalingFactor;
3292 		// yValueMovedTo = Double.NaN;
3293 		haveSelectedSpectrum = false;
3294 		selectedSpectrumIntegrals = null;
3295 		selectedSpectrumMeasurements = null;
3296 		if (!pd.isPrinting && widgets != null)
3297 			for (int j = 0; j < widgets.length; j++)
3298 				if (widgets[j] != null)
3299 					widgets[j].isVisible = false;
3300 		for (int iSplit = 0; iSplit < nSplit; iSplit++) {
3301 			// for now, at least, we only allow one 2D image
3302 			setPositionForFrame(iSplit);
3303 			drawAll(gMain, gFront, gBack, iSplit, isResized || nSplit > 1, taintedAll, pointsOnly);
3304 		}
3305 		setPositionForFrame(nSplit > 1 ? pd.currentSplitPoint : 0);
3306 		if (pd.isPrinting)
3307 			return;
3308 	}
3309 
escapeKeyPressed(boolean isDEL)3310 	synchronized void escapeKeyPressed(boolean isDEL) {
3311 		if (zoomBox1D != null)
3312 			zoomBox1D.xPixel0 = zoomBox1D.xPixel1 = 0;
3313 		if (zoomBox2D != null)
3314 			zoomBox2D.xPixel0 = zoomBox2D.xPixel1 = 0;
3315 		if (!inPlotMove)
3316 			return;
3317 		if (pendingMeasurement != null) {
3318 			pendingMeasurement = null;
3319 			return;
3320 		}
3321 		pd.thisWidget = null;
3322 		pendingMeasurement = null;
3323 		if (selectedSpectrumMeasurements != null && selectedMeasurement != null) {
3324 			if (isDEL)
3325 				selectedSpectrumMeasurements.clear(getScale().minXOnScale,
3326 						getScale().maxXOnScale);
3327 			else
3328 				selectedSpectrumMeasurements.removeObj(selectedMeasurement);
3329 			selectedMeasurement = null;
3330 			updateDialog(AType.Measurements, -1);
3331 		}
3332 		if (selectedSpectrumIntegrals != null && selectedIntegral != null) {
3333 			if (isDEL)
3334 				selectedSpectrumIntegrals.clear(getScale().minXOnScale,
3335 						getScale().maxXOnScale);
3336 			else
3337 				selectedSpectrumIntegrals.removeObj(selectedIntegral);
3338 			selectedIntegral = null;
3339 			updateDialog(AType.Integration, -1);
3340 		}
3341 	}
3342 
findGraphSet(Lst<GraphSet> graphSets, int xPixel, int yPixel)3343 	static GraphSet findGraphSet(Lst<GraphSet> graphSets, int xPixel, int yPixel) {
3344 		for (int i = graphSets.size(); --i >= 0;)
3345 			if (graphSets.get(i).hasPoint(xPixel, yPixel))
3346 				return graphSets.get(i);
3347 		return null;
3348 	}
3349 
findMatchingPeakInfo(PeakInfo pi)3350 	PeakInfo findMatchingPeakInfo(PeakInfo pi) {
3351 		PeakInfo pi2 = null;
3352 		for (int i = 0; i < spectra.size(); i++)
3353 			if ((pi2 = (spectra.get(i)).findMatchingPeakInfo(pi)) != null)
3354 				break;
3355 		return pi2;
3356 	}
3357 
getCurrentSpectrumIndex()3358 	int getCurrentSpectrumIndex() {
3359 		return (nSpectra == 1 ? 0 : iSpectrumSelected);
3360 	}
3361 
getSelectedIntegral()3362 	Integral getSelectedIntegral() {
3363 		return selectedIntegral;
3364 	}
3365 
getShowAnnotation(AType type, int i)3366 	boolean getShowAnnotation(AType type, int i) {
3367 		AnnotationData id = getDialog(type, i);
3368 		return (id != null && id.getState());
3369 	}
3370 
hasFileLoaded(String filePath)3371 	boolean hasFileLoaded(String filePath) {
3372 		for (int i = spectra.size(); --i >= 0;)
3373 			if (spectra.get(i).getFilePathForwardSlash().equals(filePath))
3374 				return true;
3375 		return false;
3376 	}
3377 
haveSelectedSpectrum()3378 	boolean haveSelectedSpectrum() {
3379 		return haveSelectedSpectrum;
3380 	}
3381 
mouseClickedEvent(int xPixel, int yPixel, int clickCount, boolean isControlDown)3382 	synchronized void mouseClickedEvent(int xPixel, int yPixel, int clickCount,
3383 			boolean isControlDown) {
3384 		selectedMeasurement = null;
3385 		selectedIntegral = null;
3386 		Double isNextClick = nextClickForSetPeak;
3387 		nextClickForSetPeak = null;
3388 		if (checkArrowUpDownClick(xPixel, yPixel)
3389 				|| checkArrowLeftRightClick(xPixel, yPixel))
3390 			return;
3391 		lastClickX = Double.NaN;
3392 		lastPixelX = Integer.MAX_VALUE;
3393 		if (isSplitWidget(xPixel, yPixel)) {
3394 			splitStack(nSplit == 1);
3395 			return;
3396 		}
3397 		if (isCloserWidget(xPixel, yPixel)) {
3398 			pd.closeSpectrum();
3399 			return;
3400 		}
3401 		PlotWidget pw = getPinSelected(xPixel, yPixel);
3402 		if (pw != null) {
3403 			setWidgetValueByUser(pw);
3404 			return;
3405 		}
3406 		boolean is2D = is2dClick(xPixel, yPixel);
3407 		if (clickCount == 2 && iSpectrumClicked == -1
3408 				&& iPreviousSpectrumClicked >= 0) {
3409 			setSpectrumClicked(iPreviousSpectrumClicked);
3410 		}
3411 		if (!is2D && isControlDown) {
3412 			setSpectrumClicked(iPreviousSpectrumClicked);
3413 			if (pendingMeasurement != null) {
3414 				processPendingMeasurement(xPixel, yPixel, -3);
3415 			} else if (iSpectrumClicked >= 0) {
3416 				processPendingMeasurement(xPixel, yPixel, 3);
3417 			}
3418 			return;
3419 		}
3420 		lastXMax = Double.NaN; // TODO: was for "is2D || !isControlDown
3421 		if (clickCount == 2) {
3422 			if (is2D) {
3423 				if (sticky2Dcursor) {
3424 					addAnnotation(
3425 							getAnnotation(imageView.toX(xPixel),
3426 									imageView.toSubspectrumIndex(yPixel), pd.coordStr, false,
3427 									true, 5, 5), true);
3428 				}
3429 
3430 					sticky2Dcursor = true;//!sticky2Dcursor;
3431 					set2DCrossHairs(xPixel, yPixel);
3432 				return;
3433 			}
3434 
3435 			// 1D double-click
3436 
3437 			if (isInTopBar(xPixel, yPixel)) {
3438 				// 1D x zoom reset to original
3439 				doZoom(toX0(xPixel0), 0, toX0(xPixel1), 0, true, false, false, true,
3440 						true);
3441 			} else if (isInRightBar(xPixel, yPixel)) {
3442 				doZoom(getScale().minXOnScale, viewList.get(0).getScale().minYOnScale,
3443 						getScale().maxXOnScale, viewList.get(0).getScale().maxYOnScale,
3444 						true, true, false, false, false);
3445 			} else if (isInTopBar2D(xPixel, yPixel)) {
3446 				reset2D(true);
3447 			} else if (isInRightBar2D(xPixel, yPixel)) {
3448 				reset2D(false);
3449 			} else if (pendingMeasurement != null) {
3450 				processPendingMeasurement(xPixel, yPixel, -2);
3451 			} else if (iSpectrumClicked >= 0) {
3452 				processPendingMeasurement(xPixel, yPixel, 2);
3453 			}
3454 			return;
3455 		}
3456 
3457 		// single click
3458 
3459 		if (is2D) {
3460 			if (annotations != null) {
3461 				Coordinate xy = new Coordinate().set(imageView.toX(xPixel),
3462 						imageView.toSubspectrumIndex(yPixel));
3463 				Annotation a = findAnnotation2D(xy);
3464 				if (a != null && setAnnotationText(a)) {
3465 					return;
3466 				}
3467 			}
3468 			if (clickCount == 1)
3469 				sticky2Dcursor = false;
3470 			set2DCrossHairs(xPixel, yPixel);
3471 			return;
3472 		}
3473 
3474 		// 1D single click
3475 
3476 		if (isInPlotRegion(xPixel, yPixel)) {
3477 			if (selectedSpectrumIntegrals != null
3478 					&& checkIntegralNormalizationClick(xPixel, yPixel))
3479 				return;
3480 			if (pendingMeasurement != null) {
3481 				processPendingMeasurement(xPixel, yPixel, 1);
3482 				return;
3483 			}
3484 
3485 			setCoordClicked(xPixel, toX(xPixel), toY(yPixel));
3486 			updateDialog(AType.PeakList, -1);
3487 			if (isNextClick != null) {
3488 				nextClickForSetPeak = isNextClick;
3489 				shiftSpectrum(SHIFT_CLICKED, Double.NaN, Double.NaN);
3490 				nextClickForSetPeak = null;
3491 				return;
3492 			}
3493 
3494 
3495 		} else {
3496 			setCoordClicked(0, Double.NaN, 0);
3497 		}
3498 		pd.notifyPeakPickedListeners(null);
3499 	}
3500 
is2dClick(int xPixel, int yPixel)3501 	private boolean is2dClick(int xPixel, int yPixel) {
3502 		return (imageView != null && xPixel == imageView.fixX(xPixel) && yPixel == fixY(yPixel));
3503 	}
3504 
updateDialog(AType type, int iSpec)3505 	private void updateDialog(AType type, int iSpec) {
3506 		AnnotationData ad = getDialog(type, iSpec);
3507 		if (ad == null || !isVisible(ad))
3508 			return;
3509 		double  xRange = toX(xPixel1) - toX(xPixel0);
3510 		int yOffset = (getSpectrum().isInverted() ? yPixel1 - pd.mouseY : pd.mouseY - yPixel0);
3511 		((JSVDialog) ad).update(pd.coordClicked, xRange, yOffset);
3512 	}
3513 
isVisible(AnnotationData ad)3514 	private boolean isVisible(AnnotationData ad) {
3515 		return ad != null && (ad.isDialog() && ad.isVisible());
3516 	}
3517 
3518 
mousePressedEvent(int xPixel, int yPixel, int clickCount)3519   public void mousePressedEvent(int xPixel, int yPixel, int clickCount) {
3520     checkWidgetEvent(xPixel, yPixel, true);
3521   }
3522 
3523   /**
3524 	 * @param xPixel
3525 	 * @param yPixel
3526 	 */
mouseReleasedEvent(int xPixel, int yPixel)3527 	synchronized void mouseReleasedEvent(int xPixel, int yPixel) {
3528 		if (pendingMeasurement != null) {
3529 			if (Math.abs(toPixelX(pendingMeasurement.getXVal()) - xPixel) < 2)
3530 				pendingMeasurement = null;
3531 			processPendingMeasurement(xPixel, yPixel, -2);
3532 			setToolTipForPixels(xPixel, yPixel);
3533 			return;
3534 		}
3535 		if (pd.integralShiftMode != 0) {
3536 			pd.integralShiftMode = 0;
3537 			zoomBox1D.xPixel1 = zoomBox1D.xPixel0;
3538 			return;
3539 		}
3540 		if (iSpectrumMovedTo >= 0)
3541 			setScale(iSpectrumMovedTo);
3542 		PlotWidget thisWidget = pd.thisWidget;
3543 		if (pd.isIntegralDrag) {
3544 			if (isGoodEvent(zoomBox1D, null, true)) {
3545 				checkIntegral(toX(zoomBox1D.xPixel0), toX(zoomBox1D.xPixel1), true);
3546 			}
3547 			zoomBox1D.xPixel1 = zoomBox1D.xPixel0 = 0;
3548 			pendingIntegral = null;
3549 			pd.isIntegralDrag = false;
3550 		} else if (thisWidget == zoomBox2D) {
3551 			if (!isGoodEvent(zoomBox2D, null, true))
3552 				return;
3553 			imageView.setZoom(zoomBox2D.xPixel0, zoomBox2D.yPixel0,
3554 					zoomBox2D.xPixel1, zoomBox2D.yPixel1);
3555 			zoomBox2D.xPixel1 = zoomBox2D.xPixel0;
3556 			// 2D xy zoom
3557 			doZoom(imageView.toX(imageView.xPixel0), getScale().minY, imageView
3558 					.toX(imageView.xPixel0 + imageView.xPixels - 1), getScale().maxY, false,
3559 					false, false, true, true);
3560 		} else if (thisWidget == zoomBox1D) {
3561 		  if (!isGoodEvent(zoomBox1D, null, true))
3562 				return;
3563 			int x1 = zoomBox1D.xPixel1;
3564 			// 1D x zoom by zoomBox
3565 			boolean doY = (pd.shiftPressed);
3566 			doZoom(toX(zoomBox1D.xPixel0),
3567 					(doY ? toY(zoomBox1D.yPixel0) : 0),
3568 					toX(x1),
3569 					(doY ? toY(zoomBox1D.yPixel1) : 0),
3570 					true, doY, true, true, true);
3571 			zoomBox1D.xPixel1 = zoomBox1D.xPixel0;
3572 		} else if (thisWidget == pin1Dx0 || thisWidget == pin1Dx1
3573 				|| thisWidget == cur2Dx0 || thisWidget == cur2Dx1) {
3574 			addCurrentZoom();
3575 		}
3576 	}
3577 
mouseMovedEvent(int xPixel, int yPixel)3578 	synchronized void mouseMovedEvent(int xPixel, int yPixel) {
3579 		if (nSpectra > 1) {
3580 
3581 			int iFrame = getSplitPoint(yPixel);
3582 			setPositionForFrame(iFrame);
3583 			setSpectrumMovedTo(nSplit > 1 ? iFrame : iSpectrumSelected);
3584 			if (iSpectrumMovedTo >= 0)
3585 				setScale(iSpectrumMovedTo);
3586 		}
3587 		inPlotMove = isInPlotRegion(xPixel, yPixel);
3588 		setXPixelMovedTo(Double.MAX_VALUE, Double.MAX_VALUE, (inPlotMove ? xPixel : -1), -1);
3589 		if (inPlotMove) {
3590 			xValueMovedTo = toX(xPixelMovedTo);
3591 			yValueMovedTo = getSpectrum().getYValueAt(xValueMovedTo);
3592 		}
3593 		if (pd.integralShiftMode != 0) {
3594 			AnnotationData ad = getDialog(AType.Integration, -1);
3595 			Coordinate[] xy = ((IntegralData) ad.getData()).getXYCoords();
3596 			double y = xy[pd.integralShiftMode > 0 ? xy.length - 1 : 0].getYVal();
3597 
3598 			((IntegralData) ad.getData()).shiftY(pd.integralShiftMode, toPixelYint(y) + yPixel
3599 					- (pd.integralShiftMode > 0 ? yPixelPlot1 : yPixelPlot0), yPixel0,
3600 					yPixels);
3601 		} else if (pd.isIntegralDrag) {
3602 		} else if (pendingMeasurement != null) {
3603 			processPendingMeasurement(xPixel, yPixel, 0);
3604 			setToolTipForPixels(xPixel, yPixel);
3605 		} else {
3606 			selectedMeasurement = (inPlotMove && selectedSpectrumMeasurements != null ? findMeasurement(
3607 					selectedSpectrumMeasurements, xPixel, yPixel,Measurement.PT_ON_LINE)
3608 					: null);
3609 			selectedIntegral = null;
3610 			if (inPlotMove && selectedSpectrumIntegrals != null
3611 					&& selectedMeasurement == null) {
3612 				selectedIntegral = (Integral) findMeasurement(
3613 						selectedSpectrumIntegrals, xPixel, yPixel, Measurement.PT_ON_LINE);
3614 				if (selectedIntegral == null)
3615 					selectedIntegral = (Integral) findMeasurement(
3616 							selectedSpectrumIntegrals, xPixel, yPixel, Measurement.PT_INT_LABEL);
3617 			}
3618 			setToolTipForPixels(xPixel, yPixel);
3619 			if (imageView == null) {
3620 				piMouseOver = null;
3621 				int iSpec = (nSplit > 1 ? iSpectrumMovedTo : iSpectrumClicked);
3622 				if (!isDrawNoSpectra() && iSpec >= 0) {
3623 					Spectrum spec = spectra.get(iSpec);
3624 					if (spec.getPeakList() != null) {
3625 						coordTemp.setXVal(toX(xPixel));
3626 						coordTemp.setYVal(toY(yPixel));
3627 						piMouseOver = spec.findPeakByCoord(xPixel, coordTemp);
3628 					}
3629 				}
3630 			} else {
3631 				if (!pd.display1D && sticky2Dcursor) {
3632 					set2DCrossHairs(xPixel, yPixel);
3633 				}
3634 			}
3635 		}
3636 	}
3637 
3638 	/**
3639 	 * Displays the next view zoomed
3640 	 */
nextView()3641 	void nextView() {
3642 		if (currentZoomIndex + 1 < viewList.size())
3643 			setZoomTo(currentZoomIndex + 1);
3644 	}
3645 
3646 	/**
3647 	 * Displays the previous view zoomed
3648 	 */
previousView()3649 	void previousView() {
3650 		if (currentZoomIndex > 0)
3651 			setZoomTo(currentZoomIndex - 1);
3652 	}
3653 
3654 	/**
3655 	 * Resets the spectrum to it's original view
3656 	 */
resetView()3657 	void resetView() {
3658 		setZoomTo(0);
3659 	}
3660 
removeAllHighlights()3661 	void removeAllHighlights() {
3662 		removeAllHighlights(null);
3663 	}
3664 
3665 	/**
3666 	 * Remove the highlight at the specified index in the internal list of
3667 	 * highlights The index depends on the order in which the highlights were
3668 	 * added
3669 	 *
3670 	 * @param index
3671 	 *          the index of the highlight in the list
3672 	 */
removeHighlight(int index)3673 	void removeHighlight(int index) {
3674 		highlights.removeItemAt(index);
3675 	}
3676 
3677 	/**
3678 	 * Remove the highlight specified by the starting and ending x value
3679 	 *
3680 	 * @param x1
3681 	 *          the x value of the coordinate where the highlight started
3682 	 * @param x2
3683 	 *          the x value of the coordinate where the highlight ended
3684 	 */
removeHighlight(double x1, double x2)3685 	void removeHighlight(double x1, double x2) {
3686 		for (int i = highlights.size(); --i >= 0;) {
3687 			Highlight h = highlights.get(i);
3688 			if (h.x1 == x1 && h.x2 == x2)
3689 				highlights.removeItemAt(i);
3690 		}
3691 	}
3692 
scaleYBy(double factor)3693 	void scaleYBy(double factor) {
3694 		if (imageView == null && !zoomEnabled)
3695 			return;
3696 		// from CTRL +/-
3697 		viewData.scaleSpectrum(imageView == null ? iSpectrumSelected : -2, factor);
3698 		if (imageView != null) {
3699 			update2dImage(false);
3700 			resetPinsFromView();
3701 		}
3702 		pd.refresh();
3703 		// view.scaleSpectrum(-1, factor);
3704 	}
3705 
3706 	/**
3707 	 * here we are selecting a spectrum based on a message from Jmol matching type
3708 	 * and model
3709 	 *
3710 	 * @param filePath
3711 	 * @param type
3712 	 * @param model
3713 	 * @return haveFound
3714 	 */
selectSpectrum(String filePath, String type, String model)3715 	boolean selectSpectrum(String filePath, String type, String model) {
3716 		boolean haveFound = false;
3717 		for (int i = spectra.size(); --i >= 0;)
3718 			if ((filePath == null || getSpectrumAt(i).getFilePathForwardSlash()
3719 					.equals(filePath))
3720 					&& (getSpectrumAt(i).matchesPeakTypeModel(type, model))) {
3721 				setSpectrumSelected(i);
3722 				if (nSplit > 1)
3723 					splitStack(true);
3724 				haveFound = true;
3725 			}
3726 		if (nSpectra > 1 && !haveFound && iSpectrumSelected >= 0
3727 				&& !pd.isCurrentGraphSet(this))
3728 			setSpectrumSelected(Integer.MIN_VALUE); // no plots in that case
3729 		return haveFound;
3730 	}
3731 
selectPeakByFileIndex(String filePath, String index, String atomKey)3732 	PeakInfo selectPeakByFileIndex(String filePath, String index, String atomKey) {
3733 		PeakInfo pi;
3734 		for (int i = spectra.size(); --i >= 0;)
3735 			if ((pi = getSpectrumAt(i).selectPeakByFileIndex(filePath, index, atomKey)) != null)
3736 				return pi;
3737 		return null;
3738 	}
3739 
setSelected(int i)3740 	void setSelected(int i) {
3741 		if (i < 0) {
3742 			bsSelected.clearAll();
3743 			setSpectrumClicked(-1);
3744 			return;
3745 		}
3746 		bsSelected.set(i);
3747 		setSpectrumClicked((bsSelected.cardinality() == 1 ? i : -1));
3748 		if (nSplit > 1 && i >= 0)
3749 			pd.currentSplitPoint = i;
3750 	}
3751 
setSelectedIntegral(double val)3752 	void setSelectedIntegral(double val) {
3753 		Spectrum spec = selectedIntegral.getSpectrum();
3754 		getIntegrationGraph(getSpectrumIndex(spec)).setSelectedIntegral(
3755 				selectedIntegral, val);
3756 	}
3757 
3758 	/**
3759 	 * turn on or off a PeakList, Integration, or Measurement dialog
3760 	 *
3761 	 * @param type
3762 	 * @param tfToggle
3763 	 */
setShowAnnotation(AType type, Boolean tfToggle)3764 	void setShowAnnotation(AType type, Boolean tfToggle) {
3765 		AnnotationData id = getDialog(type, -1);
3766 		if (id == null) {
3767 			if (tfToggle != null && tfToggle != Boolean.TRUE)
3768 				return; // does not exist and "OFF" -- ignore
3769 			// does not exist, and TOGGLE or ON
3770 			if (type == AType.PeakList || type == AType.Integration || type == AType.Measurements)
3771 				pd.showDialog(type);
3772 			return;
3773 		}
3774 		if (tfToggle == null) {
3775 			// exists and "TOGGLE", but id could be an AnnotationData, not a JDialog
3776 			if (id.isDialog())
3777 				((JSVDialog) id).setVisible(!((JSVDialog) id).isVisible());
3778 				// was tfToggle != null && ((AnnotationDialog) id).isVisible());
3779 			else
3780 				pd.showDialog(type);  //	was			id.setState(!id.getState());
3781 			return;
3782 		}
3783 		// exists and "ON" or "OFF"
3784 		boolean isON = tfToggle.booleanValue();
3785 		if (isON)
3786 			id.setState(isON);
3787 		if (isON || id.isDialog())
3788 			pd.showDialog(type);
3789 		if (!isON && id.isDialog())
3790 			((JSVDialog) id).setVisible(false);
3791 
3792 		// if (type == AType.Integration)
3793 		// checkIntegral(parameters, "UPDATE");
3794 		// id.setState(tfToggle == null ? !id.getState() : tfToggle.booleanValue());
3795 	}
3796 
checkIntegralParams(Parameters parameters, String value)3797 	boolean checkIntegralParams(Parameters parameters, String value) {
3798 		Spectrum spec = getSpectrum();
3799 		if (!spec.canIntegrate() || reversePlot)
3800 			return false;
3801 		int iSpec = getFixedSelectedSpectrumIndex();
3802 		AnnotationData ad = getDialog(AType.Integration, -1);
3803 		if (value == null)// && ad != null)
3804 			return true;
3805 		switch (IntegralData.IntMode.getMode(value.toUpperCase())) {
3806 		case NA:
3807 			return false;
3808 		case CLEAR:
3809 			integrate(iSpec, null);
3810 			integrate(iSpec, parameters);
3811 			break;
3812 		case ON:
3813 			if (ad == null)
3814 				integrate(iSpec, parameters);
3815 			else
3816 				ad.setState(true);
3817 			break;
3818 		case OFF:
3819 			if (ad != null)
3820 				ad.setState(false);
3821 //			integrate(iSpec, null);
3822 			break;
3823 		case TOGGLE:
3824 			if (ad == null)
3825 				integrate(iSpec, parameters);
3826 			else
3827 				ad.setState(!ad.getState());
3828 //			integrate(iSpec, ad == null ? parameters : null);
3829 			break;
3830 		case AUTO:
3831 			if (ad == null) {
3832 				checkIntegralParams(parameters, "ON");
3833 				ad = getDialog(AType.Integration, -1);
3834 			}
3835 			if (ad != null)
3836 				((IntegralData) ad.getData()).autoIntegrate();
3837 			break;
3838 		case LIST:
3839 			pd.showDialog(AType.Integration);
3840 			break;
3841 		case MARK:
3842 			if (ad == null) {
3843 				checkIntegralParams(parameters, "ON");
3844 				ad = getDialog(AType.Integration, -1);
3845 			}
3846 			if (ad != null)
3847 				((IntegralData) ad.getData()).addMarks(value.substring(4).trim());
3848 			break;
3849 		case MIN:
3850 			if (ad != null) {
3851 				try {
3852 					double val = Double.parseDouble(ScriptToken.getTokens(value).get(1));
3853 					((IntegralData) ad.getData()).setMinimumIntegral(val);
3854 				} catch (Exception e) {
3855 					// ignore
3856 				}
3857 			}
3858 			break;
3859 		case UPDATE:
3860 			if (ad != null)
3861 				((IntegralData) ad.getData()).update(parameters);
3862 		}
3863 		updateDialog(AType.Integration, -1);
3864 		return true;
3865 	}
3866 
setSpectrum(int iSpec, boolean fromSplit)3867 	void setSpectrum(int iSpec, boolean fromSplit) {
3868 		if (fromSplit && nSplit > 1) {
3869 			if (nSplit > 1)
3870 				setSpectrumClicked(iSpec);
3871 		} else {
3872 			setSpectrumClicked(iSpec);
3873 			stackSelected = false;
3874 			showAllStacked = false;
3875 		}
3876 		if (iSpec >= 0)
3877 			dialogsToFront(getSpectrum());
3878 	}
3879 
setSpectrumJDX(Spectrum spec)3880 	void setSpectrumJDX(Spectrum spec) {
3881 		// T/A conversion for IR
3882 		int pt = getFixedSelectedSpectrumIndex();
3883 		spectra.removeItemAt(pt);
3884 		spectra.add(pt, spec);
3885 		pendingMeasurement = null;
3886 		clearViews();
3887 		viewData.newSpectrum(spectra);
3888 	}
3889 
setZoom(double x1, double y1, double x2, double y2)3890 	void setZoom(double x1, double y1, double x2, double y2) {
3891 		// called by
3892 		// 1. double-clicking on a tree node in the application to reset (0,0,0,0)
3893 		// 2. the YSCALE command (0,y1,0,y2)
3894 		// 3. the ZOOM command (0,0,0,0) or (x1, 0, x2, 0) or (x1, y1, x2, y2)
3895 		setZoomTo(0);
3896 		if (x1 == 0 && x2 == 0 && y1 == 0 && y2 == 0) {
3897 	 		newPins();
3898 		  // reset gray-factors as well
3899 			imageView = null;
3900 			// in case this is linked, transmit the x-zoom to linked spectra
3901 			x1 = getScale().minXOnScale;
3902 			x2 = getScale().maxXOnScale;
3903 		//} else if (x1 == 0 && x2 == 0) {
3904 		//	// y zoom only
3905 		//	x1 = x2 = 0;
3906 		//	imageView = null;
3907 		} else {
3908 			doZoom(x1, y1, x2, y2, true, (y1 != y2), false, true, true);
3909 		}
3910 	}
3911 	static final int SHIFT_PEAK = 1;
3912   static final int SHIFT_SETX = 2;
3913   static final int SHIFT_X = 3;
3914   static final int SHIFT_CLICKED = 4;
3915 
3916 	/**
3917 	 * apply a shift to the x-axis based on the next click or a specified value
3918 	 *
3919 	 * @param mode
3920 	 *          one of PEAK(1), SETX(2), X(3), CLICKED(4)
3921 	 * @param xOld
3922 	 *          initial position or NaN to ask, or value
3923 	 * @param xNew
3924 	 *          DOUBLE_MAX_VALUE - reset, NaN - ask, or value
3925 	 * @return true if accomplished
3926 	 */
shiftSpectrum(int mode, double xOld, double xNew)3927 	boolean shiftSpectrum(int mode, double xOld, double xNew) {
3928 
3929 		Spectrum spec = getSpectrum();
3930 		if (!spec.isNMR() || !spec.is1D())
3931 			return false;
3932 		String ok = null;
3933 		double dx = 0;
3934 		if (xNew == Double.MAX_VALUE) {
3935 			// setPeak NONE or setX NONE
3936 			dx = -spec.addSpecShift(0);
3937 		} else {
3938 			switch (mode) {
3939 			case SHIFT_X:
3940 				dx = xNew;
3941 				break;
3942 			case SHIFT_PEAK:
3943 			case SHIFT_SETX:
3944 				nextClickMode = mode;
3945 				if (Double.isNaN(xOld)) {
3946 					ok = pd
3947 							.getInput(
3948 									"Click on "
3949 											+ (mode == SHIFT_PEAK ? "or beside a peak to set its chemical shift"
3950 													: "the spectrum set the chemical shift at that point")
3951 											+ (xNew == Integer.MIN_VALUE ? "" : " to " + xNew) + ".",
3952 									"Set Reference "
3953 											+ (mode == SHIFT_PEAK ? "for Peak" : "at Point"), "OK");
3954 					nextClickForSetPeak = ("OK".equals(ok) ? Double.valueOf(xNew) : null);
3955 					return false;
3956 				}
3957 				nextClickForSetPeak = null;
3958 				//$FALL-THROUGH$
3959 			case SHIFT_CLICKED:
3960 				if (nextClickForSetPeak != null) {
3961 					xNew = nextClickForSetPeak.doubleValue();
3962 					nextClickForSetPeak = null;
3963 				}
3964 				if (Double.isNaN(xOld))
3965 					xOld = lastClickX;
3966 				if (nextClickMode == SHIFT_PEAK)
3967 					xOld = getNearestPeak(spec, xOld, toY(pd.mouseY));
3968 				if (Double.isNaN(xNew))
3969 					try {
3970 						String s = pd.getInput("New chemical shift (set blank to reset)",
3971 								"Set Reference",
3972 								DF.formatDecimalDbl(xOld, getScale().precision[0])).trim();
3973 						if (s.length() == 0)
3974 							xNew = xOld - spec.addSpecShift(0);
3975 						else
3976 							xNew = Double.parseDouble(s);
3977 					} catch (Exception e) {
3978 						return false;
3979 					}
3980 				dx = xNew - xOld;
3981 				break;
3982 			}
3983 		}
3984 		if (dx == 0)
3985 			return false;
3986 		spec.addSpecShift(dx);
3987 		if (annotations != null)
3988 			for (int i = annotations.size(); --i >= 0;)
3989 				if (annotations.get(i).spec == spec)
3990 					annotations.get(i).addSpecShift(dx);
3991 		if (dialogs != null)
3992 			for (Map.Entry<String, AnnotationData> e : dialogs.entrySet())
3993 				if (e.getValue().getSpectrum() == spec)
3994 					e.getValue().setSpecShift(dx);
3995 		// double dx0 = getScale().specShift;
3996 		// for (int i = viewList.size(); --i >= 0;)
3997 		// viewList.get(i).addSpecShift(dx);
3998 		// if (getScale().specShift == dx0)
3999 		getScale().addSpecShift(dx);
4000 		if (!Double.isNaN(lastClickX))
4001 			lastClickX += dx;
4002 		updateDialogs();
4003 		doZoom(0, getScale().minYOnScale, 0, getScale().maxYOnScale, true, true,
4004 				false, true, false);
4005 		pd.setTaintedAll();
4006 		pd.repaint();
4007 		return true;
4008 	}
4009 
toPeak(int istep)4010 	void toPeak(int istep) {
4011 		istep *= (drawXAxisLeftToRight ? 1 : -1);
4012 		if (Double.isNaN(lastClickX))
4013 			lastClickX = lastPixelX = 0;
4014 		Spectrum spec = getSpectrum();
4015 		Coordinate coord = setCoordClicked(lastPixelX, lastClickX, 0);
4016 		int iPeak = spec.setNextPeak(coord, istep);
4017 		if (iPeak < 0)
4018 			return;
4019 		PeakInfo peak = spec.getPeakList().get(iPeak);
4020 		spec.setSelectedPeak(peak);
4021 		setCoordClicked(peak.getXPixel(), peak.getX(), 0);
4022 		pd.notifyPeakPickedListeners(new PeakPickEvent(jsvp, pd.coordClicked,
4023 				peak));
4024 	}
4025 
4026 	// methods that only act on SELECTED spectra
4027 
scaleSelectedBy(double f)4028 	void scaleSelectedBy(double f) {
4029 		for (int i = bsSelected.nextSetBit(0); i >= 0; i = bsSelected
4030 				.nextSetBit(i + 1))
4031 			viewData.scaleSpectrum(i, f);
4032 	}
4033 
4034 	// overridden methods
4035 
4036 
4037 	@Override
toString()4038 	public String toString() {
4039 		return "gs: " + nSpectra + " " + spectra + " "
4040 				+ spectra.get(0).getFilePath();
4041 	}
4042 
setXPointer(Spectrum spec, double x)4043 	void setXPointer(Spectrum spec, double x) {
4044 		if (spec != null)
4045 			setSpectrumClicked(getSpectrumIndex(spec));
4046 		xValueMovedTo = lastClickX = x;
4047 		lastPixelX = toPixelX(x);
4048 		setXPixelMovedTo(x, Double.MAX_VALUE, 0, 0);
4049 		yValueMovedTo = Double.NaN;
4050 	}
4051 
setXPointer2(Spectrum spec, double x)4052 	void setXPointer2(Spectrum spec, double x) {
4053 		if (spec != null)
4054 			setSpectrumClicked(getSpectrumIndex(spec));
4055 		setXPixelMovedTo(Double.MAX_VALUE, x, 0, 0);
4056 	}
4057 
hasCurrentMeasurement(AType type)4058 	boolean hasCurrentMeasurement(AType type) {
4059 		return ((type == AType.Integration ? selectedSpectrumIntegrals
4060 				: selectedSpectrumMeasurements) != null);
4061 	}
4062 
4063 	private Map<String, AnnotationData> dialogs;
4064 	private Object[] aIntegrationRatios;
4065 
getDialog(AType type, int iSpec)4066 	AnnotationData getDialog(AType type, int iSpec) {
4067 		if (iSpec == -1)
4068 			iSpec = getCurrentSpectrumIndex();
4069 		return (dialogs == null || iSpec < 0 ? null : dialogs.get(type + "_" + iSpec));
4070 	}
4071 
removeDialog(int iSpec, AType type)4072 	void removeDialog(int iSpec, AType type) {
4073 		if (dialogs != null && iSpec >= 0)
4074 			dialogs.remove(type + "_" + iSpec);
4075 	}
4076 
addDialog(int iSpec, AType type, AnnotationData dialog)4077 	AnnotationData addDialog(int iSpec, AType type, AnnotationData dialog) {
4078 //		if (iSpec < 0) {
4079 //			iSpec = getSpectrumIndex(dialog.getSpectrum());
4080 //			dialog = null;
4081 //		}
4082 		if (dialogs == null)
4083 			dialogs = new Hashtable<String, AnnotationData>();
4084 		String key = type + "_" + iSpec;
4085 		dialog.setGraphSetKey(key);
4086 		dialogs.put(key, dialog);
4087 		return dialog;
4088 	}
4089 
removeDialog(JSVDialog dialog)4090 	void removeDialog(JSVDialog dialog) {
4091 		String key = dialog.getGraphSetKey();
4092 		dialogs.remove(key);
4093 		AnnotationData data = dialog.getData();
4094 		if (data != null)
4095 			dialogs.put(key, data);
4096 	}
4097 
getPeakListing(int iSpec, Parameters p, boolean forceNew)4098 	MeasurementData getPeakListing(int iSpec, Parameters p, boolean forceNew) {
4099 		if (iSpec < 0)
4100 			iSpec = getCurrentSpectrumIndex();
4101 		if (iSpec < 0)
4102 			return null;
4103 		AnnotationData dialog = getDialog(AType.PeakList, -1);
4104 		if (dialog == null) {
4105 			if (!forceNew)
4106 				return null;
4107 			addDialog(iSpec, AType.PeakList, dialog = new PeakData(AType.PeakList,
4108 					getSpectrum()));
4109 		}
4110 		((PeakData) dialog.getData()).setPeakList(p, Integer.MIN_VALUE, viewData.getScale());
4111 		if (dialog.isDialog())
4112 			((JSVDialog) dialog).setFields();
4113 		return dialog.getData();
4114 	}
4115 
setPeakListing(Boolean tfToggle)4116 	void setPeakListing(Boolean tfToggle) {
4117 		AnnotationData dialog = getDialog(AType.PeakList, -1);
4118 		JSVDialog ad = (dialog != null && dialog.isDialog() ? (JSVDialog) dialog : null);
4119 		boolean isON = (tfToggle == null ? ad == null || !ad.isVisible() : tfToggle.booleanValue());
4120 		if (isON) {
4121 			pd.showDialog(AType.PeakList);
4122 		} else {
4123 			if (dialog.isDialog())
4124 				((JSVDialog) dialog).setVisible(false);
4125 		}
4126 	}
4127 
haveIntegralDisplayed(int i)4128 	boolean haveIntegralDisplayed(int i) {
4129 		AnnotationData ad = getDialog(AType.Integration, i);
4130 		return (ad != null && ad.getState());
4131 	}
4132 
getIntegrationGraph(int i)4133 	IntegralData getIntegrationGraph(int i) {
4134 		AnnotationData ad = getDialog(AType.Integration, i);
4135 		return (ad == null ? null : (IntegralData) ad.getData());
4136 	}
4137 
setIntegrationRatios(String value)4138 	void setIntegrationRatios(String value) {
4139 		int iSpec = getFixedSelectedSpectrumIndex();
4140 		if (aIntegrationRatios == null)
4141 			aIntegrationRatios = new Object[nSpectra];
4142 		aIntegrationRatios[iSpec] = IntegralData.getIntegrationRatiosFromString(
4143 				getSpectrum(), value);
4144 	}
4145 
4146 	/**
4147 	 * deprecated -- or at least not compatible with multiple spectra
4148 	 *
4149 	 * @param i
4150 	 * @return list
4151 	 */
4152 	@SuppressWarnings("unchecked")
getIntegrationRatios(int i)4153 	Lst<Annotation> getIntegrationRatios(int i) {
4154 		return (Lst<Annotation>) (aIntegrationRatios == null ? null
4155 				: aIntegrationRatios[i]);
4156 	}
4157 
integrate(int iSpec, Parameters parameters)4158 	boolean integrate(int iSpec, Parameters parameters) {
4159 		Spectrum spec = getSpectrumAt(iSpec);
4160 		if (parameters == null || !spec.canIntegrate()) {
4161 			removeDialog(iSpec, AType.Integration);
4162 			return false;
4163 		}
4164 		addDialog(iSpec, AType.Integration, new IntegralData(spec, parameters));
4165 		return true;
4166 	}
4167 
getIntegration(int iSpec, Parameters p, boolean forceNew)4168 	IntegralData getIntegration(int iSpec, Parameters p, boolean forceNew) {
4169 		if (iSpec < 0)
4170 			iSpec = getCurrentSpectrumIndex();
4171 		if (iSpec < 0)
4172 			return null;
4173 		AnnotationData dialog = getDialog(AType.Integration, -1);
4174 		if (dialog == null) {
4175 			if (!forceNew)
4176 				return null;
4177 			dialog = addDialog(iSpec, AType.Integration, new IntegralData(getSpectrum(), p));
4178 		}
4179 		return (IntegralData) dialog.getData();
4180 	}
4181 
getMeasurementInfo(AType type, int iSpec)4182 	Map<String, Object> getMeasurementInfo(AType type, int iSpec) {
4183 	  MeasurementData md;
4184 		switch (type) {
4185 		case PeakList:
4186 			md = getPeakListing(iSpec, null, false);
4187   		break;
4188 		case Integration:
4189 			md = getIntegration(iSpec, null, false);
4190 			break;
4191 		default:
4192 			return null;
4193 		}
4194 		if (md == null)
4195 			return null;
4196 		Map<String, Object> info = new Hashtable<String, Object>();
4197 		md.getInfo(info);
4198 		return info;
4199 	}
4200 
getInfo(String key, int iSpec)4201 	Map<String, Object> getInfo(String key, int iSpec) {
4202 		Map<String, Object> spectraInfo = new Hashtable<String, Object>();
4203 		if ("".equals(key)) {
4204 			spectraInfo.put("KEYS", "viewInfo spectra");
4205 		} else if ("viewInfo".equalsIgnoreCase(key))
4206 			return getScale().getInfo(spectraInfo);
4207 		Lst<Map<String, Object>> specInfo = new Lst<Map<String, Object>>();
4208 		spectraInfo.put("spectra", specInfo);
4209 		for (int i = 0; i < nSpectra; i++) {
4210 			if (iSpec >= 0 && i != iSpec)
4211 				continue;
4212 			Spectrum spec = spectra.get(i);
4213 			Map<String, Object> info = spec.getInfo(key);
4214 			if (iSpec >= 0 && key != null
4215 					&& (info.size() == 2 || key.equalsIgnoreCase("id"))) {
4216 				if (info.size() == 2)
4217 					info.remove("id");
4218 				return info;
4219 			}
4220 			Parameters.putInfo(key, info, "type", spec.getDataType());
4221 			Parameters.putInfo(key, info, "titleLabel", spec.getTitleLabel());
4222 			Parameters.putInfo(key, info, "filePath", spec.getFilePath().replace('\\', '/'));
4223 			Parameters.putInfo(key, info, "PeakList", (Parameters.isMatch(key,
4224 					"PeakList") ? getMeasurementInfo(AType.PeakList, i) : null));
4225 			Parameters.putInfo(key, info, "Integration", (Parameters.isMatch(key,
4226 					"Integration") ? getMeasurementInfo(AType.Integration, i) : null));
4227 			if (iSpec >= 0)
4228 				return info;
4229 			specInfo.addLast(info);
4230 		}
4231 		return spectraInfo;
4232 	}
4233 
4234 	/**
4235 	 *
4236 	 * @param forPrinting  (could be preparing to print)
4237 	 * @return null if ambiguous, otherwise JDXSpectrum.getTitle()
4238 	 *
4239 	 */
getTitle(boolean forPrinting)4240 	String getTitle(boolean forPrinting) {
4241 		return (nSpectra == 1 || iSpectrumSelected >= 0 && (!forPrinting || nSplit == 1) ?
4242 			getSpectrum().getTitle() : null);
4243 	}
4244 
getCurrentView()4245 	ScaleData getCurrentView() {
4246 		setScale(getFixedSelectedSpectrumIndex());
4247 		return viewData.getScale();
4248 	}
4249 
set2DXY(double x, double y, boolean isLocked)4250 	void set2DXY(double x, double y, boolean isLocked) {
4251 		int p;
4252 		if (gs2dLinkedX != null) {
4253 			p = toPixelX(x);
4254 			if(p != fixX(p)) {
4255 				p = Integer.MIN_VALUE;
4256 				x = Double.MAX_VALUE;
4257 			}
4258 			cur1D2x1.setX(x, p);
4259 		}
4260 		if (gs2dLinkedY != null) {
4261 			p = toPixelX(y);
4262 			if(p != fixX(p)) {
4263 				p = Integer.MIN_VALUE;
4264 				y = Double.MAX_VALUE;
4265 			}
4266 			cur1D2x2.setX(y, p);
4267 		}
4268 		cur1D2Locked = isLocked;
4269 	}
4270 
dialogsToFront(Spectrum spec)4271 	void dialogsToFront(Spectrum spec) {
4272 		if (dialogs == null)
4273 			return;
4274 		if (spec == null)
4275 			spec = getSpectrum();
4276 		for (Map.Entry<String, AnnotationData> e : dialogs.entrySet()) {
4277 			AnnotationData ad = e.getValue();
4278 			if (isVisible(ad)) {
4279 				if (spec == null)
4280 				((JSVDialog) ad).setVisible(true);
4281 				else
4282 					((JSVDialog) ad).setFocus(ad.getSpectrum() == spec);
4283 			}
4284 		}
4285 	}
4286 
4287 
4288 	//////////////////////////// WAS AWTGRAPHSET //////////////
4289 
4290 
setPlotColors(Object oColors)4291   void setPlotColors(Object oColors) {
4292     GenericColor[] colors = (GenericColor[]) oColors;
4293     if (colors.length > nSpectra) {
4294       GenericColor[] tmpPlotColors = new GenericColor[nSpectra];
4295       System.arraycopy(colors, 0, tmpPlotColors, 0, nSpectra);
4296       colors = tmpPlotColors;
4297     } else if (nSpectra > colors.length) {
4298       GenericColor[] tmpPlotColors = new GenericColor[nSpectra];
4299       int numAdditionColors = nSpectra - colors.length;
4300       System.arraycopy(colors, 0, tmpPlotColors, 0, colors.length);
4301       for (int i = 0, j = colors.length; i < numAdditionColors; i++, j++)
4302         tmpPlotColors[j] = generateRandomColor();
4303       colors = tmpPlotColors;
4304     }
4305     plotColors = colors;
4306   }
4307 
4308   private JSVPanel jsvp;
4309   private Object image2D;
4310   private GenericColor[] plotColors;
4311 	private GenericGraphics g2d;
4312 	private Object gMain;
4313 
4314 
disposeImage()4315   private void disposeImage() {
4316     /**
4317      * @j2sNative
4318      *
4319      * if (this.image2D != null)
4320      *   this.image2D.parentNode.removeChild(this.image2D);
4321      *
4322      */
4323     {}
4324     image2D = null;
4325     jsvp = null;
4326     pd = null;
4327     highlights = null;
4328     plotColors = null;
4329   }
4330 
4331 
generateRandomColor()4332   private GenericColor generateRandomColor() {
4333     while (true) {
4334       int red = (int) (Math.random() * 255);
4335       int green = (int) (Math.random() * 255);
4336       int blue = (int) (Math.random() * 255);
4337       GenericColor randomColor = g2d.getColor3(red, green, blue);
4338       if (randomColor.getRGB() != 0)
4339         return randomColor;
4340     }
4341   }
4342 
setPlotColor0(Object oColor)4343 	void setPlotColor0(Object oColor) {
4344     plotColors[0] = (GenericColor) oColor;
4345   }
4346 
4347   /**
4348    * Returns the color of the plot at a certain index
4349    *
4350    * @param index
4351    *        the index
4352    * @return the color of the plot
4353    */
getPlotColor(int index)4354   GenericColor getPlotColor(int index) {
4355     if (index >= plotColors.length)
4356       return null;
4357     return plotColors[index];
4358   }
4359 
4360 
setColorFromToken(Object og, ScriptToken whatColor)4361 	private void setColorFromToken(Object og, ScriptToken whatColor) {
4362 		if (whatColor != null)
4363 			g2d.setGraphicsColor(og,
4364 					whatColor == ScriptToken.PLOTCOLOR ? plotColors[0] : pd
4365 							.getColor(whatColor));
4366 	}
4367 
4368 	private final int COLOR_GREY = -3;
4369 	private final int COLOR_BLACK = -2;
4370 	private final int COLOR_INTEGRAL = -1;
4371 
setPlotColor(Object og, int i)4372   private void setPlotColor(Object og, int i) {
4373   	GenericColor c;
4374   	switch (i) {
4375   	case COLOR_GREY:
4376   		c = veryLightGrey;
4377   		break;
4378   	case COLOR_BLACK:
4379   		c = pd.BLACK;
4380   		break;
4381   	case COLOR_INTEGRAL:
4382   		c = pd.getColor(ScriptToken.INTEGRALPLOTCOLOR);
4383   		break;
4384     default:
4385     	c = plotColors[i];
4386   		break;
4387   	}
4388   	g2d.setGraphicsColor(og, c);
4389   }
4390 
4391   /////////////// 2D image /////////////////
4392 
4393 
draw2DImage()4394 	private void draw2DImage() {
4395     if (imageView != null)
4396     	g2d.drawGrayScaleImage(gMain, image2D, imageView.xPixel0, imageView.yPixel0, // destination
4397           imageView.xPixel0 + imageView.xPixels - 1, // destination
4398           imageView.yPixel0 + imageView.yPixels - 1, // destination
4399           imageView.xView1, imageView.yView1, imageView.xView2, imageView.yView2); // source
4400   }
4401 
4402 
get2DImage(Spectrum spec0)4403   private boolean get2DImage(Spectrum spec0) {
4404     imageView = new ImageView();
4405     imageView.set(viewList.get(0).getScale());
4406     if (!update2dImage(true))
4407       return false;
4408     imageView.resetZoom();
4409     sticky2Dcursor = true;// I don't know why
4410     return true;
4411   }
4412 
4413 
update2dImage(boolean isCreation)4414 	private boolean update2dImage(boolean isCreation) {
4415 		imageView.set(viewData.getScale());
4416 		Spectrum spec = getSpectrumAt(0);
4417 		int[] buffer = imageView.get2dBuffer(spec, !isCreation);
4418 		if (buffer == null) {
4419 			image2D = null;
4420 			imageView = null;
4421 			return false;
4422 		}
4423 		if (isCreation) {
4424 			buffer = imageView.adjustView(spec, viewData);
4425 			imageView.resetView();
4426 		}
4427 		image2D = g2d.newGrayScaleImage(gMain, image2D, imageView.imageWidth, imageView.imageHeight, buffer);
4428 		setImageWindow();
4429 		return true;
4430 	}
4431 
getAnnotation(double x, double y, String text, boolean isPixels, boolean is2d, int offsetX, int offsetY)4432 	private Annotation getAnnotation(double x, double y, String text,
4433 			boolean isPixels, boolean is2d, int offsetX, int offsetY) {
4434 		return new ColoredAnnotation().setCA(x, y, getSpectrum(), text, pd.BLACK,
4435 				isPixels, is2d, offsetX, offsetY);
4436 	}
4437 
getAnnotation(Lst<String> args, Annotation lastAnnotation)4438 	private Annotation getAnnotation(Lst<String> args, Annotation lastAnnotation) {
4439 		return Annotation.getColoredAnnotation(g2d, getSpectrum(), args, lastAnnotation);
4440   }
4441 
fillBox(Object g, int x0, int y0, int x1, int y1, ScriptToken whatColor)4442   private void fillBox(Object g, int x0, int y0, int x1, int y1,
4443                          ScriptToken whatColor) {
4444     setColorFromToken(g, whatColor);
4445     g2d.fillRect(g, Math.min(x0, x1), Math.min(y0, y1), Math.abs(x0
4446 				    - x1), Math.abs(y0 - y1));
4447   }
4448 
drawBox(Object g, int x0, int y0, int x1, int y1, ScriptToken whatColor)4449 	private void drawBox(Object g, int x0, int y0, int x1, int y1,
4450 			ScriptToken whatColor) {
4451 		setColorFromToken(g, whatColor);
4452 		g2d.drawRect(g, Math.min(x0, x1), Math.min(y0, y1), Math.abs(x0 - x1) - 1,
4453 				Math.abs(y0 - y1) - 1);
4454 	}
4455 
drawHandle(Object g, int x, int y, int size, boolean outlineOnly)4456   private void drawHandle(Object g, int x, int y, int size, boolean outlineOnly) {
4457     if (outlineOnly)
4458       g2d.drawRect(g, x - size, y - size, size*2, size*2);
4459     else
4460       g2d.fillRect(g, x - size, y - size, size*2 + 1, size*2+1);
4461   }
4462 
setCurrentBoxColor(Object g)4463    private void setCurrentBoxColor(Object g) {
4464     g2d.setGraphicsColor(g, pd.BLACK);
4465   }
4466 
fillArrow(Object g, int type, int x, int y, boolean doFill)4467 	private void fillArrow(Object g, int type, int x, int y, boolean doFill) {
4468 		int f = 1;
4469 		switch (type) {
4470 		case ARROW_LEFT:
4471 		case ARROW_UP:
4472 			f = -1;
4473 			break;
4474 		}
4475 		int[] axPoints = new int[] { x - 5,   x - 5, x + 5,   x + 5,   x + 8,        x, x - 8 };
4476 		int[] ayPoints = new int[] { y + 5*f, y - f, y - f, y + 5*f, y + 5*f, y + 10*f, y + 5*f };
4477 		switch (type) {
4478 		case ARROW_LEFT:
4479 		case ARROW_RIGHT:
4480 			if (doFill)
4481 				g2d.fillPolygon(g, ayPoints, axPoints, 7);
4482 			else
4483 				g2d.drawPolygon(g, ayPoints, axPoints, 7);
4484 			break;
4485 		case ARROW_UP:
4486 		case ARROW_DOWN:
4487 			if (doFill)
4488 				g2d.fillPolygon(g, axPoints, ayPoints, 7);
4489 			else
4490 				g2d.drawPolygon(g, axPoints, ayPoints, 7);
4491 
4492 		}
4493 	}
4494 
fillCircle(Object g, int x, int y, boolean doFill)4495 	private void fillCircle(Object g, int x, int y, boolean doFill) {
4496 		if (doFill)
4497   		g2d.fillCircle(g, x-4, y-4, 8);
4498 		else
4499 			g2d.drawCircle(g, x-4, y-4, 8);
4500 	}
4501 
setAnnotationColor(Object g, Annotation note, ScriptToken whatColor)4502 	void setAnnotationColor(Object g, Annotation note,
4503 			ScriptToken whatColor) {
4504 		if (whatColor != null) {
4505 			setColorFromToken(g, whatColor);
4506 			return;
4507 		}
4508 		GenericColor color = null;
4509 		if (note instanceof ColoredAnnotation)
4510 			color = ((ColoredAnnotation) note).getColor();
4511 		if (color == null)
4512 			color = pd.BLACK;
4513 		g2d.setGraphicsColor(g, color);
4514 	}
4515 
setSolutionColor(VisibleInterface vi, boolean isNone, boolean asFitted)4516 	public void setSolutionColor(VisibleInterface vi, boolean isNone, boolean asFitted) {
4517 		for (int i = 0; i < nSpectra; i++) {
4518 			Spectrum spec = spectra.get(i);
4519 			int color = (isNone || !spec.canShowSolutionColor() ? -1 : vi.getColour(spec, asFitted));
4520 			spec.setFillColor(color == -1 ? null : pd.vwr.parameters.getColor1(color));
4521 		}
4522 	}
4523 
setIRMode(IRMode mode, String type)4524 	public void setIRMode(IRMode mode, String type) {
4525 		for (int i = 0; i < nSpectra; i++) {
4526 			Spectrum spec = spectra.get(i);
4527 			if (!spec.dataType.equals(type))
4528 				continue;
4529 			Spectrum spec2 = Spectrum.taConvert(spec, mode);
4530 			if (spec2 != spec)
4531 				pd.setSpecForIRMode(spec2);
4532 		}
4533 	}
4534 
getSpectrumCount()4535 	public int getSpectrumCount() {
4536 		// TODO Auto-generated method stub
4537 		return 0;
4538 	}
4539 
invertYAxis()4540 	public void invertYAxis() {
4541 		viewList.get(0).init(null, 0, 0, getSpectrum().invertYAxis().isContinuous());
4542 		resetViewCompletely();
4543 	}
4544 
4545 }
4546