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 }