1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.xmlhammer.gui.output;
23
24 import java.awt.BorderLayout;
25 import java.awt.Toolkit;
26 import java.awt.datatransfer.Clipboard;
27 import java.awt.datatransfer.StringSelection;
28 import java.awt.event.ActionEvent;
29 import java.awt.event.KeyEvent;
30 import java.awt.event.MouseEvent;
31 import java.net.URI;
32
33 import javax.swing.AbstractAction;
34 import javax.swing.JFrame;
35 import javax.swing.JPopupMenu;
36 import javax.swing.JScrollPane;
37 import javax.swing.JTree;
38 import javax.swing.KeyStroke;
39 import javax.swing.ToolTipManager;
40 import javax.swing.border.EmptyBorder;
41 import javax.swing.event.TreeModelEvent;
42 import javax.swing.event.TreeModelListener;
43 import javax.swing.tree.DefaultMutableTreeNode;
44 import javax.swing.tree.TreePath;
45
46 import org.bounce.RunnableAction;
47 import org.bounce.MenuUtilities;
48 import org.bounce.event.DoubleClickListener;
49 import org.bounce.event.PopupListener;
50 import org.xmlhammer.gui.output.actions.CopyAction;
51 import org.xmlhammer.model.project.Output;
52
53 /***
54 * Shows the result tree.
55 *
56 * @version $Revision: 1.20 $, $Date: 2007/07/04 19:42:48 $
57 * @author Edwin Dankert <edankert@gmail.com>
58 */
59 public class ResultPanel extends SearchablePanel implements TreeModelListener {
60 private static final long serialVersionUID = 5439830288476866693L;
61
62 private boolean foundSelectedNode = false;
63 private JTree tree = null;
64 private JFrame parent = null;
65 private ResultTreeModel model = null;
66 private CopyAction copyAction = null;
67
68 public ResultPanel( JFrame parent) {
69 super( new BorderLayout());
70
71 this.parent = parent;
72
73 Output output = null;
74
75
76
77
78
79 model = new ResultTreeModel( output);
80
81 model.addTreeModelListener( this);
82
83 tree = new JTree( model);
84 tree.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_C, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false), "copy-selection");
85 tree.getActionMap().put("copy-selection", new CopyNodeAction());
86
87 tree.setRootVisible( false);
88 tree.setShowsRootHandles( true);
89 tree.expandPath( new TreePath( ((DefaultMutableTreeNode)model.getRoot()).getPath()));
90 tree.setCellRenderer( new ResultCellRenderer());
91 ToolTipManager.sharedInstance().registerComponent( tree);
92
93 JScrollPane scrollPane = new JScrollPane( tree,
94 JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
95 JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
96
97 this.setBorder( new EmptyBorder( 0, 0, 0, 0));
98 this.add( scrollPane, BorderLayout.CENTER);
99
100 tree.addMouseListener(new DoubleClickListener() {
101 public void doubleClicked(MouseEvent arg0) {
102 runDefaultAction();
103 }
104 });
105
106 tree.addMouseListener(new PopupListener() {
107 public void popupTriggered(MouseEvent event) {
108 showPopup(event);
109 }
110 });
111 }
112
113 public ResultTreeModel createModel(URI base) {
114 if (base != null && !base.isAbsolute()) {
115 throw new IllegalArgumentException("The URI \""+base+"\" has to be absolute.");
116 }
117 Output output = new Output();
118
119
120 model = new ResultTreeModel(output, base);
121
122 model.addTreeModelListener(this);
123
124 tree.setModel(model);
125
126 return model;
127 }
128
129 public ResultNode getSelectedNode() {
130 TreePath path = tree.getSelectionPath();
131
132 if (path != null) {
133 Object object = path.getLastPathComponent();
134
135 if (object instanceof ResultNode) {
136 return (ResultNode)object;
137 }
138 }
139
140 return null;
141 }
142
143 public void setSelectedNode(ResultNode node) {
144 TreePath path = new TreePath(node.getPath());
145
146 tree.setSelectionPath(path);
147 tree.expandPath(path);
148 tree.scrollPathToVisible(path);
149 }
150
151 public ResultTreeModel getModel() {
152 return model;
153 }
154
155 private void runDefaultAction() {
156 TreePath path = tree.getSelectionPath();
157 if (path != null) {
158 Object object = path.getLastPathComponent();
159
160 if ( object instanceof ResultNode && ((ResultNode)object).getChildCount() == 0) {
161 RunnableAction action = ((ResultNode)object).getDefaultAction(parent);
162 action.run();
163 }
164 }
165 }
166
167 private void showPopup(MouseEvent event) {
168 JPopupMenu popup = null;
169
170 if (tree.getSelectionCount() == 1) {
171 TreePath path = tree.getSelectionPath();
172 Object object = path.getLastPathComponent();
173
174 if (object instanceof ResultNode) {
175 popup = ((ResultNode)object).getPopupMenu(parent);
176 }
177 } else if (tree.getSelectionCount() > 1) {
178 CopyAction action = getCopyAction();
179 action.setText(getCopyValue());
180
181 popup = new JPopupMenu();
182 popup.add(action);
183 MenuUtilities.alignMenu(popup);
184 }
185
186 if (popup != null) {
187 popup.show(tree, event.getX(), event.getY());
188 }
189 }
190
191 private String getCopyValue() {
192 TreePath[] paths = tree.getSelectionPaths();
193 StringBuilder builder = new StringBuilder();
194
195 int baseLevel = 1024;
196 for (TreePath path : paths) {
197 baseLevel = Math.min(path.getPathCount(), baseLevel);
198 }
199
200 for (TreePath path : paths) {
201 Object object = path.getLastPathComponent();
202
203 if (object instanceof ResultNode) {
204 int level = path.getPathCount() - baseLevel;
205
206 for (int i = 0; i < level; i++) {
207 builder.append("\t");
208 }
209
210 builder.append(((ResultNode)object).getCopyValue());
211
212 if (path != paths[paths.length-1]) {
213 builder.append(System.getProperty("line.separator"));
214 }
215 }
216 }
217
218 return builder.toString();
219 }
220
221 protected CopyAction getCopyAction() {
222 if (copyAction == null) {
223 copyAction = new CopyAction();
224 }
225
226 return copyAction;
227 }
228
229 public void treeNodesInserted( TreeModelEvent e) {
230 Object[] children = e.getChildren();
231
232 if ( children.length > 0) {
233 if ( children[0] instanceof DirectoryNode) {
234
235 } else if ( children[0] instanceof URINode) {
236 tree.expandPath( e.getTreePath());
237 } else {
238 Object[] path = e.getPath();
239
240 tree.scrollPathToVisible( e.getTreePath());
241 model.nodeChanged( (URINode)path[ path.length-1]);
242 }
243 }
244 }
245
246 public void copySelectedNodes() {
247 Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
248 clipboard.setContents(new StringSelection(getCopyValue()), null);
249 }
250
251 public void treeNodesChanged( TreeModelEvent e) {}
252 public void treeNodesRemoved( TreeModelEvent e) {}
253 public void treeStructureChanged( TreeModelEvent e) {}
254
255 public class CopyNodeAction extends AbstractAction {
256 private static final long serialVersionUID = 2045980274706285174L;
257
258 public void actionPerformed( ActionEvent event) {
259 copySelectedNodes();
260 }
261 }
262
263 @Override
264 public boolean search(String search, boolean matchCase, boolean forward) {
265 foundSelectedNode = false;
266
267 ResultTreeModel model = getModel();
268 ResultNode selected = getSelectedNode();
269 RootNode root = (RootNode)model.getRoot();
270
271 if (selected == null) {
272 selected = root;
273 }
274
275 ResultNode node = find(selected, root, search, forward, matchCase);
276
277 if (node == null) {
278 if (forward) {
279 selected = root;
280 } else {
281 selected = getLastNode(root);
282 }
283
284 node = find(selected, root, search, forward, matchCase);
285 }
286
287 if (node != null) {
288 setSelectedNode(node);
289 return true;
290 }
291
292 return false;
293 }
294
295 private ResultNode getLastNode(ResultNode node) {
296 if (node.getChildCount() > 0) {
297 return getLastNode((ResultNode)node.getChildAt(node.getChildCount()-1));
298 }
299
300 return node;
301 }
302
303 private ResultNode find(ResultNode start, ResultNode node, String search, boolean forward, boolean matchCase) {
304 if (foundSelectedNode && matches(node.getValue(), search, matchCase) && forward) {
305 return node;
306 }
307
308 if (node == start && forward) {
309 foundSelectedNode = true;
310 }
311
312 if (forward) {
313 for (int i = 0; i < node.getChildCount(); i++) {
314 ResultNode result = find(start, (ResultNode)node.getChildAt(i), search, forward, matchCase);
315 if (result != null) {
316 return result;
317 }
318 }
319 } else {
320 for (int i = node.getChildCount()-1; i >= 0; i--) {
321 ResultNode result = find(start, (ResultNode)node.getChildAt(i), search, forward, matchCase);
322 if (result != null) {
323 return result;
324 }
325 }
326 }
327
328 if (foundSelectedNode && matches(node.getValue(), search, matchCase) && !forward) {
329 return node;
330 }
331
332 if (node == start && !forward) {
333 foundSelectedNode = true;
334 }
335
336 return null;
337 }
338
339 public boolean matches(String value, String search, boolean matchCase) {
340 if (matchCase) {
341 return value.indexOf(search) != -1;
342 }
343
344 return value.toLowerCase().indexOf(search.toLowerCase()) != -1;
345 }
346 }