
org.netbeans.modules.options.OptionsPanel Maven / Gradle / Ivy
/*
* 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.options;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.RoundRectangle2D;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.KeyStroke;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.text.JTextComponent;
import org.netbeans.modules.options.CategoryModel.Category;
import org.netbeans.modules.options.advanced.AdvancedPanel;
import org.netbeans.modules.options.ui.VariableBorder;
import org.netbeans.spi.options.OptionsPanelController;
import org.openide.awt.Mnemonics;
import org.openide.awt.QuickSearch;
import org.openide.awt.StatusDisplayer;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.util.HelpCtx;
import org.openide.util.Mutex;
import org.openide.util.NbBundle;
import org.openide.util.NbPreferences;
import org.openide.util.RequestProcessor;
import org.openide.util.Utilities;
import org.openide.windows.WindowManager;
public class OptionsPanel extends JPanel {
private static final String OPTIONS_USE_UI_DEFAULT_COLORS = "nb.options.useUIDefaultsColors"; //NOI18N
private static final String OPTIONS_CATEGORIES_SEPARATOR_COLOR = "nb.options.categories.separatorColor"; //NOI18N
private static final String OPTIONS_CATEGORIES_BUTTON_USE_NIMBUS = "nb.options.categories.button.useNimbusCategoryButton"; //NOI18N
private JPanel pCategories;
private JPanel pCategories2;
private JScrollPane categoriesScrollPane;
private JPanel pOptions;
private JPanel quickSearch;
private Color origForeground;
private String hintText;
private boolean hintVisible = false;
private JTextComponent searchTC;
private String text2search = "";
private boolean clearSearch = false;
private CardLayout cLayout;
private final HashMap categoryid2tabbedpane = new HashMap();
private final HashMap> categoryid2words = new HashMap>();
private HashMap> categoryid2tabs = new HashMap>();
private final ArrayList disabledCategories = new ArrayList();
private Map buttons = new LinkedHashMap();
private final boolean isMac = UIManager.getLookAndFeel ().getID ().equals ("Aqua");
private final Color selected = isMac ? new Color(221, 221, 221) : getSelectionBackground();
private final Color selectedB = isMac ? new Color(183, 183, 183) : getUIColorOrDefault("nb.options.categories.selectionBorderColor", new Color (149, 106, 197));
private final Color highlighted = isMac ? new Color(221, 221, 221) : getHighlightBackground();
private final Color highlightedB = getUIColorOrDefault("nb.options.categories.highlightBorderColor", new Color (152, 180, 226));
private final ControllerListener controllerListener = new ControllerListener ();
private final Color borderMac = new Color(141, 141, 141);
private final Font labelFontMac = new Font("Lucida Grande", 0, 10);
private CategoryModel categoryModel;
private boolean applyPressed = false;
private static String loc (String key) {
return NbBundle.getMessage (OptionsPanel.class, key);
}
/** Creates new form OptionsPanel */
public OptionsPanel (CategoryModel categoryModel) {
this(null, categoryModel);
}
public OptionsPanel (String categoryID, CategoryModel categoryModel) {
this.categoryModel = categoryModel;
// init UI components, layout and actions, and add some default values
initUI(categoryID);
if (getActionMap().get("SEARCH_OPTIONS") == null) {//NOI18N
InputMap inputMap = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
if(Utilities.isMac()) {
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.META_MASK), "SEARCH_OPTIONS");//NOI18N
// Mac cloverleaf symbol
hintText = Bundle.Filter_Textfield_Hint("\u2318+F");
} else {
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.CTRL_MASK), "SEARCH_OPTIONS");//NOI18N
hintText = Bundle.Filter_Textfield_Hint("Ctrl+F");
}
getActionMap().put("SEARCH_OPTIONS", new SearchAction());//NOI18N
}
}
private String getCategoryID(String categoryID) {
return categoryID == null ? categoryModel.getCurrentCategoryID() : categoryID;
}
void initCurrentCategory (final String categoryID, final String subpath) {
//generalpanel should be moved to core/options and then could be implemented better
//generalpanel doesn't need lookup
boolean isGeneralPanel = "General".equals(getCategoryID(categoryID));//NOI18N
if (categoryModel.isLookupInitialized() || isGeneralPanel) {
setCurrentCategory(categoryModel.getCategory(getCategoryID(categoryID)), subpath);
initActions();
} else {
RequestProcessor.getDefault().post(new Runnable() {
public void run() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// change cursor
Frame[] all = Frame.getFrames();
if (all == null || all.length == 0) {
return;
}
final Frame frame = all[0];
final Cursor cursor = frame.getCursor();
frame.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
setCurrentCategory(categoryModel.getCategory(getCategoryID(categoryID)), subpath);
initActions();
// reset cursor
frame.setCursor(cursor);
setCursor(cursor);
}
});
}
}, 500);
}
}
private void setCurrentCategory (final CategoryModel.Category category, String subpath) {
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
try {
if(category == null) {
JComponent component = new JPanel(new BorderLayout());
JLabel label = new JLabel(loc("CTL_Options_Search_Nothing_Found"));//NOI18N
label.setHorizontalAlignment(JLabel.CENTER);
label.setHorizontalTextPosition(JLabel.CENTER);
component.add(label, BorderLayout.CENTER);
component.setSize(pOptions.getSize());
component.setPreferredSize(pOptions.getPreferredSize());
final Dimension size = component.getSize();
if (component.getParent() == null || !pOptions.equals(component.getParent())) {
pOptions.add(component, label.getText());
}
cLayout.show(pOptions, label.getText());
checkSize(size);
firePropertyChange("buran" + OptionsPanelController.PROP_HELP_CTX, null, null);
} else {
CategoryModel.Category oldCategory = categoryModel.getCurrent();
if (oldCategory != null) {
(buttons.get(oldCategory.getID())).setNormal();
}
if (category != null) {
(buttons.get(category.getID())).setSelected();
}
categoryModel.setCurrent(category);
JComponent component = category.getComponent();
category.update(controllerListener, false);
final Dimension size = component.getSize();
if (component.getParent() == null || !pOptions.equals(component.getParent())) {
pOptions.add(component, category.getCategoryName());
}
cLayout.show(pOptions, category.getCategoryName());
checkSize(size);
/*if (CategoryModel.getInstance().getCurrent() != null) {
((CategoryButton) buttons.get (CategoryModel.getInstance().getCurrentCategoryID())).requestFocus();
} */
firePropertyChange("buran" + OptionsPanelController.PROP_HELP_CTX, null, null);
if (subpath != null) {
category.setCurrentSubcategory(subpath);
}
}
} finally {
setCursor(null);
}
}
public void setCategoryInstance(CategoryModel categoryInstance) {
this.categoryModel = categoryInstance;
}
HelpCtx getHelpCtx () {
if(categoryModel == null) {
return null;
}
return categoryModel.getHelpCtx ();
}
void update () {
if(categoryModel == null) {
return;
}
categoryModel.update(controllerListener, true);
}
void save(boolean applyButtonPressed) {
if(categoryModel == null) {
return;
}
applyPressed = applyButtonPressed;
save();
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
if (applyPressed) {
categoryModel.update(controllerListener, false);
}
applyPressed = false;
}
});
}
void save () {
if(categoryModel == null) {
return;
}
categoryModel.save();
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
if (categoryModel == null) {
return;
}
clearSearchField();
if (!applyPressed) {
categoryModel = null;
}
}
});
}
void cancel () {
if(categoryModel == null) {
return;
}
clearSearchField();
categoryModel.cancel();
categoryModel = null;
}
boolean dataValid () {
if(categoryModel == null) {
return false;
}
return categoryModel.dataValid();
}
boolean isChanged () {
if(categoryModel == null) {
return false;
}
return categoryModel.isChanged();
}
boolean needsReinit() {
if(categoryModel == null) {
return false;
}
return categoryModel.needsReinit();
}
// private methods .........................................................
@NbBundle.Messages({"Filter_Textfield_Tooltip=Press Esc or Enter with empty text to clear the filter",
"# {0} - shortcut to access the search text field",
"Filter_Textfield_Hint=Filter ({0})"})
private void initUI(String categoryName) {
this.getAccessibleContext().setAccessibleDescription(loc("ACS_OptionsPanel"));//NOI18N
// central panel
pOptions = new JPanel ();
cLayout = new CardLayout();
pOptions.setLayout (cLayout);
pOptions.setPreferredSize (getUserSize());
JLabel label = new JLabel (loc ("CTL_Loading_Options"));
label.setHorizontalAlignment (JLabel.CENTER);
pOptions.add (label, label.getText());//NOI18N
// icon view
pCategories2 = new JPanel (new GridBagLayout());
pCategories2.setBackground (getTabPanelBackground());
pCategories2.setBorder (null);
addCategoryButtons();
quickSearch = new JPanel(new FlowLayout(FlowLayout.RIGHT, 0, 0));
quickSearch.setBackground(getTabPanelBackground());
QuickSearch qs = QuickSearch.attach(quickSearch, null, new OptionsQSCallback());
qs.setAlwaysShown(true);
JComponent searchPanel = (JComponent) quickSearch.getComponent(0);
searchPanel.setToolTipText(Bundle.Filter_Textfield_Tooltip());
searchTC = (JTextComponent) searchPanel.getComponent(searchPanel.getComponentCount() - 1);
searchTC.setToolTipText(Bundle.Filter_Textfield_Tooltip());
searchTC.addFocusListener(new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
showHint(false);
}
@Override
public void focusLost(FocusEvent e) {
if (text2search.trim().isEmpty()) {
showHint(true);
} else {
showHint(false);
}
if(e.getOppositeComponent() != null && e.getOppositeComponent().equals(quickSearch) && !clearSearch) {
searchTC.requestFocusInWindow();
} else {
clearSearch = false;
if(e.getOppositeComponent() != null && e.getOppositeComponent().equals(quickSearch)) {
pOptions.requestFocusInWindow();
}
}
}
});
showHint(true);
pCategories = new JPanel (new BorderLayout ());
pCategories.setBorder (BorderFactory.createMatteBorder(0, 0, 1, 0, getUIColorOrDefault(OPTIONS_CATEGORIES_SEPARATOR_COLOR, Color.lightGray)));
pCategories.setBackground (getTabPanelBackground());
categoriesScrollPane = new JScrollPane(pCategories2, ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
categoriesScrollPane.setBorder(null);
categoriesScrollPane.getHorizontalScrollBar().setUnitIncrement(Utils.ScrollBarUnitIncrement);
pCategories.add ("Center", categoriesScrollPane);
pCategories.add ("East", quickSearch);
pCategories.setPreferredSize(new Dimension(pCategories.getPreferredSize().width,
pCategories.getPreferredSize().height + categoriesScrollPane.getHorizontalScrollBar().getPreferredSize().height));
// layout
setLayout (new BorderLayout (10, 10));
pOptions.setBorder(new CompoundBorder(
new VariableBorder(null, null, borderMac, null),
BorderFactory.createEmptyBorder(0, 5, 0, 5)
));
add(pCategories, BorderLayout.NORTH);
add(pOptions, BorderLayout.CENTER);
categoryName = getCategoryID(categoryName);
if (categoryName != null) {
CategoryModel.Category c = categoryModel.getCategory(getCategoryID(categoryName));
CategoryButton b = buttons.get(categoryName);
if (b != null) {
b.setSelected();
}
}
}
private void clearSearchField() {
if (text2search.trim().isEmpty()) {
// do nothing if options quick search was not used
return;
}
searchTC.setText("");
clearAllinQS();
}
private void showHint (boolean showHint) {
if (hintVisible == showHint) {
return ;
}
// remember orig color on first invocation
if (origForeground == null) {
origForeground = searchTC.getForeground();
}
if (showHint) {
searchTC.setForeground(searchTC.getDisabledTextColor());
searchTC.setText(hintText);
} else {
searchTC.setForeground(origForeground);
searchTC.setText(text2search);
}
hintVisible = showHint;
}
private void computeOptionsWords() {
Set> categories = categoryModel.getCategories();
categoryid2tabs = new HashMap>();
for (Map.Entry set : categories) {
JComponent jcomp = set.getValue().getComponent();
String id = set.getValue().getID();
if(jcomp instanceof JTabbedPane) {
categoryid2tabbedpane.put(id, (JTabbedPane)jcomp);
} else if(jcomp instanceof AdvancedPanel) {
categoryid2tabbedpane.put(id, (JTabbedPane)jcomp.getComponent(0));
} else if (jcomp instanceof Container) {
handleAllComponents((Container) jcomp, id, null, -1);
}
}
FileObject keywordsFOs = FileUtil.getConfigRoot().getFileObject(CategoryModel.OD_LAYER_KEYWORDS_FOLDER_NAME);
for(FileObject keywordsFO : keywordsFOs.getChildren()) {
handlePanel(keywordsFO);
}
}
private void handlePanel(FileObject keywordsFO) {
String location = keywordsFO.getAttribute("location").toString(); //NOI18N
String tabTitle = keywordsFO.getAttribute("tabTitle").toString(); //NOI18N
JTabbedPane pane = categoryid2tabbedpane.get(location);
int tabIndex = pane == null ? -1 : pane.indexOfTab(tabTitle);
Set keywords = new HashSet();
keywords.add(location.toUpperCase());
keywords.add(tabTitle.toUpperCase());
Enumeration attributes = keywordsFO.getAttributes();
while(attributes.hasMoreElements()) {
String attribute = attributes.nextElement();
if(attribute.startsWith("keywords")) {
String word = keywordsFO.getAttribute(attribute).toString();
keywords.add(word.toUpperCase());
}
}
ArrayList words = categoryid2words.get(location);
if (words == null) {
words = new ArrayList();
}
Set newWords = new HashSet();
for (String keyword : keywords) {
if (!words.contains(keyword)) {
newWords.add(keyword);
}
}
words.addAll(newWords);
categoryid2words.put(location, words);
if (!categoryid2tabs.containsKey(location)) {
categoryid2tabs.put(location, new HashMap());
}
HashMap categoryTabs = categoryid2tabs.get(location);
TabInfo tabInfo;
if (!categoryTabs.containsKey(tabIndex)) {
tabInfo = new TabInfo();
} else {
tabInfo = categoryTabs.get(tabIndex);
}
tabInfo.addWords(keywords);
categoryTabs.put(tabIndex, tabInfo);
categoryid2tabs.put(location, categoryTabs);
}
private void handleAllComponents(Container container, String categoryID, JTabbedPane tabbedPane, int index) {
Component[] components = container.getComponents();
Component component;
for (int i = 0; i < components.length; i++) {
component = components[i];
String text;
if(component instanceof JTabbedPane) {
if(categoryid2tabbedpane.get(categoryID) == null) {
categoryid2tabbedpane.put(categoryID, (JTabbedPane)component);
}
} else {
handleAllComponents((Container)component, categoryID, tabbedPane, index);
}
}
}
private class TabInfo {
private ArrayList words;
public TabInfo() {
this.words = new ArrayList();
}
public ArrayList getWords() {
return words;
}
public void addWord(String word) {
words.add(word.toUpperCase());
}
public void addWords(Set words) {
for (String word : words) {
addWord(word);
}
}
}
final class OptionsQSCallback implements QuickSearch.Callback {
private boolean initialized = false;
@Override
public void quickSearchUpdate(String searchText) {
if (!searchText.equalsIgnoreCase(hintText)) {
text2search = searchText.trim();
}
}
private void showWaitCursor() {
Mutex.EVENT.readAccess(new Runnable() {
public void run() {
JFrame mainWindow = (JFrame) WindowManager.getDefault().getMainWindow();
mainWindow.getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
mainWindow.getGlassPane().setVisible(true);
StatusDisplayer.getDefault().setStatusText(NbBundle.getMessage(OptionsDisplayerImpl.class, "CTL_Searching_Options"));
}
});
}
private void hideWaitCursor() {
Mutex.EVENT.readAccess(new Runnable() {
public void run() {
StatusDisplayer.getDefault().setStatusText(""); //NOI18N
JFrame mainWindow = (JFrame) WindowManager.getDefault().getMainWindow();
mainWindow.getGlassPane().setVisible(false);
mainWindow.getGlassPane().setCursor(null);
}
});
}
private int getNextEnabledTabIndex(JTabbedPane pane, int currentIndex) {
for (int i = currentIndex + 1; i < pane.getTabCount(); i++) {
if(pane.isEnabledAt(i)) {
return i;
}
}
for (int i = 0; i < currentIndex; i++) {
if(pane.isEnabledAt(i)) {
return i;
}
}
return -1;
}
private boolean containsAllSearchWords(ArrayList keywords, Collection stWords) {
Iterator e = stWords.iterator();
while (e.hasNext()) {
if (!containsSearchWord(keywords, e.next())) {
return false;
}
}
return true;
}
private boolean containsSearchWord(ArrayList keywords, String stWord) {
Iterator e = keywords.iterator();
while (e.hasNext()) {
if (e.next().contains(stWord)) {
return true;
}
}
return false;
}
private ArrayList getAllMatchedKeywords(ArrayList keywords, Collection stWords) {
ArrayList allMatched = new ArrayList();
Iterator e = stWords.iterator();
while (e.hasNext()) {
allMatched.addAll(getMatchedKeywords(keywords, e.next(), allMatched));
}
return allMatched;
}
private ArrayList getMatchedKeywords(ArrayList keywords, String stWord, ArrayList allMatched) {
ArrayList matched = new ArrayList();
Iterator e = keywords.iterator();
while (e.hasNext()) {
String next = e.next();
for (String s : next.split(",")) {
s = s.trim();
if (s.contains(stWord) && !allMatched.contains(s) && !matched.contains(s)) {
matched.add(s);
}
}
}
return matched;
}
private void handleSearch(String searchText) {
List stWords = Arrays.asList(searchText.toUpperCase().split(" "));
String exactCategory = null;
String exactTabTitle = null;
int exactTabIndex = -1;
for (String id : categoryModel.getCategoryIDs()) {
exactTabIndex = -1;
ArrayList entry = categoryid2words.get(id);
List matchedKeywords;
if (entry != null) {
boolean found = containsAllSearchWords(entry, stWords);
for (String stWord : stWords) {
if (id.toUpperCase().contains(stWord)) {
exactCategory = id;
}
}
if (found) {
disabledCategories.remove(id);
buttons.get(id).setEnabled(true);
JTabbedPane pane = categoryid2tabbedpane.get(id);
if (categoryid2tabs.get(id) != null) {
HashMap tabsInfo = categoryid2tabs.get(id);
boolean foundInNoTab = true;
for (Map.Entry it : tabsInfo.entrySet()) {
Integer tabIndex = it.getKey();
if (tabIndex != -1) {
ArrayList tabWords = it.getValue().getWords();
boolean foundInTab = false;
if (containsAllSearchWords(tabWords, stWords)) {
foundInTab = true;
foundInNoTab = false;
exactTabIndex = tabIndex;
if ((exactCategory == null && exactTabTitle == null) || (exactCategory != null && exactCategory.equals(id))) {
setCurrentCategory(categoryModel.getCategory(id), null);
}
}
if (foundInTab) {
for (String stWord : stWords) {
if (pane.getTitleAt(tabIndex).toUpperCase().contains(stWord)) {
exactTabTitle = pane.getTitleAt(tabIndex);
}
}
pane.setEnabledAt(tabIndex, true);
if (exactTabIndex == tabIndex
&& (exactTabTitle == null || (exactTabTitle != null && pane.getTitleAt(tabIndex).equals(exactTabTitle)))) {
pane.setSelectedIndex(tabIndex);
setCurrentCategory(categoryModel.getCategory(id), null);
}
matchedKeywords = getAllMatchedKeywords(tabWords, stWords);
categoryModel.getCurrent().handleSuccessfulSearchInController(searchText, matchedKeywords);
} else {
pane.setEnabledAt(tabIndex, false);
if(exactTabIndex == -1) {
pane.setSelectedIndex(getNextEnabledTabIndex(pane, tabIndex));
}
}
} else {
if ((exactCategory == null && exactTabTitle == null) || (exactCategory != null && exactCategory.equals(id))) {
setCurrentCategory(categoryModel.getCategory(id), null);
}
if(tabsInfo.size() == 1) {
foundInNoTab = false;
matchedKeywords = getAllMatchedKeywords(entry, stWords);
categoryModel.getCurrent().handleSuccessfulSearchInController(searchText, matchedKeywords);
}
}
}
// above we tried to find an exact match and were conservative about selecting a specific tab, so if
// the search term is found and no tab is yet selected make sure at least last one found gets selected
if (!foundInNoTab && pane != null && pane.getSelectedIndex() == -1) {
pane.setSelectedIndex(exactTabIndex);
}
if(foundInNoTab) {
handleNotFound(id, exactCategory, exactTabTitle);
}
} else {
if ((exactCategory == null && exactTabTitle == null) || (exactCategory != null && exactCategory.equals(id))) {
setCurrentCategory(categoryModel.getCategory(id), null);
}
matchedKeywords = getAllMatchedKeywords(entry, stWords);
categoryModel.getCurrent().handleSuccessfulSearchInController(searchText, matchedKeywords);
}
} else {
handleNotFound(id, exactCategory, exactTabTitle);
}
} else {
handleNotFound(id, exactCategory, exactTabTitle);
}
}
}
private void handleNotFound(String id, String exactCategory, String exactTabTitle) {
if (!disabledCategories.contains(id)) {
disabledCategories.add(id);
}
JTabbedPane pane = categoryid2tabbedpane.get(id);
if (categoryid2tabs.get(id) != null && pane != null) {
for (int i = 0; i < pane.getTabCount(); i++) {
pane.setEnabledAt(i, false);
}
}
buttons.get(id).setEnabled(false);
if (disabledCategories.size() == buttons.size()) {
setCurrentCategory(null, null);
} else {
for (String id3 : categoryModel.getCategoryIDs()) {
if (buttons.get(id3).isEnabled() && ((exactCategory != null && exactCategory.equals(id3)) || (exactCategory == null && exactTabTitle == null))) {
setCurrentCategory(categoryModel.getCategory(id3), null);
break;
}
}
}
}
@Override
public void showNextSelection(boolean forward) {
}
@Override
public String findMaxPrefix(String prefix) {
return prefix;
}
@Override
public void quickSearchConfirmed() {
if (text2search.length() == 0) {
clearAllinQS();
showHint(true);
return;
}
showWaitCursor();
try {
if (!initialized) {
final String sText = text2search;
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
computeOptionsWords();
initialized = true;
handleSearch(sText);
showHint(false);
}
});
} else {
handleSearch(text2search);
showHint(false);
}
} finally {
hideWaitCursor();
}
}
@Override
public void quickSearchCanceled() {
if(!text2search.trim().isEmpty()) {
// we got a call from GuickSearch.SearchFieldListener.searchForNode(),
// so call quickSearchUpdate ourselves.
quickSearchUpdate("");
return;
}
clearAllinQS();
if (searchTC.hasFocus()) {
showHint(false);
} else {
// Show the hint in the next EQ round to prevent from mutation in notification
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
showHint(true);
}
});
}
}
}
private void clearAllinQS() {
clearSearch = true;
for (String id : categoryModel.getCategoryIDs()) {
JTabbedPane pane = categoryid2tabbedpane.get(id);
if (categoryid2tabs.get(id) != null && pane != null) {
for (int i = 0; i < pane.getTabCount(); i++) {
pane.setEnabledAt(i, true);
}
}
buttons.get(id).setEnabled(true);
}
setCurrentCategory(categoryModel.getCurrent(), null);
disabledCategories.clear();
categoryModel.getCurrent().handleSuccessfulSearchInController(null, null);
}
private void initActions () {
if (getActionMap ().get("PREVIOUS") == null) {//NOI18N
InputMap inputMap = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
inputMap.put (KeyStroke.getKeyStroke (KeyEvent.VK_TAB, KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK), "PREVIOUS");//NOI18N
getActionMap ().put ("PREVIOUS", new PreviousAction ());//NOI18N
inputMap.put (KeyStroke.getKeyStroke (KeyEvent.VK_TAB, KeyEvent.CTRL_DOWN_MASK),"NEXT");//NOI18N
getActionMap ().put ("NEXT", new NextAction ());//NOI18N
}
}
private void addCategoryButtons () {
// remove old buttons
Iterator it = buttons.values().iterator ();
while (it.hasNext ()) {
removeButton(it.next());
}
pCategories2.removeAll ();
buttons = new LinkedHashMap();
// add new buttons
String[] names = categoryModel.getCategoryIDs();
for (int i = 0; i < names.length; i++) {
CategoryModel.Category category = categoryModel.getCategory(names[i]);
addButton (category);
}
addFakeButton ();
}
private CategoryButton addButton (CategoryModel.Category category) {
int index = buttons.size ();
CategoryButton button = UIManager.getBoolean(OPTIONS_CATEGORIES_BUTTON_USE_NIMBUS)
? new NimbusCategoryButton(category)
: new CategoryButton(category);
// add shortcut
if (!isMac) {
KeyStroke keyStroke = KeyStroke.getKeyStroke(button.getDisplayedMnemonic(), KeyEvent.ALT_MASK);
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStroke, button);
getActionMap().put(button, new SelectAction(category));
}
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.NORTHWEST;
gbc.fill = GridBagConstraints.BOTH;
gbc.weightx = 0.0;
gbc.weighty = 0.0;
gbc.gridx = index;
gbc.gridy = 0;
pCategories2.add(button, gbc);
buttons.put (category.getID(), button);
return button;
}
private void removeButton (CategoryButton button) {
KeyStroke keyStroke = KeyStroke.getKeyStroke
(button.getDisplayedMnemonic (), KeyEvent.ALT_MASK);
getInputMap (JComponent.WHEN_IN_FOCUSED_WINDOW).remove (keyStroke);
getActionMap ().remove (button);
}
private void addFakeButton () {
/* i don't know a better workaround */
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.BOTH;
gbc.weightx = 1.0;
gbc.weighty = 1.0;
gbc.gridy = 0;
pCategories2.add (new javax.swing.JLabel (""), gbc);
}
private Dimension getInitSize() {
//if necessary init size could be chosen for individual resolutions differently
//DisplayMode dm = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDisplayMode();
return new Dimension(750, 500);
}
Dimension getUserSize() {
int w = NbPreferences.forModule(OptionsPanel.class).getInt("OptionsWidth",getInitSize().width);//NOI18N
int h = NbPreferences.forModule(OptionsPanel.class).getInt("OptionsHeight",getInitSize().height);//NOI18N
return new Dimension (w, h);
}
@Override
public Dimension getPreferredSize() {
//#108865 Scrollbars appear on Options dialog - preferredSize mustn't exceed screenBounds.? - 100
//else NbPresenter will show up scrollbars
Dimension d = super.getPreferredSize();
final Rectangle screenBounds = Utilities.getUsableScreenBounds();
return new Dimension(Math.min(d.width, screenBounds.width - 101), Math.min(d.height, screenBounds.height - 101));
}
void storeUserSize() {
Dimension d = pOptions.getSize();
NbPreferences.forModule(OptionsPanel.class).putInt("OptionsWidth",d.width);//NOI18N
NbPreferences.forModule(OptionsPanel.class).putInt("OptionsHeight",d.height);//NOI18N
pOptions.setPreferredSize(d);
}
private boolean checkSize(Dimension componentSize) {
boolean retval = false;
Dimension prefSize = pOptions.getPreferredSize();
Dimension userSize = getUserSize();
componentSize = new Dimension(Math.max(componentSize.width, userSize.width),Math.max(componentSize.height, userSize.height));
if (prefSize.width < componentSize.width || prefSize.height < componentSize.height) {
Dimension newSize = new Dimension(Math.max(prefSize.width, componentSize.width),Math.max(prefSize.height, componentSize.height));
pOptions.setPreferredSize(newSize);
Window w = (Window) SwingUtilities.getAncestorOfClass(Window.class, this);
invalidate();
if (w != null) {
w.pack();
}
retval = true;
}
return retval;
}
private Color getTabPanelBackground() {
Color uiColor = UIManager.getColor("nb.options.categories.tabPanelBackground"); //NOI18N
if (uiColor != null) {
return uiColor;
}
if( useUIDefaultsColors() ) {
Color res = UIManager.getColor( "Tree.background" ); //NOI18N
if( null == res )
res = Color.white;
return new Color( res.getRGB() );
}
return Color.white;
}
private Color getTabPanelForeground() {
Color uiColor = UIManager.getColor("nb.options.categories.tabPanelForeground"); //NOI18N
if (uiColor != null) {
return uiColor;
}
if( useUIDefaultsColors() ) {
Color res = UIManager.getColor( "Tree.foreground" ); //NOI18N
if( null == res )
res = Color.black;
return new Color( res.getRGB() );
}
return Color.black;
}
private Color getSelectionBackground() {
Color uiColor = UIManager.getColor("nb.options.categories.selectionBackground"); //NOI18N
if (uiColor != null) {
return uiColor;
}
if( useUIDefaultsColors() ) {
if( !Color.white.equals( getTabPanelBackground() ) ) {
Color res = UIManager.getColor( "Tree.selectionBackground" ); //NOI18N
if( null == res )
res = Color.blue;
return new Color( res.getRGB() );
}
}
return new Color (193, 210, 238);
}
private Color getSelectionForeground() {
Color uiColor = UIManager.getColor("nb.options.categories.selectionForeground"); //NOI18N
if (uiColor != null) {
return uiColor;
}
if ( useUIDefaultsColors() ) {
Color res = UIManager.getColor("Tree.selectionForeground"); //NOI18N
if (null == res) {
return new Color(res.getRGB());
}
}
return getTabPanelForeground();
}
private Color getHighlightBackground() {
Color uiColor = UIManager.getColor("nb.options.categories.highlightBackground"); //NOI18N
if (uiColor != null) {
return uiColor;
}
if( useUIDefaultsColors() ) {
if( !Color.white.equals( getTabPanelBackground() ) ) {
Color res = UIManager.getColor( "Tree.selectionBackground" ); //NOI18N
if( null == res )
res = Color.blue;
return new Color( res.getRGB() );
}
}
return new Color (224, 232, 246);
}
private Color getHighlightForeground() {
Color uiColor = UIManager.getColor("nb.options.categories.highlightForeground"); //NOI18N
if (uiColor != null) {
return uiColor;
}
if( useUIDefaultsColors() ) {
if( !Color.white.equals( getTabPanelBackground() ) ) {
Color res = UIManager.getColor( "Tree.selectionForeground" ); //NOI18N
if( null == res )
res = Color.blue;
return new Color( res.getRGB() );
}
}
return getTabPanelForeground();
}
/**
* Get if Options Panel uses UI default colors.
* Use property nb.options.useUIDefaultsColors to use modify it.
* @return boolean
*/
private boolean useUIDefaultsColors() {
return UIManager.getBoolean(OPTIONS_USE_UI_DEFAULT_COLORS);
}
private Color getUIColorOrDefault(String uiKey, Color defaultColor) {
Color uiColor = UIManager.getColor(uiKey);
return (uiColor != null) ? uiColor : defaultColor;
}
// innerclasses ............................................................
private class SelectAction extends AbstractAction {
private CategoryModel.Category category;
SelectAction (CategoryModel.Category category) {
this.category = category;
}
public void actionPerformed (ActionEvent e) {
setCurrentCategory (category, null);
}
}
private class SelectCurrentAction extends AbstractAction {
public void actionPerformed(ActionEvent e) {
CategoryModel.Category highlightedB = categoryModel.getCategory(categoryModel.getHighlitedCategoryID());
if (highlightedB != null) {
setCurrentCategory(highlightedB, null);
}
}
}
private class SearchAction extends AbstractAction {
@Override
public void actionPerformed (ActionEvent e) {
showHint(false);
searchTC.requestFocusInWindow();
}
}
private class PreviousAction extends AbstractAction {
public void actionPerformed (ActionEvent e) {
Category previous = categoryModel.getPreviousCategory();
if(buttons.get(previous.getID()).isEnabled()) {
setCurrentCategory (previous, null);
} else {
String currentID = categoryModel.getCurrentCategoryID();
String[] ids = categoryModel.getCategoryIDs();
int idx = Arrays.asList(ids).indexOf(currentID);
if(idx - 1 > -1) {
if (doPreviousNextAction(ids, idx - 1, -1, false)) {
doPreviousNextAction(ids, ids.length - 1, idx, false);
}
} else {
doPreviousNextAction(ids, ids.length - 1, idx, false);
}
}
}
}
private class NextAction extends AbstractAction {
public void actionPerformed (ActionEvent e) {
Category next = categoryModel.getNextCategory();
if(buttons.get(next.getID()).isEnabled()) {
setCurrentCategory (next, null);
} else {
String currentID = categoryModel.getCurrentCategoryID();
String[] ids = categoryModel.getCategoryIDs();
int idx = Arrays.asList(ids).indexOf(currentID);
if(idx + 1 < ids.length) {
if(doPreviousNextAction(ids, idx + 1, ids.length, true)) {
doPreviousNextAction(ids, 0, idx, true);
}
} else {
doPreviousNextAction(ids, 0, idx, true);
}
}
}
}
private boolean doPreviousNextAction(String[] ids, int start, int end, boolean nextAction) {
if (nextAction) {
for (int i = start; i < end; i++) {
String id = ids[i];
if (buttons.get(id).isEnabled()) {
setCurrentCategory(categoryModel.getCategory(id), null);
return false;
}
}
} else {
for (int i = start; i > end; i--) {
String id = ids[i];
if (buttons.get(id).isEnabled()) {
setCurrentCategory(categoryModel.getCategory(id), null);
return false;
}
}
}
return true;
}
class ControllerListener implements PropertyChangeListener {
public void propertyChange (PropertyChangeEvent evt) {
OptionsPanel.this.firePropertyChange
("buran" + evt.getPropertyName (), null, null);
}
}
@NbBundle.Messages({"# {0} - name of the category button",
"CategoryButton_AccessibleDescription={0} category button. Use the arrow keys to move between top level categories."})
class CategoryButton extends JLabel implements MouseListener {
private final CategoryModel.Category category;
CategoryButton (final CategoryModel.Category category) {
super (category.getIcon());
this.category = category;
Mnemonics.setLocalizedText (this, category.getCategoryName());
getAccessibleContext().setAccessibleName(category.getCategoryName());
getAccessibleContext().setAccessibleDescription(Bundle.CategoryButton_AccessibleDescription(category.getCategoryName()));
setDisplayedMnemonic(0);
setOpaque (true);
setVerticalTextPosition (BOTTOM);
setHorizontalTextPosition (CENTER);
setHorizontalAlignment (CENTER);
addMouseListener (this);
setFocusable (false);
setFocusTraversalKeysEnabled (false);
if (isMac) {
setFont(labelFontMac);
setIconTextGap(2);
}
setNormal ();
}
void setNormal () {
if (isMac) {
setBorder (new EmptyBorder (5, 6, 3, 6));
} else {
setBorder (new EmptyBorder (2, 4, 2, 4));
}
setBackground(getTabPanelBackground());
setForeground(getTabPanelForeground());
}
void setSelected () {
if (isMac) {
setBorder(new CompoundBorder (
new VariableBorder(null, selectedB, null, selectedB),
BorderFactory.createEmptyBorder(5, 5, 3, 5)
));
} else {
setBorder (new CompoundBorder (
new CompoundBorder (
new LineBorder (getTabPanelBackground()),
new LineBorder (selectedB)
),
new EmptyBorder (0, 2, 0, 2)
));
}
setBackground(selected);
setForeground(getSelectionForeground());
}
void setHighlighted() {
if (!isMac) {
setBorder(new CompoundBorder(
new CompoundBorder(
new LineBorder(getTabPanelBackground()),
new LineBorder(highlightedB)
),
new EmptyBorder(0, 2, 0, 2)
));
setBackground(highlighted);
setForeground(getHighlightForeground());
}
if (!category.isHighlited()) {
if (categoryModel.getHighlitedCategoryID() != null) {
CategoryButton b = buttons.get(categoryModel.getHighlitedCategoryID());
if (b != null && !b.category.isCurrent()) {
b.setNormal();
}
}
categoryModel.setHighlited(category,true);
}
}
public void mouseClicked (MouseEvent e) {
}
public void mousePressed (MouseEvent e) {
if (buttons.get(category.getID()).isEnabled() && !isMac && categoryModel.getCurrent() != null) {
setSelected ();
}
}
public void mouseReleased (MouseEvent e) {
if (buttons.get(category.getID()).isEnabled() && !category.isCurrent() && category.isHighlited() && categoryModel.getCurrent() != null) {
setCurrentCategory(category, null);
}
}
public void mouseEntered (MouseEvent e) {
CategoryButton button = buttons.get(category.getID());
if (button != null && button.isEnabled() && !category.isCurrent() && categoryModel != null && categoryModel.getCurrent() != null) {
setHighlighted();
} else if (categoryModel != null) {
categoryModel.setHighlited(categoryModel.getCategory(categoryModel.getHighlitedCategoryID()), false);
}
}
public void mouseExited (MouseEvent e) {
if (!category.isCurrent() && !isMac && categoryModel.getCurrent() != null) {
setNormal ();
}
}
}
private static final int BORDER_WIDTH = 4;
private static final Border selBorder = new CompoundBorder(
new CompoundBorder(BorderFactory.createEmptyBorder(BORDER_WIDTH, BORDER_WIDTH, BORDER_WIDTH, BORDER_WIDTH),
new NimbusBorder() ),
BorderFactory.createEmptyBorder(BORDER_WIDTH, BORDER_WIDTH, BORDER_WIDTH, BORDER_WIDTH));
private static final Border normalBorder = BorderFactory.createEmptyBorder(2*BORDER_WIDTH+1, 2*BORDER_WIDTH+1, 2*BORDER_WIDTH+3, 2*BORDER_WIDTH+3);
private static final short STATUS_NORMAL = 0;
private static final short STATUS_SELECTED = 1;
private static final short STATUS_HIGHLIGHTED = 2;
private static final Color COL_GRADIENT1 = new Color(244,245,249);
private static final Color COL_GRADIENT2 = new Color(163,184,203);
private static final Color COL_GRADIENT3 = new Color(206,227,246);
private static final Color COL_OVER_GRADIENT1 = new Color(244,245,249,128);
private static final Color COL_OVER_GRADIENT2 = new Color(163,184,203,128);
private static final Color COL_OVER_GRADIENT3 = new Color(206,227,246,128);
private final boolean isDefaultTabBackground = Color.white.equals( getTabPanelBackground() );
private class NimbusCategoryButton extends CategoryButton {
private short status = STATUS_NORMAL;
public NimbusCategoryButton( final CategoryModel.Category category ) {
super( category );
setOpaque(false);
setBorder( normalBorder );
}
@Override
protected void paintChildren(Graphics g) {
super.paintChildren(g);
}
@Override
protected void paintComponent(Graphics g) {
if( isDefaultTabBackground && (status == STATUS_SELECTED || status == STATUS_HIGHLIGHTED) ) {
Insets in = getInsets();
in.top -= BORDER_WIDTH;
in.left -= BORDER_WIDTH;
in.bottom -= BORDER_WIDTH;
in.right -= BORDER_WIDTH;
Graphics2D g2d = (Graphics2D) g.create();
int width = getWidth()-in.left-in.right+1;
int height = getHeight()-in.top-in.bottom+1;
int topGradient = (int)(0.7*height);
int bottomGradient = height-topGradient;
Color c1 = (status == STATUS_HIGHLIGHTED ? COL_OVER_GRADIENT1 : COL_GRADIENT1);
Color c2 = (status == STATUS_HIGHLIGHTED ? COL_OVER_GRADIENT2 : COL_GRADIENT2);
Color c3 = (status == STATUS_HIGHLIGHTED ? COL_OVER_GRADIENT3 : COL_GRADIENT3);
g2d.setPaint( new GradientPaint(in.left, in.top, c1, in.left, in.top+topGradient, c2));
g2d.fillRect(in.left,in.top, width, topGradient );
g2d.setPaint( new GradientPaint(in.left, in.top+topGradient, c2, in.left, in.top+topGradient+bottomGradient, c3));
g2d.fillRect(in.left,in.top+topGradient, width, bottomGradient );
g2d.dispose();
}
super.paintComponent(g);
}
@Override
void setHighlighted() {
super.setHighlighted();
status = STATUS_HIGHLIGHTED;
setBorder(selBorder);
repaint();
}
@Override
void setNormal() {
super.setNormal();
setBorder(normalBorder);
status = STATUS_NORMAL;
repaint();
}
@Override
void setSelected() {
setBorder(selBorder);
status = STATUS_SELECTED;
repaint();
}
}
private static class NimbusBorder implements Border {
private static final Color COLOR_BORDER = new Color(72,93,112, 255);
private static final Color COLOR_SHADOW1 = new Color(72,93,112, 100);
private static final Color COLOR_SHADOW2 = new Color(72,93,112, 60) ;
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
Graphics2D g2d = (Graphics2D)g;
g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
Area rect = new Area(new RoundRectangle2D.Float(x, y, width-3, height-2, 4, 4));
g2d.setColor( COLOR_BORDER );
g2d.draw( rect );
Area shadow = new Area( rect );
AffineTransform tx = new AffineTransform();
tx.translate(1, 1);
shadow.transform(tx);
shadow.subtract(rect);
g2d.setColor( COLOR_SHADOW1 );
g2d.draw( shadow );
shadow = new Area( rect );
tx = new AffineTransform();
tx.translate(2, 2);
shadow.transform(tx);
shadow.subtract(rect);
g2d.setColor( COLOR_SHADOW2 );
g2d.draw( shadow );
}
public Insets getBorderInsets(Component c) {
return new Insets( 1,1,3,3 );
}
public boolean isBorderOpaque() {
return false;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy