001/* Top-level window containing a plotter. 002 003 Copyright (c) 1998-2014 The Regents of the University of California. 004 All rights reserved. 005 Permission is hereby granted, without written agreement and without 006 license or royalty fees, to use, copy, modify, and distribute this 007 software and its documentation for any purpose, provided that the above 008 copyright notice and the following two paragraphs appear in all copies 009 of this software. 010 011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 015 SUCH DAMAGE. 016 017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 022 ENHANCEMENTS, OR MODIFICATIONS. 023 024 PT_COPYRIGHT_VERSION_2 025 COPYRIGHTENDKEY 026 */ 027package ptolemy.plot; 028 029import java.awt.BorderLayout; 030import java.awt.Color; 031import java.awt.Dimension; 032import java.awt.Event; 033import java.awt.Toolkit; 034import java.awt.event.ActionEvent; 035import java.awt.event.ActionListener; 036import java.awt.event.KeyEvent; 037import java.awt.print.PageFormat; 038import java.awt.print.PrinterException; 039import java.awt.print.PrinterJob; 040import java.beans.PropertyChangeEvent; 041import java.beans.PropertyChangeListener; 042import java.io.File; 043import java.io.FileInputStream; 044import java.io.FileNotFoundException; 045import java.io.FileOutputStream; 046import java.io.IOException; 047import java.io.InputStream; 048import java.io.OutputStream; 049import java.net.URL; 050 051import javax.print.PrintService; 052import javax.print.attribute.HashPrintRequestAttributeSet; 053import javax.print.attribute.PrintRequestAttributeSet; 054import javax.print.attribute.standard.Destination; 055import javax.swing.JFileChooser; 056import javax.swing.JFrame; 057import javax.swing.JMenu; 058import javax.swing.JMenuBar; 059import javax.swing.JMenuItem; 060import javax.swing.JOptionPane; 061import javax.swing.KeyStroke; 062import javax.swing.UIManager; 063import javax.swing.filechooser.FileFilter; 064 065import ptolemy.gui.ImageExportable; 066import ptolemy.util.StringUtilities; 067 068// TO DO: 069// - Add a mechanism for combining two plots into one 070/////////////////////////////////////////////////////////////////// 071//// PlotFrame 072 073/** 074 075 PlotFrame is a versatile two-dimensional data plotter that runs as 076 part of an application, but in its own window. It can read files 077 compatible with the old Ptolemy plot file format (currently only ASCII). 078 It is extended with the capability to read PlotML files in PlotMLFrame. 079 An application can also interact directly with the contained Plot 080 object, which is visible as a public member, by invoking its methods. 081 <p> 082 An application that uses this class should set up the handling of 083 window-closing events. Presumably, the application will exit when 084 all windows have been closed. This is done with code something like: 085 <pre> 086 plotFrameInstance.addWindowListener(new WindowAdapter() { 087 public void windowClosing(WindowEvent e) { 088 // Handle the event 089 } 090 }); 091 </pre> 092 <p> 093 PlotFrame contains an instance of PlotBox. PlotBox is the base class for 094 classes with drawing capability, e.g. Plot, LogicAnalyzer. If not 095 specified in the constructor, the default is to contain a Plot object. This 096 field is set once in the constructor and immutable afterwards. 097 098 @see Plot 099 @see PlotBox 100 @author Christopher Brooks and Edward A. Lee 101 @version $Id$ 102 @since Ptolemy II 0.2 103 @Pt.ProposedRating Yellow (cxh) 104 @Pt.AcceptedRating Yellow (cxh) 105 */ 106@SuppressWarnings("serial") 107public class PlotFrame extends JFrame 108 implements PropertyChangeListener, ImageExportable { 109 /** Construct a plot frame with a default title and by default contains 110 * an instance of Plot. After constructing this, it is necessary 111 * to call setVisible(true) to make the plot appear. 112 */ 113 public PlotFrame() { 114 this("Ptolemy Plot Frame"); 115 } 116 117 /** Construct a plot frame with the specified title and by default 118 * contains an instance of Plot. After constructing this, it is necessary 119 * to call setVisible(true) to make the plot appear. 120 * @param title The title to put on the window. 121 */ 122 public PlotFrame(String title) { 123 this(title, null); 124 } 125 126 /** Construct a plot frame with the specified title and the specified 127 * instance of PlotBox. After constructing this, it is necessary 128 * to call setVisible(true) to make the plot appear. 129 * @param title The title to put on the window. 130 * @param plotArg the plot object to put in the frame, or null to create 131 * an instance of Plot. 132 */ 133 public PlotFrame(String title, PlotBox plotArg) { 134 super(title); 135 136 // The Java look & feel is pretty lame, so we use the native 137 // look and feel of the platform we are running on. 138 try { 139 UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 140 } catch (Throwable throwable) { 141 // Ignore exceptions, which only result in the wrong look and feel. 142 } 143 144 if (plotArg == null) { 145 plot = new Plot(); 146 } else { 147 plot = plotArg; 148 } 149 150 // Background color is a light grey. 151 plot.setBackground(new Color(0xe5e5e5)); 152 153 _fileMenu.setMnemonic(KeyEvent.VK_F); 154 _editMenu.setMnemonic(KeyEvent.VK_E); 155 _specialMenu.setMnemonic(KeyEvent.VK_S); 156 157 // File menu 158 JMenuItem[] fileMenuItems = { new JMenuItem("Open", KeyEvent.VK_O), 159 new JMenuItem("Save", KeyEvent.VK_S), 160 new JMenuItem("SaveAs", KeyEvent.VK_A), 161 new JMenuItem("Export", KeyEvent.VK_E), 162 new JMenuItem("Print", KeyEvent.VK_P), 163 new JMenuItem("Close", KeyEvent.VK_C), }; 164 165 // Open button = ctrl-o. 166 fileMenuItems[0].setAccelerator( 167 KeyStroke.getKeyStroke(KeyEvent.VK_O, Event.CTRL_MASK)); 168 169 // Save button = ctrl-s. 170 fileMenuItems[1].setAccelerator( 171 KeyStroke.getKeyStroke(KeyEvent.VK_S, Event.CTRL_MASK)); 172 173 // Print button = ctrl-p. 174 fileMenuItems[4].setAccelerator( 175 KeyStroke.getKeyStroke(KeyEvent.VK_P, Event.CTRL_MASK)); 176 177 // Close button = ctrl-w. 178 fileMenuItems[5].setAccelerator( 179 KeyStroke.getKeyStroke(KeyEvent.VK_W, Event.CTRL_MASK)); 180 181 FileMenuListener fml = new FileMenuListener(); 182 183 // Set the action command and listener for each menu item. 184 for (JMenuItem fileMenuItem : fileMenuItems) { 185 fileMenuItem.setActionCommand(fileMenuItem.getText()); 186 fileMenuItem.addActionListener(fml); 187 _fileMenu.add(fileMenuItem); 188 } 189 190 _menubar.add(_fileMenu); 191 192 // Edit menu 193 JMenuItem format = new JMenuItem("Format", KeyEvent.VK_F); 194 FormatListener formatListener = new FormatListener(); 195 format.addActionListener(formatListener); 196 _editMenu.add(format); 197 _menubar.add(_editMenu); 198 199 // Special menu 200 JMenuItem[] specialMenuItems = { new JMenuItem("About", KeyEvent.VK_A), 201 new JMenuItem("Help", KeyEvent.VK_H), 202 new JMenuItem("Clear", KeyEvent.VK_C), 203 new JMenuItem("Fill", KeyEvent.VK_F), 204 new JMenuItem("Reset axes", KeyEvent.VK_R), 205 new JMenuItem("Sample plot", KeyEvent.VK_S), }; 206 SpecialMenuListener sml = new SpecialMenuListener(); 207 208 // Set the action command and listener for each menu item. 209 for (JMenuItem specialMenuItem : specialMenuItems) { 210 specialMenuItem.setActionCommand(specialMenuItem.getText()); 211 specialMenuItem.addActionListener(sml); 212 _specialMenu.add(specialMenuItem); 213 } 214 215 _menubar.add(_specialMenu); 216 217 setJMenuBar(_menubar); 218 219 getContentPane().add(plot, BorderLayout.CENTER); 220 221 // FIXME: This should not be hardwired in here. 222 setSize(500, 300); 223 224 // Center. 225 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); 226 Dimension frameSize = getSize(); 227 int x = (screenSize.width - frameSize.width) / 2; 228 int y = (screenSize.height - frameSize.height) / 2; 229 setLocation(x, y); 230 } 231 232 /////////////////////////////////////////////////////////////////// 233 //// public methods //// 234 235 /** Respond to dialog action. 236 * @param event The dialog event. 237 */ 238 @Override 239 public void propertyChange(PropertyChangeEvent event) { 240 // System.out.println(event.paramString()); 241 Object source = event.getSource(); 242 if (source instanceof JFileChooser) { 243 FileFilter filter = ((JFileChooser) source).getFileFilter(); 244 JFileChooser fileDialog = (JFileChooser) source; 245 if (filter instanceof EPSFileFilter) { 246 fileDialog.setSelectedFile( 247 new File(fileDialog.getCurrentDirectory(), "plot.eps")); 248 } else if (filter instanceof FilterForGIF) { 249 fileDialog.setSelectedFile( 250 new File(fileDialog.getCurrentDirectory(), "plot.gif")); 251 } else { 252 // FIXME: For some inexplicable reason, the following line does nothing if the 253 // directory already exists!!!!!!!!!!!!! Pretty lame... 254 fileDialog.setSelectedFile( 255 new File(fileDialog.getCurrentDirectory(), "plot")); 256 } 257 } 258 } 259 260 /** Create a sample plot. 261 */ 262 public void samplePlot() { 263 _file = null; 264 _directory = null; 265 plot.samplePlot(); 266 } 267 268 /** Set the visibility. As a side effect, this method 269 * sets the background of the menus. 270 * @param visible True if the Frame is to be visible, false 271 * if it is not visible. 272 */ 273 @Override 274 public void setVisible(boolean visible) { 275 super.setVisible(visible); 276 _editMenu.setBackground(_menubar.getBackground()); 277 _fileMenu.setBackground(_menubar.getBackground()); 278 _specialMenu.setBackground(_menubar.getBackground()); 279 } 280 281 /** Write an image to the specified output stream in the specified 282 * format. Supported formats include at least "gif" and "png", 283 * standard image file formats. The image is a rendition of the 284 * current view of the model. 285 * @param stream The output stream to write to. 286 * @param format The image format to generate. 287 * @exception IOException If writing to the stream fails. 288 * @exception PrinterException If the specified format is not supported. 289 */ 290 @Override 291 public void writeImage(OutputStream stream, String format) 292 throws PrinterException, IOException { 293 if (plot == null) { 294 throw new IOException("No plot to write image from!"); 295 } 296 plot.exportImage(stream, format); 297 } 298 299 /////////////////////////////////////////////////////////////////// 300 //// public variables //// 301 302 /** The plot object held by this frame. */ 303 public/*final*/PlotBox plot; 304 305 /////////////////////////////////////////////////////////////////// 306 //// protected variables //// 307 308 /** Directory that contains the input file. */ 309 protected File _directory = null; 310 311 /** Edit menu for this frame. */ 312 protected JMenu _editMenu = new JMenu("Edit"); 313 314 /** The input file. */ 315 protected File _file = null; 316 317 /** File menu for this frame. */ 318 protected JMenu _fileMenu = new JMenu("File"); 319 320 /** Menubar for this frame. */ 321 protected JMenuBar _menubar = new JMenuBar(); 322 323 /** Special menu for this frame. */ 324 protected JMenu _specialMenu = new JMenu("Special"); 325 326 /////////////////////////////////////////////////////////////////// 327 //// protected methods //// 328 329 /** Display a menu that describes the Plotter. */ 330 protected void _about() { 331 JOptionPane.showMessageDialog(this, 332 "PlotFrame class\n" + "By: Edward A. Lee " 333 + "and Christopher Brooks\n" + "Version " 334 + PlotBox.PTPLOT_RELEASE + ", Build: $Id$\n\n" 335 + "For more information, see\n" 336 + "http://ptolemy.eecs.berkeley.edu/java/ptplot\n\n" 337 + "Copyright (c) 1997-2014, " 338 + "The Regents of the University of California.", 339 "About Ptolemy Plot", JOptionPane.INFORMATION_MESSAGE); 340 } 341 342 /** Close the window. 343 */ 344 protected void _close() { 345 dispose(); 346 } 347 348 /** Interactively edit the file format in a modal dialog. 349 */ 350 protected void _editFormat() { 351 PlotFormatter fmt = new PlotFormatter(plot); 352 fmt.openModal(); 353 } 354 355 /** Query the user for a filename and export the plot to that file. 356 * Currently, the supported formats are EPS and GIF. 357 */ 358 protected void _export() { 359 JFileChooser fileDialog = new JFileChooser(); 360 fileDialog.addChoosableFileFilter(new FolderForLatex()); 361 fileDialog.addChoosableFileFilter(new EPSFileFilter()); 362 fileDialog.addChoosableFileFilter(new FilterForGIF()); 363 fileDialog.setDialogTitle("Export to..."); 364 365 if (_directory != null) { 366 fileDialog.setCurrentDirectory(_directory); 367 } else { 368 // The default on Windows is to open at user.home, which is 369 // typically an absurd directory inside the O/S installation. 370 // So we use the current directory instead. 371 String cwd = StringUtilities.getProperty("user.dir"); 372 373 if (cwd != null) { 374 fileDialog.setCurrentDirectory(new File(cwd)); 375 } 376 } 377 378 fileDialog.setSelectedFile( 379 new File(fileDialog.getCurrentDirectory(), "plot.gif")); 380 381 fileDialog.addPropertyChangeListener( 382 JFileChooser.FILE_FILTER_CHANGED_PROPERTY, this); 383 384 int returnVal = fileDialog.showDialog(this, "Export"); 385 386 fileDialog.removePropertyChangeListener(this); 387 388 if (returnVal == JFileChooser.APPROVE_OPTION) { 389 // Determine which export format is selected. 390 File file = fileDialog.getSelectedFile(); 391 try { 392 FileOutputStream fout = null; 393 394 try { 395 // With no filename extension, do Latex export. 396 // Otherwise, do EPS. 397 String name = file.getName(); 398 int position = name.lastIndexOf('.'); 399 String extension = ""; 400 if (position > 0) { 401 extension = name.substring(position + 1); 402 } 403 if (extension.equals("")) { 404 // No extension. Assume Latex export. 405 plot.exportLatex(file); 406 } else if (extension.equalsIgnoreCase("eps")) { 407 fout = new FileOutputStream(file); 408 plot.export(fout); 409 } else { 410 // Default is GIF export. 411 fout = new FileOutputStream(file); 412 plot.exportImage(fout, "gif"); 413 } 414 } finally { 415 try { 416 if (fout != null) { 417 fout.close(); 418 } 419 } catch (Throwable throwable) { 420 System.out.println("Ignoring failure to close stream " 421 + "on " + file); 422 throwable.printStackTrace(); 423 } 424 } 425 } catch (IOException ex) { 426 JOptionPane.showMessageDialog(this, 427 "Error exporting plot: " + ex, "Ptolemy II Error", 428 JOptionPane.WARNING_MESSAGE); 429 } 430 } 431 } 432 433 /** Display more detailed information than given by _about(). 434 */ 435 protected void _help() { 436 JOptionPane.showMessageDialog(this, 437 "PlotFrame is a plot in a top-level window.\n" 438 + " File formats understood: Ptplot ASCII.\n" 439 + " Left mouse button: Zooming.", 440 "About Ptolemy Plot", JOptionPane.INFORMATION_MESSAGE); 441 } 442 443 /** Open a new file and plot its data. 444 */ 445 protected void _open() { 446 JFileChooser fileDialog = new JFileChooser(); 447 fileDialog.setDialogTitle("Select a plot file"); 448 449 // Filter file names. 450 fileDialog.addChoosableFileFilter(new PLTOrXMLFileFilter()); 451 452 if (_directory != null) { 453 fileDialog.setCurrentDirectory(_directory); 454 } else { 455 // The default on Windows is to open at user.home, which is 456 // typically an absurd directory inside the O/S installation. 457 // So we use the current directory instead. 458 String cwd = StringUtilities.getProperty("user.dir"); 459 460 if (cwd != null) { 461 fileDialog.setCurrentDirectory(new File(cwd)); 462 } 463 } 464 465 int returnVal = fileDialog.showOpenDialog(this); 466 467 if (returnVal == JFileChooser.APPROVE_OPTION) { 468 _file = fileDialog.getSelectedFile(); 469 setTitle(_file.getName()); 470 _directory = fileDialog.getCurrentDirectory(); 471 472 FileInputStream input = null; 473 try { 474 plot.clear(true); 475 input = new FileInputStream(_file); 476 _read(new URL("file", null, _directory.getAbsolutePath()), 477 input); 478 plot.repaint(); 479 } catch (FileNotFoundException ex) { 480 JOptionPane.showMessageDialog(this, 481 "File not found:\n" + ex.toString(), 482 "Ptolemy Plot Error", JOptionPane.WARNING_MESSAGE); 483 } catch (IOException ex) { 484 JOptionPane.showMessageDialog(this, 485 "Error reading input:\n" + ex.toString(), 486 "Ptolemy Plot Error", JOptionPane.WARNING_MESSAGE); 487 } finally { 488 if (input != null) { 489 try { 490 input.close(); 491 } catch (Exception ex) { 492 // Ignore this, but print anyway. 493 ex.printStackTrace(); 494 } 495 } 496 } 497 } 498 } 499 500 /** Print the plot using the native interface. 501 */ 502 protected void _print() { 503 // If you are using $PTII/bin/vergil, under bash, set this property: 504 // export JAVAFLAGS=-Dptolemy.ptII.print.platform=CrossPlatform 505 // and then run $PTII/bin/vergil 506 if (StringUtilities.getProperty("ptolemy.ptII.print.platform") 507 .equals("CrossPlatform")) { 508 _printCrossPlatform(); 509 } else { 510 _printNative(); 511 } 512 } 513 514 /** Print using the cross platform dialog. 515 * Note that in java 1.6.0_05, the properties button is disabled, 516 * so using _printNative() is preferred. 517 */ 518 protected void _printCrossPlatform() { 519 // FIXME: Code duplication with PlotBox and Top. 520 521 // Note that this dialog used to be slow, but this was fixed in: 522 // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6539061 523 // Note that this dialog used to appear behind other windows, 524 // but this was fixed in: 525 // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4775862 526 527 // For more notes, see 528 // https://wiki.eecs.berkeley.edu/ptolemy/Ptolemy/PrintingFromJava 529 530 // Build a set of attributes 531 PrinterJob job = PrinterJob.getPrinterJob(); 532 PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet(); 533 // No need to call pageDialog, printDialog has that same tab 534 //PageFormat pageFormat = job.pageDialog(aset); 535 //PageFormat pageFormat = job.pageDialog(job.defaultPage()); 536 //job.setPrintable(plot, pageFormat); 537 job.setPrintable(plot); 538 539 if (job.printDialog(aset)) { 540 try { 541 job.print(aset); 542 } catch (Exception ex) { 543 JOptionPane.showMessageDialog(this, 544 "Printing failed:\n" + ex.toString(), "Print Error", 545 JOptionPane.WARNING_MESSAGE); 546 } 547 } 548 } 549 550 /** If a PDF printer is available print to it. 551 * @exception PrinterException If a printer with the string "PDF" 552 * cannot be found or if the job cannot be set to the PDF print 553 * service or if there is another problem printing. 554 */ 555 protected void _printPDF() throws PrinterException { 556 // Find something that will print to PDF 557 boolean foundPDFPrinter = false; 558 559 PrintService pdfPrintService = null; 560 PrintService printServices[] = PrinterJob.lookupPrintServices(); 561 for (PrintService printService : printServices) { 562 if (printService.getName().indexOf("PDF") != -1) { 563 foundPDFPrinter = true; 564 pdfPrintService = printService; 565 } 566 } 567 568 if (pdfPrintService == null) { 569 throw new PrinterException("Could not find a printer with the " 570 + "string \"PDF\" in its name."); 571 } 572 573 PrinterJob job = PrinterJob.getPrinterJob(); 574 job.setPrintService(pdfPrintService); 575 job.setPrintable(plot, job.defaultPage()); 576 577 PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet(); 578 // This gets ignored, but let's try it anyway 579 Destination destination = new Destination(new File("plot.pdf").toURI()); 580 aset.add(destination); 581 582 job.print(aset); 583 if (foundPDFPrinter) { 584 System.out.println("Plot printed from command line. " 585 + "Under MacOSX, look for " 586 + "~/Desktop/Java Printing.pdf"); 587 } 588 } 589 590 /** Print using the native dialog. 591 */ 592 protected void _printNative() { 593 // FIXME: Code duplication with PlotBox and Top. 594 595 // Native printing used not honor the user's 596 // choice of portrait vs. landscape. 597 598 PrinterJob job = PrinterJob.getPrinterJob(); 599 PageFormat pageFormat = job.pageDialog(job.defaultPage()); 600 job.setPrintable(plot, pageFormat); 601 602 if (job.printDialog()) { 603 try { 604 // job.print() eventually 605 // calls PlotBox.print(Graphics, PageFormat) 606 job.print(); 607 } catch (Exception ex) { 608 JOptionPane.showMessageDialog(this, 609 "Printing failed:\n" + ex.toString(), "Print Error", 610 JOptionPane.WARNING_MESSAGE); 611 } 612 } 613 } 614 615 /** Read the specified stream. Derived classes may override this 616 * to support other file formats. 617 * @param base The base for relative file references, or null if 618 * there are not relative file references. 619 * @param in The input stream. 620 * @exception IOException If the stream cannot be read. 621 */ 622 protected void _read(URL base, InputStream in) throws IOException { 623 plot.read(in); 624 } 625 626 /** Save the plot to the current file, determined by the 627 * and _file protected variable. 628 */ 629 protected void _save() { 630 if (_file != null) { 631 FileOutputStream output = null; 632 try { 633 output = new FileOutputStream(_file); 634 plot.write(output); 635 } catch (IOException ex) { 636 JOptionPane.showMessageDialog(this, 637 "Error writing file:\n" + ex.toString(), 638 "Ptolemy Plot Error", JOptionPane.WARNING_MESSAGE); 639 } finally { 640 if (output != null) { 641 try { 642 output.close(); 643 } catch (Exception ex) { 644 // Ignore, but print anyway. 645 ex.printStackTrace(); 646 } 647 } 648 } 649 } else { 650 _saveAs(); 651 } 652 } 653 654 /** Query the user for a filename and save the plot to that file. 655 */ 656 protected void _saveAs() { 657 JFileChooser fileDialog = new JFileChooser(); 658 fileDialog.addChoosableFileFilter(new PLTOrXMLFileFilter()); 659 fileDialog.setDialogTitle("Save plot as..."); 660 661 if (_directory != null) { 662 fileDialog.setCurrentDirectory(_directory); 663 } else { 664 // The default on Windows is to open at user.home, which is 665 // typically an absurd directory inside the O/S installation. 666 // So we use the current directory instead. 667 String cwd = StringUtilities.getProperty("user.dir"); 668 669 if (cwd != null) { 670 fileDialog.setCurrentDirectory(new File(cwd)); 671 } 672 } 673 674 fileDialog.setSelectedFile( 675 new File(fileDialog.getCurrentDirectory(), "plot.xml")); 676 677 // Under Java 1.6 and Mac OS X, showSaveDialog() ignores the filter. 678 int returnVal = fileDialog.showSaveDialog(this); 679 680 if (returnVal == JFileChooser.APPROVE_OPTION) { 681 _file = fileDialog.getSelectedFile(); 682 setTitle(_file.getName()); 683 _directory = fileDialog.getCurrentDirectory(); 684 _save(); 685 } 686 } 687 688 /////////////////////////////////////////////////////////////////// 689 //// inner classes //// 690 class FileMenuListener implements ActionListener { 691 @Override 692 public void actionPerformed(ActionEvent e) { 693 JMenuItem target = (JMenuItem) e.getSource(); 694 String actionCommand = target.getActionCommand(); 695 696 try { 697 if (actionCommand.equals("Open")) { 698 _open(); 699 } else if (actionCommand.equals("Save")) { 700 _save(); 701 } else if (actionCommand.equals("SaveAs")) { 702 _saveAs(); 703 } else if (actionCommand.equals("Export")) { 704 _export(); 705 } else if (actionCommand.equals("Print")) { 706 _print(); 707 } else if (actionCommand.equals("Close")) { 708 _close(); 709 } 710 } catch (Throwable throwable) { 711 // If we do not catch exceptions here, then they 712 // disappear to stdout, which is bad if we launched 713 // where there is no stdout visible. 714 JOptionPane.showMessageDialog(null, 715 "File Menu Exception:\n" + throwable, 716 "Ptolemy Plot Error", JOptionPane.WARNING_MESSAGE); 717 } 718 719 // NOTE: The following should not be needed, but there jdk1.3beta 720 // appears to have a bug in swing where repainting doesn't 721 // properly occur. 722 repaint(); 723 } 724 } 725 726 class FormatListener implements ActionListener { 727 @Override 728 public void actionPerformed(ActionEvent e) { 729 try { 730 _editFormat(); 731 } catch (Exception exception) { 732 // If we do not catch exceptions here, then they 733 // disappear to stdout, which is bad if we launched 734 // where there is no stdout visible. 735 System.out.println("Format Exception: " + exception); 736 exception.printStackTrace(); 737 JOptionPane.showMessageDialog(null, 738 "Format Exception:\n" + exception.toString(), 739 "Ptolemy Plot Error", JOptionPane.WARNING_MESSAGE); 740 741 } 742 743 // NOTE: The following should not be needed, but there jdk1.3beta 744 // appears to have a bug in swing where repainting doesn't 745 // properly occur. 746 repaint(); 747 } 748 } 749 750 class SpecialMenuListener implements ActionListener { 751 @Override 752 public void actionPerformed(ActionEvent e) { 753 JMenuItem target = (JMenuItem) e.getSource(); 754 String actionCommand = target.getActionCommand(); 755 756 try { 757 if (actionCommand.equals("About")) { 758 _about(); 759 } else if (actionCommand.equals("Help")) { 760 _help(); 761 } else if (actionCommand.equals("Fill")) { 762 plot.fillPlot(); 763 } else if (actionCommand.equals("Reset axes")) { 764 plot.resetAxes(); 765 } else if (actionCommand.equals("Clear")) { 766 plot.clear(false); 767 plot.repaint(); 768 } else if (actionCommand.equals("Sample plot")) { 769 plot.clear(true); 770 samplePlot(); 771 } 772 } catch (Exception exception) { 773 // If we do not catch exceptions here, then they 774 // disappear to stdout, which is bad if we launched 775 // where there is no stdout visible. 776 JOptionPane.showMessageDialog(null, 777 "Special Menu Exception:\n" + exception.toString(), 778 "Ptolemy Plot Error", JOptionPane.WARNING_MESSAGE); 779 } 780 781 // NOTE: The following should not be needed, but there jdk1.3beta 782 // appears to have a bug in swing where repainting doesn't 783 // properly occur. 784 repaint(); 785 } 786 } 787 788 /////////////////////////////////////////////////////////////////// 789 //// inner classes //// 790 791 /** Display only .eps files */ 792 static class EPSFileFilter extends FileFilter { 793 /** Accept only .eps files. 794 * @param fileOrDirectory The file or directory to be checked. 795 * @return true if the file is a directory, a .eps file 796 */ 797 @Override 798 public boolean accept(File fileOrDirectory) { 799 if (fileOrDirectory.isDirectory()) { 800 return true; 801 } 802 803 String fileOrDirectoryName = fileOrDirectory.getName(); 804 int dotIndex = fileOrDirectoryName.lastIndexOf('.'); 805 806 if (dotIndex == -1) { 807 return false; 808 } 809 810 String extension = fileOrDirectoryName.substring(dotIndex); 811 812 if (extension.equalsIgnoreCase(".eps")) { 813 return true; 814 } else { 815 return false; 816 } 817 } 818 819 /** The description of this filter */ 820 @Override 821 public String getDescription() { 822 return "Encapsulated PostScript (.eps) files"; 823 } 824 } 825 826 /** Display only folders for inserting latex files. */ 827 static class FolderForLatex extends FileFilter { 828 /** Accept only folders. 829 * @param fileOrDirectory The file or directory to be checked. 830 * @return true if the file is a directory. 831 */ 832 @Override 833 public boolean accept(File fileOrDirectory) { 834 if (fileOrDirectory.isDirectory()) { 835 return true; 836 } 837 return false; 838 } 839 840 /** The description of this filter */ 841 @Override 842 public String getDescription() { 843 return "Latex Export to a Folder"; 844 } 845 } 846 847 /** Display only .gif files */ 848 static class FilterForGIF extends FileFilter { 849 /** Accept only .gif files. 850 * @param fileOrDirectory The file or directory to be checked. 851 * @return true if the file is a directory, a .eps file 852 */ 853 @Override 854 public boolean accept(File fileOrDirectory) { 855 if (fileOrDirectory.isDirectory()) { 856 return true; 857 } 858 859 String fileOrDirectoryName = fileOrDirectory.getName(); 860 int dotIndex = fileOrDirectoryName.lastIndexOf('.'); 861 862 if (dotIndex < 0) { 863 return false; 864 } 865 866 String extension = fileOrDirectoryName.substring(dotIndex); 867 868 if (extension.equalsIgnoreCase(".gif")) { 869 return true; 870 } else { 871 return false; 872 } 873 } 874 875 /** The description of this filter */ 876 @Override 877 public String getDescription() { 878 return "GIF Image File (.gif)"; 879 } 880 } 881 882 /** Display only .plt and .xml files */ 883 static class PLTOrXMLFileFilter extends FileFilter { 884 /** Accept only .plt or .xml files. 885 * @param fileOrDirectory The file to be checked. 886 * @return true if the file is a directory, a .plot or a .xml file. 887 */ 888 @Override 889 public boolean accept(File fileOrDirectory) { 890 if (fileOrDirectory.isDirectory()) { 891 return true; 892 } 893 894 String fileOrDirectoryName = fileOrDirectory.getName(); 895 int dotIndex = fileOrDirectoryName.lastIndexOf('.'); 896 897 if (dotIndex == -1) { 898 return false; 899 } 900 901 String extension = fileOrDirectoryName.substring(dotIndex); 902 903 if (extension.equalsIgnoreCase(".plt") 904 || extension.equalsIgnoreCase(".xml")) { 905 return true; 906 } else { 907 return false; 908 } 909 } 910 911 /** The description of this filter */ 912 @Override 913 public String getDescription() { 914 return ".plt and .xml files"; 915 } 916 } 917}