KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > editor > lib2 > search > EditorFindSupport


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.editor.lib2.search;
21
22 import java.awt.Insets JavaDoc;
23 import java.awt.Rectangle JavaDoc;
24 import java.beans.PropertyChangeListener JavaDoc;
25 import java.beans.PropertyChangeSupport JavaDoc;
26 import java.lang.ref.WeakReference JavaDoc;
27 import java.text.MessageFormat JavaDoc;
28 import java.util.ArrayList JavaDoc;
29 import java.util.HashMap JavaDoc;
30 import java.util.List JavaDoc;
31 import java.util.Map JavaDoc;
32 import java.util.WeakHashMap JavaDoc;
33 import java.util.logging.Level JavaDoc;
34 import java.util.logging.Logger JavaDoc;
35 import javax.swing.text.JTextComponent JavaDoc;
36 import javax.swing.text.BadLocationException JavaDoc;
37 import javax.swing.text.Caret JavaDoc;
38 import javax.swing.text.Document JavaDoc;
39 import javax.swing.text.Position JavaDoc;
40 import org.netbeans.api.editor.settings.FontColorNames;
41 import org.netbeans.modules.editor.lib2.ComponentUtils;
42 import org.netbeans.modules.editor.lib2.DocUtils;
43 import org.netbeans.modules.editor.lib2.DocumentsJumpList;
44 import org.netbeans.modules.editor.lib2.DocumentsRegistry;
45 import org.netbeans.modules.editor.lib2.highlighting.BlockHighlighting;
46 import org.netbeans.modules.editor.lib2.highlighting.Factory;
47 import org.netbeans.modules.editor.lib2.search.DocumentFinder.FindReplaceResult;
48 import org.openide.util.NbBundle;
49
50 /**
51 * Find management
52 *
53 * @author Miloslav Metelka
54 * @version 1.00
55 */

