IndexOutOfBoundsException on custom table implementation

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

IndexOutOfBoundsException on custom table implementation

by Wingnut :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hello everyone,

I've searched these forums for all IndexOutOfBoundsExceptions but none have unfortunately solved my issue. Basically, I'm using SWT and trying to implement GlazedLists onto the Nebula grid widget (which does not use a table model implementation nor a viewer so I have to manually add/delete items).

I used the KTable implementation without problem, but unfortunately I cannot use KTable anymore due to that it's not being worked on and there's quite a few issues with it.

Everything works fine for sorting and such, but when I do filtering I run into OutOfBounds issues. I even get OOB issues when my DELETE/UPDATE code does absolutely nothing to the table itself. If I replace everything in the table with what's in the event list then it all works, but doing that means I lose selection and these tables are loaded with data, so it's not really an option. It seems I must be breaking something when I iterate over the changed list, but I can't for the life of me figure out what.

Here's my implementation in short snippets:

Main constructor (the important bits)

public class NGridTable(List<MyTableObject> input)

    EventList<MyTableObject> eventList = GlazedLists.eventList(input);
    SortedList<MyTableObject> sortedList = new SortedList<MyTableObject>(eventList, new OurObjectComparator(this));
    FilterList<MyTableObject> filterList = new FilterList<MyTableObject>(sortedList, filterMatcher);

    // pass the filter list as source list to our "fake model"
    NGridTableModel model = new NGridTableModel(this, table, filterList, fixTableFormat)
}
"Fake model":
public class NGridTableModel implements ListEventListener<MyTableObject> {
    public NGridTableModel(NGridTable parent, Grid table, EventList<MyTableObject> source,
            TableFormat<MyTableObject> tableFormat) {

        source.addListEventListener(this);
    }

    public synchronized void listChanged(ListEvent<MyTableObject> listChanges) {
	    while (listChanges.next()) {
		List<MyTableObject> list = listChanges.getSourceList();

		int sourceIndex = listChanges.getIndex();
		int changeType = listChanges.getType();

		MyTableObject obj = list.get(sourceIndex);

		switch (changeType) {
		    case ListEvent.DELETE:
			removeItem(sourceIndex);
			break;
		    case ListEvent.INSERT:
			addItem(obj, sourceIndex);
			break;
		    case ListEvent.UPDATE:
		    	// we redraw the table at the end, no need
			break;
		}
	    }

	    table.redraw();
    }
}
method applying (and re-applying) the filter:
public void filterWasModified(Matcher<MyTableObject> newMatcher) {
   try {
       filterList.getReadWriteLock().writeLock().lock();
       filterList.setMatcher(newMatcher);
   } catch (Exception err) {
       FixLogManager.error(err);
   } finally {
       filterList.getReadWriteLock().writeLock().unlock();
   }
}

Typical exception being thrown:
Exception: java.lang.IndexOutOfBoundsException: Cannot get at 14 on list of size 14

And on a similar note. Just trying to call eventList.clear() throws the following exception:
Exception: java.lang.IndexOutOfBoundsException: Cannot get at 0 on list of size 0

Am I doing something fundamentally wrong? I've tried pretty much everything, including (SWT) proxied lists, transformed lists, threadsafe lists, order of creating the lists, and so on, but they all end up with the same problem.

Would really appreciate any input, I've tried for 6 hours straight and my head feels ready to explode. The fact that clear() fails with a similar exceptions seems I should be able to pinpoint the problem, but I just can't seem to find anything that works, and it keeps coming back to the iterator...

Best regards,
Wingnut


Re: IndexOutOfBoundsException on custom table implementation

by James Lemieux :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Dear Wingnut,

 Some of the code in your ListEventListener isn't correct. Specifically, the problem is this:

MyTableObject obj = list.get(sourceIndex);

This line of code is executed regardless of the change type. But, if the change type is a DELETE, then the source EventList NO LONGER CONTAINS THAT DATA. i.e., the index may now be out of bounds.

