001    /*
002     * LAPIS lightweight structured text processing system
003     *
004     * Copyright (C) 1998-2002 Carnegie Mellon University,
005     * Copyright (C) 2003 Massachusetts Institute of Technology.
006     * All rights reserved.
007     *
008     * This library is free software; you can redistribute it
009     * and/or modify it under the terms of the GNU General
010     * Public License as published by the Free Software
011     * Foundation, version 2.
012     *
013     * LAPIS homepage: http://graphics.lcs.mit.edu/lapis/
014     */
015    
016    package lapisx.swing;
017    
018    import java.awt.*;
019    import java.awt.event.*;
020    import java.io.*;
021    import java.util.*;
022    import javax.swing.*;
023    import javax.swing.text.*;
024    import javax.swing.event.*;
025    import javax.swing.undo.*;
026    
027    
028    public class FileEditor extends JFrame {
029        private String defaultTitle;
030        private FileEditorPanel editorPanel;
031        private UndoManager undo = new UndoManager () {
032            };
033    
034    
035        public FileEditor (String title, JTextComponent editor) {
036            super (title);
037    
038            defaultTitle = title;
039    
040            Container contentPane = getContentPane ();
041            contentPane.setLayout (new BorderLayout ());
042    
043            // Creat the file editor panel
044            editorPanel = new FileEditorPanel(editor) {
045                    protected void handleInteractiveException(Exception exception) {
046                        FileEditor.this.handleInteractiveException(exception);
047                    }
048    
049                    protected FileChooser makeFileChooser() {
050                        return FileEditor.this.makeFileChooser();
051                    }
052    
053                    public void setFile (File file) {
054                        editorPanel.setFile(file);
055                        
056                        if (file == null)
057                            setTitle (defaultTitle);
058                        else
059                            setTitle (defaultTitle + " - " + file.getName ());
060                    }
061    
062                };
063            contentPane.add(editorPanel, BorderLayout.CENTER);
064    
065            // Create actions that depend on the editor.
066            cutAction = new AcceleratedAction 
067                 ("Cu&t", 'X', KeyEvent.CTRL_MASK,
068                  getActionByName (DefaultEditorKit.cutAction));
069            copyAction = new AcceleratedAction 
070                ("&Copy", 'C', KeyEvent.CTRL_MASK,
071                 getActionByName (DefaultEditorKit.copyAction));
072            pasteAction = new AcceleratedAction 
073                ("&Paste", 'V', KeyEvent.CTRL_MASK,
074                 getActionByName (DefaultEditorKit.pasteAction));
075            selectAllAction = new AcceleratedAction 
076                ("Select &All", 'A', KeyEvent.CTRL_MASK,
077                 getActionByName (DefaultEditorKit.selectAllAction));
078    
079    
080            // Create the menubar
081            JMenuBar mb = new JMenuBar ();
082    
083            JMenu fileMenu = new AcceleratedMenu ("&File");
084            fileMenu.add (newAction);
085            fileMenu.add (openAction);
086            fileMenu.add (saveAction);
087            fileMenu.add (saveAsAction);
088            fileMenu.add (closeAction);
089            mb.add (fileMenu);
090    
091            JMenu editMenu = new AcceleratedMenu ("&Edit");
092            editMenu.add (undoAction);
093            editMenu.add (redoAction);
094            editMenu.addSeparator ();
095            editMenu.add (cutAction);
096            editMenu.add (copyAction);
097            editMenu.add (pasteAction);
098            editMenu.add (selectAllAction);
099            mb.add (editMenu);
100    
101            editMenu.addMenuListener (new MenuListener () {
102                    public void menuSelected(MenuEvent e) {
103                        undoAction.setEnabled (undo.canUndo ());
104                        redoAction.setEnabled (undo.canRedo ());
105    
106                        boolean selected = editorPanel.getEditorSelectionStart() < 
107                            editorPanel.getEditorSelectionEnd ();
108                        cutAction.setEnabled (selected);
109                        copyAction.setEnabled (selected);
110                    }
111                    public void menuDeselected(MenuEvent e) {
112                        undoAction.setEnabled (true);
113                        redoAction.setEnabled (true);
114                        cutAction.setEnabled (true);
115                        copyAction.setEnabled (true);
116                    }
117                    public void menuCanceled(MenuEvent e) {
118                        undoAction.setEnabled (true);
119                        redoAction.setEnabled (true);
120                        cutAction.setEnabled (true);
121                        copyAction.setEnabled (true);
122                    }
123                });
124                    
125            setJMenuBar (mb);
126    
127    
128            CoalescingUndo.setUndoableEditListener(editorPanel.getEditorDocument(),
129                                                   undo);
130    
131            pack ();
132        }
133    
134    
135        protected JTextComponent makeEditor () {
136            return new JTextArea ();
137        }
138    
139    
140        protected void handleInteractiveException (Exception exception) {
141            exception.printStackTrace ();
142            JOptionPane.showMessageDialog (null, exception,
143                                           "Error", JOptionPane.ERROR_MESSAGE);
144        }
145    
146    
147        /**
148         * Action invoked by File/New command.  Clears the editor.
149         */
150        public Action newAction = new AcceleratedAction ("&New", 'N', 
151                                                         KeyEvent.CTRL_MASK) {
152            public void actionPerformed (ActionEvent evt) {
153                if (okToClear ())
154                    clear ();
155            }
156        };
157        
158    
159        /**
160         * Action invoked by File/Open command.  Pops up a file-open dialog.
161         */
162        public Action openAction = new AcceleratedAction ("&Open...", 'O', 
163                                                          KeyEvent.CTRL_MASK) {
164            public void actionPerformed (ActionEvent evt) {
165                if (okToClear ())
166                    open ();
167            }
168        };
169        
170    
171        /**
172         * Action invoked by File/Save command.  Saves the contents of the edito.
173         */
174        public Action saveAction = new AcceleratedAction ("&Save", 'S', 
175                                                          KeyEvent.CTRL_MASK) {
176            public void actionPerformed (ActionEvent evt) {
177                File file = editorPanel.getFile();
178    
179                if (file != null)
180                    save (file);
181                else
182                    save ();
183            }
184        };
185        
186    
187        /**
188         * Action invoked by File/Save As command.  Pops up a save-as dialog.
189         */
190        public Action saveAsAction = new AcceleratedAction ("Save &As...") {
191            public void actionPerformed (ActionEvent evt) {
192                save ();
193            }
194        };
195        
196    
197        /**
198         * Action invoked by File/Close command.  Disposes of this editor.
199         */
200        public Action closeAction = new AcceleratedAction ("&Close") {
201            public void actionPerformed (ActionEvent evt) {
202                if (okToClear ()) {
203                    clear ();
204                    setVisible (false);
205                }
206            }
207        };
208    
209        
210        /**
211         * Action invoked by Edit/Undo command.  Undoes one editing action.
212         */
213        public Action undoAction = new AcceleratedAction ("&Undo", 'Z', 
214                                                          KeyEvent.CTRL_MASK) {
215            public void actionPerformed (ActionEvent evt) {
216                try {
217                    undo.undo ();
218                } catch (CannotUndoException e) {
219                    getToolkit ().beep ();
220                }
221            }
222        };
223    
224    
225        /**
226         * Action invoked by Edit/Redo command.  Redoes one editing action.
227         */
228        public Action redoAction = new AcceleratedAction ("&Redo", 'Y', 
229                                                          KeyEvent.CTRL_MASK) {
230            public void actionPerformed (ActionEvent evt) {
231                try {
232                    undo.redo ();
233                } catch (CannotRedoException e) {
234                    getToolkit ().beep ();
235                }
236            }
237        };
238    
239    
240        /**
241         * Action invoked by Edit/Cut command.  Cuts current selection 
242         * to clipboard.
243         */
244        public Action cutAction;
245    
246    
247        /**
248         * Action invoked by Edit/Copy command.  Copies current selection 
249         * to clipboard.
250         */
251        public Action copyAction;
252    
253    
254        /**
255         * Action invoked by Edit/Paste action.  Pastes clipboard.
256         */
257        public Action pasteAction;
258    
259    
260        /**
261         * Action invoked by Edit/Select All command.  Selects entire editor.
262         */
263        public Action selectAllAction;
264    
265    
266        /**
267         * Gets original Edit/Cut, Copy, Paste, or Select-All actions 
268         * from the editor.
269         */
270        Hashtable actions;
271        Action getActionByName (String name) {
272            if (actions == null) {
273                actions = new Hashtable ();
274                Action[] a = editorPanel.getEditor().getActions();
275                for (int i = 0; i < a.length; ++i)
276                    actions.put (a[i].getValue (Action.NAME), a[i]);
277            }
278            return (Action) actions.get (name);
279        }
280    
281    
282        /**
283         * Clear the editor.
284         */
285        public void clear () {
286            editorPanel.clear();
287            undo.discardAllEdits ();
288        }
289    
290    
291        /**
292         * Checks whether or not the editor has unsaved content.
293         */
294        public boolean okToClear () {
295            return editorPanel.okToClear();
296        }
297        
298    
299        /**
300         * Pop up a file-open dialog to open a file into the editor.
301         */
302        public void open () {
303            editorPanel.open();
304    
305        }
306        
307    
308        protected FileChooser makeFileChooser () {
309            return new FileChooser ();
310        }
311    
312    
313        /**
314         * Open a file (or URL) in the editor.  Pops up a dialog box if
315         * an error occurs.
316         *
317         * @param f File to open
318         */
319        public void open (File f) {
320            editorPanel.open(f);
321            undo.discardAllEdits ();
322        }
323    
324    
325        /**
326         * Pop up a save-as dialog box, then saves the editor contents.
327         */
328        public boolean save () {
329            return editorPanel.save();
330        }
331    
332    
333        /**
334         * Save editor contents to a local file.
335         *
336         * @param f Local file to save
337         */
338        public boolean save (File f) {
339            return editorPanel.save(f);
340        }
341    
342    
343        /**
344         * Return editor contents
345         *
346         * @return editor contents as string
347         */
348        public String getText () {
349            return editorPanel.getText();
350        }
351    
352    
353        /**
354         * Set the editor contents.
355         */
356        public void setText (String text) {
357            editorPanel.setText(text);
358        }
359    
360    
361        /**
362         * Return the editor.
363         *
364         * @return editor as a JTextComponent
365         */
366        public JTextComponent getEditor () {
367            return editorPanel.getEditor();
368        }
369    
370    
371        /**
372         * Return the toolbar.
373         *
374         * @return toolbar as a JToolBar
375         */
376        public JToolBar getToolBar () {
377            return editorPanel.getToolBar();
378        }
379    
380    
381        /**
382         * Return the value of the dirty flag, which signals 
383         * whether or not the editor's contents have been 
384         * changed but not saved.
385         *
386         * @return the value of the dirty flag as a boolean
387         */
388        public boolean getDirty () {
389            return editorPanel.getDirty();
390        }
391    
392    
393        /**
394         * Set the dirty flag to the new boolean value.
395         */
396        public void setDirty (boolean dirty) {
397            editorPanel.setDirty(dirty);
398        }
399    
400    
401        /**
402         * Return the file from which the 
403         * editor contents were loaded, or null if there 
404         * was none.
405         *
406         * @return the name of the file from which the editor 
407         *         was loaded (or null if none exists) as a 
408         *         string
409         */
410        public File getFile () {
411            return editorPanel.getFile();
412        }
413    
414    
415        public static void main (String[] args) {
416            FileEditor fe = new FileEditor ("FileEditor", new JTextArea());
417            fe.addWindowListener (new WindowAdapter () {
418                    public void windowClosing (WindowEvent event) {
419                        System.exit (0);
420                    }
421                });
422            if (args.length > 0)
423                fe.open (new File (args[0]));
424            fe.show ();
425        }
426    
427    }