Skip to main content

JXTreeTable does not handle treeStructureChanged as expected

16 replies [Last post]
hbogaards
Offline
Joined: 2005-04-08

Hi All,

After having troubles with our own implementation of a JTreeTable (based on http://java.sun.com/products/jfc/tsc/articles/treetable1/ ), we recently switched to using JXTreeTable.

When the TreeTableModel is updated (the number of columns changes) I call modelSupport.fireStructureChanged(). I would expect the JXTreeTable to update correctly and show the changed number of columns, but it doesn't.

Looking in the code of JXTreeTable I see:

<br />
        /**<br />
         * @return TreeModelListener<br />
         */<br />
        private TreeModelListener getTreeModelListener() {<br />
            if (treeModelListener == null) {<br />
                treeModelListener = new TreeModelListener() {</p>
<p>                    public void treeNodesChanged(TreeModelEvent e) {<br />
//                        LOG.info("got tree event: changed " + e);<br />
                        delayedFireTableDataUpdated(e);<br />
                    }</p>
<p>                    // We use delayedFireTableDataChanged as we can<br />
                    // not be guaranteed the tree will have finished processing<br />
                    // the event before us.<br />
                    public void treeNodesInserted(TreeModelEvent e) {<br />
                        delayedFireTableDataChanged(e, 1);<br />
                    }</p>
<p>                    public void treeNodesRemoved(TreeModelEvent e) {<br />
//                        LOG.info("got tree event: removed " + e);<br />
                       delayedFireTableDataChanged(e, 2);<br />
                    }</p>
<p>                    public void treeStructureChanged(TreeModelEvent e) {<br />
                        // ?? should be mapped to structureChanged -- JW<br />
                        delayedFireTableDataChanged();<br />
                    }<br />
                };<br />
            }<br />
            return treeModelListener;<br />
        }<br />

By changing treeStructureChanged() to:

<br />
                    public void treeStructureChanged(TreeModelEvent e) {<br />
                        delayedFireTableStructureChanged();<br />
                    }<br />

and adding

<br />
        /**<br />
         * Invokes fireTableStructureChanged after all the pending events have been<br />
         * processed. SwingUtilities.invokeLater is used to handle this.<br />
         */<br />
        private void delayedFireTableStructureChanged() {<br />
            SwingUtilities.invokeLater(new Runnable() {<br />
                public void run() {<br />
                    fireTableStructureChanged();<br />
                }<br />
            });<br />
        }<br />

the JXTreeTable acts as I expect.

Is there a reason that treeStructureChanged() does not (or should not) call fireTableStructureChanged() ??

Should I open an issue for this?
--
Hans Bogaards
Traffic IT Services B.V.
The Netherlands

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
kschaefe
Offline
Joined: 2006-06-08

Jeanette,

A couple of quick comments:
> a) differentiate by the root of the subtree with a
> structure change: if
> it's not the root of the tree, assume that it's only
> a non-column
> effecting change, if it's a root assume that the
> tabular structure is
> effected as well
This is probably the fastest and easiest, but it does add a special case to the root. It may be worth considering the state of the root (visibility) in some way to determine change type. As the tree table usually has an invisible root, it probably OK to just do it without worrying about the state.

> b) add some distinguishing state to the
> treeModelEvent structure changed
> (see below) - map all tree-structurechanged to
> table-dateChanged except
> when the event carries an additional flag
> characterizing the change as
> columns-as-well
I'm really borderline on this. I'd rather not go half way. If we're thinking about flags and extra data, we really need to consider the ability to forward cell-level changes.

> c) combine both: I wouldn't expect subtree structure
> changes to effect
> column structure (? should I?), so look for the
> marker only if structure
> changes are on the root.

or:
d) create a TreeTableModelEvent to add cell-level information and contain all the distinguishing bit for structural change.
I think we need to be here in the long run. But for the short term A can get us pretty close.

I saw you committed some code for A. I'll try to play with it.

Karl

Kleopatra

>
> or:
> d) create a TreeTableModelEvent to add cell-level information and contain all the distinguishing bit for structural change.
> I think we need to be here in the long run. But for the short term A can get us pretty close.
>