Change the looping code to resemble this:

    public void listChanged(ListEvent<MyTableObject> listChanges) {
final List<MyTableObject> list = listChanges.getSourceList();

while (listChanges.next()) {
int sourceIndex = listChanges.getIndex();
int changeType = listChanges.getType();

switch (changeType) {
case ListEvent.DELETE:
removeItem(sourceIndex);
break;
case ListEvent.INSERT:
addItem(list.get(sourceIndex), sourceIndex);
break;
case ListEvent.UPDATE:
// we redraw the table at the end, no need
break;
}
}

table.redraw();
}
and it should be faster and correct. Note also that the listChanged() method need not be synchronized. The ListEventPublisher ensures it is called serially.

Hope this helps,

James

PS: I'm glad to see that the Nebula people designed their stuff correctly and used indexes to refer to table elements, rather than objects. this is a major design flaw in SWT's table.

PPS: If there is enough support in the community for a standard binding from GL to the Nebula Grid Widget, we could add a new GL extension for it, and others wouldn't have to duplicate this code you have written.

On Fri, Jun 20, 2008 at 7:24 AM, Wingnut <emil.crumhorn@...> wrote:
Hello everyone,

I've searched these forums for all IndexOutOfBoundsExceptions but none have unfortunately solved my issue. Basically, I'm using SWT and trying to implement GlazedLists onto the Nebula grid widget (which does not use a table model implementation nor a viewer so I have to manually add/delete items).

I used the KTable implementation without problem, but unfortunately I cannot use KTable anymore due to that it's not being worked on and there's quite a few issues with it.

Everything works fine for sorting and such, but when I do filtering I run into OutOfBounds issues. I even get OOB issues when my DELETE/UPDATE code does absolutely nothing to the table itself. If I replace everything in the table with what's in the event list then it all works, but doing that means I lose selection and these tables are loaded with data, so it's not really an option. It seems I must be breaking something when I iterate over the changed list, but I can't for the life of me figure out what.

Here's my implementation in short snippets:

Main constructor (the important bits)

public class NGridTable(List<MyTableObject> input)

    EventList<MyTableObject> eventList = GlazedLists.eventList(input);
    SortedList<MyTableObject> sortedList = new SortedList<MyTableObject>(eventList, new OurObjectComparator(this));
    FilterList<MyTableObject> filterList = new FilterList<MyTableObject>(sortedList, filterMatcher);

    // pass the filter list as source list to our "fake model"
    NGridTableModel model = new NGridTableModel(this, table, filterList, fixTableFormat)
}
"Fake model":
public class NGridTableModel implements ListEventListener<MyTableObject> {
    public NGridTableModel(NGridTable parent, Grid table, EventList<MyTableObject> source,
            TableFormat<MyTableObject> tableFormat) {

        source.addListEventListener(this);
    }

    public synchronized void listChanged(ListEvent<MyTableObject> listChanges) {
	    while (listChanges.next()) {
		List<MyTableObject> list = listChanges.getSourceList();

		int sourceIndex = listChanges.getIndex();
		int changeType = listChanges.getType();

		MyTableObject obj = list.get(sourceIndex);

		switch (changeType) {
		    case ListEvent.DELETE:
			removeItem(sourceIndex);
			break;
		    case ListEvent.INSERT:
			addItem(obj, sourceIndex);
			break;
		    case ListEvent.UPDATE:
		    	// we redraw the table at the end, no need
			break;
		}
	    }

	    table.redraw();
    }
}
method applying (and re-applying) the filter:
public void filterWasModified(Matcher<MyTableObject> newMatcher) {
   try {
       filterList.getReadWriteLock().writeLock().lock();
       filterList.setMatcher(newMatcher);
   } catch (Exception err) {
       FixLogManager.error(err);
   } finally {
       filterList.getReadWriteLock().writeLock().unlock();
   }
}

Typical exception being thrown:
Exception: java.lang.IndexOutOfBoundsException: Cannot get at 14 on list of size 14

