Source Code Cross Referenced for SearchAndReplace.java in  » Swing-Library » jEdit » org » gjt » sp » jedit » search » 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 » Swing Library » jEdit » org.gjt.sp.jedit.search 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * SearchAndReplace.java - Search and replace
0003:         * :tabSize=8:indentSize=8:noTabs=false:
0004:         * :folding=explicit:collapseFolds=1:
0005:         *
0006:         * Copyright (C) 1999, 2004 Slava Pestov
0007:         * Portions copyright (C) 2001 Tom Locke
0008:         *
0009:         * This program is free software; you can redistribute it and/or
0010:         * modify it under the terms of the GNU General Public License
0011:         * as published by the Free Software Foundation; either version 2
0012:         * of the License, or any later version.
0013:         *
0014:         * This program is distributed in the hope that it will be useful,
0015:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
0016:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0017:         * GNU General Public License for more details.
0018:         *
0019:         * You should have received a copy of the GNU General Public License
0020:         * along with this program; if not, write to the Free Software
0021:         * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
0022:         */
0023:
0024:        package org.gjt.sp.jedit.search;
0025:
0026:        //{{{ Imports
0027:        import org.gjt.sp.jedit.bsh.*;
0028:        import java.awt.*;
0029:        import javax.swing.JOptionPane;
0030:        import javax.swing.text.Segment;
0031:        import org.gjt.sp.jedit.*;
0032:        import org.gjt.sp.jedit.gui.TextAreaDialog;
0033:        import org.gjt.sp.jedit.io.VFSManager;
0034:        import org.gjt.sp.jedit.msg.SearchSettingsChanged;
0035:        import org.gjt.sp.jedit.textarea.*;
0036:        import org.gjt.sp.jedit.TextUtilities;
0037:        import org.gjt.sp.util.SegmentCharSequence;
0038:        import org.gjt.sp.util.Log;
0039:
0040:        //}}}
0041:
0042:        /**
0043:         * Class that implements regular expression and literal search within
0044:         * jEdit buffers.<p>
0045:         *
0046:         * There are two main groups of methods in this class:
0047:         * <ul>
0048:         * <li>Property accessors - for changing search and replace settings.</li>
0049:         * <li>Actions - for performing search and replace.</li>
0050:         * </ul>
0051:         *
0052:         * The "HyperSearch" and "Keep dialog" features, as reflected in
0053:         * checkbox options in the search dialog, are not handled from within
0054:         * this class. If you wish to have these options set before the search dialog
0055:         * appears, make a prior call to either or both of the following:
0056:         *
0057:         * <pre> jEdit.setBooleanProperty("search.hypersearch.toggle",true);
0058:         * jEdit.setBooleanProperty("search.keepDialog.toggle",true);</pre>
0059:         *
0060:         * If you are not using the dialog to undertake a search or replace, you may
0061:         * call any of the search and replace methods (including
0062:         * {@link #hyperSearch(View)}) without concern for the value of these
0063:         * properties.
0064:         *
0065:         * @author Slava Pestov
0066:         * @author John Gellene (API documentation)
0067:         * @version $Id: SearchAndReplace.java 10894 2007-10-15 16:11:39Z mediumnet $
0068:         */
0069:        public class SearchAndReplace {
0070:            //{{{ Getters and setters
0071:
0072:            //{{{ setSearchString() method
0073:            /**
0074:             * Sets the current search string.
0075:             * @param search The new search string
0076:             */
0077:            public static void setSearchString(String search) {
0078:                if (search.equals(SearchAndReplace.search))
0079:                    return;
0080:
0081:                SearchAndReplace.search = search;
0082:                matcher = null;
0083:
0084:                EditBus.send(new SearchSettingsChanged(null));
0085:            } //}}}
0086:
0087:            //{{{ getSearchString() method
0088:            /**
0089:             * Returns the current search string.
0090:             */
0091:            public static String getSearchString() {
0092:                return search;
0093:            } //}}}
0094:
0095:            //{{{ setReplaceString() method
0096:            /**
0097:             * Sets the current replacement string.
0098:             * @param replace The new replacement string
0099:             */
0100:            public static void setReplaceString(String replace) {
0101:                if (replace.equals(SearchAndReplace.replace))
0102:                    return;
0103:
0104:                SearchAndReplace.replace = replace;
0105:
0106:                EditBus.send(new SearchSettingsChanged(null));
0107:            } //}}}
0108:
0109:            //{{{ getReplaceString() method
0110:            /**
0111:             * Returns the current replacement string.
0112:             */
0113:            public static String getReplaceString() {
0114:                return replace;
0115:            } //}}}
0116:
0117:            //{{{ setIgnoreCase() method
0118:            /**
0119:             * Sets the ignore case flag.
0120:             * @param ignoreCase True if searches should be case insensitive,
0121:             * false otherwise
0122:             */
0123:            public static void setIgnoreCase(boolean ignoreCase) {
0124:                if (ignoreCase == SearchAndReplace.ignoreCase)
0125:                    return;
0126:
0127:                SearchAndReplace.ignoreCase = ignoreCase;
0128:                matcher = null;
0129:
0130:                EditBus.send(new SearchSettingsChanged(null));
0131:            } //}}}
0132:
0133:            //{{{ getIgnoreCase() method
0134:            /**
0135:             * Returns the state of the ignore case flag.
0136:             * @return True if searches should be case insensitive,
0137:             * false otherwise
0138:             */
0139:            public static boolean getIgnoreCase() {
0140:                return ignoreCase;
0141:            } //}}}
0142:
0143:            //{{{ setRegexp() method
0144:            /**
0145:             * Sets the state of the regular expression flag.
0146:             * @param regexp True if regular expression searches should be
0147:             * performed
0148:             */
0149:            public static void setRegexp(boolean regexp) {
0150:                if (regexp == SearchAndReplace.regexp)
0151:                    return;
0152:
0153:                SearchAndReplace.regexp = regexp;
0154:                if (regexp && reverse)
0155:                    reverse = false;
0156:
0157:                matcher = null;
0158:
0159:                EditBus.send(new SearchSettingsChanged(null));
0160:            } //}}}
0161:
0162:            //{{{ getRegexp() method
0163:            /**
0164:             * Returns the state of the regular expression flag.
0165:             * @return True if regular expression searches should be performed
0166:             */
0167:            public static boolean getRegexp() {
0168:                return regexp;
0169:            } //}}}
0170:
0171:            //{{{ setReverseSearch() method
0172:            /**
0173:             * Determines whether a reverse search will conducted from the current
0174:             * position to the beginning of a buffer. Note that reverse search and
0175:             * regular expression search is mutually exclusive; enabling one will
0176:             * disable the other.
0177:             * @param reverse True if searches should go backwards,
0178:             * false otherwise
0179:             */
0180:            public static void setReverseSearch(boolean reverse) {
0181:                if (reverse == SearchAndReplace.reverse)
0182:                    return;
0183:
0184:                SearchAndReplace.reverse = reverse;
0185:
0186:                EditBus.send(new SearchSettingsChanged(null));
0187:            } //}}}
0188:
0189:            //{{{ getReverseSearch() method
0190:            /**
0191:             * Returns the state of the reverse search flag.
0192:             * @return True if searches should go backwards,
0193:             * false otherwise
0194:             */
0195:            public static boolean getReverseSearch() {
0196:                return reverse;
0197:            } //}}}
0198:
0199:            //{{{ setBeanShellReplace() method
0200:            /**
0201:             * Sets the state of the BeanShell replace flag.
0202:             * @param beanshell True if the replace string is a BeanShell expression
0203:             * @since jEdit 3.2pre2
0204:             */
0205:            public static void setBeanShellReplace(boolean beanshell) {
0206:                if (beanshell == SearchAndReplace.beanshell)
0207:                    return;
0208:
0209:                SearchAndReplace.beanshell = beanshell;
0210:
0211:                EditBus.send(new SearchSettingsChanged(null));
0212:            } //}}}
0213:
0214:            //{{{ getBeanShellReplace() method
0215:            /**
0216:             * Returns the state of the BeanShell replace flag.
0217:             * @return True if the replace string is a BeanShell expression
0218:             * @since jEdit 3.2pre2
0219:             */
0220:            public static boolean getBeanShellReplace() {
0221:                return beanshell;
0222:            } //}}}
0223:
0224:            //{{{ setAutoWrap() method
0225:            /**
0226:             * Sets the state of the auto wrap around flag.
0227:             * @param wrap If true, the 'continue search from start' dialog
0228:             * will not be displayed
0229:             * @since jEdit 3.2pre2
0230:             */
0231:            public static void setAutoWrapAround(boolean wrap) {
0232:                if (wrap == SearchAndReplace.wrap)
0233:                    return;
0234:
0235:                SearchAndReplace.wrap = wrap;
0236:
0237:                EditBus.send(new SearchSettingsChanged(null));
0238:            } //}}}
0239:
0240:            //{{{ getAutoWrap() method
0241:            /**
0242:             * Returns the state of the auto wrap around flag.
0243:             * @since jEdit 3.2pre2
0244:             */
0245:            public static boolean getAutoWrapAround() {
0246:                return wrap;
0247:            } //}}}
0248:
0249:            //{{{ setSearchMatcher() method
0250:            /**
0251:             * Sets a custom search string matcher. Note that calling
0252:             * {@link #setSearchString(String)},
0253:             * {@link #setIgnoreCase(boolean)}, or {@link #setRegexp(boolean)}
0254:             * will reset the matcher to the default.
0255:             */
0256:            public static void setSearchMatcher(SearchMatcher matcher) {
0257:                SearchAndReplace.matcher = matcher;
0258:
0259:                EditBus.send(new SearchSettingsChanged(null));
0260:            } //}}}
0261:
0262:            //{{{ getSearchMatcher() method
0263:            /**
0264:             * Returns the current search string matcher.
0265:             * @return a SearchMatcher or null if there is no search or if the matcher can match empty String
0266:             *
0267:             * @exception IllegalArgumentException if regular expression search
0268:             * is enabled, the search string or replacement string is invalid
0269:             * @since jEdit 4.1pre7
0270:             */
0271:            public static SearchMatcher getSearchMatcher() throws Exception {
0272:                if (matcher != null)
0273:                    return matcher;
0274:
0275:                if (search == null || "".equals(search))
0276:                    return null;
0277:
0278:                if (regexp)
0279:                    matcher = new PatternSearchMatcher(search, ignoreCase);
0280:                else
0281:                    matcher = new BoyerMooreSearchMatcher(search, ignoreCase);
0282:
0283:                if (matcher.nextMatch("", true, true, true, false) != null) {
0284:                    Log.log(Log.WARNING, SearchAndReplace.class, "The matcher "
0285:                            + matcher + " can match empty string !");
0286:                    matcher = null;
0287:                }
0288:
0289:                return matcher;
0290:            } //}}}
0291:
0292:            //{{{ setSearchFileSet() method
0293:            /**
0294:             * Sets the current search file set.
0295:             * @param fileset The file set to perform searches in
0296:             * @see AllBufferSet
0297:             * @see CurrentBufferSet
0298:             * @see DirectoryListSet
0299:             */
0300:            public static void setSearchFileSet(SearchFileSet fileset) {
0301:                SearchAndReplace.fileset = fileset;
0302:
0303:                EditBus.send(new SearchSettingsChanged(null));
0304:            } //}}}
0305:
0306:            //{{{ getSearchFileSet() method
0307:            /**
0308:             * Returns the current search file set.
0309:             */
0310:            public static SearchFileSet getSearchFileSet() {
0311:                return fileset;
0312:            } //}}}
0313:
0314:            //{{{ getSmartCaseReplace() method
0315:            /**
0316:             * Returns if the replacement string will assume the same case as
0317:             * each specific occurrence of the search string.
0318:             * @since jEdit 4.2pre10
0319:             */
0320:            public static boolean getSmartCaseReplace() {
0321:                return (replace != null && TextUtilities.getStringCase(replace) == TextUtilities.LOWER_CASE);
0322:            } //}}}
0323:
0324:            //}}}
0325:
0326:            //{{{ Actions
0327:
0328:            //{{{ hyperSearch() method
0329:            /**
0330:             * Performs a HyperSearch.
0331:             * @param view The view
0332:             * @since jEdit 2.7pre3
0333:             */
0334:            public static boolean hyperSearch(View view) {
0335:                return hyperSearch(view, false);
0336:            } //}}}
0337:
0338:            //{{{ hyperSearch() method
0339:            /**
0340:             * Performs a HyperSearch.
0341:             * @param view The view
0342:             * @param selection If true, will only search in the current selection.
0343:             * Note that the file set must be the current buffer file set for this
0344:             * to work.
0345:             * @since jEdit 4.0pre1
0346:             */
0347:            public static boolean hyperSearch(View view, boolean selection) {
0348:                // component that will parent any dialog boxes
0349:                Component comp = SearchDialog.getSearchDialog(view);
0350:                if (comp == null)
0351:                    comp = view;
0352:
0353:                record(view, "hyperSearch(view," + selection + ')', false,
0354:                        !selection);
0355:
0356:                view.getDockableWindowManager().addDockableWindow(
0357:                        HyperSearchResults.NAME);
0358:                final HyperSearchResults results = (HyperSearchResults) view
0359:                        .getDockableWindowManager().getDockable(
0360:                                HyperSearchResults.NAME);
0361:                results.searchStarted();
0362:
0363:                try {
0364:                    SearchMatcher matcher = getSearchMatcher();
0365:                    if (matcher == null) {
0366:                        view.getToolkit().beep();
0367:                        results.searchFailed();
0368:                        return false;
0369:                    }
0370:
0371:                    Selection[] s;
0372:                    if (selection) {
0373:                        s = view.getTextArea().getSelection();
0374:                        if (s == null) {
0375:                            results.searchFailed();
0376:                            return false;
0377:                        }
0378:                    } else
0379:                        s = null;
0380:                    VFSManager.runInWorkThread(new HyperSearchRequest(view,
0381:                            matcher, results, s));
0382:                    return true;
0383:                } catch (Exception e) {
0384:                    results.searchFailed();
0385:                    handleError(comp, e);
0386:                    return false;
0387:                }
0388:            } //}}}
0389:
0390:            //{{{ find() method
0391:            /**
0392:             * Finds the next occurrence of the search string.
0393:             * @param view The view
0394:             * @return True if the operation was successful, false otherwise
0395:             */
0396:            public static boolean find(View view) {
0397:                // component that will parent any dialog boxes
0398:                Component comp = SearchDialog.getSearchDialog(view);
0399:                if (comp == null || !comp.isShowing())
0400:                    comp = view;
0401:
0402:                String path = fileset.getNextFile(view, null);
0403:                if (path == null) {
0404:                    GUIUtilities.error(comp, "empty-fileset", null);
0405:                    return false;
0406:                }
0407:
0408:                boolean _reverse = reverse
0409:                        && fileset instanceof  CurrentBufferSet;
0410:                if (_reverse && regexp) {
0411:                    GUIUtilities.error(comp, "regexp-reverse", null);
0412:                    return false;
0413:                }
0414:
0415:                try {
0416:                    view.showWaitCursor();
0417:
0418:                    SearchMatcher matcher = getSearchMatcher();
0419:                    if (matcher == null) {
0420:                        view.getToolkit().beep();
0421:                        return false;
0422:                    }
0423:
0424:                    record(view, "find(view)", false, true);
0425:
0426:                    boolean repeat = false;
0427:                    loop: for (;;) {
0428:                        while (path != null) {
0429:                            Buffer buffer = jEdit.openTemporary(view, null,
0430:                                    path, false);
0431:
0432:                            /* this is stupid and misleading.
0433:                             * but 'path' is not used anywhere except
0434:                             * the above line, and if this is done
0435:                             * after the 'continue', then we will
0436:                             * either hang, or be forced to duplicate
0437:                             * it inside the buffer == null, or add
0438:                             * a 'finally' clause. you decide which one's
0439:                             * worse. */
0440:                            path = fileset.getNextFile(view, path);
0441:
0442:                            if (buffer == null)
0443:                                continue loop;
0444:
0445:                            // Wait for the buffer to load
0446:                            if (!buffer.isLoaded())
0447:                                VFSManager.waitForRequests();
0448:
0449:                            int start;
0450:
0451:                            if (view.getBuffer() == buffer && !repeat) {
0452:                                JEditTextArea textArea = view.getTextArea();
0453:                                Selection s = textArea
0454:                                        .getSelectionAtOffset(textArea
0455:                                                .getCaretPosition());
0456:                                if (s == null)
0457:                                    start = textArea.getCaretPosition();
0458:                                else if (_reverse)
0459:                                    start = s.getStart();
0460:                                else
0461:                                    start = s.getEnd();
0462:                            } else if (_reverse)
0463:                                start = buffer.getLength();
0464:                            else
0465:                                start = 0;
0466:
0467:                            boolean _search = true;
0468:                            if (!_reverse && matcher.isMatchingEOL()) {
0469:                                if (start < buffer.getLength())
0470:                                    start += 1;
0471:                                else
0472:                                    _search = false;
0473:                            }
0474:
0475:                            if (_search
0476:                                    && find(view, buffer, start, repeat,
0477:                                            _reverse))
0478:                                return true;
0479:                        }
0480:
0481:                        if (repeat) {
0482:                            if (!BeanShell.isScriptRunning()) {
0483:                                view
0484:                                        .getStatus()
0485:                                        .setMessageAndClear(
0486:                                                jEdit
0487:                                                        .getProperty("view.status.search-not-found"));
0488:
0489:                                view.getToolkit().beep();
0490:                            }
0491:                            return false;
0492:                        }
0493:
0494:                        boolean restart;
0495:
0496:                        // if auto wrap is on, always restart search.
0497:                        // if auto wrap is off, and we're called from
0498:                        // a macro, stop search. If we're called
0499:                        // interactively, ask the user what to do.
0500:                        if (wrap) {
0501:                            if (!BeanShell.isScriptRunning()) {
0502:                                view
0503:                                        .getStatus()
0504:                                        .setMessageAndClear(
0505:                                                jEdit
0506:                                                        .getProperty("view.status.auto-wrap"));
0507:                                // beep if beep property set
0508:                                if (jEdit
0509:                                        .getBooleanProperty("search.beepOnSearchAutoWrap")) {
0510:                                    view.getToolkit().beep();
0511:                                }
0512:                            }
0513:                            restart = true;
0514:                        } else if (BeanShell.isScriptRunning()) {
0515:                            restart = false;
0516:                        } else {
0517:                            Integer[] args = { Integer
0518:                                    .valueOf(_reverse ? 1 : 0) };
0519:                            int result = GUIUtilities.confirm(comp,
0520:                                    "keepsearching", args,
0521:                                    JOptionPane.YES_NO_OPTION,
0522:                                    JOptionPane.QUESTION_MESSAGE);
0523:                            restart = (result == JOptionPane.YES_OPTION);
0524:                        }
0525:
0526:                        if (restart) {
0527:                            // start search from beginning
0528:                            path = fileset.getFirstFile(view);
0529:                            repeat = true;
0530:                        } else
0531:                            break loop;
0532:                    }
0533:                } catch (Exception e) {
0534:                    handleError(comp, e);
0535:                } finally {
0536:                    view.hideWaitCursor();
0537:                }
0538:
0539:                return false;
0540:            } //}}}
0541:
0542:            //{{{ find() method
0543:            /**
0544:             * Finds the next instance of the search string in the specified
0545:             * buffer.
0546:             * @param view The view
0547:             * @param buffer The buffer
0548:             * @param start Location where to start the search
0549:             */
0550:            public static boolean find(View view, Buffer buffer, int start)
0551:                    throws Exception {
0552:                return find(view, buffer, start, false, false);
0553:            } //}}}
0554:
0555:            //{{{ find() method
0556:            /**
0557:             * Finds the next instance of the search string in the specified
0558:             * buffer.
0559:             * @param view The view
0560:             * @param buffer The buffer
0561:             * @param start Location where to start the search
0562:             * @param firstTime See {@link SearchMatcher#nextMatch(CharSequence,boolean,boolean,boolean,boolean)}.
0563:             * @since jEdit 4.1pre7
0564:             */
0565:            public static boolean find(View view, Buffer buffer, int start,
0566:                    boolean firstTime, boolean reverse) throws Exception {
0567:                SearchMatcher matcher = getSearchMatcher();
0568:                if (matcher == null) {
0569:                    view.getToolkit().beep();
0570:                    return false;
0571:                }
0572:
0573:                Segment text = new Segment();
0574:                if (reverse)
0575:                    buffer.getText(0, start, text);
0576:                else
0577:                    buffer.getText(start, buffer.getLength() - start, text);
0578:
0579:                // the start and end flags will be wrong with reverse search enabled,
0580:                // but they are only used by the regexp matcher, which doesn't
0581:                // support reverse search yet.
0582:                //
0583:                // REMIND: fix flags when adding reverse regexp search.
0584:                SearchMatcher.Match match = matcher.nextMatch(
0585:                        new SegmentCharSequence(text, reverse), start == 0,
0586:                        true, firstTime, reverse);
0587:
0588:                if (match != null) {
0589:                    jEdit.commitTemporary(buffer);
0590:                    view.setBuffer(buffer, true);
0591:                    JEditTextArea textArea = view.getTextArea();
0592:
0593:                    if (reverse) {
0594:                        textArea.setSelection(new Selection.Range(start
0595:                                - match.end, start - match.start));
0596:                        // make sure end of match is visible
0597:                        textArea.scrollTo(start - match.start, false);
0598:                        textArea.moveCaretPosition(start - match.end);
0599:                    } else {
0600:                        textArea.setSelection(new Selection.Range(start
0601:                                + match.start, start + match.end));
0602:                        textArea.moveCaretPosition(start + match.end);
0603:                        // make sure start of match is visible
0604:                        textArea.scrollTo(start + match.start, false);
0605:                    }
0606:
0607:                    return true;
0608:                } else
0609:                    return false;
0610:            } //}}}
0611:
0612:            //{{{ replace() method
0613:            /**
0614:             * Replaces the current selection with the replacement string.
0615:             * @param view The view
0616:             * @return True if the operation was successful, false otherwise
0617:             */
0618:            public static boolean replace(View view) {
0619:                // component that will parent any dialog boxes
0620:                Component comp = SearchDialog.getSearchDialog(view);
0621:                if (comp == null)
0622:                    comp = view;
0623:
0624:                JEditTextArea textArea = view.getTextArea();
0625:
0626:                Buffer buffer = view.getBuffer();
0627:                if (!buffer.isEditable())
0628:                    return false;
0629:
0630:                boolean smartCaseReplace = getSmartCaseReplace();
0631:
0632:                Selection[] selection = textArea.getSelection();
0633:                if (selection.length == 0) {
0634:                    try {
0635:                        SearchMatcher matcher = getSearchMatcher();
0636:                        if ((matcher != null) && (matcher.isMatchingEOL())) {
0637:                            int caretPosition = textArea.getCaretPosition();
0638:                            selection = new Selection[] { new Selection.Range(
0639:                                    caretPosition, caretPosition) };
0640:                        } else {
0641:                            view.getToolkit().beep();
0642:                            return false;
0643:                        }
0644:                    } catch (Exception e) {
0645:                        handleError(comp, e);
0646:                        return false;
0647:                    }
0648:                }
0649:
0650:                record(view, "replace(view)", true, false);
0651:
0652:                // a little hack for reverse replace and find
0653:                int caret = textArea.getCaretPosition();
0654:                Selection s = textArea.getSelectionAtOffset(caret);
0655:                if (s != null)
0656:                    caret = s.getStart();
0657:
0658:                try {
0659:                    buffer.beginCompoundEdit();
0660:
0661:                    SearchMatcher matcher = getSearchMatcher();
0662:                    if (matcher == null)
0663:                        return false;
0664:
0665:                    initReplace();
0666:
0667:                    int retVal = 0;
0668:
0669:                    for (int i = 0; i < selection.length; i++) {
0670:                        s = selection[i];
0671:
0672:                        retVal += replaceInSelection(view, textArea, buffer,
0673:                                matcher, smartCaseReplace, s);
0674:                    }
0675:
0676:                    boolean _reverse = !regexp && reverse
0677:                            && fileset instanceof  CurrentBufferSet;
0678:                    if (_reverse) {
0679:                        // so that Replace and Find continues from
0680:                        // the right location
0681:                        textArea.moveCaretPosition(caret);
0682:                    } else {
0683:                        s = textArea.getSelectionAtOffset(textArea
0684:                                .getCaretPosition());
0685:                        if (s != null)
0686:                            textArea.moveCaretPosition(s.getEnd());
0687:                    }
0688:
0689:                    if (!BeanShell.isScriptRunning()) {
0690:                        Object[] args = { Integer.valueOf(retVal),
0691:                                Integer.valueOf(1) };
0692:                        view.getStatus().setMessageAndClear(
0693:                                jEdit.getProperty("view.status.replace-all",
0694:                                        args));
0695:                    }
0696:
0697:                    if (retVal == 0) {
0698:                        view.getToolkit().beep();
0699:                        return false;
0700:                    }
0701:
0702:                    return true;
0703:                } catch (Exception e) {
0704:                    handleError(comp, e);
0705:                } finally {
0706:                    buffer.endCompoundEdit();
0707:                }
0708:
0709:                return false;
0710:            } //}}}
0711:
0712:            //{{{ replace() method
0713:            /**
0714:             * Replaces text in the specified range with the replacement string.
0715:             * @param view The view
0716:             * @param buffer The buffer
0717:             * @param start The start offset
0718:             * @param end The end offset
0719:             * @return True if the operation was successful, false otherwise
0720:             */
0721:            public static boolean replace(View view, Buffer buffer, int start,
0722:                    int end) {
0723:                if (!buffer.isEditable())
0724:                    return false;
0725:
0726:                // component that will parent any dialog boxes
0727:                Component comp = SearchDialog.getSearchDialog(view);
0728:                if (comp == null)
0729:                    comp = view;
0730:
0731:                boolean smartCaseReplace = getSmartCaseReplace();
0732:
0733:                try {
0734:                    buffer.beginCompoundEdit();
0735:
0736:                    SearchMatcher matcher = getSearchMatcher();
0737:                    if (matcher == null)
0738:                        return false;
0739:
0740:                    initReplace();
0741:
0742:                    int retVal = 0;
0743:
0744:                    retVal += _replace(view, buffer, matcher, start, end,
0745:                            smartCaseReplace);
0746:
0747:                    if (retVal != 0)
0748:                        return true;
0749:                } catch (Exception e) {
0750:                    handleError(comp, e);
0751:                } finally {
0752:                    buffer.endCompoundEdit();
0753:                }
0754:
0755:                return false;
0756:            } //}}}
0757:
0758:            //{{{ replaceAll() method
0759:            /**
0760:             * Replaces all occurrences of the search string with the replacement
0761:             * string.
0762:             * @param view The view
0763:             */
0764:            public static boolean replaceAll(View view) {
0765:                return replaceAll(view, false);
0766:            } //}}}
0767:
0768:            //{{{ replaceAll() method
0769:            /**
0770:             * Replaces all occurrences of the search string with the replacement
0771:             * string.
0772:             * @param view The view
0773:             * @param dontOpenChangedFiles Whether to open changed files or to autosave them quietly
0774:             */
0775:            public static boolean replaceAll(View view,
0776:                    boolean dontOpenChangedFiles) {
0777:                // component that will parent any dialog boxes
0778:                Component comp = SearchDialog.getSearchDialog(view);
0779:                if (comp == null)
0780:                    comp = view;
0781:
0782:                if (fileset.getFileCount(view) == 0) {
0783:                    GUIUtilities.error(comp, "empty-fileset", null);
0784:                    return false;
0785:                }
0786:
0787:                record(view, "replaceAll(view)", true, true);
0788:
0789:                view.showWaitCursor();
0790:
0791:                boolean smartCaseReplace = (replace != null && TextUtilities
0792:                        .getStringCase(replace) == TextUtilities.LOWER_CASE);
0793:
0794:                int fileCount = 0;
0795:                int occurCount = 0;
0796:                try {
0797:                    SearchMatcher matcher = getSearchMatcher();
0798:                    if (matcher == null)
0799:                        return false;
0800:
0801:                    initReplace();
0802:
0803:                    String path = fileset.getFirstFile(view);
0804:                    loop: while (path != null) {
0805:                        Buffer buffer = jEdit.openTemporary(view, null, path,
0806:                                false);
0807:
0808:                        /* this is stupid and misleading.
0809:                         * but 'path' is not used anywhere except
0810:                         * the above line, and if this is done
0811:                         * after the 'continue', then we will
0812:                         * either hang, or be forced to duplicate
0813:                         * it inside the buffer == null, or add
0814:                         * a 'finally' clause. you decide which one's
0815:                         * worse. */
0816:                        path = fileset.getNextFile(view, path);
0817:
0818:                        if (buffer == null)
0819:                            continue loop;
0820:
0821:                        // Wait for buffer to finish loading
0822:                        if (buffer.isPerformingIO())
0823:                            VFSManager.waitForRequests();
0824:
0825:                        if (!buffer.isEditable())
0826:                            continue loop;
0827:
0828:                        // Leave buffer in a consistent state if
0829:                        // an error occurs
0830:                        int retVal = 0;
0831:
0832:                        try {
0833:                            buffer.beginCompoundEdit();
0834:                            retVal = _replace(view, buffer, matcher, 0, buffer
0835:                                    .getLength(), smartCaseReplace);
0836:                        } finally {
0837:                            buffer.endCompoundEdit();
0838:                        }
0839:
0840:                        if (retVal != 0) {
0841:                            fileCount++;
0842:                            occurCount += retVal;
0843:                            if (dontOpenChangedFiles) {
0844:                                buffer.save(null, null);
0845:                            } else {
0846:                                jEdit.commitTemporary(buffer);
0847:                            }
0848:                        }
0849:                    }
0850:                } catch (Exception e) {
0851:                    handleError(comp, e);
0852:                } finally {
0853:                    view.hideWaitCursor();
0854:                }
0855:
0856:                /* Don't do this when playing a macro, cos it's annoying */
0857:                if (!BeanShell.isScriptRunning()) {
0858:                    Object[] args = { Integer.valueOf(occurCount),
0859:                            Integer.valueOf(fileCount) };
0860:                    view.getStatus().setMessageAndClear(
0861:                            jEdit.getProperty("view.status.replace-all", args));
0862:                    if (occurCount == 0)
0863:                        view.getToolkit().beep();
0864:                }
0865:
0866:                return (fileCount != 0);
0867:            } //}}}
0868:
0869:            //}}}
0870:
0871:            //{{{ escapeRegexp() method
0872:            /**
0873:             * Escapes characters with special meaning in a regexp.
0874:             * @param multiline Should \n be escaped?
0875:             * @since jEdit 4.3pre1
0876:             */
0877:            public static String escapeRegexp(String str, boolean multiline) {
0878:                return MiscUtilities.charsToEscapes(str, "\r\t\\()[]{}$^*+?|."
0879:                        + (multiline ? "" : "\n"));
0880:            } //}}}
0881:
0882:            //{{{ load() method
0883:            /**
0884:             * Loads search and replace state from the properties.
0885:             */
0886:            public static void load() {
0887:                search = jEdit.getProperty("search.find.value");
0888:                replace = jEdit.getProperty("search.replace.value");
0889:                ignoreCase = jEdit
0890:                        .getBooleanProperty("search.ignoreCase.toggle");
0891:                regexp = jEdit.getBooleanProperty("search.regexp.toggle");
0892:                beanshell = jEdit.getBooleanProperty("search.beanshell.toggle");
0893:                wrap = jEdit.getBooleanProperty("search.wrap.toggle");
0894:
0895:                fileset = new CurrentBufferSet();
0896:
0897:                // Tags plugin likes to call this method at times other than
0898:                // startup; so we need to fire a SearchSettingsChanged to
0899:                // notify the search bar and so on.
0900:                matcher = null;
0901:                EditBus.send(new SearchSettingsChanged(null));
0902:            } //}}}
0903:
0904:            //{{{ save() method
0905:            /**
0906:             * Saves search and replace state to the properties.
0907:             */
0908:            public static void save() {
0909:                jEdit.setProperty("search.find.value", search);
0910:                jEdit.setProperty("search.replace.value", replace);
0911:                jEdit
0912:                        .setBooleanProperty("search.ignoreCase.toggle",
0913:                                ignoreCase);
0914:                jEdit.setBooleanProperty("search.regexp.toggle", regexp);
0915:                jEdit.setBooleanProperty("search.beanshell.toggle", beanshell);
0916:                jEdit.setBooleanProperty("search.wrap.toggle", wrap);
0917:            } //}}}
0918:
0919:            //{{{ handleError() method
0920:            static void handleError(Component comp, Exception e) {
0921:                Log.log(Log.ERROR, SearchAndReplace.class, e);
0922:                if (comp instanceof  Dialog) {
0923:                    new TextAreaDialog((Dialog) comp,
0924:                            beanshell ? "searcherror-bsh" : "searcherror", e);
0925:                } else {
0926:                    new TextAreaDialog((Frame) comp,
0927:                            beanshell ? "searcherror-bsh" : "searcherror", e);
0928:                }
0929:            } //}}}
0930:
0931:            //{{{ Private members
0932:
0933:            //{{{ Instance variables
0934:            private static String search;
0935:            private static String replace;
0936:            private static BshMethod replaceMethod;
0937:            private static NameSpace replaceNS = new NameSpace(BeanShell
0938:                    .getNameSpace(),
0939:                    BeanShell.getNameSpace().getClassManager(),
0940:                    "search and replace");
0941:            private static boolean regexp;
0942:            private static boolean ignoreCase;
0943:            private static boolean reverse;
0944:            private static boolean beanshell;
0945:            private static boolean wrap;
0946:            private static SearchMatcher matcher;
0947:            private static SearchFileSet fileset;
0948:
0949:            //}}}
0950:
0951:            //{{{ initReplace() method
0952:            /**
0953:             * Set up BeanShell replace if necessary.
0954:             */
0955:            private static void initReplace() throws Exception {
0956:                if (beanshell && replace.length() != 0) {
0957:                    replaceMethod = BeanShell.cacheBlock("replace", "return ("
0958:                            + replace + ");", true);
0959:                } else
0960:                    replaceMethod = null;
0961:            } //}}}
0962:
0963:            //{{{ record() method
0964:            private static void record(View view, String action,
0965:                    boolean replaceAction, boolean recordFileSet) {
0966:                Macros.Recorder recorder = view.getMacroRecorder();
0967:
0968:                if (recorder != null) {
0969:                    recorder.record("SearchAndReplace.setSearchString(\""
0970:                            + MiscUtilities.charsToEscapes(search) + "\");");
0971:
0972:                    if (replaceAction) {
0973:                        recorder.record("SearchAndReplace.setReplaceString(\""
0974:                                + MiscUtilities.charsToEscapes(replace)
0975:                                + "\");");
0976:                        recorder.record("SearchAndReplace.setBeanShellReplace("
0977:                                + beanshell + ");");
0978:                    } else {
0979:                        // only record this if doing a find next
0980:                        recorder.record("SearchAndReplace.setAutoWrapAround("
0981:                                + wrap + ");");
0982:                        recorder.record("SearchAndReplace.setReverseSearch("
0983:                                + reverse + ");");
0984:                    }
0985:
0986:                    recorder.record("SearchAndReplace.setIgnoreCase("
0987:                            + ignoreCase + ");");
0988:                    recorder.record("SearchAndReplace.setRegexp(" + regexp
0989:                            + ");");
0990:
0991:                    if (recordFileSet) {
0992:                        recorder.record("SearchAndReplace.setSearchFileSet("
0993:                                + fileset.getCode() + ");");
0994:                    }
0995:
0996:                    recorder.record("SearchAndReplace." + action + ';');
0997:                }
0998:            } //}}}
0999:
1000:            //{{{ replaceInSelection() method
1001:            private static int replaceInSelection(View view,
1002:                    JEditTextArea textArea, Buffer buffer,
1003:                    SearchMatcher matcher, boolean smartCaseReplace, Selection s)
1004:                    throws Exception {
1005:                /* if an occurence occurs at the
1006:                beginning of the selection, the
1007:                selection start will get moved.
1008:                this sucks, so we hack to avoid it. */
1009:                int start = s.getStart();
1010:
1011:                int returnValue;
1012:
1013:                if (s instanceof  Selection.Range) {
1014:                    returnValue = _replace(view, buffer, matcher, s.getStart(),
1015:                            s.getEnd(), smartCaseReplace);
1016:
1017:                    textArea.removeFromSelection(s);
1018:                    textArea.addToSelection(new Selection.Range(start, s
1019:                            .getEnd()));
1020:                } else if (s instanceof  Selection.Rect) {
1021:                    Selection.Rect rect = (Selection.Rect) s;
1022:                    int startCol = rect.getStartColumn(buffer);
1023:                    int endCol = rect.getEndColumn(buffer);
1024:
1025:                    returnValue = 0;
1026:                    for (int j = s.getStartLine(); j <= s.getEndLine(); j++) {
1027:                        returnValue += _replace(view, buffer, matcher,
1028:                                getColumnOnOtherLine(buffer, j, startCol),
1029:                                getColumnOnOtherLine(buffer, j, endCol),
1030:                                smartCaseReplace);
1031:                    }
1032:                    textArea.addToSelection(new Selection.Rect(start, s
1033:                            .getEnd()));
1034:                } else
1035:                    throw new RuntimeException("Unsupported: " + s);
1036:
1037:                return returnValue;
1038:            } //}}}
1039:
1040:            //{{{ _replace() method
1041:            /**
1042:             * Replaces all occurrences of the search string with the replacement
1043:             * string.
1044:             * @param view The view
1045:             * @param buffer The buffer
1046:             * @param start The start offset
1047:             * @param end The end offset
1048:             * @param matcher The search matcher to use
1049:             * @param smartCaseReplace See user's guide
1050:             * @return The number of occurrences replaced
1051:             */
1052:            private static int _replace(View view, Buffer buffer,
1053:                    SearchMatcher matcher, int start, int end,
1054:                    boolean smartCaseReplace) throws Exception {
1055:                int occurCount = 0;
1056:
1057:                boolean endOfLine = (buffer.getLineEndOffset(buffer
1058:                        .getLineOfOffset(end)) - 1 == end);
1059:
1060:                Segment text = new Segment();
1061:                int offset = start;
1062:                loop: for (int counter = 0;; counter++) {
1063:                    buffer.getText(offset, end - offset, text);
1064:
1065:                    boolean startOfLine = (buffer.getLineStartOffset(buffer
1066:                            .getLineOfOffset(offset)) == offset);
1067:
1068:                    SearchMatcher.Match occur = matcher.nextMatch(
1069:                            new SegmentCharSequence(text, false), startOfLine,
1070:                            endOfLine, counter == 0, false);
1071:                    if (occur == null)
1072:                        break loop;
1073:
1074:                    String found = new String(text.array, text.offset
1075:                            + occur.start, occur.end - occur.start);
1076:
1077:                    int length = replaceOne(view, buffer, occur, offset, found,
1078:                            smartCaseReplace);
1079:                    if (length == -1)
1080:                        offset += occur.end;
1081:                    else {
1082:                        offset += occur.start + length;
1083:                        end += (length - found.length());
1084:                        occurCount++;
1085:                    }
1086:
1087:                    if (matcher.isMatchingEOL()) {
1088:                        if (offset < buffer.getLength())
1089:                            offset += 1;
1090:                        else
1091:                            break loop;
1092:
1093:                        if (offset >= end)
1094:                            break loop;
1095:                    }
1096:                }
1097:
1098:                return occurCount;
1099:            } //}}}
1100:
1101:            //{{{ replaceOne() method
1102:            /**
1103:             * Replace one occurrence of the search string with the
1104:             * replacement string.
1105:             */
1106:            private static int replaceOne(View view, Buffer buffer,
1107:                    SearchMatcher.Match occur, int offset, String found,
1108:                    boolean smartCaseReplace) throws Exception {
1109:                String subst = replaceOne(view, occur, found);
1110:                if (smartCaseReplace && ignoreCase) {
1111:                    int strCase = TextUtilities.getStringCase(found);
1112:                    if (strCase == TextUtilities.LOWER_CASE)
1113:                        subst = subst.toLowerCase();
1114:                    else if (strCase == TextUtilities.UPPER_CASE)
1115:                        subst = subst.toUpperCase();
1116:                    else if (strCase == TextUtilities.TITLE_CASE)
1117:                        subst = TextUtilities.toTitleCase(subst);
1118:                }
1119:
1120:                if (subst != null) {
1121:                    int start = offset + occur.start;
1122:                    int end = offset + occur.end;
1123:
1124:                    if (end - start > 0)
1125:                        buffer.remove(start, end - start);
1126:                    buffer.insert(start, subst);
1127:                    return subst.length();
1128:                } else
1129:                    return -1;
1130:            } //}}}
1131:
1132:            //{{{ replaceOne() method
1133:            private static String replaceOne(View view,
1134:                    SearchMatcher.Match occur, String found) throws Exception {
1135:                if (regexp) {
1136:                    if (replaceMethod != null)
1137:                        return regexpBeanShellReplace(view, occur);
1138:                    else
1139:                        return regexpReplace(occur, found);
1140:                } else {
1141:                    if (replaceMethod != null)
1142:                        return literalBeanShellReplace(view, found);
1143:                    else
1144:                        return replace;
1145:                }
1146:            } //}}}
1147:
1148:            //{{{ regexpBeanShellReplace() method
1149:            private static String regexpBeanShellReplace(View view,
1150:                    SearchMatcher.Match occur) throws Exception {
1151:                for (int i = 0; i < occur.substitutions.length; i++) {
1152:                    replaceNS.setVariable("_" + i, occur.substitutions[i]);
1153:                }
1154:
1155:                Object obj = BeanShell.runCachedBlock(replaceMethod, view,
1156:                        replaceNS);
1157:                if (obj == null)
1158:                    return "";
1159:                else
1160:                    return obj.toString();
1161:            } //}}}
1162:
1163:            //{{{ regexpReplace() method
1164:            private static String regexpReplace(SearchMatcher.Match occur,
1165:                    String found) throws Exception {
1166:                StringBuilder buf = new StringBuilder();
1167:
1168:                for (int i = 0; i < replace.length(); i++) {
1169:                    char ch = replace.charAt(i);
1170:                    switch (ch) {
1171:                    case '$':
1172:                        if (i == replace.length() - 1) {
1173:                            buf.append(ch);
1174:                            break;
1175:                        }
1176:
1177:                        ch = replace.charAt(++i);
1178:                        if (ch == '$')
1179:                            buf.append('$');
1180:                        else if (ch == '0')
1181:                            buf.append(found);
1182:                        else if (Character.isDigit(ch)) {
1183:                            int n = ch - '0';
1184:                            if (n < occur.substitutions.length) {
1185:                                buf.append(occur.substitutions[n]);
1186:                            }
1187:                        }
1188:                        break;
1189:                    case '\\':
1190:                        if (i == replace.length() - 1) {
1191:                            buf.append('\\');
1192:                            break;
1193:                        }
1194:                        ch = replace.charAt(++i);
1195:                        switch (ch) {
1196:                        case 'n':
1197:                            buf.append('\n');
1198:                            break;
1199:                        case 't':
1200:                            buf.append('\t');
1201:                            break;
1202:                        default:
1203:                            buf.append(ch);
1204:                            break;
1205:                        }
1206:                        break;
1207:                    default:
1208:                        buf.append(ch);
1209:                        break;
1210:                    }
1211:                }
1212:
1213:                return buf.toString();
1214:            } //}}}
1215:
1216:            //{{{ literalBeanShellReplace() method
1217:            private static String literalBeanShellReplace(View view,
1218:                    String found) throws Exception {
1219:                replaceNS.setVariable("_0", found);
1220:                Object obj = BeanShell.runCachedBlock(replaceMethod, view,
1221:                        replaceNS);
1222:                if (obj == null)
1223:                    return "";
1224:                else
1225:                    return obj.toString();
1226:            } //}}}
1227:
1228:            //{{{ getColumnOnOtherLine() method
1229:            /**
1230:             * Should be somewhere else...
1231:             */
1232:            private static int getColumnOnOtherLine(Buffer buffer, int line,
1233:                    int col) {
1234:                int returnValue = buffer.getOffsetOfVirtualColumn(line, col,
1235:                        null);
1236:                if (returnValue == -1)
1237:                    return buffer.getLineEndOffset(line) - 1;
1238:                else
1239:                    return buffer.getLineStartOffset(line) + returnValue;
1240:            } //}}}
1241:
1242:            //}}}
1243:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.