56
57 public final class EditorFindSupport {
58
59     private static final Logger JavaDoc LOG = Logger.getLogger(EditorFindSupport.class.getName());
60     
61     /* Find properties.
62     * They are read by FindSupport when its instance is being initialized.
63     * FIND_WHAT: java.lang.String - search expression
64     * FIND_REPLACE_BY: java.lang.String - replace string
65     * FIND_HIGHLIGHT_SEARCH: java.lang.Boolean - highlight matching strings in text
66     * FIND_INC_SEARCH: java.lang.Boolean - show matching strings immediately
67     * FIND_BACKWARD_SEARCH: java.lang.Boolean - search in backward direction
68     * FIND_WRAP_SEARCH: java.lang.Boolean - if end of doc reached, start from begin
69     * FIND_MATCH_CASE: java.lang.Boolean - match case of letters
70     * FIND_SMART_CASE: java.lang.Boolean - case insensitive search if FIND_MATCH_CASE
71     * is false and all letters of FIND_WHAT are small, case sensitive otherwise
72     * FIND_WHOLE_WORDS: java.lang.Boolean - match only whole words
73     * FIND_REG_EXP: java.lang.Boolean - use regular expressions in search expr
74     * FIND_HISTORY: java.util.List - History of search expressions
75     * FIND_HISTORY_SIZE: java.lang.Integer - Maximum size of the history
76     * FIND_BLOCK_SEARCH: java.lang.Boolean - search in block
77     * FIND_BLOCK_SEARCH_START: java.lang.Integer - start offset of the block
78     * FIND_BLOCK_SEARCH_END: java.lang.Integer - end offset of the block
79     *
80     */

81     public static final String JavaDoc FIND_WHAT = "find-what"; // NOI18N
82
public static final String JavaDoc FIND_REPLACE_WITH = "find-replace-with"; // NOI18N
83
public static final String JavaDoc FIND_HIGHLIGHT_SEARCH = "find-highlight-search"; // NOI18N
84
public static final String JavaDoc FIND_INC_SEARCH = "find-inc-search"; // NOI18N
85
public static final String JavaDoc FIND_INC_SEARCH_DELAY = "find-inc-search-delay"; // NOI18N
86
public static final String JavaDoc FIND_BACKWARD_SEARCH = "find-backward-search"; // NOI18N
87
public static final String JavaDoc FIND_WRAP_SEARCH = "find-wrap-search"; // NOI18N
88
public static final String JavaDoc FIND_MATCH_CASE = "find-match-case"; // NOI18N
89
public static final String JavaDoc FIND_SMART_CASE = "find-smart-case"; // NOI18N
90
public static final String JavaDoc FIND_WHOLE_WORDS = "find-whole-words"; // NOI18N
91
public static final String JavaDoc FIND_REG_EXP = "find-reg-exp"; // NOI18N
92
public static final String JavaDoc FIND_HISTORY = "find-history"; // NOI18N
93
public static final String JavaDoc FIND_HISTORY_SIZE = "find-history-size"; // NOI18N
94
public static final String JavaDoc FIND_BLOCK_SEARCH = "find-block-search"; //NOI18N
95
public static final String JavaDoc FIND_BLOCK_SEARCH_START = "find-block-search-start"; //NOI18N
96
public static final String JavaDoc FIND_BLOCK_SEARCH_END = "find-block-search-end"; //NOI18N
97

98     private static final String JavaDoc FOUND_LOCALE = "find-found"; // NOI18N
99
private static final String JavaDoc NOT_FOUND_LOCALE = "find-not-found"; // NOI18N
100
private static final String JavaDoc WRAP_START_LOCALE = "find-wrap-start"; // NOI18N
101
private static final String JavaDoc WRAP_END_LOCALE = "find-wrap-end"; // NOI18N
102
private static final String JavaDoc WRAP_BLOCK_START_LOCALE = "find-block-wrap-start"; // NOI18N
103
private static final String JavaDoc WRAP_BLOCK_END_LOCALE = "find-block-wrap-end"; // NOI18N
104
private static final String JavaDoc ITEMS_REPLACED_LOCALE = "find-items-replaced"; // NOI18N
105
/** It's public only to keep backwards compatibility of th FindSupport class. */
106     public static final String JavaDoc REVERT_MAP = "revert-map"; // NOI18N
107

108     private static final String JavaDoc SEARCH_BLOCK_START="search-block-start"; //NOI18N
109
private static final String JavaDoc SEARCH_BLOCK_END="search-block-end"; //NOI18N
110

111     /** It's public only to keep backwards compatibility of th FindSupport class. */
112     public static final String JavaDoc FIND_HISTORY_PROP = "find-history-prop"; //NOI18N
113
/** It's public only to keep backwards compatibility of th FindSupport class. */
114     public static final String JavaDoc FIND_HISTORY_CHANGED_PROP = "find-history-changed-prop"; //NOI18N
115

116     /** Shared instance of FindSupport class */
117     private static EditorFindSupport findSupport;
118
119     /** Find properties */
120     private Map JavaDoc<String JavaDoc, Object JavaDoc> findProps;
121
122     private WeakHashMap JavaDoc<JTextComponent JavaDoc, Map JavaDoc<String JavaDoc, WeakReference JavaDoc<BlockHighlighting>>> comp2layer =
123         new WeakHashMap JavaDoc<JTextComponent JavaDoc, Map JavaDoc<String JavaDoc, WeakReference JavaDoc<BlockHighlighting>>>();
124     
125     /** Support for firing change events */
126     private PropertyChangeSupport JavaDoc changeSupport = new PropertyChangeSupport JavaDoc(this);
127     
128     private SPW lastSelected;
129     private List JavaDoc<SPW> historyList;
130
131     private EditorFindSupport() {
132         // prevent instance creation
133
}
134
135     /** Get shared instance of find support */
136     public static EditorFindSupport getInstance() {
137         if (findSupport == null) {
138             findSupport = new EditorFindSupport();
139         }
140         return findSupport;
141     }
142
143     public Map JavaDoc<String JavaDoc, Object JavaDoc> getDefaultFindProperties() {
144         HashMap JavaDoc<String JavaDoc, Object JavaDoc> props = new HashMap JavaDoc<String JavaDoc, Object JavaDoc>();
145         
146         props.put(FIND_WHAT, null);
147         props.put(FIND_REPLACE_WITH, null);
148         props.put(FIND_HIGHLIGHT_SEARCH, Boolean.TRUE);
149         props.put(FIND_INC_SEARCH, Boolean.TRUE);
150         props.put(FIND_BACKWARD_SEARCH, Boolean.FALSE);
151         props.put(FIND_WRAP_SEARCH, Boolean.TRUE);
152         props.put(FIND_MATCH_CASE, Boolean.FALSE);
153         props.put(FIND_SMART_CASE, Boolean.FALSE);
154         props.put(FIND_WHOLE_WORDS, Boolean.FALSE);
155         props.put(FIND_REG_EXP, Boolean.FALSE);
156         props.put(FIND_HISTORY, new Integer JavaDoc(30));
157
158         return props;
159     }
160
161     private int getBlockEndOffset(){
162         Position JavaDoc pos = (Position JavaDoc) getFindProperties().get(FIND_BLOCK_SEARCH_END);
163         return (pos != null) ? pos.getOffset() : -1;
164     }
165     
166     public Map JavaDoc<String JavaDoc, Object JavaDoc> getFindProperties() {
167         if (findProps == null) {
168             findProps = getDefaultFindProperties();
169         }
170         return findProps;
171     }
172
173     /** Get find property with specified name */
174     public Object JavaDoc getFindProperty(String JavaDoc name) {
175         return getFindProperties().get(name);
176     }
177
178     private Map JavaDoc<String JavaDoc, Object JavaDoc> getValidFindProperties(Map JavaDoc<String JavaDoc, Object JavaDoc> props) {
179         return (props != null) ? props : getFindProperties();
180     }
181
182     /**
183      * <p><b>IMPORTANT:</b> This method is public only for keeping backwards
184      * compatibility of the {@link org.netbeans.editor.FindSupport} class.
185      */

186     public int[] getBlocks(int[] blocks, Document JavaDoc doc,
187                     int startPos, int endPos) throws BadLocationException JavaDoc {
188         Map JavaDoc props = getValidFindProperties(null);
189         
190         Boolean JavaDoc b = (Boolean JavaDoc)props.get(FIND_BLOCK_SEARCH);
191         boolean blockSearch = (b != null && b.booleanValue());
192         Integer JavaDoc i = (Integer JavaDoc) props.get(FIND_BLOCK_SEARCH_START);
193         int blockSearchStart = (i != null) ? i.intValue() : -1;
194         int blockSearchEnd = getBlockEndOffset();
195
196         if (blockSearch && blockSearchStart>-1 && blockSearchEnd >0){
197             if (endPos>=blockSearchStart && startPos <=blockSearchEnd){
198                 startPos = Math.max(blockSearchStart, startPos);
199                 endPos = Math.min(blockSearchEnd, endPos);
200             }else{
201                 return blocks;
202             }
203         }
204         return DocumentFinder.findBlocks(doc, startPos, endPos, props, blocks);
205     }
206
207     /**
208      * Get find property without performing initialization
209      * of find properties. This is useful for example for base document
210      * when it wants to query whether it should do highlight search.
211      *
212      * <p><b>IMPORTANT:</b> This method is public only for keeping backwards
213      * compatibility of the {@link org.netbeans.editor.FindSupport} class.
214      */

215     public Object JavaDoc getPropertyNoInit(String JavaDoc name) {
216         if (findProps == null) {
217             return null;
218         } else {
219             return getFindProperty(name);
220         }
221     }
222
223     /** Set find property with specified name and fire change.
224     */

225     public void putFindProperty(String JavaDoc name, Object JavaDoc newValue) {
226         Object JavaDoc oldValue = getFindProperty(name);
227         if ((oldValue == null && newValue == null)
228                 || (oldValue != null && oldValue.equals(newValue))
229            ) {
230             return;
231         }
232         if (newValue != null) {
233             getFindProperties().put(name, newValue);
234         } else {
235             getFindProperties().remove(name);
236         }
237         firePropertyChange(name, oldValue, newValue);
238     }
239
240     /** Add/replace properties from some other map
241     * to current find properties. If the added properties
242     * are different than the original ones,
243     * the property change is fired.
244     */

245     public void putFindProperties(Map JavaDoc<String JavaDoc, Object JavaDoc> propsToAdd) {
246         if (!getFindProperties().equals(propsToAdd)) {
247             getFindProperties().putAll(propsToAdd);
248             firePropertyChange(null, null, null);
249         }
250     }
251     
252     public void setBlockSearchHighlight(int startSelection, int endSelection){
253         JTextComponent JavaDoc comp = DocumentsRegistry.getMostActiveComponent();
254         BlockHighlighting layer = comp == null ? null : findLayer(comp, Factory.BLOCK_SEARCH_LAYER);
255
256         if (layer != null) {
257             
258             if (startSelection >= 0 && endSelection >= 0 && startSelection < endSelection ) {
259                 layer.highlightBlock(
260                     startSelection, endSelection, FontColorNames.BLOCK_SEARCH_COLORING);
261             } else {
262                 layer.highlightBlock(-1, -1, FontColorNames.BLOCK_SEARCH_COLORING);
263             }
264             
265         }
266         
267 // TODO: remove
268
// JTextComponent c = DocumentsRegistry.getMostActiveComponent();
269
// if (c==null) return;
270
// EditorUI editorUI = ((BaseTextUI)c.getUI()).getEditorUI();
271
// DrawLayerFactory.BlockSearchLayer blockLayer
272
// = (DrawLayerFactory.BlockSearchLayer)editorUI.findLayer(
273
// DrawLayerFactory.BLOCK_SEARCH_LAYER_NAME);
274
// Boolean b = (Boolean)getFindProperties().get(FIND_BACKWARD_SEARCH);
275
// boolean back = (b != null && b.booleanValue());
276
//
277
// if (startSelection >= endSelection){
278
// if (blockLayer != null) {
279
// if (blockLayer.isEnabled()) {
280
// blockLayer.setEnabled(false);
281
// try {
282
// editorUI.repaintBlock(blockLayer.getOffset(), blockLayer.getOffset()+blockLayer.getLength());
283
// } catch (BadLocationException e) {
284
// LOG.log(Level.WARNING, e.getMessage(), e);
285
// }
286
// }
287
// }
288
// }else{
289
// //init layer
290
// if (blockLayer == null) {
291
// blockLayer = new DrawLayerFactory.BlockSearchLayer();
292
// if (!editorUI.addLayer(blockLayer,
293
// DrawLayerFactory.BLOCK_SEARCH_LAYER_VISIBILITY)
294
// ) {
295
// return; // couldn't add layer
296
// }
297
// } else {
298
// if (blockLayer.isEnabled()) {
299
// blockLayer.setEnabled(false);
300
// try {
301
// editorUI.repaintOffset(blockLayer.getOffset());
302
// } catch (BadLocationException e) {
303
// LOG.log(Level.WARNING, e.getMessage(), e);
304
// }
305
// }
306
// }
307
//
308
// blockLayer.setEnabled(true);
309
// blockLayer.setArea(startSelection, endSelection-startSelection);
310
// try {
311
// editorUI.repaintBlock(startSelection, endSelection);
312
// } catch (BadLocationException e) {
313
// LOG.log(Level.WARNING, e.getMessage(), e);
314
// return;
315
// }
316
// c.getCaret().setDot(back ? endSelection : startSelection);
317
// }
318
}
319     
320     public boolean incSearch(Map JavaDoc<String JavaDoc, Object JavaDoc> props, int caretPos) {
321         props = getValidFindProperties(props);
322
323         // if regexp terminate incSearch
324
Boolean JavaDoc b = (Boolean JavaDoc)props.get(FIND_REG_EXP);
325         if (b !=null && b.booleanValue()){
326             return false;
327         }
328         
329         b = (Boolean JavaDoc)props.get(FIND_INC_SEARCH);
330         if (b != null && b.booleanValue()) { // inc search enabled
331
JTextComponent JavaDoc comp = DocumentsRegistry.getMostActiveComponent();
332             
333             if (comp != null) {
334                 b = (Boolean JavaDoc)props.get(FIND_BACKWARD_SEARCH);
335                 boolean back = (b != null && b.booleanValue());
336                 b = (Boolean JavaDoc)props.get(FIND_BLOCK_SEARCH);
337                 boolean blockSearch = (b != null && b.booleanValue());
338                 Integer JavaDoc i = (Integer JavaDoc) props.get(FIND_BLOCK_SEARCH_START);
339                 int blockSearchStart = (i != null) ? i.intValue() : -1;
340                 
341                 Position JavaDoc endPos = (Position JavaDoc) props.get(FIND_BLOCK_SEARCH_END);
342                 int blockSearchEnd = (endPos != null) ? endPos.getOffset() : -1;
343                 int endOffset = (back) ? 0 : -1;
344                 int pos;
345                 try {
346                     int start = (blockSearch && blockSearchStart > -1) ? blockSearchStart : 0;
347                     int end = (blockSearch && blockSearchEnd > 0) ? blockSearchEnd : -1;
348                     if (start>0 && end == -1) return false;
349                     int findRet[] = findInBlock(comp, caretPos,
350                         start,
351                         end,
352                         props, false);
353                             
354                     if (findRet == null) {
355                         incSearchReset();
356                         return false;
357                     }
358                     pos = findRet[0];
359                 } catch (BadLocationException JavaDoc e) {
360                     LOG.log(Level.WARNING, e.getMessage(), e);
361                     return false;
362                 }
363                 
364                 // Find the layer
365
BlockHighlighting layer = (BlockHighlighting)findLayer(comp, Factory.INC_SEARCH_LAYER);
366
367                 if (pos >= 0) {
368                     String JavaDoc s = (String JavaDoc)props.get(FIND_WHAT);
369                     int len = (s != null) ? s.length() : 0;
370                     if (len > 0) {
371                         if (comp.getSelectionEnd() > comp.getSelectionStart()){
372                             comp.select(caretPos, caretPos);
373                         }
374                         
375 // TODO: remove
376
// incLayer.setInversion(!blockSearch);
377
// incLayer.setEnabled(true);
378
// incLayer.setArea(pos, len);
379

380                         if (layer != null) {
381                             layer.highlightBlock(
382                                 pos,
383                                 pos + len,
384                                 blockSearch ? FontColorNames.INC_SEARCH_COLORING : FontColorNames.SELECTION_COLORING
385                             );
386                         }
387
388                         // reset higlighting
389
Map JavaDoc<String JavaDoc, Object JavaDoc> defaultProps = getValidFindProperties(null);
390                         String JavaDoc findWhatDef = (String JavaDoc)defaultProps.get(FIND_WHAT);
391                         if (findWhatDef!=null && findWhatDef.length()>0){
392                             defaultProps.put(FIND_WHAT, ""); //NOI18N
393
comp.repaint();
394                         }
395
396                         ensureVisible(comp, pos, pos);
397                         return true;
398                     }
399                 } else { // string not found
400
// !!! ((BaseCaret)c.getCaret()).dispatchUpdate();
401
}
402                
403             }
404         } else { // inc search not enabled
405
incSearchReset();
406         }
407         return false;
408     }
409
410     public void incSearchReset() {
411         // Find the layer
412
JTextComponent JavaDoc comp = DocumentsRegistry.getMostActiveComponent();
413         BlockHighlighting layer = comp == null ? null : (BlockHighlighting)findLayer(comp, Factory.INC_SEARCH_LAYER);
414         
415         if (layer != null) {
416             layer.highlightBlock(-1, -1, null);
417         }
418     }
419     
420     private boolean isBackSearch(Map JavaDoc props, boolean oppositeDir) {
421         Boolean JavaDoc b = (Boolean JavaDoc)props.get(FIND_BACKWARD_SEARCH);
422         boolean back = (b != null && b.booleanValue());
423         if (oppositeDir) {
424             back = !back;
425         }
426         return back;
427     }
428
429     private void selectText(JTextComponent JavaDoc c, int start, int end, boolean back){
430         Caret JavaDoc caret = c.getCaret();
431         ensureVisible(c, start, end);
432         if (back) {
433             caret.setDot(end);
434             caret.moveDot(start);
435         } else { // forward direction
436
caret.setDot(start);
437             caret.moveDot(end);
438         }
439     }
440     
441     private void ensureVisible(JTextComponent JavaDoc c, int startOffset, int endOffset) {
442         // TODO: read insets from settings
443
ensureVisible(c, startOffset, endOffset, new Insets JavaDoc(10, 10, 10, 10));
444     }
445     
446     /**
447      * Ensure that the given region will be visible in the view
448      * with the appropriate find insets.
449      */

450     private void ensureVisible(JTextComponent JavaDoc c, int startOffset, int endOffset, Insets JavaDoc extraInsets) {
451         try {
452             Rectangle JavaDoc startBounds = c.modelToView(startOffset);
453             Rectangle JavaDoc endBounds = c.modelToView(endOffset);
454             if (startBounds != null && endBounds != null) {
455                 startBounds.add(endBounds);
456                 if (extraInsets != null) {
457                     Rectangle JavaDoc visibleBounds = c.getVisibleRect();
458                     int extraTop = (extraInsets.top < 0)
459                         ? -extraInsets.top * visibleBounds.height / 100 // percentage
460
: extraInsets.top * endBounds.height; // line count
461
startBounds.y -= extraTop;
462                     startBounds.height += extraTop;
463                     startBounds.height += (extraInsets.bottom < 0)
464                         ? -extraInsets.bottom * visibleBounds.height / 100 // percentage
465
: extraInsets.bottom * endBounds.height; // line count
466
int extraLeft = (extraInsets.left < 0)
467                         ? -extraInsets.left * visibleBounds.width / 100 // percentage
468
: extraInsets.left * endBounds.width; // char count
469
startBounds.x -= extraLeft;
470                     startBounds.width += extraLeft;
471                     startBounds.width += (extraInsets.right < 0)
472                         ? -extraInsets.right * visibleBounds.width / 100 // percentage
473
: extraInsets.right * endBounds.width; // char count
474
}
475                 c.scrollRectToVisible(startBounds);
476             }
477         } catch (BadLocationException JavaDoc e) {
478             // do not scroll
479
}
480     }
481     
482     private FindReplaceResult findReplaceImpl(String JavaDoc replaceExp, Map JavaDoc<String JavaDoc, Object JavaDoc> props, boolean oppositeDir){
483         incSearchReset();
484         props = getValidFindProperties(props);
485         boolean back = isBackSearch(props, oppositeDir);
486         JTextComponent JavaDoc c = DocumentsRegistry.getMostActiveComponent();
487         Object JavaDoc findWhat = props.get(FIND_WHAT);
488         if (findWhat == null) { // nothing to search for
489
return null;
490         }
491
492         String JavaDoc exp = "'" + findWhat + "' "; // NOI18N
493
if (c != null) {
494             ComponentUtils.clearStatusText(c);
495             Caret JavaDoc caret = c.getCaret();
496             int dotPos = caret.getDot();
497             if (findWhat.equals(c.getSelectedText())) {
498                 Object JavaDoc dp = props.get(FIND_BACKWARD_SEARCH);
499                 boolean direction = (dp != null) ? ((Boolean JavaDoc)dp).booleanValue() : false;
500                 
501                 if (dotPos == (oppositeDir ^ direction ? c.getSelectionEnd() : c.getSelectionStart()))
502                     dotPos += (oppositeDir ^ direction ? -1 : 1);
503             }
504             
505             Boolean JavaDoc b = (Boolean JavaDoc)props.get(FIND_BLOCK_SEARCH);
506             boolean blockSearch = (b != null && b.booleanValue());
507             Integer JavaDoc i = (Integer JavaDoc) props.get(FIND_BLOCK_SEARCH_START);
508             int blockSearchStart = (i != null) ? i.intValue() : -1;
509             int blockSearchEnd = getBlockEndOffset();
510
511             try {
512                 FindReplaceResult result = findReplaceInBlock(replaceExp, c, dotPos,
513                         (blockSearch && blockSearchStart > -1) ? blockSearchStart : 0,
514                         (blockSearch && blockSearchEnd > 0) ? blockSearchEnd : -1,
515                         props, oppositeDir);
516                 int[] blk = null;
517                 if (result != null){
518                     blk = result.getFoundPositions();
519                 }
520                 if (blk != null) {
521                     selectText(c, blk[0], blk[1], back);
522                     DocumentsJumpList.checkAddEntry();
523                     String JavaDoc msg = exp + NbBundle.getBundle(EditorFindSupport.class).getString(FOUND_LOCALE)
524                                  + ' ' + DocUtils.debugPosition(c.getDocument(), blk[0]);
525                     if (blk[2] == 1) { // wrap was done
526
msg += "; "; // NOI18N
527
if (blockSearch && blockSearchEnd>0 && blockSearchStart >-1){
528                             msg += back ? NbBundle.getBundle(EditorFindSupport.class).getString(WRAP_BLOCK_END_LOCALE)
529                                    : NbBundle.getBundle(EditorFindSupport.class).getString(WRAP_BLOCK_START_LOCALE);
530                         }else{
531                             msg += back ? NbBundle.getBundle(EditorFindSupport.class).getString(WRAP_END_LOCALE)
532                                    : NbBundle.getBundle(EditorFindSupport.class).getString(WRAP_START_LOCALE);
533                         }
534                         ComponentUtils.setStatusBoldText(c, msg);
535                         c.getToolkit().beep();
536                     } else {
537                         ComponentUtils.setStatusText(c, msg);
538                     }
539                     return result;
540                 } else { // not found
541
ComponentUtils.setStatusBoldText(c, exp + NbBundle.getBundle(EditorFindSupport.class).getString(
542                                                     NOT_FOUND_LOCALE));
543                     // issue 14189 - selection was not removed
544
c.getCaret().setDot(c.getCaret().getDot());
545                 }
546             } catch (BadLocationException JavaDoc e) {
547                 LOG.log(Level.WARNING, e.getMessage(), e);
548             }
549         }
550         return null;
551     }
552     
553     /** Find the text from the caret position.
554     * @param props search properties
555     * @param oppositeDir whether search in opposite direction
556     */

557     public boolean find(Map JavaDoc<String JavaDoc, Object JavaDoc> props, boolean oppositeDir) {
558         FindReplaceResult result = findReplaceImpl(null, props, oppositeDir);
559         return (result != null);
560     }
561
562     private FindReplaceResult findReplaceInBlock(String JavaDoc replaceExp, JTextComponent JavaDoc c, int startPos, int blockStartPos,
563                              int blockEndPos, Map JavaDoc<String JavaDoc, Object JavaDoc> props, boolean oppositeDir) throws BadLocationException JavaDoc {
564         if (c != null) {
565             props = getValidFindProperties(props);
566             Document JavaDoc doc = (Document JavaDoc)c.getDocument();
567             int pos = -1;
568             boolean wrapDone = false;
569             String JavaDoc replaced = null;
570
571             boolean back = isBackSearch(props, oppositeDir);
572             Boolean JavaDoc b = (Boolean JavaDoc)props.get(FIND_WRAP_SEARCH);
573             boolean wrap = (b != null && b.booleanValue());
574             int docLen = doc.getLength();
575             if (blockEndPos == -1) {
576                 blockEndPos = docLen;
577             }
578
579             int retFind[];
580             while (true) {
581                 //pos = doc.find(sf, startPos, back ? blockStartPos : blockEndPos);
582
int off1 = startPos;
583                 int off2 = back ? blockStartPos : blockEndPos;
584                 FindReplaceResult result = DocumentFinder.findReplaceResult(replaceExp, doc, Math.min(off1, off2), Math.max(off1, off2),
585                        props, oppositeDir );
586                 if (result == null){
587                     return null;
588                 }
589                 retFind = result.getFoundPositions();
590                 replaced = result.getReplacedString();
591                 if (retFind == null){
592                     break;
593                 }
594                 pos = retFind[0];
595                 
596                 if (pos != -1) {
597                     break;
598                 }
599
600                 if (wrap) {
601                     if (back) {
602                         //Bug #20552 the wrap search check whole document
603
//instead of just the remaining not-searched part to be
604
//able to find expressions with the cursor in it
605

606                         //blockStartPos = startPos;
607
startPos = blockEndPos;
608                     } else {
609                         //blockEndPos = startPos;
610
startPos = blockStartPos;
611                     }
612                     wrapDone = true;
613                     wrap = false; // only one loop
614
} else { // no wrap set
615
break;
616                 }
617
618             }
619
620             if (pos != -1) {
621                 int[] ret = new int[3];
622                 ret[0] = pos;
623                 ret[1] = retFind[1];
624                 ret[2] = wrapDone ? 1 : 0;
625                 return new FindReplaceResult(ret, replaced);
626             }
627         }
628         return null;
629     }
630     
631     /** Find the searched expression
632     * @param startPos position from which to search. It must be inside the block.
633     * @param blockStartPos starting position of the block. It must
634     * be valid position greater or equal than zero. It must be lower than
635     * or equal to blockEndPos (except blockEndPos=-1).
636     * @param blockEndPos ending position of the block. It can be -1 for the end
637     * of document. It must be greater or equal than blockStartPos (except blockEndPos=-1).
638     * @param props search properties
639     * @param oppositeDir whether search in opposite direction
640     * @param displayWrap whether display messages about the wrapping
641     * @return either null when nothing was found or integer array with three members
642     * ret[0] - starting position of the found string
643     * ret[1] - ending position of the found string
644     * ret[2] - 1 or 0 when wrap was or wasn't performed in order to find the string
645     */

646     public int[] findInBlock(JTextComponent JavaDoc c, int startPos, int blockStartPos,
647                              int blockEndPos, Map JavaDoc<String JavaDoc, Object JavaDoc> props, boolean oppositeDir) throws BadLocationException JavaDoc {
648         FindReplaceResult result = findReplaceInBlock(null, c, startPos, blockStartPos,
649                              blockEndPos, props, oppositeDir);
650         return result == null ? null : result.getFoundPositions();
651     }
652
653     public boolean replace(Map JavaDoc<String JavaDoc, Object JavaDoc> props, boolean oppositeDir)
654     throws BadLocationException JavaDoc {
655         incSearchReset();
656         props = getValidFindProperties(props);
657         Boolean JavaDoc b = (Boolean JavaDoc)props.get(FIND_BACKWARD_SEARCH);
658         boolean back = (b != null && b.booleanValue());
659         if (oppositeDir) {
660             back = !back;
661         }
662
663         b = (Boolean JavaDoc)props.get(FIND_BLOCK_SEARCH);
664         boolean blockSearch = (b != null && b.booleanValue());
665         Integer JavaDoc i = (Integer JavaDoc) props.get(FIND_BLOCK_SEARCH_START);
666         int blockSearchStart = (i != null) ? i.intValue() : -1;
667         int blockSearchEnd = getBlockEndOffset();
668
669         JTextComponent JavaDoc c = DocumentsRegistry.getMostActiveComponent();
670         if (c != null) {
671             String JavaDoc s = (String JavaDoc)props.get(FIND_REPLACE_WITH);
672             Caret JavaDoc caret = c.getCaret();
673             if (caret.isSelectionVisible()){
674                 int dotPos = caret.getDot();
675                 Object JavaDoc dp = props.get(FIND_BACKWARD_SEARCH);
676                 boolean direction = (dp != null) ? ((Boolean JavaDoc)dp).booleanValue() : false;
677                 dotPos = (oppositeDir ^ direction ? c.getSelectionEnd() : c.getSelectionStart());
678                 c.setCaretPosition(dotPos);
679             }
680             
681             FindReplaceResult result = findReplaceImpl(s, props, oppositeDir);
682             if (result!=null){
683                 s = result.getReplacedString();
684             } else {
685                 return false;
686             }
687
688             Document JavaDoc doc = (Document JavaDoc)c.getDocument();
689             int startPos = c.getSelectionStart();
690             int len = c.getSelectionEnd() - startPos;
691             DocUtils.atomicLock(doc);
692             try {
693                 if (len > 0) {
694                     doc.remove(startPos, len);
695                 }
696                 if (s != null && s.length() > 0) {
697                     doc.insertString(startPos, s, null);
698                 }
699             } finally {
700                 DocUtils.atomicUnlock(doc);
701                 if (blockSearch){
702                     setBlockSearchHighlight(blockSearchStart, getBlockEndOffset());
703                 }
704             }
705             
706             // adjust caret pos after replace operation
707
int adjustedCaretPos = (back || s == null) ? startPos : startPos + s.length();
708             caret.setDot(adjustedCaretPos);
709             
710         }
711         
712         return true;
713     }
714
715     public void replaceAll(Map JavaDoc<String JavaDoc, Object JavaDoc> props) {
716         incSearchReset();
717         JTextComponent JavaDoc c = DocumentsRegistry.getMostActiveComponent();
718         Document JavaDoc doc = (Document JavaDoc)c.getDocument();
719         int maxCnt = doc.getLength();
720         int replacedCnt = 0;
721         int totalCnt = 0;
722
723         props = getValidFindProperties(props);
724         props = new HashMap JavaDoc<String JavaDoc, Object JavaDoc>(props);
725         String JavaDoc replaceWithOriginal = (String JavaDoc)props.get(FIND_REPLACE_WITH);
726         
727         Boolean JavaDoc b = (Boolean JavaDoc)props.get(FIND_BLOCK_SEARCH);
728         boolean blockSearch = (b != null && b.booleanValue());
729         b = (Boolean JavaDoc)props.get(FIND_WRAP_SEARCH);
730         boolean wrapSearch = (b != null && b.booleanValue());
731         b = (Boolean JavaDoc)props.get(FIND_BACKWARD_SEARCH);
732         boolean backSearch = (b != null && b.booleanValue());
733         
734         if (wrapSearch){
735             props.put(FIND_WRAP_SEARCH, Boolean.FALSE);
736             props.put(FIND_BACKWARD_SEARCH, Boolean.FALSE);
737             firePropertyChange(null, null, null);
738         }
739         
740         Integer JavaDoc i = (Integer JavaDoc) props.get(FIND_BLOCK_SEARCH_START);
741         int blockSearchStart = (i != null) ? i.intValue() : -1;
742         int blockSearchEnd = getBlockEndOffset();
743
744         if (c != null) {
745             DocUtils.atomicLock(doc);
746             try {
747                 int startPosWholeSearch = 0;
748                 int endPosWholeSearch = -1;
749                 int caretPos = c.getCaret().getDot();
750
751                 if (!wrapSearch){
752                     if (backSearch){
753                         startPosWholeSearch = 0;
754                         endPosWholeSearch = caretPos;
755                     }else{
756                         startPosWholeSearch = caretPos;
757                         endPosWholeSearch = -1;
758                     }
759                 }
760                 
761                 int actualPos = wrapSearch ? 0 : c.getCaret().getDot();
762                 
763                 int pos = (blockSearch && blockSearchStart > -1) ? ( backSearch ? blockSearchEnd : blockSearchStart) : actualPos; // actual position
764

765                 while (true) {
766                     blockSearchEnd = getBlockEndOffset();
767                     FindReplaceResult result = findReplaceInBlock(replaceWithOriginal, c, pos,
768                             (blockSearch && blockSearchStart > -1) ? blockSearchStart : startPosWholeSearch,
769                             (blockSearch && blockSearchEnd > 0) ? blockSearchEnd : endPosWholeSearch,
770                             props, false);
771                     if (result == null){
772                         break;
773                     }
774                     int[] blk = result.getFoundPositions();
775                     String JavaDoc replaceWith = result.getReplacedString();
776                     if (blk == null) {
777                         break;
778                     }
779                     totalCnt++;
780                     int len = blk[1] - blk[0];
781                     boolean skip = false; // cannot remove (because of guarded block)?
782
try {
783                         doc.remove(blk[0], len);
784                     } catch (BadLocationException JavaDoc e) {
785                         // replace in guarded block
786
if (ComponentUtils.isGuardedException(e)) {
787                             skip = true;
788                         } else {
789                             throw e;
790                         }
791                     }
792                     if (skip) {
793                         pos = blk[0] + len;
794
795                     } else { // can and will insert the new string
796
if (replaceWith != null && replaceWith.length() > 0) {
797                             doc.insertString(blk[0], replaceWith, null);
798                         }
799                         pos = blk[0] + ((replaceWith != null) ? replaceWith.length() : 0);
800                         replacedCnt++;
801                     }
802                 }
803                 
804                 // Display message about replacement
805
if (totalCnt == 0){
806                     Object JavaDoc findWhat = props.get(FIND_WHAT);
807                     String JavaDoc exp = "'' "; //NOI18N
808
if (findWhat != null) { // nothing to search for
809
exp = "'" + findWhat + "' "; // NOI18N
810
}
811                     ComponentUtils.setStatusBoldText(c, exp + NbBundle.getBundle(EditorFindSupport.class).getString(
812                                 NOT_FOUND_LOCALE));
813                 }else{
814                     MessageFormat JavaDoc fmt = new MessageFormat JavaDoc(
815                                             NbBundle.getBundle(EditorFindSupport.class).getString(ITEMS_REPLACED_LOCALE));
816                     String JavaDoc msg = fmt.format(new Object JavaDoc[] { new Integer JavaDoc(replacedCnt), new Integer JavaDoc(totalCnt) });
817                     ComponentUtils.setStatusText(c, msg);
818                 }
819
820             } catch (BadLocationException JavaDoc e) {
821                 LOG.log(Level.WARNING, e.getMessage(), e);
822             } finally {
823                 DocUtils.atomicUnlock(doc);
824                 if (blockSearch){
825                     setBlockSearchHighlight(blockSearchStart, getBlockEndOffset());
826                 }
827             }
828         }
829     }
830
831     public void hookLayer(BlockHighlighting layer, JTextComponent JavaDoc component) {
832         synchronized (comp2layer) {
833             Map JavaDoc<String JavaDoc, WeakReference JavaDoc<BlockHighlighting>> type2layer = comp2layer.get(component);
834
835             if (type2layer == null) {
836                 type2layer = new HashMap JavaDoc<String JavaDoc, WeakReference JavaDoc<BlockHighlighting>>();
837                 comp2layer.put(component, type2layer);
838             }
839
840             type2layer.put(layer.getLayerTypeId(), new WeakReference JavaDoc<BlockHighlighting>(layer));
841         }
842     }
843     
844     public void unhookLayer(BlockHighlighting layer, JTextComponent JavaDoc component) {
845         synchronized (comp2layer) {
846             Map JavaDoc<String JavaDoc, WeakReference JavaDoc<BlockHighlighting>> type2layer = comp2layer.get(component);
847
848             if (type2layer != null) {
849                 type2layer.remove(layer.getLayerTypeId());
850                 if (type2layer.isEmpty()) {
851                     comp2layer.remove(component);
852                 }
853             }
854         }
855     }
856     
857     public BlockHighlighting findLayer(JTextComponent JavaDoc component, String JavaDoc layerId) {
858         synchronized (comp2layer) {
859             Map JavaDoc<String JavaDoc, WeakReference JavaDoc<BlockHighlighting>> type2layer = comp2layer.get(component);
860             BlockHighlighting layer = null;
861
862             if (type2layer != null) {
863                 WeakReference JavaDoc<BlockHighlighting> ref = type2layer.get(layerId);
864                 if (ref != null) {
865                     layer = ref.get();
866                 }
867             }
868
869             return layer;
870         }
871     }
872     
873 // TODO: remove
874
// /** Get position of wrap mark for some document */
875
// public int getWrapSearchMarkPos(Document doc) {
876
// Mark mark = (Mark)doc.getProperty(Document.WRAP_SEARCH_MARK_PROP);
877
// try {
878
// return (mark != null) ? mark.getOffset() : doc.getLength();
879
// } catch (InvalidMarkException e) {
880
// throw new RuntimeException(); // shouldn't happen
881
// }
882
// }
883
//
884
// /** Set new position of wrap mark for some document */
885
// public void setWrapSearchMarkPos(Document doc, int pos) {
886
// //!!!
887
// }
888

889     /** Add weak listener to listen to change of any property. The caller must
890     * hold the listener object in some instance variable to prevent it
891     * from being garbage collected.
892     */

893     public void addPropertyChangeListener(PropertyChangeListener JavaDoc l) {
894         changeSupport.addPropertyChangeListener(l);
895     }
896
897     public synchronized void addPropertyChangeListener(String JavaDoc findPropertyName,
898             PropertyChangeListener JavaDoc l) {
899         changeSupport.addPropertyChangeListener(findPropertyName, l);
900     }
901
902     /** Remove listener for changes in properties */
903     public void removePropertyChangeListener(PropertyChangeListener JavaDoc l) {
904         changeSupport.removePropertyChangeListener(l);
905     }
906
907     /**
908      * <p><b>IMPORTANT:</b> This method is public only for keeping backwards
909      * compatibility of the {@link org.netbeans.editor.FindSupport} class.
910      */

911     public void firePropertyChange(String JavaDoc settingName, Object JavaDoc oldValue, Object JavaDoc newValue) {
912         changeSupport.firePropertyChange(settingName, oldValue, newValue);
913     }
914
915     public void setHistory(List JavaDoc<SPW> spwList){
916         this.historyList = new ArrayList JavaDoc<SPW>(spwList);
917         firePropertyChange(FIND_HISTORY_CHANGED_PROP,null,null);
918     }
919     
920     public List JavaDoc<SPW> getHistory(){
921         return historyList;
922     }
923     
924     public void setLastSelected(SPW spw){
925         this.lastSelected = spw;
926         Map JavaDoc<String JavaDoc, Object JavaDoc> props = getFindProperties();
927         if (spw == null) return;
928         props.put(FIND_WHAT, spw.getSearchExpression());
929         props.put(FIND_MATCH_CASE, Boolean.valueOf(spw.isMatchCase()));
930         props.put(FIND_REG_EXP, Boolean.valueOf(spw.isRegExp()));
931         props.put(FIND_WHOLE_WORDS, Boolean.valueOf(spw.isWholeWords()));
932     }
933     
934     public SPW getLastSelected(){
935         return lastSelected;
936     }
937     
938     public void addToHistory(SPW spw){
939         if (spw == null) return;
940         firePropertyChange(FIND_HISTORY_PROP, null, spw);
941     }
942     
943     public final static class SPW{
944         private String JavaDoc searchExpression;
945         private boolean wholeWords;
946         private boolean matchCase;
947         private boolean regExp;
948         
949         public SPW(String JavaDoc searchExpression, boolean wholeWords,
950             boolean matchCase, boolean regExp){
951             this.searchExpression = searchExpression;
952             this.wholeWords = wholeWords;
953             this.matchCase = matchCase;
954             this.regExp = regExp;
955         }
956         
957         /** @return searchExpression */
958         public String JavaDoc getSearchExpression(){
959             return searchExpression;
960         }
961
962         /** @return true if the wholeWords parameter was used during search performing */
963         public boolean isWholeWords(){
964             return wholeWords;
965         }
966
967         /** @return true if the matchCase parameter was used during search performing */
968         public boolean isMatchCase(){
969             return matchCase;
970         }
971
972         /** @return true if the regExp parameter was used during search performing */
973         public boolean isRegExp(){
974             return regExp;
975         }
976         
977         public boolean equals(Object JavaDoc obj){
978             if (!(obj instanceof SPW)){
979                 return false;
980             }
981             SPW sp = (SPW)obj;
982             return (this.searchExpression.equals(sp.getSearchExpression()) &&
983                     this.wholeWords == sp.isWholeWords() &&
984                     this.matchCase == sp.isMatchCase() &&
985                     this.regExp == sp.isRegExp());
986         }
987
988         public int hashCode() {
989             int result = 17;
990             result = 37*result + (this.wholeWords ? 1:0);
991             result = 37*result + (this.matchCase ? 1:0);
992             result = 37*result + (this.regExp ? 1:0);
993             result = 37*result + this.searchExpression.hashCode();
994             return result;
995         }
996         
997         public String JavaDoc toString(){
998             StringBuffer JavaDoc sb = new StringBuffer JavaDoc("[SearchPatternWrapper:]\nsearchExpression:"+searchExpression);//NOI18N
999
sb.append('\n');
1000            sb.append("wholeWords:");//NOI18N
1001
sb.append(wholeWords);
1002            sb.append('\n');
1003            sb.append("matchCase:");//NOI18N
1004
sb.append(matchCase);
1005            sb.append('\n');
1006            sb.append("regExp:");//NOI18N
1007
sb.append(regExp);
1008            return sb.toString();
1009        }
1010    } // End of SPW class
1011
}
1012
Popular Tags