And on a similar note. Just trying to call eventList.clear() throws the following exception:
Exception: java.lang.IndexOutOfBoundsException: Cannot get at 0 on list of size 0

Am I doing something fundamentally wrong? I've tried pretty much everything, including (SWT) proxied lists, transformed lists, threadsafe lists, order of creating the lists, and so on, but they all end up with the same problem.

Would really appreciate any input, I've tried for 6 hours straight and my head feels ready to explode. The fact that clear() fails with a similar exceptions seems I should be able to pinpoint the problem, but I just can't seem to find anything that works, and it keeps coming back to the iterator...

Best regards,
Wingnut


View this message in context: IndexOutOfBoundsException on custom table implementation
Sent from the GlazedLists - User mailing list archive at Nabble.com.



Re: IndexOutOfBoundsException on custom table implementation

by Brian Merrill :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Wingnut wrote:
>     public synchronized void listChanged(ListEvent<MyTableObject> listChanges) {
>    while (listChanges.next()) {
> List<MyTableObject> list = listChanges.getSourceList();
>
> int sourceIndex = listChanges.getIndex();
> int changeType = listChanges.getType();
>
> MyTableObject obj = list.get(sourceIndex);
>  
It looks to me like the line above is the source of your problems.  When
changeType is DELETE, the object at "sourceIndex" has already been
deleted from "list" and therefore you cannot access it.  You must
maintain a separate list of objects which mirrors the EventList in order
to obtain a reference to the deleted object.  However, it doesn't look
like you really need access to the deleted object so you may be able to
fix the probably by rearranging a few things and adding and "updateItem"
function in your NGridTableModel assuming that calling those functions
correctly updates a separate list:

public class NGridTableModel implements ListEventListener<MyTableObject>
{
    public NGridTableModel(NGridTable parent, Grid table, EventList<MyTableObject> source,
            TableFormat<MyTableObject> tableFormat) {
        source.addListEventListener(this);
    }

    public synchronized void listChanged(ListEvent<MyTableObject> listChanges) {
            List<MyTableObject> list = listChanges.getSourceList();
            while (listChanges.next()) {
                int sourceIndex = listChanges.getIndex();
                int changeType = listChanges.getType();

                switch (changeType) {
                    case ListEvent.DELETE:
                        removeItem(sourceIndex);
                        break;
                    case ListEvent.INSERT:
                        final MyTableObject insert = list.get(sourceIndex);
                        addItem(sourceIndex, insert);
                        break;
                    case ListEvent.UPDATE:
                        final MyTableObject update = list.get(sourceIndex);
                        updateItem(update, sourceIndex);
                        break;
                }
            }
            table.redraw();
    }
}



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@...
For additional commands, e-mail: users-help@...


Re: IndexOutOfBoundsException on custom table implementation

by Wingnut :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

That worked like a charm, and makes sense. Thanks!

Once I've cleaned it up a bit I'll gladly contribute it (Although ideally a Nebula Grid TableViewer implementation would be prettier than this, but it still works). Should I just post here or is there a better place submit contributed code?


Brian Merrill wrote:
Wingnut wrote:
>     public synchronized void listChanged(ListEvent<MyTableObject> listChanges) {
>    while (listChanges.next()) {
> List<MyTableObject> list = listChanges.getSourceList();
>
> int sourceIndex = listChanges.getIndex();
> int changeType = listChanges.getType();
>
> MyTableObject obj = list.get(sourceIndex);
>  
It looks to me like the line above is the source of your problems.  When
changeType is DELETE, the object at "sourceIndex" has already been
deleted from "list" and therefore you cannot access it.  You must
maintain a separate list of objects which mirrors the EventList in order
to obtain a reference to the deleted object.  However, it doesn't look
like you really need access to the deleted object so you may be able to
fix the probably by rearranging a few things and adding and "updateItem"
function in your NGridTableModel assuming that calling those functions
correctly updates a separate list:

public class NGridTableModel implements ListEventListener<MyTableObject>
{
    public NGridTableModel(NGridTable parent, Grid table, EventList<MyTableObject> source,
            TableFormat<MyTableObject> tableFormat) {
        source.addListEventListener(this);
    }

    public synchronized void listChanged(ListEvent<MyTableObject> listChanges) {
            List<MyTableObject> list = listChanges.getSourceList();
            while (listChanges.next()) {
                int sourceIndex = listChanges.getIndex();
                int changeType = listChanges.getType();

                switch (changeType) {
                    case ListEvent.DELETE:
                        removeItem(sourceIndex);
                        break;
                    case ListEvent.INSERT:
                        final MyTableObject insert = list.get(sourceIndex);
                        addItem(sourceIndex, insert);
                        break;
                    case ListEvent.UPDATE:
                        final MyTableObject update = list.get(sourceIndex);
                        updateItem(update, sourceIndex);
                        break;
                }
            }
            table.redraw();
    }
}



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@glazedlists.dev.java.net
For additional commands, e-mail: users-help@glazedlists.dev.java.net

Re: IndexOutOfBoundsException on custom table implementation

by James Lemieux :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Posting here is fine. By all means, clean up your implementation as much as possible. Also, testcases are quite welcome too.

James

On Sun, Jun 22, 2008 at 11:24 PM, Wingnut <emil.crumhorn@...> wrote:

That worked like a charm, and makes sense. Thanks!

Once I've cleaned it up a bit I'll gladly contribute it (Although ideally a
Nebula Grid TableViewer implementation would be prettier than this, but it
still works). Should I just post here or is there a better place submit
contributed code?



Brian Merrill wrote:
>
> Wingnut wrote:
>>     public synchronized void listChanged(ListEvent<MyTableObject>
>> listChanges) {
>>          while (listChanges.next()) {
>>              List<MyTableObject> list = listChanges.getSourceList();
>>
>>              int sourceIndex = listChanges.getIndex();
>>              int changeType = listChanges.getType();
>>
>>              MyTableObject obj = list.get(sourceIndex);
>>
> It looks to me like the line above is the source of your problems.  When
> changeType is DELETE, the object at "sourceIndex" has already been
> deleted from "list" and therefore you cannot access it.  You must
> maintain a separate list of objects which mirrors the EventList in order
> to obtain a reference to the deleted object.  However, it doesn't look
> like you really need access to the deleted object so you may be able to
> fix the probably by rearranging a few things and adding and "updateItem"
> function in your NGridTableModel assuming that calling those functions
> correctly updates a separate list:
>
> public class NGridTableModel implements ListEventListener<MyTableObject>
> {
>     public NGridTableModel(NGridTable parent, Grid table,
> EventList<MyTableObject> source,
>             TableFormat<MyTableObject> tableFormat) {
>         source.addListEventListener(this);
>     }
>
>     public synchronized void listChanged(ListEvent<MyTableObject>
> listChanges) {
>           List<MyTableObject> list = listChanges.getSourceList();
>           while (listChanges.next()) {
>               int sourceIndex = listChanges.getIndex();
>               int changeType = listChanges.getType();
>
>               switch (changeType) {
>                   case ListEvent.DELETE:
>                       removeItem(sourceIndex);
>                       break;
>                   case ListEvent.INSERT:
>                       final MyTableObject insert = list.get(sourceIndex);
>                       addItem(sourceIndex, insert);
>                       break;
>                   case ListEvent.UPDATE:
>                       final MyTableObject update = list.get(sourceIndex);
>                       updateItem(update, sourceIndex);
>                       break;
>               }
>           }
>           table.redraw();
>     }
> }
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@...
> For additional commands, e-mail: users-help@...
>
>
>

--
View this message in context: http://www.nabble.com/IndexOutOfBoundsException-on-custom-table-implementation-tp18030648p18063247.html
Sent from the GlazedLists - User mailing list archive at Nabble.com.


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@...
For additional commands, e-mail: users-help@...