KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > gjt > sp > jedit > Buffer


1 /*
2  * Buffer.java - jEdit buffer
3  * :tabSize=8:indentSize=8:noTabs=false:
4  * :folding=explicit:collapseFolds=1:
5  *
6  * Copyright (C) 1998, 2005 Slava Pestov
7  * Portions copyright (C) 1999, 2000 mike dillon
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22  */

23
24 package org.gjt.sp.jedit;
25
26 //{{{ Imports
27
import javax.swing.*;
28 import javax.swing.text.*;
29 import java.io.File JavaDoc;
30 import java.io.IOException JavaDoc;
31 import java.net.Socket JavaDoc;
32 import java.util.*;
33 import org.gjt.sp.jedit.browser.VFSBrowser;
34 import org.gjt.sp.jedit.buffer.*;
35 import org.gjt.sp.jedit.io.*;
36 import org.gjt.sp.jedit.msg.*;
37 import org.gjt.sp.jedit.syntax.*;
38 import org.gjt.sp.jedit.textarea.*;
39 import org.gjt.sp.jedit.bufferio.BufferIORequest;
40 import org.gjt.sp.jedit.bufferio.BufferAutosaveRequest;
41 import org.gjt.sp.jedit.bufferio.MarkersSaveRequest;
42 import org.gjt.sp.util.*;
43 //}}}
44

45 /**
46  * A <code>Buffer</code> represents the contents of an open text
47  * file as it is maintained in the computer's memory (as opposed to
48  * how it may be stored on a disk).<p>
49  *
50  * In a BeanShell script, you can obtain the current buffer instance from the
51  * <code>buffer</code> variable.<p>
52  *
53  * This class does not have a public constructor.
54  * Buffers can be opened and closed using methods in the <code>jEdit</code>
55  * class.<p>
56  *
57  * This class is partially thread-safe, however you must pay attention to two
58  * very important guidelines:
59  * <ul>
60  * <li>Changes to a buffer can only be made from the AWT thread.
61  * <li>When accessing the buffer from another thread, you must
62  * grab a read lock if you plan on performing more than one call, to ensure that
63  * the buffer contents are not changed by the AWT thread for the duration of the
64  * lock. Only methods whose descriptions specify thread safety can be invoked
65  * from other threads.
66  * </ul>
67  *
68  * @author Slava Pestov
69  * @version $Id: Buffer.java 8340 2007-01-10 21:12:06Z kpouer $
70  */

