TreeList bug?

View: New views
3 Messages — Rating Filter:   Alert me  

TreeList bug?

by avitaln :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi

I am trying to build a tree table from a flat list, just like encouraged by GL but with one small difference: the source list contains all nodes and not just the leaves.
For this purpose, I wrote a FilterList which filters out the non leaf elements.

When windows is shown I see this tree table:

code1/name1
        code11/name11
        code12/name12
code2/name2
        code21/name21
        code22/name22

Now the user is updating name2 cell. What happens is that EventTableModel.setValueAt is trying to refresh row 3
this means that treeList.set(3, treeList.get(3)); is called.

After this call the tree looks like this (one element was lost!!!)

code1/name1
        code11/name11
code2/name2
        code21/name21
        code22/name22
       
       
I wrote a small program which demonstrate the problem:

------ code start -------

import java.util.Comparator;
import java.util.List;
import java.util.Map;

import ca.odell.glazedlists.BasicEventList;
import ca.odell.glazedlists.EventList;
import ca.odell.glazedlists.FilterList;
import ca.odell.glazedlists.FunctionList;
import ca.odell.glazedlists.GlazedLists;
import ca.odell.glazedlists.TreeList;
import ca.odell.glazedlists.TreeList.Format;
import ca.odell.glazedlists.matchers.Matcher;

public class TreeListBug {
   
    private TreeList<Item> treeList;
   
    public TreeListBug() {
        // prepare the source list
        final EventList<Item> eventList = new BasicEventList<Item>();
        Item sect1 = new Item(null, "code1", "name1");
        Item sect11 = new Item(sect1, "code11", "name11");
        Item sect12 = new Item(sect1, "code12", "name12");
        final Item sect2 = new Item(null, "code2", "name2");
        Item sect21 = new Item(sect2, "code21", "name21");
        Item sect22 = new Item(sect2, "code22", "name22");
        eventList.add(sect1);
        eventList.add(sect2);
        eventList.add(sect11);
        eventList.add(sect12);
        eventList.add(sect21);
        eventList.add(sect22);
       
        // A trivial tree format - defined by item.parent
        Format format = new Format<Item>() {
            public boolean allowsChildren(Item element) { return true; }
            public Comparator<? extends Item> getComparator(int depth) { return null; }
            public void getPath(List<Item> path, Item item) {
                Item parent = item.parent;
                while (parent != null) {
                    path.add(0, parent);
                    parent = parent.parent;
                }
                path.add(item);
            }
        };
       
        // Build a decorated list which contains only the leaves
        OnlyLeavesMatcher matcher = new OnlyLeavesMatcher(eventList);
        EventList<Item> onlyLeaves = new FilterList<Item>(eventList, matcher);
       
        // Build the treeList from the onlyLeaves list
        treeList = new TreeList<Item>(onlyLeaves, format, TreeList.NODES_START_EXPANDED);
       
        System.err.println("eventList="+eventList);
        System.err.println("treeList="+treeList);
        System.err.println("onlyLeaves="+onlyLeaves);
       
        System.err.println("refreshing item 3 in treeList...");
       
        Item item = treeList.get(3);
        treeList.set(3, item);
       
        System.err.println("eventList="+eventList);
        System.err.println("treeList="+treeList);
        System.err.println("onlyLeaves="+onlyLeaves);
    }
   
    // A matcher which will filter out nodes which are not leaves
    private static class OnlyLeavesMatcher implements Matcher<Item> {
       
        private Map<Integer, List<Item>> mapByParent;    

        public OnlyLeavesMatcher(EventList<Item> eventList) {
            mapByParent = GlazedLists.syncEventListToMultiMap(eventList, new IdentityOfParentFunction());
        }

        public boolean matches(Item item) {
            List<Item> children = mapByParent.get(new Integer(System.identityHashCode(item)));
            if (children == null || children.isEmpty()) {
                return true;
            }
            return false;
        }
       
        private static class IdentityOfParentFunction implements FunctionList.Function<Item,Integer> {
            public Integer evaluate(Item item) {
                Object parent = item.parent;
                if (parent == null) {
                    return 0;
                }
                return System.identityHashCode(parent);
            }
        }
    }
   
    public static class Item {
        public String code;
        public String name;
        public Item parent;
       
        public Item(Item parent, String code, String name) {
            this.parent = parent;
            this.code = code;
            this.name = name;
        }
        public String toString() { return code+"/"+name; }
    }

    public static void main(String[] args) {
        new TreeListBug();
    }
}


------ code ends --------


Any idea?

Thanks in advance
       
Avital





Re: TreeList bug?

by avitaln :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi again. I have just noticed that the problems also happens even without the "only leaves" filter

