Lines 133-139
Link Here
|
133 |
import javax.swing.event.TreeWillExpandListener; |
133 |
import javax.swing.event.TreeWillExpandListener; |
134 |
import javax.swing.plaf.TreeUI; |
134 |
import javax.swing.plaf.TreeUI; |
135 |
import javax.swing.plaf.UIResource; |
135 |
import javax.swing.plaf.UIResource; |
136 |
import javax.swing.text.Position; |
|
|
137 |
import javax.swing.tree.ExpandVetoException; |
136 |
import javax.swing.tree.ExpandVetoException; |
138 |
import javax.swing.tree.RowMapper; |
137 |
import javax.swing.tree.RowMapper; |
139 |
import javax.swing.tree.TreeCellEditor; |
138 |
import javax.swing.tree.TreeCellEditor; |
Lines 141-146
Link Here
|
141 |
import javax.swing.tree.TreeNode; |
140 |
import javax.swing.tree.TreeNode; |
142 |
import javax.swing.tree.TreePath; |
141 |
import javax.swing.tree.TreePath; |
143 |
import javax.swing.tree.TreeSelectionModel; |
142 |
import javax.swing.tree.TreeSelectionModel; |
|
|
143 |
import org.openide.awt.QuickSearch; |
144 |
import org.openide.awt.QuickSearchListener; |
144 |
|
145 |
|
145 |
|
146 |
|
146 |
/** |
147 |
/** |
Lines 224-231
Link Here
|
224 |
transient private int allowedDropActions = DnDConstants.ACTION_COPY_OR_MOVE | DnDConstants.ACTION_REFERENCE; |
225 |
transient private int allowedDropActions = DnDConstants.ACTION_COPY_OR_MOVE | DnDConstants.ACTION_REFERENCE; |
225 |
|
226 |
|
226 |
/** Quick Search support */ |
227 |
/** Quick Search support */ |
227 |
transient private boolean allowedQuickSearch = true; |
228 |
transient private QuickSearch qs; |
228 |
transient private KeyAdapter quickSearchKeyAdapter; |
|
|
229 |
|
229 |
|
230 |
/** wait cursor is shown automatically during expanding */ |
230 |
/** wait cursor is shown automatically during expanding */ |
231 |
transient private boolean autoWaitCursor = true; |
231 |
transient private boolean autoWaitCursor = true; |
Lines 454-460
Link Here
|
454 |
* @return true if quick search feature is enabled, false otherwise. |
454 |
* @return true if quick search feature is enabled, false otherwise. |
455 |
*/ |
455 |
*/ |
456 |
public boolean isQuickSearchAllowed() { |
456 |
public boolean isQuickSearchAllowed() { |
457 |
return allowedQuickSearch; |
457 |
return qs.isEnabled(); |
458 |
} |
458 |
} |
459 |
|
459 |
|
460 |
/** |
460 |
/** |
Lines 463-477
Link Here
|
463 |
* @param allowedQuickSearch <code>true</code> if quick search shall be enabled |
463 |
* @param allowedQuickSearch <code>true</code> if quick search shall be enabled |
464 |
*/ |
464 |
*/ |
465 |
public void setQuickSearchAllowed(boolean allowedQuickSearch) { |
465 |
public void setQuickSearchAllowed(boolean allowedQuickSearch) { |
466 |
this.allowedQuickSearch = allowedQuickSearch; |
466 |
qs.setEnabled(allowedQuickSearch); |
467 |
if (quickSearchKeyAdapter != null && tree != null) { |
|
|
468 |
if (allowedQuickSearch) { |
469 |
tree.addKeyListener(quickSearchKeyAdapter); |
470 |
} else { |
471 |
removeSearchField(); |
472 |
tree.removeKeyListener(quickSearchKeyAdapter); |
473 |
} |
474 |
} |
475 |
} |
467 |
} |
476 |
|
468 |
|
477 |
|
469 |
|
Lines 1683-1693
Link Here
|
1683 |
} |
1675 |
} |
1684 |
|
1676 |
|
1685 |
@Override |
1677 |
@Override |
|
|
1678 |
public void add(Component comp, Object constraints) { |
1679 |
if (constraints == searchConstraints) { |
1680 |
searchPanel = comp; |
1681 |
constraints = null; |
1682 |
} |
1683 |
super.add(comp, constraints); |
1684 |
} |
1685 |
|
1686 |
@Override |
1687 |
public void remove(Component comp) { |
1688 |
if (comp == searchPanel) { |
1689 |
searchPanel = null; |
1690 |
} |
1691 |
super.remove(comp); |
1692 |
} |
1693 |
|
1694 |
@Override |
1686 |
public Insets getInsets() { |
1695 |
public Insets getInsets() { |
1687 |
Insets res = getInnerInsets(); |
1696 |
Insets res = getInnerInsets(); |
1688 |
res = new Insets(res.top, res.left, res.bottom, res.right); |
1697 |
res = new Insets(res.top, res.left, res.bottom, res.right); |
1689 |
if( null != searchpanel && searchpanel.isVisible() ) { |
1698 |
if( null != searchPanel && searchPanel.isVisible() ) { |
1690 |
res.bottom += searchpanel.getPreferredSize().height; |
1699 |
res.bottom += searchPanel.getPreferredSize().height; |
1691 |
} |
1700 |
} |
1692 |
return res; |
1701 |
return res; |
1693 |
} |
1702 |
} |
Lines 1701-1830
Link Here
|
1701 |
} |
1710 |
} |
1702 |
|
1711 |
|
1703 |
TreePath[] origSelectionPaths = null; |
1712 |
TreePath[] origSelectionPaths = null; |
1704 |
JPanel searchpanel = null; |
1713 |
private Component searchPanel = null; |
1705 |
// searchTextField manages focus because it handles VK_TAB key |
1714 |
private final Object searchConstraints = new Object(); |
1706 |
private JTextField searchTextField = new JTextField() { |
1715 |
|
1707 |
@Override |
1716 |
/** Called from tests */ |
1708 |
public boolean isManagingFocus() { |
1717 |
Component getSearchPanel() { |
1709 |
return true; |
1718 |
return searchPanel; |
1710 |
} |
|
|
1711 |
|
1712 |
@Override |
1713 |
public void processKeyEvent(KeyEvent ke) { |
1714 |
//override the default handling so that |
1715 |
//the parent will never receive the escape key and |
1716 |
//close a modal dialog |
1717 |
if (ke.getKeyCode() == KeyEvent.VK_ESCAPE) { |
1718 |
removeSearchField(); |
1719 |
ke.consume(); |
1720 |
|
1721 |
// bugfix #32909, reqest focus when search field is removed |
1722 |
SwingUtilities.invokeLater( |
1723 |
new Runnable() { |
1724 |
//additional bugfix - do focus change later or removing |
1725 |
//the component while it's focused will cause focus to |
1726 |
//get transferred to the next component in the |
1727 |
//parent focusTraversalPolicy *after* our request |
1728 |
//focus completes, so focus goes into a black hole - Tim |
1729 |
@Override |
1730 |
public void run() { |
1731 |
if( null != tree ) |
1732 |
tree.requestFocus(); |
1733 |
} |
1734 |
} |
1735 |
); |
1736 |
} else { |
1737 |
super.processKeyEvent(ke); |
1738 |
} |
1739 |
} |
1740 |
}; |
1741 |
private int originalScrollMode; |
1742 |
|
1743 |
private static class SearchPanel extends JPanel { |
1744 |
public SearchPanel() { |
1745 |
if( ViewUtil.isAquaLaF ) |
1746 |
setBorder(BorderFactory.createEmptyBorder(9,6,8,2)); |
1747 |
else |
1748 |
setBorder(BorderFactory.createEmptyBorder(2,6,2,2)); |
1749 |
setOpaque( true ); |
1750 |
} |
1751 |
|
1752 |
@Override |
1753 |
protected void paintComponent(Graphics g) { |
1754 |
if( ViewUtil.isAquaLaF && g instanceof Graphics2D ) { |
1755 |
Graphics2D g2d = (Graphics2D) g; |
1756 |
g2d.setPaint( new GradientPaint(0, 0, UIManager.getColor("NbExplorerView.quicksearch.background.top"), |
1757 |
0, getHeight(), UIManager.getColor("NbExplorerView.quicksearch.background.bottom")));//NOI18N |
1758 |
g2d.fillRect(0, 0, getWidth(), getHeight()); |
1759 |
g2d.setColor( UIManager.getColor("NbExplorerView.quicksearch.border") ); //NOI18N |
1760 |
g2d.drawLine(0, 0, getWidth(), 0); |
1761 |
} else { |
1762 |
super.paintComponent(g); |
1763 |
} |
1764 |
} |
1765 |
} |
1766 |
|
1767 |
|
1768 |
private void prepareSearchPanel() { |
1769 |
if( searchpanel == null ) { |
1770 |
searchpanel = new SearchPanel(); |
1771 |
|
1772 |
JLabel lbl = new JLabel(NbBundle.getMessage(TreeView.class, "LBL_QUICKSEARCH")); //NOI18N |
1773 |
searchpanel.setLayout(new BoxLayout(searchpanel, BoxLayout.X_AXIS)); |
1774 |
searchpanel.add(lbl); |
1775 |
searchpanel.add(searchTextField); |
1776 |
lbl.setLabelFor(searchTextField); |
1777 |
searchTextField.setColumns(10); |
1778 |
searchTextField.setMaximumSize(searchTextField.getPreferredSize()); |
1779 |
searchTextField.putClientProperty("JTextField.variant", "search"); //NOI18N |
1780 |
lbl.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5)); |
1781 |
} |
1782 |
} |
1783 |
|
1784 |
/** |
1785 |
* Adds the search field to the tree. |
1786 |
*/ |
1787 |
private void displaySearchField() { |
1788 |
if( null != searchpanel || !isQuickSearchAllowed()) |
1789 |
return; |
1790 |
|
1791 |
TreeView previousSearchField = lastSearchField.get(); |
1792 |
if (previousSearchField != null && previousSearchField != this) { |
1793 |
previousSearchField.removeSearchField(); |
1794 |
} |
1795 |
|
1796 |
JViewport vp = getViewport(); |
1797 |
originalScrollMode = vp.getScrollMode(); |
1798 |
vp.setScrollMode(JViewport.SIMPLE_SCROLL_MODE); |
1799 |
searchTextField.setFont(tree.getFont()); |
1800 |
prepareSearchPanel(); |
1801 |
add(searchpanel); |
1802 |
invalidate(); |
1803 |
revalidate(); |
1804 |
repaint(); |
1805 |
searchTextField.requestFocus(); |
1806 |
|
1807 |
lastSearchField = new WeakReference<TreeView>(this); |
1808 |
} |
1809 |
|
1810 |
/** |
1811 |
* Removes the search field from the tree. |
1812 |
*/ |
1813 |
private void removeSearchField() { |
1814 |
if( null == searchpanel ) |
1815 |
return; |
1816 |
|
1817 |
if (tree.getSelectionPaths() == null && origSelectionPaths != null) { |
1818 |
tree.setSelectionPaths(origSelectionPaths); |
1819 |
} |
1820 |
|
1821 |
remove(searchpanel); |
1822 |
searchpanel = null; |
1823 |
origSelectionPaths = null; |
1824 |
getViewport().setScrollMode(originalScrollMode); |
1825 |
invalidate(); |
1826 |
revalidate(); |
1827 |
repaint(); |
1828 |
} |
1719 |
} |
1829 |
|
1720 |
|
1830 |
private class ExplorerScrollPaneLayout extends ScrollPaneLayout { |
1721 |
private class ExplorerScrollPaneLayout extends ScrollPaneLayout { |
Lines 1832-1851
Link Here
|
1832 |
@Override |
1723 |
@Override |
1833 |
public void layoutContainer( Container parent ) { |
1724 |
public void layoutContainer( Container parent ) { |
1834 |
super.layoutContainer(parent); |
1725 |
super.layoutContainer(parent); |
1835 |
if( null != searchpanel && searchpanel.isVisible() ) { |
1726 |
if( null != searchPanel && searchPanel.isVisible() ) { |
1836 |
Insets innerInsets = getInnerInsets(); |
1727 |
Insets innerInsets = getInnerInsets(); |
1837 |
Dimension prefSize = searchpanel.getPreferredSize(); |
1728 |
Dimension prefSize = searchPanel.getPreferredSize(); |
1838 |
searchpanel.setBounds(innerInsets.left, parent.getHeight()-innerInsets.bottom-prefSize.height, |
1729 |
searchPanel.setBounds(innerInsets.left, parent.getHeight()-innerInsets.bottom-prefSize.height, |
1839 |
parent.getWidth()-innerInsets.left-innerInsets.right, prefSize.height); |
1730 |
parent.getWidth()-innerInsets.left-innerInsets.right, prefSize.height); |
1840 |
} |
1731 |
} |
1841 |
} |
1732 |
} |
1842 |
} |
1733 |
} |
1843 |
|
1734 |
|
1844 |
private final class ExplorerTree extends JTree implements Autoscroll { |
1735 |
private final class ExplorerTree extends JTree implements Autoscroll, QuickSearchListener { |
1845 |
AutoscrollSupport support; |
1736 |
AutoscrollSupport support; |
1846 |
private String maxPrefix; |
1737 |
private String maxPrefix; |
1847 |
int SEARCH_FIELD_SPACE = 3; |
1738 |
int SEARCH_FIELD_SPACE = 3; |
1848 |
private boolean firstPaint = true; |
1739 |
private boolean firstPaint = true; |
|
|
1740 |
/** The last search searchResults */ |
1741 |
private List<TreePath> searchResults = new ArrayList<TreePath>(); |
1742 |
/** The last selected index from the search searchResults. */ |
1743 |
private int currentSelectionIndex; |
1744 |
private String lastSearchText; |
1849 |
|
1745 |
|
1850 |
|
1746 |
|
1851 |
ExplorerTree(TreeModel model) { |
1747 |
ExplorerTree(TreeModel model) { |
Lines 2008-2013
Link Here
|
2008 |
new GuardedActions(3, fe); |
1904 |
new GuardedActions(3, fe); |
2009 |
} |
1905 |
} |
2010 |
|
1906 |
|
|
|
1907 |
@Override |
1908 |
protected void processKeyEvent(KeyEvent e) { |
1909 |
qs.processKeyEvent(e); |
1910 |
if (!e.isConsumed()) { |
1911 |
super.processKeyEvent(e); |
1912 |
} |
1913 |
} |
1914 |
|
2011 |
private void repaintSelection() { |
1915 |
private void repaintSelection() { |
2012 |
int first = getSelectionModel().getMinSelectionRow(); |
1916 |
int first = getSelectionModel().getMinSelectionRow(); |
2013 |
int last = getSelectionModel().getMaxSelectionRow(); |
1917 |
int last = getSelectionModel().getMaxSelectionRow(); |
Lines 2039-2096
Link Here
|
2039 |
|
1943 |
|
2040 |
private void setupSearch() { |
1944 |
private void setupSearch() { |
2041 |
// Remove the default key listeners |
1945 |
// Remove the default key listeners |
2042 |
KeyListener[] keyListeners = getListeners(KeyListener.class); |
1946 |
// KeyListener[] keyListeners = getListeners(KeyListener.class); |
2043 |
|
1947 |
// |
2044 |
for (int i = 0; i < keyListeners.length; i++) { |
1948 |
// for (int i = 0; i < keyListeners.length; i++) { |
2045 |
removeKeyListener(keyListeners[i]); |
1949 |
// removeKeyListener(keyListeners[i]); |
2046 |
} |
1950 |
// } |
2047 |
|
1951 |
|
2048 |
// create new key listeners |
1952 |
qs = QuickSearch.attach(TreeView.this, searchConstraints); |
2049 |
quickSearchKeyAdapter = ( |
1953 |
qs.addQuickSearchListener(this); |
2050 |
new KeyAdapter() { |
|
|
2051 |
@Override |
2052 |
public void keyTyped(KeyEvent e) { |
2053 |
int modifiers = e.getModifiers(); |
2054 |
int keyCode = e.getKeyCode(); |
2055 |
char c = e.getKeyChar(); |
2056 |
|
2057 |
//#43617 - don't eat + and - |
2058 |
//#98634 - and all its duplicates dont't react to space |
2059 |
if ((c == '+') || (c == '-') || (c==' ')) return; // NOI18N |
2060 |
|
2061 |
if (((modifiers > 0) && (modifiers != KeyEvent.SHIFT_MASK)) || e.isActionKey()) { |
2062 |
return; |
2063 |
} |
2064 |
|
2065 |
if (Character.isISOControl(c) || |
2066 |
(keyCode == KeyEvent.VK_SHIFT) || |
2067 |
(keyCode == KeyEvent.VK_ESCAPE)) return; |
2068 |
|
2069 |
final KeyStroke stroke = KeyStroke.getKeyStrokeForEvent(e); |
2070 |
origSelectionPaths = getSelectionPaths(); |
2071 |
if (origSelectionPaths != null && origSelectionPaths.length == 0) { |
2072 |
origSelectionPaths = null; |
2073 |
} |
2074 |
searchTextField.setText(String.valueOf(stroke.getKeyChar())); |
2075 |
|
2076 |
displaySearchField(); |
2077 |
e.consume(); |
2078 |
} |
2079 |
} |
2080 |
); |
2081 |
if(isQuickSearchAllowed()){ |
2082 |
addKeyListener(quickSearchKeyAdapter); |
2083 |
} |
2084 |
// Create a the "multi-event" listener for the text field. Instead of |
2085 |
// adding separate instances of each needed listener, we're using a |
2086 |
// class which implements them all. This approach is used in order |
2087 |
// to avoid the creation of 4 instances which takes some time |
2088 |
SearchFieldListener searchFieldListener = new SearchFieldListener(); |
2089 |
searchTextField.addKeyListener(searchFieldListener); |
2090 |
searchTextField.addFocusListener(searchFieldListener); |
2091 |
searchTextField.getDocument().addDocumentListener(searchFieldListener); |
2092 |
} |
1954 |
} |
2093 |
|
1955 |
|
|
|
1956 |
@Override |
1957 |
public void quickSearchUpdate(String searchText) { |
1958 |
lastSearchText = searchText; |
1959 |
currentSelectionIndex = 0; |
1960 |
searchResults.clear(); |
1961 |
maxPrefix = null; |
1962 |
|
1963 |
String text = searchText.toUpperCase(); |
1964 |
|
1965 |
if (text.length() > 0) { |
1966 |
searchResults = doSearch(text); |
1967 |
} |
1968 |
displaySearchResult(); |
1969 |
} |
1970 |
|
1971 |
@Override |
1972 |
public void showNextSelection(boolean forward) { |
1973 |
if (forward) { |
1974 |
currentSelectionIndex++; |
1975 |
} else { |
1976 |
currentSelectionIndex--; |
1977 |
} |
1978 |
displaySearchResult(); |
1979 |
} |
1980 |
|
1981 |
@Override |
1982 |
public String findMaxPrefix(String prefix) { |
1983 |
return maxPrefix; |
1984 |
} |
1985 |
|
1986 |
@Override |
1987 |
public void quickSearchConfirmed() { |
1988 |
TreePath selectedTPath = getSelectionPath(); |
1989 |
if (selectedTPath != null) { |
1990 |
TreeNode selectedTNode = (TreeNode) selectedTPath.getLastPathComponent(); |
1991 |
Node selectedNode = Visualizer.findNode(selectedTNode); |
1992 |
performPreferredActionOnNodes(new Node[] { selectedNode }); |
1993 |
} |
1994 |
origSelectionPaths = null; |
1995 |
searchResults.clear(); |
1996 |
lastSearchText = null; |
1997 |
} |
1998 |
|
1999 |
@Override |
2000 |
public void quickSearchCanceled() { |
2001 |
origSelectionPaths = null; |
2002 |
searchResults.clear(); |
2003 |
lastSearchText = null; |
2004 |
} |
2005 |
|
2094 |
private List<TreePath> doSearch(String prefix) { |
2006 |
private List<TreePath> doSearch(String prefix) { |
2095 |
List<TreePath> results = new ArrayList<TreePath>(); |
2007 |
List<TreePath> results = new ArrayList<TreePath>(); |
2096 |
Set<TreePath> resSet = new HashSet<TreePath>(); |
2008 |
Set<TreePath> resSet = new HashSet<TreePath>(); |
Lines 2109-2115
Link Here
|
2109 |
while (true) { |
2021 |
while (true) { |
2110 |
startIndex = startIndex % size; |
2022 |
startIndex = startIndex % size; |
2111 |
|
2023 |
|
2112 |
SubstringSearchResult substringSearchResult = getNextSubstringMatch(prefix, startIndex, Position.Bias.Forward); |
2024 |
SubstringSearchResult substringSearchResult = getNextSubstringMatch(prefix, startIndex, true); |
2113 |
TreePath path = substringSearchResult != null? substringSearchResult.treePath: null; |
2025 |
TreePath path = substringSearchResult != null? substringSearchResult.treePath: null; |
2114 |
|
2026 |
|
2115 |
if ((path != null) && !resSet.contains(path)) { |
2027 |
if ((path != null) && !resSet.contains(path)) { |
Lines 2134-2140
Link Here
|
2134 |
maxPrefix = elementName; |
2046 |
maxPrefix = elementName; |
2135 |
} |
2047 |
} |
2136 |
|
2048 |
|
2137 |
maxPrefix = findMaxPrefix(maxPrefix, elementName); |
2049 |
maxPrefix = QuickSearch.findMaxPrefix(maxPrefix, elementName, true); |
2138 |
} |
2050 |
} |
2139 |
// try next element |
2051 |
// try next element |
2140 |
startIndex++; |
2052 |
startIndex++; |
Lines 2146-2161
Link Here
|
2146 |
return results; |
2058 |
return results; |
2147 |
} |
2059 |
} |
2148 |
|
2060 |
|
2149 |
private String findMaxPrefix(String str1, String str2) { |
|
|
2150 |
String res = null; |
2151 |
|
2152 |
for (int i = 0; str1.regionMatches(true, 0, str2, 0, i); i++) { |
2153 |
res = str1.substring(0, i); |
2154 |
} |
2155 |
|
2156 |
return res; |
2157 |
} |
2158 |
|
2159 |
/** |
2061 |
/** |
2160 |
* Copied and adapted from JTree.getNextMatch(...). |
2062 |
* Copied and adapted from JTree.getNextMatch(...). |
2161 |
* |
2063 |
* |
Lines 2163-2169
Link Here
|
2163 |
* and the index of the first occurrence of the substring in TreePath. |
2065 |
* and the index of the first occurrence of the substring in TreePath. |
2164 |
*/ |
2066 |
*/ |
2165 |
private SubstringSearchResult getNextSubstringMatch( |
2067 |
private SubstringSearchResult getNextSubstringMatch( |
2166 |
String substring, int startingRow, Position.Bias bias) { |
2068 |
String substring, int startingRow, boolean forward) { |
2167 |
|
2069 |
|
2168 |
int max = getRowCount(); |
2070 |
int max = getRowCount(); |
2169 |
if (substring == null) { |
2071 |
if (substring == null) { |
Lines 2176-2182
Link Here
|
2176 |
|
2078 |
|
2177 |
// start search from the next/previous element froom the |
2079 |
// start search from the next/previous element froom the |
2178 |
// selected element |
2080 |
// selected element |
2179 |
int increment = (bias == Position.Bias.Forward) ? 1 : -1; |
2081 |
int increment = (forward) ? 1 : -1; |
2180 |
int row = startingRow; |
2082 |
int row = startingRow; |
2181 |
do { |
2083 |
do { |
2182 |
TreePath path = getPathForRow(row); |
2084 |
TreePath path = getPathForRow(row); |
Lines 2193-2198
Link Here
|
2193 |
return null; |
2095 |
return null; |
2194 |
} |
2096 |
} |
2195 |
|
2097 |
|
|
|
2098 |
private void displaySearchResult() { |
2099 |
int sz = searchResults.size(); |
2100 |
|
2101 |
if (sz > 0) { |
2102 |
if (currentSelectionIndex < 0) { |
2103 |
currentSelectionIndex = sz - 1; |
2104 |
} else if (currentSelectionIndex >= sz) { |
2105 |
currentSelectionIndex = 0; |
2106 |
} |
2107 |
|
2108 |
TreePath path = searchResults.get(currentSelectionIndex); |
2109 |
setSelectionPath(path); |
2110 |
scrollPathToVisible(path); |
2111 |
} else { |
2112 |
if (lastSearchText.isEmpty() && origSelectionPaths != null) { |
2113 |
setSelectionPaths(origSelectionPaths); |
2114 |
scrollPathToVisible(origSelectionPaths[0]); |
2115 |
} else { |
2116 |
clearSelection(); |
2117 |
} |
2118 |
} |
2119 |
} |
2120 |
|
2196 |
/** notify the Component to autoscroll */ |
2121 |
/** notify the Component to autoscroll */ |
2197 |
@Override |
2122 |
@Override |
2198 |
public void autoscroll(Point cursorLoc) { |
2123 |
public void autoscroll(Point cursorLoc) { |
Lines 2295-2425
Link Here
|
2295 |
} |
2220 |
} |
2296 |
} |
2221 |
} |
2297 |
|
2222 |
|
2298 |
private class SearchFieldListener extends KeyAdapter implements DocumentListener, FocusListener { |
|
|
2299 |
/** The last search results */ |
2300 |
private List<TreePath> results = new ArrayList<TreePath>(); |
2301 |
|
2302 |
/** The last selected index from the search results. */ |
2303 |
private int currentSelectionIndex; |
2304 |
|
2305 |
SearchFieldListener() { |
2306 |
} |
2307 |
|
2308 |
@Override |
2309 |
public void changedUpdate(DocumentEvent e) { |
2310 |
searchForNode(); |
2311 |
} |
2312 |
|
2313 |
@Override |
2314 |
public void insertUpdate(DocumentEvent e) { |
2315 |
searchForNode(); |
2316 |
} |
2317 |
|
2318 |
@Override |
2319 |
public void removeUpdate(DocumentEvent e) { |
2320 |
searchForNode(); |
2321 |
} |
2322 |
|
2323 |
@Override |
2324 |
public void keyPressed(KeyEvent e) { |
2325 |
int keyCode = e.getKeyCode(); |
2326 |
|
2327 |
if (keyCode == KeyEvent.VK_ESCAPE) { |
2328 |
removeSearchField(); |
2329 |
ExplorerTree.this.requestFocus(); |
2330 |
} else if (keyCode == KeyEvent.VK_UP || (keyCode == KeyEvent.VK_F3 && e.isShiftDown())) { |
2331 |
currentSelectionIndex--; |
2332 |
displaySearchResult(); |
2333 |
|
2334 |
// Stop processing the event here. Otherwise it's dispatched |
2335 |
// to the tree too (which scrolls) |
2336 |
e.consume(); |
2337 |
} else if (keyCode == KeyEvent.VK_DOWN || keyCode == KeyEvent.VK_F3) { |
2338 |
currentSelectionIndex++; |
2339 |
displaySearchResult(); |
2340 |
|
2341 |
// Stop processing the event here. Otherwise it's dispatched |
2342 |
// to the tree too (which scrolls) |
2343 |
e.consume(); |
2344 |
} else if (keyCode == KeyEvent.VK_TAB) { |
2345 |
if (maxPrefix != null) { |
2346 |
searchTextField.setText(maxPrefix); |
2347 |
} |
2348 |
|
2349 |
e.consume(); |
2350 |
} else if (keyCode == KeyEvent.VK_ENTER) { |
2351 |
removeSearchField(); |
2352 |
|
2353 |
// bugfix #39607, don't expand selected node when default action invoked |
2354 |
TreePath selectedTPath = getSelectionPath(); |
2355 |
|
2356 |
if (selectedTPath != null) { |
2357 |
TreeNode selectedTNode = (TreeNode) selectedTPath.getLastPathComponent(); |
2358 |
Node selectedNode = Visualizer.findNode(selectedTNode); |
2359 |
|
2360 |
if ( |
2361 |
(selectedNode.getPreferredAction() == null) || |
2362 |
!selectedNode.getPreferredAction().isEnabled() |
2363 |
) { |
2364 |
expandPath(getSelectionPath()); |
2365 |
} |
2366 |
} |
2367 |
|
2368 |
ExplorerTree.this.requestFocus(); |
2369 |
ExplorerTree.this.dispatchEvent(e); |
2370 |
} |
2371 |
} |
2372 |
|
2373 |
/** Searches for a node in the tree. */ |
2374 |
private void searchForNode() { |
2375 |
currentSelectionIndex = 0; |
2376 |
results.clear(); |
2377 |
maxPrefix = null; |
2378 |
|
2379 |
String text = searchTextField.getText().toUpperCase(); |
2380 |
|
2381 |
if (text.length() > 0) { |
2382 |
results = doSearch(text); |
2383 |
} |
2384 |
displaySearchResult(); |
2385 |
} |
2386 |
|
2387 |
private void displaySearchResult() { |
2388 |
int sz = results.size(); |
2389 |
|
2390 |
if (sz > 0) { |
2391 |
if (currentSelectionIndex < 0) { |
2392 |
currentSelectionIndex = sz - 1; |
2393 |
} else if (currentSelectionIndex >= sz) { |
2394 |
currentSelectionIndex = 0; |
2395 |
} |
2396 |
|
2397 |
TreePath path = results.get(currentSelectionIndex); |
2398 |
setSelectionPath(path); |
2399 |
scrollPathToVisible(path); |
2400 |
} else { |
2401 |
if (searchTextField.getText().length() == 0 && origSelectionPaths != null) { |
2402 |
setSelectionPaths(origSelectionPaths); |
2403 |
scrollPathToVisible(origSelectionPaths[0]); |
2404 |
} else { |
2405 |
clearSelection(); |
2406 |
} |
2407 |
} |
2408 |
} |
2409 |
|
2410 |
@Override |
2411 |
public void focusGained(FocusEvent e) { |
2412 |
// make sure nothing is selected |
2413 |
searchTextField.select(1, 1); |
2414 |
} |
2415 |
|
2416 |
@Override |
2417 |
public void focusLost(FocusEvent e) { |
2418 |
results.clear(); |
2419 |
removeSearchField(); |
2420 |
} |
2421 |
} |
2422 |
|
2423 |
private class AccessibleExplorerTree extends JTree.AccessibleJTree { |
2223 |
private class AccessibleExplorerTree extends JTree.AccessibleJTree { |
2424 |
AccessibleExplorerTree() { |
2224 |
AccessibleExplorerTree() { |
2425 |
} |
2225 |
} |