--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/demo/share/jfc/Notepad/Notepad.java Tue Sep 12 19:03:39 2017 +0200
@@ -0,0 +1,863 @@
+/*
+ * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Oracle nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This source code is provided to illustrate the usage of a given feature
+ * or technique and has been deliberately simplified. Additional steps
+ * required for a production-quality application, such as security checks,
+ * input validation and proper error handling, might not be present in
+ * this sample code.
+ */
+
+
+
+import java.awt.*;
+import java.awt.event.*;
+import java.beans.*;
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import java.util.logging.*;
+import javax.swing.*;
+import javax.swing.undo.*;
+import javax.swing.text.*;
+import javax.swing.event.*;
+import javax.swing.UIManager.LookAndFeelInfo;
+
+
+/**
+ * Sample application using the simple text editor component that
+ * supports only one font.
+ *
+ * @author Timothy Prinzing
+ */
+@SuppressWarnings("serial")
+class Notepad extends JPanel {
+
+ protected static Properties properties;
+ private static ResourceBundle resources;
+ private static final String EXIT_AFTER_PAINT = "-exit";
+ private static boolean exitAfterFirstPaint;
+
+ private static final String[] MENUBAR_KEYS = {"file", "edit", "debug"};
+ private static final String[] TOOLBAR_KEYS = {"new", "open", "save", "-", "cut", "copy", "paste"};
+ private static final String[] FILE_KEYS = {"new", "open", "save", "-", "exit"};
+ private static final String[] EDIT_KEYS = {"cut", "copy", "paste", "-", "undo", "redo"};
+ private static final String[] DEBUG_KEYS = {"dump", "showElementTree"};
+
+ static {
+ try {
+ properties = new Properties();
+ properties.load(Notepad.class.getResourceAsStream(
+ "resources/NotepadSystem.properties"));
+ resources = ResourceBundle.getBundle("resources.Notepad",
+ Locale.getDefault());
+ } catch (MissingResourceException | IOException e) {
+ System.err.println("resources/Notepad.properties "
+ + "or resources/NotepadSystem.properties not found");
+ System.exit(1);
+ }
+ }
+
+ @Override
+ public void paintChildren(Graphics g) {
+ super.paintChildren(g);
+ if (exitAfterFirstPaint) {
+ System.exit(0);
+ }
+ }
+
+ @SuppressWarnings("OverridableMethodCallInConstructor")
+ Notepad() {
+ super(true);
+
+ // Trying to set Nimbus look and feel
+ try {
+ for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
+ if ("Nimbus".equals(info.getName())) {
+ UIManager.setLookAndFeel(info.getClassName());
+ break;
+ }
+ }
+ } catch (Exception ignored) {
+ }
+
+ setBorder(BorderFactory.createEtchedBorder());
+ setLayout(new BorderLayout());
+
+ // create the embedded JTextComponent
+ editor = createEditor();
+ // Add this as a listener for undoable edits.
+ editor.getDocument().addUndoableEditListener(undoHandler);
+
+ // install the command table
+ commands = new HashMap<Object, Action>();
+ Action[] actions = getActions();
+ for (Action a : actions) {
+ commands.put(a.getValue(Action.NAME), a);
+ }
+
+ JScrollPane scroller = new JScrollPane();
+ JViewport port = scroller.getViewport();
+ port.add(editor);
+
+ String vpFlag = getProperty("ViewportBackingStore");
+ if (vpFlag != null) {
+ Boolean bs = Boolean.valueOf(vpFlag);
+ port.setScrollMode(bs
+ ? JViewport.BACKINGSTORE_SCROLL_MODE
+ : JViewport.BLIT_SCROLL_MODE);
+ }
+
+ JPanel panel = new JPanel();
+ panel.setLayout(new BorderLayout());
+ panel.add("North", createToolbar());
+ panel.add("Center", scroller);
+ add("Center", panel);
+ add("South", createStatusbar());
+ }
+
+ public static void main(String[] args) throws Exception {
+ if (args.length > 0 && args[0].equals(EXIT_AFTER_PAINT)) {
+ exitAfterFirstPaint = true;
+ }
+ SwingUtilities.invokeAndWait(new Runnable() {
+
+ public void run() {
+ JFrame frame = new JFrame();
+ frame.setTitle(resources.getString("Title"));
+ frame.setBackground(Color.lightGray);
+ frame.getContentPane().setLayout(new BorderLayout());
+ Notepad notepad = new Notepad();
+ frame.getContentPane().add("Center", notepad);
+ frame.setJMenuBar(notepad.createMenubar());
+ frame.addWindowListener(new AppCloser());
+ frame.pack();
+ frame.setSize(500, 600);
+ frame.setVisible(true);
+ }
+ });
+ }
+
+ /**
+ * Fetch the list of actions supported by this
+ * editor. It is implemented to return the list
+ * of actions supported by the embedded JTextComponent
+ * augmented with the actions defined locally.
+ */
+ public Action[] getActions() {
+ return TextAction.augmentList(editor.getActions(), defaultActions);
+ }
+
+ /**
+ * Create an editor to represent the given document.
+ */
+ protected JTextComponent createEditor() {
+ JTextComponent c = new JTextArea();
+ c.setDragEnabled(true);
+ c.setFont(new Font("monospaced", Font.PLAIN, 12));
+ return c;
+ }
+
+ /**
+ * Fetch the editor contained in this panel
+ */
+ protected JTextComponent getEditor() {
+ return editor;
+ }
+
+
+ /**
+ * To shutdown when run as an application. This is a
+ * fairly lame implementation. A more self-respecting
+ * implementation would at least check to see if a save
+ * was needed.
+ */
+ protected static final class AppCloser extends WindowAdapter {
+
+ @Override
+ public void windowClosing(WindowEvent e) {
+ System.exit(0);
+ }
+ }
+
+ /**
+ * Find the hosting frame, for the file-chooser dialog.
+ */
+ protected Frame getFrame() {
+ for (Container p = getParent(); p != null; p = p.getParent()) {
+ if (p instanceof Frame) {
+ return (Frame) p;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * This is the hook through which all menu items are
+ * created.
+ */
+ protected JMenuItem createMenuItem(String cmd) {
+ JMenuItem mi = new JMenuItem(getResourceString(cmd + labelSuffix));
+ URL url = getResource(cmd + imageSuffix);
+ if (url != null) {
+ mi.setHorizontalTextPosition(JButton.RIGHT);
+ mi.setIcon(new ImageIcon(url));
+ }
+ String astr = getProperty(cmd + actionSuffix);
+ if (astr == null) {
+ astr = cmd;
+ }
+ mi.setActionCommand(astr);
+ Action a = getAction(astr);
+ if (a != null) {
+ mi.addActionListener(a);
+ a.addPropertyChangeListener(createActionChangeListener(mi));
+ mi.setEnabled(a.isEnabled());
+ } else {
+ mi.setEnabled(false);
+ }
+ return mi;
+ }
+
+ protected Action getAction(String cmd) {
+ return commands.get(cmd);
+ }
+
+ protected String getProperty(String key) {
+ return properties.getProperty(key);
+ }
+
+ protected String getResourceString(String nm) {
+ String str;
+ try {
+ str = resources.getString(nm);
+ } catch (MissingResourceException mre) {
+ str = null;
+ }
+ return str;
+ }
+
+ protected URL getResource(String key) {
+ String name = getResourceString(key);
+ if (name != null) {
+ return this.getClass().getResource(name);
+ }
+ return null;
+ }
+
+ /**
+ * Create a status bar
+ */
+ protected Component createStatusbar() {
+ // need to do something reasonable here
+ status = new StatusBar();
+ return status;
+ }
+
+ /**
+ * Resets the undo manager.
+ */
+ protected void resetUndoManager() {
+ undo.discardAllEdits();
+ undoAction.update();
+ redoAction.update();
+ }
+
+ /**
+ * Create the toolbar. By default this reads the
+ * resource file for the definition of the toolbar.
+ */
+ private Component createToolbar() {
+ toolbar = new JToolBar();
+ for (String toolKey: getToolBarKeys()) {
+ if (toolKey.equals("-")) {
+ toolbar.add(Box.createHorizontalStrut(5));
+ } else {
+ toolbar.add(createTool(toolKey));
+ }
+ }
+ toolbar.add(Box.createHorizontalGlue());
+ return toolbar;
+ }
+
+ /**
+ * Hook through which every toolbar item is created.
+ */
+ protected Component createTool(String key) {
+ return createToolbarButton(key);
+ }
+
+ /**
+ * Create a button to go inside of the toolbar. By default this
+ * will load an image resource. The image filename is relative to
+ * the classpath (including the '.' directory if its a part of the
+ * classpath), and may either be in a JAR file or a separate file.
+ *
+ * @param key The key in the resource file to serve as the basis
+ * of lookups.
+ */
+ protected JButton createToolbarButton(String key) {
+ URL url = getResource(key + imageSuffix);
+ JButton b = new JButton(new ImageIcon(url)) {
+
+ @Override
+ public float getAlignmentY() {
+ return 0.5f;
+ }
+ };
+ b.setRequestFocusEnabled(false);
+ b.setMargin(new Insets(1, 1, 1, 1));
+
+ String astr = getProperty(key + actionSuffix);
+ if (astr == null) {
+ astr = key;
+ }
+ Action a = getAction(astr);
+ if (a != null) {
+ b.setActionCommand(astr);
+ b.addActionListener(a);
+ } else {
+ b.setEnabled(false);
+ }
+
+ String tip = getResourceString(key + tipSuffix);
+ if (tip != null) {
+ b.setToolTipText(tip);
+ }
+
+ return b;
+ }
+
+ /**
+ * Create the menubar for the app. By default this pulls the
+ * definition of the menu from the associated resource file.
+ */
+ protected JMenuBar createMenubar() {
+ JMenuBar mb = new JMenuBar();
+ for(String menuKey: getMenuBarKeys()){
+ JMenu m = createMenu(menuKey);
+ if (m != null) {
+ mb.add(m);
+ }
+ }
+ return mb;
+ }
+
+ /**
+ * Create a menu for the app. By default this pulls the
+ * definition of the menu from the associated resource file.
+ */
+ protected JMenu createMenu(String key) {
+ JMenu menu = new JMenu(getResourceString(key + labelSuffix));
+ for (String itemKey: getItemKeys(key)) {
+ if (itemKey.equals("-")) {
+ menu.addSeparator();
+ } else {
+ JMenuItem mi = createMenuItem(itemKey);
+ menu.add(mi);
+ }
+ }
+ return menu;
+ }
+
+ /**
+ * Get keys for menus
+ */
+ protected String[] getItemKeys(String key) {
+ switch (key) {
+ case "file":
+ return FILE_KEYS;
+ case "edit":
+ return EDIT_KEYS;
+ case "debug":
+ return DEBUG_KEYS;
+ default:
+ return null;
+ }
+ }
+
+ protected String[] getMenuBarKeys() {
+ return MENUBAR_KEYS;
+ }
+
+ protected String[] getToolBarKeys() {
+ return TOOLBAR_KEYS;
+ }
+
+ // Yarked from JMenu, ideally this would be public.
+ protected PropertyChangeListener createActionChangeListener(JMenuItem b) {
+ return new ActionChangedListener(b);
+ }
+
+ // Yarked from JMenu, ideally this would be public.
+
+ private class ActionChangedListener implements PropertyChangeListener {
+
+ JMenuItem menuItem;
+
+ ActionChangedListener(JMenuItem mi) {
+ super();
+ this.menuItem = mi;
+ }
+
+ public void propertyChange(PropertyChangeEvent e) {
+ String propertyName = e.getPropertyName();
+ if (e.getPropertyName().equals(Action.NAME)) {
+ String text = (String) e.getNewValue();
+ menuItem.setText(text);
+ } else if (propertyName.equals("enabled")) {
+ Boolean enabledState = (Boolean) e.getNewValue();
+ menuItem.setEnabled(enabledState.booleanValue());
+ }
+ }
+ }
+ private JTextComponent editor;
+ private Map<Object, Action> commands;
+ private JToolBar toolbar;
+ private JComponent status;
+ private JFrame elementTreeFrame;
+ protected ElementTreePanel elementTreePanel;
+
+ /**
+ * Listener for the edits on the current document.
+ */
+ protected UndoableEditListener undoHandler = new UndoHandler();
+ /** UndoManager that we add edits to. */
+ protected UndoManager undo = new UndoManager();
+ /**
+ * Suffix applied to the key used in resource file
+ * lookups for an image.
+ */
+ public static final String imageSuffix = "Image";
+ /**
+ * Suffix applied to the key used in resource file
+ * lookups for a label.
+ */
+ public static final String labelSuffix = "Label";
+ /**
+ * Suffix applied to the key used in resource file
+ * lookups for an action.
+ */
+ public static final String actionSuffix = "Action";
+ /**
+ * Suffix applied to the key used in resource file
+ * lookups for tooltip text.
+ */
+ public static final String tipSuffix = "Tooltip";
+ public static final String openAction = "open";
+ public static final String newAction = "new";
+ public static final String saveAction = "save";
+ public static final String exitAction = "exit";
+ public static final String showElementTreeAction = "showElementTree";
+
+
+ class UndoHandler implements UndoableEditListener {
+
+ /**
+ * Messaged when the Document has created an edit, the edit is
+ * added to <code>undo</code>, an instance of UndoManager.
+ */
+ public void undoableEditHappened(UndoableEditEvent e) {
+ undo.addEdit(e.getEdit());
+ undoAction.update();
+ redoAction.update();
+ }
+ }
+
+
+ /**
+ * FIXME - I'm not very useful yet
+ */
+ class StatusBar extends JComponent {
+
+ public StatusBar() {
+ super();
+ setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
+ }
+
+ @Override
+ public void paint(Graphics g) {
+ super.paint(g);
+ }
+ }
+ // --- action implementations -----------------------------------
+ private UndoAction undoAction = new UndoAction();
+ private RedoAction redoAction = new RedoAction();
+ /**
+ * Actions defined by the Notepad class
+ */
+ private Action[] defaultActions = {
+ new NewAction(),
+ new OpenAction(),
+ new SaveAction(),
+ new ExitAction(),
+ new ShowElementTreeAction(),
+ undoAction,
+ redoAction
+ };
+
+
+ class UndoAction extends AbstractAction {
+
+ public UndoAction() {
+ super("Undo");
+ setEnabled(false);
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ try {
+ undo.undo();
+ } catch (CannotUndoException ex) {
+ Logger.getLogger(UndoAction.class.getName()).log(Level.SEVERE,
+ "Unable to undo", ex);
+ }
+ update();
+ redoAction.update();
+ }
+
+ protected void update() {
+ if (undo.canUndo()) {
+ setEnabled(true);
+ putValue(Action.NAME, undo.getUndoPresentationName());
+ } else {
+ setEnabled(false);
+ putValue(Action.NAME, "Undo");
+ }
+ }
+ }
+
+
+ class RedoAction extends AbstractAction {
+
+ public RedoAction() {
+ super("Redo");
+ setEnabled(false);
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ try {
+ undo.redo();
+ } catch (CannotRedoException ex) {
+ Logger.getLogger(RedoAction.class.getName()).log(Level.SEVERE,
+ "Unable to redo", ex);
+ }
+ update();
+ undoAction.update();
+ }
+
+ protected void update() {
+ if (undo.canRedo()) {
+ setEnabled(true);
+ putValue(Action.NAME, undo.getRedoPresentationName());
+ } else {
+ setEnabled(false);
+ putValue(Action.NAME, "Redo");
+ }
+ }
+ }
+
+
+ class OpenAction extends NewAction {
+
+ OpenAction() {
+ super(openAction);
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ Frame frame = getFrame();
+ JFileChooser chooser = new JFileChooser();
+ int ret = chooser.showOpenDialog(frame);
+
+ if (ret != JFileChooser.APPROVE_OPTION) {
+ return;
+ }
+
+ File f = chooser.getSelectedFile();
+ if (f.isFile() && f.canRead()) {
+ Document oldDoc = getEditor().getDocument();
+ if (oldDoc != null) {
+ oldDoc.removeUndoableEditListener(undoHandler);
+ }
+ if (elementTreePanel != null) {
+ elementTreePanel.setEditor(null);
+ }
+ getEditor().setDocument(new PlainDocument());
+ frame.setTitle(f.getName());
+ Thread loader = new FileLoader(f, editor.getDocument());
+ loader.start();
+ } else {
+ JOptionPane.showMessageDialog(getFrame(),
+ "Could not open file: " + f,
+ "Error opening file",
+ JOptionPane.ERROR_MESSAGE);
+ }
+ }
+ }
+
+
+ class SaveAction extends AbstractAction {
+
+ SaveAction() {
+ super(saveAction);
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ Frame frame = getFrame();
+ JFileChooser chooser = new JFileChooser();
+ int ret = chooser.showSaveDialog(frame);
+
+ if (ret != JFileChooser.APPROVE_OPTION) {
+ return;
+ }
+
+ File f = chooser.getSelectedFile();
+ frame.setTitle(f.getName());
+ Thread saver = new FileSaver(f, editor.getDocument());
+ saver.start();
+ }
+ }
+
+
+ class NewAction extends AbstractAction {
+
+ NewAction() {
+ super(newAction);
+ }
+
+ NewAction(String nm) {
+ super(nm);
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ Document oldDoc = getEditor().getDocument();
+ if (oldDoc != null) {
+ oldDoc.removeUndoableEditListener(undoHandler);
+ }
+ getEditor().setDocument(new PlainDocument());
+ getEditor().getDocument().addUndoableEditListener(undoHandler);
+ resetUndoManager();
+ getFrame().setTitle(resources.getString("Title"));
+ revalidate();
+ }
+ }
+
+
+ /**
+ * Really lame implementation of an exit command
+ */
+ class ExitAction extends AbstractAction {
+
+ ExitAction() {
+ super(exitAction);
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ System.exit(0);
+ }
+ }
+
+
+ /**
+ * Action that brings up a JFrame with a JTree showing the structure
+ * of the document.
+ */
+ class ShowElementTreeAction extends AbstractAction {
+
+ ShowElementTreeAction() {
+ super(showElementTreeAction);
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ if (elementTreeFrame == null) {
+ // Create a frame containing an instance of
+ // ElementTreePanel.
+ try {
+ String title = resources.getString("ElementTreeFrameTitle");
+ elementTreeFrame = new JFrame(title);
+ } catch (MissingResourceException mre) {
+ elementTreeFrame = new JFrame();
+ }
+
+ elementTreeFrame.addWindowListener(new WindowAdapter() {
+
+ @Override
+ public void windowClosing(WindowEvent weeee) {
+ elementTreeFrame.setVisible(false);
+ }
+ });
+ Container fContentPane = elementTreeFrame.getContentPane();
+
+ fContentPane.setLayout(new BorderLayout());
+ elementTreePanel = new ElementTreePanel(getEditor());
+ fContentPane.add(elementTreePanel);
+ elementTreeFrame.pack();
+ }
+ elementTreeFrame.setVisible(true);
+ }
+ }
+
+
+ /**
+ * Thread to load a file into the text storage model
+ */
+ class FileLoader extends Thread {
+
+ FileLoader(File f, Document doc) {
+ setPriority(4);
+ this.f = f;
+ this.doc = doc;
+ }
+
+ @Override
+ public void run() {
+ try {
+ // initialize the statusbar
+ status.removeAll();
+ JProgressBar progress = new JProgressBar();
+ progress.setMinimum(0);
+ progress.setMaximum((int) f.length());
+ status.add(progress);
+ status.revalidate();
+
+ // try to start reading
+ Reader in = new FileReader(f);
+ char[] buff = new char[4096];
+ int nch;
+ while ((nch = in.read(buff, 0, buff.length)) != -1) {
+ doc.insertString(doc.getLength(), new String(buff, 0, nch),
+ null);
+ progress.setValue(progress.getValue() + nch);
+ }
+ } catch (IOException e) {
+ final String msg = e.getMessage();
+ SwingUtilities.invokeLater(new Runnable() {
+
+ public void run() {
+ JOptionPane.showMessageDialog(getFrame(),
+ "Could not open file: " + msg,
+ "Error opening file",
+ JOptionPane.ERROR_MESSAGE);
+ }
+ });
+ } catch (BadLocationException e) {
+ System.err.println(e.getMessage());
+ }
+ doc.addUndoableEditListener(undoHandler);
+ // we are done... get rid of progressbar
+ status.removeAll();
+ status.revalidate();
+
+ resetUndoManager();
+
+ if (elementTreePanel != null) {
+ SwingUtilities.invokeLater(new Runnable() {
+
+ public void run() {
+ elementTreePanel.setEditor(getEditor());
+ }
+ });
+ }
+ }
+ Document doc;
+ File f;
+ }
+
+
+ /**
+ * Thread to save a document to file
+ */
+ class FileSaver extends Thread {
+
+ Document doc;
+ File f;
+
+ FileSaver(File f, Document doc) {
+ setPriority(4);
+ this.f = f;
+ this.doc = doc;
+ }
+
+ @Override
+ @SuppressWarnings("SleepWhileHoldingLock")
+ public void run() {
+ try {
+ // initialize the statusbar
+ status.removeAll();
+ JProgressBar progress = new JProgressBar();
+ progress.setMinimum(0);
+ progress.setMaximum(doc.getLength());
+ status.add(progress);
+ status.revalidate();
+
+ // start writing
+ Writer out = new FileWriter(f);
+ Segment text = new Segment();
+ text.setPartialReturn(true);
+ int charsLeft = doc.getLength();
+ int offset = 0;
+ while (charsLeft > 0) {
+ doc.getText(offset, Math.min(4096, charsLeft), text);
+ out.write(text.array, text.offset, text.count);
+ charsLeft -= text.count;
+ offset += text.count;
+ progress.setValue(offset);
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ Logger.getLogger(FileSaver.class.getName()).log(
+ Level.SEVERE,
+ null, e);
+ }
+ }
+ out.flush();
+ out.close();
+ } catch (IOException e) {
+ final String msg = e.getMessage();
+ SwingUtilities.invokeLater(new Runnable() {
+
+ public void run() {
+ JOptionPane.showMessageDialog(getFrame(),
+ "Could not save file: " + msg,
+ "Error saving file",
+ JOptionPane.ERROR_MESSAGE);
+ }
+ });
+ } catch (BadLocationException e) {
+ System.err.println(e.getMessage());
+ }
+ // we are done... get rid of progressbar
+ status.removeAll();
+ status.revalidate();
+ }
+ }
+}