0

Unable to write a groupsmodel which can grow and shrink as new groups are added or removed

asked 2012-08-13 08:18:01 +0800

cvarona gravatar image cvarona
554 1 6

Hi,

I've written a groupsmodel in order to represent a list of task groups; I've followed a quite naïve approach, the one everybody will come in the first place to when confronting the task:

public class TaskListModel extends AbstractGroupsModel<PfTaskWrapper, TaskGroup, Object, Object> implements GroupsSortableModel<PfTaskWrapper>, ComponentCloneListener, Cloneable {

    private List<TaskGroup> _taskGroups = new ArrayList<TaskGroup>();
    private Set<Integer> _openGroupIndex = new HashSet<Integer>();
    ...
        public boolean addOpenGroup( int groupIndex ) {
        return _openGroupIndex.add( groupIndex );
    }

    public TaskGroup getGroup( int groupIndex ) {
        return _taskGroups.get( groupIndex );
    }

    public int getGroupCount() {
        return _taskGroups.size();
    }

    public PfTaskWrapper getChild( int groupIndex, int index ) {
        return getGroup( groupIndex ).getTasks().get( index );
    }

    public int getChildCount( int groupIndex ) {
        return getGroup( groupIndex ).getTasks().size();
    }
    ...
}

public class TaskGroup {

    private String _groupName;
    private List<PfTaskWrapper> _tasks;
    
    public List<PfTaskWrapper> getTasks() {
        return _tasks;
    }
    ...
}


(I do not include the whole TaskListModel for it's long, everybody can imagine how it goes and ends up not being too relevant for the problem this question is concerned with)

Well, in addition to the pure GroupsModel methods, I've also included some methods in order to add and remove task groups from the model, like this:

public void add( TaskGroup pTaskGroup ) {

        if( _taskGroups.contains( pTaskGroup ) ) {

            throw new RuntimeException( "Task group " + pTaskGroup + " already belongs to the model" );

        } else {

            _taskGroups.add( pTaskGroup );

            Collections.sort( _taskGroups, _taskGroupComparator );

            int index = _taskGroups.indexOf( pTaskGroup );
            fireEvent( GroupsDataEvent.GROUPS_ADDED, -1, index, index );
        }
    }

    public void remove( TaskGroup pTaskGroup ) {

        if( _taskGroups.contains( pTaskGroup ) ) {

            int index = _taskGroups.indexOf( pTaskGroup );

            _taskGroups.remove( pTaskGroup );
            fireEvent( GroupsDataEvent.GROUPS_REMOVED, -1, index, index );
        }
    }

This is the piece of code that gets executed, as of zk6.01, when a task group is added to the model:

(in org.zkoss.zul.impl.GroupsListModel)

private class DataListener implements GroupsDataListener {
    public void onChange(GroupsDataEvent event) {
        int type = event.getType(),
            j0 = event.getIndex0(),
            j1 = event.getIndex1();

        switch (type) {
           ...
           case GroupsDataEvent.GROUPS_CHANGED:
			case GroupsDataEvent.GROUPS_ADDED:
			case GroupsDataEvent.GROUPS_REMOVED:
				type -= GroupsDataEvent.GROUPS_CHANGED;
				if (j0 >= 0) {
					if (j0 >= _gpofs.length)
						throw new IndexOutOfBoundsException("Group index not in 0.."+getGroupCount()+", "+j0);
					j0 = _gpofs;
				}
				...

The problem with this code, if I've correctly understood how it works, lies in the fact that, if the task group model was initially empty (and thus _gpofs is a zero-length array) j0 will allways verify >= _gpofs.length. In other words: a group model like this that happens to be initially empty will have no choice but to remain so forever.

Am I missing something? Is there any means of writing an non-immutable groups model that can function with the current zk version?

With kind regards

César Varona

delete flag offensive retag edit

1 Reply

Sort by » oldest newest

answered 2012-08-20 08:55:44 +0800

cvarona gravatar image cvarona
554 1 6

I finally managed to solve it like this:

if( _taskGroups.size() == 1 ) {
        structureChanged();
    } else {
        Collections.sort( _taskGroups, _taskGroupComparator );

        // It should be possible to notify group addition, but it does not seem to work
        //int index = _taskGroups.indexOf( pTaskGroup );
        //fireEvent( GroupsDataEvent.GROUPS_ADDED, -1, index, index );
        structureChanged();
    }

...
private void structureChanged() {
    fireEvent( GroupsDataEvent.STRUCTURE_CHANGED, -1, -1, -1 );
}

but I think it should be possible to write a group model that grows and shrinks without having to resort to such tricks. I've been unable to make group addition work, even if the model is not empty.

As for the group opening and closing, I've mimicked the existing zk simple group model code, like this:

public boolean addOpenGroup( int groupIndex ) {
    
    boolean aux = _openGroups.add( getGroup( groupIndex ) );
    if( aux ) {
        fireEvent( GroupsDataEvent.GROUPS_CHANGED, groupIndex, -1, -1 );
    }
    
    return aux;
    }

At first I could not make it work. I hadn't expected I should tell zk which group has been requested to open (after all it's the very zk engine who is telling me about it in the first place). If by whichever reason it's not possible for the zk grid or listbox to just open the group if the bound group model does not veto the operation, I think it should be better to state it clearly in the documentation: "it's up to the developer to notify the groups changed event".

With kind regards

César Varona

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: 2012-08-13 08:18:01 +0800

Seen: 102 times

Last updated: Aug 20 '12

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