0

Duplicate last tree node

asked 2011-08-03 13:25:02 +0800

valmar gravatar image valmar
925 2 13
http://www.timo-ernst.net

Hi everyone,

I got a very strange bug going on here in a tree component, which should look like this:

- [email protected]
  INBOX
  Stuff
- [email protected]
  - foo
    ddd
    jsfh

This tree displays two email accounts. Each account gets created in a separate thread. In each thread I create TreeNode instances and add them to the parent node one by one.

Now, the strange thing is, when I run the application, I get this: http://dl.dropbox.com/u/17844821/zeug/zk_tree_duplicate.jpg

As you can see, the last account is getting duplicated. When I open that node, I get a NullPointerException and the child nodes ("ddd" and "jsfh") are not there.

So, I started to debug. My first thought was: Is the tree messing up something or is the model I created corrupt?

To test this, I added a custom tree item renderer which prints the whole TreeModel hierarchy to the console whenever the renderer for a tree item gets called.

This gave me the following:

20:11:53,120  INFO MailAccountTree:51 - [email protected]
20:11:53,120  INFO MailAccountTree:51 - INBOX
20:11:53,121  INFO MailAccountTree:51 - Stuff

20:11:53,121  INFO MailAccountTree:51 - [email protected]
20:11:53,121  INFO MailAccountTree:51 - INBOX
20:11:53,121  INFO MailAccountTree:51 - foo
20:11:53,121  INFO MailAccountTree:51 - ddd
20:11:53,121  INFO MailAccountTree:51 - jsfh

As you can see, the model does NOT contain the duplicate. So what's going on here?

delete flag offensive retag edit

7 Replies

Sort by ยป oldest newest

answered 2011-08-03 13:54:43 +0800

marcelodecampos gravatar image marcelodecampos
183

Hi, Valmar!

Could you isolate your source code and post here, so we can see what's happening???

link publish delete flag offensive edit

answered 2011-08-03 19:18:35 +0800

valmar gravatar image valmar
925 2 13
http://www.timo-ernst.net

updated 2011-08-03 19:27:29 +0800

Sure, here it goes:

This creates the model for the tree:

for (MailAccount mailAccount : mailAccounts){
	TreeNode node = toNode(mailAccount, true);
	TreeModel model = tree.getModel();
	TreeNode root = (TreeNode) model.getRoot();
	addNode(root, node);
}

Helper functions:

private void addNode(final TreeNode parent, final TreeNode node) {
	Executions.schedule(desktop, new EventListener() {
		@Override
		public void onEvent(Event event) throws Exception {
			parent.add(node);
		}
	}, null);
}

/**
 * Converts the given mail account into a tree node
 * 
 * @param account
 *            The mail account to convert
 * @return The tree node
 * @throws MessagingException
 *             Thrown if something went wrong while checking the mail
 *             account's content (e.g. folders)
 */
public static TreeNode toNode(MailAccount account, boolean recursive) throws MessagingException {
	SmampiTreeNode rootNode = null;
	if (account != null) {
		IncomingMailServer incomingServer = account.getIncomingServer();
		if (incomingServer != null) {
			Set<CachedFolder> cachedFolders = incomingServer.getCachedFolders();
			List<TreeNode> children = new Vector<TreeNode>();

			/*
			 * Create a node for each folder in the mail account
			 * (recursively with all subfolders)
			 */
			if (recursive) {
				if (cachedFolders != null) {
					List<CachedFolder> tmpCachedFolders = new ArrayList<CachedFolder>(cachedFolders);
					for (CachedFolder tmpCachedFolder : tmpCachedFolders) {
						TreeNode folderNode = toNode(tmpCachedFolder, true);
						if (tmpCachedFolder.isInbox(true)) {
							// Put INBOX to the top
							children.add(0, folderNode);
							// Set this folder as the inbox
							tmpCachedFolder.setFolderType(FolderType.INBOX, true);
						} else {
							children.add(folderNode);
						}
					}
				}
			}

			if (children != null) {
				if (children.size() <= 0) {
					children = null;
				}
			}

			// Create the node for "account" and its children and return it
			rootNode = new SmampiTreeNode(account, children);
		}
	}
	return rootNode;
}

/**
 * Converts the given folder into a tree node
 * 
 * @param cachedFolder
 *            The folder to convert
 * @return The tree node
 * @throws MessagingException
 *             Thrown if something went wrong during conversion.
 */
