java/JFTable/src/cz/frantovo/gui/tabulky/TableSorterModel.java
author František Kučera <franta-hg@frantovo.cz>
Sat Feb 28 17:11:20 2009 +0100 (2009-02-28)
changeset 3 74211841e25c
parent 2 29fb34084b12
child 4 44c9171272a0
permissions -rwxr-xr-x
Naformátování zdrojového kódu
franta-hg@0
     1
package cz.frantovo.gui.tabulky;
franta-hg@0
     2
franta-hg@0
     3
import java.awt.Component;
franta-hg@0
     4
import java.awt.event.MouseAdapter;
franta-hg@0
     5
import java.awt.event.MouseEvent;
franta-hg@0
     6
import java.awt.event.MouseListener;
franta-hg@0
     7
import java.util.ArrayList;
franta-hg@0
     8
import java.util.Arrays;
franta-hg@0
     9
import java.util.Comparator;
franta-hg@0
    10
import java.util.HashMap;
franta-hg@0
    11
import java.util.Iterator;
franta-hg@0
    12
import java.util.List;
franta-hg@0
    13
import java.util.Map;
franta-hg@0
    14
franta-hg@0
    15
import javax.swing.Icon;
franta-hg@0
    16
import javax.swing.ImageIcon;
franta-hg@0
    17
import javax.swing.JLabel;
franta-hg@0
    18
import javax.swing.JTable;
franta-hg@0
    19
import javax.swing.event.TableModelEvent;
franta-hg@0
    20
import javax.swing.event.TableModelListener;
franta-hg@0
    21
import javax.swing.table.AbstractTableModel;
franta-hg@0
    22
import javax.swing.table.JTableHeader;
franta-hg@0
    23
import javax.swing.table.TableCellRenderer;
franta-hg@0
    24
import javax.swing.table.TableColumnModel;
franta-hg@0
    25
import javax.swing.table.TableModel;
franta-hg@0
    26
franta-hg@0
    27
/**
franta-hg@2
    28
 * <p>Tato třída přidává tabulce funkčnost řazení podle více sloupců. Skutečný
franta-hg@2
    29
 * model obsahující data stačí obalit touto třídou + je potřeba nastavit:
franta-hg@2
    30
 * tableSorterModel.setTableHeader(table.getTableHeader());</p>
franta-hg@0
    31
 * 
franta-hg@2
    32
 * <p>Jednodušší ale je používat třídu cz.frantovo.gui.tabulky.JFTable, která všechno
franta-hg@2
    33
 * udělá za vás. </p>
franta-hg@2
    34
 * 
franta-hg@2
    35
 * <p>Tento TableSorterModel je založen na původním TableSorter od autorů: Philip
franta-hg@2
    36
 * Milne, Brendon McLean, Dan van Enckevort a Parwinder Sekhon.</p>
franta-hg@2
    37
 *
franta-hg@2
    38
 * <p>Já jsem přidal hezčí grafické šipky v záhlaví tabulky</p>
franta-hg@0
    39
 * 
franta-hg@0
    40
 * @author František Kučera
franta-hg@0
    41
 */
franta-hg@0
    42