maybe I'll agree in the long-run - but for now I not (yet) really
convinced that we need it. Would like to see some use-cases as to which
problems such an event would solve. What exactly would cell-level
notification buy? Kind of consistency with TableEvent is all I can think
of (but then it's Friday and raining )

Cheers
Jeanette

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

Kleopatra

okay, we a use-case where the tree-structureChange mapping to
table-structureChange is unwanted:

http://forums.java.net/jive/thread.jspa?threadID=30320&tstart=0

so we have to go a step further: enhance the event. How far exactly, is
open to debate.

Jeanette

PS: I'm more or less offline this week, so little immediate action to
expect.

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

kschaefe
Offline
Joined: 2006-06-08

I'll pipe up again with full cell-level events.

Karl

Kleopatra

jdnc-interest@javadesktop.org schrieb:
> I'll pipe up again with full cell-level events.
>

yeah, and I'm still waiting for your list of problems which will be
solved by cell-level events (as opposed to the problem discussed here
which is a tree-structure-changed mapped to either
table-structure-changed or table-data-changed)

Cheers (I'm not really here now, stealing a few seconds:-)
Jeanette

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

kschaefe
Offline
Joined: 2006-06-08

> > I'll pipe up again with full cell-level events.
> >
>
> yeah, and I'm still waiting for your list of problems
> which will be
> solved by cell-level events (as opposed to the
> problem discussed here
> which is a tree-structure-changed mapped to either
> table-structure-changed or table-data-changed)
To really be a tree and a table we need the ability to support all of table event mechanisms and cell-level detail is required for that.

I'm sure I could come up with more reasons, but I really think that if we're going to create an event to handle the dirty details of tree/table structure changes, it's not going to take much more work to add the cell-level detail. It's an effort thing. Why revisit the area later, when we're doing work there now.

> Cheers (I'm not really here now, stealing a few
> seconds:-)
Oktoberfest doesn't even start until the 22nd. So, you've got time, right? :)

Karl

Kleopatra

jdnc-interest@javadesktop.org schrieb:
>>> I'll pipe up again with full cell-level events.
>>>
>> yeah, and I'm still waiting for your list of problems
>> which will be
>> solved by cell-level events (as opposed to the
>> problem discussed here
>> which is a tree-structure-changed mapped to either
>> table-structure-changed or table-data-changed)
> To really be a tree and a table we need the ability to support all of table event mechanisms and cell-level detail is required for that.
>

playing devil's advocat: my question was and is why? Table's only
cell-level event is a single cell update (next in granularity is
all-cells-in-row). So what is that single cell update good for? And is
it good enough to extend the mechanism to treetableModel? And why is
multiple cell update (specific cells in a row/table) not important?

> I'm sure I could come up with more reasons, but I really think that if we're going to create an event to handle the dirty details of tree/table structure changes, it's not going to take much more work to add the cell-level detail. It's an effort thing. Why revisit the area later, when we're doing work there now.
>

each single line takes more work, as you well know :-). Needs to be
clearly defined, tested, demo'ed, documented .... There's nothing
inherently bad in revisting a solution later (mostly it's not quite the
right at first anyway). And, while we are at it, did I ever mention that
I always wanted column-related tableEvents

>> Cheers (I'm not really here now, stealing a few
>> seconds:-)
> Oktoberfest doesn't even start until the 22nd. So, you've got time, right? :)
>

LOL!

Jeanette

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

kschaefe
Offline
Joined: 2006-06-08

> jdnc-interest@javadesktop.org schrieb:
> >>> I'll pipe up again with full cell-level events.
> >>>
> >> yeah, and I'm still waiting for your list of
> problems
> >> which will be
> >> solved by cell-level events (as opposed to the
> >> problem discussed here
> >> which is a tree-structure-changed mapped to either
>
> >> table-structure-changed or table-data-changed)
> > To really be a tree and a table we need the ability
> to support all of table event mechanisms and
> cell-level detail is required for that.
> >
>
> playing devil's advocat: my question was and is why?
> Table's only
> cell-level event is a single cell update (next in
> granularity is
> all-cells-in-row). So what is that single cell update
> good for? And is
> it good enough to extend the mechanism to
> treetableModel? And why is
> multiple cell update (specific cells in a row/table)
> not important?
It depends on the UI-delegate that's used. As I recall the TAME table delegate does cells in column and row bounds w/o repainting the whole row. Just because BasicTableUI is not well-behaved doesn't mean another UI delegate isn't better behaved.