Just by updating one of the TreeList elements - the structure is getting messy.

Here is a trivial program that demonstrate the problem:


----- code start -----

import java.util.Comparator;
import java.util.List;

import ca.odell.glazedlists.BasicEventList;
import ca.odell.glazedlists.EventList;
import ca.odell.glazedlists.TreeList;
import ca.odell.glazedlists.TreeList.Format;

public class TreeListBug {
   
    private TreeList<Item> treeList;
   
   
    public TreeListBug() {
        // prepare the source list
        final EventList<Item> eventList = new BasicEventList<Item>();
        Item sect1 = new Item(null, "code1", "name1");
        Item sect11 = new Item(sect1, "code11", "name11");
        Item sect12 = new Item(sect1, "code12", "name12");
        final Item sect2 = new Item(null, "code2", "name2");
        Item sect21 = new Item(sect2, "code21", "name21");
        Item sect22 = new Item(sect2, "code22", "name22");

        eventList.add(sect11);
        eventList.add(sect12);
        eventList.add(sect21);
        eventList.add(sect22);
       
        // A trivial tree format - defined by item.parent
        Format format = new Format<Item>() {
            public boolean allowsChildren(Item element) { return true; }
            public Comparator<? extends Item> getComparator(int depth) { return null; }
            public void getPath(List<Item> path, Item item) {
                Item parent = item.parent;
                while (parent != null) {
                    path.add(0, parent);
                    parent = parent.parent;
                }
                path.add(item);
            }
        };
       
        treeList = new TreeList<Item>(eventList, format, TreeList.NODES_START_EXPANDED);
       
        System.err.println("eventList="+eventList);
        System.err.println("treeList="+treeList);
       
        System.err.println("refreshing item 3 in treeList...");
       
        Item item = treeList.get(3);
        treeList.set(3, item);
       
        System.err.println("eventList="+eventList);
        System.err.println("treeList="+treeList);
       
       
    }
   
    public static class Item {
        public String code;
        public String name;
        public Item parent;
       
        public Item(Item parent, String code, String name) {
            this.parent = parent;
            this.code = code;
            this.name = name;
        }
        public String toString() { return code+"/"+name; }
    }

    public static void main(String[] args) {
        new TreeListBug();
    }

}


----- code ends -----


Thanks again for help

Avital



avitaln wrote:
Hi

I am trying to build a tree table from a flat list, just like encouraged by GL but with one small difference: the source list contains all nodes and not just the leaves.
For this purpose, I wrote a FilterList which filters out the non leaf elements.

When windows is shown I see this tree table:

code1/name1
        code11/name11
        code12/name12
code2/name2
        code21/name21
        code22/name22

Now the user is updating name2 cell. What happens is that EventTableModel.setValueAt is trying to refresh row 3
this means that treeList.set(3, treeList.get(3)); is called.

After this call the tree looks like this (one element was lost!!!)

code1/name1
        code11/name11
code2/name2
        code21/name21
        code22/name22
       
       
I wrote a small program which demonstrate the problem:

------ code start -------

import java.util.Comparator;
import java.util.List;
import java.util.Map;

import ca.odell.glazedlists.BasicEventList;
import ca.odell.glazedlists.EventList;
import ca.odell.glazedlists.FilterList;
import ca.odell.glazedlists.FunctionList;
import ca.odell.glazedlists.GlazedLists;
import ca.odell.glazedlists.TreeList;
import ca.odell.glazedlists.TreeList.Format;
import ca.odell.glazedlists.matchers.Matcher;

public class TreeListBug {
   
    private TreeList<Item> treeList;
   
    public TreeListBug() {
        // prepare the source list
        final EventList<Item> eventList = new BasicEventList<Item>();
        Item sect1 = new Item(null, "code1", "name1");
        Item sect11 = new Item(sect1, "code11", "name11");
        Item sect12 = new Item(sect1, "code12", "name12");
        final Item sect2 = new Item(null, "code2", "name2");
        Item sect21 = new Item(sect2, "code21", "name21");
        Item sect22 = new Item(sect2, "code22", "name22");
        eventList.add(sect1);
        eventList.add(sect2);
        eventList.add(sect11);
        eventList.add(sect12);
        eventList.add(sect21);
        eventList.add(sect22);
       
        // A trivial tree format - defined by item.parent
        Format format = new Format<Item>() {
            public boolean allowsChildren(Item element) { return true; }
            public Comparator<? extends Item> getComparator(int depth) { return null; }
            public void getPath(List<Item> path, Item item) {
                Item parent = item.parent;
                while (parent != null) {
                    path.add(0, parent);
                    parent = parent.parent;
                }
                path.add(item);
            }
        };
       
        // Build a decorated list which contains only the leaves
        OnlyLeavesMatcher matcher = new OnlyLeavesMatcher(eventList);
        EventList<Item> onlyLeaves = new FilterList<Item>(eventList, matcher);
       
        // Build the treeList from the onlyLeaves list
        treeList = new TreeList<Item>(onlyLeaves, format, TreeList.NODES_START_EXPANDED);
       
        System.err.println("eventList="+eventList);
        System.err.println("treeList="+treeList);
        System.err.println("onlyLeaves="+onlyLeaves);
       
        System.err.println("refreshing item 3 in treeList...");
       
        Item item = treeList.get(3);
        treeList.set(3, item);
       
        System.err.println("eventList="+eventList);
        System.err.println("treeList="+treeList);
        System.err.println("onlyLeaves="+onlyLeaves);
    }
   
