gt:         Enumeration e = node.children();
context: // $Id: ExplorerTree.java 41 2010-04-03 20:04:12Z marcusvnac $
  // Copyright (c) 1996-2008 The Regents of the University of California. All
  // Rights Reserved. Permission to use, copy, modify, and distribute this
  // software and its documentation without fee, and without a written
  // agreement is hereby granted, provided that the above copyright notice
  // and this paragraph appear in all copies.  This software program and
  // documentation are copyrighted by The Regents of the University of
  // California. The software program and documentation are supplied "AS
  // IS", without any accompanying services from The Regents. The Regents
  // does not warrant that the operation of the program will be
  // uninterrupted or error-free. The end-user understands that the program
  // was developed for research purposes and is advised not to rely
  // exclusively on the program for any reason.  IN NO EVENT SHALL THE
  // UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
  // SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
  // ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
  // THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
  // SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY
  // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
  // PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
  // CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT,
  // UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  
  package org.argouml.ui.explorer;
  
  import java.awt.event.MouseAdapter;
  import java.awt.event.MouseEvent;
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.Enumeration;
  import java.util.HashSet;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Set;
  
  import javax.swing.JPopupMenu;
  import javax.swing.JTree;
  import javax.swing.event.TreeExpansionEvent;
  import javax.swing.event.TreeExpansionListener;
  import javax.swing.event.TreeSelectionEvent;
  import javax.swing.event.TreeSelectionListener;
  import javax.swing.event.TreeWillExpandListener;
  import javax.swing.tree.DefaultMutableTreeNode;
  import javax.swing.tree.TreePath;
  
  import org.argouml.kernel.Project;
  import org.argouml.kernel.ProjectManager;
  import org.argouml.kernel.ProjectSettings;
  import org.argouml.ui.DisplayTextTree;
  import org.argouml.ui.ProjectActions;
  import org.argouml.ui.targetmanager.TargetEvent;
  import org.argouml.ui.targetmanager.TargetListener;
  import org.argouml.ui.targetmanager.TargetManager;
  import org.tigris.gef.presentation.Fig;
  
  /**
   * This class is the JTree for the explorer. It provides:<p>
   * <pre>
   *  - selection/target management
   *  - mouse listener for the pop up </pre>
   *
   * @author  alexb
   * @since 0.15.2
   */
  public class ExplorerTree
      extends DisplayTextTree {
  
  
      /**
       * Prevents target event cycles between this and the TargetManager.
       */
      private boolean updatingSelection;
  
      /**
       * Prevents target event cycles between this and the TargetManager
       * for tree selection events.
       */
      private boolean updatingSelectionViaTreeSelection;
  
      /**
       * Creates a new instance of ExplorerTree.
       */
      public ExplorerTree() {
          super();
          
          Project p = ProjectManager.getManager().getCurrentProject();
          this.setModel(new ExplorerTreeModel(p, this));
  
          ProjectSettings ps = p.getProjectSettings();
          setShowStereotype(ps.getShowStereotypesValue());
  
          this.addMouseListener(new ExplorerMouseListener(this));
          this.addTreeSelectionListener(new ExplorerTreeSelectionListener());
          this.addTreeWillExpandListener(new ExplorerTreeWillExpandListener());
          this.addTreeExpansionListener(new ExplorerTreeExpansionListener());
  
          TargetManager.getInstance()
  	    .addTargetListener(new ExplorerTargetListener());
      }
  
      /**
       * Listens to mouse events coming from the *JTree*,
       * on right click, brings up the pop-up menu.
       */
      class ExplorerMouseListener extends MouseAdapter {
  
          private JTree mLTree;
  
          /**
           * The constructor.
           * @param newtree
           */
          public ExplorerMouseListener(JTree newtree) {
              super();
              mLTree = newtree;
          }
  
          /**
           * Brings up the pop-up menu.
           * 
           * @see java.awt.event.MouseListener#mousePressed(
           *      java.awt.event.MouseEvent)
           */
          @Override
          public void mousePressed(MouseEvent me) {
              if (me.isPopupTrigger()) {
                  me.consume();
                  showPopupMenu(me);
              }
          }
  
          /**
           * Brings up the pop-up menu.
           * 
           * On Windows and Motif platforms, the user brings up a popup menu by
           * releasing the right mouse button while the cursor is over a component
           * that is popup-enabled.
           * 
           * @see java.awt.event.MouseListener#mouseReleased(
           *      java.awt.event.MouseEvent)
           */
          @Override
          public void mouseReleased(MouseEvent me) {
              if (me.isPopupTrigger()) {
                  me.consume();
                  showPopupMenu(me);
              }
          }
  
          /**
           * Brings up the pop-up menu.
           * 
           * @see java.awt.event.MouseListener#mouseClicked(
           *      java.awt.event.MouseEvent)
           */
          @Override
          public void mouseClicked(MouseEvent me) {
              if (me.isPopupTrigger()) {
                  me.consume();
                  showPopupMenu(me);
              }
              if (me.getClickCount() >= 2) {
                  myDoubleClick();
              }
          }
  
          /**
           * Double-clicking on an item attempts
           * to show the item in a diagram.
           */
          private void myDoubleClick() {
              Object target = TargetManager.getInstance().getTarget();
              if (target != null) {
                  List show = new ArrayList();
                  show.add(target);
                  ProjectActions.jumpToDiagramShowing(show);
              }
          }
  
          /**
           * Builds a pop-up menu for extra functionality for the Tree.
           *
           * @param me The mouse event.
           */
          public void showPopupMenu(MouseEvent me) {
  
              TreePath path = getPathForLocation(me.getX(), me.getY());
              if (path == null) {
                  return;
              }
  
              /*
               * We preserve the current (multiple) selection,
               * if we are over part of it ...
               */
              if (!isPathSelected(path)) {
                  /* ... otherwise we select the item below the mousepointer. */
                  getSelectionModel().setSelectionPath(path);
              }
  
              Object selectedItem =
                  ((DefaultMutableTreeNode) path.getLastPathComponent())
                          .getUserObject();
              JPopupMenu popup = new ExplorerPopup(selectedItem, me);
  
              if (popup.getComponentCount() > 0) {
                  popup.show(mLTree, me.getX(), me.getY());
              }
          }
  
      } /* end class ExplorerMouseListener */
  
  
      /**
       * Helps prepare state before a node is expanded.
       */
      class ExplorerTreeWillExpandListener implements TreeWillExpandListener {
  
          /*
           * @see javax.swing.event.TreeWillExpandListener#treeWillCollapse(javax.swing.event.TreeExpansionEvent)
           */
          public void treeWillCollapse(TreeExpansionEvent tee) {
              // unimplemented - we only care about expanding
  	}
  
          /*
           * Updates stereotype setting,
           * adds all children per treemodel 'build on demand' design.
           *
           * @see javax.swing.event.TreeWillExpandListener#treeWillExpand(javax.swing.event.TreeExpansionEvent)
           */
          public void treeWillExpand(TreeExpansionEvent tee) {
              // TODO: This should not need to know about ProjectSettings - tfm
              Project p = ProjectManager.getManager().getCurrentProject();
              ProjectSettings ps = p.getProjectSettings();
              setShowStereotype(ps.getShowStereotypesValue());
  
              if (getModel() instanceof ExplorerTreeModel) {
  
                  ((ExplorerTreeModel) getModel()).updateChildren(tee.getPath());
              }
          }
      }
  
      /**
       * Helps react to tree expansion events.
       */
      class ExplorerTreeExpansionListener implements TreeExpansionListener {
  
          /*
           * @see javax.swing.event.TreeExpansionListener#treeCollapsed(
           *         javax.swing.event.TreeExpansionEvent)
           */
          public void treeCollapsed(TreeExpansionEvent event) {
              // does nothing.
          }
  
          /*
           * @see javax.swing.event.TreeExpansionListener#treeExpanded(
           *         javax.swing.event.TreeExpansionEvent)
           * Updates the selection state.
           */
          public void treeExpanded(TreeExpansionEvent event) {
  
              // need to update the selection state.
              setSelection(TargetManager.getInstance().getTargets().toArray());
          }
      }
  
      /**
       * Refresh the selection of the tree nodes.
       * This does not cause new events to be fired to the TargetManager.
       */
      public void refreshSelection() {
          Collection targets = TargetManager.getInstance().getTargets();
          updatingSelectionViaTreeSelection = true;
          setSelection(targets.toArray());
          updatingSelectionViaTreeSelection = false;
      }
  
      /**
       * Sets the selection state for a given set of targets.
       *
       * @param targets the targets
       */
      private void setSelection(Object[] targets) {
          updatingSelectionViaTreeSelection = true;
  
          this.clearSelection();
          addTargetsInternal(targets);
          updatingSelectionViaTreeSelection = false;
      }
  
  
      
      private void addTargetsInternal(Object[] addedTargets) {
          if (addedTargets.length < 1) {
              return;
          }
          Set targets = new HashSet();
          for (Object t : addedTargets) {
              if (t instanceof Fig) {
                  targets.add(((Fig) t).getOwner());
              } else {
                  targets.add(t);
              }
              // TODO: The following can be removed if selectAll gets fixed
              selectVisible(t);
          }
  
          // TODO: This doesn't perform well enough with large models to have
          // it enabled by default.  If the performance can't be improved, 
          // perhaps we can introduce a manual "find in explorer tree" action.
  //        selectAll(targets);
      
          int[] selectedRows = getSelectionRows();
          if (selectedRows != null && selectedRows.length > 0) {
              // TODO: This only works if the item is visible
              // (all its parents are expanded)
              // getExpandedDescendants, makeVisible
              makeVisible(getPathForRow(selectedRows[0]));
              scrollRowToVisible(selectedRows[0]);
          }
      }
  
      /**
       * Select any targets which are visible in the explorer pane
       */
      private void selectVisible(Object target) {
          for (int j = 0; j < getRowCount(); j++) {
              Object rowItem =
                      ((DefaultMutableTreeNode) getPathForRow(j)
                              .getLastPathComponent()).getUserObject();
              if (rowItem == target) {
                  addSelectionRow(j);
              }
          }
      }
  
  
      /**
       * Search the entire tree and select all instances of targets found.
       */
      private void selectAll(Set targets) {
          ExplorerTreeModel model = (ExplorerTreeModel) getModel();
          ExplorerTreeNode root = (ExplorerTreeNode) model.getRoot();  
          selectChildren(model, root, targets);
      }
      
      /*
       * Perform recursive search of subtree rooted at 'node', selecting all nodes
       * which have a userObject matching one of our targets.
       */
      private void selectChildren(ExplorerTreeModel model, ExplorerTreeNode node,
              Set targets) {
          if (targets.isEmpty()) {
              return;
          }
  
          Object nodeObject = node.getUserObject();
          if (nodeObject != null) {
              for (Object t : targets) {
                  if (t == nodeObject) {
                      addSelectionPath(new TreePath(node.getPath()));
                      // target may appear multiple places in the tree, so 
                      // we don't stop here (but it's expensive to search
                      // the whole tree) - tfm - 20070904
  //                  targets.remove(t);
  //                  break;
                  }
              }
          }
  
          model.updateChildren(new TreePath(node.getPath()));
  