> > I'm sure I could come up with more reasons, but I
> really think that if we're going to create an event
> to handle the dirty details of tree/table structure
> changes, it's not going to take much more work to add
> the cell-level detail. It's an effort thing. Why
> revisit the area later, when we're doing work there
> now.
> >
>
> each single line takes more work, as you well know
> :-). Needs to be
> clearly defined, tested, demo'ed, documented ....
> There's nothing
> inherently bad in revisting a solution later (mostly
> it's not quite the
> right at first anyway). And, while we are at it, did
> I ever mention that
> I always wanted column-related tableEvents
True. So, let's figure out what we want:
I think cell-level is important. We should be able to do at least contiguous cell-ranges. These ranges can span one or more columns and/or rows and need not cover the entire column or row. The real question is should we allow cell level selection of multiple non-contiguous cells. Since the selection models allow it, we should have something similar in the update events.

I started fooling around with a TreeTableModelSupport that creates detailed events. When I get it completed, I'll post it.

Karl

Kleopatra

Karl,

Still pestering, but you didn't answer:

>> playing devil's advocat: my question was and is why?

> I think cell-level is important.

again: why do you think so? What do you want to do with that notification?

Jeanette

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

kschaefe
Offline
Joined: 2006-06-08

> > I think cell-level is important.
>
> again: why do you think so? What do you want to do
> with that notification?
I want the ability to give notification of atomic updates. I want to be able to build custom L&F delegates that paint only the changed cell(s). I want to be able to cascade events notification for specific cell changes. Etc.

To really answer the question: I don't know, since I don't already have it.

Something like JXSpreadsheet could/would really want such notification (of course it's tabular and not a tree table, but still). I'm trying to think outside of the box. What do I need it for? Nothing currently. Won't know until I have it and use it.

Karl

Kleopatra

Hi Hans, Karl

we've got a dedicated issue

https://swingx.dev.java.net/issues/show_bug.cgi?id=592

(which I think is a special case of the general problems with event
notification as of #493-swingx) which I plan to fix sooon ... maybe

>
> And... ;-) You haven't answered my question:
> Why does the TreeModelListener call fireTableDataChanged() on a treeStructureChanged() and not fireTableStructureChanged() ??

because a "structureChange" in tree event nofication is different from a
"structureChange" in table event notification: it's vertical vs.
horizontal "structure" the tree vs table is interested in - with the
additional catch that they both are mostly uninterested in the other
(that is horizontal vs. vertical, respectively) dimension ;-)

So there is no way for the tableModelAdapter to find out (from a tree
event) it it'll _really_ means a structure change (in terms of table
columns) or simply a reload from a node. If it can't decide anyway, plus
the fact that a table-structureChange has (mostly unwanted) side-effects
like loosing selection, column config ... the adapter backs out
completely and expects "real" table-structure changes through setting
the treeTableModel on the treeTable. Doing so it can map all
tree-structure changes as dataChanged.

Obviously, that's not optimal :-) So the task is to come up with a
(preferably low-impact) way to distinguish a column-structure effecting
change from a simple tree-structure. It doesn't help, that
TreeModelEvent/Listener belongs to the worst (inconsistent and
contradictory, the implementation yet another story and default models
notifying as they feel ...), documented part of whole Swing ...

Some options:

a) differentiate by the root of the subtree with a structure change: if
it's not the root of the tree, assume that it's only a non-column
effecting change, if it's a root assume that the tabular structure is
effected as well

b) add some distinguishing state to the treeModelEvent structure changed
(see below) - map all tree-structurechanged to table-dateChanged except
when the event carries an additional flag characterizing the change as
columns-as-well

c) combine both: I wouldn't expect subtree structure changes to effect
column structure (? should I?), so look for the marker only if structure
changes are on the root.

