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 org.apache.log4j.lf5.LogRecord;
    20
    21  import javax.swing.*;
    22  import javax.swing.tree.DefaultTreeModel;
    23  import javax.swing.tree.TreeNode;
    24  import javax.swing.tree.TreePath;
    25  import java.awt.*;
    26  import java.awt.event.ActionEvent;
    27  import java.awt.event.ActionListener;
    28  import java.util.Enumeration;
    29
    30  /***
    31   * CategoryExplorerModel
    32   *
    33   * @author Michael J. Sikorsky
    34   * @author Robert Shaw
    35   * @author Brent Sprecher
    36   * @author Richard Hurst
    37   */
    38
    39  // Contributed by ThoughtWorks Inc.
    40
    41  public class CategoryExplorerModel extends DefaultTreeModel {
    42    private static final long serialVersionUID = -3413887384316015901L;
    43
    44    //--------------------------------------------------------------------------
    45    //   Constants:
    46    //--------------------------------------------------------------------------
    47
    48    //--------------------------------------------------------------------------
    49    //   Protected Variables:
    50    //--------------------------------------------------------------------------
    51
    52    protected boolean _renderFatal = true;
    53    protected ActionListener _listener = null;
    54    protected ActionEvent _event = new ActionEvent(this,
    55        ActionEvent.ACTION_PERFORMED,
    56        "Nodes Selection changed");
    57
    58    //--------------------------------------------------------------------------
    59    //   Private Variables:
    60    //--------------------------------------------------------------------------
    61
    62    //--------------------------------------------------------------------------
    63    //   Constructors:
    64    //--------------------------------------------------------------------------
    65
    66    public CategoryExplorerModel(CategoryNode node) {
    67      super(node);
    68    }
    69    //--------------------------------------------------------------------------
    70    //   Public Methods:
    71    //--------------------------------------------------------------------------
    72
    73    public void addLogRecord(LogRecord lr) {
    74      CategoryPath path = new CategoryPath(lr.getCategory());
    75      addCategory(path); // create category path if it is new
    76      CategoryNode node = getCategoryNode(path);
    77      node.addRecord(); // update category node
    78      if (_renderFatal && lr.isFatal()) {
    79        TreeNode[] nodes = getPathToRoot(node);
    80        int len = nodes.length;
    81        CategoryNode parent;
    82
    83        // i = 0 gives root node
    84        // skip node and root, loop through "parents" in between
    85        for (int i = 1; i < len - 1; i++) {
    86          parent = (CategoryNode) nodes[i];
    87          parent.setHasFatalChildren(true);
    88          nodeChanged(parent);
    89        }
    90        node.setHasFatalRecords(true);
    91        nodeChanged(node);
    92      }
    93    }
    94
    95    public CategoryNode getRootCategoryNode() {
    96      return (CategoryNode) getRoot();
    97    }
    98
    99    public CategoryNode getCategoryNode(String category) {
    100     CategoryPath path = new CategoryPath(category);
    101     return (getCategoryNode(path));
    102   }
    103
    104   /***
    105    * returns null if no CategoryNode exists.
    106    */
    107   public CategoryNode getCategoryNode(CategoryPath path) {
    108     CategoryNode root = (CategoryNode) getRoot();
    109     CategoryNode parent = root; // Start condition.
    110
    111     for (int i = 0; i < path.size(); i++) {
    112       CategoryElement element = path.categoryElementAt(i);
    113
    114       // If the two nodes have matching titles they are considered equal.
    115       Enumeration children = parent.children();
    116
    117       boolean categoryAlreadyExists = false;
    118       while (children.hasMoreElements()) {
    119         CategoryNode node = (CategoryNode) children.nextElement();
    120         String title = node.getTitle().toLowerCase();
    121
    122         String pathLC = element.getTitle().toLowerCase();
    123         if (title.equals(pathLC)) {
    124           categoryAlreadyExists = true;
    125           // This is now the new parent node.
    126           parent = node;
    127           break; // out of the while, and back to the for().
    128         }
    129       }
    130
    131       if (categoryAlreadyExists == false) {
    132         return null; // Didn't find the Node.
    133       }
    134     }
    135
    136     return (parent);
    137   }
    138
    139   /***
    140    * @return true if all the nodes in the specified CategoryPath are
    141    * selected.
    142    */
    143   public boolean isCategoryPathActive(CategoryPath path) {
    144     CategoryNode root = (CategoryNode) getRoot();
    145     CategoryNode parent = root; // Start condition.
    146     boolean active = false;
    147
    148     for (int i = 0; i < path.size(); i++) {
    149       CategoryElement element = path.categoryElementAt(i);
    150
    151       // If the two nodes have matching titles they are considered equal.
    152       Enumeration children = parent.children();
    153
    154       boolean categoryAlreadyExists = false;
    155       active = false;
    156
    157       while (children.hasMoreElements()) {
    158         CategoryNode node = (CategoryNode) children.nextElement();
    159         String title = node.getTitle().toLowerCase();
    160
    161         String pathLC = element.getTitle().toLowerCase();
    162         if (title.equals(pathLC)) {
    163           categoryAlreadyExists = true;
    164           // This is now the new parent node.
    165           parent = node;
    166
    167           if (parent.isSelected()) {
    168             active = true;
    169           }
    170
    171           break; // out of the while, and back to the for().
    172         }
    173       }
    174
    175       if (active == false || categoryAlreadyExists == false) {
    176         return false;
    177       }
    178     }
    179
    180     return (active);
    181   }
    182
    183
    184   /***
    185    * <p>Method altered by Richard Hurst such that it returns the CategoryNode
    186    * corresponding to the CategoryPath</p>
    187    *
    188    * @param path category path.
    189    * @return CategoryNode
    190    */
    191   public CategoryNode addCategory(CategoryPath path) {
    192     CategoryNode root = (CategoryNode) getRoot();
    193     CategoryNode parent = root; // Start condition.
    194
    195     for (int i = 0; i < path.size(); i++) {
    196       CategoryElement element = path.categoryElementAt(i);
    197
    198       // If the two nodes have matching titles they are considered equal.
    199       Enumeration children = parent.children();
    200
    201       boolean categoryAlreadyExists = false;
    202       while (children.hasMoreElements()) {
    203         CategoryNode node = (CategoryNode) children.nextElement();
    204         String title = node.getTitle().toLowerCase();
    205
    206         String pathLC = element.getTitle().toLowerCase();
    207         if (title.equals(pathLC)) {
    208           categoryAlreadyExists = true;
    209           // This is now the new parent node.
    210           parent = node;
    211           break;
    212         }
    213       }
    214
    215       if (categoryAlreadyExists == false) {
    216         // We need to add the node.
    217         CategoryNode newNode = new CategoryNode(element.getTitle());
    218
    219         //This method of adding a new node cause parent roots to be
    220         // collapsed.
    221         //parent.add( newNode );
    222         //reload(parent);
    223
    224         // This doesn't force the nodes to collapse.
    225         insertNodeInto(newNode, parent, parent.getChildCount());
    226         refresh(newNode);
    227
    228         // The newly added node is now the parent.
    229         parent = newNode;
    230
    231       }
    232     }
    233
    234     return parent;
    235   }
    236
    237   public void update(CategoryNode node, boolean selected) {
    238     if (node.isSelected() == selected) {
    239       return; // nothing was changed, nothing to do
    240     }
    241     // select parents or deselect children
    242     if (selected) {
    243       setParentSelection(node, true);
    244     } else {
    245       setDescendantSelection(node, false);
    246     }
    247   }
    248
    249   public void setDescendantSelection(CategoryNode node, boolean selected) {
    250     Enumeration descendants = node.depthFirstEnumeration();
    251     CategoryNode current;
    252     while (descendants.hasMoreElements()) {
    253       current = (CategoryNode) descendants.nextElement();
    254       // does the current node need to be changed?
    255       if (current.isSelected() != selected) {
    256         current.setSelected(selected);
    257         nodeChanged(current);
    258       }
    259     }
    260     notifyActionListeners();
    261   }
    262
    263   public void setParentSelection(CategoryNode node, boolean selected) {
    264     TreeNode[] nodes = getPathToRoot(node);
    265     int len = nodes.length;
    266     CategoryNode parent;
    267
    268     // i = 0 gives root node, i=len-1 gives this node
    269     // skip the root node
    270     for (int i = 1; i < len; i++) {
    271       parent = (CategoryNode) nodes[i];
    272       if (parent.isSelected() != selected) {
    273         parent.setSelected(selected);
    274         nodeChanged(parent);
    275       }
    276     }
    277     notifyActionListeners();
    278   }
    279
    280
    281   public synchronized void addActionListener(ActionListener l) {
    282     _listener = AWTEventMulticaster.add(_listener, l);
    283   }
    284
    285   public synchronized void removeActionListener(ActionListener l) {
    286     _listener = AWTEventMulticaster.remove(_listener, l);
    287   }
    288
    289   public void resetAllNodeCounts() {
    290     Enumeration nodes = getRootCategoryNode().depthFirstEnumeration();
    291     CategoryNode current;
    292     while (nodes.hasMoreElements()) {
    293       current = (CategoryNode) nodes.nextElement();
    294       current.resetNumberOfContainedRecords();
    295       nodeChanged(current);
    296     }
    297   }
    298
    299   /***
    300    * <p>Returns the CategoryPath to the specified CategoryNode</p>
    301    *
    302    * @param node The target CategoryNode
    303    * @return CategoryPath
    304    */
    305   public TreePath getTreePathToRoot(CategoryNode node) {
    306     if (node == null) {
    307       return null;
    308     }
    309     return (new TreePath(getPathToRoot(node)));
    310   }
    311
    312   //--------------------------------------------------------------------------
    313   //   Protected Methods:
    314   //--------------------------------------------------------------------------
    315   protected void notifyActionListeners() {
    316     if (_listener != null) {
    317       _listener.actionPerformed(_event);
    318     }
    319   }
    320
    321   /***
    322    * Fires a nodechanged event on the SwingThread.
    323    */
    324   protected void refresh(final CategoryNode node) {
    325     SwingUtilities.invokeLater(new Runnable() {
    326       public void run() {
    327         nodeChanged(node); // remind the tree to render the new node
    328       }
    329     });
    330   }
    331
    332   //--------------------------------------------------------------------------
    333   //   Private Methods:
    334   //--------------------------------------------------------------------------
    335
    336   //--------------------------------------------------------------------------
    337   //   Nested Top-Level Classes or Interfaces:
    338   //--------------------------------------------------------------------------
    339
    340 }
    341
    342
    343
    344
    345
    346