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