    // A matcher which will filter out nodes which are not leaves
    private static class OnlyLeavesMatcher implements Matcher<Item> {
       
        private Map<Integer, List<Item>> mapByParent;    

        public OnlyLeavesMatcher(EventList<Item> eventList) {
            mapByParent = GlazedLists.syncEventListToMultiMap(eventList, new IdentityOfParentFunction());
        }

        public boolean matches(Item item) {
            List<Item> children = mapByParent.get(new Integer(System.identityHashCode(item)));
            if (children == null || children.isEmpty()) {
                return true;
            }
            return false;
        }
       
        private static class IdentityOfParentFunction implements FunctionList.Function<Item,Integer> {
            public Integer evaluate(Item item) {
                Object parent = item.parent;
                if (parent == null) {
                    return 0;
                }
                return System.identityHashCode(parent);
            }
        }
    }
   
    public static class Item {
        public String code;
        public String name;
        public Item parent;
       
        public Item(Item parent, String code, String name) {
            this.parent = parent;
            this.code = code;
            this.name = name;
        }
        public String toString() { return code+"/"+name; }
    }

    public static void main(String[] args) {
        new TreeListBug();
    }
}


------ code ends --------


Any idea?

Thanks in advance
       
Avital




Re: TreeList bug?

by avitaln :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


Hi again

I found the issue. The TreeList contains more elements than the source eventList.
When calling TreeList.set - GL tries to do a reverse update but it is impossible to translate the index back to the source list since some elements do not exist (non leaves elements).

The workaround for now is to decorate the TreeList and ignore the "set" calls.

Avital



Hi again. I have just noticed that the problems also happens even without the "only leaves" filter

Just by updating one of the TreeList elements - the structure is getting messy.

Here is a trivial program that demonstrate the problem:


----- code start -----

import java.util.Comparator;
import java.util.List;

import ca.odell.glazedlists.BasicEventList;
import ca.odell.glazedlists.EventList;
import ca.odell.glazedlists.TreeList;
import ca.odell.glazedlists.TreeList.Format;

public class TreeListBug {
   
    private TreeList<Item> treeList;
   
   
    public TreeListBug() {
        // prepare the source list
        final EventList<Item> eventList = new BasicEventList<Item>();
        Item sect1 = new Item(null, "code1", "name1");
        Item sect11 = new Item(sect1, "code11", "name11");
        Item sect12 = new Item(sect1, "code12", "name12");
        final Item sect2 = new Item(null, "code2", "name2");
        Item sect21 = new Item(sect2, "code21", "name21");
        Item sect22 = new Item(sect2, "code22", "name22");

        eventList.add(sect11);
        eventList.add(sect12);
        eventList.add(sect21);
        eventList.add(sect22);
       
        // A trivial tree format - defined by item.parent
        Format format = new Format<Item>() {
            public boolean allowsChildren(Item element) { return true; }
            public Comparator<? extends Item> getComparator(int depth) { return null; }
            public void getPath(List<Item> path, Item item) {
                Item parent = item.parent;
                while (parent != null) {
                    path.add(0, parent);
                    parent = parent.parent;
                }
                path.add(item);
            }
        };
       
        treeList = new TreeList<Item>(eventList, format, TreeList.NODES_START_EXPANDED);
       
        System.err.println("eventList="+eventList);
        System.err.println("treeList="+treeList);
       
        System.err.println("refreshing item 3 in treeList...");
       
        Item item = treeList.get(3);
        treeList.set(3, item);
       
        System.err.println("eventList="+eventList);
        System.err.println("treeList="+treeList);
       
       
    }
   
    public static class Item {
        public String code;
        public String name;
        public Item parent;
       
        public Item(Item parent, String code, String name) {
            this.parent = parent;
            this.code = code;
            this.name = name;
        }
        public String toString() { return code+"/"+name; }
    }

