1   
28  package demo.view.graphexplorer;
29  
30  import y.view.Graph2D;
31  import y.view.hierarchy.DefaultNodeChangePropagator;
32  import y.view.hierarchy.HierarchyJTree;
33  import y.view.hierarchy.HierarchyManager;
34  import y.view.hierarchy.HierarchyTreeModel;
35  import y.view.hierarchy.HierarchyTreeTransferHandler;
36  
37  import java.awt.BorderLayout;
38  import java.awt.Color;
39  import java.awt.Dimension;
40  import java.awt.event.KeyAdapter;
41  import java.awt.event.KeyEvent;
42  import javax.swing.JLabel;
43  import javax.swing.JPanel;
44  import javax.swing.JScrollPane;
45  import javax.swing.JTextField;
46  import javax.swing.JTree;
47  import javax.swing.border.EmptyBorder;
48  import javax.swing.event.DocumentEvent;
49  import javax.swing.event.DocumentListener;
50  import javax.swing.tree.TreeModel;
51  import javax.swing.tree.TreePath;
52  
53  
56  class SearchableTreeViewPanel extends JPanel {
57    private JTree jTree;
58    private TreePath lastMatch;
59  
60    SearchableTreeViewPanel( final Graph2D model ) {
61      setLayout(new BorderLayout());
62      jTree = configureHierarchyJTree(model);
63      jTree.setExpandsSelectedPaths(true);
64      jTree.setDragEnabled(false);
65  
66      final JScrollPane scrollPane = new JScrollPane(jTree);
67      scrollPane.setPreferredSize(new Dimension(200, 0));
68      scrollPane.setMinimumSize(new Dimension(200, 0));
69      add(addSearchPanel(jTree), BorderLayout.NORTH);
70      add(scrollPane, BorderLayout.CENTER);
71    }
72  
73    JTree getTree() {
74      return jTree;
75    }
76  
77    private JPanel addSearchPanel(final JTree currentTree) {
78      final JPanel searchPanel = new JPanel(new BorderLayout(5, 5));
79      searchPanel.setBorder(new EmptyBorder(2, 5, 2, 2));
80      searchPanel.add(new JLabel("Search"), BorderLayout.WEST);
81      final JTextField searchField = new JTextField();
82  
83          searchField.getDocument().addDocumentListener(new DocumentListener() {
85        public void insertUpdate(DocumentEvent e) {
86          updateSelection(searchField, currentTree);
87        }
88  
89        public void removeUpdate(DocumentEvent e) {
90          updateSelection(searchField, currentTree);
91        }
92  
93        public void changedUpdate(DocumentEvent e) {
94          updateSelection(searchField, currentTree);
95        }
96      });
97  
98              searchField.addKeyListener(new KeyAdapter() {
101       public void keyPressed(KeyEvent e) {
102         int keyCode = e.getKeyCode();
103         if (keyCode == KeyEvent.VK_ESCAPE) {
104                     clearSearchField(searchField);
106 
107                               e.consume();
110         } else if (keyCode == KeyEvent.VK_ENTER) {
111                     String searchString = searchField.getText();
113           if (currentTree != null && currentTree.getModel() != null && searchString != null && searchString.length() > 0) {
114             TreePath match = findNextMatch(searchString, new TreePath(currentTree.getModel().getRoot()), currentTree);
115             if (match != null) {
116               selectMatch(match, currentTree);
117             } else {
118               lastMatch = null;
119               TreePath wrappedMatch = findNextMatch(searchString, new TreePath(currentTree.getModel().getRoot()),
120                   currentTree);
121               if (wrappedMatch != null) {
122                 selectMatch(wrappedMatch, currentTree);
123               } else {
124                 noMatchExists(searchField);
125               }
126             }
127           }
128         }
129       }
130     });
131     searchPanel.add(searchField, BorderLayout.CENTER);
132     return searchPanel;
133   }
134 
135   private void selectMatch(final TreePath match, final JTree actualTree) {
136     actualTree.setSelectionPath(match);
137     actualTree.scrollPathToVisible(match);
138     lastMatch = match;
139   }
140 
141   private void clearSearchField(final JTextField searchField) {
142     searchField.setText("");
143     searchField.setBackground(Color.WHITE);
144     searchField.setForeground(Color.BLACK);
145     lastMatch = null;
146   }
147 
148   private void noMatchExists(final JTextField searchField) {
149     searchField.setBackground(Color.RED);
150     searchField.setForeground(Color.WHITE);
151     lastMatch = null;
152   }
153 
154   private void updateSelection(final JTextField searchField, final JTree actualTree) {
155     searchField.setBackground(Color.WHITE);
156     searchField.setForeground(Color.BLACK);
157     lastMatch = null;
158     if (actualTree != null && actualTree.getModel() != null) {
159       actualTree.clearSelection();
160       String searchString = searchField.getText();
161       if (searchString != null && searchString.length() > 0) {
162         TreePath match = findNextMatch(searchString, new TreePath(actualTree.getModel().getRoot()), actualTree);
163         if (match != null) {
164           selectMatch(match, actualTree);
165         } else {
166           noMatchExists(searchField);
167         }
168       }
169     }
170   }
171 
172     private TreePath findNextMatch(String searchString, TreePath parent, final JTree actualTree) {
174     TreeModel model = actualTree.getModel();
175     Object treeRoot = parent.getLastPathComponent();
176     for (int i = 0; i < model.getChildCount(treeRoot); i++) {
177       Object treeNode = model.getChild(treeRoot, i);
178       TreePath path = parent.pathByAddingChild(treeNode);
179       if (isMatch(treeNode, searchString)) {
180         if (lastMatch != null) {
181           if (path.equals(lastMatch)) {
182             lastMatch = null;
183           }
184         } else {
185           return path;
186         }
187       }
188       TreePath match = findNextMatch(searchString, path, actualTree);
189       if (match != null) {
190         return match;
191       }
192     }
193     return null;
194   }
195 
196   private boolean isMatch(Object treeNode, String searchString) {
197             String text = treeNode.toString().toUpperCase();
200     return text.startsWith(searchString.toUpperCase());
201   }
202 
203   private JTree configureHierarchyJTree(Graph2D model) {
204         model.addGraph2DListener(new DefaultNodeChangePropagator());
206 
207         HierarchyManager hierarchy = model.getHierarchyManager();
209     HierarchyTreeModel treeModel = new HierarchyTreeModel(hierarchy);
210 
211             treeModel.setChildComparator(HierarchyTreeModel.createNodeStateComparator(hierarchy));
214 
215         final JTree tree = new HierarchyJTree(hierarchy, treeModel);
217     tree.setEditable(false);
218 
219             tree.setDragEnabled(true);
222     tree.setTransferHandler(new HierarchyTreeTransferHandler(hierarchy));
223     return tree;
224   }
225 }
226