2
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
6
* The contents of this file are subject to the terms of either the GNU
7
* General Public License Version 2 only ("GPL") or the Common
8
* Development and Distribution License("CDDL") (collectively, the
9
* "License"). You may not use this file except in compliance with the
10
* License. You can obtain a copy of the License at
11
* http://www.netbeans.org/cddl-gplv2.html
12
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
* specific language governing permissions and limitations under the
14
* License. When distributing the software, include this License Header
15
* Notice in each file and include the License file at
16
* nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
17
* particular file as subject to the "Classpath" exception as provided
18
* by Sun in the GPL Version 2 section of the License file that
19
* accompanied this code. If applicable, add the following below the
20
* License Header, with the fields enclosed by brackets [] replaced by
21
* your own identifying information:
22
* "Portions Copyrighted [year] [name of copyright owner]"
26
* The Original Software is NetBeans. The Initial Developer of the Original
27
* Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
28
* Microsystems, Inc. All Rights Reserved.
30
* If you wish your version of this file to be governed by only the CDDL
31
* or only the GPL Version 2, indicate your decision by adding
32
* "[Contributor] elects to include this software in this distribution
33
* under the [CDDL or GPL Version 2] license." If you do not indicate a
34
* single choice of license, a recipient has the option to distribute
35
* your version of this file under either the CDDL, the GPL Version 2 or
36
* to extend the choice of license to its licensees as provided above.
37
* However, if you add GPL Version 2 code and therefore, elected the GPL
38
* Version 2 license, then the option applies only if the new code is
39
* made subject to such option by the copyright holder.
41
package org.netbeans.modules.editor.impl;
43
import java.awt.event.FocusEvent;
44
import javax.swing.event.PopupMenuEvent;
45
import javax.swing.text.BadLocationException;
46
import javax.swing.text.Document;
47
import javax.swing.text.Position;
48
import org.netbeans.editor.*;
49
import javax.swing.Action;
50
import org.openide.util.NbBundle;
52
import java.awt.Color;
53
import java.awt.Component;
54
import java.awt.Container;
55
import java.awt.Dimension;
56
import java.awt.Insets;
57
import java.awt.Toolkit;
58
import java.awt.event.ActionEvent;
59
import java.awt.event.ActionListener;
60
import java.awt.event.ComponentAdapter;
61
import java.awt.event.ComponentEvent;
62
import java.awt.event.FocusAdapter;
63
import java.awt.event.InputEvent;
64
import java.awt.event.KeyEvent;
65
import java.awt.event.MouseEvent;
66
import java.awt.event.MouseListener;
67
import java.util.ArrayList;
69
import java.util.HashMap;
70
import java.util.LinkedList;
71
import java.util.List;
73
import java.util.logging.Logger;
74
import java.util.regex.Pattern;
75
import java.util.regex.PatternSyntaxException;
77
import javax.swing.AbstractAction;
78
import javax.swing.AbstractButton;
79
import javax.swing.BoxLayout;
80
import javax.swing.ImageIcon;
81
import javax.swing.InputMap;
82
import javax.swing.JButton;
83
import javax.swing.JCheckBox;
84
import javax.swing.JComboBox;
85
import javax.swing.JComponent;
86
import javax.swing.JLabel;
87
import javax.swing.JPanel;
88
import javax.swing.JPopupMenu;
89
import javax.swing.JTextField;
90
import javax.swing.JToolBar;
91
import javax.swing.KeyStroke;
92
import javax.swing.MutableComboBoxModel;
93
import javax.swing.event.DocumentEvent;
94
import javax.swing.event.DocumentListener;
95
import javax.swing.event.PopupMenuListener;
96
import javax.swing.text.JTextComponent;
97
import javax.swing.text.Keymap;
98
import org.netbeans.api.editor.EditorRegistry;
99
import org.openide.awt.Mnemonics;
100
import org.openide.util.Utilities;
104
* This is an implementation of a Firefox(TM) style Incremental Search Side Bar.
106
* @author Sandip V. Chitale (Sandip.Chitale@Sun.Com)
108
public final class SearchBar extends JPanel {
110
private static final Logger LOG = Logger.getLogger(SearchBar.class.getName());
112
private static final Insets BUTTON_INSETS = new Insets(2, 1, 0, 1);
113
private static final Color NOT_FOUND = Color.RED.darker();
114
private static final Color INVALID_REGEXP = Color.red;
116
/** Shared mouse listener used for setting the border painting property
117
* of the toolbar buttons and for invoking the popup menu.
119
private static final MouseListener sharedMouseListener
120
= new org.openide.awt.MouseUtils.PopupMouseAdapter() {
121
public @Override void mouseEntered(MouseEvent evt) {
122
Object src = evt.getSource();
124
if (src instanceof JButton) { // ignore JMenuItem and JToggleButton
125
AbstractButton button = (AbstractButton)evt.getSource();
126
if (button.isEnabled()) {
127
button.setContentAreaFilled(true);
128
button.setBorderPainted(true);
133
public @Override void mouseExited(MouseEvent evt) {
134
Object src = evt.getSource();
135
if (src instanceof JButton) { // ignore JMenuItem and JToggleButton
136
AbstractButton button = (AbstractButton)evt.getSource();
137
button.setContentAreaFilled(false);
138
button.setBorderPainted(false);
142
protected void showPopup(MouseEvent evt) {
146
private JTextComponent component;
147
private JButton closeButton;
148
private JButton expandButton;
149
private JLabel findLabel;
150
private JComboBox incrementalSearchComboBox;
151
private JTextField incrementalSearchTextField;
152
private DocumentListener incrementalSearchTextFieldListener;
153
private JButton findNextButton;
154
private JButton findPreviousButton;
155
private JCheckBox matchCaseCheckBox;
156
private JCheckBox wholeWordsCheckBox;
157
private JCheckBox regexpCheckBox;
158
private JCheckBox highlightCheckBox;
159
private Map<Object, Object> findProps;
160
private JPopupMenu expandPopup;
161
private JPanel padding;
163
* contains everything that is in Search bar and is possible to move to expand popup
165
private final List<Component> inBar = new ArrayList<Component>();
167
* components moved to popup
169
private final LinkedList<Component> inPopup = new LinkedList<Component>();
171
* defines index of all components in Search bar
173
private final List<Component> barOrder = new ArrayList<Component>();
174
private boolean isPopupGoingToShow = false;
175
private boolean isPopupShown = false;
177
@SuppressWarnings("unchecked")
178
public SearchBar(JTextComponent component) {
179
this.component = component;
181
setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
182
Color bgColor = getBackground();
183
bgColor = new Color( Math.max( 0, bgColor.getRed() - 20 ),
184
Math.max( 0, bgColor.getGreen() - 20 ),
185
Math.max( 0, bgColor.getBlue() - 20 ) );
186
setBackground(bgColor);
188
//setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED));
189
addMouseListener(sharedMouseListener);
191
Keymap keymap = component.getKeymap();
193
if (keymap instanceof MultiKeymap) {
194
MultiKeymap multiKeymap = (MultiKeymap) keymap;
196
Action[] actions = component.getActions();
197
for(Action action:actions) {
198
// Discover the keyStrokes for incremental-search-forward
199
if (action.getValue(Action.NAME).equals(IncrementalSearchForwardAction.ACTION_NAME)) {
200
Action incrementalSearchForwardAction = action;
201
KeyStroke[] keyStrokes = multiKeymap.getKeyStrokesForAction(incrementalSearchForwardAction);
202
if (keyStrokes != null) {
203
InputMap inputMap = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
204
for(KeyStroke ks : keyStrokes) {
205
LOG.fine("found IncrementalSearchForwardAction, " + ks); //NOI18N
206
inputMap.put(ks, IncrementalSearchForwardAction.ACTION_NAME);
208
getActionMap().put(IncrementalSearchForwardAction.ACTION_NAME,
209
new AbstractAction() {
210
public void actionPerformed(ActionEvent e) {
215
// Discover the keyStrokes for incremental-search-backward
216
} else if (action.getValue(Action.NAME).equals(IncrementalSearchBackwardAction.ACTION_NAME)) {
217
Action incrementalSearchBackwardAction = action;
218
KeyStroke[] keyStrokes = multiKeymap.getKeyStrokesForAction(incrementalSearchBackwardAction);
219
if (keyStrokes != null) {
220
InputMap inputMap = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
221
for(KeyStroke ks : keyStrokes) {
222
LOG.fine("found IncrementalSearchBackwardAction, " + ks); //NOI18N
223
inputMap.put(ks, IncrementalSearchBackwardAction.ACTION_NAME);
225
getActionMap().put(IncrementalSearchBackwardAction.ACTION_NAME,
226
new AbstractAction() {
227
public void actionPerformed(ActionEvent e) {
236
// ESCAPE to put focus back in the editor
237
getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
238
.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, true),
239
"loose-focus"); // NOI18N
240
getActionMap().put("loose-focus", // NOI18N
241
new AbstractAction() {
242
public void actionPerformed(ActionEvent e) {
247
closeButton = new JButton(new ImageIcon(Utilities.loadImage("org/netbeans/modules/editor/resources/find_close.png"))); // NOI18N
248
closeButton.addActionListener(new ActionListener() {
249
public void actionPerformed(ActionEvent e) {
253
closeButton.setToolTipText(NbBundle.getMessage(SearchBar.class, "TOOLTIP_CloseIncrementalSearchSidebar")); // NOI18N
254
processButton(closeButton);
256
expandButton = new JButton(new ImageIcon(Utilities.loadImage("org/netbeans/modules/editor/resources/find_expand.png"))); // NOI18N
257
expandButton.setMnemonic(NbBundle.getMessage(SearchBar.class, "CTL_ExpandButton_Mnemonic").charAt(0)); // NOI18N
258
processButton(expandButton);
259
expandButton.addActionListener(new ActionListener() {
260
public void actionPerformed(ActionEvent e) {
261
boolean state = !isPopupShown;
262
isPopupShown = state;
271
findLabel = new JLabel();
272
Mnemonics.setLocalizedText( findLabel, NbBundle.getMessage(SearchBar.class, "CTL_Find")); // NOI18N
274
// configure incremental search text field
275
incrementalSearchComboBox = new JComboBox()
277
public @Override Dimension getMinimumSize() {
278
return getPreferredSize();
281
public @Override Dimension getMaximumSize() {
282
return getPreferredSize();
285
incrementalSearchComboBox.setEditable(true);
286
incrementalSearchTextField = (JTextField) incrementalSearchComboBox.getEditor().getEditorComponent();
287
incrementalSearchTextField.setToolTipText(NbBundle.getMessage(SearchBar.class, "TOOLTIP_IncrementalSearchText")); // NOI18N
289
// listen on text change
290
incrementalSearchTextFieldListener = new DocumentListener() {
291
public void changedUpdate(DocumentEvent e) {
294
public void insertUpdate(DocumentEvent e) {
295
// text changed - attempt incremental search
299
public void removeUpdate(DocumentEvent e) {
300
// text changed - attempt incremental search
304
incrementalSearchTextField.getDocument().addDocumentListener(incrementalSearchTextFieldListener);
306
incrementalSearchTextField.addFocusListener(new FocusAdapter() {
307
public @Override void focusLost(FocusEvent e) {
312
// ENTER to find next
313
incrementalSearchTextField.addActionListener(new ActionListener() {
314
public void actionPerformed(ActionEvent e) {
319
// Shift+ENTER to find previous
320
incrementalSearchTextField.getInputMap()
321
.put(KeyStroke.getKeyStroke(
322
KeyEvent.VK_ENTER, InputEvent.SHIFT_MASK, true),
323
"incremental-find-previous"); // NOI18N
324
incrementalSearchTextField.getActionMap().put("incremental-find-previous", // NOI18N
325
new AbstractAction() {
326
public void actionPerformed(ActionEvent e) {
330
// configure find next button
331
findNextButton = new JButton(
332
new ImageIcon(Utilities.loadImage("org/netbeans/modules/editor/resources/find_next.png"))); // NOI18N
333
Mnemonics.setLocalizedText( findNextButton, NbBundle.getMessage(SearchBar.class, "CTL_FindNext")); // NOI18N
334
findNextButton.addActionListener(new ActionListener() {
335
public void actionPerformed(ActionEvent e) {
338
processButton(findNextButton);
340
// configure find previous button
341
findPreviousButton = new JButton(
342
new ImageIcon(Utilities.loadImage("org/netbeans/modules/editor/resources/find_previous.png"))); // NOI18N
343
Mnemonics.setLocalizedText(findPreviousButton, NbBundle.getMessage(SearchBar.class, "CTL_FindPrevious")); // NOI18N
344
findPreviousButton.addActionListener(new ActionListener() {
345
public void actionPerformed(ActionEvent e) {
349
processButton(findPreviousButton);
351
// configure match case check box
352
matchCaseCheckBox = new JCheckBox();
353
Mnemonics.setLocalizedText(matchCaseCheckBox, NbBundle.getMessage(SearchBar.class, "CTL_MatchCase")); // NOI18N
354
matchCaseCheckBox.addActionListener(new ActionListener() {
355
public void actionPerformed(ActionEvent e) {
356
// Put focus back in the incremental search textField
358
incrementalSearchTextField.requestFocusInWindow();
361
processButton(matchCaseCheckBox);
363
wholeWordsCheckBox = new JCheckBox();
364
Mnemonics.setLocalizedText(wholeWordsCheckBox, NbBundle.getMessage(SearchBar.class, "CTL_WholeWords")); // NOI18N
365
wholeWordsCheckBox.addActionListener(new ActionListener() {
366
public void actionPerformed(ActionEvent e) {
367
// Put focus back in the incremental search textField
369
incrementalSearchTextField.requestFocusInWindow();
372
processButton(wholeWordsCheckBox);
374
regexpCheckBox = new JCheckBox();
375
Mnemonics.setLocalizedText(regexpCheckBox, NbBundle.getMessage(SearchBar.class, "CTL_Regexp")); // NOI18N
376
regexpCheckBox.addActionListener(new ActionListener() {
377
public void actionPerformed(ActionEvent e) {
378
// Switch other checkbozes on/off
379
wholeWordsCheckBox.setEnabled(!regexpCheckBox.isSelected());
380
// Put focus back in the incremental search textField
382
incrementalSearchTextField.requestFocusInWindow();
385
processButton(regexpCheckBox);
387
highlightCheckBox = new JCheckBox();
388
Mnemonics.setLocalizedText(highlightCheckBox, NbBundle.getMessage(SearchBar.class, "CTL_Highlight")); // NOI18N
389
highlightCheckBox.addActionListener(new ActionListener() {
390
public void actionPerformed(ActionEvent e) {
391
// Put focus back in the incremental search textField
393
incrementalSearchTextField.requestFocusInWindow();
396
highlightCheckBox.setSelected(true);
397
processButton(highlightCheckBox);
399
expandPopup = new JPopupMenu();
400
expandPopup.addPopupMenuListener(new PopupMenuListener() {
402
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
405
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
408
public void popupMenuCanceled(PopupMenuEvent e) {
409
// check if it was canceled by click on expand button
410
if (expandButton.getMousePosition() == null) {
411
expandButton.setContentAreaFilled(false);
412
expandButton.setBorderPainted(false);
413
isPopupShown = false;
418
// configure find properties
419
findProps = new HashMap<Object, Object>();
420
findProps.put(SettingsNames.FIND_HIGHLIGHT_SEARCH, true);
421
findProps.put(SettingsNames.FIND_WHOLE_WORDS, false);
422
findProps.put(SettingsNames.FIND_WRAP_SEARCH, true);
423
findProps.put(SettingsNames.FIND_BLOCK_SEARCH, false);
424
findProps.put(SettingsNames.FIND_BLOCK_SEARCH_START, null);
425
findProps.put(SettingsNames.FIND_BLOCK_SEARCH_END, null);
426
// XXX take from preferences
427
findProps.put(SettingsNames.FIND_MATCH_CASE, false);
428
findProps.put(SettingsNames.FIND_REG_EXP, false);
429
findProps.put(SettingsNames.FIND_HIGHLIGHT_SEARCH, true);
431
// padding at the end of the toolbar
432
JPanel spacer = new JPanel();
433
spacer.setSize(4, 4);
434
spacer.setMaximumSize(new Dimension(4,4));
435
spacer.setOpaque(false);
439
add(incrementalSearchComboBox);
440
add(new JToolBar.Separator());
441
add(findPreviousButton);
443
add(new JToolBar.Separator());
444
add(matchCaseCheckBox);
445
add(wholeWordsCheckBox);
447
add(highlightCheckBox);
449
// padding at the end of the toolbar
450
padding = new JPanel();
451
padding.setOpaque(false);
457
// initially not visible
460
this.addComponentListener(new ComponentAdapter() {
462
public void componentResized(ComponentEvent evt) {
468
private void makeBarExpandable() {
469
// inBar.add(findPreviousButton);
470
// inBar.add(findNextButton);
471
inBar.add(matchCaseCheckBox);
472
inBar.add(wholeWordsCheckBox);
473
inBar.add(regexpCheckBox);
474
inBar.add(highlightCheckBox);
475
for (Component c : this.getComponents()) {
478
remove(expandButton);
481
private void computeLayout() {
482
Container parent = this.getParent();
483
int parentWidth = parent.getWidth();
486
boolean change = false;
488
for (Component c : this.getComponents()) {
490
totalWidth += c.getWidth();
494
if (totalWidth <= parentWidth) {
495
// enough space try to clear expand popup
496
while (!inPopup.isEmpty()) {
497
Component c = inPopup.getFirst();
498
totalWidth += c.getWidth();
500
if (totalWidth > parentWidth) {
503
inPopup.removeFirst();
505
expandPopup.remove(c);
506
add(c, barOrder.indexOf(c));
511
while (totalWidth > parentWidth && !inBar.isEmpty()) {
512
Component c = inBar.remove(inBar.size() - 1);
515
expandPopup.add(c, 0);
516
totalWidth -= c.getWidth();
522
if (inPopup.isEmpty()) {
523
remove(expandButton);
524
} else if (getComponentIndex(expandButton) < 0) {
525
add(expandButton, getComponentIndex(padding));
528
expandPopup.invalidate();
529
expandPopup.validate();
533
private int getComponentIndex(Component c) {
534
Component[] comps = getComponents();
535
for (int i = 0; i < comps.length; i++) {
543
private void showExpandedMenu() {
544
if (!inPopup.isEmpty() && !expandPopup.isVisible()) {
545
isPopupGoingToShow = true;
546
Insets ins = expandPopup.getInsets();
547
// compute popup height since JPopupMenu.getHeight does not work
548
expandPopup.show(expandButton, 0, -(matchCaseCheckBox.getHeight() * inPopup.size() + ins.top + ins.bottom));
552
private void hideExpandedMenu() {
553
if (expandPopup.isVisible()) {
554
expandPopup.setVisible(false);
556
incrementalSearchTextField.requestFocusInWindow();
560
public @Override String getName() {
561
//Required for Aqua L&F toolbar UI
562
return "editorSearchBar"; // NOI18N
565
private void gainFocus() {
567
incrementalSearchTextField.requestFocusInWindow();
571
isPopupShown = false;
575
incrementalSearchTextField.requestFocusInWindow();
577
if (incrementalSearchTextField.getText().length() > 0) {
578
// preselect the text in incremental search text field
579
incrementalSearchTextField.selectAll();
580
findPreviousButton.setEnabled(true);
581
findNextButton.setEnabled(true);
584
findPreviousButton.setEnabled(false);
585
findNextButton.setEnabled(false);
589
private void looseFocus() {
590
if (isPopupGoingToShow) {
591
isPopupGoingToShow = false;
594
FindSupport.getFindSupport().setBlockSearchHighlight(0, 0);
595
FindSupport.getFindSupport().incSearchReset();
598
if (component.isEnabled()) {
599
component.requestFocusInWindow();
603
private void incrementalSearch() {
604
String incrementalSearchText = incrementalSearchTextField.getText();
605
boolean empty = incrementalSearchText.length() <= 0;
607
// Enable/disable the pre/next buttons
608
findPreviousButton.setEnabled(!empty);
609
findNextButton.setEnabled(!empty);
611
// configure find properties
612
FindSupport findSupport = FindSupport.getFindSupport();
614
findProps.put(SettingsNames.FIND_WHAT, incrementalSearchText);
615
findProps.put(SettingsNames.FIND_MATCH_CASE, matchCaseCheckBox.isSelected());
616
findProps.put(SettingsNames.FIND_WHOLE_WORDS, wholeWordsCheckBox.isSelected());
617
findProps.put(SettingsNames.FIND_REG_EXP, regexpCheckBox.isSelected());
618
findProps.put(SettingsNames.FIND_HIGHLIGHT_SEARCH, !empty && highlightCheckBox.isSelected());
620
findProps.put(SettingsNames.FIND_BACKWARD_SEARCH, false);
621
findProps.put(SettingsNames.FIND_INC_SEARCH, true);
623
findSupport.putFindProperties(findProps);
625
// search starting at current caret position
626
int caretPosition = component.getCaretPosition();
628
if (regexpCheckBox.isSelected()) {
631
pattern = Pattern.compile(incrementalSearchText);
632
} catch (PatternSyntaxException e) {
635
if (pattern != null) {
637
incrementalSearchTextField.setBackground(null);
638
incrementalSearchTextField.setForeground(Color.BLACK);
641
incrementalSearchTextField.setBackground(null);
642
incrementalSearchTextField.setForeground(INVALID_REGEXP);
645
if (findSupport.incSearch(findProps, caretPosition) || empty) {
646
// text found - reset incremental search text field's foreground
647
incrementalSearchTextField.setBackground(null);
648
incrementalSearchTextField.setForeground(Color.BLACK);
650
// text not found - indicate error in incremental search
651
// text field with red foreground
652
incrementalSearchTextField.setBackground(null);
653
incrementalSearchTextField.setForeground(NOT_FOUND);
654
Toolkit.getDefaultToolkit().beep();
659
private void findNext() {
663
private void findPrevious() {
667
private void find(boolean next) {
668
String incrementalSearchText = incrementalSearchTextField.getText();
669
boolean empty = incrementalSearchText.length() <= 0;
671
incrementalSearchTextField.getDocument().removeDocumentListener(incrementalSearchTextFieldListener);
672
// Add the text to the top of the list
673
for(int i = incrementalSearchComboBox.getItemCount() - 1; i >= 0; i--) {
674
String item = (String) incrementalSearchComboBox.getItemAt(i);
675
if (item.equals(incrementalSearchText)) {
676
incrementalSearchComboBox.removeItemAt(i);
679
((MutableComboBoxModel) incrementalSearchComboBox.getModel()).insertElementAt(incrementalSearchText, 0);
680
incrementalSearchComboBox.setSelectedIndex(0);
681
incrementalSearchTextField.getDocument().addDocumentListener(incrementalSearchTextFieldListener);
683
// configure find properties
684
FindSupport findSupport = FindSupport.getFindSupport();
686
findProps.put(SettingsNames.FIND_WHAT, incrementalSearchText);
687
findProps.put(SettingsNames.FIND_MATCH_CASE, matchCaseCheckBox.isSelected());
688
findProps.put(SettingsNames.FIND_WHOLE_WORDS, wholeWordsCheckBox.isSelected());
689
findProps.put(SettingsNames.FIND_REG_EXP, regexpCheckBox.isSelected());
690
findProps.put(SettingsNames.FIND_BACKWARD_SEARCH, Boolean.FALSE);
691
findProps.put(SettingsNames.FIND_INC_SEARCH, Boolean.TRUE);
692
findProps.put(SettingsNames.FIND_HIGHLIGHT_SEARCH, !empty && highlightCheckBox.isSelected());
694
findSupport.putFindProperties(findProps);
696
if (findSupport.find(findProps, !next) || empty) {
697
// text found - reset incremental search text field's foreground
698
incrementalSearchTextField.setBackground(null);
699
incrementalSearchTextField.setForeground(Color.BLACK);
701
// text not found - indicate error in incremental search text field with red foreground
702
incrementalSearchTextField.setBackground(null);
703
incrementalSearchTextField.setForeground(NOT_FOUND);
704
Toolkit.getDefaultToolkit().beep();
708
private void processButton(AbstractButton button) {
709
button.setContentAreaFilled(false);
710
button.setBorderPainted(false);
711
button.setMargin(BUTTON_INSETS);
712
if (button instanceof JButton) {
713
button.addMouseListener(sharedMouseListener);
715
button.setFocusable(false);
718
@SuppressWarnings("unchecked")
719
private void initBlockSearch() {
720
JTextComponent c = EditorRegistry.lastFocusedComponent();
721
String selText = null;
722
int startSelection = 0;
723
int endSelection = 0;
724
boolean blockSearchVisible = false;
727
startSelection = c.getSelectionStart();
728
endSelection = c.getSelectionEnd();
730
Document doc = c.getDocument();
731
if (doc instanceof BaseDocument){
732
BaseDocument bdoc = (BaseDocument) doc;
734
int startLine = org.netbeans.editor.Utilities.getLineOffset(bdoc, startSelection);
735
int endLine = org.netbeans.editor.Utilities.getLineOffset(bdoc, endSelection);
736
if (endLine > startLine) {
737
blockSearchVisible = true;
739
} catch (BadLocationException ble){
743
// caretPosition = bwdSearch.isSelected() ? c.getSelectionEnd() : c.getSelectionStart();
745
if (!blockSearchVisible){
746
selText = c.getSelectedText();
747
if (selText != null && selText.length() > 0) {
748
int n = selText.indexOf( '\n' );
749
if (n >= 0 ) selText = selText.substring(0, n);
750
incrementalSearchTextField.setText(selText);
751
// findWhat.getEditor().setItem(selText);
752
// changeFindWhat(true);
754
String findWhat = (String) FindSupport.getFindSupport().getFindProperty(SettingsNames.FIND_WHAT);
755
if (findWhat != null && findWhat.length() > 0) {
756
incrementalSearchTextField.setText(findWhat);
761
int blockSearchStartPos = blockSearchVisible ? startSelection : 0;
762
int blockSearchEndPos = blockSearchVisible ? endSelection : 0;
765
findProps.put(SettingsNames.FIND_BLOCK_SEARCH, blockSearchVisible);
766
findProps.put(SettingsNames.FIND_BLOCK_SEARCH_START, blockSearchStartPos);
767
int be = getBlockEndOffset();
769
findProps.put(SettingsNames.FIND_BLOCK_SEARCH_END, doc.createPosition(blockSearchEndPos));
771
blockSearchEndPos = be;
773
FindSupport.getFindSupport().setBlockSearchHighlight(blockSearchStartPos, blockSearchEndPos);
774
} catch(BadLocationException ble){
775
findProps.put(SettingsNames.FIND_BLOCK_SEARCH, Boolean.FALSE);
776
findProps.put(SettingsNames.FIND_BLOCK_SEARCH_START, null);
779
FindSupport.getFindSupport().putFindProperties(findProps);
783
private int getBlockEndOffset(){
784
Position pos = (Position) FindSupport.getFindSupport().getFindProperties().get(SettingsNames.FIND_BLOCK_SEARCH_END);
785
return (pos != null) ? pos.getOffset() : -1;
789
* Factory for creating the incremental search sidebar
791
public static final class Factory implements SideBarFactory {
792
public JComponent createSideBar(JTextComponent target) {
793
return new SearchBar(target);
797
public static class IncrementalSearchForwardAction extends BaseAction {
799
public static final String ACTION_NAME = "incremental-search-forward"; // NOI18N
801
static final long serialVersionUID = -1;
803
public IncrementalSearchForwardAction() {
804
super(ACTION_NAME, CLEAR_STATUS_TEXT);
805
putValue(SHORT_DESCRIPTION, NbBundle.getMessage(IncrementalSearchForwardAction.class, ACTION_NAME));
808
public void actionPerformed(ActionEvent evt, JTextComponent target) {
809
if (target != null) {
810
EditorUI eui = org.netbeans.editor.Utilities.getEditorUI(target);
812
JComponent comp = eui.getExtComponent();
814
SearchBar issb = findComponent(comp,SearchBar.class, 5);
824
public static class IncrementalSearchBackwardAction extends BaseAction {
826
public static final String ACTION_NAME = "incremental-search-backward"; // NOI18N
828
static final long serialVersionUID = -1;
830
public IncrementalSearchBackwardAction() {
831
super(ACTION_NAME, CLEAR_STATUS_TEXT);
832
putValue(SHORT_DESCRIPTION, NbBundle.getMessage(IncrementalSearchBackwardAction.class, ACTION_NAME));
835
public void actionPerformed(ActionEvent evt, JTextComponent target) {
836
if (target != null) {
837
EditorUI eui = org.netbeans.editor.Utilities.getEditorUI(target);
839
JComponent comp = eui.getExtComponent();
841
SearchBar issb = findComponent(comp,SearchBar.class, 5);
851
private static <T> T findComponent(Container container, Class<T> componentClass, int depth) {
853
for(Component c : container.getComponents()) {
854
if (componentClass.isAssignableFrom(c.getClass())) {
855
@SuppressWarnings("unchecked")
858
} else if (c instanceof Container) {
859
T target = findComponent((Container) c, componentClass, depth - 1);
860
if (target != null) {