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    //import javax.swing.filechooser.FileFilter;
027    
028    
029    public class FileEditorPanel extends JPanel {
030        private JToolBar toolbar;
031        private JTextComponent editor;
032        private File file;      // file from which editor contents were
033                                //  loaded (or null if no file yet)
034        private boolean dirty = false;  // editor contents have been changed 
035                                        // but not saved
036        private UndoManager undo = new UndoManager ();
037    
038    
039        public FileEditorPanel () {
040            this(new JTextArea());
041        }
042    
043    
044        public FileEditorPanel (JTextComponent myEditor) {
045            super ();
046    
047            setLayout (new BorderLayout ());
048    
049            // Set up the editor
050            editor = myEditor;
051            editor.setMargin (new Insets (2, 2, 2, 2));
052            editor.setFont (new Font ("Monospaced", Font.PLAIN, 12));
053    
054            // Create the toolbar
055            toolbar = new JToolBar (JToolBar.HORIZONTAL);
056            toolbar.setFloatable (false);
057    
058            add (Layout.horizontal()
059                 .add(toolbar)
060                 .addGlue()
061                 .done(), 
062                 BorderLayout.NORTH);
063    
064            // Register dirty-flag listener
065            Document doc = editor.getDocument ();
066            doc.addDocumentListener (new DocumentListener () {
067                public void changedUpdate (DocumentEvent event) {
068                }
069                public void insertUpdate (DocumentEvent event) {
070                    dirty = true;
071                }
072                public void removeUpdate (DocumentEvent event) {
073                    dirty = true;
074                }
075            });
076    
077            CoalescingUndo.setUndoableEditListener (editor.getDocument (), undo);
078    
079            // Wrap editor in a scrolling pane
080            JScrollPane scrollPane = new JScrollPane (editor);
081            scrollPane.setDoubleBuffered (true);
082            scrollPane.setPreferredSize (new Dimension (500, 500));
083            add (scrollPane, BorderLayout.CENTER);
084        }
085    
086    
087        protected void handleInteractiveException (Exception exception) {
088            exception.printStackTrace ();
089            JOptionPane.showMessageDialog (null, exception,
090                                           "Error", JOptionPane.ERROR_MESSAGE);
091        }
092    
093    
094        /**
095         * Clear the editor.
096         */
097        public void clear () {
098            setText ("");
099            dirty = false;
100            setFile (null);
101            undo.discardAllEdits ();
102        }
103    
104    
105        /**
106         * Check whether or not the editor has unsaved content; 
107         * if there is, pops up a dialog box to ask if editor 
108         * contents should be saved.
109         */
110        public boolean okToClear () {
111            if (!dirty)
112                return true;
113    
114            switch (JOptionPane.showConfirmDialog (this, 
115                                                   "The current file has been " + 
116                                                   "changed.  Do you want to " + 
117                                                   "save it?",
118                                                   "Save First?", 
119                                                   JOptionPane.YES_NO_CANCEL_OPTION)) {
120            case JOptionPane.YES_OPTION:
121                return (file != null)
122                    ? save (file)
123                    : save ();
124                
125            case JOptionPane.NO_OPTION:
126                return true;
127               
128            default:
129                return false;
130            }
131        }
132    
133        
134        /**
135         * Pop up a file-open dialog to open a file into the editor.
136         */
137        public void open () {
138            FileChooser chooser = makeFileChooser ();
139                
140            if (chooser.showOpenDialog (this) == JFileChooser.APPROVE_OPTION)
141                open (chooser.getSelectedFile ());
142        }
143        
144    
145        /**
146         * Make a file-chooser object.
147         */
148        protected FileChooser makeFileChooser () {
149            return new FileChooser ();
150        }
151    
152    
153        /**
154         * Open a file (or URL) in the editor.  Pops up a dialog box if
155         * an error occurs.
156         *
157         * @param f File to open
158         */
159        public void open (File f) {
160            try {
161                Reader r = new FileReader (f);
162    
163                int n;
164                StringBuffer contentBuf = new StringBuffer ();
165                char[] buf = new char[256];
166                while ((n = r.read (buf)) != -1)
167                    contentBuf.append (buf, 0, n);
168    
169                setText (contentBuf.toString ());
170                dirty = false;
171                editor.select (0, 0);
172                setFile (f);
173                undo.discardAllEdits ();
174            } catch (Exception e) {
175                handleInteractiveException (e);
176                dirty = false;
177                clear ();
178                return;
179            }
180        }
181    
182    
183        /**
184         * Pop up a save-as dialog box, then saves the editor contents.
185         */
186        public boolean save () {
187            FileChooser chooser = makeFileChooser ();
188            if (file != null)
189                chooser.setSelectedFile (file);
190            
191            if (chooser.showSaveDialog (this) != JFileChooser.APPROVE_OPTION)
192                return false;
193    
194            File f = chooser.getSelectedFile ();
195                if (f.exists ()) 
196                    switch (JOptionPane.showConfirmDialog (FileEditorPanel.this, 
197                                                           f + 
198                                                           " already exists. " + 
199                                                           "Overwrite?\n", 
200                                                           "Overwrite?", 
201                                                           JOptionPane.YES_NO_CANCEL_OPTION)) {
202                        case JOptionPane.YES_OPTION:
203                            break;
204                        case JOptionPane.NO_OPTION:
205                            // Pop up dialog box again
206                            return save ();
207                        case JOptionPane.CANCEL_OPTION:
208                            return false;
209                    }
210    
211            return save (f);
212        }
213    
214    
215        /**
216         * Save editor contents to a local file.
217         *
218         * @param f Local file to save
219         */
220        public boolean save (File f) {
221            try {
222                PrintWriter out = new PrintWriter (new FileWriter (f));
223                out.print (editor.getText ());
224                out.close ();
225                dirty = false;
226                setFile (f);
227                return true;
228            } catch (Exception e) {
229                handleInteractiveException (e);
230                return false;
231            }
232        }
233    
234    
235        /**
236         * Return editor contents.
237         *
238         * @return editor contents as string
239         */
240        public String getText () {
241            return editor.getText ();
242        }
243    
244    
245        /**
246         * Set the editor contents.
247         */
248        public void setText (String text) {
249            editor.setText (text);
250        }
251    
252    
253        /**
254         * Return the editor.
255         *
256         * @return editor as a JTextComponent
257         */
258        public JTextComponent getEditor () {
259            return editor;    
260        }
261    
262    
263        /**
264         * Return the starting index of the selection in 
265         * the editor.
266         */
267        public int getEditorSelectionStart() {
268            return editor.getSelectionStart();
269        }
270    
271    
272        /**
273         * Return the ending index of the selection in 
274         * the editor.
275         */
276        public int getEditorSelectionEnd() {
277            return editor.getSelectionEnd();
278        }
279    
280    
281        /**
282         * Return the document for the editor.
283         */
284        public Document getEditorDocument() {
285            return editor.getDocument();
286        }
287    
288    
289        /**
290         * Return the toolbar.
291         *
292         * @return toolbar as a JToolBar
293         */
294        public JToolBar getToolBar () {
295            return toolbar;
296        }
297    
298    
299        /**
300         * Return the value of the dirty flag, which signals 
301         * whether or not the editor's contents have been 
302         * changed but not saved.
303         *
304         * @return the value of the dirty flag as a boolean
305         */
306        public boolean getDirty () {
307            return dirty;
308        }
309    
310    
311        /**
312         * Set the dirty flag to the new boolean value.
313         */
314        public void setDirty (boolean dirty) {
315            this.dirty = dirty;
316        }
317    
318    
319        /**
320         * Return the file from which the 
321         * editor contents were loaded, or null if there 
322         * was none.
323         *
324         * @return the name of the file from which the editor 
325         *         was loaded (or null if none exists) as a 
326         *         string
327         */
328        public File getFile () {
329            return file;
330        }
331    
332    
333        /**
334         * Set the file from which the editor 
335         * contents are loaded.
336         */
337        public void setFile (File file) {
338            this.file = file;
339        }
340    
341    
342        /**
343         * Add a file "menu" (actually a combo box) to the toolbar.
344         */
345        public void addFileMenu () {
346            final JComboBox fileMenu = new JComboBox();
347    
348            fileMenu.addItem("File");
349            fileMenu.addItem("  New");
350            fileMenu.addItem("  Open...");
351            fileMenu.addItem("  Save");
352            fileMenu.addItem("  Save As...");
353    
354            Action fileMenuAction = new AbstractAction() {
355                public void actionPerformed (ActionEvent evt) {
356                    String selection = (String) fileMenu.getSelectedItem();
357    
358                    fileMenu.setSelectedItem("File");
359    
360                    if (selection.equals("  New")) {
361                        if (okToClear()) {
362                            clear();
363                        }
364                    }
365                    else if (selection.equals("  Open...")) {
366                        if (okToClear())
367                            open();
368                    }
369                    else if (selection.equals("  Save")) {
370                        if (file != null)
371                            save(file);
372                        else
373                            save();
374                    }
375                    else if (selection.equals("  Save As...")) {
376                        save();
377                    }
378                }
379            };
380            fileMenu.addActionListener(fileMenuAction);
381            
382            toolbar.add(fileMenu);
383        }
384    
385        
386        /**
387         * Add a Select Color button that allows the background color 
388         * for the text editor to be changed.
389         *
390         * @effects adds a button that pops up a color chooser dialog
391         *          box and sets the background color for the text 
392         *          editor
393         * @returns nothing
394         */
395        public void addColorChooser() {
396            Action selectColorAction = new AcceleratedAction ("&Select Color") {
397                    public void actionPerformed (ActionEvent evt) {
398                        Color c = JColorChooser.showDialog(FileEditorPanel.this, 
399                                                           "Select Background Color",
400                                                           editor.getBackground());
401                        if (c != null) {
402                            editor.setBackground(c);
403                            editor.repaint();
404                        }
405                    }
406                };
407    
408            toolbar.add(selectColorAction);
409        }
410    
411    }