Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / November 2006

Tip: Looking for answers? Try searching our database.

JTable/TableModel undoing

Thread view: 
Deniz Dogan - 16 Nov 2006 14:15 GMT
Hello!

Does anyone know of a way to provide some sort of undo manager for
JTables or TableModels?  This should of course also work for removing of
rows and adding of rows and not just the cells of the table.

-Deniz Dogan
Thomas Weidenfeller - 16 Nov 2006 15:13 GMT
> Hello!
>
> Does anyone know of a way to provide some sort of undo manager for
> JTables or TableModels?

The undo manager is not the problem. Java comes with
//javax.swing.undo.UndoManager//. The problem is that you will have to
implement your own //TableModel// that can talk to the manager by
providing the following.

a) Allows to register //UndoableEditListener//s with the model, so an
//UndoManager// can listen to changes.

b) Allows to de-register //UndoableEditListener//s with the model

c) Generates and fires //UndoableEditEvent//s for each relevant edit,

d) containing an //UndoableEdit// instance describing the edit and
providing the means to undo/redo it.

For bonus points:

e) Make the //UndoableEdit// a //CompoundEdit// for sequences of similar
and related edits (e.g. collapsing multiple single character deletions
into a "word deleted" edit).

All this is not much fun to implement.

The general problem you are facing here is that Sun once started with
the undo/redo system in the javax.swing.undo package, but didn't follow
through. They only implemented the necessary support in text components,
and skipped every other GUI elements.

<rant>
Unfortunately this is typical for Sun when it comes to Java. Them much
prefer to add a new shiny feature instead of first finishing what they
started :-(
</rant>

/Thomas
Signature

The comp.lang.java.gui FAQ:
http://gd.tuwien.ac.at/faqs/faqs-hierarchy/comp/comp.lang.java.gui/
ftp://ftp.cs.uu.nl/pub/NEWS.ANSWERS/computer-lang/java/gui/faq

Thomas Weidenfeller - 16 Nov 2006 15:27 GMT
> The problem is that you will have to
> implement your own //TableModel// that can talk to the manager by
> providing the following.

A minor correction. You need a subclass of JTable to fire the
UndoableEditEvents, because they also need to report about
representation issues, like a change of a selection. And the TableModel
is not aware of such changes. But the TableModel is still part of the
game. A customized TableModel will likely need to support the customized
JTable for some types of edits, too.

/Thomas
Signature

The comp.lang.java.gui FAQ:
http://gd.tuwien.ac.at/faqs/faqs-hierarchy/comp/comp.lang.java.gui/
ftp://ftp.cs.uu.nl/pub/NEWS.ANSWERS/computer-lang/java/gui/faq

Michael Rauscher - 16 Nov 2006 20:11 GMT
Thomas Weidenfeller schrieb:
>> Hello!
>>
[quoted text clipped - 21 lines]
> and related edits (e.g. collapsing multiple single character deletions
> into a "word deleted" edit).

Agreed with one exception: to me, e) makes little sense with respect to
tables. Either a cell (or row in the case of additions and deletions)
was updated or it wasn't.

> All this is not much fun to implement.

But it's straight-forward if one implements a Decorator for ordinary
TableModels. Of course, in this case row additions/deletions get lost,
but I'd consider it as a starting point.

To substantiate my babbling, I've written a small implementation,
perhaps someone has some use for it ;) [should I GPL it now? - SCNR]

import javax.swing.event.*;
import javax.swing.table.*;
import javax.swing.undo.*;

public class UndoableTableModel extends AbstractTableModel
                                implements TableModelListener {
    private TableModel delegate;
    private UndoableEditSupport support = new UndoableEditSupport();

    public UndoableTableModel( TableModel delegate ) {
        setDelegate( delegate );
    }

    public void setDelegate( TableModel delegate ) {
        if ( this.delegate != null )
            this.delegate.removeTableModelListener( this );
        this.delegate = delegate;
        if ( this.delegate != null )
            this.delegate.addTableModelListener( this );
        fireTableStructureChanged();
    }

    public Class<?> getColumnClass( int columnIndex ) {
        return delegate.getColumnClass( columnIndex );
    }

    public int getColumnCount() {
        return delegate.getColumnCount();
    }

    public String getColumnName( int columnIndex ) {
        return delegate.getColumnName( columnIndex );
    }

    public int getRowCount() {
        return delegate.getRowCount();
    }

    public Object getValueAt( int rowIndex, int columnIndex ) {
        return delegate.getValueAt( rowIndex, columnIndex );
    }

    public boolean isCellEditable( int rowIndex, int columnIndex ) {
        return delegate.isCellEditable( rowIndex, columnIndex );
    }

    public void setValueAt( Object aValue,
                            int rowIndex, int columnIndex ) {
        Object oldValue = delegate.getValueAt( rowIndex, columnIndex );
        delegate.setValueAt( aValue, rowIndex, columnIndex );
        Object newValue = delegate.getValueAt( rowIndex, columnIndex );
        fireChangeEdit( rowIndex, columnIndex, oldValue, newValue );
    }

    public void addUndoableEditListener( UndoableEditListener l ) {
        support.addUndoableEditListener( l );
    }

    public void removeUndoableEditListener( UndoableEditListener l ) {
        support.removeUndoableEditListener( l );
    }

    public void tableChanged( TableModelEvent e ) {
        TableModelEvent newEvent = new TableModelEvent( this,
                e.getFirstRow(), e.getLastRow(), e.getColumn(),
                e.getType() );
        fireTableChanged( newEvent );
    }

    protected void fireChangeEdit( int row, int col, Object oldValue,
                                   Object newValue ) {
        UndoableEdit edit = new TableChangeEdit(row, col,
                oldValue, newValue);
        support.beginUpdate();
        support.postEdit( edit );
        support.endUpdate();
    }

    private class TableChangeEdit extends AbstractUndoableEdit {
        private int columnIndex;
        private int rowIndex;
        private Object oldValue;
        private Object newValue;

        public TableChangeEdit( int rowIndex, int columnIndex,
                                Object oldValue, Object newValue ) {
            this.columnIndex = columnIndex;
            this.rowIndex = rowIndex;
            this.oldValue = oldValue;
            this.newValue = newValue;
        }

        public void undo() {
            super.undo();
            delegate.setValueAt( oldValue, rowIndex, columnIndex );
        }

        public void redo() {
            super.redo();
            delegate.setValueAt( newValue, rowIndex, columnIndex );
        }
    }
}

