I am trying to change the name of a node in my JTree. I use the following code to do so:
/**
* Change the name of the currently selected node
* @param newName Name to change the node too
*/
public void changeNodeName(String newName) {
//get the path to the selected nod
TreePath selectedPath = mainWindow.getStructureTree().getSelectionPath() ;
//make sure there is no other node with this name
DefaultMutableTreeNode node = (DefaultMutableTreeNode) selectedPath.getLastPathComponent();
//change its name
node.setUserObject(newName);
}
This code works ok. So say I want to rename node b in the picture below to c. The code does it correctly as the pictures illustrate.
However, if I then drag the node and place it somewhere else in the tree, its name returns to the original name of b.
So obviously I am not changing something correctly here. How do I or what do I change so the nodes value stays changed?
Thanks
EDIT:
I have a class which extends DefaultMutableTreeNode. Here is the source
package Structure;
import GUI.Window;
import Logging.LogRunner;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JSeparator;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
/**
* This class provides the basic functionality that all subclass of the structre
* will need such as a pop up menu, and adding new nodes.
* @author dvargo
*/
public abstract class BCStructure extends DefaultMutableTreeNode
{
/**
* The root node to which this class belongs
*/
DefaultMutableTreeNode root;
/**
* Reference to the main window
*/
Window mainWindow;
/**
* Name of this node
*/
String name;
/**
* The pop up menu
*/
JPopupMenu Pmenu;
/**
* The pop up menu intems
*/
JMenuItem deleteMenuItem,renameMenuItem,newSectionMenuItem,newPageMenuItem;
/**
* What type of node this is
*/
String type;
/**
* Basic constructor that adds a pop up menu, sets the name, and initalizes values
* @param newName - Name for this node
* @param inWindow - Reference to the main window.
*/
public BCStructure(String newName,Window inWindow)
{
this(newName,inWindow,true);
}
/**
* Returns the type of node this is
* @return Page if the node is a page, Module if the node is a module, Section
* if the node is a section
*/
public String getType()
{
return type;
}
/**
* Returns a copy of this node
* @return
*/
public abstract BCStructure copy();
/**
* If this is a page, this constructor should be called, it will not allof a page to
*have any children
* @param newName - Name for the page
* @param inWindow - Refernce to the main window
* @param letChildren - False to disallow this node from having children
*/
public BCStructure(String newName,Window inWindow,boolean letChildren)
{
super(newName,letChildren);
mainWindow = inWindow;
name = newName;
//add the popup menu
addPopUp();
}
/**
* Updates a specific node
* @param parentNode The parent node to update
*/
public void update(DefaultMutableTreeNode parentNode)
{
((DefaultTreeModel)mainWindow.getStructureTree().getModel()).reload(parentNode);
mainWindow.getStructureTree().repaint();
}
/**
* Returns the node that is currently selected (by being clicked on) in the tree
* @return Node that is selected in the tree
*/
public DefaultMutableTreeNode getSelectedNode()
{
return (DefaultMutableTreeNode)mainWindow.getStructureTree().getLastSelectedPathComponent();
}
/**
* Returns the TreePath to this node
* @return The TreePath to this node
*/
public TreePath getTreePath()
{
return new TreePath(this.getPath());
}
/**
* Sets the selected node in the tree
* @param node The node to set selected in the tree
*/
public void setSelectedNode(BCStructure node)
{
mainWindow.getStructureTree().setSelectionPath(new TreePath(node.getPath()));
update(node);
}
/**
* Change the name of the currently selected node
* @param newName Name to change the node too
*/
public void changeNodeName(String newName) {
//get the path to the selected nod
TreePath selectedPath = mainWindow.getStructureTree().getSelectionPath() ;
//make sure there is no other node with this name
DefaultMutableTreeNode node = (DefaultMutableTreeNode) selectedPath.getLastPathComponent();
DefaultMutableTreeNode nodeParent = (DefaultMutableTreeNode) node.getParent();
if(nodeParent != null)
{
for(int i = 0; i lt nodeParent.getChildCount(); i++)
{
DefaultMutableTreeNode currNode = (DefaultMutableTreeNode) nodeParent.getChildAt(i);
if(currNode.getUserObject().equals(newName))
{
JOptionPane.showMessageDialog(mainWindow,"Another page or section already has this name in this level. Please select another.");
return;
}
}
}
//change its name
node.setUserObject(newName);
//mainWindow.getStructureTree().getModel().valueForPathChanged(selectedPath, newName);
update(getSelectedNode());
}
/**
* Adds a new section node to the tree
* @param newName Name for this node
*/
public void addNewSectionNode(String newName) {
DefaultMutableTreeNode temp = getSelectedNode();
Section newNode = null;
if(temp == null)
{
LogRunner.dialogMessage(this.getClass(),"Please select a node to add this section to.");
}
else
{
newNode = new Section(newName,mainWindow);
try
{
temp.add(newNode);
}
catch(java.lang.IllegalStateException e)
{
LogRunner.getLogger().warning("You can not add a section to a page");
temp = (DefaultMutableTreeNode) temp.getParent();
temp.add(newNode);
}
}
//set the selected node to the previously selected node
update(temp);
if(newNode != null)
{
mainWindow.getStructureTree().setSelectionPath(new TreePath(newNode.getPath()));
}
}
/**
* Adds a new page to this tree
* @param newName Name for the node
* @return The newly created page
*/
public Page addNewPageNode(String newName)
{
TreePath oldPath = mainWindow.getStructureTree().getSelectionPath();
//Section newSection = new Section(newSectionName);
DefaultMutableTreeNode temp = getSelectedNode();
Page newPage = null;
if(temp == null)
{
LogRunner.dialogMessage(this.getClass(),"Please select a module or section to add this section to.");
}
else
{
newPage = new Page(newName,mainWindow);
try
{
temp.add(newPage);
}
catch(java.lang.IllegalStateException e)
{
LogRunner.getLogger().warning("You can not add any more nodes to a page.");
temp = (DefaultMutableTreeNode) temp.getParent();
temp.add(newPage);
}
}
update(temp);
mainWindow.getStructureTree().setSelectionPath(oldPath);
return newPage;
}
/**
* Propmpts the user to entere a new name for a node that is selected
*/
private void rename()
{
String newname = JOptionPane.showInputDialog("New name?");
changeNodeName(newname);
}
/**
* Deletes the selected node from the tree
*/
private void delete()
{
DefaultMutableTreeNode node = (DefaultMutableTreeNode)mainWindow.getStructureTree().getLastSelectedPathComponent();
if(node == null) return;
DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode)(node.getParent());
if(parentNode == null) return;
//remove node
parentNode.remove(node);
((DefaultTreeModel)mainWindow.getStructureTree().getModel()).reload(parentNode);
}
/**
* Deletes a specific node from the tree
* @param node The node to delete
*/
protected void delete(DefaultMutableTreeNode node)
{
if(node == null) return;
DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode)(node.getParent());
if(parentNode == null) return;
//remove node
parentNode.remove(node);
((DefaultTreeModel)mainWindow.getStructureTree().getModel()).reload(parentNode);
}
/**
* Adds the popup menu functionality to the tree
*/
private void addPopUp()
{
Pmenu = new JPopupMenu();
newSectionMenuItem = new JMenuItem("Add New Section");
Pmenu.add(newSectionMenuItem);
newPageMenuItem = new JMenuItem("Add New Page");
Pmenu.add(newPageMenuItem);
Pmenu.add(new JSeparator());
deleteMenuItem = new JMenuItem("Delete");
Pmenu.add(deleteMenuItem);
renameMenuItem = new JMenuItem("Rename");
Pmenu.add(renameMenuItem);
//add actionlisteners to the menu items
deleteMenuItem.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
delete();}
}
);
renameMenuItem.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
rename();}
}
);
newSectionMenuItem.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
mainWindow.createNewSectionPublicCall();}
}
);
newPageMenuItem.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
mainWindow.createNewPagePublicCall();}
}
);
//add action listener to the tree
mainWindow.getStructureTree().addMouseListener(new MouseAdapter()
{
public void mouseReleased(MouseEvent Me)
{
if(Me.isPopupTrigger())
{
Pmenu.show(Me.getComponent(), Me.getX(), Me.getY());
}
}
});
if(getClass().equals(Page.class))
{
newSectionMenuItem.setEnabled(false);
}
}
/**
* Returns all the nodes in this tree from doing a left heavy recursive
* traversal of the tree from the given root
* @param root The root from which to start the search
* @return A list of the nodes
*/
public ArrayList getAllNodesInOrder(BCStructure root)
{
ArrayList nodes = new ArrayList();
getAllNodesInOrderRec(root, nodes);
return nodes;
}
/**
* Recursive function that gets the nodes in the tree
* @param currNode
* @param theNodes
*/
private void getAllNodesInOrderRec(BCStructure currNode, ArrayList theNodes)
{
theNodes.add(currNode);
for(int i = 0; i lt currNode.getChildCount(); i++)
{
currNode.getAllNodesInOrderRec((BCStructure) currNode.getChildAt(i), theNodes);
}
}
}
And in the example above, the actual nodes you are seeing are a subclass of BCStructure called Page. This is the actual class that I am renaming.
package Structure;
import Components.BCFrame;
import Components.Basic.BackGroundImage;
import GUI.Window;
import Logging.LogRunner;
import XMLProcessing.XMLWriter;
import java.awt.Color;
import java.awt.Dimension;
import java.util.ArrayList;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.tree.DefaultTreeCellRenderer;
/**
* This class is responcible for holding the components the make up a page and
* is accessible through the tree structure. In other words, this class is what
* actually makes up a page. It holds the componenets in an array, and since it
* node in a tree, it can be notified when it has been clicked, and load the
* compoenents it is holding.
* @author dvargo
*/
public class Page extends BCStructure
{
/**
* Holds all the componenets in the content pane so an action can be done on
* all componenets. Also sets the added component to the current component.
*/
private ArrayList theComponents = new ArrayList()
{
@Override
public boolean add(BCFrame e)
{
e.setPage(selfReference);
return super.add(e);
}
};
/**
* Self reference to this page
*/
private Page selfReference = this;
/**
* The dimensions of this page. It defualts to a medium page size
*/
private Dimension pageSize = Window.NORMAL;
/**
* This bages background;
*/
private BackGroundImage background;
/**
* Constructor that sets the node up in the tree and inializes values.
* @param newName - Name for this node
* @param inWindow - Reference to the main window
* @param inRoot - The section or module that is the root for this page.
*/
public Page(String newName, Window inWindow)
{
super(newName, inWindow,false);
DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();
ImageIcon theImage = new ImageIcon(new JFrame().getToolkit().getImage(getClass().getResource("/GUI/fileIcon.png")));
renderer.setLeafIcon(theImage);
//set the background color to white, there will always be a background
background = new BackGroundImage(0,0,pageSize.width,pageSize.height,mainWindow);
background.setColor(Color.WHITE);
theComponents.add(background);
//you must add this to the content pane to keep indexes correct. it will not display anything though
mainWindow.getComponentContentPane().add(background,0);
mainWindow.getContentPanePanel().repaint();
}
/**
* Loads all the componenets held in the arraylist to to the screen.
*/
public void loadPage()
{
//remove the background of the previous page
mainWindow.getComponentContentPane().removeAll();
mainWindow.setPageSizeComboSeleted(pageSize);
background.setSize(pageSize);
mainWindow.getComponentContentPane().setPreferredSize(pageSize);
mainWindow.getComponentContentPane().setSize(pageSize);
for(BCFrame currentComp : theComponents)
{
mainWindow.getComponentContentPane().add(currentComp);
currentComp.setVisible(true);
currentComp.revalidate();
currentComp.repaint();
currentComp.setPage(this);
}
mainWindow.getComponentContentPane().repaint();
mainWindow.getComponentContentPane().revalidate();
}
/**
* Writes the componenets to file in XML.
* @param filePath - The path and name of the file to write.
*/
public void save(String filePath)
{
XMLWriter theWriter = new XMLWriter();
for(int i = 0; i newComponents)
{
theComponents = newComponents;
boolean backgroundExists = false;
for(BCFrame curr : theComponents)
{
if(curr.getClass().equals(BackGroundImage.class))
{
background = (BackGroundImage) curr; //make sure background isnt null
backgroundExists = true;
}
curr.setPage(this);
}
if(backgroundExists)
{
return;
}
LogRunner.getLogger().severe("Could not find a background while setting the components, adding a new dfualt white one");
BackGroundImage bgi= new BackGroundImage();
bgi.setSize(pageSize);
bgi.setColor(Color.WHITE);
theComponents.add(bgi);
background = bgi;
}
public ArrayList getComponents()
{
return theComponents;
}
}