Source Code Cross Referenced for Buffer.java in  » IDE » J » org » armedbear » j » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE » J » org.armedbear.j 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Buffer.java
0003:         *
0004:         * Copyright (C) 1998-2003 Peter Graves
0005:         * $Id: Buffer.java,v 1.52 2004/08/30 17:13:48 piso Exp $
0006:         *
0007:         * This program is free software; you can redistribute it and/or
0008:         * modify it under the terms of the GNU General Public License
0009:         * as published by the Free Software Foundation; either version 2
0010:         * of the License, or (at your option) any later version.
0011:         *
0012:         * This program is distributed in the hope that it will be useful,
0013:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0015:         * GNU General Public License for more details.
0016:         *
0017:         * You should have received a copy of the GNU General Public License
0018:         * along with this program; if not, write to the Free Software
0019:         * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
0020:         */
0021:
0022:        package org.armedbear.j;
0023:
0024:        import java.awt.Cursor;
0025:        import java.io.BufferedInputStream;
0026:        import java.io.BufferedOutputStream;
0027:        import java.io.BufferedReader;
0028:        import java.io.IOException;
0029:        import java.io.InputStream;
0030:        import java.io.InputStreamReader;
0031:        import java.io.OutputStream;
0032:        import java.lang.ref.SoftReference;
0033:        import java.util.ArrayList;
0034:        import java.util.Iterator;
0035:        import java.util.List;
0036:        import java.util.zip.GZIPInputStream;
0037:        import java.util.zip.GZIPOutputStream;
0038:        import java.util.zip.ZipEntry;
0039:        import javax.swing.Icon;
0040:        import javax.swing.SwingUtilities;
0041:        import javax.swing.undo.CannotRedoException;
0042:        import javax.swing.undo.CannotUndoException;
0043:        import javax.swing.undo.CompoundEdit;
0044:        import javax.swing.undo.UndoableEdit;
0045:
0046:        public class Buffer extends SystemBuffer {
0047:            private static int untitledCount;
0048:
0049:            protected boolean isUntitled;
0050:
0051:            protected Formatter formatter;
0052:
0053:            protected String title;
0054:
0055:            private boolean needsParsing;
0056:
0057:            boolean needsRenumbering;
0058:
0059:            public final boolean needsRenumbering() {
0060:                return needsRenumbering;
0061:            }
0062:
0063:            public final void needsRenumbering(boolean b) {
0064:                needsRenumbering = b;
0065:            }
0066:
0067:            private int visibleLineCount;
0068:
0069:            protected boolean supportsUndo = true;
0070:
0071:            public final boolean supportsUndo() {
0072:                return supportsUndo;
0073:            }
0074:
0075:            private int modCount;
0076:            private int saveModCount; // Value of modCount when last saved.
0077:
0078:            // Autosave.
0079:            protected boolean autosaveEnabled;
0080:            private File autosaveFile;
0081:            private int autosaveModCount; // Value of modCount when last autosaved.
0082:
0083:            private File cache;
0084:            private String listing;
0085:
0086:            public final String getListing() {
0087:                return listing;
0088:            }
0089:
0090:            public final void setListing(String s) {
0091:                this .listing = s;
0092:            }
0093:
0094:            private View lastView;
0095:
0096:            private boolean backedUp = false; // Ignored for local buffers.
0097:
0098:            private int fileType = FILETYPE_UNKNOWN;
0099:
0100:            private Compression compression;
0101:
0102:            public final Compression getCompression() {
0103:                return compression;
0104:            }
0105:
0106:            public final void setCompression(Compression compression) {
0107:                this .compression = compression;
0108:            }
0109:
0110:            protected PropertyList properties = new PropertyList();
0111:
0112:            private BackgroundProcess backgroundProcess;
0113:
0114:            private Mutex mutex = new Mutex();
0115:            private final ReadWriteLock rwlock = new ReadWriteLock();
0116:
0117:            private boolean isNewFile;
0118:
0119:            protected Buffer parentBuffer;
0120:
0121:            public final Buffer getParentBuffer() {
0122:                return parentBuffer;
0123:            }
0124:
0125:            public final void setParentBuffer(Buffer b) {
0126:                this .parentBuffer = b;
0127:            }
0128:
0129:            public boolean isPrimary() {
0130:                return true;
0131:            }
0132:
0133:            public boolean isSecondary() {
0134:                return false;
0135:            }
0136:
0137:            public boolean isPaired() {
0138:                return isSecondary() || getSecondary() != null;
0139:            }
0140:
0141:            public Buffer getPrimary() {
0142:                return null;
0143:            }
0144:
0145:            public Buffer getSecondary() {
0146:                return null;
0147:            }
0148:
0149:            public float getSplit() {
0150:                return 0.5F;
0151:            }
0152:
0153:            public void promote() {
0154:            }
0155:
0156:            public final boolean isNewFile() {
0157:                return isNewFile;
0158:            }
0159:
0160:            private final void setNewFile(boolean b) {
0161:                isNewFile = b;
0162:            }
0163:
0164:            protected Buffer() {
0165:                // Add new buffer to global buffer list.
0166:                Editor.getBufferList().add(this );
0167:            }
0168:
0169:            // Called only by Editor.newBuffer().
0170:            public Buffer(int i /*ignored*/) {
0171:                this ();
0172:                Debug.assertTrue(Editor.getBufferList().contains(this ));
0173:                initializeUndo();
0174:                type = TYPE_NORMAL;
0175:                isUntitled = true;
0176:                ++untitledCount;
0177:                String name = "Untitled-" + untitledCount;
0178:                File directory = Editor.currentEditor().getCurrentDirectory();
0179:                if (directory == null || directory.isRemote())
0180:                    directory = Directories.getUserHomeDirectory();
0181:                setFile(File.getInstance(directory, name));
0182:                autosaveEnabled = true;
0183:                lineSeparator = System.getProperty("line.separator");
0184:                mode = PlainTextMode.getMode();
0185:                formatter = mode.getFormatter(this );
0186:                setNewFile(true);
0187:                try {
0188:                    lockWrite();
0189:                } catch (InterruptedException e) {
0190:                    Log.debug(e);
0191:                    return; // Shouldn't happen.
0192:                }
0193:                try {
0194:                    appendLine("");
0195:                    renumber();
0196:                    setLoaded(true);
0197:                } finally {
0198:                    unlockWrite();
0199:                }
0200:            }
0201:
0202:            public Buffer(File file) {
0203:                this ();
0204:                Debug.assertTrue(Editor.getBufferList().contains(this ));
0205:                initializeUndo();
0206:                setFile(file);
0207:                type = TYPE_NORMAL;
0208:                autosaveEnabled = true;
0209:            }
0210:
0211:            public static Buffer createBuffer(File file) {
0212:                if (file instanceof  FtpFile) {
0213:                    FtpSession session = FtpSession.getSession((FtpFile) file);
0214:                    if (session == null)
0215:                        return null;
0216:                    return new RemoteBuffer((FtpFile) file, session);
0217:                }
0218:                if (file instanceof  HttpFile) {
0219:                    if (Editor.getModeList().modeAccepts(IMAGE_MODE,
0220:                            file.getName()))
0221:                        return new RemoteBuffer(file);
0222:                    if (Editor.preferences().getBooleanProperty(
0223:                            Property.ENABLE_WEB)) {
0224:                        int modeId = Editor.getModeList().getModeIdForFileName(
0225:                                file.getName());
0226:                        if (modeId < 0 || modeId == HTML_MODE)
0227:                            return WebBuffer.createWebBuffer(file, null, null);
0228:                    }
0229:                    return new RemoteBuffer(file);
0230:                }
0231:                if (file instanceof  SshFile) {
0232:                    SshFile sshFile = (SshFile) file;
0233:                    SshSession session = SshSession.getSession(sshFile);
0234:                    if (session == null)
0235:                        return null;
0236:                    if (!session.isLocked()) {
0237:                        Debug.bug();
0238:                        return null;
0239:                    }
0240:                    session.checkLogin();
0241:                    if (sshFile.getUserName() == null) {
0242:                        Debug.bug();
0243:                        sshFile.setUserName(session.getUserName());
0244:                    }
0245:                    if (!sshFile.getUserName().equals(session.getUserName())) {
0246:                        Debug.bug();
0247:                        session.unlock();
0248:                        return null;
0249:                    }
0250:                    session.unlock();
0251:                    return new RemoteBuffer(file);
0252:                }
0253:                // Special case for unsent messages.
0254:                File dir = file.getParentFile();
0255:                if (dir != null && dir.equals(Directories.getDraftsFolder())) {
0256:                    Mode sendMailMode = Editor.getModeList().getMode(
0257:                            SEND_MAIL_MODE);
0258:                    if (sendMailMode != null)
0259:                        return sendMailMode.createBuffer(file);
0260:                }
0261:                // Local file.
0262:                return createBuffer(file, null, null);
0263:            }
0264:
0265:            protected static Buffer createBuffer(File file, File cache,
0266:                    String listing) {
0267:                Compression compression = null;
0268:                int fileType = Utilities.getFileType(cache != null ? cache
0269:                        : file);
0270:                if (fileType == FILETYPE_GZIP) {
0271:                    // If we're looking at a remote file, gunzip the cached copy
0272:                    // of it; otherwise, gunzip the file itself into the cache.
0273:                    File uncompressed = cacheGZIP(cache != null ? cache : file);
0274:                    if (uncompressed != null) {
0275:                        cache = uncompressed;
0276:                        fileType = Utilities.getFileType(cache);
0277:                        compression = new Compression(COMPRESSION_GZIP);
0278:                    } else
0279:                        fileType = FILETYPE_BINARY; // Something went wrong.
0280:                }
0281:                if (fileType == FILETYPE_JPEG
0282:                        || Editor.getModeList().modeAccepts(IMAGE_MODE,
0283:                                file.getName())) {
0284:                    Buffer buffer = ImageBuffer.createImageBuffer(file, cache,
0285:                            listing);
0286:                    if (buffer != null) {
0287:                        buffer.setFileType(fileType);
0288:                        return buffer;
0289:                    }
0290:                }
0291:                // Normal case.
0292:                Buffer buffer = new Buffer(file);
0293:                Debug.assertTrue(Editor.getBufferList().contains(buffer));
0294:                buffer.setFileType(fileType);
0295:                buffer.setCache(cache);
0296:                buffer.setListing(listing);
0297:                buffer.setCompression(compression);
0298:                if (file.isLocal() && !file.isFile())
0299:                    buffer.setNewFile(true);
0300:                return buffer;
0301:            }
0302:
0303:            // For Session.createBuffers().
0304:            public static Buffer precreateBuffer(File file) {
0305:                if (file == null) {
0306:                    Debug.bug();
0307:                    return null;
0308:                }
0309:                if (file.isRemote()) {
0310:                    Debug.bug();
0311:                    return null;
0312:                }
0313:                // Special case for unsent messages.
0314:                File dir = file.getParentFile();
0315:                if (dir != null && dir.equals(Directories.getDraftsFolder())) {
0316:                    Mode sendMailMode = Editor.getModeList().getMode(
0317:                            SEND_MAIL_MODE);
0318:                    if (sendMailMode != null)
0319:                        return sendMailMode.createBuffer(file);
0320:                }
0321:                // Normal case.
0322:                return new Buffer(file);
0323:            }
0324:
0325:            private boolean initialized;
0326:
0327:            public synchronized boolean initialized() {
0328:                return initialized;
0329:            }
0330:
0331:            public synchronized void setInitialized(boolean b) {
0332:                initialized = b;
0333:            }
0334:
0335:            public synchronized void initialize() {
0336:                Debug.assertTrue(!initialized);
0337:                final File file = getFile();
0338:                if (fileType == FILETYPE_UNKNOWN) {
0339:                    fileType = Utilities.getFileType(cache != null ? cache
0340:                            : file);
0341:                    if (fileType == FILETYPE_GZIP) {
0342:                        // If we're looking at a remote file, gunzip the cached copy
0343:                        // of it; otherwise, gunzip the file itself into the cache.
0344:                        File uncompressed = cacheGZIP(cache != null ? cache
0345:                                : file);
0346:                        if (uncompressed != null) {
0347:                            cache = uncompressed;
0348:                            fileType = Utilities.getFileType(cache);
0349:                            compression = new Compression(COMPRESSION_GZIP);
0350:                        } else
0351:                            fileType = FILETYPE_BINARY; // Something went wrong.
0352:                    }
0353:                }
0354:                mode = getDefaultMode();
0355:                formatter = mode.getFormatter(this );
0356:                if (fileType == FILETYPE_ZIP) {
0357:                    supportsUndo = false;
0358:                    type = TYPE_ARCHIVE;
0359:                    readOnly = true;
0360:                } else if (fileType == FILETYPE_BINARY) {
0361:                    readOnly = true;
0362:                } else if (fileType == FILETYPE_WORD) {
0363:                    readOnly = true;
0364:                } else if (file != null) {
0365:                    FileHistoryEntry entry = FileHistory.getFileHistory()
0366:                            .findEntry(file.netPath());
0367:                    if (entry != null) {
0368:                        // Set encoding.
0369:                        final String encoding = entry.getEncoding();
0370:                        if (encoding != null
0371:                                && Utilities.isSupportedEncoding(encoding))
0372:                            file.setEncoding(encoding);
0373:                        // Set mode.
0374:                        mode = Editor.getModeList().getModeFromModeName(
0375:                                entry.getMode());
0376:                        if (mode == null)
0377:                            mode = Editor.getModeList()
0378:                                    .getMode(PLAIN_TEXT_MODE);
0379:                        else if (mode.getId() == BINARY_MODE)
0380:                            readOnly = true;
0381:                        formatter = mode.getFormatter(this );
0382:                        // Properties from FileHistoryEntry override defaults set by
0383:                        // mode.
0384:                        properties.putAll(entry.getProperties());
0385:                    }
0386:                }
0387:                if (file != null) {
0388:                    if (file.getProtocol() == File.PROTOCOL_HTTP
0389:                            || file.getProtocol() == File.PROTOCOL_HTTPS)
0390:                        readOnly = true;
0391:                }
0392:                initialized = true;
0393:            }
0394:
0395:            public Mode getDefaultMode() {
0396:                final File file = getFile();
0397:                final ModeList modeList = Editor.getModeList();
0398:                switch (fileType) {
0399:                case FILETYPE_XML:
0400:                    return modeList.getMode(XML_MODE);
0401:                case FILETYPE_SHELLSCRIPT: {
0402:                    Mode m = grovelModeFromFile(file);
0403:                    if (m != null)
0404:                        return m;
0405:                    return modeList.getMode(SHELL_SCRIPT_MODE);
0406:                }
0407:                case FILETYPE_PERL:
0408:                    return modeList.getMode(PERL_MODE);
0409:                case FILETYPE_PHP:
0410:                    return modeList.getMode(PHP_MODE);
0411:                case FILETYPE_ZIP:
0412:                    return modeList.getMode(ARCHIVE_MODE);
0413:                case FILETYPE_GZIP:
0414:                case FILETYPE_BINARY:
0415:                    return modeList.getMode(BINARY_MODE);
0416:                case FILETYPE_JPEG:
0417:                    return modeList.getMode(IMAGE_MODE);
0418:                case FILETYPE_WORD:
0419:                    return modeList.getMode(WORD_MODE);
0420:                case FILETYPE_TEXT:
0421:                default: {
0422:                    Mode m = grovelModeFromFile(file);
0423:                    if (m == null) {
0424:                        if (compression != null
0425:                                && compression.getType() == COMPRESSION_ZIP) {
0426:                            String entryName = compression.getEntryName();
0427:                            if (entryName != null)
0428:                                m = getModeForFileName(entryName);
0429:                        } else if (file != null) {
0430:                            m = getModeForFileName(file.getName());
0431:                        }
0432:                        if (m != null && m.getId() == IMAGE_MODE) {
0433:                            if (fileType == FILETYPE_TEXT)
0434:                                m = modeList.getMode(PLAIN_TEXT_MODE);
0435:                            else
0436:                                m = modeList.getMode(BINARY_MODE);
0437:                        } else if (m == null) {
0438:                            if (file != null) {
0439:                                if (file.getProtocol() == File.PROTOCOL_HTTP
0440:                                        || file.getProtocol() == File.PROTOCOL_HTTPS)
0441:                                    m = modeList.getMode(HTML_MODE);
0442:                            }
0443:                            if (m == null)
0444:                                m = modeList.getMode(PLAIN_TEXT_MODE);
0445:                        }
0446:                    }
0447:                    return m;
0448:                }
0449:                }
0450:            }
0451:
0452:            private static final Mode grovelModeFromFile(File file) {
0453:                if (file == null)
0454:                    return null;
0455:                if (!file.isLocal())
0456:                    return null;
0457:                if (!file.isFile())
0458:                    return null;
0459:                Mode mode = null;
0460:                try {
0461:                    BufferedReader reader = new BufferedReader(
0462:                            new InputStreamReader(file.getInputStream()));
0463:                    String s = reader.readLine();
0464:                    if (s != null) {
0465:                        mode = grovelModeFromString(s);
0466:                        if (mode == null && s.startsWith("#!")) {
0467:                            // Consider second line too.
0468:                            s = reader.readLine();
0469:                            if (s != null)
0470:                                mode = grovelModeFromString(s);
0471:                        }
0472:                    }
0473:                    reader.close();
0474:                } catch (IOException e) {
0475:                    Log.error(e);
0476:                }
0477:                return mode;
0478:            }
0479:
0480:            private static final Mode grovelModeFromString(String s) {
0481:                if (s != null) {
0482:                    int begin = s.indexOf("-*-");
0483:                    if (begin >= 0) {
0484:                        s = s.substring(begin + 3);
0485:                        int end = s.indexOf("-*-");
0486:                        if (end >= 0) {
0487:                            s = s.substring(0, end).trim().toLowerCase();
0488:                            int index = s.indexOf("mode:");
0489:                            String modeName;
0490:                            if (index < 0) {
0491:                                // "-*- Lisp -*-"
0492:                                modeName = s;
0493:                            } else {
0494:                                // "-*- Mode: LISP; Syntax: ANSI-Common-Lisp; Base: 10 -*-"
0495:                                s = s.substring(5).trim();
0496:                                for (end = 0; end < s.length(); end++) {
0497:                                    char c = s.charAt(end);
0498:                                    if (c == ' ' || c == '\t' || c == ';')
0499:                                        break;
0500:                                }
0501:                                modeName = s.substring(0, end);
0502:                            }
0503:                            return Editor.getModeList().getModeFromModeName(
0504:                                    modeName);
0505:                        }
0506:                    }
0507:                }
0508:                return null;
0509:            }
0510:
0511:            // Locking.
0512:            public final boolean isInUse() {
0513:                return mutex.isInUse();
0514:            }
0515:
0516:            public void acquire() throws InterruptedException {
0517:                mutex.acquire();
0518:            }
0519:
0520:            public synchronized void release() {
0521:                mutex.release();
0522:            }
0523:
0524:            public boolean attempt() throws InterruptedException {
0525:                return mutex.attempt();
0526:            }
0527:
0528:            public boolean attempt(long msecs) throws InterruptedException {
0529:                return mutex.attempt(msecs);
0530:            }
0531:
0532:            public final boolean isLocked() {
0533:                return isInUse();
0534:            }
0535:
0536:            public synchronized boolean lock() {
0537:                try {
0538:                    return attempt();
0539:                } catch (InterruptedException e) {
0540:                    return false;
0541:                }
0542:            }
0543:
0544:            public synchronized void unlock() {
0545:                release();
0546:            }
0547:
0548:            public final void lockRead() throws InterruptedException {
0549:                rwlock.lockRead();
0550:            }
0551:
0552:            public final void unlockRead() {
0553:                rwlock.unlockRead();
0554:            }
0555:
0556:            public final void lockWrite() throws InterruptedException {
0557:                rwlock.lockWrite();
0558:            }
0559:
0560:            public final void unlockWrite() {
0561:                rwlock.unlockWrite();
0562:            }
0563:
0564:            public final boolean isWriteLocked() {
0565:                return rwlock.isWriteLocked();
0566:            }
0567:
0568:            public boolean isVisible() {
0569:                for (EditorIterator it = new EditorIterator(); it.hasNext();)
0570:                    if (it.nextEditor().getBuffer() == this )
0571:                        return true;
0572:
0573:                return false;
0574:            }
0575:
0576:            public void setWaitCursor() {
0577:                for (EditorIterator it = new EditorIterator(); it.hasNext();) {
0578:                    Editor ed = it.nextEditor();
0579:                    if (ed.getBuffer() == this )
0580:                        ed.setWaitCursor();
0581:                }
0582:            }
0583:
0584:            public void setDefaultCursor() {
0585:                for (EditorIterator it = new EditorIterator(); it.hasNext();) {
0586:                    Editor ed = it.nextEditor();
0587:                    if (ed.getBuffer() == this )
0588:                        ed.setDefaultCursor();
0589:                }
0590:            }
0591:
0592:            public final PropertyList getProperties() {
0593:                return properties;
0594:            }
0595:
0596:            public final void setCache(File file) {
0597:                cache = file;
0598:            }
0599:
0600:            public final File getCache() {
0601:                return cache;
0602:            }
0603:
0604:            public final Formatter getFormatter() {
0605:                return formatter;
0606:            }
0607:
0608:            public final void setFormatter(Formatter formatter) {
0609:                this .formatter = formatter;
0610:            }
0611:
0612:            public boolean isReadOnly() {
0613:                return readOnly || forceReadOnly;
0614:            }
0615:
0616:            private boolean busy;
0617:
0618:            public synchronized final boolean isBusy() {
0619:                return busy;
0620:            }
0621:
0622:            public synchronized final void setBusy(boolean b) {
0623:                busy = b;
0624:            }
0625:
0626:            public final BackgroundProcess getBackgroundProcess() {
0627:                return backgroundProcess;
0628:            }
0629:
0630:            public final void setBackgroundProcess(
0631:                    BackgroundProcess backgroundProcess) {
0632:                this .backgroundProcess = backgroundProcess;
0633:            }
0634:
0635:            public File getCurrentDirectory() {
0636:                return getFile() != null ? getFile().getParentFile()
0637:                        : Directories.getUserHomeDirectory();
0638:            }
0639:
0640:            // Subclasses should override this method if appropriate!
0641:            public File getCompletionDirectory() {
0642:                final File file = getFile();
0643:                if (file != null) {
0644:                    if (file.isLocal() || file instanceof  SshFile)
0645:                        return file.isDirectory() ? file : file.getParentFile();
0646:                }
0647:                return Directories.getUserHomeDirectory();
0648:            }
0649:
0650:            public View getInitialView() {
0651:                View view = new View();
0652:                view.setDot(getInitialDotPos());
0653:                return view;
0654:            }
0655:
0656:            private int initialLineNumber;
0657:            private int initialOffset;
0658:
0659:            public Position getInitialDotPos() {
0660:                Line line = getLine(initialLineNumber);
0661:                if (line == null) {
0662:                    line = getFirstLine();
0663:                    return line != null ? new Position(line, 0) : null;
0664:                }
0665:                return new Position(line, Math
0666:                        .min(initialOffset, line.length()));
0667:            }
0668:
0669:            public void setInitialDotPos(int lineNumber, int offset) {
0670:                initialLineNumber = lineNumber;
0671:                initialOffset = offset;
0672:            }
0673:
0674:            private long lastActivated;
0675:
0676:            public final long getLastActivated() {
0677:                return lastActivated;
0678:            }
0679:
0680:            public final void setLastActivated(long l) {
0681:                lastActivated = l;
0682:            }
0683:
0684:            public final int getLineCount() {
0685:                return lineCount;
0686:            }
0687:
0688:            public final int getModCount() {
0689:                return modCount;
0690:            }
0691:
0692:            public final synchronized void setModCount(int count) {
0693:                if (count != modCount) {
0694:                    modCount = count;
0695:                    srText = null;
0696:                }
0697:            }
0698:
0699:            public final synchronized void incrementModCount() {
0700:                ++modCount;
0701:                srText = null;
0702:            }
0703:
0704:            public final void setModCountWhenLastSaved(int count) {
0705:                autosaveModCount = count;
0706:            }
0707:
0708:            public final KeyMap getKeyMapForMode() {
0709:                // Should never return null.
0710:                return mode.getKeyMap();
0711:            }
0712:
0713:            public final int getFileType() {
0714:                return fileType;
0715:            }
0716:
0717:            private final void setFileType(int fileType) {
0718:                this .fileType = fileType;
0719:            }
0720:
0721:            private static File cacheGZIP(File f) {
0722:                try {
0723:                    File tempFile = Utilities.getTempFile();
0724:                    if (tempFile != null) {
0725:                        InputStream in = new GZIPInputStream(f.getInputStream());
0726:                        if (in != null) {
0727:                            OutputStream out = tempFile.getOutputStream();
0728:                            byte[] buf = new byte[4096];
0729:                            int bytesRead;
0730:                            while ((bytesRead = in.read(buf)) > 0)
0731:                                out.write(buf, 0, bytesRead);
0732:                            out.close();
0733:                            in.close();
0734:                            return tempFile;
0735:                        }
0736:                    }
0737:                } catch (IOException e) {
0738:                    Log.error(e);
0739:                }
0740:                return null;
0741:            }
0742:
0743:            // Handles all the paperwork when we rename a buffer.
0744:            public void changeFile(File f) {
0745:                if (f == null)
0746:                    return;
0747:                String newName = f.canonicalPath();
0748:                if (newName == null)
0749:                    return;
0750:                File oldFile = getFile();
0751:                String oldName = oldFile != null ? oldFile.canonicalPath()
0752:                        : null;
0753:                setFile(f);
0754:                setCompression(null);
0755:                type = TYPE_NORMAL;
0756:                title = null;
0757:                Mode oldMode = mode;
0758:                if (oldMode == PlainTextMode.getMode()) {
0759:                    setModeFromFilename(newName);
0760:                    if (mode != oldMode) {
0761:                        // Mode has changed.
0762:                        needsParsing = true;
0763:
0764:                        // Make sure we parse the buffer before we display it.
0765:                        if (formatter != null)
0766:                            formatter.parseBuffer();
0767:                    }
0768:                }
0769:                readOnly = false;
0770:                isUntitled = false;
0771:                if (oldName != null)
0772:                    Autosave.rename(oldName, newName);
0773:                Editor.getBufferList().modified();
0774:                Sidebar.setUpdateFlagInAllFrames(SIDEBAR_BUFFER_LIST_CHANGED);
0775:                for (EditorIterator it = new EditorIterator(); it.hasNext();) {
0776:                    Editor editor = it.nextEditor();
0777:                    if (editor.getBuffer() == this ) {
0778:                        editor.updateLocation();
0779:                        editor.getDisplay().repaint();
0780:                    }
0781:                }
0782:            }
0783:
0784:            protected void setModeFromFilename(String filename) {
0785:                mode = Editor.getModeList().getModeForFileName(filename);
0786:                if (mode == null)
0787:                    mode = Editor.getModeList().getMode(PLAIN_TEXT_MODE);
0788:                formatter = mode.getFormatter(this );
0789:            }
0790:
0791:            private static Mode getModeForFileName(String filename) {
0792:                if (filename.endsWith(".gz"))
0793:                    filename = filename.substring(0, filename.length() - 3);
0794:
0795:                // Strip path prefix (if any).
0796:                // Look for '/' on both Windows and Unix (filename might be a ZipEntry name).
0797:                int index = filename.lastIndexOf('/');
0798:                if (index >= 0)
0799:                    filename = filename.substring(index + 1);
0800:
0801:                // Look for '\' on Windows only.
0802:                if (Platform.isPlatformWindows()) {
0803:                    index = filename.lastIndexOf('\\');
0804:                    if (index >= 0)
0805:                        filename = filename.substring(index + 1);
0806:                }
0807:
0808:                return Editor.getModeList().getModeForFileName(filename);
0809:            }
0810:
0811:            public final void setMode(Mode mode) {
0812:                this .mode = mode;
0813:                formatter = mode.getFormatter(this );
0814:            }
0815:
0816:            public void changeMode(Mode newMode) {
0817:                final int oldModeId = mode.getId();
0818:                if (oldModeId == DIRECTORY_MODE)
0819:                    return;
0820:                final int newModeId = newMode.getId();
0821:                if (newModeId != oldModeId) {
0822:                    // Must reload buffer if changing into or out of binary mode.
0823:                    boolean reloading = newModeId == BINARY_MODE
0824:                            || oldModeId == BINARY_MODE;
0825:                    mode = newMode;
0826:                    formatter = mode.getFormatter(this );
0827:                    if (reloading) {
0828:                        reload();
0829:                        if (newModeId == IMAGE_MODE)
0830:                            return;
0831:                    }
0832:
0833:                    if (newModeId == BINARY_MODE) {
0834:                        readOnly = true;
0835:                    } else {
0836:                        final File file = getFile();
0837:                        if (file != null && !file.isRemote() && file.isFile())
0838:                            readOnly = !file.canWrite();
0839:                    }
0840:
0841:                    formatter.parseBuffer();
0842:
0843:                    for (EditorIterator it = new EditorIterator(); it.hasNext();) {
0844:                        Editor ed = it.nextEditor();
0845:                        if (ed.getBuffer() == this ) {
0846:                            if (reloading) {
0847:                                ed.setDot(getFirstLine(), 0);
0848:                                ed.setMark(null);
0849:                                ed.setTopLine(getFirstLine());
0850:                                ed.moveCaretToDotCol();
0851:                                ed.updateLocation();
0852:                            }
0853:                            ed.setUpdateFlag(REPAINT);
0854:                            ed.updateDisplay();
0855:                        }
0856:                    }
0857:                }
0858:            }
0859:
0860:            public final String getCommentStart() {
0861:                return mode.getCommentStart();
0862:            }
0863:
0864:            public final String getCommentEnd() {
0865:                return mode.getCommentEnd();
0866:            }
0867:
0868:            private long lastModified;
0869:
0870:            public final long getLastModified() {
0871:                return lastModified;
0872:            }
0873:
0874:            public final void setLastModified(long lastModified) {
0875:                this .lastModified = lastModified;
0876:            }
0877:
0878:            protected void loadFile(File toBeLoaded) {
0879:                try {
0880:                    int modeId = getModeId();
0881:                    if (modeId == ARCHIVE_MODE || modeId == WORD_MODE
0882:                            || modeId == XML_MODE)
0883:                        mode.loadFile(this , toBeLoaded);
0884:                    else {
0885:                        final String encoding = toBeLoaded.getEncoding();
0886:                        load(toBeLoaded.getInputStream(), encoding);
0887:                        if (encoding != null)
0888:                            saveProperties(); // Remember encoding for next time.
0889:                    }
0890:                } catch (IOException e) {
0891:                    Log.error(e);
0892:                }
0893:                // Handle zero length files.
0894:                if (getFirstLine() == null) {
0895:                    appendLine("");
0896:                    lineSeparator = System.getProperty("line.separator");
0897:                }
0898:                final File file = getFile();
0899:                if (file != null && file.getProtocol() != File.PROTOCOL_HTTP)
0900:                    lastModified = toBeLoaded.lastModified();
0901:                renumberOriginal();
0902:            }
0903:
0904:            public int load() {
0905:                if (!isLoaded()) {
0906:                    try {
0907:                        lockWrite();
0908:                    } catch (InterruptedException e) {
0909:                        Log.error(e);
0910:                        return LOAD_FAILED;
0911:                    }
0912:                    try {
0913:                        final File file = getFile();
0914:                        final File toBeLoaded = cache != null ? cache : file;
0915:                        if (toBeLoaded.isFile()) {
0916:                            Editor editor = Editor.currentEditor();
0917:                            FastStringBuffer sb = new FastStringBuffer(
0918:                                    "Loading");
0919:                            if (compression != null) {
0920:                                if (compression.getType() == COMPRESSION_ZIP) {
0921:                                    String entryName = compression
0922:                                            .getEntryName();
0923:                                    if (entryName != null) {
0924:                                        sb.append(' ');
0925:                                        sb.append(entryName);
0926:                                    }
0927:                                }
0928:                            } else if (file != null) {
0929:                                sb.append(' ');
0930:                                sb.append(file.getName());
0931:                            }
0932:                            sb.append("...");
0933:                            editor.status(sb.toString());
0934:                            Debug.assertTrue(mode != null);
0935:                            Debug.assertTrue(toBeLoaded != null);
0936:                            loadFile(toBeLoaded);
0937:                            // At this point, if we loaded from a cache, lastModified will
0938:                            // be set based on the cache file, which is not what we want
0939:                            // in the case of a local file.
0940:                            if (toBeLoaded == cache && file != null
0941:                                    && !file.isRemote())
0942:                                lastModified = file.lastModified();
0943:                            formatter.parseBuffer();
0944:                            checkCVS();
0945:                            sb.append("done");
0946:                            editor.status(sb.toString());
0947:                        } else {
0948:                            // File doesn't exist.
0949:                            if (getFirstLine() == null) {
0950:                                appendLine("");
0951:                                lineSeparator = System
0952:                                        .getProperty("line.separator");
0953:                            }
0954:                            renumberOriginal();
0955:                            setModeFromFilename(file.canonicalPath());
0956:                            setLoaded(true);
0957:                        }
0958:                    } catch (OutOfMemoryError e) {
0959:                        _empty();
0960:                        throw e;
0961:                    } finally {
0962:                        unlockWrite();
0963:                    }
0964:                }
0965:                return LOAD_COMPLETED;
0966:            }
0967:
0968:            private void reloadSucceeded() {
0969:                Debug.assertTrue(!rwlock.isWriteLocked());
0970:                Debug.assertTrue(SwingUtilities.isEventDispatchThread());
0971:                for (EditorIterator it = new EditorIterator(); it.hasNext();) {
0972:                    Editor ed = it.nextEditor();
0973:                    if (ed.getBuffer() != this )
0974:                        continue;
0975:                    View view = ed.getView(this );
0976:                    if (view != null) {
0977:                        Line dotLine = getLine(view.getDotLineNumber());
0978:                        if (dotLine == null)
0979:                            dotLine = getFirstLine();
0980:                        if (dotLine != null) {
0981:                            ed.setDot(dotLine, 0);
0982:                            ed.moveCaretToDotCol();
0983:                        }
0984:                        Line topLine = getLine(view.getTopLineNumber());
0985:                        if (topLine == null)
0986:                            topLine = dotLine;
0987:                        ed.setTopLine(topLine);
0988:                    } else {
0989:                        ed.setDot(getFirstLine(), 0);
0990:                        ed.moveCaretToDotCol();
0991:                        ed.setTopLine(getFirstLine());
0992:                    }
0993:                    ed.setUpdateFlag(REPAINT);
0994:                    ed.updateDisplay();
0995:                }
0996:                // The buffer is unmodified now, so we need to update its icon in the
0997:                // buffer list(s).
0998:                Sidebar.setUpdateFlagInAllFrames(SIDEBAR_REPAINT_BUFFER_LIST);
0999:            }
1000:
1001:            private void reloadFailed() {
1002:                MessageDialog.showMessageDialog("Reload failed", "Error");
1003:            }
1004:
1005:            public void reload() {
1006:                final File file = getFile();
1007:                if (file == null)
1008:                    return;
1009:                switch (file.getProtocol()) {
1010:                case File.PROTOCOL_FTP:
1011:                    reloadFtp((FtpFile) file);
1012:                    return;
1013:                case File.PROTOCOL_HTTP:
1014:                case File.PROTOCOL_HTTPS:
1015:                    reloadHttp((HttpFile) file);
1016:                    return;
1017:                case File.PROTOCOL_FILE:
1018:                    if (file.isFile()) {
1019:                        // Local file.
1020:                        if (getModeId() == ARCHIVE_MODE) {
1021:                            empty();
1022:                            resetUndo();
1023:                            mode.loadFile(this , file);
1024:                        } else
1025:                            reloadLocal(file);
1026:                    }
1027:                    reloadSucceeded();
1028:                    return;
1029:                default:
1030:                    Debug.assertTrue(false);
1031:                    break;
1032:                }
1033:            }
1034:
1035:            // Asynchronous.
1036:            private void reloadFtp(FtpFile file) {
1037:                Log.debug("reloadFtp");
1038:                Debug.assertTrue(SwingUtilities.isEventDispatchThread());
1039:                FtpSession session = FtpSession.getSession(file);
1040:                final FtpLoadProcess ftpLoadProcess = new FtpLoadProcess(this ,
1041:                        file, session);
1042:                Runnable successRunnable = new Runnable() {
1043:                    public void run() {
1044:                        File newCache = ftpLoadProcess.getCache();
1045:                        if (newCache != null) {
1046:                            Log.debug("newCache != null");
1047:                            if (cache != null && cache.isFile())
1048:                                cache.delete();
1049:                            cache = newCache;
1050:                            reloadLocal(cache);
1051:                        } else {
1052:                            // User cancelled.
1053:                            setLoaded(true);
1054:                        }
1055:                        setBusy(false);
1056:                        reloadSucceeded();
1057:                    }
1058:                };
1059:                ErrorRunnable errorRunnable = new ErrorRunnable("Reload failed") {
1060:                    public void run() {
1061:                        setBusy(false);
1062:                        reloadFailed();
1063:                    }
1064:                };
1065:                ftpLoadProcess
1066:                        .setProgressNotifier(new StatusBarProgressNotifier(this ));
1067:                ftpLoadProcess.setSuccessRunnable(successRunnable);
1068:                ftpLoadProcess.setErrorRunnable(errorRunnable);
1069:                ftpLoadProcess.start();
1070:            }
1071:
1072:            private void reloadHttp(HttpFile file) {
1073:                Log.debug("reloadHttp");
1074:                Debug.assertTrue(SwingUtilities.isEventDispatchThread());
1075:                final HttpLoadProcess httpLoadProcess = new HttpLoadProcess(
1076:                        this , file);
1077:                Runnable successRunnable = new Runnable() {
1078:                    public void run() {
1079:                        File newCache = httpLoadProcess.getCache();
1080:                        if (newCache != null) {
1081:                            Log.debug("newCache != null");
1082:                            if (cache != null && cache.isFile())
1083:                                cache.delete();
1084:                            cache = newCache;
1085:                            reloadLocal(cache);
1086:                        } else {
1087:                            // User cancelled.
1088:                            setLoaded(true);
1089:                        }
1090:                        setBusy(false);
1091:                        reloadSucceeded();
1092:                    }
1093:                };
1094:                ErrorRunnable errorRunnable = new ErrorRunnable("Reload failed") {
1095:                    public void run() {
1096:                        setBusy(false);
1097:                        reloadFailed();
1098:                    }
1099:                };
1100:                httpLoadProcess
1101:                        .setProgressNotifier(new StatusBarProgressNotifier(this ));
1102:                httpLoadProcess.setSuccessRunnable(successRunnable);
1103:                httpLoadProcess.setErrorRunnable(errorRunnable);
1104:                setBusy(true);
1105:                new Thread(httpLoadProcess).start();
1106:            }
1107:
1108:            private void reloadLocal(File file) {
1109:                try {
1110:                    lockWrite();
1111:                } catch (InterruptedException e) {
1112:                    Log.error(e);
1113:                    return;
1114:                }
1115:                try {
1116:                    empty();
1117:                    loadFile(file);
1118:                    formatter.parseBuffer();
1119:                } finally {
1120:                    unlockWrite();
1121:                }
1122:                unmodified();
1123:                deleteAutosaveFile();
1124:                resetUndo();
1125:            }
1126:
1127:            public synchronized void kill() {
1128:                BufferList bufferList = Editor.getBufferList();
1129:                if (!bufferList.contains(this )) {
1130:                    Debug.bug("buffer.kill() buffer not in list");
1131:                    return;
1132:                }
1133:
1134:                Marker.invalidateMarkers(this );
1135:
1136:                Buffer buf = bufferList.getPreviousPrimaryBuffer(this );
1137:                if (buf != null && buf.isPaired()) {
1138:                    Buffer secondary = buf.getSecondary();
1139:                    if (secondary != null) {
1140:                        if (secondary.getLastActivated() > buf
1141:                                .getLastActivated())
1142:                            buf = secondary;
1143:                    }
1144:                }
1145:                if (buf == null)
1146:                    buf = new Directory(getCurrentDirectory());
1147:                // Copy editor list since switchToBuffer() may close an editor.
1148:                ArrayList editors = new ArrayList();
1149:                for (EditorIterator it = new EditorIterator(); it.hasNext();)
1150:                    editors.add(it.next());
1151:                for (Iterator it = editors.iterator(); it.hasNext();) {
1152:                    Editor ed = (Editor) it.next();
1153:                    // Skip editor if it has been closed.
1154:                    if (Editor.getEditorList().contains(ed)) {
1155:                        if (ed.getBuffer() == this )
1156:                            ed.switchToBuffer(buf);
1157:                        ed.removeView(this );
1158:                    }
1159:                }
1160:                deleteAutosaveFile();
1161:                bufferList.remove(this );
1162:                dispose();
1163:                Sidebar.setUpdateFlagInAllFrames(SIDEBAR_BUFFER_LIST_CHANGED
1164:                        | SIDEBAR_MODIFIED_BUFFER_COUNT);
1165:            }
1166:
1167:            public synchronized void relink() {
1168:                BufferList bufferList = Editor.getBufferList();
1169:                if (bufferList.contains(this )) {
1170:                    Debug.bug();
1171:                    return;
1172:                }
1173:                bufferList.add(this );
1174:            }
1175:
1176:            private Thread startTaggerThread(int priority) {
1177:                if (mode != null) {
1178:                    Tagger tagger = mode.getTagger(this );
1179:                    if (tagger != null) {
1180:                        Thread thread = new Thread(tagger);
1181:                        thread.setPriority(priority);
1182:                        thread.setDaemon(true);
1183:                        thread.setName("tagger " + getFile().getName());
1184:                        thread.start();
1185:                        return thread;
1186:                    }
1187:                }
1188:                return null;
1189:            }
1190:
1191:            public boolean isTaggable() {
1192:                final File file = getFile();
1193:                if (file == null)
1194:                    return false;
1195:                if (file.isRemote())
1196:                    return false;
1197:                return mode.isTaggable();
1198:            }
1199:
1200:            // Runs tagger if tags == null.
1201:            public List getTags(boolean update) {
1202:                List tags = getTags();
1203:                if (tags != null)
1204:                    return tags;
1205:                if (mode != null) {
1206:                    Tagger tagger = mode.getTagger(this );
1207:                    if (tagger != null)
1208:                        tagger.run();
1209:                }
1210:                return getTags();
1211:            }
1212:
1213:            public boolean saveToCache() {
1214:                if (lineSeparator == null)
1215:                    lineSeparator = System.getProperty("line.separator");
1216:                final File tempFile = Utilities.getTempFile();
1217:                if (tempFile != null) {
1218:                    File file = getFile();
1219:                    if (file != null)
1220:                        tempFile.setEncoding(file.getEncoding());
1221:                    if (writeFile(tempFile)) {
1222:                        final File oldCache = cache;
1223:                        cache = tempFile;
1224:                        if (oldCache != null && oldCache.isFile())
1225:                            oldCache.delete();
1226:                        return true;
1227:                    }
1228:                }
1229:                return false;
1230:            }
1231:
1232:            private boolean maybeWriteBackupFromCache() {
1233:                if (cache == null) {
1234:                    Log.error("maybeWriteBackupFromCache cache is null");
1235:                    return false;
1236:                }
1237:                if (!cache.isFile()) {
1238:                    Log.error("maybeWriteBackupFromCache cache is not a file");
1239:                    return false;
1240:                }
1241:                if (!cache.canRead()) {
1242:                    Log
1243:                            .error("maybeWriteBackupFromCache cache is not readable");
1244:                    return false;
1245:                }
1246:                if (backedUp)
1247:                    return true; // We only want to do the backup once!
1248:                File file = getFile();
1249:                if (file == null) {
1250:                    Debug.bug();
1251:                    return false;
1252:                }
1253:                String name = file.getName();
1254:                if (compression != null
1255:                        && compression.getType() == COMPRESSION_GZIP) {
1256:                    if (name.endsWith(".gz"))
1257:                        name = name.substring(0, name.length() - 3);
1258:                }
1259:                return backedUp = Utilities.makeBackup(cache, name, false);
1260:            }
1261:
1262:            public boolean save() {
1263:                Debug.assertTrue(SwingUtilities.isEventDispatchThread());
1264:                if (!isModified())
1265:                    return true;
1266:                addUndoBoundary();
1267:                boolean succeeded = false;
1268:                final File file = getFile();
1269:                if (file != null) {
1270:                    if (file.isLocal())
1271:                        succeeded = saveLocal(file);
1272:                    if (file instanceof  FtpFile)
1273:                        succeeded = saveFtp();
1274:                    if (file instanceof  SshFile)
1275:                        succeeded = saveSsh((SshFile) file);
1276:                }
1277:                if (succeeded && Editor.isLispInitialized())
1278:                    LispAPI.invokeAfterSaveHook(this );
1279:                return succeeded;
1280:            }
1281:
1282:            private boolean saveLocal(final File file) {
1283:                Debug.assertTrue(file.isLocal());
1284:
1285:                if (compression != null
1286:                        && compression.getType() == COMPRESSION_GZIP)
1287:                    return saveLocalCompressed(file);
1288:
1289:                try {
1290:                    writeBuffer();
1291:                    renumberOriginal();
1292:                    saved();
1293:                    lastModified = file.lastModified();
1294:                } catch (SaveException e) {
1295:                    final String where = "Save";
1296:                    String message = e.getMessage();
1297:                    // Tell user exactly what error occurred.
1298:                    if (message != null)
1299:                        MessageDialog.showMessageDialog(message, where);
1300:                    // Display summary message.
1301:                    message = "Unable to save " + file.canonicalPath();
1302:                    MessageDialog.showMessageDialog(message, where);
1303:                    return false;
1304:                }
1305:
1306:                if (isTaggable())
1307:                    Editor.getTagFileManager().addToQueue(file.getParentFile(),
1308:                            mode);
1309:                startTaggerThread(Thread.MIN_PRIORITY);
1310:                boolean repaint = false;
1311:                final ModeList modeList = Editor.getModeList();
1312:                if (file.equals(Preferences.getPreferencesFile())) {
1313:                    // Reload preferences.
1314:                    Editor.loadPreferences();
1315:                    if (Editor.preferences().getBooleanProperty(
1316:                            Property.AUTO_RELOAD_KEY_MAPS)) {
1317:                        // Reload keymaps.
1318:                        KeyMap.reloadKeyMaps();
1319:                    }
1320:                    repaint = true;
1321:                } else {
1322:                    if (Editor.preferences().getBooleanProperty(
1323:                            Property.AUTO_RELOAD_KEY_MAPS)) {
1324:                        // Reload mode-specific keymap(s) if modified.
1325:                        synchronized (modeList) {
1326:                            for (Iterator it = modeList.iterator(); it
1327:                                    .hasNext();) {
1328:                                ModeListEntry entry = (ModeListEntry) it.next();
1329:                                Mode mode = entry.getMode(false);
1330:                                if (mode != null) {
1331:                                    if (file.equals(mode.getKeyMapFile()))
1332:                                        mode.deleteKeyMap();
1333:                                }
1334:                            }
1335:                        }
1336:                        // Global keymap.
1337:                        if (file.equals(KeyMap.getGlobalKeyMapFile()))
1338:                            KeyMap.deleteGlobalKeyMap();
1339:                    }
1340:                }
1341:                // Reload theme if modified.
1342:                String theme = Editor.preferences().getStringProperty(
1343:                        Property.THEME);
1344:                if (theme != null) {
1345:                    if (Utilities.isFilenameAbsolute(theme)) {
1346:                        if (file.canonicalPath().equals(
1347:                                File.getInstance(theme).canonicalPath())) {
1348:                            Editor.loadPreferences();
1349:                            repaint = true;
1350:                        }
1351:                    } else if (file.getName().equals(theme)) {
1352:                        Editor.loadPreferences();
1353:                        repaint = true;
1354:                    }
1355:                }
1356:
1357:                // Reload aliases if modified.
1358:                if (file.equals(Editor.getAliasesFile()))
1359:                    Editor.reloadAliases();
1360:
1361:                // Update listRegisters buffer (if any).
1362:                File parent = file.getParentFile();
1363:                if (parent != null
1364:                        && parent.equals(Directories.getRegistersDirectory())) {
1365:                    Buffer buf = Registers.findListRegistersBuffer();
1366:                    if (buf != null)
1367:                        buf.reload();
1368:                }
1369:
1370:                checkCVS();
1371:
1372:                if (repaint) {
1373:                    // Force formatters to be re-initialized.
1374:                    for (BufferIterator it = new BufferIterator(); it.hasNext();) {
1375:                        Buffer buf = it.nextBuffer();
1376:                        if (buf.getFormatter() != null)
1377:                            buf.getFormatter().reset();
1378:                    }
1379:                    Display.initializeStaticValues();
1380:                    for (int i = 0; i < Editor.getFrameCount(); i++) {
1381:                        Frame f = Editor.getFrame(i);
1382:                        if (f != null) {
1383:                            f.resetDisplay();
1384:                            f.repaint();
1385:                        }
1386:                    }
1387:                    Editor.restoreFocus();
1388:                }
1389:                return true;
1390:            }
1391:
1392:            private boolean saveLocalCompressed(File file) {
1393:                final String dialogTitle = "Save";
1394:                final Editor editor = Editor.currentEditor();
1395:                // Do this before saving changes to cache!
1396:                if (!maybeWriteBackupFromCache()) {
1397:                    FastStringBuffer sb = new FastStringBuffer(
1398:                            "Unable to write backup file for ");
1399:                    sb.append(file.getName());
1400:                    sb.append(". Save anyway?");
1401:                    if (!editor.confirm(dialogTitle, sb.toString()))
1402:                        return false;
1403:                }
1404:                if (!saveToCache()) {
1405:                    FastStringBuffer sb = new FastStringBuffer(
1406:                            "Unable to write temporary file for ");
1407:                    sb.append(file.getName());
1408:                    MessageDialog.showMessageDialog(sb.toString(), dialogTitle);
1409:                    return false;
1410:                }
1411:                if (!compress(cache, file))
1412:                    return false;
1413:                saved();
1414:                lastModified = file.lastModified();
1415:                return true;
1416:            }
1417:
1418:            private boolean compress(File source, File destination) {
1419:                if (source == null) {
1420:                    Debug.bug();
1421:                    return false;
1422:                }
1423:                if (destination == null) {
1424:                    Debug.bug();
1425:                    return false;
1426:                }
1427:                if (!source.isFile()) {
1428:                    Debug.bug();
1429:                    return false;
1430:                }
1431:                final File tempFile = Utilities.getTempFile(destination
1432:                        .getParentFile());
1433:                try {
1434:                    final int bufSize = 4096;
1435:                    BufferedInputStream in = new BufferedInputStream(source
1436:                            .getInputStream());
1437:                    GZIPOutputStream out = new GZIPOutputStream(
1438:                            new BufferedOutputStream(tempFile.getOutputStream()),
1439:                            bufSize);
1440:                    byte[] buffer = new byte[bufSize];
1441:                    while (true) {
1442:                        int bytesRead = in.read(buffer, 0, bufSize);
1443:                        if (bytesRead > 0)
1444:                            out.write(buffer, 0, bytesRead);
1445:                        else
1446:                            break;
1447:                    }
1448:                    in.close();
1449:                    out.flush();
1450:                    out.close();
1451:                    return Utilities.deleteRename(tempFile, destination);
1452:                } catch (IOException e) {
1453:                    Log.error(e);
1454:                    return false;
1455:                }
1456:            }
1457:
1458:            private boolean saveFtp() {
1459:                Debug.assertTrue(SwingUtilities.isEventDispatchThread());
1460:                Debug.assertTrue(getFile() instanceof  FtpFile);
1461:                final FtpFile file = (FtpFile) getFile();
1462:                final FtpSession session = FtpSession.getSession(file);
1463:                if (session == null)
1464:                    return false;
1465:                Debug.assertTrue(session.isLocked());
1466:                if (!lock()) {
1467:                    session.unlock();
1468:                    MessageDialog.showMessageDialog("Buffer is busy", file
1469:                            .netPath());
1470:                    return false;
1471:                }
1472:                Debug.assertTrue(isLocked());
1473:                final Editor editor = Editor.currentEditor();
1474:                editor.setWaitCursor();
1475:                // Do this before saving changes to cache!
1476:                if (!maybeWriteBackupFromCache()) {
1477:                    editor.setDefaultCursor();
1478:                    String message = "Unable to write backup file for "
1479:                            + file.getName() + ". Save anyway?";
1480:                    if (!editor.confirm("Save", message)) {
1481:                        unlock();
1482:                        session.unlock();
1483:                        return false;
1484:                    }
1485:                    editor.setWaitCursor();
1486:                }
1487:                if (!saveToCache()) {
1488:                    unlock();
1489:                    session.unlock();
1490:                    editor.setDefaultCursor();
1491:                    String message = "Unable to write temporary file for "
1492:                            + file.getName();
1493:                    MessageDialog.showMessageDialog(message, "Save");
1494:                    return false;
1495:                }
1496:                final FtpSaveProcess saveProcess;
1497:                if (compression != null
1498:                        && compression.getType() == COMPRESSION_GZIP) {
1499:                    final File tempFile = Utilities.getTempFile();
1500:                    if (!compress(cache, tempFile)) {
1501:                        String message = "Unable to compress temporary file for "
1502:                                + file.getName();
1503:                        MessageDialog.showMessageDialog(message, "Save");
1504:                        return false;
1505:                    }
1506:                    saveProcess = new FtpSaveProcess(this , tempFile, file,
1507:                            session);
1508:                } else
1509:                    saveProcess = new FtpSaveProcess(this , cache, file, session);
1510:                saveProcess.setConfirmIfDestinationChanged(true);
1511:                saveProcess.setTitle("Save");
1512:                final Runnable successRunnable = new Runnable() {
1513:                    public void run() {
1514:                        saved();
1515:                        setListing(saveProcess.getListing());
1516:                        for (EditorIterator it = new EditorIterator(); it
1517:                                .hasNext();) {
1518:                            Editor ed = it.nextEditor();
1519:                            if (ed.getBuffer() == Buffer.this )
1520:                                ed.setDefaultCursor();
1521:                        }
1522:                        Sidebar.repaintBufferListInAllFrames();
1523:                    }
1524:                };
1525:                saveProcess.setSuccessRunnable(successRunnable);
1526:                Debug.assertTrue(isLocked());
1527:                saveProcess.start();
1528:                return true;
1529:            }
1530:
1531:            private boolean saveSsh(final SshFile file) {
1532:                final String title = "Save";
1533:                final Editor editor = Editor.currentEditor();
1534:                boolean succeeded = false;
1535:                String message = null;
1536:
1537:                // Do this before saving changes to cache!
1538:                if (!maybeWriteBackupFromCache()) {
1539:                    message = "Unable to write backup file for "
1540:                            + file.getName() + ". Save anyway?";
1541:                    if (!editor.confirm(title, message))
1542:                        return false;
1543:                }
1544:
1545:                if (!saveToCache()) {
1546:                    message = "Unable to write temporary file for "
1547:                            + file.getName();
1548:                    MessageDialog.showMessageDialog(message, title);
1549:                    return false;
1550:                }
1551:
1552:                Ssh ssh = new Ssh();
1553:
1554:                if (compression != null
1555:                        && compression.getType() == COMPRESSION_GZIP) {
1556:                    final File tempFile = Utilities.getTempFile();
1557:                    if (!compress(cache, tempFile)) {
1558:                        message = "Unable to compress temporary file for "
1559:                                + file.getName();
1560:                        MessageDialog.showMessageDialog(message, "Save");
1561:                        return false;
1562:                    }
1563:                    succeeded = ssh.copy(tempFile, file);
1564:                } else
1565:                    succeeded = ssh.copy(cache, file);
1566:
1567:                if (!succeeded)
1568:                    message = ssh.getErrorText();
1569:
1570:                if (succeeded) {
1571:                    saved();
1572:                } else {
1573:                    // Tell user exactly what error occurred.
1574:                    if (message != null)
1575:                        MessageDialog.showMessageDialog(message, title);
1576:
1577:                    // Display summary message.
1578:                    message = "Unable to save " + file.canonicalPath();
1579:                    MessageDialog.showMessageDialog(message, title);
1580:                }
1581:
1582:                return succeeded;
1583:            }
1584:
1585:            public void saveAs(File destination) {
1586:                File file = getFile();
1587:                if (file != null)
1588:                    destination.setEncoding(file.getEncoding());
1589:                if (destination.isLocal())
1590:                    saveAsLocal(destination);
1591:                else if (destination instanceof  FtpFile)
1592:                    saveAsFtp((FtpFile) destination);
1593:                else
1594:                    MessageDialog.showMessageDialog("Invalid destination",
1595:                            "Save As");
1596:            }
1597:
1598:            private boolean saveAsLocal(File destination) {
1599:                Debug.assertTrue(SwingUtilities.isEventDispatchThread());
1600:                if (destination == null)
1601:                    return false;
1602:                if (destination.isDirectory()) {
1603:                    final String prompt = destination.canonicalPath().concat(
1604:                            " is a directory");
1605:                    MessageDialog.showMessageDialog(prompt, "Save As");
1606:                    return false;
1607:                }
1608:                setBusy(true);
1609:                Editor.currentEditor().setWaitCursor();
1610:                boolean succeeded = false;
1611:                String message = null;
1612:                if (lineSeparator == null)
1613:                    lineSeparator = System.getProperty("line.separator");
1614:                final File tempFile = Utilities.getTempFile(destination
1615:                        .getParent());
1616:                if (tempFile == null) {
1617:                    message = "Unable to create temporary file for "
1618:                            + destination.canonicalPath();
1619:                } else {
1620:                    tempFile.setEncoding(destination.getEncoding());
1621:                    if (writeFile(tempFile)) {
1622:                        Log.debug("buffer written to "
1623:                                + tempFile.canonicalPath());
1624:                        if (Utilities.makeBackup(destination, false)) {
1625:                            destination.delete();
1626:                            if (tempFile.renameTo(destination)) {
1627:                                succeeded = true;
1628:                            } else {
1629:                                Log.error("unable to rename "
1630:                                        + tempFile.canonicalPath() + " to "
1631:                                        + destination.canonicalPath());
1632:                                message = "Unable to rename temporary file";
1633:                            }
1634:                        } else {
1635:                            Log.error("backup failed");
1636:                            message = "Unable to write backup file for "
1637:                                    + destination.canonicalPath();
1638:                        }
1639:                    } else {
1640:                        Log.error("writeFile failed");
1641:                        message = "Unable to create temporary file in "
1642:                                + tempFile.getParent();
1643:                    }
1644:                }
1645:                setBusy(false);
1646:                if (succeeded) {
1647:                    saved();
1648:                    changeFile(destination);
1649:                    setLastModified(getFile().lastModified());
1650:                    checkCVS();
1651:                    final String encoding = destination.getEncoding();
1652:                    if (encoding != null)
1653:                        saveProperties(); // Remember encoding for next time.
1654:                    if (isTaggable())
1655:                        Editor.getTagFileManager().addToQueue(
1656:                                destination.getParentFile(), mode);
1657:                    Sidebar
1658:                            .setUpdateFlagInAllFrames(SIDEBAR_REPAINT_BUFFER_LIST);
1659:                } else {
1660:                    // Tell user exactly what error occurred.
1661:                    if (message != null)
1662:                        MessageDialog.showMessageDialog(message, "Save As");
1663:                    MessageDialog.showMessageDialog("Save failed", "Save As");
1664:                }
1665:                return succeeded;
1666:            }
1667:
1668:            private void saveAsFtp(final FtpFile destination) {
1669:                Debug.assertTrue(SwingUtilities.isEventDispatchThread());
1670:                FtpSession session = FtpSession.getSession(destination);
1671:                if (session == null)
1672:                    return;
1673:                Debug.assertTrue(session.isLocked());
1674:                if (!lock()) {
1675:                    session.unlock();
1676:                    MessageDialog.showMessageDialog("Buffer is busy", getFile()
1677:                            .netPath());
1678:                    return;
1679:                }
1680:                final Editor editor = Editor.currentEditor();
1681:                editor.setWaitCursor();
1682:                if (!saveToCache()) {
1683:                    unlock();
1684:                    session.unlock();
1685:                    editor.setDefaultCursor();
1686:                    String message = "Unable to write temporary file for "
1687:                            + destination.netPath();
1688:                    MessageDialog.showMessageDialog(message, "Save As");
1689:                    return;
1690:                }
1691:                final FtpSaveProcess saveProcess = new FtpSaveProcess(this ,
1692:                        cache, destination, session);
1693:                saveProcess.setConfirmOverwrite(true);
1694:                saveProcess.setTitle("Save As");
1695:                final Runnable successRunnable = new Runnable() {
1696:                    public void run() {
1697:                        saved();
1698:                        changeFile(destination);
1699:                        setListing(saveProcess.getListing());
1700:                        Sidebar
1701:                                .setUpdateFlagInAllFrames(SIDEBAR_REPAINT_BUFFER_LIST);
1702:                        for (EditorIterator it = new EditorIterator(); it
1703:                                .hasNext();) {
1704:                            Editor ed = it.nextEditor();
1705:                            if (ed.getBuffer() == Buffer.this )
1706:                                ed.setDefaultCursor();
1707:                        }
1708:                        Sidebar.repaintBufferListInAllFrames();
1709:                    }
1710:                };
1711:                saveProcess.setSuccessRunnable(successRunnable);
1712:                Debug.assertTrue(isLocked());
1713:                saveProcess.start();
1714:            }
1715:
1716:            public void saveCopy(File destination) {
1717:                if (destination.isLocal())
1718:                    saveCopyLocal(destination);
1719:                else if (destination instanceof  FtpFile)
1720:                    saveCopyFtp((FtpFile) destination);
1721:                else
1722:                    MessageDialog.showMessageDialog("Invalid destination",
1723:                            "Save Copy");
1724:            }
1725:
1726:            private void saveCopyLocal(File destination) {
1727:                boolean succeeded = false;
1728:                String message = null;
1729:                if (lineSeparator == null)
1730:                    lineSeparator = System.getProperty("line.separator");
1731:                File tempFile = Utilities.getTempFile(destination.getParent());
1732:                if (tempFile == null) {
1733:                    message = "Unable to create temporary file for "
1734:                            + destination.canonicalPath();
1735:                } else {
1736:                    tempFile.setEncoding(destination.getEncoding());
1737:                    if (writeFile(tempFile)) {
1738:                        Log.debug("buffer written to "
1739:                                + tempFile.canonicalPath());
1740:                        if (Utilities.makeBackup(destination, false)) {
1741:                            destination.delete();
1742:                            if (tempFile.renameTo(destination)) {
1743:                                succeeded = true;
1744:                            } else {
1745:                                Log.error("unable to rename "
1746:                                        + tempFile.canonicalPath() + " to "
1747:                                        + destination.canonicalPath());
1748:                                message = "Unable to rename temporary file";
1749:                            }
1750:                        } else {
1751:                            Log.error("backup failed");
1752:                            message = "Unable to write backup file for "
1753:                                    + destination.canonicalPath();
1754:                        }
1755:                    } else {
1756:                        Log.error("writeFile failed");
1757:                        message = "Unable to create temporary file in "
1758:                                + tempFile.getParent();
1759:                    }
1760:                }
1761:                if (succeeded) {
1762:                    if (isTaggable())
1763:                        Editor.getTagFileManager().addToQueue(
1764:                                destination.getParentFile(), mode);
1765:                } else {
1766:                    // Tell user exactly what error occurred.
1767:                    if (message != null)
1768:                        MessageDialog.showMessageDialog(message, "Save Copy");
1769:                    MessageDialog.showMessageDialog("Save failed", "Save Copy");
1770:                }
1771:            }
1772:
1773:            private void saveCopyFtp(FtpFile destination) {
1774:                Debug.assertTrue(SwingUtilities.isEventDispatchThread());
1775:                FtpSession session = FtpSession.getSession(destination);
1776:                if (session == null)
1777:                    return;
1778:                Debug.assertTrue(session.isLocked());
1779:                if (!lock()) {
1780:                    session.unlock();
1781:                    MessageDialog.showMessageDialog("Buffer is busy", getFile()
1782:                            .netPath());
1783:                    return;
1784:                }
1785:                final Editor editor = Editor.currentEditor();
1786:                editor.setWaitCursor();
1787:                if (!saveToCache()) {
1788:                    unlock();
1789:                    session.unlock();
1790:                    editor.setDefaultCursor();
1791:                    String message = "Unable to write temporary file for "
1792:                            + destination.netPath();
1793:                    MessageDialog.showMessageDialog(message, "Save Copy");
1794:                    return;
1795:                }
1796:                final Runnable successRunnable = new Runnable() {
1797:                    public void run() {
1798:                        for (EditorIterator it = new EditorIterator(); it
1799:                                .hasNext();) {
1800:                            Editor ed = it.nextEditor();
1801:                            if (ed.getBuffer() == Buffer.this )
1802:                                ed.setDefaultCursor();
1803:                        }
1804:                        Sidebar.repaintBufferListInAllFrames();
1805:                    }
1806:                };
1807:                final FtpSaveProcess saveProcess = new FtpSaveProcess(this ,
1808:                        cache, destination, session);
1809:                saveProcess.setConfirmOverwrite(true);
1810:                saveProcess.setTitle("Save Copy");
1811:                saveProcess.setSuccessRunnable(successRunnable);
1812:                Debug.assertTrue(isLocked());
1813:                saveProcess.start();
1814:            }
1815:
1816:            // Removes tabs and spaces only.
1817:            public void removeTrailingWhitespace() {
1818:                boolean bufferChanged = false;
1819:                CompoundEdit compoundEdit = null;
1820:                try {
1821:                    lockWrite();
1822:                } catch (InterruptedException e) {
1823:                    Log.error(e);
1824:                    return;
1825:                }
1826:                try {
1827:                    for (Line line = getFirstLine(); line != null; line = line
1828:                            .next()) {
1829:                        final String text = line.getText();
1830:                        final int originalLength = text.length();
1831:                        int length = originalLength;
1832:                        for (int i = originalLength - 1; i >= 0; i--) {
1833:                            char c = text.charAt(i);
1834:                            if (c == ' ' || c == '\t')
1835:                                --length;
1836:                            else
1837:                                break;
1838:                        }
1839:                        if (length != originalLength) {
1840:                            if (!bufferChanged) {
1841:                                // First change.
1842:                                compoundEdit = new CompoundEdit();
1843:                                bufferChanged = true;
1844:                            }
1845:                            compoundEdit.addEdit(new UndoLineEdit(this , line));
1846:                            line.setText(text.substring(0, length));
1847:                        }
1848:                    }
1849:                    if (bufferChanged)
1850:                        modified();
1851:                } finally {
1852:                    unlockWrite();
1853:                }
1854:                if (compoundEdit != null && undoManager != null) {
1855:                    compoundEdit.end();
1856:                    undoManager.addEdit(compoundEdit);
1857:                }
1858:                if (bufferChanged) {
1859:                    for (EditorIterator it = new EditorIterator(); it.hasNext();) {
1860:                        Editor ed = it.nextEditor();
1861:                        if (ed.getBuffer() == this ) {
1862:                            if (ed.getDotOffset() > ed.getDotLine().length()) {
1863:                                ed.getDot().setOffset(ed.getDotLine().length());
1864:                                if (getBooleanProperty(Property.RESTRICT_CARET)) {
1865:                                    ed.moveCaretToDotCol();
1866:                                    ed.updateDotLine();
1867:                                }
1868:                            }
1869:                            if (ed.getMark() != null) {
1870:                                if (ed.getMarkOffset() > ed.getMarkLine()
1871:                                        .length())
1872:                                    ed.getMark().setOffset(
1873:                                            ed.getMarkLine().length());
1874:                            }
1875:                            ed.repaintDisplay();
1876:                        }
1877:                    }
1878:                }
1879:            }
1880:
1881:            public synchronized void autosave() {
1882:                if (autosaveEnabled && Autosave.isAutosaveEnabled())
1883:                    if (modCount != autosaveModCount)
1884:                        new Thread(autosaveRunnable, "autosave").start();
1885:            }
1886:
1887:            private final Runnable autosaveRunnable = new Runnable() {
1888:                public void run() {
1889:                    try {
1890:                        lockRead();
1891:                    } catch (InterruptedException e) {
1892:                        Log.error(e);
1893:                        return;
1894:                    }
1895:                    try {
1896:                        autosaveInternal();
1897:                    } finally {
1898:                        unlockRead();
1899:                    }
1900:                }
1901:            };
1902:
1903:            private void autosaveInternal() {
1904:                if (autosaveFile == null) {
1905:                    final File autosaveDirectory = Autosave
1906:                            .getAutosaveDirectory();
1907:                    if (autosaveDirectory == null)
1908:                        return;
1909:                    autosaveFile = Utilities.getTempFile(autosaveDirectory);
1910:                    if (autosaveFile == null)
1911:                        return;
1912:                    // Update autosave catalog file.
1913:                    Autosave.put(getFile().netPath(), autosaveFile.getName());
1914:                    Autosave.flush();
1915:                }
1916:                autosaveFile.setEncoding(getFile().getEncoding());
1917:                if (writeFile(autosaveFile))
1918:                    autosaveModCount = modCount;
1919:                else
1920:                    Log.error("autosave writeFile failed");
1921:            }
1922:
1923:            public void deleteAutosaveFile() {
1924:                if (autosaveFile != null)
1925:                    autosaveFile.delete();
1926:            }
1927:
1928:            public void setFirstLine(Line line) {
1929:                if (!rwlock.isWriteLocked()) {
1930:                    Log
1931:                            .error("----- setFirstLine() called without write lock -----");
1932:                    Debug.dumpStack();
1933:                }
1934:                super .setFirstLine(line);
1935:            }
1936:
1937:            public void modified() {
1938:                if (!rwlock.isWriteLocked()) {
1939:                    Log
1940:                            .error("----- modified() called without write lock -----");
1941:                    Debug.dumpStack();
1942:                }
1943:                if (modCount > saveModCount) {
1944:                    // Already modified.
1945:                    incrementModCount();
1946:                } else {
1947:                    // First change.
1948:                    setModCount(saveModCount + 1);
1949:                    Sidebar
1950:                            .setUpdateFlagInAllFrames(SIDEBAR_MODIFIED_BUFFER_COUNT);
1951:                    Sidebar.repaintBufferListInAllFrames();
1952:                }
1953:                invalidate();
1954:            }
1955:
1956:            public void unmodified() {
1957:                setModCount(0);
1958:                saveModCount = 0;
1959:                autosaveModCount = 0;
1960:                Sidebar.setUpdateFlagInAllFrames(SIDEBAR_MODIFIED_BUFFER_COUNT);
1961:                Sidebar.repaintBufferListInAllFrames();
1962:            }
1963:
1964:            public void saved() {
1965:                saveModCount = modCount;
1966:                autosaveModCount = modCount;
1967:                if (isNewFile()) {
1968:                    for (Line line = getFirstLine(); line != null; line = line
1969:                            .next()) {
1970:                        line.setOriginalText(null);
1971:                        line.setNew(false);
1972:                    }
1973:                    setNewFile(false);
1974:                } else {
1975:                    for (Line line = getFirstLine(); line != null; line = line
1976:                            .next()) {
1977:                        if (line.isModified())
1978:                            line.setSaved(true);
1979:                    }
1980:                    if (getBooleanProperty(Property.SHOW_CHANGE_MARKS))
1981:                        repaint();
1982:                }
1983:                backedUp = false; // Ignored for local buffers.
1984:                Sidebar.setUpdateFlagInAllFrames(SIDEBAR_MODIFIED_BUFFER_COUNT);
1985:                Sidebar.repaintBufferListInAllFrames();
1986:                deleteAutosaveFile();
1987:            }
1988:
1989:            public void empty() {
1990:                try {
1991:                    lockWrite();
1992:                } catch (InterruptedException e) {
1993:                    Log.debug(e);
1994:                    return;
1995:                }
1996:                try {
1997:                    _empty();
1998:                } finally {
1999:                    unlockWrite();
2000:                }
2001:                setTags(null);
2002:                // Invalidate any stored views that are referencing the old contents
2003:                // of this buffer.
2004:                if (lastView != null)
2005:                    lastView.invalidate();
2006:                for (EditorIterator it = new EditorIterator(); it.hasNext();) {
2007:                    Editor ed = it.nextEditor();
2008:                    View view = ed.getView(this );
2009:                    if (view != null)
2010:                        view.invalidate();
2011:                    if (ed.getBuffer() == this ) {
2012:                        ed.setDot(null);
2013:                        ed.setMark(null);
2014:                        ed.setTopLine(null);
2015:                    }
2016:                }
2017:            }
2018:
2019:            public void invalidate() {
2020:                needsParsing = true;
2021:                maxColsValid = false;
2022:                setTags(null);
2023:            }
2024:
2025:            public final View getLastView() {
2026:                if (lastView != null)
2027:                    return (View) lastView.clone();
2028:                else
2029:                    return null;
2030:            }
2031:
2032:            public final void setLastView(View view) {
2033:                lastView = (View) view.clone();
2034:            }
2035:
2036:            public void saveView(Editor editor) {
2037:                final View view = saveViewInternal(editor);
2038:                editor.setView(this , view);
2039:                setLastView(view);
2040:            }
2041:
2042:            protected View saveViewInternal(Editor editor) {
2043:                final Display display = editor.getDisplay();
2044:                View view = editor.getView(this );
2045:                if (view == null)
2046:                    view = new View();
2047:                final Position dot = editor.getDot();
2048:                view.dot = dot == null ? null : new Position(dot);
2049:                final Position mark = editor.getMark();
2050:                view.mark = mark == null ? null : new Position(mark);
2051:                view.selection = editor.getSelection();
2052:                view.setColumnSelection(editor.isColumnSelection());
2053:                view.topLine = editor.getTopLine();
2054:                if (view.topLine != null)
2055:                    view.topLineNumber = view.topLine.lineNumber();
2056:                view.pixelsAboveTopLine = display.getPixelsAboveTopLine();
2057:                view.shift = display.shift;
2058:                view.caretCol = display.caretCol;
2059:                view.timestamp = System.currentTimeMillis();
2060:                if (view.dot == null) {
2061:                    view.lineNumber = 0;
2062:                    view.offs = 0;
2063:                } else {
2064:                    view.lineNumber = view.dot.lineNumber();
2065:                    view.offs = view.dot.getOffset();
2066:                }
2067:                return view;
2068:            }
2069:
2070:            public boolean needsParsing() {
2071:                return needsParsing;
2072:            }
2073:
2074:            public final void setNeedsParsing(boolean b) {
2075:                needsParsing = b;
2076:            }
2077:
2078:            public boolean isModified() {
2079:                return modCount != saveModCount;
2080:            }
2081:
2082:            public Line getLine(int lineNumber) {
2083:                if (lineNumber < 0)
2084:                    return null;
2085:                int n = 0;
2086:                Line line = getFirstLine();
2087:                while (line != null && n != lineNumber) {
2088:                    line = line.next();
2089:                    ++n;
2090:                }
2091:                return line;
2092:            }
2093:
2094:            /**
2095:             * Returns position in buffer based on original line number. Never returns
2096:             * null.
2097:             *
2098:             * @param lineNumber        the original line number to look for
2099:             * @param offset            the offset within the line
2100:             * @return                  the position.
2101:             */
2102:            public Position findOriginal(int lineNumber, int offset) {
2103:                if (offset < 0)
2104:                    offset = 0;
2105:                Line line = getFirstLine();
2106:                while (line != null && line.originalLineNumber() != lineNumber)
2107:                    line = line.next();
2108:                if (line != null)
2109:                    return new Position(line, Math.min(offset, line.length()));
2110:                if (line == null) {
2111:                    // We didn't find the exact line we were looking for. Find the
2112:                    // line with the next highest original line number.
2113:                    line = getFirstLine();
2114:                    while (line != null
2115:                            && line.originalLineNumber() < lineNumber)
2116:                        line = line.next();
2117:                }
2118:                if (line != null)
2119:                    return new Position(line, 0);
2120:                return getEnd();
2121:            }
2122:
2123:            // Convert position into absolute character offset from start of buffer.
2124:            public int getAbsoluteOffset(Position pos) {
2125:                Line targetLine = pos.getLine();
2126:                int offset = 0;
2127:                Line line = getFirstLine();
2128:                while (line != null && line != targetLine) {
2129:                    offset += line.length() + 1;
2130:                    line = line.next();
2131:                }
2132:                if (line == null)
2133:                    return -1; // Line not in buffer.
2134:                else
2135:                    return offset + pos.getOffset();
2136:            }
2137:
2138:            // Convert absolute character offset from start of buffer into position.
2139:            public Position getPosition(int goal) {
2140:                int offset = 0;
2141:                Line line = getFirstLine();
2142:                while (line != null) {
2143:                    // Line separator always counts as 1.
2144:                    offset += line.length() + 1;
2145:                    if (offset >= goal) {
2146:                        if (offset == goal)
2147:                            line = line.next();
2148:                        break;
2149:                    }
2150:                    line = line.next();
2151:                }
2152:                if (line == null)
2153:                    return null; // We hit the end of the buffer without reaching our goal.
2154:                if (offset == goal)
2155:                    return new Position(line, 0);
2156:                offset -= line.length() + 1;
2157:                return new Position(line, goal - offset);
2158:            }
2159:
2160:            private UndoManager undoManager;
2161:
2162:            protected void initializeUndo() {
2163:                undoManager = new UndoManager();
2164:            }
2165:
2166:            public void resetUndo() {
2167:                if (supportsUndo)
2168:                    undoManager.discardAllEdits();
2169:            }
2170:
2171:            public void resetRedo() {
2172:            }
2173:
2174:            public final UndoManager getUndoManager() {
2175:                return undoManager;
2176:            }
2177:
2178:            public final void addEdit(UndoableEdit edit) {
2179:                if (undoManager != null)
2180:                    undoManager.addEdit(edit);
2181:            }
2182:
2183:            public final void addUndoBoundary() {
2184:                if (undoManager != null)
2185:                    undoManager.addEdit(UndoBoundary.getInstance());
2186:            }
2187:
2188:            public final void appendUndoFold(Editor editor) {
2189:                if (undoManager != null)
2190:                    undoManager.appendUndoFold(editor);
2191:            }
2192:
2193:            public boolean canUndo() {
2194:                return (undoManager != null && undoManager.canUndo());
2195:            }
2196:
2197:            public void undo() {
2198:                if (undoManager != null) {
2199:                    if (needsRenumbering)
2200:                        renumber();
2201:                    try {
2202:                        undoManager.undo();
2203:                    } catch (CannotUndoException e) {
2204:                        Editor.currentEditor().status("Nothing to undo");
2205:                    }
2206:                }
2207:            }
2208:
2209:            public boolean canRedo() {
2210:                return (undoManager != null && undoManager.canRedo());
2211:            }
2212:
2213:            public void redo() {
2214:                if (undoManager != null) {
2215:                    if (needsRenumbering)
2216:                        renumber();
2217:                    try {
2218:                        undoManager.redo();
2219:                    } catch (CannotRedoException e) {
2220:                        Editor.currentEditor().status("Nothing to redo");
2221:                    }
2222:                }
2223:            }
2224:
2225:            public CompoundEdit beginCompoundEdit() {
2226:                if (supportsUndo) {
2227:                    CompoundEdit compoundEdit = new CompoundEdit();
2228:                    undoManager.addEdit(compoundEdit);
2229:                    return compoundEdit;
2230:                } else
2231:                    return null;
2232:            }
2233:
2234:            public void endCompoundEdit(CompoundEdit compoundEdit) {
2235:                if (compoundEdit != null)
2236:                    compoundEdit.end();
2237:            }
2238:
2239:            protected void setText(String text) {
2240:                try {
2241:                    lockWrite();
2242:                } catch (InterruptedException e) {
2243:                    Log.debug(e);
2244:                    return;
2245:                }
2246:                try {
2247:                    empty();
2248:                    if (text != null) {
2249:                        FastStringReader reader = new FastStringReader(text);
2250:                        String s;
2251:                        while ((s = reader.readLine()) != null)
2252:                            appendLine(s);
2253:                    }
2254:                    if (getFirstLine() == null)
2255:                        appendLine("");
2256:                    renumber();
2257:                    invalidate();
2258:                    setLoaded(true);
2259:                } finally {
2260:                    unlockWrite();
2261:                }
2262:            }
2263:
2264:            // Inserts s at pos, moves pos past s.
2265:            public void insertString(Position pos, String s) {
2266:                try {
2267:                    lockWrite();
2268:                } catch (InterruptedException e) {
2269:                    Log.error(e);
2270:                    return;
2271:                }
2272:                try {
2273:                    FastStringBuffer sb = new FastStringBuffer();
2274:                    final int limit = s.length();
2275:                    boolean skipLF = false;
2276:                    for (int i = 0; i < limit; i++) {
2277:                        char c = s.charAt(i);
2278:                        if (c == '\r') {
2279:                            if (sb.length() > 0) {
2280:                                insertChars(pos, sb.toString());
2281:                                sb.setLength(0);
2282:                            }
2283:                            insertLineSeparator(pos);
2284:                            skipLF = true;
2285:                        } else if (c == '\n') {
2286:                            if (skipLF) {
2287:                                skipLF = false;
2288:                            } else {
2289:                                if (sb.length() > 0) {
2290:                                    insertChars(pos, sb.toString());
2291:                                    sb.setLength(0);
2292:                                }
2293:                                insertLineSeparator(pos);
2294:                            }
2295:                        } else {
2296:                            skipLF = false;
2297:                            sb.append(c);
2298:                        }
2299:                    }
2300:                    if (sb.length() > 0)
2301:                        insertChars(pos, sb.toString());
2302:                } finally {
2303:                    unlockWrite();
2304:                }
2305:            }
2306:
2307:            // Inserts s at pos, moves pos past s.
2308:            // String must not contain a line separator!
2309:            public void insertChars(Position pos, String s) {
2310:                final int length = s.length();
2311:                if (length > 0) {
2312:                    String text = pos.getLine().getText();
2313:                    FastStringBuffer sb = new FastStringBuffer(text.length()
2314:                            + length);
2315:                    sb.append(text.substring(0, pos.getOffset()));
2316:                    sb.append(s);
2317:                    sb.append(text.substring(pos.getOffset()));
2318:                    pos.getLine().setText(sb.toString());
2319:                    pos.skip(length);
2320:                    modified();
2321:                }
2322:            }
2323:
2324:            public void insertLineSeparator(Position pos) {
2325:                final Line line = pos.getLine();
2326:                final int offset = pos.getOffset();
2327:                if (offset == 0) {
2328:                    final Line newLine = new TextLine("");
2329:                    newLine.setNew(true);
2330:                    // Assume that the line flags should carry over to the new line.
2331:                    newLine.setFlags(line.flags());
2332:                    final Line prevLine = line.previous();
2333:                    newLine.setPrevious(prevLine);
2334:                    if (prevLine != null) {
2335:                        prevLine.setNext(newLine);
2336:                    } else {
2337:                        Debug.assertTrue(line == getFirstLine());
2338:                        setFirstLine(newLine);
2339:                    }
2340:                    newLine.setNext(line);
2341:                    line.setPrevious(newLine);
2342:                } else if (offset == line.length()) {
2343:                    final Line newLine = new TextLine("");
2344:                    newLine.setNew(true);
2345:                    // Assume that the line flags should carry over to the new line.
2346:                    newLine.setFlags(line.flags());
2347:                    final Line prevLine = line;
2348:                    final Line nextLine = line.next();
2349:                    newLine.setPrevious(prevLine);
2350:                    if (prevLine != null) {
2351:                        prevLine.setNext(newLine);
2352:                    } else {
2353:                        Debug.assertTrue(line == getFirstLine());
2354:                        setFirstLine(newLine);
2355:                    }
2356:                    newLine.setNext(nextLine);
2357:                    if (nextLine != null)
2358:                        nextLine.setPrevious(newLine);
2359:                    pos.moveTo(newLine, 0);
2360:                } else {
2361:                    final String head = line.substring(0, offset);
2362:                    final String tail = line.substring(offset);
2363:                    line.setText(head);
2364:                    final Line nextLine = line.next();
2365:                    final Line newLine = new TextLine(tail);
2366:                    newLine.setNew(true);
2367:                    // Assume that the line flags should carry over to the new line.
2368:                    newLine.setFlags(line.flags());
2369:                    line.setNext(newLine);
2370:                    newLine.setPrevious(line);
2371:                    newLine.setNext(nextLine);
2372:                    if (nextLine != null)
2373:                        nextLine.setPrevious(newLine);
2374:                    pos.moveTo(newLine, 0);
2375:                }
2376:                needsRenumbering = true;
2377:                modified();
2378:                repaint();
2379:            }
2380:
2381:            // Repaint all windows displaying this buffer.
2382:            public final void repaint() {
2383:                for (EditorIterator it = new EditorIterator(); it.hasNext();) {
2384:                    Editor ed = it.nextEditor();
2385:                    if (ed.getBuffer() == this )
2386:                        ed.repaintDisplay();
2387:                }
2388:            }
2389:
2390:            public String getTitle() {
2391:                if (title != null)
2392:                    return title;
2393:                final File file = getFile();
2394:                if (file != null)
2395:                    return file.netPath();
2396:                else
2397:                    return "";
2398:            }
2399:
2400:            public final void setTitle(String s) {
2401:                title = s;
2402:            }
2403:
2404:            public String getFileNameForDisplay() {
2405:                final File file = getFile();
2406:                if (file != null)
2407:                    return file.isRemote() ? file.netPath() : file
2408:                            .canonicalPath();
2409:                return "";
2410:            }
2411:
2412:            // For the buffer list.
2413:            public String toString() {
2414:                if (title != null)
2415:                    return title;
2416:                final File file = getFile();
2417:                if (file == null) {
2418:                    // This case should be handled by toString() in the derived class.
2419:                    return null;
2420:                }
2421:                if (file instanceof  HttpFile)
2422:                    return file.netPath();
2423:                if (file.isRemote()) {
2424:                    // SSH, FTP.
2425:                    FastStringBuffer sb = new FastStringBuffer(file.getName());
2426:                    sb.append(" [");
2427:                    sb.append(file.netPath());
2428:                    sb.append(']');
2429:                    return sb.toString();
2430:                }
2431:                // Local file.
2432:                if (file.isDirectory())
2433:                    return file.canonicalPath();
2434:                return Editor.getBufferList().getUniqueName(this );
2435:            }
2436:
2437:            // For the buffer list.
2438:            public Icon getIcon() {
2439:                if (isModified())
2440:                    return Utilities.getIconFromFile("modified.png");
2441:                else if (isReadOnly())
2442:                    return Utilities.getIconFromFile("read_only.png");
2443:                else
2444:                    return Utilities.getIconFromFile("buffer.png");
2445:            }
2446:
2447:            public final int getCol(Position pos) {
2448:                return getCol(pos.getLine(), pos.getOffset());
2449:            }
2450:
2451:            // Returns the absolute column for a given line and offset, based on the
2452:            // tab width of the buffer.
2453:            public final int getCol(Line line, int offset) {
2454:                return getCol(line, offset, getTabWidth());
2455:            }
2456:
2457:            public final static int getCol(Line line, int offset, int tabWidth) {
2458:                final int limit = Math.min(offset, line.length());
2459:                int col = 0;
2460:                for (int i = 0; i < limit; i++) {
2461:                    if (line.charAt(i) == '\t')
2462:                        col += tabWidth - col % tabWidth;
2463:                    else
2464:                        ++col;
2465:                }
2466:                return col;
2467:            }
2468:
2469:            // Return existing indentation of line (number of columns).
2470:            public int getIndentation(Line line) {
2471:                int indent = 0;
2472:                final int tabWidth = getTabWidth();
2473:                final int limit = line.length();
2474:                for (int i = 0; i < limit; i++) {
2475:                    char c = line.charAt(i);
2476:                    if (c == '\t')
2477:                        indent += tabWidth - indent % tabWidth;
2478:                    else if (c == ' ')
2479:                        ++indent;
2480:                    else
2481:                        break;
2482:                }
2483:                return indent;
2484:            }
2485:
2486:            // No write locking, does not call modified().
2487:            public void setIndentation(Line line, int indent) {
2488:                // Skip over existing indentation.
2489:                final int length = line.length();
2490:                int i = 0;
2491:                while (i < length && Character.isWhitespace(line.charAt(i)))
2492:                    ++i;
2493:                if (i < length) {
2494:                    String remainder = line.substring(i);
2495:                    if (indent > 0) {
2496:                        // Put required indentation into stringbuffer.
2497:                        FastStringBuffer sb = getCorrectIndentationString(indent);
2498:                        sb.append(remainder);
2499:                        line.setText(sb.toString());
2500:                    } else
2501:                        line.setText(remainder);
2502:                } else
2503:                    line.setText("");
2504:            }
2505:
2506:            public FastStringBuffer getCorrectIndentationString(int indent) {
2507:                FastStringBuffer sb = new FastStringBuffer(256);
2508:                if (getUseTabs()) {
2509:                    final int tabWidth = getTabWidth();
2510:                    int col = 0;
2511:                    while (col + tabWidth <= indent) {
2512:                        sb.append('\t');
2513:                        col += tabWidth;
2514:                    }
2515:                    while (col < indent) {
2516:                        sb.append(' ');
2517:                        ++col;
2518:                    }
2519:                } else
2520:                    sb.append(Utilities.spaces(indent));
2521:                return sb;
2522:            }
2523:
2524:            private boolean folded;
2525:
2526:            public final void renumber() {
2527:                folded = false;
2528:                lineCount = 0;
2529:                visibleLineCount = 0;
2530:                for (Line line = getFirstLine(); line != null; line = line
2531:                        .next()) {
2532:                    line.setLineNumber(lineCount++);
2533:                    if (line.isHidden())
2534:                        folded = true;
2535:                    else
2536:                        ++visibleLineCount;
2537:                }
2538:                needsRenumbering = false;
2539:            }
2540:
2541:            protected void renumberOriginal() {
2542:                folded = false;
2543:                lineCount = 0;
2544:                visibleLineCount = 0;
2545:                for (Line line = getFirstLine(); line != null; line = line
2546:                        .next()) {
2547:                    line.setOriginalLineNumber(lineCount);
2548:                    line.setLineNumber(lineCount++);
2549:                    if (line.isHidden())
2550:                        folded = true;
2551:                    else
2552:                        ++visibleLineCount;
2553:                }
2554:                needsRenumbering = false;
2555:            }
2556:
2557:            protected void enforceOutputLimit(Property property) {
2558:                Debug.assertTrue(property != null);
2559:                final int outputLimit = Editor.preferences()
2560:                        .getIntegerProperty(property);
2561:                if (outputLimit == 0 || lineCount <= outputLimit)
2562:                    return;
2563:                try {
2564:                    lockWrite();
2565:                } catch (InterruptedException e) {
2566:                    Log.error(e);
2567:                    return;
2568:                }
2569:                try {
2570:                    Position begin = new Position(getFirstLine(), 0);
2571:                    Line line = getFirstLine();
2572:                    for (int i = lineCount - outputLimit; i > 0; i--) {
2573:                        if (line.next() == null)
2574:                            break;
2575:                        line = line.next();
2576:                    }
2577:                    Position end = new Position(line, 0);
2578:                    Region r = new Region(this , begin, end);
2579:                    r.delete();
2580:                    if (needsRenumbering)
2581:                        renumber();
2582:                    resetUndo();
2583:                } finally {
2584:                    unlockWrite();
2585:                }
2586:            }
2587:
2588:            public void saveProperties() {
2589:                if (type != TYPE_NORMAL)
2590:                    return;
2591:                if (isUntitled)
2592:                    return;
2593:                final File file = getFile();
2594:                if (file == null)
2595:                    return;
2596:                final String netPath = file.netPath();
2597:                // Name must not contain any characters that can't appear in an XML
2598:                // attribute value. In particular, an HTTP query might contain '&'.
2599:                if (netPath.indexOf('<') >= 0 || netPath.indexOf('&') >= 0)
2600:                    return;
2601:                FileHistoryEntry entry = new FileHistoryEntry();
2602:                entry.setName(netPath);
2603:                entry.setEncoding(file.getEncoding());
2604:                entry.setMode(mode.toString());
2605:                entry.setWhen(System.currentTimeMillis());
2606:                entry.setProperties(properties);
2607:                FileHistory fileHistory = FileHistory.getFileHistory();
2608:                fileHistory.store(entry);
2609:                fileHistory.save();
2610:            }
2611:
2612:            public void windowClosing() {
2613:            }
2614:
2615:            public void dispose() {
2616:                if (cache != null && cache.isFile()) {
2617:                    // Only delete the cache file if no other buffer is using it.
2618:                    for (BufferIterator it = new BufferIterator(); it.hasNext();) {
2619:                        Buffer buf = it.nextBuffer();
2620:                        if (buf != this  && buf.getCache() == cache)
2621:                            return;
2622:                    }
2623:                    // Not in use. OK to delete.
2624:                    cache.delete();
2625:                }
2626:            }
2627:
2628:            protected void finalize() throws Throwable {
2629:                try {
2630:                    lockWrite();
2631:                } catch (InterruptedException e) {
2632:                    Log.debug(e);
2633:                    return;
2634:                }
2635:                try {
2636:                    empty();
2637:                } finally {
2638:                    unlockWrite();
2639:                }
2640:                super .finalize();
2641:            }
2642:
2643:            public final boolean canBeRestored() {
2644:                final File file = getFile();
2645:                if (file != null && file.isRemote())
2646:                    return false;
2647:                if (this  instanceof  RemoteBuffer)
2648:                    return false;
2649:                switch (type) {
2650:                case TYPE_NORMAL:
2651:                case TYPE_ARCHIVE:
2652:                case TYPE_DIRECTORY:
2653:                    return true;
2654:                default:
2655:                    return false;
2656:                }
2657:            }
2658:
2659:            public final boolean isUntitled() {
2660:                return isUntitled;
2661:            }
2662:
2663:            private boolean isTransient;
2664:
2665:            public boolean isTransient() {
2666:                return isTransient;
2667:            }
2668:
2669:            public final void setTransient(boolean b) {
2670:                unsplitOnClose = isTransient = b;
2671:            }
2672:
2673:            private boolean unsplitOnClose;
2674:
2675:            public boolean unsplitOnClose() {
2676:                return unsplitOnClose;
2677:            }
2678:
2679:            public final void setUnsplitOnClose(boolean b) {
2680:                unsplitOnClose = b;
2681:            }
2682:
2683:            // Cache for getText().
2684:            private SoftReference srText;
2685:
2686:            // Never returns null.
2687:            public synchronized String getText() {
2688:                if (srText != null) {
2689:                    final String text = (String) srText.get();
2690:                    if (text != null)
2691:                        return text;
2692:                }
2693:                FastStringBuffer sb = new FastStringBuffer(16384);
2694:                Line line = getFirstLine();
2695:                if (line != null) {
2696:                    String text = line.getText();
2697:                    if (text != null)
2698:                        sb.append(text);
2699:                    line = line.next();
2700:                    while (line != null) {
2701:                        text = line.getText();
2702:                        if (text != null) {
2703:                            sb.append('\n');
2704:                            sb.append(text);
2705:                        }
2706:                        line = line.next();
2707:                    }
2708:                }
2709:                final String text = sb.toString();
2710:                srText = new SoftReference(text);
2711:                return text;
2712:            }
2713:
2714:            public boolean isEmpty() {
2715:                Line first = getFirstLine();
2716:                if (first == null)
2717:                    return true;
2718:                if (first.next() != null)
2719:                    return false;
2720:                return first.length() == 0;
2721:            }
2722:
2723:            public int getDisplayHeight() {
2724:                return visibleLineCount * Display.getCharHeight();
2725:            }
2726:
2727:            // Returns cumulative height to top of target line.
2728:            public int getY(Line line) {
2729:                Debug.assertTrue(!line.isHidden());
2730:                if (folded) {
2731:                    final int charHeight = Display.getCharHeight();
2732:                    int y = 0;
2733:                    for (Line l = getFirstLine(); l != null; l = l
2734:                            .nextVisible()) {
2735:                        if (l == line)
2736:                            break;
2737:                        else
2738:                            y += charHeight;
2739:                    }
2740:                    return y;
2741:                } else
2742:                    return line.lineNumber() * Display.getCharHeight();
2743:            }
2744:
2745:            public int getDisplayWidth() {
2746:                return Display.getGutterWidth(this ) + (getMaximumColumns() + 1)
2747:                        * Display.getCharWidth();
2748:            }
2749:
2750:            private int maxCols = 0;
2751:            private boolean maxColsValid = false;
2752:
2753:            public int getMaximumColumns() {
2754:                if (maxCols == 0) {
2755:                    maxCols = calculateMaximumColumns();
2756:                    maxColsValid = true;
2757:                }
2758:                return maxCols;
2759:            }
2760:
2761:            private int calculateMaximumColumns() {
2762:                if (getModeId() == BINARY_MODE)
2763:                    return getFirstLine().length();
2764:                final int tabWidth = getTabWidth();
2765:                int max = 0;
2766:                for (Line line = getFirstLine(); line != null; line = line
2767:                        .next()) {
2768:                    int cols;
2769:                    if ((cols = getCol(line, line.length(), tabWidth)) > max)
2770:                        max = cols;
2771:                }
2772:                return max;
2773:            }
2774:
2775:            // Returns true if there was a change.
2776:            public boolean validateMaximumColumns() {
2777:                if (maxColsValid)
2778:                    return false;
2779:                final int oldMaxCols = maxCols;
2780:                maxCols = calculateMaximumColumns();
2781:                maxColsValid = true;
2782:                return maxCols != oldMaxCols;
2783:            }
2784:
2785:            public void setProperty(Property property, Object value) {
2786:                properties.setProperty(property, value);
2787:            }
2788:
2789:            public void setProperty(Property property, boolean value) {
2790:                properties.setProperty(property, value);
2791:            }
2792:
2793:            public void setProperty(Property property, int value) {
2794:                properties.setProperty(property, value);
2795:            }
2796:
2797:            boolean setPropertyFromString(Property property, String value) {
2798:                return properties.setPropertyFromString(property, value);
2799:            }
2800:
2801:            boolean removeProperty(Property property) {
2802:                return properties.removeProperty(property);
2803:            }
2804:
2805:            public String getStringProperty(Property property) {
2806:                Object value = properties.getProperty(property);
2807:                if (value instanceof  String)
2808:                    return (String) value;
2809:                if (mode != null)
2810:                    return mode.getStringProperty(property);
2811:                return (String) property.getDefaultValue();
2812:            }
2813:
2814:            public int getIntegerProperty(Property property) {
2815:                if (!property.isIntegerProperty())
2816:                    Debug.bug();
2817:                Object value = properties.getProperty(property);
2818:                if (value instanceof  Integer)
2819:                    return ((Integer) value).intValue();
2820:                if (mode != null)
2821:                    return mode.getIntegerProperty(property);
2822:                return ((Integer) property.getDefaultValue()).intValue();
2823:            }
2824:
2825:            public boolean getBooleanProperty(Property property) {
2826:                if (!property.isBooleanProperty())
2827:                    Debug.bug();
2828:                Object value = properties.getProperty(property);
2829:                if (value == Boolean.TRUE)
2830:                    return true;
2831:                if (value == Boolean.FALSE)
2832:                    return false;
2833:                if (mode != null)
2834:                    return mode.getBooleanProperty(property);
2835:                return ((Boolean) property.getDefaultValue()).booleanValue();
2836:            }
2837:
2838:            public final int getTabWidth() {
2839:                return getIntegerProperty(Property.TAB_WIDTH);
2840:            }
2841:
2842:            public void setTabWidth(int tabWidth) {
2843:                properties.setProperty(Property.TAB_WIDTH, tabWidth);
2844:            }
2845:
2846:            public final boolean getUseTabs() {
2847:                return getBooleanProperty(Property.USE_TABS);
2848:            }
2849:
2850:            public final int getIndentSize() {
2851:                return getIntegerProperty(Property.INDENT_SIZE);
2852:            }
2853:
2854:            public final void setIndentSize(int indentSize) {
2855:                properties.setProperty(Property.INDENT_SIZE, indentSize);
2856:            }
2857:
2858:            private static final Cursor textCursor = Cursor
2859:                    .getPredefinedCursor(Cursor.TEXT_CURSOR);
2860:
2861:            public Cursor getDefaultCursor() {
2862:                return textCursor;
2863:            }
2864:
2865:            public Cursor getDefaultCursor(Position pos) {
2866:                if (pos == null || pos.getLine() instanceof  ImageLine)
2867:                    return Cursor.getDefaultCursor();
2868:                else
2869:                    return textCursor;
2870:            }
2871:
2872:            public String getStatusText(Editor editor) {
2873:                Debug.assertTrue(editor.getBuffer() == this );
2874:                Position dot = editor.getDotCopy();
2875:                if (dot == null)
2876:                    return null;
2877:                final FastStringBuffer sb = new FastStringBuffer();
2878:                if (cvsEntry != null) {
2879:                    sb.append("CVS ");
2880:                    final String revision = cvsEntry.getRevision();
2881:                    if (revision.equals("0")) {
2882:                        sb.append('A');
2883:                    } else {
2884:                        sb.append(revision);
2885:                        if (cvsEntry.getCheckoutTime() != lastModified)
2886:                            sb.append(" M");
2887:                    }
2888:                    sb.append("   ");
2889:                }
2890:                if (Editor.preferences().getBooleanProperty(
2891:                        Property.STATUS_BAR_DISPLAY_LINE_SEPARATOR)) {
2892:                    if (lineSeparator != null) {
2893:                        if (lineSeparator.equals("\n"))
2894:                            sb.append("LF   ");
2895:                        else if (lineSeparator.equals("\r\n"))
2896:                            sb.append("CR+LF   ");
2897:                        else if (lineSeparator.equals("\r"))
2898:                            sb.append("CR   ");
2899:                    }
2900:                }
2901:                sb.append("Line ");
2902:                sb.append(String.valueOf(dot.lineNumber() + 1));
2903:                if (Editor.preferences().getBooleanProperty(
2904:                        Property.STATUS_BAR_DISPLAY_LINE_COUNT)) {
2905:                    sb.append(" of ");
2906:                    sb.append(String.valueOf(getLineCount()));
2907:                }
2908:                sb.append("  Col ");
2909:                final Display display = editor.getDisplay();
2910:                sb.append(String.valueOf(display.getAbsoluteCaretCol() + 1));
2911:                if (getBooleanProperty(Property.WRAP))
2912:                    sb.append("   Wrap");
2913:                if (Editor.isRecordingMacro())
2914:                    sb.append("   [Recording macro...]");
2915:                return sb.toString();
2916:            }
2917:
2918:            public Expansion getExpansion(Position dot) {
2919:                return new Expansion(dot, mode);
2920:            }
2921:
2922:            public void restoreView(Editor editor) {
2923:                final Display display = editor.getDisplay();
2924:                final View view = editor.getView(this );
2925:                Debug.assertTrue(view != null);
2926:                if (view != null) {
2927:                    if (view.getDot() == null) {
2928:                        Line line = getLine(view.getDotLineNumber());
2929:                        if (line != null) {
2930:                            int offset = view.getDotOffset();
2931:                            if (offset < 0)
2932:                                offset = 0;
2933:                            else if (offset > line.length())
2934:                                offset = line.length();
2935:                            view.setDot(new Position(line, offset));
2936:                        } else {
2937:                            line = getFirstLine();
2938:                            if (line != null)
2939:                                view.setDot(new Position(line, 0));
2940:                        }
2941:                    }
2942:                    editor.setDot(view.getDot() == null ? null : new Position(
2943:                            view.getDot()));
2944:                    editor.setMark(view.getMark() == null ? null
2945:                            : new Position(view.getMark()));
2946:                    editor.setSelection(view.getSelection());
2947:                    editor.setColumnSelection(view.isColumnSelection());
2948:                    if (view.getTopLine() == null) {
2949:                        view.topLine = getFirstLine();
2950:                        view.pixelsAboveTopLine = 0;
2951:                    }
2952:                    display.setTopLine(view.getTopLine());
2953:                    display.setPixelsAboveTopLine(view.pixelsAboveTopLine);
2954:                    display.setShift(view.getShift());
2955:                    display.setCaretCol(view.getCaretCol());
2956:                }
2957:            }
2958:
2959:            private CVSEntry cvsEntry;
2960:
2961:            public final CVSEntry getCVSEntry() {
2962:                return cvsEntry;
2963:            }
2964:
2965:            public final void checkCVS() {
2966:                cvsEntry = CVSEntry.parseEntryForFile(getFile());
2967:            }
2968:
2969:            public final boolean isKeyword(String s) {
2970:                return mode.isKeyword(s);
2971:            }
2972:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.