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 }