PreferencesNode childNodeFor(Preferences child) {
   for (Enumeration stream = this.children(); stream.hasMoreElements(); ) {
     PreferencesNode childNode = (PreferencesNode) stream.nextElement();
     if (childNode.preferences() == child) {
       return childNode;
     }
   }
   throw new IllegalArgumentException(child.toString());
 }
 void exportSelectedNode() {
   PreferencesNode selectedNode = this.selectedPreferencesNode();
   if (selectedNode == null) {
     return;
   }
   JFileChooser fc = new JFileChooser();
   int rc = fc.showSaveDialog(this);
   if (rc != JFileChooser.APPROVE_OPTION) {
     return;
   }
   try {
     OutputStream stream =
         new BufferedOutputStream(new FileOutputStream(fc.getSelectedFile()), 2048);
     selectedNode.preferences().exportSubtree(stream);
     stream.close();
   } catch (IOException ex) {
     this.handleException(ex);
   } catch (BackingStoreException ex) {
     this.handleException(ex);
   }
 }
  void removeSelectedNode() {
    PreferencesNode selectedNode = this.selectedPreferencesNode();
    if (selectedNode == null || selectedNode.cannotBeRemoved()) {
      return;
    }

    TreePath postRemoveSelectionPath = this.calculatePostRemoveSelectionPath(selectedNode);
    // clear the selection *before* removing the node, so we are no longer
    // listening to the node when it gets deleted - it will be in an invalid state...
    this.treeSelectionModel.clearSelection();
    Preferences preferences = selectedNode.preferences();
    try {
      preferences.removeNode();
      // flush the change, so an event is fired and the parent node is updated
      preferences.flush();
    } catch (BackingStoreException ex) {
      this.handleException(ex);
      return; // skip the selection of the parent node...
    }
    this.treeSelectionModel.setSelectionPath(postRemoveSelectionPath);
  }
  void addChildToSelectedNode() {
    PreferencesNode selectedNode = this.selectedPreferencesNode();
    if (selectedNode == null) {
      return;
    }
    String name = this.promptForNodeName();
    if (name == null) {
      return;
    }

    Preferences preferences = selectedNode.preferences();
    // this will cause the preferences to be created if it does not already exist
    Preferences newPreferences = preferences.node(name);
    try {
      // flush the change, so an event is fired and the node is
      // created and added to the tree before we try to select it
      preferences.flush();
    } catch (BackingStoreException ex) {
      this.handleException(ex);
      return; // skip the selection of a node that might not be there...
    }
    PreferencesNode newNode = selectedNode.childNodeFor(newPreferences);
    this.treeSelectionModel.setSelectionPath(new TreePath(newNode.getPath()));
  }
  /** we can't simply rename the node - we have to clone it, then remove it... */
  void renameSelectedNode() {
    PreferencesNode selectedNode = this.selectedPreferencesNode();
    if (selectedNode == null || selectedNode.cannotBeRemoved()) {
      return;
    }

    String name = this.promptForNodeName();
    if (name == null) {
      return;
    }

    Preferences oldPreferences = selectedNode.preferences();
    PreferencesNode parentNode = (PreferencesNode) selectedNode.getParent();
    Preferences parentPreferences = parentNode.preferences();
    try {
      if (parentPreferences.nodeExists(name)) {
        // cannot rename to same name as existing node
        return;
      }
    } catch (BackingStoreException ex) {
      this.handleException(ex);
      return;
    }

    // clear the selection *before* removing the node, so we are no longer
    // listening to the node when it gets deleted - it will be in an invalid state...
    this.treeSelectionModel.clearSelection();
    Preferences newPreferences = parentPreferences.node(name);
    try {
      this.clone(oldPreferences, newPreferences);
      oldPreferences.removeNode();
      // flush the changes, so events are fired and the tree is updated
      parentPreferences.flush();
    } catch (BackingStoreException ex) {
      this.handleException(ex);
      return; // skip the selection of a node that might not be there...
    }
    PreferencesNode newNode = parentNode.childNodeFor(newPreferences);
    this.treeSelectionModel.setSelectionPath(new TreePath(newNode.getPath()));
  }
 /**
  * Calculate what the selection path should be once the specified node has been removed from the
  * tree.
  */
 private TreePath calculatePostRemoveSelectionPath(PreferencesNode node) {
   PreferencesNode parentNode = (PreferencesNode) node.getParent();
   int childCount = parentNode.getChildCount();
   if (childCount == 1) {
     // the only child is to be removed - select the parent
     return new TreePath(parentNode.getPath());
   }
   int nodeIndex = parentNode.getIndex(node);
   if (nodeIndex == childCount - 1) {
     // the last child in the list is to be removed - select the previous child
     return new TreePath(((PreferencesNode) parentNode.getChildAt(nodeIndex - 1)).getPath());
   }
   // by default, select the next child
   return new TreePath(((PreferencesNode) parentNode.getChildAt(nodeIndex + 1)).getPath());
 }
 private Preferences selectedPreferences() {
   PreferencesNode node = this.selectedPreferencesNode();
   return (node == null) ? null : node.preferences();
 }