A possibility to smoothly add such a flag might be the treeModelEvent
as-is. My tentative assumption currently is that the two-parameter
TreeModelEvent constructor is the one meant for structure change
notification: children and childIndices are irrelevant (everything below
is changed anyway) and null (which is not the whole truth but good
enough for now). So both fields are unused by default and could get a
meaning in treetableModelEvent notification. Then treeTableModel
implementations must take the responsibility to set the marker
(modelSupport would get a cover method as well).

With that in place, collaborators would do something along the following
snippets ...

[code]
// Adapter when listening
void structureChanged(TreeModelEvent e) {
if (isTableStructureChange(e)) {
fireDelayedTableStructureChange(..);
} else {
fireDelayedTableDateChanged(..)
}

}

boolean isTableStructureChange(TableModelEvent e) {
if ((e == null) || (e.getPath() == null) return true;
return (e.getPath().getLastPathElement()
== e.getSource().getRoot()) &&
TreeTableModel.TABLE_STRUCTURE_CHANGE.equals(
e.getChildren());
}

// modelSupport

void fireTreeStructureChange(TreePath path) {
fireStructureChange(path, false);
}

void fireStructureChange(TreePath path,
boolean tableStructureEffected) {

...

TreeModelEvent e = createStructureEvent(path, tableStructure);
...
}

TreeModelEvent createStructureEvent(...);
Object[] tableStructure = null;
if (tableStructureEffected) {
tableStructure = TABLE_STRUCTURE_CHANGE;
}
return createTreeModelEvent(treeModel, path,
null, tableStructure);

}

// treeTableModels

void setRoot(...) {
...
getModelSupport().fireStructureChanged(..., true);
}

void reload() {
getModelSupport().fireStructureChange(...);
}

void setColumnIdentifiers(...) {
....
// same in any method effecting column structure
getModelSupport().fireStructureChanged(..., true);
}
[/code]

comments, please?

Jeanette

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

Kleopatra

Kleopatra schrieb:

>
> a) differentiate by the root of the subtree with a structure change: if
> it's not the root of the tree, assume that it's only a non-column
> effecting change, if it's a root assume that the tabular structure is
> effected as well
>

As this is the most simple thing to do, I started with it :-) Let me
know how it goes.

Jeanette

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

mauromol
Offline
Joined: 2006-05-05

I don't know if I am a bit off-topic in this discussion. Please consider that:

- I read the topic quickly
- I'm coming from a SwingX nighthly build of 2007-01-21 and just recently switched to 0.9.4, so something I'm saying may not be so much up to date
- I can't comment on Issue 727, why? I can't understand how Collabnet actually works... :-(

Anyway, after using JXTreeTables for a while and creating my own TreeTableModel implementations (either extending AbstractTreeTableModel or by reimplementing TreeTableModel from scratch), I came to the conclusion that there's something missing in it. A TreeTableModel actually controls not only the tree, but also the table, providing data to fill in the table. However, it does not have a mechanism for:
1) notifying that the number of columns has changed: you might have a tree table model where columns are added or removed dynamically
2) notifying that a row, or a column, or a cell data has changed
3) notifying that the whole data of a table has changed (including headers), while the tree structure has not

In my code, I solved problem #2 by creating a synchronization class that calls javax.swing.JTable.tableChanged(TableModelEvent) on my JXTreeTable (because, in that particular context, it was ok to solve the synchronization problem externally), while problem #1 and #3 has been solved by creating an extension of TreeTableModel interface and some related classes for event handling (I'm removing Javadoc because it has been written in Italian, sorry; I just translated some IMHO important comments):

public interface DynamicTreeTableModel extends TreeTableModel
{
void addDynamicTreeTableModelListener(DynamicTreeTableModelListener l);
void removeDynamicTreeTableModelListener(DynamicTreeTableModelListener l);
DynamicTreeTableModelListener[] getDynamicTreeTableModelListeners();
}

public static interface DynamicTreeTableModelListener extends EventListener
{
void columnCountChanged(DynamicTreeTableModelEvent e);
void wholeTableContentChanged(DynamicTreeTableModelEvent e);
}

