View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.log4j.lf5.viewer.categoryexplorer;
18  
19  import javax.swing.*;
20  import javax.swing.tree.TreePath;
21  import java.awt.*;
22  import java.awt.event.ActionEvent;
23  import java.awt.event.ActionListener;
24  import java.awt.event.MouseAdapter;
25  import java.awt.event.MouseEvent;
26  import java.util.ArrayList;
27  import java.util.Enumeration;
28  
29  /***
30   * CategoryNodeEditor
31   *
32   * @author Michael J. Sikorsky
33   * @author Robert Shaw
34   */
35  
36  // Contributed by ThoughtWorks Inc.
37  
38  public class CategoryNodeEditor extends CategoryAbstractCellEditor {
39    //--------------------------------------------------------------------------
40    //   Constants:
41    //--------------------------------------------------------------------------
42  
43    //--------------------------------------------------------------------------
44    //   Protected Variables:
45    //--------------------------------------------------------------------------
46    protected CategoryNodeEditorRenderer _renderer;
47    protected CategoryNode _lastEditedNode;
48    protected JCheckBox _checkBox;
49    protected CategoryExplorerModel _categoryModel;
50    protected JTree _tree;
51  
52    //--------------------------------------------------------------------------
53    //   Private Variables:
54    //--------------------------------------------------------------------------
55  
56    //--------------------------------------------------------------------------
57    //   Constructors:
58    //--------------------------------------------------------------------------
59  
60    public CategoryNodeEditor(CategoryExplorerModel model) {
61      _renderer = new CategoryNodeEditorRenderer();
62      _checkBox = _renderer.getCheckBox();
63      _categoryModel = model;
64  
65      _checkBox.addActionListener(new ActionListener() {
66        public void actionPerformed(ActionEvent e) {
67          _categoryModel.update(_lastEditedNode, _checkBox.isSelected());
68          stopCellEditing();
69        }
70      });
71  
72      _renderer.addMouseListener(new MouseAdapter() {
73        public void mousePressed(MouseEvent e) {
74          if ((e.getModifiers() & MouseEvent.BUTTON3_MASK) != 0) {
75            showPopup(_lastEditedNode, e.getX(), e.getY());
76          }
77          stopCellEditing();
78        }
79      });
80    }
81  
82    //--------------------------------------------------------------------------
83    //   Public Methods:
84    //--------------------------------------------------------------------------
85  
86    public Component getTreeCellEditorComponent(JTree tree, Object value,
87        boolean selected, boolean expanded,
88        boolean leaf, int row) {
89      _lastEditedNode = (CategoryNode) value;
90      _tree = tree;
91  
92      return _renderer.getTreeCellRendererComponent(tree,
93          value, selected, expanded,
94          leaf, row, true);
95      // hasFocus ignored
96    }
97  
98    public Object getCellEditorValue() {
99      return _lastEditedNode.getUserObject();
100   }
101   //--------------------------------------------------------------------------
102   //   Protected Methods:
103   //--------------------------------------------------------------------------
104 
105   protected JMenuItem createPropertiesMenuItem(final CategoryNode node) {
106     JMenuItem result = new JMenuItem("Properties");
107     result.addActionListener(new ActionListener() {
108       public void actionPerformed(ActionEvent e) {
109         showPropertiesDialog(node);
110       }
111     });
112     return result;
113   }
114 
115   protected void showPropertiesDialog(CategoryNode node) {
116     JOptionPane.showMessageDialog(
117         _tree,
118         getDisplayedProperties(node),
119         "Category Properties: " + node.getTitle(),
120         JOptionPane.PLAIN_MESSAGE
121     );
122   }
123 
124   protected Object getDisplayedProperties(CategoryNode node) {
125     ArrayList result = new ArrayList();
126     result.add("Category: " + node.getTitle());
127     if (node.hasFatalRecords()) {
128       result.add("Contains at least one fatal LogRecord.");
129     }
130     if (node.hasFatalChildren()) {
131       result.add("Contains descendants with a fatal LogRecord.");
132     }
133     result.add("LogRecords in this category alone: " +
134         node.getNumberOfContainedRecords());
135     result.add("LogRecords in descendant categories: " +
136         node.getNumberOfRecordsFromChildren());
137     result.add("LogRecords in this category including descendants: " +
138         node.getTotalNumberOfRecords());
139     return result.toArray();
140   }
141 
142   protected void showPopup(CategoryNode node, int x, int y) {
143     JPopupMenu popup = new JPopupMenu();
144     popup.setSize(150, 400);
145     //
146     // Configure the Popup
147     //
148     if (node.getParent() == null) {
149       popup.add(createRemoveMenuItem());
150       popup.addSeparator();
151     }
152     popup.add(createSelectDescendantsMenuItem(node));
153     popup.add(createUnselectDescendantsMenuItem(node));
154     popup.addSeparator();
155     popup.add(createExpandMenuItem(node));
156     popup.add(createCollapseMenuItem(node));
157     popup.addSeparator();
158     popup.add(createPropertiesMenuItem(node));
159     popup.show(_renderer, x, y);
160   }
161 
162   protected JMenuItem createSelectDescendantsMenuItem(final CategoryNode node) {
163     JMenuItem selectDescendants =
164         new JMenuItem("Select All Descendant Categories");
165     selectDescendants.addActionListener(
166         new ActionListener() {
167           public void actionPerformed(ActionEvent e) {
168             _categoryModel.setDescendantSelection(node, true);
169           }
170         }
171     );
172     return selectDescendants;
173   }
174 
175   protected JMenuItem createUnselectDescendantsMenuItem(final CategoryNode node) {
176     JMenuItem unselectDescendants =
177         new JMenuItem("Deselect All Descendant Categories");
178     unselectDescendants.addActionListener(
179 
180         new ActionListener() {
181           public void actionPerformed(ActionEvent e) {
182             _categoryModel.setDescendantSelection(node, false);
183           }
184         }
185 
186     );
187     return unselectDescendants;
188   }
189 
190   protected JMenuItem createExpandMenuItem(final CategoryNode node) {
191     JMenuItem result = new JMenuItem("Expand All Descendant Categories");
192     result.addActionListener(new ActionListener() {
193       public void actionPerformed(ActionEvent e) {
194         expandDescendants(node);
195       }
196     });
197     return result;
198   }
199 
200   protected JMenuItem createCollapseMenuItem(final CategoryNode node) {
201     JMenuItem result = new JMenuItem("Collapse All Descendant Categories");
202     result.addActionListener(new ActionListener() {
203       public void actionPerformed(ActionEvent e) {
204         collapseDescendants(node);
205       }
206     });
207     return result;
208   }
209 
210   /***
211    * This featured was moved from the LogBrokerMonitor class
212    * to the CategoryNodeExplorer so that the Category tree
213    * could be pruned from the Category Explorer popup menu.
214    * This menu option only appears when a user right clicks on
215    * the Category parent node.
216    *
217    * See removeUnusedNodes()
218    */
219   protected JMenuItem createRemoveMenuItem() {
220     JMenuItem result = new JMenuItem("Remove All Empty Categories");
221     result.addActionListener(new ActionListener() {
222       public void actionPerformed(ActionEvent e) {
223         while (removeUnusedNodes() > 0) ;
224       }
225     });
226     return result;
227   }
228 
229   protected void expandDescendants(CategoryNode node) {
230     Enumeration descendants = node.depthFirstEnumeration();
231     CategoryNode current;
232     while (descendants.hasMoreElements()) {
233       current = (CategoryNode) descendants.nextElement();
234       expand(current);
235     }
236   }
237 
238   protected void collapseDescendants(CategoryNode node) {
239     Enumeration descendants = node.depthFirstEnumeration();
240     CategoryNode current;
241     while (descendants.hasMoreElements()) {
242       current = (CategoryNode) descendants.nextElement();
243       collapse(current);
244     }
245   }
246 
247   /***
248    * Removes any inactive nodes from the Category tree.
249    */
250   protected int removeUnusedNodes() {
251     int count = 0;
252     CategoryNode root = _categoryModel.getRootCategoryNode();
253     Enumeration enumeration = root.depthFirstEnumeration();
254     while (enumeration.hasMoreElements()) {
255       CategoryNode node = (CategoryNode) enumeration.nextElement();
256       if (node.isLeaf() && node.getNumberOfContainedRecords() == 0
257           && node.getParent() != null) {
258         _categoryModel.removeNodeFromParent(node);
259         count++;
260       }
261     }
262 
263     return count;
264   }
265 
266   protected void expand(CategoryNode node) {
267     _tree.expandPath(getTreePath(node));
268   }
269 
270   protected TreePath getTreePath(CategoryNode node) {
271     return new TreePath(node.getPath());
272   }
273 
274   protected void collapse(CategoryNode node) {
275     _tree.collapsePath(getTreePath(node));
276   }
277 
278   //-----------------------------------------------------------------------
279   //   Private Methods:
280   //--------------------------------------------------------------------------
281 
282   //--------------------------------------------------------------------------
283   //   Nested Top-Level Classes or Interfaces:
284   //--------------------------------------------------------------------------
285 
286 }