71 public class Buffer extends JEditBuffer
72 {
73     //{{{ Some constants
74
/**
75      * Backed up property.
76      * @since jEdit 3.2pre2
77      */

78     public static final String JavaDoc BACKED_UP = "Buffer__backedUp";
79
80     /**
81      * Caret info properties.
82      * @since jEdit 3.2pre1
83      */

84     public static final String JavaDoc CARET = "Buffer__caret";
85     public static final String JavaDoc CARET_POSITIONED = "Buffer__caretPositioned";
86
87     /**
88      * Stores a List of {@link Selection} instances.
89      */

90     public static final String JavaDoc SELECTION = "Buffer__selection";
91
92     /**
93      * This should be a physical line number, so that the scroll
94      * position is preserved correctly across reloads (which will
95      * affect virtual line numbers, due to fold being reset)
96      */

97     public static final String JavaDoc SCROLL_VERT = "Buffer__scrollVert";
98     public static final String JavaDoc SCROLL_HORIZ = "Buffer__scrollHoriz";
99
100     /**
101      * Should jEdit try to set the encoding based on a UTF8, UTF16 or
102      * XML signature at the beginning of the file?
103      */

104     public static final String JavaDoc ENCODING_AUTODETECT = "encodingAutodetect";
105
106     /**
107      * This property is set to 'true' if the file has a trailing newline.
108      * @since jEdit 4.0pre1
109      */

110     public static final String JavaDoc TRAILING_EOL = "trailingEOL";
111
112     /**
113      * This property is set to 'true' if the file should be GZipped.
114      * @since jEdit 4.0pre4
115      */

116     public static final String JavaDoc GZIPPED = "gzipped";
117     //}}}
118

119     //{{{ Input/output methods
120

121     //{{{ reload() method
122
/**
123      * Reloads the buffer from disk, asking for confirmation if the buffer
124      * has unsaved changes.
125      * @param view The view
126      * @since jEdit 2.7pre2
127      */

128     public void reload(View view)
129     {
130         if (getFlag(NEW_FILE))
131             return;
132         if(isDirty())
133         {
134             String JavaDoc[] args = { path };
135             int result = GUIUtilities.confirm(view,"changedreload",
136                 args,JOptionPane.YES_NO_OPTION,
137                 JOptionPane.WARNING_MESSAGE);
138             if(result != JOptionPane.YES_OPTION)
139                 return;
140         }
141         EditPane[] editPanes = view.getEditPanes();
142         for (int i = 0; i < editPanes.length; i++)
143             editPanes[i].saveCaretInfo();
144         load(view,true);
145     } //}}}
146

147     //{{{ load() method
148
/**
149      * Loads the buffer from disk.
150      * @param view The view
151      * @param reload If true, user will not be asked to recover autosave
152      * file, if any
153      *
154      * @since 2.5pre1
155      */

156     public boolean load(final View view, final boolean reload)
157     {
158         if(isPerformingIO())
159         {
160             GUIUtilities.error(view,"buffer-multiple-io",null);
161             return false;
162         }
163
164         setBooleanProperty(BufferIORequest.ERROR_OCCURRED,false);
165
166         setLoading(true);
167
168         // view text areas temporarily blank out while a buffer is
169
// being loaded, to indicate to the user that there is no
170
// data available yet.
171
if(!getFlag(TEMPORARY))
172             EditBus.send(new BufferUpdate(this,view,BufferUpdate.LOAD_STARTED));
173
174         final boolean loadAutosave;
175
176         if(reload || !getFlag(NEW_FILE))
177         {
178             if(file != null)
179                 modTime = file.lastModified();
180
181             // Only on initial load
182
if(!reload && autosaveFile != null && autosaveFile.exists())
183                 loadAutosave = recoverAutosave(view);
184             else
185             {
186                 if(autosaveFile != null)
187                     autosaveFile.delete();
188                 loadAutosave = false;
189             }
190
191             if(!loadAutosave)
192             {
193                 VFS vfs = VFSManager.getVFSForPath(path);
194
195                 if(!checkFileForLoad(view,vfs,path))
196                 {
197                     setLoading(false);
198                     return false;
199                 }
200
201                 // have to check again since above might set
202
// NEW_FILE flag
203
if(reload || !getFlag(NEW_FILE))
204                 {
205                     if(!vfs.load(view,this,path))
206                     {
207                         setLoading(false);
208                         return false;
209                     }
210                 }
211             }
212         }
213         else
214             loadAutosave = false;
215
216         //{{{ Do some stuff once loading is finished
217
Runnable JavaDoc runnable = new Runnable JavaDoc()
218         {
219             public void run()
220             {
221                 String JavaDoc newPath = getStringProperty(
222                     BufferIORequest.NEW_PATH);
223                 Segment seg = (Segment)getProperty(
224                     BufferIORequest.LOAD_DATA);
225                 IntegerArray endOffsets = (IntegerArray)
226                     getProperty(BufferIORequest.END_OFFSETS);
227
228                 loadText(seg,endOffsets);
229
230                 unsetProperty(BufferIORequest.LOAD_DATA);
231                 unsetProperty(BufferIORequest.END_OFFSETS);
232                 unsetProperty(BufferIORequest.NEW_PATH);
233
234                 undoMgr.clear();
235                 undoMgr.setLimit(jEdit.getIntegerProperty(
236                     "buffer.undoCount",100));
237
238                 if(!getFlag(TEMPORARY))
239                     finishLoading();
240
241                 setLoading(false);
242
243                 // if reloading a file, clear dirty flag
244
if(reload)
245                     setDirty(false);
246
247                 if(!loadAutosave && newPath != null)
248                     setPath(newPath);
249
250                 // if loadAutosave is false, we loaded an
251
// autosave file, so we set 'dirty' to true
252

253                 // note that we don't use setDirty(),
254
// because a) that would send an unnecessary
255
// message, b) it would also set the
256
// AUTOSAVE_DIRTY flag, which will make
257
// the autosave thread write out a
258
// redundant autosave file
259
if(loadAutosave)
260                     Buffer.super.setDirty(true);
261
262                 // send some EditBus messages
263
if(!getFlag(TEMPORARY))
264                 {
265                     fireBufferLoaded();
266                     EditBus.send(new BufferUpdate(Buffer.this,
267                         view,BufferUpdate.LOADED));
268                     //EditBus.send(new BufferUpdate(Buffer.this,
269
// view,BufferUpdate.MARKERS_CHANGED));
270
}
271             }
272         }; //}}}
273

274         if(getFlag(TEMPORARY))
275             runnable.run();
276         else
277             VFSManager.runInAWTThread(runnable);
278
279         return true;
280     } //}}}
281

282     //{{{ insertFile() method
283
/**
284      * Loads a file from disk, and inserts it into this buffer.
285      * @param view The view
286      *
287      * @since 4.0pre1
288      */

289     public boolean insertFile(View view, String JavaDoc path)
290     {
291         if(isPerformingIO())
292         {
293             GUIUtilities.error(view,"buffer-multiple-io",null);
294             return false;
295         }
296
297         setBooleanProperty(BufferIORequest.ERROR_OCCURRED,false);
298
299         path = MiscUtilities.constructPath(this.path,path);
300
301         Buffer buffer = jEdit.getBuffer(path);
302         if(buffer != null)
303         {
304             view.getTextArea().setSelectedText(
305                 buffer.getText(0,buffer.getLength()));
306             return true;
307         }
308
309         VFS vfs = VFSManager.getVFSForPath(path);
310
311         // this returns false if initial sanity
312
// checks (if the file is a directory, etc)
313
// fail
314
return vfs.insert(view,this,path);
315     } //}}}
316

317     //{{{ autosave() method
318
/**
319      * Autosaves this buffer.
320      */

321     public void autosave()
322     {
323         if(autosaveFile == null || !getFlag(AUTOSAVE_DIRTY)
324             || !isDirty() || isPerformingIO())
325             return;
326
327         setFlag(AUTOSAVE_DIRTY,false);
328
329         VFSManager.runInWorkThread(new BufferAutosaveRequest(
330             null,this,null,VFSManager.getFileVFS(),
331             autosaveFile.getPath()));
332     } //}}}
333

334     //{{{ saveAs() method
335
/**
336      * Prompts the user for a file to save this buffer to.
337      * @param view The view
338      * @param rename True if the buffer's path should be changed, false
339      * if only a copy should be saved to the specified filename
340      * @since jEdit 2.6pre5
341      */

342     public boolean saveAs(View view, boolean rename)
343     {
344         String JavaDoc[] files = GUIUtilities.showVFSFileDialog(view,path,
345             VFSBrowser.SAVE_DIALOG,false);
346
347         // files[] should have length 1, since the dialog type is
348
// SAVE_DIALOG
349
if(files == null)
350             return false;
351
352         return save(view,files[0],rename);
353     } //}}}
354

355     //{{{ save() method
356
/**
357      * Saves this buffer to the specified path name, or the current path
358      * name if it's null.
359      * @param view The view
360      * @param path The path name to save the buffer to, or null to use
361      * the existing path
362      */

363     public boolean save(View view, String JavaDoc path)
364     {
365         return save(view,path,true);
366     } //}}}
367

368     //{{{ save() method
369
/**
370      * Saves this buffer to the specified path name, or the current path
371      * name if it's null.
372      * @param view The view
373      * @param path The path name to save the buffer to, or null to use
374      * the existing path
375      * @param rename True if the buffer's path should be changed, false
376      * if only a copy should be saved to the specified filename
377      * @since jEdit 2.6pre5
378      */

379     public boolean save(final View view, String JavaDoc path, final boolean rename)
380     {
381         if(isPerformingIO())
382         {
383             GUIUtilities.error(view,"buffer-multiple-io",null);
384             return false;
385         }
386
387         setBooleanProperty(BufferIORequest.ERROR_OCCURRED,false);
388
389         if(path == null && getFlag(NEW_FILE))
390             return saveAs(view,rename);
391
392         if(path == null && file != null)
393         {
394             long newModTime = file.lastModified();
395
396             if(newModTime != modTime
397                 && jEdit.getBooleanProperty("view.checkModStatus"))
398             {
399                 Object JavaDoc[] args = { this.path };
400                 int result = GUIUtilities.confirm(view,
401                     "filechanged-save",args,
402                     JOptionPane.YES_NO_OPTION,
403                     JOptionPane.WARNING_MESSAGE);
404                 if(result != JOptionPane.YES_OPTION)
405                     return false;
406             }
407         }
408
409         EditBus.send(new BufferUpdate(this,view,BufferUpdate.SAVING));
410
411         setPerformingIO(true);
412
413         final String JavaDoc oldPath = this.path;
414         final String JavaDoc oldSymlinkPath = symlinkPath;
415         final String JavaDoc newPath = path == null ? this.path : path;
416
417         VFS vfs = VFSManager.getVFSForPath(newPath);
418
419         if(!checkFileForSave(view,vfs,newPath))
420         {
421             setPerformingIO(false);
422             return false;
423         }
424
425         Object JavaDoc session = vfs.createVFSSession(newPath,view);
426         if (session == null)
427         {
428             setPerformingIO(false);
429             return false;
430         }
431
432         unsetProperty("overwriteReadonly");
433         unsetProperty("forbidTwoStageSave");
434         try
435         {
436             VFSFile file = vfs._getFile(session,newPath,view);
437             if (file != null)
438             {
439                 boolean vfsRenameCap = (vfs.getCapabilities() & VFS.RENAME_CAP) != 0;
440                 if (!file.isWriteable())
441                 {
442                     Log.log(Log.WARNING, this, "Buffer saving : File " + file + " is readOnly");
443                     if (vfsRenameCap)
444                     {
445                         Log.log(Log.DEBUG, this, "Buffer saving : VFS can rename files");
446                         String JavaDoc savePath = vfs._canonPath(session,newPath,view);
447                         if(!MiscUtilities.isURL(savePath))
448                             savePath = MiscUtilities.resolveSymlinks(savePath);
449                         savePath = vfs.getTwoStageSaveName(savePath);
450                         if (savePath == null)
451                         {
452                             Log.log(Log.DEBUG, this, "Buffer saving : two stage save impossible because path is null");
453                             VFSManager.error(view,
454                                 newPath,
455                                 "ioerror.save-readonly-twostagefail",
456                                 null);
457                             setPerformingIO(false);
458                             return false;
459                         }
460                         else
461                         {
462                             int result = GUIUtilities.confirm(
463                                 view, "vfs.overwrite-readonly",
464                                 new Object JavaDoc[]{newPath},
465                                 JOptionPane.YES_NO_OPTION,
466                                 JOptionPane.WARNING_MESSAGE);
467                             if (result == JOptionPane.YES_OPTION)
468                             {
469                                 Log.log(Log.WARNING, this, "Buffer saving : two stage save will be used to save buffer");
470                                 setBooleanProperty("overwriteReadonly",true);
471                             }
472                             else
473                             {
474                                 Log.log(Log.DEBUG,this, "Buffer not saved");
475                                 setPerformingIO(false);
476                                 return false;
477                             }
478                         }
479                     }
480                     else
481                     {
482                         Log.log(Log.WARNING, this, "Buffer saving : file is readonly and vfs cannot do two stage save");
483                         VFSManager.error(view,
484                             newPath,
485                             "ioerror.write-error-readonly",
486                             null);
487                         setPerformingIO(false);
488                         return false;
489                     }
490                 }
491                 else
492                 {
493                     String JavaDoc savePath = vfs._canonPath(session,newPath,view);
494                     if(!MiscUtilities.isURL(savePath))
495                         savePath = MiscUtilities.resolveSymlinks(savePath);
496                     savePath = vfs.getTwoStageSaveName(savePath);
497                     if (jEdit.getBooleanProperty("twoStageSave") && (!vfsRenameCap || savePath == null))
498                     {
499                         // the file is writeable but the vfs cannot do two stage. We must overwrite
500
// readonly flag
501

502
503                         int result = GUIUtilities.confirm(
504                                 view, "vfs.twostageimpossible",
505                                 new Object JavaDoc[]{newPath},
506                                 JOptionPane.YES_NO_OPTION,
507                                 JOptionPane.WARNING_MESSAGE);
508                         if (result == JOptionPane.YES_OPTION)
509                         {
510                             Log.log(Log.WARNING, this, "Buffer saving : two stage save cannot be used");
511                             setBooleanProperty("forbidTwoStageSave",true);
512                         }
513                         else
514                         {
515                             Log.log(Log.DEBUG,this, "Buffer not saved");
516                             setPerformingIO(false);
517                             return false;
518                         }
519
520                     }
521                 }
522             }
523         }
524         catch(IOException JavaDoc io)
525         {
526             VFSManager.error(view,newPath,"ioerror",
527                 new String JavaDoc[] { io.toString() });
528             setPerformingIO(false);
529             return false;
530         }
531         finally
532         {
533             try
534             {
535                 vfs._endVFSSession(session,view);
536             }
537             catch(IOException JavaDoc io)
538             {
539                 VFSManager.error(view,newPath,"ioerror",
540                     new String JavaDoc[] { io.toString() });
541                 setPerformingIO(false);
542                 return false;
543             }
544         }
545
546         if(!vfs.save(view,this,newPath))
547         {
548             setPerformingIO(false);
549             return false;
550         }
551
552         // Once save is complete, do a few other things
553
VFSManager.runInAWTThread(new Runnable JavaDoc()
554             {
555                 public void run()
556                 {
557                     setPerformingIO(false);
558                     setProperty("overwriteReadonly",null);
559                     finishSaving(view,oldPath,oldSymlinkPath,
560                         newPath,rename,getBooleanProperty(
561                             BufferIORequest.ERROR_OCCURRED));
562                     updateMarkersFile(view);
563                 }
564             });
565
566         return true;
567     } //}}}
568

569     //{{{ checkFileStatus() method
570
public static final int FILE_NOT_CHANGED = 0;
571     public static final int FILE_CHANGED = 1;
572     public static final int FILE_DELETED = 2;
573     /**
574      * Check if the buffer has changed on disk.
575      * @return One of <code>NOT_CHANGED</code>, <code>CHANGED</code>, or
576      * <code>DELETED</code>.
577      *
578      * @since jEdit 4.2pre1
579      */

580     public int checkFileStatus(View view)
581     {
582         // - don't do these checks while a save is in progress,
583
// because for a moment newModTime will be greater than
584
// oldModTime, due to the multithreading
585
// - only supported on local file system
586
if(!isPerformingIO() && file != null && !getFlag(NEW_FILE))
587         {
588             boolean newReadOnly = (file.exists() && !file.canWrite());
589             if(newReadOnly != isFileReadOnly())
590             {
591                 setFileReadOnly(newReadOnly);
592                 EditBus.send(new BufferUpdate(this,null,
593                     BufferUpdate.DIRTY_CHANGED));
594             }
595
596             long oldModTime = modTime;
597             long newModTime = file.lastModified();
598
599             if(newModTime != oldModTime)
600             {
601                 modTime = newModTime;
602
603                 if(!file.exists())
604                 {
605                     setFlag(NEW_FILE,true);
606                     setDirty(true);
607                     return FILE_DELETED;
608                 }
609                 else
610                 {
611                     return FILE_CHANGED;
612                 }
613             }
614         }
615
616         return FILE_NOT_CHANGED;
617     } //}}}
618

619     //}}}
620

621     //{{{ Getters/setter methods for various buffer meta-data
622

623     //{{{ getLastModified() method
624
/**
625      * Returns the last time jEdit modified the file on disk.
626      * This method is thread-safe.
627      */

628     public long getLastModified()
629     {
630         return modTime;
631     } //}}}
632

633     //{{{ setLastModified() method
634
/**
635      * Sets the last time jEdit modified the file on disk.
636      * @param modTime The new modification time
637      */

638     public void setLastModified(long modTime)
639     {
640         this.modTime = modTime;
641     } //}}}
642

643     //{{{ getAutoReload() method
644
/**
645      * Returns the status of the AUTORELOAD flag
646      * If true, reload changed files automatically
647      */

648     public boolean getAutoReload()
649     {
650         return getFlag(AUTORELOAD);
651     } //}}}
652

653     //{{{ setAutoReload() method
654
/**
655      * Sets the status of the AUTORELOAD flag
656      * @param value # If true, reload changed files automatically
657      */

658     public void setAutoReload(boolean value)
659     {
660         setFlag(AUTORELOAD, value);
661     } //}}}
662

663     //{{{ getAutoReloadDialog() method
664
/**
665      * Returns the status of the AUTORELOAD_DIALOG flag
666      * If true, prompt for reloading or notify user
667      * when the file has changed on disk
668      */

669     public boolean getAutoReloadDialog()
670     {
671         return getFlag(AUTORELOAD_DIALOG);
672     } //}}}
673

674     //{{{ setAutoReloadDialog() method
675
/**
676      * Sets the status of the AUTORELOAD_DIALOG flag
677      * @param value # If true, prompt for reloading or notify user
678      * when the file has changed on disk
679
680      */

681     public void setAutoReloadDialog(boolean value)
682     {
683         setFlag(AUTORELOAD_DIALOG, value);
684     } //}}}
685

686     //{{{ getVFS() method
687
/**
688      * Returns the virtual filesystem responsible for loading and
689      * saving this buffer. This method is thread-safe.
690      */

691     public VFS getVFS()
692     {
693         return VFSManager.getVFSForPath(path);
694     } //}}}
695

696     //{{{ getAutosaveFile() method
697
/**
698      * Returns the autosave file for this buffer. This may be null if
699      * the file is non-local.
700      */

701     public File JavaDoc getAutosaveFile()
702     {
703         return autosaveFile;
704     } //}}}
705

706     //{{{ getName() method
707
/**
708      * Returns the name of this buffer. This method is thread-safe.
709      */

710     public String JavaDoc getName()
711     {
712         return name;
713     } //}}}
714

715     //{{{ getPath() method
716
/**
717      * Returns the path name of this buffer. This method is thread-safe.
718      */

719     public String JavaDoc getPath()
720     {
721         return path;
722     } //}}}
723

724     //{{{ getSymlinkPath() method
725
/**
726      * If this file is a symbolic link, returns the link destination.
727      * Otherwise returns the file's path. This method is thread-safe.
728      * @since jEdit 4.2pre1
729      */

730     public String JavaDoc getSymlinkPath()
731     {
732         return symlinkPath;
733     } //}}}
734

735     //{{{ getDirectory() method
736
/**
737      * Returns the directory containing this buffer.
738      * @since jEdit 4.1pre11
739      */

740     public String JavaDoc getDirectory()
741     {
742         return directory;
743     } //}}}
744

745     //{{{ isClosed() method
746
/**
747      * Returns true if this buffer has been closed with
748      * {@link org.gjt.sp.jedit.jEdit#closeBuffer(View,Buffer)}.
749      * This method is thread-safe.
750      */

751     public boolean isClosed()
752     {
753         return getFlag(CLOSED);
754     } //}}}
755

756     //{{{ isLoaded() method
757
/**
758      * Returns true if the buffer is loaded. This method is thread-safe.
759      */

760     public boolean isLoaded()
761     {
762         return !isLoading();
763     } //}}}
764

765     //{{{ isNewFile() method
766
/**
767      * Returns whether this buffer lacks a corresponding version on disk.
768      * This method is thread-safe.
769      */

770     public boolean isNewFile()
771     {
772         return getFlag(NEW_FILE);
773     } //}}}
774

775     //{{{ setNewFile() method
776
/**
777      * Sets the new file flag.
778      * @param newFile The new file flag
779      */

780     public void setNewFile(boolean newFile)
781     {
782         setFlag(NEW_FILE,newFile);
783         if(!newFile)
784             setFlag(UNTITLED,false);
785     } //}}}
786

787     //{{{ isUntitled() method
788
/**
789      * Returns true if this file is 'untitled'. This method is thread-safe.
790      */

791     public boolean isUntitled()
792     {
793         return getFlag(UNTITLED);
794     } //}}}
795

796     //{{{ setDirty() method
797
/**
798      * Sets the 'dirty' (changed since last save) flag of this buffer.
799      */

800     public void setDirty(boolean d)
801     {
802         boolean old_d = isDirty();
803         super.setDirty(d);
804         boolean editable = isEditable();
805
806         if(d)
807         {
808             if(editable)
809                 setFlag(AUTOSAVE_DIRTY,true);
810         }
811         else
812         {
813             setFlag(AUTOSAVE_DIRTY,false);
814
815             if(autosaveFile != null)
816                 autosaveFile.delete();
817         }
818
819         if(d != old_d && editable)
820         {
821             EditBus.send(new BufferUpdate(this,null,
822                 BufferUpdate.DIRTY_CHANGED));
823         }
824     } //}}}
825

826     //{{{ isTemporary() method
827
/**
828      * Returns if this is a temporary buffer. This method is thread-safe.
829      * @see jEdit#openTemporary(View,String,String,boolean)
830      * @see jEdit#commitTemporary(Buffer)
831      * @since jEdit 2.2pre7
832      */

833     public boolean isTemporary()
834     {
835         return getFlag(TEMPORARY);
836     } //}}}
837

838     //{{{ getIcon() method
839
/**
840      * Returns this buffer's icon.
841      * @since jEdit 2.6pre6
842      */

843     public Icon getIcon()
844     {
845         if(isDirty())
846             return GUIUtilities.loadIcon("dirty.gif");
847         else if(isReadOnly())
848             return GUIUtilities.loadIcon("readonly.gif");
849         else if(getFlag(NEW_FILE))
850             return GUIUtilities.loadIcon("new.gif");
851         else
852             return GUIUtilities.loadIcon("normal.gif");
853     } //}}}
854

855     //}}}
856

857     //{{{ Buffer events
858

859     //{{{ addBufferChangeListener() method
860
/**
861      * @deprecated Call {@link JEditBuffer#addBufferListener(BufferListener,int)}.
862      */

863     public void addBufferChangeListener(BufferChangeListener listener,
864         int priority)
865     {
866         addBufferListener(new BufferChangeListener.Adapter(listener),priority);
867     } //}}}
868

869     //{{{ addBufferChangeListener() method
870
/**
871      * @deprecated Call {@link JEditBuffer#addBufferListener(BufferListener)}.
872      */

873     public void addBufferChangeListener(BufferChangeListener listener)
874     {
875         addBufferChangeListener(listener,NORMAL_PRIORITY);
876     } //}}}
877

878     //{{{ removeBufferChangeListener() method
879
/**
880      * @deprecated Call {@link JEditBuffer#removeBufferListener(BufferListener)}.
881      */

882     public void removeBufferChangeListener(BufferChangeListener listener)
883     {
884         BufferListener[] listeners = getBufferListeners();
885
886         for(int i = 0; i < listeners.length; i++)
887         {
888             BufferListener l = listeners[i];
889             if(l instanceof BufferChangeListener.Adapter)
890             {
891                 if(((BufferChangeListener.Adapter)l).getDelegate() == listener)
892                 {
893                     removeBufferListener(l);
894                     return;
895                 }
896             }
897         }
898     } //}}}
899

900     //}}}
901

902     //{{{ Property methods
903

904     //{{{ propertiesChanged() method
905
/**
906      * Reloads settings from the properties. This should be called
907      * after the <code>syntax</code> or <code>folding</code>
908      * buffer-local properties are changed.
909      */

910     public void propertiesChanged()
911     {
912         String JavaDoc folding = getStringProperty("folding");
913         FoldHandler handler = FoldHandler.getFoldHandler(folding);
914
915         if(handler != null)
916         {
917             setFoldHandler(handler);
918         }
919         else
920         {
921             if (folding != null)
922                 Log.log(Log.WARNING, this, path + ": invalid 'folding' property: " + folding);
923             setFoldHandler(new DummyFoldHandler());
924         }
925
926         EditBus.send(new BufferUpdate(this,null,BufferUpdate.PROPERTIES_CHANGED));
927     } //}}}
928

929     //{{{ getDefaultProperty() method
930
public Object JavaDoc getDefaultProperty(String JavaDoc name)
931     {
932         Object JavaDoc retVal;
933
934         if(mode != null)
935         {
936             retVal = mode.getProperty(name);
937             if(retVal == null)
938                 return null;
939
940             setDefaultProperty(name,retVal);
941             return retVal;
942         }
943         // Now try buffer.<property>
944
String JavaDoc value = jEdit.getProperty("buffer." + name);
945         if(value == null)
946             return null;
947
948         // Try returning it as an integer first
949
try
950         {
951             retVal = new Integer JavaDoc(value);
952         }
953         catch(NumberFormatException JavaDoc nf)
954         {
955             retVal = value;
956         }
957
958         return retVal;
959     } //}}}
960

961     //{{{ toggleWordWrap() method
962
/**
963      * Toggles word wrap between the three available modes. This is used
964      * by the status bar.
965      * @param view We show a message in the view's status bar
966      * @since jEdit 4.1pre3
967      */

968     public void toggleWordWrap(View view)
969     {
970         String JavaDoc wrap = getStringProperty("wrap");
971         if(wrap.equals("none"))
972             wrap = "soft";
973         else if(wrap.equals("soft"))
974             wrap = "hard";
975         else if(wrap.equals("hard"))
976             wrap = "none";
977         view.getStatus().setMessageAndClear(jEdit.getProperty(
978             "view.status.wrap-changed",new String JavaDoc[] {
979             wrap }));
980         setProperty("wrap",wrap);
981         propertiesChanged();
982     } //}}}
983

984     //{{{ toggleLineSeparator() method
985
/**
986      * Toggles the line separator between the three available settings.
987      * This is used by the status bar.
988      * @param view We show a message in the view's status bar
989      * @since jEdit 4.1pre3
990      */

991     public void toggleLineSeparator(View view)
992     {
993         String JavaDoc status = null;
994         String JavaDoc lineSep = getStringProperty("lineSeparator");
995         if("\n".equals(lineSep))
996         {
997             status = "windows";
998             lineSep = "\r\n";
999         }
1000        else if("\r\n".equals(lineSep))
1001        {
1002            status = "mac";
1003            lineSep = "\r";
1004        }
1005        else if("\r".equals(lineSep))
1006        {
1007            status = "unix";
1008            lineSep = "\n";
1009        }
1010        view.getStatus().setMessageAndClear(jEdit.getProperty(
1011            "view.status.linesep-changed",new String JavaDoc[] {
1012            jEdit.getProperty("lineSep." + status) }));
1013        setProperty("lineSeparator",lineSep);
1014        setDirty(true);
1015        propertiesChanged();
1016    } //}}}
1017

1018    //{{{ getContextSensitiveProperty() method
1019
/**
1020     * Some settings, like comment start and end strings, can
1021     * vary between different parts of a buffer (HTML text and inline
1022     * JavaScript, for example).
1023     * @param offset The offset
1024     * @param name The property name
1025     * @since jEdit 4.0pre3
1026     */

1027    public String JavaDoc getContextSensitiveProperty(int offset, String JavaDoc name)
1028    {
1029        Object JavaDoc value = super.getContextSensitiveProperty(offset,name);
1030
1031        if(value == null)
1032        {
1033            ParserRuleSet rules = getRuleSetAtOffset(offset);
1034
1035            value = jEdit.getMode(rules.getModeName())
1036                .getProperty(name);
1037
1038            if(value == null)
1039                value = mode.getProperty(name);
1040        }
1041
1042        if(value == null)
1043            return null;
1044        else
1045            return String.valueOf(value);
1046    } //}}}
1047

1048    //}}}
1049

1050    //{{{ Edit modes, syntax highlighting
1051

1052    //{{{ getMode() method
1053
/**
1054     * Returns this buffer's edit mode. This method is thread-safe.
1055     */

1056    public Mode getMode()
1057    {
1058        return mode;
1059    } //}}}
1060

1061    //{{{ setMode() method
1062
/**
1063     * Sets this buffer's edit mode. Note that calling this before a buffer
1064     * is loaded will have no effect; in that case, set the "mode" property
1065     * to the name of the mode. A bit inelegant, I know...
1066     * @param mode The mode name
1067     * @since jEdit 4.2pre1
1068     */

1069    public void setMode(String JavaDoc mode)
1070    {
1071        setMode(jEdit.getMode(mode));
1072    } //}}}
1073

1074    //{{{ setMode() method
1075
/**
1076     * Sets this buffer's edit mode. Note that calling this before a buffer
1077     * is loaded will have no effect; in that case, set the "mode" property
1078     * to the name of the mode. A bit inelegant, I know...
1079     * @param mode The mode
1080     */

1081    public void setMode(Mode mode)
1082    {
1083        /* This protects against stupid people (like me)
1084         * doing stuff like buffer.setMode(jEdit.getMode(...)); */

1085        if(mode == null)
1086            throw new NullPointerException JavaDoc("Mode must be non-null");
1087
1088        this.mode = mode;
1089
1090        textMode = "text".equals(mode.getName());
1091
1092        setTokenMarker(mode.getTokenMarker());
1093
1094        resetCachedProperties();
1095        propertiesChanged();
1096    } //}}}
1097

1098    //{{{ setMode() method
1099
/**
1100     * Sets this buffer's edit mode by calling the accept() method
1101     * of each registered edit mode.
1102     */

1103    public void setMode()
1104    {
1105        String JavaDoc userMode = getStringProperty("mode");
1106        if(userMode != null)
1107        {
1108            Mode m = jEdit.getMode(userMode);
1109            if(m != null)
1110            {
1111                setMode(m);
1112                return;
1113            }
1114        }
1115
1116        String JavaDoc nogzName = name.substring(0,name.length() -
1117            (name.endsWith(".gz") ? 3 : 0));
1118        Mode[] modes = jEdit.getModes();
1119
1120        String JavaDoc firstLine = getLineText(0);
1121
1122        // this must be in reverse order so that modes from the user
1123
// catalog get checked first!
1124
for(int i = modes.length - 1; i >= 0; i--)
1125        {
1126            if(modes[i].accept(nogzName,firstLine))
1127            {
1128                setMode(modes[i]);
1129                return;
1130            }
1131        }
1132
1133        Mode defaultMode = jEdit.getMode(jEdit.getProperty("buffer.defaultMode"));
1134        if(defaultMode == null)
1135            defaultMode = jEdit.getMode("text");
1136        setMode(defaultMode);
1137    } //}}}
1138

1139    //}}}
1140

1141    //{{{ Deprecated methods
1142

1143    //{{{ putProperty() method
1144
/**
1145     * @deprecated Call <code>setProperty()</code> instead.
1146     */

1147    public void putProperty(Object JavaDoc name, Object JavaDoc value)
1148    {
1149        // for backwards compatibility
1150
if(!(name instanceof String JavaDoc))
1151            return;
1152
1153        setProperty((String JavaDoc)name,value);
1154    } //}}}
1155

1156    //{{{ putBooleanProperty() method
1157
/**
1158     * @deprecated Call <code>setBooleanProperty()</code> instead
1159     */

1160    public void putBooleanProperty(String JavaDoc name, boolean value)
1161    {
1162        setBooleanProperty(name,value);
1163    } //}}}
1164

1165    //{{{ markTokens() method
1166
/**
1167     * @deprecated Use org.gjt.sp.jedit.syntax.DefaultTokenHandler instead
1168     */

1169    public static class TokenList extends DefaultTokenHandler
1170    {
1171        public Token getFirstToken()
1172        {
1173            return getTokens();
1174        }
1175    }
1176
1177    /**
1178     * @deprecated Use the other form of <code>markTokens()</code> instead
1179     */

1180    public TokenList markTokens(int lineIndex)
1181    {
1182        TokenList list = new TokenList();
1183        markTokens(lineIndex,list);
1184        return list;
1185    } //}}}
1186

1187    //{{{ insertString() method
1188
/**
1189     * @deprecated Call <code>insert()</code> instead.
1190     */

1191    public void insertString(int offset, String JavaDoc str, AttributeSet attr)
1192    {
1193        insert(offset,str);
1194    } //}}}
1195

1196    //{{{ getFile() method
1197
/**
1198     * @deprecated Do not call this method, use {@link #getPath()}
1199     * instead.
1200     */

1201    public File JavaDoc getFile()
1202    {
1203        return file;
1204    } //}}}
1205

1206    //}}}
1207

1208    //{{{ Marker methods
1209

1210    //{{{ getMarkers() method
1211
/**
1212     * Returns a vector of markers.
1213     * @since jEdit 3.2pre1
1214     */

1215    public Vector<Marker> getMarkers()
1216    {
1217        return markers;
1218    } //}}}
1219

1220    //{{{ getMarkerStatusPrompt() method
1221
/**
1222     * Returns the status prompt for the given marker action. Only
1223     * intended to be called from <code>actions.xml</code>.
1224     * @since jEdit 4.2pre2
1225     */

1226    public String JavaDoc getMarkerStatusPrompt(String JavaDoc action)
1227    {
1228        return jEdit.getProperty("view.status." + action,
1229            new String JavaDoc[] { getMarkerNameString() });
1230    } //}}}
1231

1232    //{{{ getMarkerNameString() method
1233
/**
1234     * Returns a string of all set markers, used by the status bar
1235     * (eg, "a b $ % ^").
1236     * @since jEdit 4.2pre2
1237     */

1238    public String JavaDoc getMarkerNameString()
1239    {
1240        StringBuilder JavaDoc buf = new StringBuilder JavaDoc();
1241        for(int i = 0; i < markers.size(); i++)
1242        {
1243            Marker marker = markers.get(i);
1244            if(marker.getShortcut() != '\0')
1245            {
1246                if(buf.length() != 0)
1247                    buf.append(' ');
1248                buf.append(marker.getShortcut());
1249            }
1250        }
1251
1252        if(buf.length() == 0)
1253            return jEdit.getProperty("view.status.no-markers");
1254        else
1255            return buf.toString();
1256    } //}}}
1257

1258    //{{{ addOrRemoveMarker() method
1259
/**
1260     * If a marker is set on the line of the position, it is removed. Otherwise
1261     * a new marker with the specified shortcut is added.
1262     * @param pos The position of the marker
1263     * @param shortcut The shortcut ('\0' if none)
1264     * @since jEdit 3.2pre5
1265     */

1266    public void addOrRemoveMarker(char shortcut, int pos)
1267    {
1268        int line = getLineOfOffset(pos);
1269        if(getMarkerAtLine(line) != null)
1270            removeMarker(line);
1271        else
1272            addMarker(shortcut,pos);
1273    } //}}}
1274

1275    //{{{ addMarker() method
1276
/**
1277     * Adds a marker to this buffer.
1278     * @param pos The position of the marker
1279     * @param shortcut The shortcut ('\0' if none)
1280     * @since jEdit 3.2pre1
1281     */

1282    public void addMarker(char shortcut, int pos)
1283    {
1284        Marker markerN = new Marker(this,shortcut,pos);
1285        boolean added = false;
1286
1287        // don't sort markers while buffer is being loaded
1288
if(isLoaded())
1289        {
1290            setFlag(MARKERS_CHANGED,true);
1291
1292            markerN.createPosition();
1293
1294            for(int i = 0; i < markers.size(); i++)
1295            {
1296                Marker marker = markers.get(i);
1297                if(shortcut != '\0' && marker.getShortcut() == shortcut)
1298                    marker.setShortcut('\0');
1299
1300                if(marker.getPosition() == pos)
1301                {
1302                    markers.removeElementAt(i);
1303                    i--;
1304                }
1305            }
1306
1307            for(int i = 0; i < markers.size(); i++)
1308            {
1309                Marker marker = markers.get(i);
1310                if(marker.getPosition() > pos)
1311                {
1312                    markers.insertElementAt(markerN,i);
1313                    added = true;
1314                    break;
1315                }
1316            }
1317        }
1318
1319        if(!added)
1320            markers.addElement(markerN);
1321
1322        if(isLoaded() && !getFlag(TEMPORARY))
1323        {
1324            EditBus.send(new BufferUpdate(this,null,
1325                BufferUpdate.MARKERS_CHANGED));
1326        }
1327    } //}}}
1328

1329    //{{{ getMarkerInRange() method
1330
/**
1331     * Returns the first marker within the specified range.
1332     * @param start The start offset
1333     * @param end The end offset
1334     * @since jEdit 4.0pre4
1335     */

1336    public Marker getMarkerInRange(int start, int end)
1337    {
1338        for(int i = 0; i < markers.size(); i++)
1339        {
1340            Marker marker = markers.get(i);
1341            int pos = marker.getPosition();
1342            if(pos >= start && pos < end)
1343                return marker;
1344        }
1345
1346        return null;
1347    } //}}}
1348

1349    //{{{ getMarkerAtLine() method
1350
/**
1351     * Returns the first marker at the specified line, or <code>null</code>
1352     * if there is none.
1353     * @param line The line number
1354     * @since jEdit 3.2pre2
1355     */

1356    public Marker getMarkerAtLine(int line)
1357    {
1358        for(int i = 0; i < markers.size(); i++)
1359        {
1360            Marker marker = markers.get(i);
1361            if(getLineOfOffset(marker.getPosition()) == line)
1362                return marker;
1363        }
1364
1365        return null;
1366    } //}}}
1367

1368    //{{{ removeMarker() method
1369
/**
1370     * Removes all markers at the specified line.
1371     * @param line The line number
1372     * @since jEdit 3.2pre2
1373     */

1374    public void removeMarker(int line)
1375    {
1376        for(int i = 0; i < markers.size(); i++)
1377        {
1378            Marker marker = markers.get(i);
1379            if(getLineOfOffset(marker.getPosition()) == line)
1380            {
1381                setFlag(MARKERS_CHANGED,true);
1382                marker.removePosition();
1383                markers.removeElementAt(i);
1384                i--;
1385            }
1386        }
1387
1388        EditBus.send(new BufferUpdate(this,null,
1389            BufferUpdate.MARKERS_CHANGED));
1390    } //}}}
1391

1392    //{{{ removeAllMarkers() method
1393
/**
1394     * Removes all defined markers.
1395     * @since jEdit 2.6pre1
1396     */

1397    public void removeAllMarkers()
1398    {
1399        setFlag(MARKERS_CHANGED,true);
1400
1401        for(int i = 0; i < markers.size(); i++)
1402            markers.get(i).removePosition();
1403
1404        markers.removeAllElements();
1405
1406        if(isLoaded())
1407        {
1408            EditBus.send(new BufferUpdate(this,null,
1409                BufferUpdate.MARKERS_CHANGED));
1410        }
1411    } //}}}
1412

1413    //{{{ getMarker() method
1414
/**
1415     * Returns the marker with the specified shortcut.
1416     * @param shortcut The shortcut
1417     * @since jEdit 3.2pre2
1418     */

1419    public Marker getMarker(char shortcut)
1420    {
1421        Enumeration<Marker> e = markers.elements();
1422        while(e.hasMoreElements())
1423        {
1424            Marker marker = e.nextElement();
1425            if(marker.getShortcut() == shortcut)
1426                return marker;
1427        }
1428        return null;
1429    } //}}}
1430

1431    //{{{ getMarkersPath() method
1432
/**
1433     * Returns the path for this buffer's markers file
1434     * @param vfs The appropriate VFS
1435     * @since jEdit 4.3pre7
1436     */

1437    public String JavaDoc getMarkersPath(VFS vfs)
1438    {
1439        return vfs.getParentOfPath(path)
1440            + '.' + vfs.getFileName(path)
1441            + ".marks";
1442    } //}}}
1443

1444    //{{{ updateMarkersFile() method
1445
/**
1446     * Save the markers file, or delete it when there are mo markers left
1447     * Handling markers is now independent from saving the buffer.
1448     * Changing markers will not set the buffer dirty any longer.
1449     * @param view The current view
1450     * @since jEdit 4.3pre7
1451     */

1452    public boolean updateMarkersFile(View view)
1453    {
1454        if(!markersChanged())
1455            return true;
1456        // adapted from VFS.save
1457
VFS vfs = VFSManager.getVFSForPath(getPath());
1458        if ((vfs.getCapabilities() & VFS.WRITE_CAP) == 0) {
1459            VFSManager.error(view, path, "vfs.not-supported.save",
1460                new String JavaDoc[] { "markers file" });
1461            return false;
1462            }
1463        Object JavaDoc session = vfs.createVFSSession(path, view);
1464        if(session == null)
1465            return false;
1466        VFSManager.runInWorkThread(
1467            new MarkersSaveRequest(
1468                view, this, session, vfs, path));
1469        return true;
1470    } //}}}
1471

1472    //{{{ markersChanged() method
1473
/**
1474     * Return true when markers have changed and the markers file needs
1475     * to be updated
1476     * @since jEdit 4.3pre7
1477     */

1478    public boolean markersChanged()
1479    {
1480        return getFlag(MARKERS_CHANGED);
1481    } //}}}
1482

1483    //{{{ setMarkersChanged() method
1484
/**
1485     * Sets/unsets the MARKERS_CHANGED flag
1486     * @since jEdit 4.3pre7
1487     */

1488    public void setMarkersChanged(boolean changed)
1489    {
1490        setFlag(MARKERS_CHANGED, changed);
1491    } //}}}
1492

1493    //}}}
1494

1495    //{{{ Miscellaneous methods
1496

1497    //{{{ setWaitSocket() method
1498
/**
1499     * This socket is closed when the buffer is closed.
1500     */

1501    public void setWaitSocket(Socket JavaDoc waitSocket)
1502    {
1503        this.waitSocket = waitSocket;
1504    } //}}}
1505

1506    //{{{ getNext() method
1507
/**
1508     * Returns the next buffer in the list.
1509     */

1510    public Buffer getNext()
1511    {
1512        return next;
1513    } //}}}
1514

1515    //{{{ getPrev() method
1516
/**
1517     * Returns the previous buffer in the list.
1518     */

1519    public Buffer getPrev()
1520    {
1521        return prev;
1522    } //}}}
1523

1524    //{{{ getIndex() method
1525
/**
1526     * Returns the position of this buffer in the buffer list.
1527     */

1528    public int getIndex()
1529    {
1530        int count = 0;
1531        Buffer buffer = prev;
1532        while (true)
1533        {
1534            if(buffer == null)
1535                break;
1536            count++;
1537            buffer = buffer.prev;
1538        }
1539        return count;
1540    } //}}}
1541

1542    //{{{ toString() method
1543
/**
1544     * Returns a string representation of this buffer.
1545     * This simply returns the path name.
1546     */

1547    public String JavaDoc toString()
1548    {
1549        return name + " (" + directory + ')';
1550    } //}}}
1551

1552    //}}}
1553

1554    //{{{ Package-private members
1555
/** The previous buffer in the list. */
1556    Buffer prev;
1557    /** The next buffer in the list. */
1558    Buffer next;
1559
1560    //{{{ Buffer constructor
1561
Buffer(String JavaDoc path, boolean newFile, boolean temp, Hashtable props)
1562    {
1563        super(props);
1564
1565        markers = new Vector<Marker>();
1566
1567        setFlag(TEMPORARY,temp);
1568
1569        // this must be called before any EditBus messages are sent
1570
setPath(path);
1571
1572        /* Magic: UNTITLED is only set if newFile param to
1573         * constructor is set, NEW_FILE is also set if file
1574         * doesn't exist on disk.
1575         *
1576         * This is so that we can tell apart files created
1577         * with jEdit.newFile(), and those that just don't
1578         * exist on disk.
1579         *
1580         * Why do we need to tell the difference between the
1581         * two? jEdit.addBufferToList() checks if the only
1582         * opened buffer is an untitled buffer, and if so,
1583         * replaces it with the buffer to add. We don't want
1584         * this behavior to occur with files that don't
1585         * exist on disk; only untitled ones.
1586         */

1587        setFlag(UNTITLED,newFile);
1588        setFlag(NEW_FILE,newFile);
1589        setFlag(AUTORELOAD,jEdit.getBooleanProperty("autoReload"));
1590        setFlag(AUTORELOAD_DIALOG,jEdit.getBooleanProperty("autoReloadDialog"));
1591    } //}}}
1592

1593    //{{{ commitTemporary() method
1594
void commitTemporary()
1595    {
1596        setFlag(TEMPORARY,false);
1597
1598        finishLoading();
1599    } //}}}
1600

1601    //{{{ close() method
1602
void close()
1603    {
1604        setFlag(CLOSED,true);
1605
1606        if(autosaveFile != null)
1607            autosaveFile.delete();
1608
1609        // notify clients with -wait
1610
if(waitSocket != null)
1611        {
1612            try
1613            {
1614                waitSocket.getOutputStream().write('\0');
1615                waitSocket.getOutputStream().flush();
1616                waitSocket.getInputStream().close();
1617                waitSocket.getOutputStream().close();
1618                waitSocket.close();
1619            }
1620            catch(IOException JavaDoc io)
1621            {
1622                //Log.log(Log.ERROR,this,io);
1623
}
1624        }
1625    } //}}}
1626

1627    //}}}
1628

1629    //{{{ Private members
1630

1631    //{{{ Flags
1632

1633    //{{{ setFlag() method
1634
private void setFlag(int flag, boolean value)
1635    {
1636        if(value)
1637            flags |= (1 << flag);
1638        else
1639            flags &= ~(1 << flag);
1640    } //}}}
1641

1642    //{{{ getFlag() method
1643
private boolean getFlag(int flag)
1644    {
1645        int mask = (1 << flag);
1646        return (flags & mask) == mask;
1647    } //}}}
1648

1649    //{{{ Flag values
1650
private static final int CLOSED = 0;
1651    private static final int NEW_FILE = 3;
1652    private static final int UNTITLED = 4;
1653    private static final int AUTOSAVE_DIRTY = 5;
1654    private static final int AUTORELOAD = 6;
1655    private static final int AUTORELOAD_DIALOG = 7;
1656    private static final int TEMPORARY = 10;
1657    private static final int MARKERS_CHANGED = 12;
1658    //}}}
1659

1660    private int flags;
1661
1662    //}}}
1663

1664    //{{{ Instance variables
1665
private String JavaDoc path;
1666    private String JavaDoc symlinkPath;
1667    private String JavaDoc name;
1668    private String JavaDoc directory;
1669    private File JavaDoc file;
1670    private File JavaDoc autosaveFile;
1671    private long modTime;
1672    private Mode mode;
1673
1674    private final Vector<Marker> markers;
1675
1676    private Socket JavaDoc waitSocket;
1677    //}}}
1678

1679    //{{{ setPath() method
1680
private void setPath(String JavaDoc path)
1681    {
1682        View[] views = jEdit.getViews();
1683        for (int i = 0; i < views.length; i++)
1684        {
1685            View view = views[i];
1686            EditPane[] editPanes = view.getEditPanes();
1687            for (int j = 0; j < editPanes.length; j++)
1688                editPanes[j].bufferRenamed(this.path, path);
1689        }
1690
1691        this.path = path;
1692        VFS vfs = VFSManager.getVFSForPath(path);
1693        if((vfs.getCapabilities() & VFS.WRITE_CAP) == 0)
1694            setFileReadOnly(true);
1695        name = vfs.getFileName(path);
1696        directory = vfs.getParentOfPath(path);
1697
1698        if(vfs instanceof FileVFS)
1699        {
1700            file = new File JavaDoc(path);
1701            symlinkPath = MiscUtilities.resolveSymlinks(path);
1702
1703            // if we don't do this, the autosave file won't be
1704
// deleted after a save as
1705
if(autosaveFile != null)
1706                autosaveFile.delete();
1707            autosaveFile = new File JavaDoc(file.getParent(),'#' + name + '#');
1708        }
1709        else
1710        {
1711            // I wonder if the lack of this broke anything in the
1712
// past?
1713
file = null;
1714            autosaveFile = null;
1715            symlinkPath = path;
1716        }
1717    } //}}}
1718

1719    //{{{ recoverAutosave() method
1720
private boolean recoverAutosave(final View view)
1721    {
1722        if(!autosaveFile.canRead())
1723            return false;
1724
1725        // this method might get called at startup
1726
GUIUtilities.hideSplashScreen();
1727
1728        final Object JavaDoc[] args = { autosaveFile.getPath() };
1729        int result = GUIUtilities.confirm(view,"autosave-found",args,
1730            JOptionPane.YES_NO_OPTION,JOptionPane.WARNING_MESSAGE);
1731
1732        if(result == JOptionPane.YES_OPTION)
1733        {
1734            VFSManager.getFileVFS().load(view,this,autosaveFile.getPath());
1735
1736            // show this message when all I/O requests are
1737
// complete
1738
VFSManager.runInAWTThread(new Runnable JavaDoc()
1739            {
1740                public void run()
1741                {
1742                    GUIUtilities.message(view,"autosave-loaded",args);
1743                }
1744            });
1745
1746            return true;
1747        }
1748        else
1749            return false;
1750    } //}}}
1751

1752    //{{{ checkFileForLoad() method
1753
private boolean checkFileForLoad(View view, VFS vfs, String JavaDoc path)
1754    {
1755        if((vfs.getCapabilities() & VFS.LOW_LATENCY_CAP) != 0)
1756        {
1757            Object JavaDoc session = vfs.createVFSSession(path,view);
1758            if(session == null)
1759                return false;
1760
1761            try
1762            {
1763                VFSFile file = vfs._getFile(session,path,view);
1764                if(file == null)
1765                {
1766                    setNewFile(true);
1767                    return true;
1768                }
1769
1770                if(!file.isReadable())
1771                {
1772                    VFSManager.error(view,path,"ioerror.no-read",null);
1773                    setNewFile(false);
1774                    return false;
1775                }
1776
1777                setFileReadOnly(!file.isWriteable());
1778
1779                if(file.getType() != VFSFile.FILE)
1780                {
1781                    VFSManager.error(view,path,
1782                        "ioerror.open-directory",null);
1783                    setNewFile(false);
1784                    return false;
1785                }
1786            }
1787            catch(IOException JavaDoc io)
1788            {
1789                VFSManager.error(view,path,"ioerror",
1790                    new String JavaDoc[] { io.toString() });
1791                return false;
1792            }
1793            finally
1794            {
1795                try
1796                {
1797                    vfs._endVFSSession(session,view);
1798                }
1799                catch(IOException JavaDoc io)
1800                {
1801                    VFSManager.error(view,path,"ioerror",
1802                        new String JavaDoc[] { io.toString() });
1803                    return false;
1804                }
1805            }
1806        }
1807
1808        return true;
1809    } //}}}
1810

1811    //{{{ checkFileForSave() method
1812
private static boolean checkFileForSave(View view, VFS vfs, String JavaDoc path)
1813    {
1814        if((vfs.getCapabilities() & VFS.LOW_LATENCY_CAP) != 0)
1815        {
1816            Object JavaDoc session = vfs.createVFSSession(path,view);
1817            if(session == null)
1818                return false;
1819
1820            try
1821            {
1822                VFSFile file = vfs._getFile(session,path,view);
1823                if(file == null)
1824                    return true;
1825
1826                if(file.getType() != VFSFile.FILE)
1827                {
1828                    VFSManager.error(view,path,
1829                        "ioerror.save-directory",null);
1830                    return false;
1831                }
1832            }
1833            catch(IOException JavaDoc io)
1834            {
1835                VFSManager.error(view,path,"ioerror",
1836                    new String JavaDoc[] { io.toString() });
1837                return false;
1838            }
1839            finally
1840            {
1841                try
1842                {
1843                    vfs._endVFSSession(session,view);
1844                }
1845                catch(IOException JavaDoc io)
1846                {
1847                    VFSManager.error(view,path,"ioerror",
1848                        new String JavaDoc[] { io.toString() });
1849                    return false;
1850                }
1851            }
1852        }
1853
1854        return true;
1855    } //}}}
1856

1857    //{{{ finishLoading() method
1858
private void finishLoading()
1859    {
1860        parseBufferLocalProperties();
1861        // AHA!
1862
// this is probably the only way to fix this
1863
FoldHandler oldFoldHandler = getFoldHandler();
1864        setMode();
1865
1866        if(getFoldHandler() == oldFoldHandler)
1867        {
1868            // on a reload, the fold handler doesn't change, but
1869
// we still need to re-collapse folds.
1870
// don't do this on initial fold handler creation
1871
invalidateFoldLevels();
1872
1873            fireFoldHandlerChanged();
1874        }
1875
1876        // Create marker positions
1877
for(int i = 0; i < markers.size(); i++)
1878        {
1879            Marker marker = markers.get(i);
1880            marker.removePosition();
1881            int pos = marker.getPosition();
1882            if(pos > getLength())
1883                marker.setPosition(getLength());
1884            else if(pos < 0)
1885                marker.setPosition(0);
1886            marker.createPosition();
1887        }
1888    } //}}}
1889

1890    //{{{ finishSaving() method
1891
private void finishSaving(View view, String JavaDoc oldPath,
1892        String JavaDoc oldSymlinkPath, String JavaDoc path,
1893        boolean rename, boolean error)
1894    {
1895        //{{{ Set the buffer's path
1896
// Caveat: won't work if save() called with a relative path.
1897
// But I don't think anyone calls it like that anyway.
1898
if(!error && !path.equals(oldPath))
1899        {
1900            Buffer buffer = jEdit.getBuffer(path);
1901
1902            if(rename)
1903            {
1904                /* if we save a file with the same name as one
1905                 * that's already open, we presume that we can
1906                 * close the existing file, since the user
1907                 * would have confirmed the overwrite in the
1908                 * 'save as' dialog box anyway */

1909                if(buffer != null && /* can't happen? */
1910                    !buffer.getPath().equals(oldPath))
1911                {
1912                    buffer.setDirty(false);
1913                    jEdit.closeBuffer(view,buffer);
1914                }
1915
1916                setPath(path);
1917            }
1918            else
1919            {
1920                /* if we saved over an already open file using
1921                 * 'save a copy as', then reload the existing
1922                 * buffer */

1923                if(buffer != null && /* can't happen? */
1924                    !buffer.getPath().equals(oldPath))
1925                {
1926                    buffer.load(view,true);
1927                }
1928            }
1929        } //}}}
1930

1931        //{{{ Update this buffer for the new path
1932
if(rename)
1933        {
1934            if(file != null)
1935                modTime = file.lastModified();
1936
1937            if(!error)
1938            {
1939                // we do a write lock so that the
1940
// autosave, which grabs a read lock,
1941
// is not executed between the
1942
// deletion of the autosave file
1943
// and clearing of the dirty flag
1944
try
1945                {
1946                    writeLock();
1947
1948                    if(autosaveFile != null)
1949                        autosaveFile.delete();
1950
1951                    setFlag(AUTOSAVE_DIRTY,false);
1952                    setFileReadOnly(false);
1953                    setFlag(NEW_FILE,false);
1954                    setFlag(UNTITLED,false);
1955                    super.setDirty(false);
1956
1957                    // this ensures that undo can clear
1958
// the dirty flag properly when all
1959
// edits up to a save are undone
1960
undoMgr.bufferSaved();
1961                }
1962                finally
1963                {
1964                    writeUnlock();
1965                }
1966
1967                parseBufferLocalProperties();
1968
1969                if(!getPath().equals(oldPath))
1970                {
1971                    jEdit.updatePosition(oldSymlinkPath,this);
1972                    setMode();
1973                }
1974                else
1975                {
1976                    // if user adds mode buffer-local property
1977
String JavaDoc newMode = getStringProperty("mode");
1978                    if(newMode != null &&
1979                        !newMode.equals(getMode()
1980                        .getName()))
1981                        setMode();
1982                    else
1983                        propertiesChanged();
1984                }
1985
1986                EditBus.send(new BufferUpdate(this,
1987                    view,BufferUpdate.DIRTY_CHANGED));
1988
1989                // new message type introduced in 4.0pre4
1990
EditBus.send(new BufferUpdate(this,
1991                    view,BufferUpdate.SAVED));
1992            }
1993        } //}}}
1994
} //}}}
1995

1996    //}}}
1997
}
1998
Popular Tags