public static class DynamicTreeTableModelEvent extends EventObject
{
private static final long serialVersionUID = 1L;

public static enum DynamicTreeTableModelEventType
{
COLUMN_COUNT_CHANGED,
WHOLE_TABLE_CONTENT_CHANGED;
}

private final DynamicTreeTableModelEventType eventType;

public DynamicTreeTableModelEvent(final DynamicTreeTableModel source,
final DynamicTreeTableModelEventType eventType)
{
super(source);
this.eventType = eventType;
}

public DynamicTreeTableModelEventType getType()
{
return eventType;
}
}

and an extension of JXTreeTable that honours these new events:

public class DynamicJXTreeTable extends JXTreeTable
{
private static final long serialVersionUID = 1L;

private final DynamicTreeTableModelSynchronizer dttml =
new DynamicTreeTableModelSynchronizer();

public DynamicJXTreeTable()
{
super();
}

public DynamicJXTreeTable(final TreeTableModel treeTableModel)
{
super(treeTableModel);
if(getTreeTableModel() instanceof DynamicTreeTableModel)
((DynamicTreeTableModel) getTreeTableModel())
.addDynamicTreeTableModelListener(dttml);
}

@Override
public void setTreeTableModel(final TreeTableModel treeTableModel)
{
final TreeTableModel oldModel = getTreeTableModel();
if(oldModel instanceof DynamicTreeTableModel)
((DynamicTreeTableModel) oldModel)
.removeDynamicTreeTableModelListener(dttml);
super.setTreeTableModel(treeTableModel);
if(treeTableModel instanceof DynamicTreeTableModel)
((DynamicTreeTableModel) treeTableModel)
.addDynamicTreeTableModelListener(dttml);
}

protected void columnCountChanged(final DynamicTreeTableModelEvent e)
{
tableChanged(new TableModelEvent(getModel(), TableModelEvent.HEADER_ROW));
}

protected void wholeTableContentChanged(final DynamicTreeTableModelEvent e)
{
// update all columns headers
updateColumnHeader(-1);
// update cell data
tableChanged(new TableModelEvent(getModel(), 0, getRowCount(),
TableModelEvent.ALL_COLUMNS, TableModelEvent.UPDATE));
}

public void updateColumnHeader(final int index)
{
if(index == -1)
{
final TableModel dataModel = getModel();
// update names of all columns
for(TableColumn column : getColumns(true))
column.setHeaderValue(dataModel.getColumnName(column.getModelIndex()));
}
else
{
/*
* NOTE: I can't use model-to-view index conversion, because in this way
* hidden columns headers are not updated. If they go back visible, they
* would still display the old header! So, I'm iterating over ALL the columns.
*/
final String newColumnHeader = getModel().getColumnName(index);
for(TableColumn column : getColumns(true))
{
if(column.getModelIndex() == index)
{
column.setHeaderValue(newColumnHeader);
// column found, jump to next
break;
}
}
}
getTableHeader().repaint();
}

private class DynamicTreeTableModelSynchronizer implements
DynamicTreeTableModelListener
{
public void columnCountChanged(final DynamicTreeTableModelEvent e)
{
DynamicJXTreeTable.this.columnCountChanged(e);
}

public void wholeTableContentChanged(final DynamicTreeTableModelEvent e)
{
DynamicJXTreeTable.this.wholeTableContentChanged(e);
}
}
}

An implementation of DynamicTreeTableModel can provide the fireColumnCountChanged and fireWholeTableContentChanged methods (or a similar modelSupport solution...).

This approach can be extended to fully support problem #2.
However, please consider that I don't know if this is the best way to extend TreeTableModel and JXTreeTable to solve these problems: this is just my quite straightforward solution.

Anyway, I really miss these features in TreeTableModel/JXTreeTable.

What do you think about?

Mauro.

kschaefe
Offline
Joined: 2006-06-08

> When the TreeTableModel is updated (the number of
> columns changes) I call
> modelSupport.fireStructureChanged(). I would expect
> the JXTreeTable to update correctly and show the
> changed number of columns, but it doesn't.
You may have encountered a bug, but let me ask a few questions.

Are you using the latest version of the code? I fixed some timing/ordering bugs last Friday.

I'd like to know more about your model. How are you changing the number of columns in the table? Are you rolling a custom model with AbstractTreeTableModel or are you extending AbstractMutableTreeTableNode and using the DefaultTreeTableModel (sounds like the former from your comments)? Better yet, are you able post your model?

