blob: 61ce33ab5299aef4667aa7650c417c364d374374 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.editor.search;
import java.awt.*;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import java.util.prefs.Preferences;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.text.*;
import org.netbeans.api.editor.EditorRegistry;
import org.netbeans.api.editor.mimelookup.MimeLookup;
import org.netbeans.api.editor.mimelookup.MimePath;
import org.netbeans.api.editor.settings.SimpleValueNames;
import org.netbeans.api.editor.caret.EditorCaret;
import org.netbeans.api.search.ReplacePattern;
import org.netbeans.api.search.SearchHistory;
import org.netbeans.api.search.SearchPattern;
import org.netbeans.editor.BaseDocument;
import org.netbeans.editor.BaseKit;
import org.netbeans.editor.MultiKeymap;
import org.netbeans.modules.editor.search.SearchPropertiesSupport.SearchProperties;
import org.openide.awt.CloseButtonFactory;
import org.openide.awt.Mnemonics;
import org.openide.awt.StatusDisplayer;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
import org.openide.util.WeakListeners;
/**
* This is an implementation of a Firefox(TM) style Incremental Search Side Bar.
*
* @author Sandip V. Chitale (Sandip.Chitale@Sun.Com)
*/
public final class SearchBar extends JPanel implements PropertyChangeListener {
private static SearchBar searchbarInstance = null;
private static final Logger LOG = Logger.getLogger(SearchBar.class.getName());
private static final Insets BUTTON_INSETS = new Insets(2, 1, 0, 1);
private static final Color NOT_FOUND = UIManager.getColor("nb.errorForeground");
private static final Color INVALID_REGEXP = Color.red;
// Delay times for incremental search [ms]
private static final int SEARCH_DELAY_TIME_LONG = 300; // < 3 chars
private static final int SEARCH_DELAY_TIME_SHORT = 20; // >= 3 chars
private static final Color DEFAULT_FG_COLOR = isCurrentLF("Nimbus") ? UIManager.getColor("text") : UIManager.getColor("textText"); //NOI18N
private WeakReference<JTextComponent> actualTextComponent;
private final List<PropertyChangeListener> actualComponentListeners = new LinkedList<>();
private FocusAdapter focusAdapterForComponent;
private int regainFocusState; // 0==do not regain; 1==regain; 2==check-on-next-focusGained
private KeyListener keyListenerForComponent;
private CaretListener caretListenerForComponent;
private PropertyChangeListener propertyChangeListenerForComponent;
private final JLabel findLabel;
private final JComboBox<String> incSearchComboBox;
private final JTextComponent incSearchTextField;
private final DocumentListener incSearchTextFieldListener;
private boolean hadFocusOnIncSearchTextField = false;
private final JButton findNextButton;
private final JButton findPreviousButton;
private final JButton selectAllButton;
private final JToggleButton matchCase;
private final JToggleButton wholeWords;
private final JToggleButton regexp;
private final JToggleButton highlight;
private final JToggleButton wrapAround;
private final JButton closeButton;
private final JLabel matches;
private int numOfMatches = -1;
private SearchProperties searchProps = SearchPropertiesSupport.getSearchProperties();
private boolean popupMenuWasCanceled = false;
private Rectangle actualViewPort;
private boolean highlightCanceled = false;
private boolean whenOpenedWasNotVisible = false;
private boolean lastIncrementalSearchWasSuccessful = true;
public static SearchBar getInstance() {
if (searchbarInstance == null) {
searchbarInstance = new SearchBar();
}
return searchbarInstance;
}
/*
* default getInstance
*/
public static SearchBar getInstance(JTextComponent component) {
SearchBar searchbarIns = getInstance();
if (searchbarIns.getActualTextComponent() != component) {
searchbarIns.setActualTextComponent(component);
}
return searchbarIns;
}
@SuppressWarnings("unchecked")
private SearchBar() {
loadSearchHistory();
addEscapeKeystrokeFocusBackTo(this);
setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
setFocusCycleRoot(true);
setForeground(DEFAULT_FG_COLOR); //NOI18N
setBorder(new SeparatorBorder());
add(Box.createHorizontalStrut(8)); //spacer in the beginnning of the toolbar
SearchComboBox<String> scb = new SearchComboBox<>();
incSearchComboBox = scb;
incSearchComboBox.setFocusable(false);
incSearchComboBox.addPopupMenuListener(new SearchPopupMenuListener());
incSearchTextField = scb.getEditorPane();
//todo fix no effect
incSearchTextField.setToolTipText(NbBundle.getMessage(SearchBar.class, "TOOLTIP_IncrementalSearchText")); //NOI18N
incSearchTextFieldListener = createIncSearchTextFieldListener(incSearchTextField);
incSearchTextField.getDocument().addDocumentListener(incSearchTextFieldListener);
addEnterKeystrokeFindNextTo(incSearchTextField);
addShiftEnterKeystrokeFindPreviousTo(incSearchTextField);
addAltEnterKeystrokeSelect(incSearchTextField);
if (getCurrentKeyMapProfile().startsWith("Emacs")) { // NOI18N
emacsProfileFix(incSearchTextField);
}
incSearchTextField.addFocusListener(new FocusAdapter() {
@Override
public void focusGained(FocusEvent e) {
hadFocusOnIncSearchTextField = true;
}
});
findLabel = new JLabel();
Mnemonics.setLocalizedText(findLabel, NbBundle.getMessage(SearchBar.class, "CTL_Find")); // NOI18N
findLabel.setLabelFor(incSearchTextField);
add(findLabel);
add(incSearchComboBox);
final JToolBar.Separator leftSeparator = new JToolBar.Separator();
leftSeparator.setOrientation(SwingConstants.VERTICAL);
add(leftSeparator);
findPreviousButton = SearchButton.createButton("org/netbeans/modules/editor/search/resources/find_previous.png", "CTL_FindPrevious"); // NOI18N
findPreviousButton.setToolTipText(NbBundle.getMessage(SearchBar.class, "TOOLTIP_IncrementalSearchText")); //NOI18N
findPreviousButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
findPrevious();
}
});
add(findPreviousButton);
findNextButton = SearchButton.createButton("org/netbeans/modules/editor/search/resources/find_next.png", "CTL_FindNext"); // NOI18N
findNextButton.setToolTipText(NbBundle.getMessage(SearchBar.class, "TOOLTIP_IncrementalSearchText")); //NOI18N
findNextButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
findNext();
}
});
add(findNextButton);
selectAllButton = SearchButton.createButton("org/netbeans/modules/editor/search/resources/select_all.png", "CTL_SelectAll"); // NOI18N
selectAllButton.setToolTipText(NbBundle.getMessage(SearchBar.class, "TOOLTIP_SelectAllText")); //NOI18N
selectAllButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
selectAll();
}
});
add(selectAllButton);
final JToolBar.Separator rightSeparator = new JToolBar.Separator();
rightSeparator.setOrientation(SwingConstants.VERTICAL);
add(rightSeparator);
matchCase = SearchButton.createToggleButton("org/netbeans/modules/editor/search/resources/matchCase.png"); //NOI18N
processToggleButton(matchCase, EditorFindSupport.FIND_MATCH_CASE);
matchCase.setToolTipText(NbBundle.getMessage(SearchBar.class, "TT_MatchCase")); //NOI18N
add(matchCase);
wholeWords = SearchButton.createToggleButton("org/netbeans/modules/editor/search/resources/wholeWord.png"); //NOI18N
processToggleButton(wholeWords, EditorFindSupport.FIND_WHOLE_WORDS);
wholeWords.setToolTipText(NbBundle.getMessage(SearchBar.class, "TT_WholeWords")); //NOI18N
add(wholeWords);
regexp = SearchButton.createToggleButton("org/netbeans/modules/editor/search/resources/regexp.png"); //NOI18N
processToggleButton(regexp, EditorFindSupport.FIND_REG_EXP);
regexp.setToolTipText(NbBundle.getMessage(SearchBar.class, "TT_Regexp")); //NOI18N
add(regexp);
highlight = SearchButton.createToggleButton("org/netbeans/modules/editor/search/resources/highlight.png"); //NOI18N
processToggleButton(highlight, EditorFindSupport.FIND_HIGHLIGHT_SEARCH);
highlight.setToolTipText(NbBundle.getMessage(SearchBar.class, "TT_Highlight")); //NOI18N
add(highlight);
wrapAround = SearchButton.createToggleButton("org/netbeans/modules/editor/search/resources/wrapAround.png" ); //NOI18N
processToggleButton(wrapAround, EditorFindSupport.FIND_WRAP_SEARCH);
add(wrapAround);
wrapAround.setToolTipText(NbBundle.getMessage(SearchBar.class, "TT_WrapAround")); //NOI18N
selectCheckBoxes();
addCheckBoxesActions(incSearchTextField);
EditorFindSupport.getInstance().addPropertyChangeListener(WeakListeners.propertyChange(this, EditorFindSupport.getInstance()));
matches = new JLabel();
add(Box.createHorizontalGlue());
add(matches);
add(Box.createHorizontalStrut(8)); //spacer in the ending of the toolbar
closeButton = createCloseButton();
add(closeButton);
setVisible(false);
usageLogging();
}
void addCheckBoxesActions(JTextComponent incSearchTextField) {
String key = "matchcasekey";
incSearchTextField.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.ALT_DOWN_MASK), key);
incSearchTextField.getActionMap().put(key, new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
matchCase.doClick();
}
} );
key = "wholewordkey";
incSearchTextField.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_O, InputEvent.ALT_DOWN_MASK), key);
incSearchTextField.getActionMap().put(key, new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
wholeWords.doClick();
}
} );
key = "regexpkey";
incSearchTextField.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_G, InputEvent.ALT_DOWN_MASK), key);
incSearchTextField.getActionMap().put(key, new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
regexp.doClick();
}
} );
key = "highlightkey";
incSearchTextField.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_H, InputEvent.ALT_DOWN_MASK), key);
incSearchTextField.getActionMap().put(key, new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
highlight.doClick();
}
} );
key = "wraparoundkey";
incSearchTextField.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_U, InputEvent.ALT_DOWN_MASK), key);
incSearchTextField.getActionMap().put(key, new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
wrapAround.doClick();
}
} );
}
void notifyFocusLost(PropertyChangeEvent focusLostRegistryEvt) {
Component origFocusedComponent = (Component) focusLostRegistryEvt.getOldValue();
Component focusGainingComponent = (Component) focusLostRegistryEvt.getNewValue();
// If the searchbar (or replacebar) had a focus and the focus is lost to a text component registered
// in EditorRegistry then attempt to regain the focus later.
if (origFocusedComponent == incSearchTextField ||
origFocusedComponent == ReplaceBar.getInstance(SearchBar.this).getReplaceTextField() ||
origFocusedComponent == getActualTextComponent()) // ER reports actual TC when focus in search field
{
if (focusGainingComponent == null) { // Must check on focusGained
regainFocusState = 2;
} else if (focusGainingComponent instanceof JTextComponent &&
EditorRegistry.componentList().contains(focusGainingComponent))
{
regainFocusState = 1;
} else {
regainFocusState = 0;
}
}
}
void checkRegainFocus(PropertyChangeEvent focusGainedRegistryEvt) {
if (regainFocusState == 2) { // On focusLost the focus gaining component was null
Component origFocusedComponent = (Component) focusGainedRegistryEvt.getOldValue();
// Check if the focus came from the actual component of this searchbar
// (other components like OutlineView for search results or find-usages results mean no focus regain
if (origFocusedComponent == null || // Can be used when opening a new editor
origFocusedComponent == getActualTextComponent() ||
origFocusedComponent instanceof JFrame) // This parent is used when switching tabs so it must be allowed here
{
regainFocusState = 1;
} else {
regainFocusState = 0;
}
if (regainFocusState == 1) {
ReplaceBar replaceBar = ReplaceBar.getInstance(this);
JTextComponent c;
if (this.hadFocusOnTextField()) {
if (replaceBar.isVisible() && (c = getActualTextComponent()) != null && c.isEditable()) {
replaceBar.gainFocus(true);
} else {
this.gainFocus(true);
}
}
}
}
}
private static class SearchHistoryUtility {
public static List<EditorFindSupport.SPW> convertFromSearchHistoryToEditorFindSupport(List<SearchPattern> searchPatterns) {
List<EditorFindSupport.SPW> history = new ArrayList<>();
for (int i = 0; i < searchPatterns.size(); i++) {
SearchPattern sptr = searchPatterns.get(i);
EditorFindSupport.SPW spwrap = new EditorFindSupport.SPW(sptr.getSearchExpression(),
sptr.isWholeWords(), sptr.isMatchCase(), sptr.isRegExp());
history.add(spwrap);
}
return history;
}
public static List<EditorFindSupport.RP> convertFromReplaceHistoryToEditorFindSupport(List<ReplacePattern> replacePatterns) {
List<EditorFindSupport.RP> history = new ArrayList<>();
for (int i = 0; i < replacePatterns.size(); i++) {
ReplacePattern rp = replacePatterns.get(i);
EditorFindSupport.RP spwrap = new EditorFindSupport.RP(rp.getReplaceExpression(), rp.isPreserveCase());
history.add(spwrap);
}
return history;
}
}
private static PropertyChangeListener searchSelectedPatternListener;
private static PropertyChangeListener editorHistoryChangeListener;
private static void loadSearchHistory() {
searchSelectedPatternListener = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt == null || evt.getPropertyName() == null) {
return;
}
switch(evt.getPropertyName()) {
case SearchHistory.ADD_TO_HISTORY:
EditorFindSupport.getInstance().setHistory(
SearchHistoryUtility.convertFromSearchHistoryToEditorFindSupport(SearchHistory.getDefault().getSearchPatterns()));
break;
case SearchHistory.ADD_TO_REPLACE:
EditorFindSupport.getInstance().setReplaceHistory(
SearchHistoryUtility.convertFromReplaceHistoryToEditorFindSupport(SearchHistory.getDefault().getReplacePatterns()));
break;
}
}
};
editorHistoryChangeListener = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt == null || evt.getPropertyName() == null) {
return;
}
switch (evt.getPropertyName()) {
case EditorFindSupport.FIND_HISTORY_PROP:
EditorFindSupport.SPW spw = (EditorFindSupport.SPW) evt.getNewValue();
if (spw == null || spw.getSearchExpression() == null || "".equals(spw.getSearchExpression())) { //NOI18N
return;
}
SearchPattern sp = SearchPattern.create(spw.getSearchExpression(),
spw.isWholeWords(), spw.isMatchCase(), spw.isRegExp());
SearchHistory.getDefault().add(sp);
if (!SearchBar.getInstance().incSearchTextField.getText().equals(sp.getSearchExpression())) {
SearchBar.getInstance().incSearchTextField.setText(sp.getSearchExpression());
}
break;
case EditorFindSupport.FIND_HISTORY_CHANGED_PROP:
EditorFindSupport.getInstance().setHistory(
SearchHistoryUtility.convertFromSearchHistoryToEditorFindSupport(SearchHistory.getDefault().getSearchPatterns()));
break;
case EditorFindSupport.REPLACE_HISTORY_PROP:
EditorFindSupport.RP rp = (EditorFindSupport.RP) evt.getNewValue();
if (rp == null || rp.getReplaceExpression() == null || "".equals(rp.getReplaceExpression())) { //NOI18N
return;
}
ReplacePattern replacePattern = ReplacePattern.create(rp.getReplaceExpression(), rp.isPreserveCase());
SearchHistory.getDefault().addReplace(replacePattern);
break;
case EditorFindSupport.REPLACE_HISTORY_CHANGED_PROP:
EditorFindSupport.getInstance().setReplaceHistory(
SearchHistoryUtility.convertFromReplaceHistoryToEditorFindSupport(SearchHistory.getDefault().getReplacePatterns()));
break;
}
}
};
SearchHistory.getDefault().addPropertyChangeListener(searchSelectedPatternListener);
EditorFindSupport.getInstance().addPropertyChangeListener(editorHistoryChangeListener);
}
private static void usageLogging() {
Logger logger = Logger.getLogger("org.netbeans.ui.metrics.editor"); // NOI18N
LogRecord rec = new LogRecord(Level.INFO, "USG_SEARCH_TYPE"); // NOI18N
Preferences prefs = MimeLookup.getLookup(MimePath.EMPTY).lookup(Preferences.class);
rec.setParameters(new Object[] {prefs.get(SimpleValueNames.EDITOR_SEARCH_TYPE, "default")}); // NOI18N
rec.setLoggerName(logger.getName());
logger.log(rec);
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt != null) {
selectCheckBoxes();
}
}
void updateIncSearchComboBoxHistory(String incrementalSearchText) {
EditorFindSupport.getInstance().addToHistory(new EditorFindSupport.SPW(incrementalSearchText,
wholeWords.isSelected(), matchCase.isSelected(), regexp.isSelected()));
incSearchTextField.getDocument().removeDocumentListener(incSearchTextFieldListener);
// Add the text to the top of the list
for (int i = incSearchComboBox.getItemCount() - 1; i >= 0; i--) {
String item = incSearchComboBox.getItemAt(i);
if (item.equals(incrementalSearchText)) {
incSearchComboBox.removeItemAt(i);
}
}
((MutableComboBoxModel<String>) incSearchComboBox.getModel()).insertElementAt(incrementalSearchText, 0);
incSearchComboBox.setSelectedIndex(0);
incSearchTextField.getDocument().addDocumentListener(incSearchTextFieldListener);
}
private KeyListener createKeyListenerForComponent() {
return new KeyListener() {
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
if(looseFocus()) {
e.consume();
};
ReplaceBar replaceBarInstance = ReplaceBar.getInstance(SearchBar.this);
if (replaceBarInstance.isVisible()) {
replaceBarInstance.looseFocus();
}
}
}
@Override
public void keyReleased(KeyEvent e) {
}
};
}
private CaretListener createCaretListenerForComponent() {
return new CaretListener() {
@Override
public void caretUpdate(CaretEvent e) {
if (SearchBar.getInstance().isVisible()) {
int num = SearchBar.getInstance().getNumOfMatches();
SearchBar.getInstance().showNumberOfMatches(null, num);
}
}
};
}
private FocusAdapter createFocusAdapterForComponent() {
return new FocusAdapter() {
@Override
public void focusGained(FocusEvent e) {
if (e.getOppositeComponent() instanceof JRootPane) {
// Hack for linux where invoking Find from main menu caused focus gained on editor
// even when openning quick search
return;
}
hadFocusOnIncSearchTextField = false;
if (isClosingSearchType() && !ReplaceBar.getInstance(SearchBar.getInstance()).isVisible()) {
looseFocus();
}
}
};
}
private PropertyChangeListener createPropertyChangeListenerForComponent() {
PropertyChangeListener pcl = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt == null || !"keymap".equals(evt.getPropertyName())) { // NOI18N
return;
}
JTextComponent lastFocusedComponent = EditorRegistry.lastFocusedComponent();
if (lastFocusedComponent == null) {
return;
}
Keymap keymap = lastFocusedComponent.getKeymap();
if (keymap instanceof MultiKeymap) {
MultiKeymap multiKeymap = (MultiKeymap) keymap;
Action[] actions = lastFocusedComponent.getActions();
for (Action action : actions) {
String actionName = (String) action.getValue(Action.NAME);
if (actionName == null) {
LOG.log(Level.WARNING, "SearchBar: Null Action.NAME property of action: {0}\n", action); //NOI18N
} else if (actionName.equals(BaseKit.findNextAction)) {
keystrokeForSearchAction(multiKeymap, action,
new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
findNext();
}
});
} else if (actionName.equals(BaseKit.findPreviousAction)) {
keystrokeForSearchAction(multiKeymap, action,
new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
findPrevious();
}
});
}
}
}
}
private void keystrokeForSearchAction(MultiKeymap multiKeymap, Action searchAction, AbstractAction newSearchAction) {
KeyStroke[] keyStrokes = multiKeymap.getKeyStrokesForAction(searchAction);
if (keyStrokes != null) {
InputMap inputMap = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
for (KeyStroke ks : keyStrokes) {
LOG.log(Level.FINE, "found {1} search action, {0}", new Object[]{ks, searchAction.getValue(Action.NAME)}); //NOI18N
inputMap.put(ks, (String) searchAction.getValue(Action.NAME));
}
getActionMap().put((String) searchAction.getValue(Action.NAME), newSearchAction);
}
}
};
pcl.propertyChange(new PropertyChangeEvent(this, "keymap", null, null)); //NOI18N
return pcl;
}
private void addAltEnterKeystrokeSelect(JTextComponent incSearchTextField) {
incSearchTextField.getInputMap().put(KeyStroke.getKeyStroke(
KeyEvent.VK_ENTER, InputEvent.ALT_MASK, true),
"select-all"); // NOI18N
incSearchTextField.getActionMap().put("select-all", // NOI18N
new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
selectAll();
}
});
}
private void addShiftEnterKeystrokeFindPreviousTo(JTextComponent incSearchTextField) {
incSearchTextField.getInputMap().put(KeyStroke.getKeyStroke(
KeyEvent.VK_ENTER, InputEvent.SHIFT_MASK, true),
"incremental-find-previous"); // NOI18N
incSearchTextField.getActionMap().put("incremental-find-previous", // NOI18N
new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
findPrevious();
}
});
}
private void addEnterKeystrokeFindNextTo(JTextComponent incSearchTextField) {
incSearchTextField.getInputMap().put(
KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, true),
"incremental-find-next"); // NOI18N
incSearchTextField.getActionMap().put("incremental-find-next", // NOI18N
new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
findNext();
if (isClosingSearchType() && !ReplaceBar.getInstance(SearchBar.getInstance()).isVisible()) {
looseFocus();
}
}
});
}
private DocumentListener createIncSearchTextFieldListener(final JTextComponent incSearchTextField) {
final Timer searchDelayTimer = new Timer(SEARCH_DELAY_TIME_LONG, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
incrementalSearch();
}
});
searchDelayTimer.setRepeats(false);
// listen on text change
return new DocumentListener() {
@Override
public void changedUpdate(DocumentEvent e) {
}
@Override
public void insertUpdate(DocumentEvent e) {
// text changed - attempt incremental search
if (incSearchTextField.getText().length() > 3) {
searchDelayTimer.setInitialDelay(SEARCH_DELAY_TIME_SHORT);
}
searchDelayTimer.restart();
}
@Override
public void removeUpdate(DocumentEvent e) {
// text changed - attempt incremental search
if (incSearchTextField.getText().length() <= 3) {
searchDelayTimer.setInitialDelay(SEARCH_DELAY_TIME_LONG);
}
searchDelayTimer.restart();
}
};
}
private JButton createCloseButton() {
JButton button = CloseButtonFactory.createBigCloseButton();
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
looseFocus();
}
});
button.setToolTipText(NbBundle.getMessage(SearchBar.class, "TOOLTIP_CloseIncrementalSearchSidebar")); // NOI18N
return button;
}
void processToggleButton(JToggleButton button, final String findConstant) {
button.setOpaque(false);
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
switchFindSupportValue(findConstant);
incrementalSearch();
}
});
}
// TODO: remove after replace icons
JCheckBox createCheckBox(String resName, final String findConstant) {
final JCheckBox checkBox = new JCheckBox();
checkBox.setOpaque(false);
Mnemonics.setLocalizedText(checkBox, NbBundle.getMessage(SearchBar.class, resName));
checkBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
switchFindSupportValue(findConstant);
incrementalSearch();
}
});
checkBox.setMargin(BUTTON_INSETS);
checkBox.setFocusable(false);
return checkBox;
}
private void selectCheckBoxes() {
wholeWords.setSelected(getFindSupportValue(EditorFindSupport.FIND_WHOLE_WORDS));
wholeWords.setEnabled(!getRegExp());
matchCase.setSelected(getFindSupportValue(EditorFindSupport.FIND_MATCH_CASE));
regexp.setSelected(getRegExp());
highlight.setSelected(getFindSupportValue(EditorFindSupport.FIND_HIGHLIGHT_SEARCH));
wrapAround.setSelected(getFindSupportValue(EditorFindSupport.FIND_WRAP_SEARCH));
}
// Treat Emacs profile specially in order to fix #191895
private void emacsProfileFix(final JTextComponent incSearchTextField) {
class JumpOutOfSearchAction extends AbstractAction {
private final String actionName;
public JumpOutOfSearchAction(String n) {
actionName = n;
}
@Override
public void actionPerformed(ActionEvent e) {
looseFocus();
if (getActualTextComponent() != null) {
ActionEvent ev = new ActionEvent(getActualTextComponent(), e.getID(), e.getActionCommand(), e.getModifiers());
Action action = getActualTextComponent().getActionMap().get(actionName);
action.actionPerformed(ev);
}
}
}
String actionName = "caret-begin-line"; // NOI18N
Action a1 = new JumpOutOfSearchAction(actionName);
incSearchTextField.getActionMap().put(actionName, a1);
actionName = "caret-end-line"; // NOI18N
Action a2 = new JumpOutOfSearchAction(actionName);
incSearchTextField.getActionMap().put(actionName, a2);
incSearchTextField.getInputMap().put(KeyStroke.getKeyStroke(
KeyEvent.VK_P, InputEvent.CTRL_MASK, false), "caret-up-alt"); // NOI18N
actionName = "caret-up"; // NOI18N
Action a3 = new JumpOutOfSearchAction(actionName);
incSearchTextField.getActionMap().put("caret-up-alt", a3); // NOI18N
incSearchTextField.getInputMap().put(KeyStroke.getKeyStroke(
KeyEvent.VK_N, InputEvent.CTRL_MASK, false), "caret-down-alt"); // NOI18N
actionName = "caret-down"; // NOI18N
Action a4 = new JumpOutOfSearchAction(actionName);
incSearchTextField.getActionMap().put("caret-down-alt", a4); // NOI18N
}
// From org.netbeans.modules.editor.settings.storage.EditorSettingsImpl
private static final String DEFAULT_PROFILE = "NetBeans"; //NOI18N
private static final String FATTR_CURRENT_KEYMAP_PROFILE = "currentKeymap"; // NOI18N
private static final String KEYMAPS_FOLDER = "Keymaps"; // NOI18N
/*
* This method is verbatim copy from class
* org.netbeans.modules.editor.settings.storage.EditorSettingsImpl bacause
* we don't want to introduce the dependency between this module and Editor
* Setting Storage module.
*/
public static String getCurrentKeyMapProfile() {
String currentKeyMapProfile = null;
FileObject fo = FileUtil.getConfigFile(KEYMAPS_FOLDER);
if (fo != null) {
Object o = fo.getAttribute(FATTR_CURRENT_KEYMAP_PROFILE);
if (o instanceof String) {
currentKeyMapProfile = (String) o;
}
}
if (currentKeyMapProfile == null) {
currentKeyMapProfile = DEFAULT_PROFILE;
}
return currentKeyMapProfile;
}
@Override
public String getName() {
//Required for Aqua L&F toolbar UI
return "editorSearchBar"; // NOI18N
}
void addEscapeKeystrokeFocusBackTo(JComponent component) {
component.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, true),
"loose-focus"); // NOI18N
component.getActionMap().put("loose-focus", // NOI18N
new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
if (!popupMenuWasCanceled) {
looseFocus();
if (isClosingSearchType()) {
getActualTextComponent().scrollRectToVisible(actualViewPort);
}
} else {
popupMenuWasCanceled = false;
}
}
});
}
private static boolean isClosingSearchType() {
Preferences prefs = MimeLookup.getLookup(MimePath.EMPTY).lookup(Preferences.class);
return prefs.get(SimpleValueNames.EDITOR_SEARCH_TYPE, "default").equals("closing"); // NOI18N
}
public void gainFocus(boolean persistanceStatus) {
String lastSearch = "";
if (!isClosingSearchType()) {
lastSearch = incSearchTextField.getText();
Object findWhat = searchProps.getProperty(EditorFindSupport.FIND_WHAT);
if (findWhat instanceof String) {
lastSearch = (String) findWhat;
}
}
incSearchTextField.getDocument().removeDocumentListener(incSearchTextFieldListener);
SearchComboBoxEditor.changeToOneLineEditorPane((JEditorPane) incSearchTextField);
addEnterKeystrokeFindNextTo(incSearchTextField);
MutableComboBoxModel<String> comboBoxModelIncSearch = ((MutableComboBoxModel<String>) incSearchComboBox.getModel());
for (int i = comboBoxModelIncSearch.getSize() - 1; i >= 0; i--) {
comboBoxModelIncSearch.removeElementAt(i);
}
for (EditorFindSupport.SPW spw : EditorFindSupport.getInstance().getHistory()) {
comboBoxModelIncSearch.addElement(spw.getSearchExpression());
}
if (!isClosingSearchType()) {
incSearchTextField.setText(lastSearch);
}
if (!isVisible() && isClosingSearchType()) {
whenOpenedWasNotVisible = true;
}
if (whenOpenedWasNotVisible) {
incSearchTextField.setText("");
whenOpenedWasNotVisible = false;
}
hadFocusOnIncSearchTextField = true;
setVisible(true);
initBlockSearch(persistanceStatus);
EditorFindSupport.getInstance().setFocusedTextComponent(getActualTextComponent());
incSearchTextField.requestFocusInWindow();
boolean empty = incSearchTextField.getText().isEmpty();
if (!empty) { // preselect the text in incremental search text field
incSearchTextField.selectAll();
}
findPreviousButton.setEnabled(!empty);
findNextButton.setEnabled(!empty);
ReplaceBar.getInstance(this).getReplaceButton().setEnabled(!empty);
ReplaceBar.getInstance(this).getReplaceAllButton().setEnabled(!empty);
actualViewPort = getActualTextComponent().getVisibleRect();
if (!isClosingSearchType() && highlightCanceled) {
searchProps.setProperty(EditorFindSupport.FIND_HIGHLIGHT_SEARCH, Boolean.TRUE);
highlightCanceled = false;
}
incSearchTextField.getDocument().addDocumentListener(incSearchTextFieldListener);
}
public boolean looseFocus() {
hadFocusOnIncSearchTextField = false;
if (!isVisible()) {
return false;
}
EditorFindSupport.getInstance().setBlockSearchHighlight(0, 0);
EditorFindSupport.getInstance().incSearchReset();
EditorFindSupport.getInstance().setFocusedTextComponent(null);
if (getActualTextComponent() != null) {
org.netbeans.editor.Utilities.setStatusText(getActualTextComponent(), "");
getActualTextComponent().requestFocusInWindow();
}
setVisible(false);
if (!isClosingSearchType() && getFindSupportValue(EditorFindSupport.FIND_HIGHLIGHT_SEARCH)) {
searchProps.setProperty(EditorFindSupport.FIND_HIGHLIGHT_SEARCH, Boolean.FALSE);
highlightCanceled = true;
}
searchProps.setProperty(EditorFindSupport.FIND_BLOCK_SEARCH, Boolean.FALSE);
searchProps.setProperty(EditorFindSupport.FIND_BLOCK_SEARCH_START, null);
searchProps.setProperty(EditorFindSupport.FIND_BLOCK_SEARCH_END, null);
EditorFindSupport.getInstance().putFindProperties(searchProps.getProperties());
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
searchProps.saveToPrefs();
}
});
return true;
}
private void incrementalSearch() {
if (getActualTextComponent() == null || getActualTextComponent().getCaret() == null) {
return;
}
String incrementalSearchText = incSearchTextField.getText();
boolean empty = incrementalSearchText.length() <= 0;
// Enable/disable the pre/next buttons
findPreviousButton.setEnabled(!empty);
findNextButton.setEnabled(!empty);
ReplaceBar.getInstance(this).getReplaceButton().setEnabled(!empty);
ReplaceBar.getInstance(this).getReplaceAllButton().setEnabled(!empty);
// configure find properties
EditorFindSupport findSupport = EditorFindSupport.getInstance();
findSupport.putFindProperties(getSearchProperties());
// search starting at current caret position
int caretPosition = getActualTextComponent().getSelectionStart();
if (isClosingSearchType()) {
caretPosition = getActualTextComponent().getCaretPosition();
}
if (findSupport.incSearch(searchProps.getProperties(), caretPosition) || empty) {
// text found - reset incremental search text field's foreground
incSearchTextField.setForeground(DEFAULT_FG_COLOR); //NOI18N
org.netbeans.editor.Utilities.setStatusText(getActualTextComponent(), "", StatusDisplayer.IMPORTANCE_INCREMENTAL_FIND);
showNumberOfMatches(findSupport, -1);
lastIncrementalSearchWasSuccessful = true;
} else {
// text not found - indicate error in incremental search
// text field with red foreground
incSearchTextField.setForeground(NOT_FOUND);
org.netbeans.editor.Utilities.setStatusText(getActualTextComponent(), NbBundle.getMessage(
SearchBar.class, "find-not-found", incrementalSearchText),
StatusDisplayer.IMPORTANCE_INCREMENTAL_FIND); //NOI18N
if (lastIncrementalSearchWasSuccessful) {
Toolkit.getDefaultToolkit().beep();
lastIncrementalSearchWasSuccessful = false;
}
showNumberOfMatches(findSupport, 0);
}
}
void findNext() {
find(true);
}
void findPrevious() {
find(false);
}
void selectAll() {
EditorFindSupport findSupport = EditorFindSupport.getInstance();
JTextComponent textComponent = getActualTextComponent();
Document doc = textComponent.getDocument();
Caret caret = textComponent.getCaret();
if(caret instanceof EditorCaret) {
EditorCaret editorCaret = (EditorCaret) caret;
try {
int[] blocks = findSupport.getBlocks(new int[]{-1, -1}, doc, 0, doc.getLength());
if(blocks[0] >= 0 && blocks.length % 2 == 0) {
List<Position> newCarets = new ArrayList<>(editorCaret.getCarets().size() << 1);
for (int i = 0; i < blocks.length; i += 2) {
int start = blocks[i];
int end = blocks[i+1];
if(start == -1 || end == -1) {
break;
}
Position startPos = doc.createPosition(start);
Position endPos = doc.createPosition(end);
newCarets.add(endPos);
newCarets.add(startPos);
}
editorCaret.replaceCarets(newCarets, null); // TODO handle biases
textComponent.requestFocusInWindow();
}
} catch (BadLocationException ex) {
Exceptions.printStackTrace(ex);
}
}
}
public int getNumOfMatches() {
return numOfMatches;
}
/**
* @param findSupport if null EditorFindSupport.getInstance() is used
* @param numMatches if numOfMatches < 0, calculate numOfMatches and position, else show numOfMatches.
* @return
*/
public int lastCurrentPosStart = -1;
public int lastCurrentPosEnd = -1;
public int showNumberOfMatches(EditorFindSupport findSupport, int numMatches) {
if (findSupport == null) {
findSupport = EditorFindSupport.getInstance();
}
int pos = 0;
int currentposStart = getActualTextComponent().getSelectionStart();
int currentposEnd = getActualTextComponent().getSelectionEnd();
if (numMatches < 0 || (lastCurrentPosStart == currentposStart && lastCurrentPosEnd == currentposEnd)) {
numMatches = -1;
boolean notFound = true;
try {
int[] blocks = findSupport.getBlocks(new int[]{-1, -1}, getActualTextComponent().getDocument(), 0, getActualTextComponent().getDocument().getLength());
for (int i = 0; i < blocks.length; i++) {
if (blocks[i] > 0) {
numMatches++;
if (blocks[i] < currentposStart) {
pos++;
}
if (blocks[i] == currentposStart && i+1 < blocks.length && blocks[i+1] == currentposEnd) {
notFound = false;
}
} else if (blocks[i] == 0 && i + 1 < blocks.length && blocks[i+1] > 0) {
numMatches++;
}
}
} catch (BadLocationException ex) {
Exceptions.printStackTrace(ex);
}
numMatches = numMatches == 0 ? 0 : (numMatches + 1) / 2;
pos = (pos == 0 ? 0 : (pos + 1) / 2) + 1;
if (pos > numMatches) {
pos = 0;
}
if (notFound) {
pos = 0;
}
}
lastCurrentPosStart = currentposStart;
lastCurrentPosEnd = currentposEnd;
if (incSearchTextField.getText().isEmpty()) {
Mnemonics.setLocalizedText(matches, ""); //NOI18N
} else if (numMatches == 0) {
Mnemonics.setLocalizedText(matches, NbBundle.getMessage(SearchBar.class, "0_matches")); //NOI18N
} else if (numMatches == 1) {
Mnemonics.setLocalizedText(matches, NbBundle.getMessage(SearchBar.class, "1_matches")); //NOI18N
} else {
if (pos == 0) {
Mnemonics.setLocalizedText(matches, NbBundle.getMessage(SearchBar.class, "n_matches", numMatches)); //NOI18N
} else {
Mnemonics.setLocalizedText(matches, NbBundle.getMessage(SearchBar.class, "i_n_matches", pos, numMatches)); //NOI18N
}
}
this.numOfMatches = numMatches;
return numMatches;
}
private void find(boolean next) {
String incrementalSearchText = incSearchTextField.getText();
boolean empty = incrementalSearchText.length() <= 0;
updateIncSearchComboBoxHistory(incrementalSearchText);
// configure find properties
EditorFindSupport findSupport = EditorFindSupport.getInstance();
Map<String, Object> actualfindProps = getSearchProperties();
findSupport.putFindProperties(actualfindProps);
if (findSupport.find(actualfindProps, !next) || empty) {
// text found - reset incremental search text field's foreground
incSearchTextField.setForeground(DEFAULT_FG_COLOR); //NOI18N
showNumberOfMatches(findSupport, -1);
} else {
// text not found - indicate error in incremental search text field with red foreground
incSearchTextField.setForeground(NOT_FOUND);
showNumberOfMatches(findSupport, 0);
Toolkit.getDefaultToolkit().beep();
}
}
@SuppressWarnings("unchecked")
void initBlockSearch(boolean persistanceStatus) {
JTextComponent c = getActualTextComponent();
String selText;
int startSelection;
int endSelection;
boolean blockSearchVisible = false;
if (c != null) {
startSelection = c.getSelectionStart();
endSelection = c.getSelectionEnd();
Document doc = c.getDocument();
if (doc instanceof BaseDocument) {
BaseDocument bdoc = (BaseDocument) doc;
try {
int startLine = org.netbeans.editor.Utilities.getLineOffset(bdoc, startSelection);
int endLine = org.netbeans.editor.Utilities.getLineOffset(bdoc, endSelection);
if (endLine > startLine) {
blockSearchVisible = true;
}
} catch (BadLocationException ble) {
}
}
// caretPosition = bwdSearch.isSelected() ? c.getSelectionEnd() : c.getSelectionStart();
if (!blockSearchVisible && !persistanceStatus) {
selText = c.getSelectedText();
if (selText != null && selText.length() > 0) {
int n = selText.indexOf('\n');
if (n >= 0) {
selText = selText.substring(0, n);
}
incSearchTextField.setText(selText);
searchProps.setProperty(EditorFindSupport.FIND_WHAT, selText);
} else {
if (isClosingSearchType()) {
String findWhat = (String) EditorFindSupport.getInstance().getFindProperty(EditorFindSupport.FIND_WHAT);
if (findWhat != null && findWhat.length() > 0) {
incSearchTextField.setText(findWhat);
}
}
}
}
int blockSearchStartOffset = blockSearchVisible ? startSelection : 0;
int blockSearchEndOffset = blockSearchVisible ? endSelection : 0;
try {
searchProps.setProperty(EditorFindSupport.FIND_BLOCK_SEARCH, blockSearchVisible);
searchProps.setProperty(EditorFindSupport.FIND_BLOCK_SEARCH_START, doc.createPosition(blockSearchStartOffset));
searchProps.setProperty(EditorFindSupport.FIND_BLOCK_SEARCH_END, doc.createPosition(blockSearchEndOffset));
EditorFindSupport.getInstance().setBlockSearchHighlight(blockSearchStartOffset, blockSearchEndOffset);
} catch (BadLocationException ble) {
searchProps.setProperty(EditorFindSupport.FIND_BLOCK_SEARCH, Boolean.FALSE);
searchProps.setProperty(EditorFindSupport.FIND_BLOCK_SEARCH_START, null);
searchProps.setProperty(EditorFindSupport.FIND_BLOCK_SEARCH_END, null);
}
EditorFindSupport.getInstance().putFindProperties(searchProps.getProperties());
showNumberOfMatches(null, -1);
}
}
boolean getFindSupportValue(String findConstant) {
Boolean b = (Boolean) searchProps.getProperty(findConstant);
return b != null ? b.booleanValue() : false;
}
private void switchFindSupportValue(String findConstant) {
searchProps.setProperty(findConstant, !getFindSupportValue(findConstant));
}
boolean getRegExp() {
return getFindSupportValue(EditorFindSupport.FIND_REG_EXP);
}
boolean hadFocusOnTextField() {
return hadFocusOnIncSearchTextField;
}
void lostFocusOnTextField() {
hadFocusOnIncSearchTextField = false;
}
void setActualTextComponent(JTextComponent component) {
if (getActualTextComponent() != null) {
getActualTextComponent().removeFocusListener(focusAdapterForComponent);
getActualTextComponent().removePropertyChangeListener(propertyChangeListenerForComponent);
getActualTextComponent().removeKeyListener(keyListenerForComponent);
getActualTextComponent().removeCaretListener(caretListenerForComponent);
}
if (focusAdapterForComponent == null) {
focusAdapterForComponent = createFocusAdapterForComponent();
}
if (propertyChangeListenerForComponent == null) {
propertyChangeListenerForComponent = createPropertyChangeListenerForComponent();
}
if (keyListenerForComponent == null) {
keyListenerForComponent = createKeyListenerForComponent();
}
if (caretListenerForComponent == null) {
caretListenerForComponent = createCaretListenerForComponent();
}
component.addCaretListener(caretListenerForComponent);
component.addFocusListener(focusAdapterForComponent);
component.addPropertyChangeListener(propertyChangeListenerForComponent);
component.addKeyListener(keyListenerForComponent);
for (PropertyChangeListener pcl : actualComponentListeners) {
pcl.propertyChange(new PropertyChangeEvent(this, "actualTextComponent", getActualTextComponent(), component)); //NOI18N
}
actualTextComponent = new WeakReference<>(component);
EditorFindSupport.getInstance().setFocusedTextComponent(getActualTextComponent());
//This is for component without highlighting
if (Boolean.TRUE.equals(component.getClientProperty("searchbar.hideHighlightIcon"))) { //NOI18N
highlight.setVisible(false);
} else if (!highlight.isVisible()) {
highlight.setVisible(true);
}
}
void addActualComponentListener(PropertyChangeListener propertyChangeListener) {
actualComponentListeners.add(propertyChangeListener);
}
public JTextComponent getActualTextComponent() {
return actualTextComponent != null ? actualTextComponent.get() : null;
}
JTextComponent getIncSearchTextField() {
return incSearchTextField;
}
JButton getCloseButton() {
return closeButton;
}
JLabel getFindLabel() {
return findLabel;
}
JButton getFindNextButton() {
return findNextButton;
}
JButton getFindPreviousButton() {
return findPreviousButton;
}
public Map<String, Object> getSearchProperties() {
searchProps.setProperty(EditorFindSupport.FIND_WHAT, incSearchTextField.getText());
searchProps.setProperty(EditorFindSupport.FIND_MATCH_CASE, matchCase.isSelected());
searchProps.setProperty(EditorFindSupport.FIND_WHOLE_WORDS, wholeWords.isSelected());
searchProps.setProperty(EditorFindSupport.FIND_REG_EXP, regexp.isSelected());
searchProps.setProperty(EditorFindSupport.FIND_BACKWARD_SEARCH, Boolean.FALSE);
searchProps.setProperty(EditorFindSupport.FIND_INC_SEARCH, Boolean.TRUE);
searchProps.setProperty(EditorFindSupport.FIND_HIGHLIGHT_SEARCH, highlight.isSelected());
searchProps.setProperty(EditorFindSupport.FIND_WRAP_SEARCH, wrapAround.isSelected());
return searchProps.getProperties();
}
public void setSearchProperties(SearchProperties searchProperties) {
searchProps = searchProperties;
selectCheckBoxes();
}
public boolean isPopupMenuWasCanceled() {
return popupMenuWasCanceled;
}
public void setPopupMenuWasCanceled(boolean popupMenuWasCanceled) {
this.popupMenuWasCanceled = popupMenuWasCanceled;
}
public JComboBox<String> getIncSearchComboBox() {
return incSearchComboBox;
}
private class SearchPopupMenuListener implements PopupMenuListener {
private boolean canceled = false;
@Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
}
@Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
if (!canceled) {
Object selectedItem = getIncSearchComboBox().getModel().getSelectedItem();
if (selectedItem instanceof String) {
String findWhat = (String) selectedItem;
for (EditorFindSupport.SPW spw : EditorFindSupport.getInstance().getHistory()) {
if (findWhat.equals(spw.getSearchExpression())) {
searchProps.setProperty(EditorFindSupport.FIND_REG_EXP, spw.isRegExp());
break;
}
}
}
} else {
canceled = false;
}
}
@Override
public void popupMenuCanceled(PopupMenuEvent e) {
canceled = true;
SearchBar.getInstance().setPopupMenuWasCanceled(true);
}
};
private static final class SeparatorBorder implements Border {
private static final int BORDER_WIDTH = 1;
private final Insets INSETS = new Insets(BORDER_WIDTH, 0, 0, 0);
@Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
Color originalColor = g.getColor();
g.setColor (UIManager.getColor ("controlShadow")); //NOI18N
g.drawLine(0, 0, c.getWidth(), 0);
g.setColor(originalColor);
}
@Override public Insets getBorderInsets(Component c) {
return INSETS;
}
@Override public boolean isBorderOpaque() {
return true;
}
}
private static boolean isCurrentLF(String lf) {
LookAndFeel laf = UIManager.getLookAndFeel();
String lfID = laf.getID();
return lf.equals(lfID);
}
}