protected final void loadChildren(DynamicNode node) throws DbException {
    if (node.hasLoaded() || node.isLeaf()) return;
    node.setHasLoaded();
    Object userObject = node.getUserObject();
    if (userObject == ROOT) return;
    SrVector children = new SrVector(10);
    boolean isSorted = true;
    DbObject dbParent = null;
    if (userObject == DB_RAM) {
      Db[] dbs = Db.getDbs();
      for (int i = 0; i < dbs.length; i++) {
        if (dbs[i] instanceof DbRAM) insertProjects(children, dbs[i]);
      }
    } else if (userObject instanceof Db) {
      insertProjects(children, (Db) userObject);
    } else {
      dbParent = (DbObject) userObject;
      dbParent.getDb().beginTrans(Db.READ_TRANS);
      insertComponents(children, dbParent);
      isSorted = childrenAreSorted(dbParent);
      dbParent.getDb().commitTrans();
    }

    if (isSorted) {
      children.sort(getComparator(dbParent));
    }

    ArrayList groupNodeList = new ArrayList();
    DynamicNode groupNode = null;
    Enumeration enumeration = children.elements();
    while (enumeration.hasMoreElements()) {
      DynamicNode childNode = (DynamicNode) enumeration.nextElement();
      GroupParams group = childNode.getGroupParams();
      if (group.name == null) {
        node.add(childNode);
      } else {
        if (groupNode == null) {
          groupNode = createGroupNode(group);
          node.add(groupNode);
          groupNodeList.add(groupNode);
        } else if (!groupNode.toString().equals(group.name)) {
          boolean groupFound = false;
          for (int i = 0; i < groupNodeList.size(); i++) {
            groupNode = (DynamicNode) groupNodeList.get(i);
            if (groupNode.toString().equals(group.name)) {
              groupFound = true;
              break;
            }
          }
          if (!groupFound) {
            groupNode = createGroupNode(group);
            node.add(groupNode);
            groupNodeList.add(groupNode);
          }
        }
        groupNode.add(childNode);
      }
    }
    groupNodeList.clear();
  }
 // This method updates the explorer for changes in a relation N where all
 // children are secondary nodes.
 // IMPORTANT: a node whose children are secondary nodes cannot have grouping
 // nodes.
 protected final void updateSecondaryChildren(DbUpdateEvent evt) throws DbException {
   if (!ApplicationContext.getSemanticalModel()
       .isVisibleOnScreen(evt.dbo, evt.neighbor, Explorer.class)) return;
   DynamicNode parentNode = getDynamicNode(evt.dbo, false);
   if (parentNode == null || !parentNode.hasLoaded()) return;
   DynamicNode childNode = null;
   int nb = getChildCount(parentNode);
   for (int i = 0; i < nb; i++) {
     DynamicNode node = (DynamicNode) getChild(parentNode, i);
     if (((DynamicNode) node.getUserObject()).getUserObject() == evt.neighbor) {
       childNode = node;
       break;
     }
   }
   if (evt.op == Db.REMOVE_FROM_RELN) {
     if (childNode != null) removeNodeFromParent(childNode);
   } else if (evt.op == Db.ADD_TO_RELN) {
     if (childNode == null) {
       childNode = createSecondaryNode(evt.dbo, evt.neighbor);
       int index = getInsertionIndex(evt.dbo, evt.neighbor, parentNode, childNode);
       insertNodeInto(childNode, parentNode, index);
     }
   } else { // Db.REINSERT_IN_RELN
     if (!childrenAreSorted(evt.dbo) && childNode != null) {
       removeNodeFromParent(childNode);
       int index = getInsertionIndex(evt.dbo, evt.neighbor, parentNode, childNode);
       insertNodeInto(childNode, parentNode, index);
     }
   }
 }
 protected final void refreshChildren(DynamicNode parentNode) throws DbException {
   int count = getChildCount(parentNode);
   for (int i = 0; i < count; i++) {
     DynamicNode node = (DynamicNode) getChild(parentNode, i);
     if (node.getUserObject() instanceof GroupParams) refreshChildren(node);
     else refresh(node);
   }
 }
 private DynamicNode getGroupNode(DynamicNode parentNode, GroupParams group, int iStart) {
   DynamicNode nodeFound = null;
   int count = getChildCount(parentNode);
   for (int i = iStart; i < count; i++) {
     DynamicNode node = (DynamicNode) getChild(parentNode, i);
     if (node.getUserObject() instanceof GroupParams && node.toString().equals(group.name)) {
       nodeFound = node;
       break;
     }
   }
   return nodeFound;
 }
 private DynamicNode getDynamicNode(DynamicNode parentNode, Object userObj, int iStart)
     throws DbException {
   DynamicNode nodeFound = null;
   int count = getChildCount(parentNode);
   for (int i = iStart; i < count; i++) {
     DynamicNode node = (DynamicNode) getChild(parentNode, i);
     if (node.getUserObject() == userObj) {
       nodeFound = node;
       break;
     }
   }
   return nodeFound;
 }
 private void refreshNode(DynamicNode srcNode, DynamicNode parentNode, int index)
     throws DbException {
   DynamicNode dstNode = getDynamicNode(parentNode, srcNode.getUserObject(), index);
   if (dstNode == null) {
     insertNodeInto(srcNode, parentNode, index);
   } else {
     if (dstNode != getChild(parentNode, index)) {
       removeNodeFromParent(dstNode);
       insertNodeInto(dstNode, parentNode, index);
     }
     if (dstNode.getUserObject() instanceof DynamicNode) {
       nodeChanged(dstNode); // in case text of primary node has
       // changed
     } else if (!dstNode.toString().equals(srcNode.toString())
         || dstNode.getIcon() != srcNode.getIcon()
         || (dstNode.getToolTips() != null
             && !dstNode.getToolTips().equals(srcNode.getToolTips()))) {
       dstNode.setDisplayText(srcNode.toString(), srcNode.getEditText());
       dstNode.setIcon(srcNode.getIcon());
       dstNode.setToolTips(srcNode.getToolTips());
       nodeChanged(dstNode);
     }
   }
 }
  // This method refreshes the display text of a node.
  protected final void updateNode(DbObject dbo) throws DbException {
    DynamicNode node = getDynamicNode(dbo, false);
    if (node == null) return;

    // backup selection and restore later
    Object focusObject = ApplicationContext.getFocusManager().getFocusObject();
    TreePath[] selPaths = null;
    if (focusObject instanceof ExplorerView) {
      selPaths = ((ExplorerView) focusObject).getSelectionPaths();
    }

    String displayText = getDisplayText(null, dbo);
    String editText = getEditText(null, dbo);
    String toolTipText = getToolTipsText(null, dbo);
    Icon icon = getIcon(dbo);

    node.setDisplayText(displayText, editText);
    node.setToolTips(toolTipText);
    node.setIcon(icon);
    nodeChanged(node);
    DynamicNode parentNode = (DynamicNode) node.getParent();
    Object parent = parentNode.getUserObject();
    if (!(parent instanceof DbObject) || childrenAreSorted((DbObject) parent)) {
      removeNodeFromParent(node);
      int index = getSortedIndex(parentNode, node);
      insertNodeInto(node, parentNode, index);
    }

    // Restore selection
    if (focusObject instanceof ExplorerView && selPaths != null) {
      ExplorerView explorerView = (ExplorerView) focusObject;
      try { // Should not occurs
        explorerView.setSelectionPaths(selPaths);
      } catch (Exception e) {
        explorerView.setSelectionPaths(new TreePath[] {});
      }
    }
  }
 // Remove the group node if this node is the last of its group.
 protected final void removeNode(DynamicNode node) {
   DynamicNode parentNode = (DynamicNode) node.getParent();
   if (parentNode.getUserObject() instanceof GroupParams && getChildCount(parentNode) == 1)
     removeNodeFromParent(parentNode);
   else removeNodeFromParent(node);
 }
  protected final void refresh(DynamicNode parentNode) throws DbException {
    if (ApplicationContext.getFocusManager().isGuiLocked()) return;

    if (parentNode == null) return;
    if (!parentNode.hasLoaded() || parentNode.isLeaf()) {
      if (parentNode.getUserObject() instanceof DbObject)
        updateNode((DbObject) parentNode.getUserObject());
      return;
    }
    Object userObject = parentNode.getUserObject();
    if (userObject == ROOT) {
      int count = getChildCount(parentNode);
      for (int i = 0; i < count; i++) {
        DynamicNode node = (DynamicNode) getChild(parentNode, i);
        userObject = node.getUserObject();
        if (userObject == DB_RAM) refresh(node);
        else {
          if (((Db) userObject).isValid()) {
            ((Db) userObject).beginTrans(Db.READ_TRANS);
            refresh(node);
            ((Db) userObject).commitTrans();
          } else {
            removeNode(node);
          }
        }
      }
      return;
    }
    if (userObject == DB_RAM) {
      int count = getChildCount(parentNode);
      for (int i = count - 1; i >= 0; i--) {
        DynamicNode node = (DynamicNode) getChild(parentNode, i);
        Db db = ((DbObject) node.getUserObject()).getDb();
        if (!db.isValid()) {
          removeNode(node);
          continue;
        }
        db.beginTrans(Db.READ_TRANS);
        refresh(node);
        // refresh the display text for the projects - we do not want to
        // apply a full update
        // using update(dbo) because we want to preserve the expanded
        // state for projects.
        node.setDisplayText(getDisplayText(null, (DbObject) node.getUserObject()));
        db.commitTrans();
      }
      // check for missing Db
      Db[] dbs = Db.getDbs();
      for (int i = 0; i < dbs.length; i++) {
        if (!dbs[i].isValid() || !(dbs[i] instanceof DbRAM)) continue;
        DynamicNode dbNode = getDynamicNode(parentNode, dbs[i], 0);
        if (dbNode != null) continue;
        dbs[i].beginTrans(Db.READ_TRANS);
        DbEnumeration dbEnum = dbs[i].getRoot().getComponents().elements(DbProject.metaClass);
        if (dbEnum.hasMoreElements()) {
          getDynamicNode(dbEnum.nextElement(), false);
        }
        dbEnum.close();
        dbs[i].commitTrans();
      }
      return;
    }

    SrVector children = new SrVector(10);
    if (userObject instanceof Db) {
      insertProjects(children, (Db) userObject);
      children.sort();
    } else if (((DbObject) userObject).isAlive()) {
      insertComponents(children, (DbObject) userObject);
      if (childrenAreSorted((DbObject) userObject))
        children.sort(getComparator((DbObject) userObject));
    }

    DynamicNode groupNode = null;
    int index = 0;
    int iGroup = 0;
    for (int i = 0; i < children.size(); i++) {
      DynamicNode srcNode = (DynamicNode) children.elementAt(i);
      GroupParams group = srcNode.getGroupParams();
      if (group.name == null) {
        refreshNode(srcNode, parentNode, index);
        index++;
      } else {
        if (groupNode == null || !groupNode.toString().equals(group.name)) {
          if (groupNode != null) deleteNodes(groupNode, iGroup);
          groupNode = getGroupNode(parentNode, group, index);
          if (groupNode == null) {
            groupNode = createGroupNode(group);
            insertNodeInto(groupNode, parentNode, index);
          } else if (groupNode != getChild(parentNode, index)) {
            removeNodeFromParent(groupNode);
            insertNodeInto(groupNode, parentNode, index);
          }
          index++;
          iGroup = 0;
        }
        refreshNode(srcNode, groupNode, iGroup);
        iGroup++;
      }
    }
    if (groupNode != null) deleteNodes(groupNode, iGroup);
    deleteNodes(parentNode, index);

    // Refresh subnodes in a separate pass to avoid interference from
    // automatic
    // adding of a primary node when adding a secondary node.
    refreshChildren(parentNode);
  }