001 package ui.recognizer;
002
003 import javax.swing.*;
004 import java.awt.*;
005 import java.awt.event.*;
006 import java.awt.geom.*;
007 import java.awt.image.*;
008 import java.net.*;
009 import java.io.*;
010 import java.text.*;
011 import java.util.*;
012 import java.util.Collection.*;
013
014 import java.awt.dnd.*;
015 import java.awt.datatransfer.*;
016
017 public class PlotRecognizer extends JFrame implements ItemListener, ActionListener, DropTargetListener {
018
019 public static final String FILE = "File";
020 public static final String FILE_LOAD = "Load Image";
021 public static final String FILE_SAVE = "Save Data"; // disabled until data available
022 public static final String FILE_QUIT = "Quit";
023 JMenuItem saveMenuItem; // disabled until data available
024
025 JMenu editMenu; // disabled until image is loaded
026 public static final String EDIT = "Edit";
027 public static final String EDIT_CLEAN = "Remove blemishes";
028 public static final String EDIT_REMOVE_GRID= "Remove grid";
029 public static final String EDIT_CALIBRATE = "Calibrate axes";
030 public static final String EDIT_WINDOW = "Restrict data to window";
031 public static final String EDIT_RECOGNIZE = "Recognize plot";
032
033 JMenu viewMenu; // disabled until image is loaded
034 public static final String VIEW = "View";
035 public static final String VIEW_ZOOM_IN = "Zoom out";
036 public static final String VIEW_ZOOM_OUT = "Zoom in";
037 public static final String VIEW_ZOOM_NORMAL= "Zoom normal";
038
039 JMenu dataMenu; // disabled until data available
040 public static final String DATA = "Data";
041 public static final String DATA_MODIFY = "View or modify data";
042 public static final String DATA_SMOOTH = "Smooth data";
043 public static final String DATA_FLATEN = "Flaten data";
044 public static final String DATA_OVERLAY = "Show overlay";
045
046 public static int WIDTH = 1024;
047 public static int HEIGHT = 768;
048
049 JFileChooser loadFileChooser = new PlotFileChooser("Load a GIF or PNG plot image to be recognized",
050 "Image Files", new String[] {"gif", "png"});
051 JFileChooser saveFileChooser = new PlotFileChooser("Save recognized plot data as x, y file",
052 "Data Files", new String[] {"txt", "dat"});
053
054 // fields which determine the state of the plot processor
055
056 DataCoordinate[] data;
057 ImageCoordinate[] imagePoints;
058 ImageIcon imageIcon = null;
059
060 //Rectangle plotBorder = null; // the image coordinates of the plot border
061 Calibration calibration;
062
063 public static String DATA_OUTPUT_FORMAT_TEXT = "text";
064 public static String DATA_OUTPUT_FORMAT_XML = "xml";
065 public static String DATA_OUTPUT_FORMAT_FITS = "fits";
066
067 private String dataOutputFormat = DATA_OUTPUT_FORMAT_TEXT;
068 private String xTextOutputFormat = "0.00";
069 private String yTextOutputFormat = "0.0000";
070
071 private int blackThreshold = 128;
072
073 // the data ranges (will be different for most plots)
074 private double xlow = 0.0d;
075 private double xhigh = 1.0d;
076 private double ylow = 0.0d;
077 private double yhigh = 1.0d;
078
079 private int samples = 0;
080 private String dataFileType = ".dat";
081 private String dataFileName;
082 private String imageFileName;
083 private boolean imageLoaded = false;
084 private boolean dataAvailable = false;
085 private boolean overlay = true;
086 private boolean axesCalibrated = false;
087
088 JScrollPane scrollPane = new JScrollPane(new JLabel("Load Image"));
089
090 public PlotRecognizer(String aTitle) {
091 super(aTitle);
092 }
093
094 public void init() {
095 JMenuBar menuBar = createMenu();
096 setJMenuBar(menuBar);
097 scrollPane.setPreferredSize(new Dimension(400, 100));
098 getContentPane().add(scrollPane);
099 setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
100
101 // TODO: create a mousemotion listener and show coordinates in status bar or title bar ...
102 setSize(new Dimension(WIDTH, HEIGHT));
103 setDropTarget(new DropTarget(this, this)); // set this JFrame as a drag and drop drop target
104 pack();
105 setVisible(true);
106 }
107
108 public JMenuBar createMenu() {
109 //Create the menu bar.
110 JMenuBar menuBar = new JMenuBar();
111
112 JMenu fileMenu = new JMenu(FILE);
113 //fileMenu.setMnemonic('f');
114 fileMenu.getAccessibleContext().setAccessibleDescription("The File menu");
115 fileMenu.add(createSimpleMenuItem(FILE, FILE_LOAD, "Load an image containing a plot"));
116 saveMenuItem = createSimpleMenuItem(FILE, FILE_SAVE, "Save the recognized plot data");
117 saveMenuItem.setEnabled(isDataAvailable());
118 fileMenu.add(saveMenuItem);
119 fileMenu.add(createSimpleMenuItem(FILE, FILE_QUIT, "Quit the application without saving data"));
120 menuBar.add(fileMenu);
121
122 editMenu = new JMenu(EDIT);
123 editMenu.getAccessibleContext().setAccessibleDescription("The Edit menu");
124 editMenu.add(createSimpleMenuItem(EDIT, EDIT_CLEAN, "Remove blemishes such as isolated pixels and dust shadows"));
125 editMenu.add(createSimpleMenuItem(EDIT, EDIT_REMOVE_GRID, "Remove grids"));
126 editMenu.add(createSimpleMenuItem(EDIT, EDIT_CALIBRATE, "Remove blemishes such as isolated pixels and dust shadows"));
127 editMenu.add(createSimpleMenuItem(EDIT, EDIT_WINDOW, "Restrict the data to a window"));
128 editMenu.add(createSimpleMenuItem(EDIT, EDIT_RECOGNIZE, "Recognize the plot and produce plot data"));
129 editMenu.setEnabled(isImageLoaded());
130 menuBar.add(editMenu);
131
132 viewMenu = new JMenu(VIEW);
133 viewMenu.getAccessibleContext().setAccessibleDescription("The View menu");
134 viewMenu.add(createSimpleMenuItem(VIEW, VIEW_ZOOM_IN, "Zoom in image"));
135 viewMenu.add(createSimpleMenuItem(VIEW, VIEW_ZOOM_OUT, "Zoom out image"));
136 viewMenu.add(createSimpleMenuItem(VIEW, VIEW_ZOOM_NORMAL, "Zoom normal"));
137 viewMenu.setEnabled(isImageLoaded());
138 menuBar.add(viewMenu);
139
140 dataMenu = new JMenu(DATA);
141 dataMenu.getAccessibleContext().setAccessibleDescription("The Data menu");
142 dataMenu.add(createSimpleMenuItem(DATA, DATA_MODIFY, "View and/or modify the data in a table"));
143 dataMenu.add(createSimpleMenuItem(DATA, DATA_SMOOTH, "Smooth the data to eliminate high frequencies"));
144 dataMenu.add(createSimpleMenuItem(DATA, DATA_FLATEN, "Flatent the data to eliminate low frequencies"));
145 dataMenu.add(createCheckBoxMenuItem(DATA_OVERLAY, DATA_OVERLAY, "Show overlay", isOverlay()));
146 dataMenu.setEnabled(isDataAvailable());
147 menuBar.add(dataMenu);
148
149 return menuBar;
150 }
151
152 private JMenuItem createSimpleMenuItem(String aMenu, String aLabel, String anAccessibleDescription) {
153 JMenuItem simpleMenuItem = new JMenuItem(aLabel);
154 simpleMenuItem.getAccessibleContext().setAccessibleDescription(anAccessibleDescription);
155 simpleMenuItem.setName(aMenu);
156 simpleMenuItem.setActionCommand(aLabel);
157 simpleMenuItem.addActionListener(this);
158 return simpleMenuItem;
159 }
160
161 private JMenuItem createSimpleMenuItem(String aMenu, String aLabel, String anAccessibleDescription, int aShortcut) {
162 JMenuItem simpleMenuItem = createSimpleMenuItem(aMenu, aLabel, anAccessibleDescription);
163 simpleMenuItem.setAccelerator(KeyStroke.getKeyStroke(aShortcut, ActionEvent.CTRL_MASK));
164 return simpleMenuItem;
165 }
166
167 private JMenuItem createCheckBoxMenuItem(String aMenu, String aLabel, String anAccessibleDescription, boolean aSelected) {
168 JCheckBoxMenuItem checkBoxMenuItem = new JCheckBoxMenuItem(aLabel);
169 checkBoxMenuItem.getAccessibleContext().setAccessibleDescription(anAccessibleDescription);
170 checkBoxMenuItem.setName(aMenu);
171 checkBoxMenuItem.setActionCommand(aLabel);
172 checkBoxMenuItem.setSelected(aSelected); // must be set before adding item listener
173 checkBoxMenuItem.addItemListener(this);
174 return checkBoxMenuItem;
175 }
176
177 // BUG: this never gets called, why ?
178 public void itemStateChanged(ItemEvent e) {
179 JMenuItem source = (JMenuItem) (e.getSource()); // this property is the action 'grouper'
180 String name = source.getName(); // this property is the specific selection
181 boolean repaint = false;
182 if (e.getStateChange() == ItemEvent.SELECTED) {
183 if (name.equals(DATA_OVERLAY)) {
184 setOverlay(true);
185 repaint = true;
186 }
187 } else if (e.getStateChange() == ItemEvent.DESELECTED) {
188 if (name.equals(DATA_OVERLAY)) {
189 setOverlay(false);
190 repaint = true;
191 }
192 }
193 if (repaint) reDraw();
194 }
195
196 public void reDraw() {
197 // TODO:
198 };
199
200 // implementation for ActionListener (menus and popup menus)
201 public void actionPerformed(ActionEvent e) {
202 JMenuItem source = (JMenuItem) (e.getSource());
203 String name = source.getName();
204 String action = source.getActionCommand();
205 boolean repaint = false;
206 if (name.equals(FILE)) {
207 if (action.equals(FILE_LOAD)) {
208 loadImage();
209 } else if (action.equals(FILE_SAVE)) {
210 saveData();
211 } else if (action.equals(FILE_QUIT)) {
212 System.exit(0);
213 }
214 } else if (name.equals(EDIT)) {
215 if (action.equals(EDIT_CALIBRATE)) {
216 calibrate();
217 } else if (action.equals(EDIT_RECOGNIZE)) {
218 recognize();
219 }
220 }
221 // outline the graph frame (if no outline is specified pixel coordinates are used as a metric and bounds are edges of image)
222 // manual : click on at least three corners (parallelogram like-behavior)
223 // automatic (a statitical estimate is made of the location and orientation of the axis lines)
224 if (repaint) reDraw();
225 }
226
227 public void loadImage() {
228 setDataAvailable(false); // new image must be recognized before data becomes available
229 if (loadFileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { // BUG: 'up' icon in file chooser is disabled
230 // if File is a directory then process all files in that directory
231 //UIUtilities.setWaitCursor(this, true);
232 loadFileChooser.getSelectedFile();
233 loadImage(loadFileChooser.getSelectedFile());
234 }
235 }
236
237 private XRule xRule;
238 private YRule yRule;
239
240 private JToggleButton isDataUnits;
241
242 public void loadImage(File aFile) {
243 setDataAvailable(false);
244 if (scrollPane == null) return;
245 try {
246 setImageFileName(aFile.getName());
247 imageIcon = new ImageIcon(aFile.toURL());
248
249 setUpScrollPane(imageIcon);
250
251 //Image image = Toolkit.getDefaultToolkit().getImage(getFileName());
252 //Image img = UIUtilities.getImage(getFileName());
253
254 setImageLoaded(true);
255 } catch(Exception ex) {
256 System.out.println("Could not open file : " + ex);
257 }
258 }
259
260 void setUpScrollPane(ImageIcon anImageIcon) {
261
262 // default calibration
263 Rectangle plotBorder = new Rectangle(0, 0, anImageIcon.getIconWidth(), anImageIcon.getIconHeight());
264 //Rectangle ticZone = plotBorder;
265 calibration = new Calibration(plotBorder);
266
267 // create the rulers
268 xRule = new XRule(true, calibration, null);
269 xRule.setPreferredWidth(anImageIcon.getIconWidth());
270 yRule = new YRule(true, calibration);
271 yRule.setPreferredHeight(anImageIcon.getIconHeight());
272
273 // Create the corners
274 JPanel buttonCorner = new JPanel();
275 isDataUnits = new JToggleButton("Data", true);
276 isDataUnits.setFont(new Font("SansSerif", Font.PLAIN, 11));
277 isDataUnits.setMargin(new Insets(2,2,2,2));
278 isDataUnits.addItemListener(new UnitsListener());
279 buttonCorner.add(isDataUnits); //Use the default FlowLayout
280
281 // Create the main view
282 JLabel label = new JLabel(anImageIcon);
283 label.setVerticalAlignment(JLabel.TOP);
284 label.setHorizontalAlignment(JLabel.LEFT);
285
286 scrollPane.setViewportView(label);
287 scrollPane.setPreferredSize(new Dimension(300, 250));
288 scrollPane.setViewportBorder(BorderFactory.createLineBorder(Color.black));
289 scrollPane.setColumnHeaderView(xRule);
290 scrollPane.setRowHeaderView(yRule);
291 scrollPane.setCorner(JScrollPane.UPPER_LEFT_CORNER, buttonCorner);
292 scrollPane.setCorner(JScrollPane.LOWER_LEFT_CORNER, new Corner());
293 scrollPane.setCorner(JScrollPane.UPPER_RIGHT_CORNER, new Corner());
294 }
295
296 class UnitsListener implements ItemListener {
297 public void itemStateChanged(ItemEvent e) {
298 if (e.getStateChange() == ItemEvent.SELECTED) {
299 // Turn it to metric.
300 yRule.setDataUnits(true);
301 xRule.setDataUnits(true);
302 } else {
303 // Turn it to inches.
304 yRule.setDataUnits(false);
305 xRule.setDataUnits(false);
306 }
307 //picture.setMaxUnitIncrement(yRule.getIncrement());
308 }
309 }
310
311 /** Bring up a file requestor and save the current data into that file.
312 */
313 public void saveData() {
314 // TODO: use the file name for the current image, strip its terminator and append .txt
315 // BUG: 'up' icon in file chooser is disabled
316 if (saveFileChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION)
317 saveData(saveFileChooser.getSelectedFile());
318 }
319
320 /** Save the current data as file, the file will be saved in the current export format
321 * @param aFile a file in which to save the data
322 */
323 public void saveData(File aFile) {
324 String format = getDataOutputFormat();
325 DecimalFormat xFormatter = new DecimalFormat(getXTextOutputFormat());
326 DecimalFormat yFormatter = new DecimalFormat(getYTextOutputFormat());
327 //String output = xFormatter.format(value);
328
329 if (format != null && format.equals(DATA_OUTPUT_FORMAT_TEXT)) {
330 for (int i = 0; i < getSamples(); i++) {
331 DataCoordinate sample = data[i];
332 System.out.println(xFormatter.format(sample.getX()) + " " +
333 yFormatter.format(sample.getY()) );
334 }
335 }
336 }
337
338 /** Process a list of image files. The list could be a product of a
339 * drag and drop operation involving multiple files or it could be constructed from a special file
340 * containing a list of filenames. The calibration and recognition steps are performed automatically.
341 * The calibration must be the same for all plots, they must have the same x-range.
342 * @param aListOfFiles a collection of File objects to be processed.
343 */
344 public void processFiles(java.util.List aListOfFiles) {
345 int files = aListOfFiles.size();
346 ProgressMonitor progressMonitor = new ProgressMonitor(this, "Recognizing a list of images", "", 0, files);
347 progressMonitor.setMillisToDecideToPopup(500);
348 for(int i = 0; i < files; i++ ) {
349 File file = (File) aListOfFiles.get(i);
350 if (file.isFile()) {
351 System.out.println("Processing file : " + file.getAbsolutePath());
352 loadImage(file);
353 recognize();
354 //saveData(new File(file.getName() + ".dat"));
355 progressMonitor.setProgress(i);
356 progressMonitor.setNote("Plot : " + getImageFileName());
357 } else if (file.isDirectory()){
358 System.out.println("Processing directory : " + file.getAbsolutePath());
359 //TODO: process all files in the dictory called 'file'
360 File[] fileList = file.listFiles();
361 processFiles(Arrays.asList(fileList)); // recursive call
362 }
363 }
364 progressMonitor.close();
365 }
366
367 /** Calibrate the image by asking for the user to click on the axes and to define a numerical value for the coordinates of those points.
368 */
369 public void calibrate() {
370 // setSamples(imageIcon.getWidth());
371 }
372
373 /** Recognize the image by iterating over the pixexl columns of the calibrated image window and by searching for
374 * the plot 'trace' or 'pen' which represents the function y=f(x).
375 */
376 public void recognize() {
377 Image image = imageIcon.getImage();
378 int width = image.getWidth(this);
379 int height = image.getHeight(this);
380 setSamples(width);
381 data = new DataCoordinate[getSamples()];
382 imagePoints = new ImageCoordinate[getSamples()];
383 BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY); // TYPE_INT_RGB
384 //bufferedImage = createImage(width, height);
385 Graphics2D g2 = bufferedImage.createGraphics();
386 g2.drawImage(image, 0, 0, this);
387
388 WritableRaster raster = bufferedImage.getRaster();
389 SampleModel sampleModel = raster.getSampleModel();
390 DataBufferByte dataBuffer = (DataBufferByte) raster.getDataBuffer();
391 byte[] byteData = dataBuffer.getData();
392
393
394 int edge = 40; // borders are about 40 pixels from the edge for LBQS quasars
395 // this area defines a rectangle which should be obtained during the calibration
396 int xEdgeLow = edge;
397 int xEdgeHigh = width - edge;
398 int yEdgeLow = edge;
399 int yEdgeHigh = height - edge;
400
401 // data for HD124448;
402 //edge = 100;
403 //int xEdgeLow = 0;
404 //int xEdgeHigh = width;
405 //int yEdgeLow = edge;
406 //int yEdgeHigh = height;
407
408 double x, y;
409 int penHeight;
410 double dataX, dataY;
411 for (int i = 0; i < getSamples(); i++) {
412 byte aByte;
413 penHeight = 0;
414 if (i > xEdgeLow && i < xEdgeHigh) {
415 int sumj = 0; // the sum of the height of the 'black' pixels
416 int blackPixels = 0; // the number of 'black' pixels
417 int offset = yEdgeLow * width + i;
418 for (int j = yEdgeLow; j < yEdgeHigh; j++) {
419 aByte = byteData[offset]; // -1 is white, 0 is black,
420 offset += width;
421 if (aByte >= 0 && aByte < getBlackThreshold()) {
422 sumj += j;
423 blackPixels++;
424 }
425 }
426 if (blackPixels > 0)
427 penHeight = sumj / blackPixels; // average of the height of the 'black' pixels
428 }
429 //dataX = 3200.0d + (7000.0d - 3200.0d) * (double) i / (double) width;
430 dataX = 3200.0d + (5160.0d - 3200.0d) * (double) i / (double) width;
431 if (penHeight == 0)
432 dataY = 0.0d;
433 else
434 dataY = (double) (height - penHeight)/ (double) height;
435
436 data[i] = new DataCoordinate(dataX, dataY);
437 imagePoints[i] = new ImageCoordinate(i, penHeight);
438 }
439 setDataAvailable(true);
440 xRule.setImagePoints(imagePoints); // let the x rule display a gray representation of plot data
441 }
442
443 public void overlay() {
444
445 // TODO: how do we draw into the viewport, use createImage(w,h) ?
446 //Graphics g = imageIcon.getImage().getGraphics();
447
448 if (imageIcon != null) {
449 ImageIcon newImageIcon;
450 if (isDataAvailable() && isOverlay()) {
451 Image image = imageIcon.getImage();
452 int width = imageIcon.getIconWidth();
453 int height = imageIcon.getIconHeight();
454
455 Image bufferedImage = createImage(width, height);
456 Graphics2D g2 = (Graphics2D) bufferedImage.getGraphics();
457 g2.drawImage(image, 0, 0, this);
458 g2.setColor(Color.red); // overlay color
459
460 ImageCoordinate point;
461 int x, y, lastx = 0, lasty = height-1;
462 for (int i = 0; i < getSamples(); i++) {
463 point = imagePoints[i];
464 if (point != null) {
465 x = (int) point.getX();
466 y = (int) point.getY();
467 if (y == 0) y = height-1;
468 g2.drawLine(lastx, lasty, x, y);
469 lastx = x;
470 lasty = y;
471 }
472 }
473 newImageIcon = new ImageIcon(bufferedImage);
474 } else {
475 newImageIcon = imageIcon; // clear overlay
476 }
477 JLabel label = new JLabel(newImageIcon);
478 label.setVerticalAlignment(JLabel.TOP);
479 label.setHorizontalAlignment(JLabel.LEFT);
480 scrollPane.setViewportView(label);
481 }
482 }
483
484 public static void main(String argv[]) {
485 final PlotRecognizer recognizer = new PlotRecognizer("Plot Recognizer v1.0");
486 recognizer.init();
487 }
488
489 //-----Accessor methods---------------------------------------------------------------------------------
490
491 /** Set the data output format such as text or xml.
492 * @param aDataOutputFormat the data output format
493 */
494 public void setDataOutputFormat(String aDataOutputFormat) {
495 dataOutputFormat = aDataOutputFormat;
496 }
497
498 /** Get the data output format such as text or xml.
499 * @return the data output format
500 */
501 public String getDataOutputFormat() {
502 return dataOutputFormat;
503 }
504
505 /** Get the text output format string for the x data values, which determines the precision or number of significant digits when exporting the x value as text
506 * @return a decimal format string for the x values
507 */
508 public String getXTextOutputFormat() {
509 return xTextOutputFormat;
510 }
511
512 /** Set the text output format string for the x data values.
513 * @param aXTextOutputFormat a string representing the decimal text output format for the x values
514 */
515 public void setXTextOutputFormat(String aXTextOutputFormat) {
516 xTextOutputFormat = aXTextOutputFormat;
517 }
518
519 /** Get the text output format string for the y data values, which determines the precision or number of significant digits when exporting the y value as text
520 * @return a decimal format string for the y values
521 */
522 public String getYTextOutputFormat() {
523 return yTextOutputFormat;
524 }
525
526 /** Set the text output format string for the y data values.
527 * @param aYTextOutputFormat a string representing the decimal text output format for the y values
528 */
529 public void setYTextOutputFormat(String aYTextOutputFormat) {
530 yTextOutputFormat = aYTextOutputFormat;
531 }
532
533 /** Get the gray color intensity below which a pixel is considered 'black'
534 * @return the threshold intensity for black, an integer between 0 and 255
535 */
536 public int getBlackThreshold() {
537 return blackThreshold;
538 }
539
540 /** Set the gray color intensity below which a pixel is considered 'black'
541 * @param aBlackThreshold the threshold intensity for black, an integer between 0 and 255
542 */
543 public void setBlackThreshold(int aBlackThreshold) {
544 blackThreshold = aBlackThreshold;
545 }
546
547 /** Get the number of data samples in the plot
548 * @return the number of data samples in the plot
549 */
550 public int getSamples() {
551 return samples;
552 }
553
554 /** Set the number of data samples in the plot
555 * @param aSamples the number of data samples in the plot
556 */
557 public void setSamples(int aSamples) {
558 samples = aSamples;
559 }
560
561 /** Get the data file type.
562 * @return a string representing the data file type.
563 */
564 public String getDataFileType() {
565 return dataFileType;
566 }
567
568 /** Set the file name for the plot data.
569 * @param aDataFileType a string representing the data file name
570 */
571 public void setDataFileType(String aDataFileType) {
572 dataFileType = aDataFileType;
573 }
574
575 /** Get the file name for the plot data.
576 * @return a string representing the data file name.
577 */
578 public String getDataFileName() {
579 return dataFileName;
580 }
581
582 /** Set the file name for the plot data.
583 * @param aDataFileName a string representing the data file name
584 */
585 public void setDataFileName(String aDataFileName) {
586 dataFileName = aDataFileName;
587 }
588
589 /** Get the file name for the image.
590 * @return a string representing the image file name.
591 */
592 public String getImageFileName() {
593 return imageFileName;
594 }
595
596 public void setImageFileName(String anImageFileName) {
597 imageFileName = anImageFileName;
598 }
599
600 /** Get the status of the axes calibration procedure.
601 * @return true if the axes have been calibrated according to the axis labels
602 */
603 public boolean isAxesCalibrated() {
604 return axesCalibrated;
605 }
606
607 /** Set the status of the axis calibration procedure.
608 * @param aAxesCalibrated boolean flag indicating if axes have been calibrated
609 */
610 public void setAxesCalibrated(boolean aAxesCalibrated) {
611 axesCalibrated = aAxesCalibrated;
612 }
613
614 /** Get the status of the available processed data.
615 * @return true if image has been processed and data is available for saving etc...
616 */
617 public boolean isDataAvailable() {
618 return dataAvailable;
619 }
620
621 /** Set the status of the available processed data.
622 * @param aDataAvailable a boolean flag indicating if the data is available
623 */
624 public void setDataAvailable(boolean aDataAvailable) {
625 dataAvailable = aDataAvailable;
626 // these menus are disabled until some data is available
627 dataMenu.setEnabled(isDataAvailable());
628 saveMenuItem.setEnabled(isDataAvailable());
629 if (!isDataAvailable()) {
630 imagePoints = null; // clear data arrays
631 data = null;
632 }
633 overlay();
634 }
635
636 /** Get the status of the image loading process.
637 * @return true if image is loaded and ready for processing
638 */
639 public boolean isImageLoaded() {
640 return imageLoaded;
641 }
642
643 /** Set the status of the image loading process.
644 */
645 public void setImageLoaded(boolean anImageLoaded) {
646 imageLoaded = anImageLoaded;
647 // these menus are disabled until an image is loaded
648 editMenu.setEnabled(isImageLoaded());
649 viewMenu.setEnabled(isImageLoaded());
650 }
651
652 /** Get the overlay option.
653 * @return true if overlay is to be plotted when available
654 */
655 public boolean isOverlay() {
656 return overlay;
657 }
658
659 /** Set the overlay option.
660 * @param anOverlay a boolean flag representing the choice to plot data over the image
661 */
662 public void setOverlay(boolean anOverlay) {
663 overlay = anOverlay;
664 overlay();
665 }
666
667 //-------------------- drag and drop --------------------------------------------------
668
669 // TODO: if a series of files are dropped then they are processed automatically
670 // each is recognized and its data is saved with the same filename but with .dat extension
671
672 public void dragEnter(DropTargetDragEvent e) {
673 e.acceptDrag(DnDConstants.ACTION_COPY);
674 }
675
676 public void dragOver(DropTargetDragEvent e) {
677 e.acceptDrag(DnDConstants.ACTION_COPY);
678 }
679
680 public void dragExit(DropTargetEvent e) {
681 }
682
683 public void drop(DropTargetDropEvent e) {
684 DropTargetContext targetContext = e.getDropTargetContext();
685
686 boolean outcome = false;
687
688 if ((e.getSourceActions() & DnDConstants.ACTION_COPY) != 0)
689 e.acceptDrop(DnDConstants.ACTION_COPY);
690 else {
691 e.rejectDrop();
692 return;
693 }
694
695 DataFlavor[] dataFlavors = e.getCurrentDataFlavors();
696 DataFlavor transferDataFlavor = null;
697
698 for (int i = 0; i < dataFlavors.length; i++) {
699 if (dataFlavors[i].isFlavorJavaFileListType()) {
700 transferDataFlavor = dataFlavors[i];
701 break;
702 }
703 }
704
705 // If a DataFlavor is specified with a MIME "Content-Type" of application/x-java-file-list;class=java.util.List
706 // the Drag and Drop system will expect the list elements to be a homogeneous list of objects of type java.io.File.
707
708 if (transferDataFlavor != null) {
709 Transferable t = e.getTransferable();
710 try {
711 java.util.List fileList = (java.util.List) t.getTransferData(DataFlavor.javaFileListFlavor);
712 processFiles(fileList); // progress monitor will not appear within this event handler method
713 outcome = true;
714 } catch(java.io.IOException ioe) {
715 System.out.println(ioe);
716 } catch(java.awt.datatransfer.UnsupportedFlavorException ex) {
717 System.out.println(ex);
718 }
719 }
720 targetContext.dropComplete(outcome);
721 }
722
723 public void dragScroll(DropTargetDragEvent e) {
724 }
725
726 public void dropActionChanged(DropTargetDragEvent e) {
727 // System.err.println("[Target] dropActionChanged");
728 }
729 }
730