Bye
Michael
Thomas Weidenfeller - 17 Nov 2006 08:34 GMT
> Thomas Weidenfeller schrieb:
>> e) Make the //UndoableEdit// a //CompoundEdit// for sequences of
[quoted text clipped - 4 lines]
> tables. Either a cell (or row in the case of additions and deletions)
> was updated or it wasn't.

I was assuming table cells with editable text, where you probably want
to undo/redo text changes while you edit, but also undo/redo minor
operations like selection, deselection, and adjustments of selection.

E.g. what should happen if the user has edited some change in a cell,
the change has not been applied to the model, but the user invokes undo
(e.g. via a keyboard shortcut)? Here it seems to me that the JTable (and
not the TableModel) should have delivered change notifications for the
text edits to the undo manager. And these would be candidates for
/CompoundEdit/. Getting that right, however, would mean to have a close
look at the JTable's cell editing behavior. I am to lazy to do that :-).

> To substantiate my babbling, I've written a small implementation,
> perhaps someone has some use for it ;) [should I GPL it now? - SCNR]

Ask a lawyer :-)

/Thomas
Signature

The comp.lang.java.gui FAQ:
http://gd.tuwien.ac.at/faqs/faqs-hierarchy/comp/comp.lang.java.gui/
ftp://ftp.cs.uu.nl/pub/NEWS.ANSWERS/computer-lang/java/gui/faq

Michael Rauscher - 17 Nov 2006 21:57 GMT
Thomas Weidenfeller schrieb:
>> Thomas Weidenfeller schrieb:
>>> e) Make the //UndoableEdit// a //CompoundEdit// for sequences of
[quoted text clipped - 8 lines]
> to undo/redo text changes while you edit, but also undo/redo minor
> operations like selection, deselection, and adjustments of selection.

Your point.

>> To substantiate my babbling, I've written a small implementation,
>> perhaps someone has some use for it ;) [should I GPL it now? - SCNR]
>
> Ask a lawyer :-)

Perhaps Sun could lend me one :)

Bye
Michael
Thomas Weidenfeller - 20 Nov 2006 08:21 GMT
> Thomas Weidenfeller schrieb:
>> Ask a lawyer :-)
>
> Perhaps Sun could lend me one :)

You do not want a Sun lawyer. These are the guys who write 70+ words of
gibberish in a single sentence, as can be witnessed in the JCP agreement.

/Thomas
Signature

The comp.lang.java.gui FAQ:
http://gd.tuwien.ac.at/faqs/faqs-hierarchy/comp/comp.lang.java.gui/
ftp://ftp.cs.uu.nl/pub/NEWS.ANSWERS/computer-lang/java/gui/faq

Michael Rauscher - 20 Nov 2006 09:07 GMT
Thomas Weidenfeller schrieb:
>> Thomas Weidenfeller schrieb:
>>> Ask a lawyer :-)
[quoted text clipped - 3 lines]
> You do not want a Sun lawyer. These are the guys who write 70+ words of
> gibberish in a single sentence, as can be witnessed in the JCP agreement.

Hmm and I thought Sun's 190 lawyers had to read each of Java SE's 6 Mio.
lines of code [1] - ROTFL.

Bye
Michael

[1] http://www.eweek.com/article2/0,1895,2055770,00.asp
Thomas Weidenfeller - 20 Nov 2006 09:37 GMT
> Hmm and I thought Sun's 190 lawyers had to read each of Java SE's 6 Mio.
> lines of code [1] - ROTFL.
[...]
> [1] http://www.eweek.com/article2/0,1895,2055770,00.asp

Nice. That is ample punishment for lawyers, assuming they really do it
line-by-line. And I guess no one of the developers had told them about
text search tools :-)

/Thomas
Signature

The comp.lang.java.gui FAQ:
http://gd.tuwien.ac.at/faqs/faqs-hierarchy/comp/comp.lang.java.gui/
ftp://ftp.cs.uu.nl/pub/NEWS.ANSWERS/computer-lang/java/gui/faq



Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.