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.actor.gui; 028 029import java.awt.BorderLayout; 030import java.awt.Color; 031import java.awt.Graphics; 032import java.awt.event.ActionEvent; 033import java.awt.event.ActionListener; 034import java.awt.event.KeyEvent; 035import java.awt.print.PageFormat; 036import java.awt.print.Printable; 037import java.awt.print.PrinterException; 038import java.io.File; 039import java.io.FileOutputStream; 040import java.io.IOException; 041import java.io.OutputStream; 042import java.lang.reflect.Constructor; 043import java.util.LinkedList; 044import java.util.Locale; 045 046import javax.swing.AbstractAction; 047import javax.swing.Action; 048import javax.swing.JFileChooser; 049import javax.swing.JMenu; 050import javax.swing.JMenuItem; 051import javax.swing.JOptionPane; 052import javax.swing.KeyStroke; 053import javax.swing.filechooser.FileFilter; 054 055import ptolemy.actor.injection.PortablePlaceable; 056import ptolemy.data.expr.StringParameter; 057import ptolemy.gui.ExtensionFilenameFilter; 058import ptolemy.gui.ImageExportable; 059import ptolemy.gui.JFileChooserBugFix; 060import ptolemy.gui.Top; 061import ptolemy.kernel.util.InternalErrorException; 062import ptolemy.plot.Plot; 063import ptolemy.plot.PlotBox; 064import ptolemy.plot.PlotFormatter; 065import ptolemy.util.MessageHandler; 066import ptolemy.util.StringUtilities; 067 068/////////////////////////////////////////////////////////////////// 069//// PlotTableauFrame 070 071/** 072 073 PlotTableauFrame is a version of PlotFrame in the plot package that 074 works more closely with the Ptolemy actor.gui infrastructure. 075 In particular, the File menu commands will open Ptolemy models 076 and HTML files, not just PlotML files. It contains an instance 077 of PlotBox. If not specified in the constructor, the default 078 is to contain a Plot object, where Plot extends PlotBox. This 079 field is set once in the constructor and immutable afterwards. 080 081 @see Plot 082 @see PlotBox 083 @author Edward A. Lee 084 @version $Id$ 085 @since Ptolemy II 2.1 086 @Pt.ProposedRating Yellow (cxh) 087 @Pt.AcceptedRating Yellow (cxh) 088 */ 089@SuppressWarnings("serial") 090public class PlotTableauFrame extends TableauFrame 091 implements Printable, ImageExportable { 092 /** Construct a plot frame with a default title and by default contains 093 * an instance of Plot. After constructing this, it is necessary 094 * to call setVisible(true) to make the plot appear. 095 */ 096 public PlotTableauFrame() { 097 this(null); 098 } 099 100 /** Construct a plot frame in the corresponding Tableau with the 101 * specified instance of PlotBox. 102 * After constructing this, it is necessary 103 * to call setVisible(true) to make the plot appear. 104 * @param tableau The tableau where the window is placed 105 */ 106 public PlotTableauFrame(Tableau tableau) { 107 this(tableau, new Plot()); 108 } 109 110 /** Construct a plot frame with the specified title and by default 111 * contains an instance of Plot. After constructing this, it is necessary 112 * to call setVisible(true) to make the plot appear. 113 * @param tableau The tableau where the window is placed. 114 * @param plotBox the plot object to put in the frame, or null to create 115 * an instance of Plot. 116 */ 117 public PlotTableauFrame(Tableau tableau, PlotBox plotBox) { 118 this(tableau, plotBox, (Placeable) null); 119 } 120 121 /** Construct a plot frame with the specified title and by default 122 * contains an instance of Plot. After constructing this, it is necessary 123 * to call setVisible(true) to make the plot appear. 124 * @param tableau The tableau where the window is placed. 125 * @param plotBox the plot object to put in the frame, or null to create 126 * an instance of Plot. 127 * @param placeable The associated plot actor, or null if none. 128 */ 129 public PlotTableauFrame(Tableau tableau, PlotBox plotBox, 130 Placeable placeable) { 131 super(tableau, null, placeable); 132 plot = plotBox; 133 134 // We don't define a file name filter here because we are 135 // only supporting PlotML files. .plt files are not supported 136 // for opening here. 137 138 // Background color is a light grey. 139 plot.setBackground(new Color(0xe5e5e5)); 140 getContentPane().add(plot, BorderLayout.CENTER); 141 _initialSaveAsFileName = "plot.plt"; 142 } 143 144 /** Construct a plot frame with the specified title and by default 145 * contains an instance of Plot. After constructing this, it is necessary 146 * to call setVisible(true) to make the plot appear. 147 * @param tableau The tableau where the window is placed. 148 * @param plotBox the plot object to put in the frame, or null to create 149 * an instance of Plot. 150 * @param placeable The associated plot actor, or null if none. 151 */ 152 public PlotTableauFrame(Tableau tableau, PlotBox plotBox, 153 PortablePlaceable placeable) { 154 super(tableau, null, placeable); 155 plot = plotBox; 156 157 // We don't define a file name filter here because we are 158 // only supporting PlotML files. .plt files are not supported 159 // for opening here. 160 161 // Background color is a light grey. 162 plot.setBackground(new Color(0xe5e5e5)); 163 getContentPane().add(plot, BorderLayout.CENTER); 164 _initialSaveAsFileName = "plot.plt"; 165 } 166 167 /////////////////////////////////////////////////////////////////// 168 //// public methods //// 169 170 /** Print the plot to a printer, 171 * which is represented by the specified graphics object. 172 * @param graphics The context into which the page is drawn. 173 * @param format The size and orientation of the page being drawn. 174 * @param index The zero based index of the page to be drawn. 175 * @return PAGE_EXISTS if the page is rendered successfully, or 176 * NO_SUCH_PAGE if pageIndex specifies a non-existent page. 177 * @exception PrinterException If the print job is terminated. 178 */ 179 @Override 180 public int print(Graphics graphics, PageFormat format, int index) 181 throws PrinterException { 182 // Note that the Plot print menu does not directly call 183 // this method, instead it calls _print(). This method is 184 // included so that this class implement printable and the 185 // print menu choice is enabled. 186 return plot.print(graphics, format, index); 187 } 188 189 /** Create a sample plot. 190 */ 191 public void samplePlot() { 192 _file = null; 193 _directory = null; 194 plot.samplePlot(); 195 } 196 197 /** Dispose of this frame. 198 * 199 * <p>Override this dispose() method to unattach any listeners 200 * that may keep this model from getting garbage collected. This 201 * method invokes the dispose() method of the superclass, 202 * {@link ptolemy.gui.Top}.</p> 203 */ 204 @Override 205 public void dispose() { 206 if (_debugClosing) { 207 System.out.println("TableauFrame.dispose() : " + this.getName()); 208 } 209 super.dispose(); 210 } 211 212 /** Write an image to the specified output stream in the specified format. 213 * Supported formats include at least "gif" and "png", standard image file formats. 214 * The image is a rendition of the current view of the model. 215 * @param stream The output stream to write to. 216 * @param format The image format to generate. 217 * @exception IOException If writing to the stream fails. 218 * @exception PrinterException If the specified format is not supported. 219 */ 220 @Override 221 public void writeImage(OutputStream stream, String format) 222 throws PrinterException, IOException { 223 if (plot == null) { 224 throw new IOException("No plot to write image from!"); 225 } 226 plot.exportImage(stream, format); 227 } 228 229 /////////////////////////////////////////////////////////////////// 230 //// public variables //// 231 232 /** The plot object held by this frame. */ 233 public final PlotBox plot; 234 235 /////////////////////////////////////////////////////////////////// 236 //// protected variables //// 237 238 /** Directory that contains the input file. */ 239 protected File _directory = null; 240 241 /** The export to PDF action. */ 242 protected Action _exportPDFAction; 243 244 /** Edit menu for this frame. */ 245 protected JMenu _editMenu; 246 247 /** The export to GIF action. */ 248 protected Action _exportGIFAction; 249 250 /** The export to PNG action. */ 251 protected Action _exportPNGAction; 252 253 /** The input file. */ 254 protected File _file = null; 255 256 /** Special menu for this frame. */ 257 protected JMenu _specialMenu; 258 259 /////////////////////////////////////////////////////////////////// 260 //// protected methods //// 261 262 /** Create the menus that are used by this frame. 263 */ 264 @Override 265 protected void _addMenus() { 266 super._addMenus(); 267 268 // Edit menu 269 _editMenu = new JMenu("Edit"); 270 _editMenu.setMnemonic(KeyEvent.VK_E); 271 _menubar.add(_editMenu); 272 273 FormatAction formatAction = new FormatAction(); 274 // Avoid a dependency on diva/gui/GUIUtilities.java here, but 275 // add some code duplication. 276 JMenuItem item = _editMenu.add(formatAction); 277 item.setText((String) formatAction.getValue(Action.NAME)); 278 item.setMnemonic((Integer) formatAction.getValue(Action.MNEMONIC_KEY)); 279 item.setToolTipText((String) formatAction.getValue("tooltip")); 280 281 KeyStroke key = (KeyStroke) formatAction 282 .getValue(Action.ACCELERATOR_KEY); 283 item.setAccelerator(key); 284 formatAction.putValue("menuItem", item); 285 // End of duplicated code from diva GUIUtilities. 286 287 // Special menu 288 _specialMenu = new JMenu("Special"); 289 _specialMenu.setMnemonic(KeyEvent.VK_S); 290 _menubar.add(_specialMenu); 291 292 JMenuItem[] specialMenuItems = { new JMenuItem("Clear", KeyEvent.VK_C), 293 new JMenuItem("Export", KeyEvent.VK_E), 294 new JMenuItem("Fill", KeyEvent.VK_F), 295 new JMenuItem("Reset axes", KeyEvent.VK_R), 296 new JMenuItem("Sample plot", KeyEvent.VK_S), }; 297 SpecialMenuListener sml = new SpecialMenuListener(); 298 299 // Set the action command and listener for each menu item. 300 for (JMenuItem specialMenuItem : specialMenuItems) { 301 specialMenuItem.setActionCommand(specialMenuItem.getText()); 302 specialMenuItem.addActionListener(sml); 303 _specialMenu.add(specialMenuItem); 304 } 305 } 306 307 /** Clear the current plot. This class checks to see whether 308 * the contents have been modified, and if so, then prompts the user 309 * to save them. A return value of false 310 * indicates that the user has canceled the action. 311 * @return False if the user cancels the clear. 312 */ 313 @Override 314 protected boolean _clear() { 315 boolean result = super._clear(); 316 317 // The false argument prevents clearing decorations. 318 plot.clear(false); 319 return result; 320 } 321 322 /** Create the items in the File menu's Export section 323 * This method adds a menu items to export images of the plot 324 * in GIF, PNG, and possibly PDF. 325 * @return The items in the File menu. 326 */ 327 @Override 328 protected JMenuItem[] _createFileMenuItems() { 329 JMenuItem[] fileMenuItems = super._createFileMenuItems(); 330 331 JMenu exportMenu = (JMenu) fileMenuItems[_EXPORT_MENU_INDEX]; 332 exportMenu.setEnabled(true); 333 334 try { 335 // Get the "export PDF" action classname from the configuration. 336 // This may or many not be included because it depends on GPL'd code, 337 // and hence cannot be included included in any pure BSD distribution. 338 // NOTE: Cannot use getConfiguration() because the configuration is 339 // not set when this method is called. Hence, we assume that there 340 // is only one configuration, or that if there are multiple configurations 341 // in this execution, that the first one will determine whether PDF 342 // export is provided. 343 Configuration configuration = Configuration.configurations().get(0); 344 // NOTE: Configuration should not be null, but just in case: 345 if (configuration != null) { 346 // Deal with the PDF Action first. 347 StringParameter exportPDFActionClassNameParameter = (StringParameter) configuration 348 .getAttribute("_exportPDFActionClassName", 349 StringParameter.class); 350 351 if (exportPDFActionClassNameParameter != null) { 352 if (_exportPDFAction == null) { 353 String exportPDFActionClassName = exportPDFActionClassNameParameter 354 .stringValue(); 355 try { 356 Class exportPDFActionClass = Class 357 .forName(exportPDFActionClassName); 358 Constructor exportPDFActionConstructor = exportPDFActionClass 359 .getDeclaredConstructor(Top.class); 360 _exportPDFAction = (AbstractAction) exportPDFActionConstructor 361 .newInstance(this); 362 } catch (Throwable throwable) { 363 throw new InternalErrorException(null, throwable, 364 "Failed to construct export PDF class \"" 365 + exportPDFActionClassName 366 + "\", which was read from the configuration."); 367 } 368 } 369 } 370 } 371 } catch (Exception ex) { 372 // We do not want to abort at this point because the worst 373 // case is that we will have no Export PDF in the menu. 374 // That is better than preventing the user from opening a model. 375 System.err.println( 376 "Warning: Tried to create Export PDF menu item, but failed: " 377 + ex); 378 } 379 380 // Uncomment the next block to have Export PDF *ALWAYS* enabled. 381 // We don't want it always enabled because ptiny, the applets and 382 // Web Start should not included this AGPL'd piece of software 383 384 // NOTE: Comment out the entire block with lines that begin with // 385 // so that the test in adm notices that the block is commented out. 386 387 // if (_exportPDFAction == null) { 388 // //String exportPDFActionClassName = exportPDFActionClassNameParameter.stringValue(); 389 // String exportPDFActionClassName = "ptolemy.vergil.basic.export.itextpdf.ExportPDFAction"; 390 // try { 391 // Class exportPDFActionClass = Class 392 // .forName(exportPDFActionClassName); 393 // Constructor exportPDFActionConstructor = exportPDFActionClass 394 // .getDeclaredConstructor(Top.class); 395 // _exportPDFAction = (AbstractAction) exportPDFActionConstructor 396 // .newInstance(this); 397 // } catch (Throwable throwable) { 398 // new InternalErrorException(null, throwable, 399 // "Failed to construct export PDF class \"" 400 // + exportPDFActionClassName 401 // + "\", which was read from the configuration."); 402 // } 403 // } 404 // End of block to uncomment. 405 406 if (_exportPDFAction != null) { 407 // Insert the Export PDF item. 408 JMenuItem exportItem = new JMenuItem(_exportPDFAction); 409 exportMenu.add(exportItem); 410 } 411 412 // Next do the export GIF action. 413 if (_exportGIFAction == null) { 414 _exportGIFAction = new ExportImageAction("GIF"); 415 } 416 JMenuItem exportItem = new JMenuItem(_exportGIFAction); 417 exportMenu.add(exportItem); 418 419 // Next do the export PNG action. 420 if (_exportPNGAction == null) { 421 _exportPNGAction = new ExportImageAction("PNG"); 422 } 423 exportItem = new JMenuItem(_exportPNGAction); 424 exportMenu.add(exportItem); 425 426 return fileMenuItems; 427 } 428 429 /** Interactively edit the file format in a modal dialog. 430 */ 431 protected void _editFormat() { 432 PlotFormatter formatter = new PlotFormatter(plot); 433 formatter.openModal(); 434 } 435 436 /** Query the user for a filename and export the plot to that file. 437 * Currently, the only supported format is EPS. 438 */ 439 protected void _export() { 440 JFileChooser fileDialog = new JFileChooser(); 441 fileDialog.addChoosableFileFilter(new EPSFileFilter()); 442 fileDialog.setDialogTitle("Export EPS to..."); 443 444 if (_directory != null) { 445 fileDialog.setCurrentDirectory(_directory); 446 } else { 447 // The default on Windows is to open at user.home, which is 448 // typically an absurd directory inside the O/S installation. 449 // So we use the current directory instead. 450 String cwd = StringUtilities.getProperty("user.dir"); 451 452 if (cwd != null) { 453 fileDialog.setCurrentDirectory(new File(cwd)); 454 } 455 } 456 457 fileDialog.setSelectedFile( 458 new File(fileDialog.getCurrentDirectory(), "plot.eps")); 459 460 int returnVal = fileDialog.showDialog(this, "Export"); 461 462 if (returnVal == JFileChooser.APPROVE_OPTION) { 463 File file = fileDialog.getSelectedFile(); 464 FileOutputStream fout = null; 465 466 try { 467 fout = new FileOutputStream(file); 468 plot.export(fout); 469 } catch (IOException ex) { 470 JOptionPane.showMessageDialog(this, 471 "Error exporting plot to '" + file + "': " + ex, 472 "Ptolemy II Error", JOptionPane.WARNING_MESSAGE); 473 } finally { 474 if (fout != null) { 475 try { 476 fout.close(); 477 } catch (Throwable throwable) { 478 System.out.println("Ignoring failure to close stream " 479 + "on " + file); 480 throwable.printStackTrace(); 481 } 482 } 483 } 484 } 485 } 486 487 /** Display more detailed information than given by _about(). 488 */ 489 @Override 490 protected void _help() { 491 JOptionPane.showMessageDialog(this, 492 "PlotTableauFrame is a plot in a top-level window.\n" 493 + " File formats understood: Ptplot ASCII.\n" 494 + " Left mouse button: Zooming.", 495 "About Ptolemy Plot", JOptionPane.INFORMATION_MESSAGE); 496 } 497 498 /** Write the plot to the specified file in PlotML syntax. 499 * @param file The file to which to write. 500 * @exception IOException If the write fails. 501 */ 502 @Override 503 protected void _writeFile(File file) throws IOException { 504 FileOutputStream out = null; 505 try { 506 out = new FileOutputStream(file); 507 plot.write(out); 508 } finally { 509 if (out != null) { 510 out.close(); 511 } 512 } 513 } 514 515 /////////////////////////////////////////////////////////////////// 516 //// inner classes //// 517 518 /////////////////////////////////////////////////////////////////// 519 //// ExportImageAction 520 521 /** Export an image of a plot. */ 522 public class ExportImageAction extends AbstractAction { 523 524 /** Create a new action to export an image. 525 * @param formatName The name of the format, currently PNG and 526 * GIF are supported. 527 */ 528 public ExportImageAction(String formatName) { 529 super("Export " + formatName); 530 _formatName = formatName.toLowerCase(Locale.getDefault()); 531 putValue("tooltip", "Export " + formatName + " image to a file."); 532 // putValue(GUIUtilities.MNEMONIC_KEY, Integer.valueOf(KeyEvent.VK_G)); 533 } 534 535 /////////////////////////////////////////////////////////////////// 536 //// public methods //// 537 538 /** Export an image. 539 * @param e The ActionEvent that invoked this action. 540 */ 541 @Override 542 public void actionPerformed(ActionEvent e) { 543 JFileChooserBugFix jFileChooserBugFix = new JFileChooserBugFix(); 544 Color background = null; 545 try { 546 background = jFileChooserBugFix.saveBackground(); 547 548 JFileChooser fileDialog = new JFileChooser(); 549 fileDialog.setDialogTitle("Specify a file to write to."); 550 LinkedList extensions = new LinkedList(); 551 extensions.add(_formatName); 552 fileDialog.addChoosableFileFilter( 553 new ExtensionFilenameFilter(extensions)); 554 555 if (_directory != null) { 556 fileDialog.setCurrentDirectory(_directory); 557 } else { 558 // The default on Windows is to open at user.home, which is 559 // typically an absurd directory inside the O/S installation. 560 // So we use the current directory instead. 561 // This will throw a security exception in an applet. 562 // FIXME: we should support users under applets opening files 563 // on the server. 564 String currentWorkingDirectory = StringUtilities 565 .getProperty("user.dir"); 566 if (currentWorkingDirectory != null) { 567 fileDialog.setCurrentDirectory( 568 new File(currentWorkingDirectory)); 569 } 570 } 571 572 int returnVal = fileDialog.showDialog(PlotTableauFrame.this, 573 "Export " 574 + _formatName.toUpperCase(Locale.getDefault())); 575 576 if (returnVal == JFileChooser.APPROVE_OPTION) { 577 _directory = fileDialog.getCurrentDirectory(); 578 File file = fileDialog.getSelectedFile().getCanonicalFile(); 579 580 if (file.getName().indexOf(".") == -1) { 581 // If the user has not given the file an extension, add it 582 file = new File( 583 file.getAbsolutePath() + "." + _formatName); 584 } 585 if (file.exists()) { 586 if (!MessageHandler.yesNoQuestion( 587 "Overwrite " + file.getName() + "?")) { 588 return; 589 } 590 } 591 OutputStream out = null; 592 try { 593 out = new FileOutputStream(file); 594 plot.exportImage(out, _formatName); 595 } finally { 596 if (out != null) { 597 out.close(); 598 } 599 } 600 601 // Open the PNG file. 602 // FIXME: We don't do the right thing with PNG files. 603 // It just opens in a text editor. 604 // _read(file.toURI().toURL()); 605 MessageHandler.message( 606 "Image file exported to " + file.getName()); 607 } 608 } catch (Exception ex) { 609 MessageHandler.error("Export to " 610 + _formatName.toUpperCase(Locale.getDefault()) 611 + " failed", ex); 612 } finally { 613 jFileChooserBugFix.restoreBackground(background); 614 } 615 } 616 617 private String _formatName; 618 } 619 620 /** Format the plot. */ 621 private class FormatAction extends AbstractAction { 622 /** Create a new action to format the plot. */ 623 public FormatAction() { 624 super("Format"); 625 putValue("tooltip", "Open a dialog to format the plot."); 626 putValue(Action.MNEMONIC_KEY, Integer.valueOf(KeyEvent.VK_F)); 627 } 628 629 @Override 630 public void actionPerformed(ActionEvent e) { 631 try { 632 _editFormat(); 633 } catch (Exception exception) { 634 // If we do not catch exceptions here, then they 635 // disappear to stdout, which is bad if we launched 636 // where there is no stdout visible. 637 JOptionPane.showMessageDialog(null, 638 "Format Exception:\n" + exception.toString(), 639 "Ptolemy Plot Error", JOptionPane.WARNING_MESSAGE); 640 } 641 642 // NOTE: The following should not be needed, but there jdk1.3beta 643 // appears to have a bug in swing where repainting doesn't 644 // properly occur. 645 repaint(); 646 } 647 } 648 649 class SpecialMenuListener implements ActionListener { 650 @Override 651 public void actionPerformed(ActionEvent e) { 652 JMenuItem target = (JMenuItem) e.getSource(); 653 String actionCommand = target.getActionCommand(); 654 655 try { 656 if (actionCommand.equals("Fill")) { 657 plot.fillPlot(); 658 } else if (actionCommand.equals("Reset axes")) { 659 plot.resetAxes(); 660 } else if (actionCommand.equals("Clear")) { 661 plot.clear(false); 662 plot.repaint(); 663 } else if (actionCommand.equals("Export")) { 664 _export(); 665 } else if (actionCommand.equals("Sample plot")) { 666 plot.clear(true); 667 samplePlot(); 668 } 669 } catch (Exception exception) { 670 // If we do not catch exceptions here, then they 671 // disappear to stdout, which is bad if we launched 672 // where there is no stdout visible. 673 JOptionPane.showMessageDialog(null, 674 "Special Menu Exception:\n" + exception.toString(), 675 "Ptolemy Plot Error", JOptionPane.WARNING_MESSAGE); 676 } 677 678 // NOTE: The following should not be needed, but there jdk1.3beta 679 // appears to have a bug in swing where repainting doesn't 680 // properly occur. 681 repaint(); 682 } 683 } 684 685 /////////////////////////////////////////////////////////////////// 686 //// inner classes //// 687 688 /** Display only .eps files. */ 689 static class EPSFileFilter extends FileFilter { 690 // FindBugs suggests making this class static so as to decrease 691 // the size of instances and avoid dangling references. 692 693 /** Accept only .eps files. 694 * @param fileOrDirectory The file to be checked. 695 * @return true if the file is a directory, a .eps file 696 */ 697 @Override 698 public boolean accept(File fileOrDirectory) { 699 if (fileOrDirectory.isDirectory()) { 700 return true; 701 } 702 703 String fileOrDirectoryName = fileOrDirectory.getName(); 704 int dotIndex = fileOrDirectoryName.lastIndexOf('.'); 705 706 if (dotIndex == -1) { 707 return false; 708 } 709 710 String extension = fileOrDirectoryName.substring(dotIndex); 711 712 if (extension != null) { 713 if (extension.equalsIgnoreCase(".eps")) { 714 return true; 715 } else { 716 return false; 717 } 718 } 719 720 return false; 721 } 722 723 /** The description of this filter */ 724 @Override 725 public String getDescription() { 726 return "Encapsulated PostScript (.eps) files"; 727 } 728 } 729}