public class TableSorterModel extends AbstractTableModel {
franta-hg@0
    43
franta-hg@3
    44
    private static final long serialVersionUID = 7902301859145867387L;
franta-hg@3
    45
    protected TableModel tableModel;
franta-hg@3
    46
    public static final int DESCENDING = -1;
franta-hg@3
    47
    public static final int NOT_SORTED = 0;
franta-hg@3
    48
    public static final int ASCENDING = 1;
franta-hg@3
    49
    private static Directive EMPTY_DIRECTIVE = new Directive(-1,
franta-hg@3
    50
            NOT_SORTED);
franta-hg@3
    51
    public static final Comparator COMPARABLE_COMAPRATOR = new Comparator() {
franta-hg@0
    52
franta-hg@3
    53
        public int compare(Object o1,
franta-hg@3
    54
                Object o2) {
franta-hg@3
    55
            return ((Comparable) o1).compareTo(o2);
franta-hg@3
    56
        }
franta-hg@3
    57
    };
franta-hg@3
    58
    public static final Comparator LEXICAL_COMPARATOR = new Comparator() {
franta-hg@0
    59
franta-hg@3
    60
        public int compare(Object o1,
franta-hg@3
    61
                Object o2) {
franta-hg@3
    62
            return o1.toString().compareTo(o2.toString());
franta-hg@3
    63
        }
franta-hg@3
    64
    };
franta-hg@3
    65
    private Row[] viewToModel;
franta-hg@3
    66
    private int[] modelToView;
franta-hg@3
    67
    private JTableHeader tableHeader;
franta-hg@3
    68
    private MouseListener mouseListener;
franta-hg@3
    69
    private TableModelListener tableModelListener;
franta-hg@3
    70
    private Map columnComparators = new HashMap();
franta-hg@3
    71
    private List sortingColumns = new ArrayList();
franta-hg@3
    72
    private ImageIcon headerIconDown = new ImageIcon(getClass().getResource("/cz/frantovo/gui/tabulky/dolu.png"));
franta-hg@3
    73
    private ImageIcon headerIconUp = new ImageIcon(getClass().getResource("/cz/frantovo/gui/tabulky/nahoru.png"));
franta-hg@0
    74
franta-hg@3
    75
    public TableSorterModel() {
franta-hg@3
    76
        this.mouseListener = new MouseHandler();
franta-hg@3
    77
        this.tableModelListener = new TableModelHandler();
franta-hg@3
    78
    }
franta-hg@0
    79
franta-hg@3
    80
    public TableSorterModel(TableModel tableModel) {
franta-hg@3
    81
        this();
franta-hg@3
    82
        setTableModel(tableModel);
franta-hg@3
    83
    }
franta-hg@0
    84
franta-hg@3
    85
    public TableSorterModel(TableModel tableModel,
franta-hg@3
    86
            JTableHeader tableHeader) {
franta-hg@3
    87
        this();
franta-hg@3
    88
        setTableHeader(tableHeader);
franta-hg@3
    89
        setTableModel(tableModel);
franta-hg@3
    90
    }
franta-hg@0
    91
franta-hg@3
    92
    private void clearSortingState() {
franta-hg@3
    93
        viewToModel = null;
franta-hg@3
    94
        modelToView = null;
franta-hg@3
    95
    }
franta-hg@0
    96
franta-hg@3
    97
    public TableModel getTableModel() {
franta-hg@3
    98
        return tableModel;
franta-hg@3
    99
    }
franta-hg@0
   100
franta-hg@3
   101
    public void setTableModel(TableModel tableModel) {
franta-hg@3
   102
        if (this.tableModel != null) {
franta-hg@3
   103
            this.tableModel.removeTableModelListener(tableModelListener);
franta-hg@0
   104
        }
franta-hg@0
   105
franta-hg@3
   106
        this.tableModel = tableModel;
franta-hg@3
   107
        if (this.tableModel != null) {
franta-hg@3
   108
            this.tableModel.addTableModelListener(tableModelListener);
franta-hg@0
   109
        }
franta-hg@0
   110
franta-hg@3
   111
        clearSortingState();
franta-hg@3
   112
        fireTableStructureChanged();
franta-hg@3
   113
    }
franta-hg@3
   114
franta-hg@3
   115
    public JTableHeader getTableHeader() {
franta-hg@3
   116
        return tableHeader;
franta-hg@3
   117
    }
franta-hg@3
   118
franta-hg@3
   119
    public void setTableHeader(JTableHeader tableHeader) {
franta-hg@3
   120
        if (this.tableHeader != null) {
franta-hg@3
   121
            this.tableHeader.removeMouseListener(mouseListener);
franta-hg@3
   122
            TableCellRenderer defaultRenderer = this.tableHeader.getDefaultRenderer();
franta-hg@3
   123
            if (defaultRenderer instanceof SortableHeaderRenderer) {
franta-hg@3
   124
                this.tableHeader.setDefaultRenderer(((SortableHeaderRenderer) defaultRenderer).tableCellRenderer);
franta-hg@3
   125
            }
franta-hg@3
   126
        }
franta-hg@3
   127
        this.tableHeader = tableHeader;
franta-hg@3
   128
        if (this.tableHeader != null) {
franta-hg@3
   129
            this.tableHeader.addMouseListener(mouseListener);
franta-hg@3
   130
            this.tableHeader.setDefaultRenderer(new SortableHeaderRenderer(this.tableHeader.getDefaultRenderer()));
franta-hg@3
   131
        }
franta-hg@3
   132
    }
franta-hg@3
   133
franta-hg@3
   134
    public boolean isSorting() {
franta-hg@3
   135
        return sortingColumns.size() != 0;
franta-hg@3
   136
    }
franta-hg@3
   137
franta-hg@3
   138
    private Directive getDirective(int column) {
franta-hg@3
   139
        for (int i = 0; i < sortingColumns.size(); i++) {
franta-hg@3
   140
            Directive directive = (Directive) sortingColumns.get(i);
franta-hg@3
   141
            if (directive.column == column) {
franta-hg@3
   142
                return directive;
franta-hg@3
   143
            }
franta-hg@3
   144
        }
franta-hg@3
   145
        return EMPTY_DIRECTIVE;
franta-hg@3
   146
    }
franta-hg@3
   147
franta-hg@3
   148
    public int getSortingStatus(int column) {
franta-hg@3
   149
        return getDirective(column).direction;
franta-hg@3
   150
    }
franta-hg@3
   151
franta-hg@3
   152
    private void sortingStatusChanged() {
franta-hg@3
   153
        clearSortingState();
franta-hg@3
   154
        fireTableDataChanged();
franta-hg@3
   155
        if (tableHeader != null) {
franta-hg@3
   156
            tableHeader.repaint();
franta-hg@3
   157
        }
franta-hg@3
   158
    }
franta-hg@3
   159
franta-hg@3
   160
    public void setSortingStatus(int column,
franta-hg@3
   161
            int status) {
franta-hg@3
   162
        Directive directive = getDirective(column);
franta-hg@3
   163
        if (directive != EMPTY_DIRECTIVE) {
franta-hg@3
   164
            sortingColumns.remove(directive);
franta-hg@3
   165
        }
franta-hg@3
   166
        if (status != NOT_SORTED) {
franta-hg@3
   167
            sortingColumns.add(new Directive(column,
franta-hg@3
   168
                    status));
franta-hg@3
   169
        }
franta-hg@3
   170
        sortingStatusChanged();
franta-hg@3
   171
    }
franta-hg@3
   172
franta-hg@3
   173
    protected Icon getHeaderRendererIcon(int column,
franta-hg@3
   174
            int size) {
franta-hg@3
   175
        Directive directive = getDirective(column);
franta-hg@3
   176
        if (directive == EMPTY_DIRECTIVE) {
franta-hg@3
   177
            return null;
franta-hg@0
   178
        }
franta-hg@0
   179
franta-hg@3
   180
        if (directive.direction == DESCENDING) {
franta-hg@3
   181
            return headerIconDown;
franta-hg@3
   182
        } else {
franta-hg@3
   183
            return headerIconUp;
franta-hg@3
   184
        }
franta-hg@3
   185
    }
franta-hg@3
   186
franta-hg@3
   187
    private void cancelSorting() {
franta-hg@3
   188
        sortingColumns.clear();
franta-hg@3
   189
        sortingStatusChanged();
franta-hg@3
   190
    }
franta-hg@3
   191
franta-hg@3
   192
    public void setColumnComparator(Class type,
franta-hg@3
   193
            Comparator comparator) {
franta-hg@3
   194
        if (comparator == null) {
franta-hg@3
   195
            columnComparators.remove(type);
franta-hg@3
   196
        } else {
franta-hg@3
   197
            columnComparators.put(type,
franta-hg@3
   198
                    comparator);
franta-hg@3
   199
        }
franta-hg@3
   200
    }
franta-hg@3
   201
franta-hg@3
   202
    protected Comparator getComparator(int column) {
franta-hg@3
   203
        Class columnType = tableModel.getColumnClass(column);
franta-hg@3
   204
        Comparator comparator = (Comparator) columnComparators.get(columnType);
franta-hg@3
   205
        if (comparator != null) {
franta-hg@3
   206
            return comparator;
franta-hg@3
   207
        }
franta-hg@3
   208
        if (Comparable.class.isAssignableFrom(columnType)) {
franta-hg@3
   209
            return COMPARABLE_COMAPRATOR;
franta-hg@3
   210
        }
franta-hg@3
   211
        return LEXICAL_COMPARATOR;
franta-hg@3
   212
    }
franta-hg@3
   213
franta-hg@3
   214
    private Row[] getViewToModel() {
franta-hg@3
   215
        if (viewToModel == null) {
franta-hg@3
   216
            int tableModelRowCount = tableModel.getRowCount();
franta-hg@3
   217
            viewToModel = new Row[tableModelRowCount];
franta-hg@3
   218
            for (int row = 0; row < tableModelRowCount; row++) {
franta-hg@3
   219
                viewToModel[row] = new Row(row);
franta-hg@3
   220
            }
franta-hg@3
   221
franta-hg@3
   222
            if (isSorting()) {
franta-hg@3
   223
                Arrays.sort(viewToModel);
franta-hg@3
   224
            }
franta-hg@3
   225
        }
franta-hg@3
   226
        return viewToModel;
franta-hg@3
   227
    }
franta-hg@3
   228
franta-hg@3
   229
    public int modelIndex(int viewIndex) {
franta-hg@3
   230
        if (viewIndex > -1 && viewIndex < getViewToModel().length) {
franta-hg@3
   231
            return getViewToModel()[viewIndex].modelIndex;
franta-hg@3
   232
        } else {
franta-hg@3
   233
            return -1;
franta-hg@3
   234
        }
franta-hg@3
   235
    }
franta-hg@3
   236
franta-hg@3
   237
    private int[] getModelToView() {
franta-hg@3
   238
        if (modelToView == null) {
franta-hg@3
   239
            int n = getViewToModel().length;
franta-hg@3
   240
            modelToView = new int[n];
franta-hg@3
   241
            for (int i = 0; i < n; i++) {
franta-hg@3
   242
                modelToView[modelIndex(i)] = i;
franta-hg@3
   243
            }
franta-hg@3
   244
        }
franta-hg@3
   245
        return modelToView;
franta-hg@3
   246
    }
franta-hg@3
   247
franta-hg@3
   248
    // Metody rozhran� TableModel
franta-hg@3
   249
    public int getRowCount() {
franta-hg@3
   250
        return (tableModel == null) ? 0 : tableModel.getRowCount();
franta-hg@3
   251
    }
franta-hg@3
   252
franta-hg@3
   253
    public int getColumnCount() {
franta-hg@3
   254
        return (tableModel == null) ? 0 : tableModel.getColumnCount();
franta-hg@3
   255
    }
franta-hg@3
   256
franta-hg@3
   257
    public String getColumnName(int column) {
franta-hg@3
   258
        return tableModel.getColumnName(column);
franta-hg@3
   259
    }
franta-hg@3
   260
franta-hg@3
   261
    public Class getColumnClass(int column) {
franta-hg@3
   262
        return tableModel.getColumnClass(column);
franta-hg@3
   263
    }
franta-hg@3
   264
franta-hg@3
   265
    public boolean isCellEditable(int row,
franta-hg@3
   266
            int column) {
franta-hg@3
   267
        return tableModel.isCellEditable(modelIndex(row),
franta-hg@3
   268
                column);
franta-hg@3
   269
    }
franta-hg@3
   270
franta-hg@3
   271
    public Object getValueAt(int row,
franta-hg@3
   272
            int column) {
franta-hg@3
   273
        return tableModel.getValueAt(modelIndex(row),
franta-hg@3
   274
                column);
franta-hg@3
   275
    }
franta-hg@3
   276
franta-hg@3
   277
    public void setValueAt(Object aValue,
franta-hg@3
   278
            int row,
franta-hg@3
   279
            int column) {
franta-hg@3
   280
        tableModel.setValueAt(aValue,
franta-hg@3
   281
                modelIndex(row),
franta-hg@3
   282
                column);
franta-hg@3
   283
    }
franta-hg@3
   284
franta-hg@3
   285
    // Pomocn� t��dy
franta-hg@3
   286
    private class Row implements Comparable {
franta-hg@3
   287
franta-hg@3
   288
        private int modelIndex;
franta-hg@3
   289
franta-hg@3
   290
        public Row(int index) {
franta-hg@3
   291
            this.modelIndex = index;
franta-hg@0
   292
        }
franta-hg@0
   293
franta-hg@3
   294
        public int compareTo(Object o) {
franta-hg@3
   295
            int row1 = modelIndex;
franta-hg@3
   296
            int row2 = ((Row) o).modelIndex;
franta-hg@3
   297
franta-hg@3
   298
            for (Iterator it = sortingColumns.iterator(); it.hasNext();) {
franta-hg@3
   299
                Directive directive = (Directive) it.next();
franta-hg@3
   300
                int column = directive.column;
franta-hg@3
   301
                Object o1 = tableModel.getValueAt(row1,
franta-hg@3
   302
                        column);
franta-hg@3
   303
                Object o2 = tableModel.getValueAt(row2,
franta-hg@3
   304
                        column);
franta-hg@3
   305
franta-hg@3
   306
                int comparison = 0;
franta-hg@3
   307
                // Define null less than everything, except
franta-hg@3
   308
                // null.
franta-hg@3
   309
                if (o1 == null && o2 == null) {
franta-hg@3
   310
                    comparison = 0;
franta-hg@3
   311
                } else if (o1 == null) {
franta-hg@3
   312
                    comparison = -1;
franta-hg@3
   313
                } else if (o2 == null) {
franta-hg@3
   314
                    comparison = 1;
franta-hg@3
   315
                } else {
franta-hg@3
   316
                    comparison = getComparator(column).compare(o1,
franta-hg@3
   317
                            o2);
franta-hg@3
   318
                }
franta-hg@3
   319
                if (comparison != 0) {
franta-hg@3
   320
                    return directive.direction == DESCENDING ? -comparison : comparison;
franta-hg@3
   321
                }
franta-hg@3
   322
            }
franta-hg@3
   323
            return 0;
franta-hg@3
   324
        }
franta-hg@3
   325
    }
franta-hg@3
   326
franta-hg@3
   327
    private class TableModelHandler implements TableModelListener {
franta-hg@3
   328
franta-hg@3
   329
        public void tableChanged(TableModelEvent e) {
franta-hg@3
   330
            // If we're not sorting by anything, just pass the event
franta-hg@3
   331
            // along.
franta-hg@3
   332
            if (!isSorting()) {
franta-hg@3
   333
                clearSortingState();
franta-hg@3
   334
                fireTableChanged(e);
franta-hg@3
   335
                return;
franta-hg@3
   336
            }
franta-hg@3
   337
franta-hg@3
   338
            // If the table structure has changed, cancel the
franta-hg@3
   339
            // sorting; the
franta-hg@3
   340
            // sorting columns may have been either moved or deleted
franta-hg@3
   341
            // from
franta-hg@3
   342
            // the model.
franta-hg@3
   343
            if (e.getFirstRow() == TableModelEvent.HEADER_ROW) {
franta-hg@3
   344
                cancelSorting();
franta-hg@3
   345
                fireTableChanged(e);
franta-hg@3
   346
                return;
franta-hg@3
   347
            }
franta-hg@3
   348
franta-hg@3
   349
            // We can map a cell event through to the view without
franta-hg@3
   350
            // widening
franta-hg@3
   351
            // when the following conditions apply:
franta-hg@3
   352
            //
franta-hg@3
   353
            // a) all the changes are on one row (e.getFirstRow() ==
franta-hg@3
   354
            // e.getLastRow()) and,
franta-hg@3
   355
            // b) all the changes are in one column (column !=
franta-hg@3
   356
            // TableModelEvent.ALL_COLUMNS) and,
franta-hg@3
   357
            // c) we are not sorting on that column
franta-hg@3
   358
            // (getSortingStatus(column) == NOT_SORTED) and,
franta-hg@3
   359
            // d) a reverse lookup will not trigger a sort
franta-hg@3
   360
            // (modelToView != null)
franta-hg@3
   361
            //
franta-hg@3
   362
            // Note: INSERT and DELETE events fail this test as they
franta-hg@3
   363
            // have column == ALL_COLUMNS.
franta-hg@3
   364
            //
franta-hg@3
   365
            // The last check, for (modelToView != null) is to see
franta-hg@3
   366
            // if modelToView
franta-hg@3
   367
            // is already allocated. If we don't do this check;
franta-hg@3
   368
            // sorting can become
franta-hg@3
   369
            // a performance bottleneck for applications where cells
franta-hg@3
   370
            // change rapidly in different parts of the table. If
franta-hg@3
   371
            // cells
franta-hg@3
   372
            // change alternately in the sorting column and then
franta-hg@3
   373
            // outside of
franta-hg@3
   374
            // it this class can end up re-sorting on alternate cell
franta-hg@3
   375
            // updates -
franta-hg@3
   376
            // which can be a performance problem for large tables.
franta-hg@3
   377
            // The last
franta-hg@3
   378
            // clause avoids this problem.
franta-hg@3
   379
            int column = e.getColumn();
franta-hg@3
   380
            if (e.getFirstRow() == e.getLastRow() && column != TableModelEvent.ALL_COLUMNS && getSortingStatus(column) == NOT_SORTED && modelToView != null) {
franta-hg@3
   381
                int viewIndex = getModelToView()[e.getFirstRow()];
franta-hg@3
   382
                fireTableChanged(new TableModelEvent(TableSorterModel.this,
franta-hg@3
   383
                        viewIndex,
franta-hg@3
   384
                        viewIndex,
franta-hg@3
   385
                        column,
franta-hg@3
   386
                        e.getType()));
franta-hg@3
   387
                return;
franta-hg@3
   388
            }
franta-hg@3
   389
franta-hg@3
   390
            // Something has happened to the data that may have
franta-hg@3
   391
            // invalidated the row order.
franta-hg@3
   392
            clearSortingState();
franta-hg@3
   393
            fireTableDataChanged();
franta-hg@3
   394
            return;
franta-hg@3
   395
        }
franta-hg@3
   396
    }
franta-hg@3
   397
franta-hg@3
   398
    private class MouseHandler extends MouseAdapter {
franta-hg@3
   399
franta-hg@3
   400
        public void mouseClicked(MouseEvent e) {
franta-hg@3
   401
            JTableHeader h = (JTableHeader) e.getSource();
franta-hg@3
   402
            TableColumnModel columnModel = h.getColumnModel();
franta-hg@3
   403
            int viewColumn = columnModel.getColumnIndexAtX(e.getX());
franta-hg@3
   404
            int column = columnModel.getColumn(viewColumn).getModelIndex();
franta-hg@3
   405
            if (column != -1) {
franta-hg@3
   406
                int status = getSortingStatus(column);
franta-hg@3
   407
                if (!e.isControlDown()) {
franta-hg@3
   408
                    cancelSorting();
franta-hg@3
   409
                }
franta-hg@3
   410
                // Cycle the sorting states through {NOT_SORTED,
franta-hg@3
   411
                // ASCENDING, DESCENDING} or
franta-hg@3
   412
                // {NOT_SORTED, DESCENDING, ASCENDING} depending
franta-hg@3
   413
                // on whether shift is pressed.
franta-hg@3
   414
                status = status + (e.isShiftDown() ? -1 : 1);
franta-hg@3
   415
                status = (status + 4) % 3 - 1; // signed mod,
franta-hg@3
   416
                // returning
franta-hg@3
   417
                // {-1, 0, 1}
franta-hg@3
   418
                setSortingStatus(column,
franta-hg@3
   419
                        status);
franta-hg@3
   420
            }
franta-hg@3
   421
        }
franta-hg@3
   422
    }
franta-hg@3
   423
franta-hg@3
   424
    private class SortableHeaderRenderer implements TableCellRenderer {
franta-hg@3
   425
franta-hg@3
   426
        private TableCellRenderer tableCellRenderer;
franta-hg@3
   427
franta-hg@3
   428
        public SortableHeaderRenderer(TableCellRenderer tableCellRenderer) {
franta-hg@3
   429
            this.tableCellRenderer = tableCellRenderer;
franta-hg@0
   430
        }
franta-hg@0
   431
franta-hg@3
   432
        public Component getTableCellRendererComponent(JTable table,
franta-hg@3
   433
                Object value,
franta-hg@3
   434
                boolean isSelected,
franta-hg@3
   435
                boolean hasFocus,
franta-hg@3
   436
                int row,
franta-hg@3
   437
                int column) {
franta-hg@3
   438
            Component c = tableCellRenderer.getTableCellRendererComponent(table,
franta-hg@3
   439
                    value,
franta-hg@3
   440
                    isSelected,
franta-hg@3
   441
                    hasFocus,
franta-hg@3
   442
                    row,
franta-hg@3
   443
                    column);
franta-hg@3
   444
            if (c instanceof JLabel) {
franta-hg@3
   445
                JLabel l = (JLabel) c;
franta-hg@3
   446
                l.setHorizontalTextPosition(JLabel.LEFT);
franta-hg@3
   447
                int modelColumn = table.convertColumnIndexToModel(column);
franta-hg@3
   448
                l.setIcon(getHeaderRendererIcon(modelColumn,
franta-hg@3
   449
                        l.getFont().getSize()));
franta-hg@3
   450
            }
franta-hg@3
   451
            return c;
franta-hg@3
   452
        }
franta-hg@3
   453
    }
franta-hg@0
   454
franta-hg@3
   455
    private static class Directive {
franta-hg@0
   456
franta-hg@3
   457
        private int column;
franta-hg@3
   458
        private int direction;
franta-hg@3
   459
franta-hg@3
   460
        public Directive(int column,
franta-hg@3
   461
                int direction) {
franta-hg@3
   462
            this.column = column;
franta-hg@3
   463
            this.direction = direction;
franta-hg@0
   464
        }
franta-hg@3
   465
    }
franta-hg@0
   466
franta-hg@3
   467
    public void fireTableColumnUpdated(int index) {
franta-hg@3
   468
        for (int i = 0; i < getRowCount(); i++) {
franta-hg@3
   469
            fireTableCellUpdated(i,
franta-hg@3
   470
                    index);
franta-hg@0
   471
        }
franta-hg@3
   472
    }
franta-hg@0
   473
}