Karl

hbogaards
Offline
Joined: 2005-04-08

Hi Karl,

I am using the latest version of the code. I got the code from CVS last Monday and have kept it updated since.

I have a model based on AbstractTreeTableModel with extended DefaultTreeTableNodes.

In our application the user selects nodes in a JTree with checkboxes. After the selection, we copy the nodes in the JXTreeTable, so now we have a JXTreeTable with only the tree-column.

Now the user selects a start and end date and we retrieve date-based data for the selected objects. After retrieval the TreeTableModel and the nodes are updated with the data, creating a column for each day of available data. Note that not all nodes need to have the same number of days in their data, esp. the root will never have any data!

After we have updated the TreeTableModel and the nodes, the modelSupport.fireStructureChanged() is called.

With the unpatched JXTreeTable the columns do not appear, with the patch they do.

As an experiment I modified our model and nodes to extend DefaultTreeTableModel (the only extensions are utility methods to easily add the nodes and the data) and the nodes to extend AbstractMutableTreeTableNode with no obvious difference in behaviour.

I am not (yet) able to post our model and nodes, have to consult with my boss for that and strip them for anything 'interesting', but my boss is away for a couple of days.

And... ;-) You haven't answered my question:
Why does the TreeModelListener call fireTableDataChanged() on a treeStructureChanged() and not fireTableStructureChanged() ??

I hope this answers your questions...
--
Hans Bogaards
Traffic IT Services B.V.
The Netherlands

kschaefe
Offline
Joined: 2006-06-08

> I am using the latest version of the code. I got the
> code from CVS last Monday and have kept it updated
> since.
Great.

> I have a model based on AbstractTreeTableModel with
> extended DefaultTreeTableNodes.
Do not extend DefaultMutableTreeTableNode. I should really make that class final. It's sole design purpose is for ease of tree table creation for non-production data. Think of it in the same way you would the JTree's default constructor. It's there but should only be used for special needs. You should extend AbstractMutableTreeTableNode.

> In our application the user selects nodes in a JTree
> with checkboxes. After the selection, we copy the
> nodes in the JXTreeTable, so now we have a
> JXTreeTable with only the tree-column.
>
> Now the user selects a start and end date and we
> retrieve date-based data for the selected objects.
> After retrieval the TreeTableModel and the nodes are
> updated with the data, creating a column for each day
> of available data. Note that not all nodes need to
> have the same number of days in their data, esp. the
> root will never have any data!
This is fine.

> After we have updated the TreeTableModel and the
> nodes, the modelSupport.fireStructureChanged() is
> called.
I'd really like to see this update. This will help me discover if there's a bug in my code or your code.

> With the unpatched JXTreeTable the columns do not
> appear, with the patch they do.
OK.

> As an experiment I modified our model and nodes to
> extend DefaultTreeTableModel (the only extensions are
> utility methods to easily add the nodes and the data)
> and the nodes to extend AbstractMutableTreeTableNode
> with no obvious difference in behaviour.
With you so far. What about extending the FileSystemModel to show more data or less data and updating? If you're unable to post the model, perhaps you could build a test case with FSM to demonstrate the problem.

> I am not (yet) able to post our model and nodes, have
> to consult with my boss for that and strip them for
> anything 'interesting', but my boss is away for a
> couple of days.
>
> And... ;-) You haven't answered my question:
> Why does the TreeModelListener call
> fireTableDataChanged() on a treeStructureChanged()
> and not fireTableStructureChanged() ??
I'm going to go with, "I didn't write that part." ;) Seriously, I'm not sure. Both are going to force the table to rerender every cell, but the latter will cause the recreation of the TableColumnModel, assuming that autoCreate is not disabled.

This seems potentially problematic to just go one way or the other. Just, off the top of my head, we could solve this problem in a couple of ways (comments welcomed):
1. Change fireDataChanged to fireTableStructureChanged. Adds the overhead of recreating the column model. I think we're better off with a structure change that a data change if we're not going to address this any further. This could be a short term solution en route to the next approach.
2. Create a TreeTableModel support and event set that includes among other things columns counts. Refire the appropriate event. This would allow us to create new events that will help us to have a better idea on whether to refire data change or structure change.

Karl