    public static void main(String[] args) {
        new TreeListBug();
    }

}


----- code ends -----


Thanks again for help

Avital



avitaln wrote:
Hi

I am trying to build a tree table from a flat list, just like encouraged by GL but with one small difference: the source list contains all nodes and not just the leaves.
For this purpose, I wrote a FilterList which filters out the non leaf elements.

When windows is shown I see this tree table:

code1/name1
        code11/name11
        code12/name12
code2/name2
        code21/name21
        code22/name22

Now the user is updating name2 cell. What happens is that EventTableModel.setValueAt is trying to refresh row 3
this means that treeList.set(3, treeList.get(3)); is called.

After this call the tree looks like this (one element was lost!!!)

code1/name1
        code11/name11
code2/name2
        code21/name21
        code22/name22
       
       
I wrote a small program which demonstrate the problem:

------ code start -------

import java.util.Comparator;
import java.util.List;
import java.util.Map;

import ca.odell.glazedlists.BasicEventList;
import ca.odell.glazedlists.EventList;
import ca.odell.glazedlists.FilterList;
import ca.odell.glazedlists.FunctionList;
import ca.odell.glazedlists.GlazedLists;
import ca.odell.glazedlists.TreeList;
import ca.odell.glazedlists.TreeList.Format;
import ca.odell.glazedlists.matchers.Matcher;

public class TreeListBug {
   
    private TreeList<Item> treeList;
   
    public TreeListBug() {
        // prepare the source list
        final EventList<Item> eventList = new BasicEventList<Item>();
        Item sect1 = new Item(null, "code1", "name1");
        Item sect11 = new Item(sect1, "code11", "name11");
        Item sect12 = new Item(sect1, "code12", "name12");
        final Item sect2 = new Item(null, "code2", "name2");
        Item sect21 = new Item(sect2, "code21", "name21");
        Item sect22 = new Item(sect2, "code22", "name22");
        eventList.add(sect1);
        eventList.add(sect2);
        eventList.add(sect11);
        eventList.add(sect12);
        eventList.add(sect21);
        eventList.add(sect22);
       
        // A trivial tree format - defined by item.parent
        Format format = new Format<Item>() {
            public boolean allowsChildren(Item element) { return true; }
            public Comparator<? extends Item> getComparator(int depth) { return null; }
            public void getPath(List<Item> path, Item item) {
                Item parent = item.parent;
                while (parent != null) {
                    path.add(0, parent);
                    parent = parent.parent;
                }
                path.add(item);
            }
        };
       
        // Build a decorated list which contains only the leaves
        OnlyLeavesMatcher matcher = new OnlyLeavesMatcher(eventList);
        EventList<Item> onlyLeaves = new FilterList<Item>(eventList, matcher);
       
        // Build the treeList from the onlyLeaves list
        treeList = new TreeList<Item>(onlyLeaves, format, TreeList.NODES_START_EXPANDED);
       
        System.err.println("eventList="+eventList);
        System.err.println("treeList="+treeList);
        System.err.println("onlyLeaves="+onlyLeaves);
       
        System.err.println("refreshing item 3 in treeList...");
       
        Item item = treeList.get(3);
        treeList.set(3, item);
       
        System.err.println("eventList="+eventList);
        System.err.println("treeList="+treeList);
        System.err.println("onlyLeaves="+onlyLeaves);
    }
   
    // A matcher which will filter out nodes which are not leaves
    private static class OnlyLeavesMatcher implements Matcher<Item> {
       
        private Map<Integer, List<Item>> mapByParent;    

        public OnlyLeavesMatcher(EventList<Item> eventList) {
            mapByParent = GlazedLists.syncEventListToMultiMap(eventList, new IdentityOfParentFunction());
        }

        public boolean matches(Item item) {
            List<Item> children = mapByParent.get(new Integer(System.identityHashCode(item)));
            if (children == null || children.isEmpty()) {
                return true;
            }
            return false;
        }
       
        private static class IdentityOfParentFunction implements FunctionList.Function<Item,Integer> {
            public Integer evaluate(Item item) {
                Object parent = item.parent;
                if (parent == null) {
                    return 0;
                }
                return System.identityHashCode(parent);
            }
        }
    }
   
    public static class Item {
        public String code;
        public String name;
        public Item parent;
       
        public Item(Item parent, String code, String name) {
            this.parent = parent;
            this.code = code;
            this.name = name;
        }
        public String toString() { return code+"/"+name; }
    }

    public static void main(String[] args) {
        new TreeListBug();
    }
}


------ code ends --------


Any idea?

Thanks in advance
       
Avital