1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.log4j.chainsaw;
20
21 import java.awt.BorderLayout;
22 import java.awt.Component;
23 import java.awt.Cursor;
24 import java.awt.FlowLayout;
25 import java.awt.Font;
26 import java.awt.Point;
27 import java.awt.Toolkit;
28 import java.awt.event.ActionEvent;
29 import java.awt.event.InputEvent;
30 import java.awt.event.MouseAdapter;
31 import java.awt.event.MouseEvent;
32 import java.awt.event.MouseMotionAdapter;
33 import java.awt.event.MouseMotionListener;
34 import java.beans.PropertyChangeEvent;
35 import java.beans.PropertyChangeListener;
36 import java.util.ArrayList;
37 import java.util.Collection;
38 import java.util.Collections;
39 import java.util.Enumeration;
40 import java.util.HashSet;
41 import java.util.Iterator;
42 import java.util.List;
43 import java.util.Set;
44
45 import javax.swing.AbstractAction;
46 import javax.swing.Action;
47 import javax.swing.BorderFactory;
48 import javax.swing.Box;
49 import javax.swing.BoxLayout;
50 import javax.swing.DefaultListModel;
51 import javax.swing.ImageIcon;
52 import javax.swing.JButton;
53 import javax.swing.JCheckBoxMenuItem;
54 import javax.swing.JDialog;
55 import javax.swing.JLabel;
56 import javax.swing.JList;
57 import javax.swing.JPanel;
58 import javax.swing.JPopupMenu;
59 import javax.swing.JScrollPane;
60 import javax.swing.JToolBar;
61 import javax.swing.JTree;
62 import javax.swing.SwingUtilities;
63 import javax.swing.ToolTipManager;
64 import javax.swing.event.ChangeEvent;
65 import javax.swing.event.ChangeListener;
66 import javax.swing.event.EventListenerList;
67 import javax.swing.event.TreeModelEvent;
68 import javax.swing.event.TreeModelListener;
69 import javax.swing.event.TreeSelectionEvent;
70 import javax.swing.event.TreeSelectionListener;
71 import javax.swing.tree.DefaultMutableTreeNode;
72 import javax.swing.tree.DefaultTreeCellRenderer;
73 import javax.swing.tree.DefaultTreeSelectionModel;
74 import javax.swing.tree.TreeNode;
75 import javax.swing.tree.TreePath;
76 import javax.swing.tree.TreeSelectionModel;
77
78 import org.apache.log4j.LogManager;
79 import org.apache.log4j.Logger;
80 import org.apache.log4j.chainsaw.icons.ChainsawIcons;
81 import org.apache.log4j.chainsaw.icons.LineIconFactory;
82 import org.apache.log4j.rule.AbstractRule;
83 import org.apache.log4j.rule.Rule;
84 import org.apache.log4j.spi.LoggingEvent;
85
86
87 /***
88 * A panel that encapsulates the Logger Name tree, with associated actions
89 * and implements the Rule interface so that it can filter in/out events
90 * that do not match the users request for refining the view based on Loggers.
91 *
92 * @author Paul Smith <psmith@apache.org>
93 */
94 final class LoggerNameTreePanel extends JPanel implements Rule
95 {
96
97
98 private static final int WARN_DEPTH = 4;
99
100
101
102 private LoggerNameTreeCellRenderer cellRenderer =
103 new LoggerNameTreeCellRenderer();
104 private final Action clearIgnoreListAction;
105 private final Action closeAction;
106 private final JButton closeButton = new SmallButton();
107 private final Action collapseAction;
108 private final JButton collapseButton = new SmallButton();
109 private final Action editLoggerAction;
110 private final JButton editLoggerButton = new SmallButton();
111 private final Action expandAction;
112 private final JButton expandButton = new SmallButton();
113 private final Action focusOnAction;
114 private final SmallToggleButton focusOnLoggerButton =
115 new SmallToggleButton();
116 private final Set hiddenSet = new HashSet();
117 private final Action hideAction;
118 private final LogPanelPreferenceModel preferenceModel;
119
120 private final JList ignoreList = new JList();
121 private final JScrollPane ignoreListScroll = new JScrollPane(ignoreList);
122 private final JDialog ignoreDialog = new JDialog();
123 private final JLabel ignoreSummary = new JLabel("0 hidden loggers");
124 private final SmallToggleButton ignoreLoggerButton = new SmallToggleButton();
125 private final EventListenerList listenerList = new EventListenerList();
126 private final JTree logTree;
127 private final Logger logger = LogManager.getLogger(LoggerNameTreePanel.class);
128
129
130
131 private final LogPanelLoggerTreeModel logTreeModel;
132 private final PopupListener popupListener;
133 private final LoggerTreePopupMenu popupMenu;
134 private final Rule ruleDelegate;
135 private Rule colorRuleDelegate;
136 private final JScrollPane scrollTree;
137 private final JToolBar toolbar = new JToolBar();
138
139
140
141 /***
142 * Creates a new LoggerNameTreePanel object.
143 *
144 * @param logTreeModel
145 */
146 LoggerNameTreePanel(LogPanelLoggerTreeModel logTreeModel, LogPanelPreferenceModel preferenceModel)
147 {
148 super();
149 this.logTreeModel = logTreeModel;
150 this.preferenceModel = preferenceModel;
151
152 setLayout(new BorderLayout());
153
154 ruleDelegate = new AbstractRule() {
155 public boolean evaluate(LoggingEvent e)
156 {
157 String currentlySelectedLoggerName = getCurrentlySelectedLoggerName();
158 if (currentlySelectedLoggerName == null) {
159
160 return true;
161 }
162 boolean isHidden = getHiddenSet().contains(e.getLoggerName());
163 boolean result = (e.getLoggerName() != null) && (!isHidden);
164
165 if (result && isFocusOnSelected())
166 {
167 result = result && (e.getLoggerName() != null && (e.getLoggerName().startsWith(currentlySelectedLoggerName+".") || e.getLoggerName().endsWith(currentlySelectedLoggerName))) ;
168 }
169
170 return result;
171 }
172 };
173
174 colorRuleDelegate =
175 new AbstractRule()
176 {
177 public boolean evaluate(LoggingEvent e)
178 {
179 boolean isHidden = getHiddenSet().contains(e.getLoggerName());
180 String currentlySelectedLoggerName = getCurrentlySelectedLoggerName();
181
182 if (!isFocusOnSelected() && !isHidden && currentlySelectedLoggerName != null && !"".equals(currentlySelectedLoggerName))
183 {
184 return (e.getLoggerName().startsWith(currentlySelectedLoggerName+".") || e.getLoggerName().endsWith(currentlySelectedLoggerName)) ;
185 }
186 return false;
187 }
188 };
189
190 logTree =
191 new JTree(logTreeModel)
192 {
193 public String getToolTipText(MouseEvent ev)
194 {
195 if (ev == null)
196 {
197 return null;
198 }
199
200 TreePath path = logTree.getPathForLocation(ev.getX(), ev.getY());
201
202 String loggerName = getLoggerName(path);
203
204 if (hiddenSet.contains(loggerName))
205 {
206 loggerName += " (you are ignoring this logger)";
207 }
208
209 return loggerName;
210 }
211 };
212
213 ToolTipManager.sharedInstance().registerComponent(logTree);
214 logTree.setCellRenderer(cellRenderer);
215
216
217 logTreeModel.addTreeModelListener(new TreeModelListener()
218 {
219 private boolean latched = false;
220
221 public void treeNodesChanged(TreeModelEvent e)
222 {
223 }
224
225 public void treeNodesInserted(TreeModelEvent e)
226 {
227 if (!latched)
228 {
229 ensureRootExpanded();
230 latched = true;
231 }
232 }
233
234 public void treeNodesRemoved(TreeModelEvent e)
235 {
236 }
237
238 public void treeStructureChanged(TreeModelEvent e)
239 {
240 }
241 });
242
243 logTree.setEditable(false);
244
245
246 TreeSelectionModel selectionModel = new DefaultTreeSelectionModel();
247 selectionModel.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
248 logTree.setSelectionModel(selectionModel);
249
250 logTree.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
251 scrollTree = new JScrollPane(logTree);
252 toolbar.setLayout(new BoxLayout(toolbar, BoxLayout.X_AXIS));
253
254 expandAction = createExpandAction();
255 editLoggerAction = createEditLoggerAction();
256 closeAction = createCloseAction();
257 collapseAction = createCollapseAction();
258 focusOnAction = createFocusOnAction();
259 hideAction = createIgnoreAction();
260 clearIgnoreListAction = createClearIgnoreListAction();
261
262 popupMenu = new LoggerTreePopupMenu();
263 popupListener = new PopupListener(popupMenu);
264
265 setupListeners();
266 configureToolbarPanel();
267
268 add(toolbar, BorderLayout.NORTH);
269 add(scrollTree, BorderLayout.CENTER);
270
271 ignoreDialog.setTitle("Hidden/Ignored Loggers");
272 ignoreDialog.setModal(true);
273 JPanel ignoreSummaryPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
274 ignoreSummaryPanel.add(ignoreSummary);
275
276 Action showIgnoreDialogAction = new AbstractAction("...") {
277
278 public void actionPerformed(ActionEvent e)
279 {
280 ignoreDialog.setVisible(true);
281 }};
282 showIgnoreDialogAction.putValue(Action.SHORT_DESCRIPTION, "Click to view and manage your hidden/ignored loggers");
283 JButton btnShowIgnoreDialog = new SmallButton(showIgnoreDialogAction);
284
285 ignoreSummaryPanel.add(btnShowIgnoreDialog);
286 add(ignoreSummaryPanel, BorderLayout.SOUTH);
287
288 ignoreList.setModel(new DefaultListModel());
289 ignoreList.addMouseListener(new MouseAdapter()
290 {
291 public void mouseClicked(MouseEvent e)
292 {
293 if (
294 (e.getClickCount() > 1)
295 && ((e.getModifiers() & InputEvent.BUTTON1_MASK) > 0))
296 {
297 int index = ignoreList.locationToIndex(e.getPoint());
298
299 if (index >= 0)
300 {
301 String string =
302 ignoreList.getModel().getElementAt(index).toString();
303 toggleHiddenLogger(string);
304 fireChangeEvent();
305
306 /***
307 * TODO this needs to get the node that has this logger and fire a visual update
308 */
309 LoggerNameTreePanel.this.logTreeModel.nodeStructureChanged(
310 (TreeNode) LoggerNameTreePanel.this.logTreeModel.getRoot());
311 }
312 }
313 }
314 });
315
316 JPanel ignoreListPanel = new JPanel(new BorderLayout());
317 ignoreListScroll.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(),"Double click an entry to unhide it"));
318 ignoreListPanel.add(ignoreListScroll, BorderLayout.CENTER);
319
320 Box ignoreListButtonPanel = Box.createHorizontalBox();
321
322 JButton unhideAll = new JButton(new AbstractAction("Unhide All") {
323
324 public void actionPerformed(final ActionEvent e)
325 {
326 SwingUtilities.invokeLater(new Runnable() {
327
328 public void run()
329 {
330 clearIgnoreListAction.actionPerformed(e);
331 }});
332
333 }});
334 ignoreListButtonPanel.add(unhideAll);
335
336 ignoreListButtonPanel.add(Box.createHorizontalGlue());
337 JButton ignoreCloseButton = new JButton(new AbstractAction("Close") {
338
339 public void actionPerformed(ActionEvent e)
340 {
341 ignoreDialog.setVisible(false);
342
343 }});
344 ignoreListButtonPanel.add(ignoreCloseButton);
345
346
347 ignoreListPanel.add(ignoreListButtonPanel, BorderLayout.SOUTH);
348
349
350 ignoreDialog.getContentPane().add(ignoreListPanel);
351 ignoreDialog.pack();
352 }
353
354
355
356 /***
357 * Adds a change Listener to this LoggerNameTreePanel to be notfied
358 * when the State of the Focus or Hidden details have changed.
359 *
360 * @param l
361 */
362 public void addChangeListener(ChangeListener l)
363 {
364 listenerList.add(ChangeListener.class, l);
365 }
366
367
368
369
370 /***
371 * DOCUMENT ME!
372 *
373 * @param e DOCUMENT ME!
374 *
375 * @return DOCUMENT ME!
376 */
377 public boolean evaluate(LoggingEvent e)
378 {
379 return ruleDelegate.evaluate(e);
380 }
381
382 public Rule getLoggerColorRule() {
383 return colorRuleDelegate;
384 }
385
386 /***
387 * DOCUMENT ME!
388 *
389 * @param l DOCUMENT ME!
390 */
391 public void removeChangeListener(ChangeListener l)
392 {
393 listenerList.remove(ChangeListener.class, l);
394 }
395
396 /***
397 * Ensures the Focus is set to a specific logger name
398 * @param logger
399 */
400 public void setFocusOn(String newLogger)
401 {
402 DefaultMutableTreeNode node = logTreeModel.lookupLogger(newLogger);
403
404 if (node != null)
405 {
406 TreeNode[] nodes = node.getPath();
407 TreePath treePath = new TreePath(nodes);
408 logTree.setSelectionPath(treePath);
409
410 if (!focusOnLoggerButton.isSelected())
411 {
412 focusOnLoggerButton.doClick();
413 }
414 }
415 else
416 {
417 logger.error("failed to lookup logger " + newLogger);
418 }
419 }
420
421 /***
422 * DOCUMENT ME!
423 *
424 * @param logger
425 */
426 protected void toggleHiddenLogger(String logger)
427 {
428 if (!hiddenSet.contains(logger))
429 {
430 hiddenSet.add(logger);
431 }
432 else
433 {
434 hiddenSet.remove(logger);
435 }
436
437 firePropertyChange("hiddenSet", (Object) null, (Object) null);
438 }
439
440 /***
441 * Returns the full name of the Logger that is represented by
442 * the currently selected Logger node in the tree.
443 *
444 * This is the dotted name, of the current node including all it's parents.
445 *
446 * If multiple Nodes are selected, the first path is used
447 * @return Logger Name or null if nothing selected
448 */
449 String getCurrentlySelectedLoggerName()
450 {
451 TreePath[] paths = logTree.getSelectionPaths();
452
453 if ((paths == null) || (paths.length == 0))
454 {
455 return null;
456 }
457
458 TreePath firstPath = paths[0];
459
460 return getLoggerName(firstPath);
461 }
462
463 /***
464 * Returns an unmodifiable set of those Loggers marked as hidden.
465 * @return
466 */
467 Set getHiddenSet()
468 {
469 return Collections.unmodifiableSet(hiddenSet);
470 }
471
472 /***
473 * Returns the full
474 * @param path DOCUMENT ME!
475 * @return
476 */
477 String getLoggerName(TreePath path)
478 {
479 if (path != null)
480 {
481 Object[] objects = path.getPath();
482 StringBuffer buf = new StringBuffer();
483
484 for (int i = 1; i < objects.length; i++)
485 {
486 buf.append(objects[i].toString());
487
488 if (i < (objects.length - 1))
489 {
490 buf.append(".");
491 }
492 }
493
494 return buf.toString();
495 }
496
497 return null;
498 }
499
500 /***
501 * adds a Collection of Strings to the ignore List and notifise all listeners of
502 * both the "hiddenSet" property and those expecting the Rule to change
503 * via the ChangeListener interface
504 * @param fqnLoggersToIgnore
505 */
506 void ignore(Collection fqnLoggersToIgnore)
507 {
508 hiddenSet.addAll(fqnLoggersToIgnore);
509 firePropertyChange("hiddenSet", null, null);
510 fireChangeEvent();
511 }
512
513 /***
514 * Returns true if the FocusOn element has been selected
515 * @return true if the FocusOn action/lement has been selected
516 */
517 boolean isFocusOnSelected()
518 {
519 return focusOnAction.getValue("checked") != null;
520 }
521
522 void setFocusOnSelected(boolean selected)
523 {
524 if (selected)
525 {
526 focusOnAction.putValue("checked", Boolean.TRUE);
527 }
528 else
529 {
530 focusOnAction.putValue("checked", null);
531 }
532 }
533
534 /***
535 * Given the currently selected nodes
536 * collapses all the children of those nodes.
537 *
538 */
539 private void collapseCurrentlySelectedNode()
540 {
541 TreePath[] paths = logTree.getSelectionPaths();
542
543 if (paths == null)
544 {
545 return;
546 }
547
548 logger.debug("Collapsing all children of selected node");
549
550 for (int i = 0; i < paths.length; i++)
551 {
552 TreePath path = paths[i];
553 DefaultMutableTreeNode node =
554 (DefaultMutableTreeNode) path.getLastPathComponent();
555 Enumeration enumeration = node.depthFirstEnumeration();
556
557 while (enumeration.hasMoreElements())
558 {
559 DefaultMutableTreeNode child =
560 (DefaultMutableTreeNode) enumeration.nextElement();
561
562 if ((child.getParent() != null) && (child != node))
563 {
564 TreeNode[] nodes =
565 ((DefaultMutableTreeNode) child.getParent()).getPath();
566
567 TreePath treePath = new TreePath(nodes);
568 logTree.collapsePath(treePath);
569 }
570 }
571 }
572
573 ensureRootExpanded();
574 }
575
576 /***
577 * configures all the components that are used in the mini-toolbar of this
578 * component
579 */
580 private void configureToolbarPanel()
581 {
582 toolbar.setFloatable(false);
583
584 expandButton.setAction(expandAction);
585 expandButton.setText(null);
586 collapseButton.setAction(collapseAction);
587 collapseButton.setText(null);
588 focusOnLoggerButton.setAction(focusOnAction);
589 focusOnLoggerButton.setText(null);
590 ignoreLoggerButton.setAction(hideAction);
591 ignoreLoggerButton.setText(null);
592
593 expandButton.setFont(expandButton.getFont().deriveFont(Font.BOLD));
594 collapseButton.setFont(collapseButton.getFont().deriveFont(Font.BOLD));
595
596 editLoggerButton.setAction(editLoggerAction);
597 editLoggerButton.setText(null);
598 closeButton.setAction(closeAction);
599 closeButton.setText(null);
600
601 toolbar.add(expandButton);
602 toolbar.add(collapseButton);
603 toolbar.addSeparator();
604 toolbar.add(focusOnLoggerButton);
605 toolbar.add(ignoreLoggerButton);
606
607
608 toolbar.addSeparator();
609
610 toolbar.add(Box.createHorizontalGlue());
611 toolbar.add(closeButton);
612 toolbar.add(Box.createHorizontalStrut(5));
613 }
614
615 /***
616 * DOCUMENT ME!
617 *
618 * @return
619 */
620 private Action createClearIgnoreListAction()
621 {
622 Action action = new AbstractAction("Clear Ignore list", null)
623 {
624 public void actionPerformed(ActionEvent e)
625 {
626 ignoreLoggerButton.setSelected(false);
627 logTreeModel.reload();
628 hiddenSet.clear();
629 fireChangeEvent();
630 }
631 };
632
633 action.putValue(
634 Action.SHORT_DESCRIPTION,
635 "Removes all entries from the Ignore list so you can see their events in the view");
636
637 return action;
638 }
639
640 /***
641 * An action that closes (hides) this panel
642 * @return
643 */
644 private Action createCloseAction()
645 {
646 Action action = new AbstractAction()
647 {
648 public void actionPerformed(ActionEvent e)
649 {
650 preferenceModel.setLogTreePanelVisible(false);
651 }
652 };
653
654 action.putValue(Action.NAME, "Close");
655 action.putValue(Action.SHORT_DESCRIPTION, "Closes the Logger panel");
656 action.putValue(Action.SMALL_ICON, LineIconFactory.createCloseIcon());
657
658 return action;
659 }
660
661 /***
662 * DOCUMENT ME!
663 *
664 * @return
665 */
666 private Action createCollapseAction()
667 {
668 Action action = new AbstractAction()
669 {
670 public void actionPerformed(ActionEvent e)
671 {
672 collapseCurrentlySelectedNode();
673 }
674 };
675
676 action.putValue(Action.SMALL_ICON, LineIconFactory.createCollapseIcon());
677 action.putValue(Action.NAME, "Collapse Branch");
678 action.putValue(
679 Action.SHORT_DESCRIPTION,
680 "Collapses all the children of the currently selected node");
681 action.setEnabled(false);
682
683 return action;
684 }
685
686 private Action createEditLoggerAction()
687 {
688 Action action = new AbstractAction()
689 {
690 public void actionPerformed(ActionEvent e)
691 {
692
693 }
694 };
695
696
697 action.putValue("enabled", Boolean.FALSE);
698
699 action.putValue(Action.NAME, "Edit filters/colors");
700 action.putValue(
701 Action.SHORT_DESCRIPTION,
702 "Allows you to specify filters and coloring for this Logger");
703 action.putValue(
704 Action.SMALL_ICON, new ImageIcon(ChainsawIcons.ICON_EDIT_RECEIVER));
705 action.setEnabled(false);
706
707 return action;
708 }
709
710 /***
711 * Creates an action that is used to expand the selected node
712 * and all children
713 * @return an Action
714 */
715 private Action createExpandAction()
716 {
717 Action action = new AbstractAction()
718 {
719 public void actionPerformed(ActionEvent e)
720 {
721 expandCurrentlySelectedNode();
722 }
723 };
724
725 action.putValue(Action.SMALL_ICON, LineIconFactory.createExpandIcon());
726 action.putValue(Action.NAME, "Expand branch");
727 action.putValue(
728 Action.SHORT_DESCRIPTION,
729 "Expands all the child nodes of the currently selected node, recursively");
730 action.setEnabled(false);
731
732 return action;
733 }
734
735 /***
736 * DOCUMENT ME!
737 *
738 * @return
739 */
740 private Action createFocusOnAction()
741 {
742 final Action action = new AbstractAction()
743 {
744 public void actionPerformed(ActionEvent e)
745 {
746 toggleFocusOnState();
747 }
748 };
749
750 action.putValue(Action.NAME, "Focus");
751 action.putValue(
752 Action.SHORT_DESCRIPTION,
753 "Allows you to Focus on the selected logger by setting a filter that discards all but this Logger");
754 action.putValue(
755 Action.SMALL_ICON, new ImageIcon(ChainsawIcons.WINDOW_ICON));
756
757 action.setEnabled(false);
758
759 return action;
760 }
761
762 /***
763 * DOCUMENT ME!
764 *
765 * @return
766 */
767 private Action createIgnoreAction()
768 {
769 Action action =
770 new AbstractAction(
771 "Ignore this Logger", new ImageIcon(ChainsawIcons.ICON_COLLAPSE))
772 {
773 public void actionPerformed(ActionEvent e)
774 {
775 String logger = getCurrentlySelectedLoggerName();
776
777 if (logger != null)
778 {
779 toggleHiddenLogger(logger);
780 logTreeModel.nodeChanged(
781 (TreeNode) logTree.getSelectionPath().getLastPathComponent());
782 ignoreLoggerButton.setSelected(hiddenSet.contains(logger));
783 focusOnAction.setEnabled(!hiddenSet.contains(logger));
784 popupMenu.hideCheck.setSelected(hiddenSet.contains(logger));
785 }
786
787 fireChangeEvent();
788 }
789 };
790
791 action.putValue(
792 Action.SHORT_DESCRIPTION,
793 "Adds the selected Logger to your Ignore list, filtering those events from view");
794
795 return action;
796 }
797
798 private void ensureRootExpanded()
799 {
800 logger.debug("Ensuring Root node is expanded.");
801
802 final DefaultMutableTreeNode root =
803 (DefaultMutableTreeNode) logTreeModel.getRoot();
804 SwingUtilities.invokeLater(new Runnable()
805 {
806 public void run()
807 {
808 logTree.expandPath(new TreePath(root));
809 }
810 });
811 }
812
813 /***
814 * Expands the currently selected node (if any)
815 * including all the children.
816 *
817 */
818 private void expandCurrentlySelectedNode()
819 {
820 TreePath[] paths = logTree.getSelectionPaths();
821
822 if (paths == null)
823 {
824 return;
825 }
826
827 logger.debug("Expanding all children of selected node");
828
829 for (int i = 0; i < paths.length; i++)
830 {
831 TreePath path = paths[i];
832
833 /***
834 * TODO this is commented out, right now it expands all nodes including the root, so if there is a large tree..... look out.
835 */
836
837 /***
838 // * Handle an expansion of the Root node by only doing the first level.
839 // * Safe...
840 // */
841
842
843
844
845
846
847 DefaultMutableTreeNode treeNode =
848 (DefaultMutableTreeNode) path.getLastPathComponent();
849
850 Enumeration depthEnum = treeNode.depthFirstEnumeration();
851
852 if (!depthEnum.hasMoreElements())
853 {
854 break;
855 }
856
857 List depths = new ArrayList();
858
859 while (depthEnum.hasMoreElements())
860 {
861 depths.add(
862 new Integer(
863 ((DefaultMutableTreeNode) depthEnum.nextElement()).getDepth()));
864 }
865
866 Collections.sort(depths);
867 Collections.reverse(depths);
868
869 int maxDepth = ((Integer) depths.get(0)).intValue();
870
871 if (maxDepth > WARN_DEPTH)
872 {
873 logger.warn("Should warn user, depth=" + maxDepth);
874 }
875
876 depthEnum = treeNode.depthFirstEnumeration();
877
878 while (depthEnum.hasMoreElements())
879 {
880 DefaultMutableTreeNode node =
881 (DefaultMutableTreeNode) depthEnum.nextElement();
882
883 if (node.isLeaf())
884 {
885 TreeNode[] nodes =
886 ((DefaultMutableTreeNode) node.getParent()).getPath();
887 TreePath treePath = new TreePath(nodes);
888
889 logger.debug("Expanding path:" + treePath);
890
891 logTree.expandPath(treePath);
892 }
893 }
894 }
895 }
896
897 private void fireChangeEvent()
898 {
899 ChangeListener[] listeners =
900 (ChangeListener[]) listenerList.getListeners(ChangeListener.class);
901 ChangeEvent e = null;
902
903 for (int i = 0; i < listeners.length; i++)
904 {
905 if (e == null)
906 {
907 e = new ChangeEvent(this);
908 }
909
910 listeners[i].stateChanged(e);
911 }
912 }
913
914 private void reconfigureMenuText()
915 {
916 String logger = getCurrentlySelectedLoggerName();
917
918 if ((logger == null) || (logger.length() == 0))
919 {
920 focusOnAction.putValue(Action.NAME, "Focus On...");
921 hideAction.putValue(Action.NAME, "Ignore ...");
922 }
923 else
924 {
925 focusOnAction.putValue(Action.NAME, "Focus On '" + logger + "'");
926 hideAction.putValue(Action.NAME, "Ignore '" + logger + "'");
927 }
928
929
930 focusOnLoggerButton.setText(null);
931 ignoreLoggerButton.setText(null);
932 }
933
934 /***
935 * Configures varoius listeners etc for the components within
936 * this Class.
937 */
938 private void setupListeners()
939 {
940 logTree.addMouseMotionListener(new MouseKeyIconListener());
941
942 /***
943 * Enable the actions depending on state of the tree selection
944 */
945 logTree.addTreeSelectionListener(new TreeSelectionListener()
946 {
947 public void valueChanged(TreeSelectionEvent e)
948 {
949 TreePath path = e.getNewLeadSelectionPath();
950 TreeNode node = null;
951
952 if (path != null)
953 {
954 node = (TreeNode) path.getLastPathComponent();
955 }
956
957
958 String logger = getCurrentlySelectedLoggerName();
959 focusOnAction.setEnabled(
960 (path != null) && (node != null) && (node.getParent() != null)
961 && !hiddenSet.contains(logger));
962 hideAction.setEnabled(
963 (path != null) && (node != null) && (node.getParent() != null)
964 && !isFocusOnSelected());
965
966 if (!focusOnAction.isEnabled())
967 {
968 setFocusOnSelected(false);
969 }
970 else
971 {
972 }
973
974 expandAction.setEnabled(path != null);
975
976 if (logger != null)
977 {
978 boolean isHidden = hiddenSet.contains(logger);
979 popupMenu.hideCheck.setSelected(isHidden);
980 ignoreLoggerButton.setSelected(isHidden);
981 }
982
983 collapseAction.setEnabled(path != null);
984
985 reconfigureMenuText();
986 }
987 });
988
989 logTree.addMouseListener(popupListener);
990
991 /***
992 * This listener ensures the Tool bar toggle button and popup menu check box
993 * stay in sync, plus notifies all the ChangeListeners that
994 * an effective filter criteria has been modified
995 */
996 focusOnAction.addPropertyChangeListener(new PropertyChangeListener()
997 {
998 public void propertyChange(PropertyChangeEvent evt)
999 {
1000 popupMenu.focusOnCheck.setSelected(isFocusOnSelected());
1001 focusOnLoggerButton.setSelected(isFocusOnSelected());
1002
1003 if (logTree.getSelectionPath() != null)
1004 {
1005 logTreeModel.nodeChanged(
1006 (TreeNode) logTree.getSelectionPath().getLastPathComponent());
1007 }
1008
1009 fireChangeEvent();
1010 }
1011 });
1012
1013 hideAction.addPropertyChangeListener(new PropertyChangeListener()
1014 {
1015 public void propertyChange(PropertyChangeEvent evt)
1016 {
1017 if (logTree.getSelectionPath() != null)
1018 {
1019 logTreeModel.nodeChanged(
1020 (TreeNode) logTree.getSelectionPath().getLastPathComponent());
1021 }
1022
1023 fireChangeEvent();
1024 }
1025 });
1026
1027 /***
1028 // * Now add a MouseListener that fires the expansion
1029 // * action if CTRL + DBL CLICK is done.
1030 // */
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047 logTree.addMouseListener(new MouseFocusOnListener());
1048
1049 /***
1050 * We listen for when the FocusOn action changes, and then translate
1051 * that to a RuleChange
1052 */
1053 addChangeListener(new ChangeListener()
1054 {
1055 public void stateChanged(ChangeEvent evt)
1056 {
1057 firePropertyChange("rule", null, null);
1058 updateAllIgnoreStuff();
1059 }
1060 });
1061
1062 addPropertyChangeListener("hiddenSet", new PropertyChangeListener()
1063 {
1064 public void propertyChange(PropertyChangeEvent arg0)
1065 {
1066 updateAllIgnoreStuff();
1067 }
1068 });
1069 }
1070
1071 private void updateAllIgnoreStuff() {
1072 updateHiddenSetModels();
1073 updateIgnoreSummary();
1074 }
1075
1076 private void updateHiddenSetModels() {
1077 DefaultListModel model = (DefaultListModel) ignoreList.getModel();
1078 model.clear();
1079 List sortedIgnoreList = new ArrayList(getHiddenSet());
1080 Collections.sort(sortedIgnoreList);
1081
1082 for (Iterator iter = sortedIgnoreList.iterator(); iter.hasNext();)
1083 {
1084 String string = (String) iter.next();
1085 model.addElement(string);
1086 }
1087
1088
1089
1090 }
1091 private void updateIgnoreSummary() {
1092 ignoreSummary.setText(ignoreList.getModel().getSize() + " hidden loggers");
1093 }
1094
1095 private void toggleFocusOnState()
1096 {
1097 setFocusOnSelected(!isFocusOnSelected());
1098 hideAction.setEnabled(!isFocusOnSelected());
1099 }
1100
1101
1102
1103 /***
1104 * DOCUMENT ME!
1105 *
1106 * @author $author$
1107 * @version $Revision: 529672 $, $Date: 2007-04-17 11:59:53 -0500 (Tue, 17 Apr 2007) $
1108 *
1109 * @author Paul Smith <psmith@apache.org>
1110 *
1111 */
1112 private class LoggerNameTreeCellRenderer extends DefaultTreeCellRenderer
1113 {
1114
1115
1116
1117 private LoggerNameTreeCellRenderer()
1118 {
1119 super();
1120
1121
1122
1123 setLeafIcon(null);
1124 setOpaque(false);
1125 }
1126
1127
1128
1129
1130
1131
1132 /***
1133 * DOCUMENT ME!
1134 *
1135 * @param tree DOCUMENT ME!
1136 * @param value DOCUMENT ME!
1137 * @param sel DOCUMENT ME!
1138 * @param expanded DOCUMENT ME!
1139 * @param leaf DOCUMENT ME!
1140 * @param row DOCUMENT ME!
1141 * @param focus DOCUMENT ME!
1142 *
1143 * @return DOCUMENT ME!
1144 */
1145 public Component getTreeCellRendererComponent(
1146 JTree tree, Object value, boolean sel, boolean expanded, boolean leaf,
1147 int row, boolean focus)
1148 {
1149 JLabel component =
1150 (JLabel) super.getTreeCellRendererComponent(
1151 tree, value, sel, expanded, leaf, row, focus);
1152
1153 Font originalFont = component.getFont();
1154
1155 int style = Font.PLAIN;
1156
1157 if (sel && focusOnLoggerButton.isSelected())
1158 {
1159 style = style | Font.BOLD;
1160 }
1161
1162 String logger =
1163 getLoggerName(
1164 new TreePath(((DefaultMutableTreeNode) value).getPath()));
1165
1166 if (hiddenSet.contains(logger))
1167 {
1168
1169
1170 style = style | Font.ITALIC;
1171
1172
1173 }
1174 else
1175 {
1176
1177
1178 }
1179
1180 if (originalFont != null)
1181 {
1182 Font font2 = originalFont.deriveFont(style);
1183
1184 if (font2 != null)
1185 {
1186 component.setFont(font2);
1187 }
1188 }
1189
1190 return component;
1191 }
1192 }
1193
1194 private class LoggerTreePopupMenu extends JPopupMenu
1195 {
1196
1197
1198 JCheckBoxMenuItem focusOnCheck = new JCheckBoxMenuItem();
1199 JCheckBoxMenuItem hideCheck = new JCheckBoxMenuItem();
1200
1201
1202
1203 private LoggerTreePopupMenu()
1204 {
1205 initMenu();
1206 }
1207
1208
1209
1210
1211
1212
1213 /***
1214 * DOCUMENT ME!
1215 *
1216 * @param invoker DOCUMENT ME!
1217 * @param x DOCUMENT ME!
1218 * @param y DOCUMENT ME!
1219 */
1220 public void show(Component invoker, int x, int y)
1221 {
1222 DefaultMutableTreeNode node =
1223 (DefaultMutableTreeNode) logTree.getLastSelectedPathComponent();
1224
1225 if (node == null)
1226 {
1227 return;
1228 }
1229
1230 super.show(invoker, x, y);
1231 }
1232
1233 /***
1234 * DOCUMENT ME!
1235 */
1236 private void initMenu()
1237 {
1238 add(expandAction);
1239 add(collapseAction);
1240 addSeparator();
1241 focusOnCheck.setAction(focusOnAction);
1242 hideCheck.setAction(hideAction);
1243 add(focusOnCheck);
1244 add(hideCheck);
1245
1246
1247 addSeparator();
1248 add(clearIgnoreListAction);
1249 }
1250 }
1251
1252 private final class MouseFocusOnListener extends MouseAdapter
1253 {
1254
1255
1256
1257
1258
1259 /***
1260 * DOCUMENT ME!
1261 *
1262 * @param e DOCUMENT ME!
1263 */
1264 public void mouseClicked(MouseEvent e)
1265 {
1266 if (
1267 (e.getClickCount() > 1)
1268 && ((e.getModifiers() & InputEvent.CTRL_MASK) > 0)
1269 && ((e.getModifiers() & InputEvent.SHIFT_MASK) > 0))
1270 {
1271 ignoreLoggerAtPoint(e.getPoint());
1272 e.consume();
1273 fireChangeEvent();
1274 }
1275 else if (
1276 (e.getClickCount() > 1)
1277 && ((e.getModifiers() & InputEvent.CTRL_MASK) > 0))
1278 {
1279 focusAnLoggerAtPoint(e.getPoint());
1280 e.consume();
1281 fireChangeEvent();
1282 }
1283 }
1284
1285 /***
1286 * DOCUMENT ME!
1287 *
1288 * @param point
1289 */
1290 private void focusAnLoggerAtPoint(Point point)
1291 {
1292 String logger = getLoggerAtPoint(point);
1293
1294 if (logger != null)
1295 {
1296 toggleFocusOnState();
1297 }
1298 }
1299
1300 /***
1301 * DOCUMENT ME!
1302 *
1303 * @param point
1304 * @return
1305 */
1306 private String getLoggerAtPoint(Point point)
1307 {
1308 TreePath path = logTree.getPathForLocation(point.x, point.y);
1309
1310 if (path != null)
1311 {
1312 return getLoggerName(path);
1313 }
1314
1315 return null;
1316 }
1317
1318 /***
1319 * DOCUMENT ME!
1320 *
1321 * @param point
1322 */
1323 private void ignoreLoggerAtPoint(Point point)
1324 {
1325 String logger = getLoggerAtPoint(point);
1326
1327 if (logger != null)
1328 {
1329 toggleHiddenLogger(logger);
1330 }
1331 }
1332 }
1333
1334 private final class MouseKeyIconListener extends MouseMotionAdapter
1335 implements MouseMotionListener
1336 {
1337
1338
1339 Cursor focusOnCursor =
1340 Toolkit.getDefaultToolkit().createCustomCursor(
1341 ChainsawIcons.FOCUS_ON_ICON.getImage(), new Point(10, 10), "");
1342 Cursor ignoreCursor =
1343 Toolkit.getDefaultToolkit().createCustomCursor(
1344 ChainsawIcons.IGNORE_ICON.getImage(), new Point(10, 10), "");
1345
1346
1347
1348
1349
1350
1351 /***
1352 * DOCUMENT ME!
1353 *
1354 * @param e DOCUMENT ME!
1355 */
1356 public void mouseMoved(MouseEvent e)
1357 {
1358
1359 if (
1360 ((e.getModifiers() & InputEvent.CTRL_MASK) > 0)
1361 && ((e.getModifiers() & InputEvent.SHIFT_MASK) > 0))
1362 {
1363 logTree.setCursor(ignoreCursor);
1364 }
1365 else if ((e.getModifiers() & InputEvent.CTRL_MASK) > 0)
1366 {
1367 logTree.setCursor(focusOnCursor);
1368 }
1369 else
1370 {
1371 logTree.setCursor(Cursor.getDefaultCursor());
1372 }
1373 }
1374 }
1375 }