public static TreeNode toNode(CachedFolder cachedFolder, boolean recursive) throws MessagingException {

	Set<CachedFolder> cachedFolders = cachedFolder.getCachedFolders(true);
	List<TreeNode> children = new Vector<TreeNode>();

	// Recursively transform each (sub-)folder into a tree node
	if (recursive) {
		if (cachedFolders != null) {
			List<CachedFolder> tmpCachedFolders = new ArrayList<CachedFolder>(cachedFolders);
			for (CachedFolder tmpCachedFolder : tmpCachedFolders) {
				TreeNode node = null;
				if (tmpCachedFolder.holdsFolders(true)) {
					node = toNode(tmpCachedFolder, true);
					children.add(node);
				} else {
					node = toNode(tmpCachedFolder, true);
					children.add(node);
				}
			}
		}
	}

	if (children != null) {
		if (children.size() <= 0) {
			children = null;
		}
	}

	// Create the node for cachedFolder and return it
	TreeNode rootNode = new SmampiTreeNode(cachedFolder, children);
	return rootNode;
}

The custom TreeNode:

/**
 * Own implementation of the ZK TreeNode. Will correctly return true or false if
 * isLeaf() is called.
 */
public class SmampiTreeNode extends DefaultTreeNode {

	private static final long	serialVersionUID	= 5343670451152165601L;
	private boolean				_leaf;

	/**
	 * Constructor method
	 * 
	 * @param data
	 *            The data
	 * @param children
	 *            The children as collection
	 */
	public SmampiTreeNode(Object data, Collection<TreeNode> children) {
		super(data, children);
		if (getChildCount() == 0) {
			_leaf = true;
		}
	}

	/**
	 * Constructor method
	 * 
	 * @param data
	 *            The data
	 * @param children
	 *            The children as array
	 */
	public SmampiTreeNode(Object data, SmampiTreeNode[] children) {
		super(data, children);
		if (getChildCount() == 0) {
			_leaf = true;
		}
	}

	@Override
	public void insert(TreeNode child, int index) {
		if (child != null) {
			_leaf = false;
			super.insert(child, index);
			if (getChildCount() == 0) {
				_leaf = true;
			}
		}
	}

	@Override
	public boolean isLeaf() {
		return _leaf && getChildCount() == 0;
	}

}

link publish delete flag offensive edit

answered 2011-08-04 18:02:04 +0800

valmar gravatar image valmar
925 2 13
http://www.timo-ernst.net

Soooo,
does anyone have an idea? :-)

link publish delete flag offensive edit

answered 2011-08-04 18:44:08 +0800

TonyQ gravatar image TonyQ
642
https://www.masterbranch....

updated 2011-08-04 18:44:55 +0800

Sorry , I am not actually get the process well , since what I see is how you add the node to the treemodel root ,
but it's still hard to trace what's the real process when you run it from your sample code.


Would you mind to test with tree.invalidate or try to set the model again after you add the node to root?


A quick guess is that there's a data sync issue in the treemodel,
but I am not sure which part is going wrong since I don't have a reproducible case.

link publish delete flag offensive edit

answered 2011-08-05 05:28:00 +0800

valmar gravatar image valmar
925 2 13
http://www.timo-ernst.net

updated 2011-08-05 05:28:38 +0800

Tony, you're a genius.

calling

tree.setModel(tree.getModel());

after adding all nodes did the trick!

(Smells like a ZK bug though)

link publish delete flag offensive edit

answered 2011-08-05 12:12:51 +0800

TonyQ gravatar image TonyQ
642
https://www.masterbranch....

Yes , if it works after you call setModel , it's more like a bug for ZK.


Let me try to reproduce it , and will inform you if I find anything. :P

link publish delete flag offensive edit

answered 2011-08-05 16:15:03 +0800

valmar gravatar image valmar
925 2 13
http://www.timo-ernst.net

Sure,

one thing though: I am processing each account in a seperate thread, so the first lines are more like:

for (MailAccount mailAccount : mailAccounts){
	Thread t = new Thread(){
		@Overide
		public void run(){
			TreeNode node = toNode(mailAccount, true);
			TreeModel model = tree.getModel();
			TreeNode root = (TreeNode) model.getRoot();
			addNode(root, node);
		}
	}
	t.start();
}

May that's causing the trouble.

link publish delete flag offensive edit
Your reply
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!

[hide preview]

Question tools

Follow

RSS

Stats

Asked: 2011-08-03 13:25:02 +0800

Seen: 461 times

Last updated: Aug 05 '11

Support Options
  • Email Support
  • Training
  • Consulting
  • Outsourcing
Learn More