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