1.1 --- a/java/JFTable/src/cz/frantovo/gui/tabulky/TableSorterModel.java Sat Feb 28 17:10:53 2009 +0100
1.2 +++ b/java/JFTable/src/cz/frantovo/gui/tabulky/TableSorterModel.java Sat Feb 28 17:11:20 2009 +0100
1.3 @@ -1,6 +1,5 @@
1.4 package cz.frantovo.gui.tabulky;
1.5
1.6 -
1.7 import java.awt.Component;
1.8 import java.awt.event.MouseAdapter;
1.9 import java.awt.event.MouseEvent;
1.10 @@ -40,493 +39,435 @@
1.11 *
1.12 * @author František Kučera
1.13 */
1.14 -
1.15 public class TableSorterModel extends AbstractTableModel {
1.16
1.17 - private static final long serialVersionUID = 7902301859145867387L;
1.18 + private static final long serialVersionUID = 7902301859145867387L;
1.19 + protected TableModel tableModel;
1.20 + public static final int DESCENDING = -1;
1.21 + public static final int NOT_SORTED = 0;
1.22 + public static final int ASCENDING = 1;
1.23 + private static Directive EMPTY_DIRECTIVE = new Directive(-1,
1.24 + NOT_SORTED);
1.25 + public static final Comparator COMPARABLE_COMAPRATOR = new Comparator() {
1.26
1.27 - protected TableModel tableModel;
1.28 + public int compare(Object o1,
1.29 + Object o2) {
1.30 + return ((Comparable) o1).compareTo(o2);
1.31 + }
1.32 + };
1.33 + public static final Comparator LEXICAL_COMPARATOR = new Comparator() {
1.34
1.35 - public static final int DESCENDING = -1;
1.36 + public int compare(Object o1,
1.37 + Object o2) {
1.38 + return o1.toString().compareTo(o2.toString());
1.39 + }
1.40 + };
1.41 + private Row[] viewToModel;
1.42 + private int[] modelToView;
1.43 + private JTableHeader tableHeader;
1.44 + private MouseListener mouseListener;
1.45 + private TableModelListener tableModelListener;
1.46 + private Map columnComparators = new HashMap();
1.47 + private List sortingColumns = new ArrayList();
1.48 + private ImageIcon headerIconDown = new ImageIcon(getClass().getResource("/cz/frantovo/gui/tabulky/dolu.png"));
1.49 + private ImageIcon headerIconUp = new ImageIcon(getClass().getResource("/cz/frantovo/gui/tabulky/nahoru.png"));
1.50
1.51 - public static final int NOT_SORTED = 0;
1.52 + public TableSorterModel() {
1.53 + this.mouseListener = new MouseHandler();
1.54 + this.tableModelListener = new TableModelHandler();
1.55 + }
1.56
1.57 - public static final int ASCENDING = 1;
1.58 + public TableSorterModel(TableModel tableModel) {
1.59 + this();
1.60 + setTableModel(tableModel);
1.61 + }
1.62
1.63 - private static Directive EMPTY_DIRECTIVE = new Directive( -1,
1.64 - NOT_SORTED);
1.65 + public TableSorterModel(TableModel tableModel,
1.66 + JTableHeader tableHeader) {
1.67 + this();
1.68 + setTableHeader(tableHeader);
1.69 + setTableModel(tableModel);
1.70 + }
1.71
1.72 - public static final Comparator COMPARABLE_COMAPRATOR = new Comparator() {
1.73 + private void clearSortingState() {
1.74 + viewToModel = null;
1.75 + modelToView = null;
1.76 + }
1.77
1.78 - public int compare (Object o1,
1.79 - Object o2)
1.80 - {
1.81 - return ((Comparable) o1).compareTo(o2);
1.82 - }
1.83 - };
1.84 + public TableModel getTableModel() {
1.85 + return tableModel;
1.86 + }
1.87
1.88 - public static final Comparator LEXICAL_COMPARATOR = new Comparator() {
1.89 -
1.90 - public int compare (Object o1,
1.91 - Object o2)
1.92 - {
1.93 - return o1.toString().compareTo(o2.toString());
1.94 - }
1.95 - };
1.96 -
1.97 - private Row[] viewToModel;
1.98 -
1.99 - private int[] modelToView;
1.100 -
1.101 - private JTableHeader tableHeader;
1.102 -
1.103 - private MouseListener mouseListener;
1.104 -
1.105 - private TableModelListener tableModelListener;
1.106 -
1.107 - private Map columnComparators = new HashMap();
1.108 -
1.109 - private List sortingColumns = new ArrayList();
1.110 -
1.111 - private ImageIcon headerIconDown = new ImageIcon(getClass().getResource("/cz/frantovo/gui/tabulky/dolu.png"));
1.112 -
1.113 - private ImageIcon headerIconUp = new ImageIcon(getClass().getResource("/cz/frantovo/gui/tabulky/nahoru.png"));
1.114 -
1.115 - public TableSorterModel ()
1.116 - {
1.117 - this.mouseListener = new MouseHandler();
1.118 - this.tableModelListener = new TableModelHandler();
1.119 + public void setTableModel(TableModel tableModel) {
1.120 + if (this.tableModel != null) {
1.121 + this.tableModel.removeTableModelListener(tableModelListener);
1.122 }
1.123
1.124 - public TableSorterModel (TableModel tableModel)
1.125 - {
1.126 - this();
1.127 - setTableModel(tableModel);
1.128 + this.tableModel = tableModel;
1.129 + if (this.tableModel != null) {
1.130 + this.tableModel.addTableModelListener(tableModelListener);
1.131 }
1.132
1.133 - public TableSorterModel (TableModel tableModel,
1.134 - JTableHeader tableHeader)
1.135 - {
1.136 - this();
1.137 - setTableHeader(tableHeader);
1.138 - setTableModel(tableModel);
1.139 + clearSortingState();
1.140 + fireTableStructureChanged();
1.141 + }
1.142 +
1.143 + public JTableHeader getTableHeader() {
1.144 + return tableHeader;
1.145 + }
1.146 +
1.147 + public void setTableHeader(JTableHeader tableHeader) {
1.148 + if (this.tableHeader != null) {
1.149 + this.tableHeader.removeMouseListener(mouseListener);
1.150 + TableCellRenderer defaultRenderer = this.tableHeader.getDefaultRenderer();
1.151 + if (defaultRenderer instanceof SortableHeaderRenderer) {
1.152 + this.tableHeader.setDefaultRenderer(((SortableHeaderRenderer) defaultRenderer).tableCellRenderer);
1.153 + }
1.154 + }
1.155 + this.tableHeader = tableHeader;
1.156 + if (this.tableHeader != null) {
1.157 + this.tableHeader.addMouseListener(mouseListener);
1.158 + this.tableHeader.setDefaultRenderer(new SortableHeaderRenderer(this.tableHeader.getDefaultRenderer()));
1.159 + }
1.160 + }
1.161 +
1.162 + public boolean isSorting() {
1.163 + return sortingColumns.size() != 0;
1.164 + }
1.165 +
1.166 + private Directive getDirective(int column) {
1.167 + for (int i = 0; i < sortingColumns.size(); i++) {
1.168 + Directive directive = (Directive) sortingColumns.get(i);
1.169 + if (directive.column == column) {
1.170 + return directive;
1.171 + }
1.172 + }
1.173 + return EMPTY_DIRECTIVE;
1.174 + }
1.175 +
1.176 + public int getSortingStatus(int column) {
1.177 + return getDirective(column).direction;
1.178 + }
1.179 +
1.180 + private void sortingStatusChanged() {
1.181 + clearSortingState();
1.182 + fireTableDataChanged();
1.183 + if (tableHeader != null) {
1.184 + tableHeader.repaint();
1.185 + }
1.186 + }
1.187 +
1.188 + public void setSortingStatus(int column,
1.189 + int status) {
1.190 + Directive directive = getDirective(column);
1.191 + if (directive != EMPTY_DIRECTIVE) {
1.192 + sortingColumns.remove(directive);
1.193 + }
1.194 + if (status != NOT_SORTED) {
1.195 + sortingColumns.add(new Directive(column,
1.196 + status));
1.197 + }
1.198 + sortingStatusChanged();
1.199 + }
1.200 +
1.201 + protected Icon getHeaderRendererIcon(int column,
1.202 + int size) {
1.203 + Directive directive = getDirective(column);
1.204 + if (directive == EMPTY_DIRECTIVE) {
1.205 + return null;
1.206 }
1.207
1.208 - private void clearSortingState ()
1.209 - {
1.210 - viewToModel = null;
1.211 - modelToView = null;
1.212 + if (directive.direction == DESCENDING) {
1.213 + return headerIconDown;
1.214 + } else {
1.215 + return headerIconUp;
1.216 + }
1.217 + }
1.218 +
1.219 + private void cancelSorting() {
1.220 + sortingColumns.clear();
1.221 + sortingStatusChanged();
1.222 + }
1.223 +
1.224 + public void setColumnComparator(Class type,
1.225 + Comparator comparator) {
1.226 + if (comparator == null) {
1.227 + columnComparators.remove(type);
1.228 + } else {
1.229 + columnComparators.put(type,
1.230 + comparator);
1.231 + }
1.232 + }
1.233 +
1.234 + protected Comparator getComparator(int column) {
1.235 + Class columnType = tableModel.getColumnClass(column);
1.236 + Comparator comparator = (Comparator) columnComparators.get(columnType);
1.237 + if (comparator != null) {
1.238 + return comparator;
1.239 + }
1.240 + if (Comparable.class.isAssignableFrom(columnType)) {
1.241 + return COMPARABLE_COMAPRATOR;
1.242 + }
1.243 + return LEXICAL_COMPARATOR;
1.244 + }
1.245 +
1.246 + private Row[] getViewToModel() {
1.247 + if (viewToModel == null) {
1.248 + int tableModelRowCount = tableModel.getRowCount();
1.249 + viewToModel = new Row[tableModelRowCount];
1.250 + for (int row = 0; row < tableModelRowCount; row++) {
1.251 + viewToModel[row] = new Row(row);
1.252 + }
1.253 +
1.254 + if (isSorting()) {
1.255 + Arrays.sort(viewToModel);
1.256 + }
1.257 + }
1.258 + return viewToModel;
1.259 + }
1.260 +
1.261 + public int modelIndex(int viewIndex) {
1.262 + if (viewIndex > -1 && viewIndex < getViewToModel().length) {
1.263 + return getViewToModel()[viewIndex].modelIndex;
1.264 + } else {
1.265 + return -1;
1.266 + }
1.267 + }
1.268 +
1.269 + private int[] getModelToView() {
1.270 + if (modelToView == null) {
1.271 + int n = getViewToModel().length;
1.272 + modelToView = new int[n];
1.273 + for (int i = 0; i < n; i++) {
1.274 + modelToView[modelIndex(i)] = i;
1.275 + }
1.276 + }
1.277 + return modelToView;
1.278 + }
1.279 +
1.280 + // Metody rozhran� TableModel
1.281 + public int getRowCount() {
1.282 + return (tableModel == null) ? 0 : tableModel.getRowCount();
1.283 + }
1.284 +
1.285 + public int getColumnCount() {
1.286 + return (tableModel == null) ? 0 : tableModel.getColumnCount();
1.287 + }
1.288 +
1.289 + public String getColumnName(int column) {
1.290 + return tableModel.getColumnName(column);
1.291 + }
1.292 +
1.293 + public Class getColumnClass(int column) {
1.294 + return tableModel.getColumnClass(column);
1.295 + }
1.296 +
1.297 + public boolean isCellEditable(int row,
1.298 + int column) {
1.299 + return tableModel.isCellEditable(modelIndex(row),
1.300 + column);
1.301 + }
1.302 +
1.303 + public Object getValueAt(int row,
1.304 + int column) {
1.305 + return tableModel.getValueAt(modelIndex(row),
1.306 + column);
1.307 + }
1.308 +
1.309 + public void setValueAt(Object aValue,
1.310 + int row,
1.311 + int column) {
1.312 + tableModel.setValueAt(aValue,
1.313 + modelIndex(row),
1.314 + column);
1.315 + }
1.316 +
1.317 + // Pomocn� t��dy
1.318 + private class Row implements Comparable {
1.319 +
1.320 + private int modelIndex;
1.321 +
1.322 + public Row(int index) {
1.323 + this.modelIndex = index;
1.324 }
1.325
1.326 - public TableModel getTableModel ()
1.327 - {
1.328 - return tableModel;
1.329 + public int compareTo(Object o) {
1.330 + int row1 = modelIndex;
1.331 + int row2 = ((Row) o).modelIndex;
1.332 +
1.333 + for (Iterator it = sortingColumns.iterator(); it.hasNext();) {
1.334 + Directive directive = (Directive) it.next();
1.335 + int column = directive.column;
1.336 + Object o1 = tableModel.getValueAt(row1,
1.337 + column);
1.338 + Object o2 = tableModel.getValueAt(row2,
1.339 + column);
1.340 +
1.341 + int comparison = 0;
1.342 + // Define null less than everything, except
1.343 + // null.
1.344 + if (o1 == null && o2 == null) {
1.345 + comparison = 0;
1.346 + } else if (o1 == null) {
1.347 + comparison = -1;
1.348 + } else if (o2 == null) {
1.349 + comparison = 1;
1.350 + } else {
1.351 + comparison = getComparator(column).compare(o1,
1.352 + o2);
1.353 + }
1.354 + if (comparison != 0) {
1.355 + return directive.direction == DESCENDING ? -comparison : comparison;
1.356 + }
1.357 + }
1.358 + return 0;
1.359 + }
1.360 + }
1.361 +
1.362 + private class TableModelHandler implements TableModelListener {
1.363 +
1.364 + public void tableChanged(TableModelEvent e) {
1.365 + // If we're not sorting by anything, just pass the event
1.366 + // along.
1.367 + if (!isSorting()) {
1.368 + clearSortingState();
1.369 + fireTableChanged(e);
1.370 + return;
1.371 + }
1.372 +
1.373 + // If the table structure has changed, cancel the
1.374 + // sorting; the
1.375 + // sorting columns may have been either moved or deleted
1.376 + // from
1.377 + // the model.
1.378 + if (e.getFirstRow() == TableModelEvent.HEADER_ROW) {
1.379 + cancelSorting();
1.380 + fireTableChanged(e);
1.381 + return;
1.382 + }
1.383 +
1.384 + // We can map a cell event through to the view without
1.385 + // widening
1.386 + // when the following conditions apply:
1.387 + //
1.388 + // a) all the changes are on one row (e.getFirstRow() ==
1.389 + // e.getLastRow()) and,
1.390 + // b) all the changes are in one column (column !=
1.391 + // TableModelEvent.ALL_COLUMNS) and,
1.392 + // c) we are not sorting on that column
1.393 + // (getSortingStatus(column) == NOT_SORTED) and,
1.394 + // d) a reverse lookup will not trigger a sort
1.395 + // (modelToView != null)
1.396 + //
1.397 + // Note: INSERT and DELETE events fail this test as they
1.398 + // have column == ALL_COLUMNS.
1.399 + //
1.400 + // The last check, for (modelToView != null) is to see
1.401 + // if modelToView
1.402 + // is already allocated. If we don't do this check;
1.403 + // sorting can become
1.404 + // a performance bottleneck for applications where cells
1.405 + // change rapidly in different parts of the table. If
1.406 + // cells
1.407 + // change alternately in the sorting column and then
1.408 + // outside of
1.409 + // it this class can end up re-sorting on alternate cell
1.410 + // updates -
1.411 + // which can be a performance problem for large tables.
1.412 + // The last
1.413 + // clause avoids this problem.
1.414 + int column = e.getColumn();
1.415 + if (e.getFirstRow() == e.getLastRow() && column != TableModelEvent.ALL_COLUMNS && getSortingStatus(column) == NOT_SORTED && modelToView != null) {
1.416 + int viewIndex = getModelToView()[e.getFirstRow()];
1.417 + fireTableChanged(new TableModelEvent(TableSorterModel.this,
1.418 + viewIndex,
1.419 + viewIndex,
1.420 + column,
1.421 + e.getType()));
1.422 + return;
1.423 + }
1.424 +
1.425 + // Something has happened to the data that may have
1.426 + // invalidated the row order.
1.427 + clearSortingState();
1.428 + fireTableDataChanged();
1.429 + return;
1.430 + }
1.431 + }
1.432 +
1.433 + private class MouseHandler extends MouseAdapter {
1.434 +
1.435 + public void mouseClicked(MouseEvent e) {
1.436 + JTableHeader h = (JTableHeader) e.getSource();
1.437 + TableColumnModel columnModel = h.getColumnModel();
1.438 + int viewColumn = columnModel.getColumnIndexAtX(e.getX());
1.439 + int column = columnModel.getColumn(viewColumn).getModelIndex();
1.440 + if (column != -1) {
1.441 + int status = getSortingStatus(column);
1.442 + if (!e.isControlDown()) {
1.443 + cancelSorting();
1.444 + }
1.445 + // Cycle the sorting states through {NOT_SORTED,
1.446 + // ASCENDING, DESCENDING} or
1.447 + // {NOT_SORTED, DESCENDING, ASCENDING} depending
1.448 + // on whether shift is pressed.
1.449 + status = status + (e.isShiftDown() ? -1 : 1);
1.450 + status = (status + 4) % 3 - 1; // signed mod,
1.451 + // returning
1.452 + // {-1, 0, 1}
1.453 + setSortingStatus(column,
1.454 + status);
1.455 + }
1.456 + }
1.457 + }
1.458 +
1.459 + private class SortableHeaderRenderer implements TableCellRenderer {
1.460 +
1.461 + private TableCellRenderer tableCellRenderer;
1.462 +
1.463 + public SortableHeaderRenderer(TableCellRenderer tableCellRenderer) {
1.464 + this.tableCellRenderer = tableCellRenderer;
1.465 }
1.466
1.467 - public void setTableModel (TableModel tableModel)
1.468 - {
1.469 - if (this.tableModel != null) {
1.470 - this.tableModel.removeTableModelListener(tableModelListener);
1.471 - }
1.472 + public Component getTableCellRendererComponent(JTable table,
1.473 + Object value,
1.474 + boolean isSelected,
1.475 + boolean hasFocus,
1.476 + int row,
1.477 + int column) {
1.478 + Component c = tableCellRenderer.getTableCellRendererComponent(table,
1.479 + value,
1.480 + isSelected,
1.481 + hasFocus,
1.482 + row,
1.483 + column);
1.484 + if (c instanceof JLabel) {
1.485 + JLabel l = (JLabel) c;
1.486 + l.setHorizontalTextPosition(JLabel.LEFT);
1.487 + int modelColumn = table.convertColumnIndexToModel(column);
1.488 + l.setIcon(getHeaderRendererIcon(modelColumn,
1.489 + l.getFont().getSize()));
1.490 + }
1.491 + return c;
1.492 + }
1.493 + }
1.494
1.495 - this.tableModel = tableModel;
1.496 - if (this.tableModel != null) {
1.497 - this.tableModel.addTableModelListener(tableModelListener);
1.498 - }
1.499 + private static class Directive {
1.500
1.501 - clearSortingState();
1.502 - fireTableStructureChanged();
1.503 + private int column;
1.504 + private int direction;
1.505 +
1.506 + public Directive(int column,
1.507 + int direction) {
1.508 + this.column = column;
1.509 + this.direction = direction;
1.510 }
1.511 + }
1.512
1.513 - public JTableHeader getTableHeader ()
1.514 - {
1.515 - return tableHeader;
1.516 + public void fireTableColumnUpdated(int index) {
1.517 + for (int i = 0; i < getRowCount(); i++) {
1.518 + fireTableCellUpdated(i,
1.519 + index);
1.520 }
1.521 -
1.522 - public void setTableHeader (JTableHeader tableHeader)
1.523 - {
1.524 - if (this.tableHeader != null) {
1.525 - this.tableHeader.removeMouseListener(mouseListener);
1.526 - TableCellRenderer defaultRenderer = this.tableHeader.getDefaultRenderer();
1.527 - if (defaultRenderer instanceof SortableHeaderRenderer) {
1.528 - this.tableHeader.setDefaultRenderer(((SortableHeaderRenderer) defaultRenderer).tableCellRenderer);
1.529 - }
1.530 - }
1.531 - this.tableHeader = tableHeader;
1.532 - if (this.tableHeader != null) {
1.533 - this.tableHeader.addMouseListener(mouseListener);
1.534 - this.tableHeader.setDefaultRenderer(new SortableHeaderRenderer(this.tableHeader.getDefaultRenderer()));
1.535 - }
1.536 - }
1.537 -
1.538 - public boolean isSorting ()
1.539 - {
1.540 - return sortingColumns.size() != 0;
1.541 - }
1.542 -
1.543 - private Directive getDirective (int column)
1.544 - {
1.545 - for (int i = 0; i < sortingColumns.size(); i++) {
1.546 - Directive directive = (Directive) sortingColumns.get(i);
1.547 - if (directive.column == column) {
1.548 - return directive;
1.549 - }
1.550 - }
1.551 - return EMPTY_DIRECTIVE;
1.552 - }
1.553 -
1.554 - public int getSortingStatus (int column)
1.555 - {
1.556 - return getDirective(column).direction;
1.557 - }
1.558 -
1.559 - private void sortingStatusChanged ()
1.560 - {
1.561 - clearSortingState();
1.562 - fireTableDataChanged();
1.563 - if (tableHeader != null) {
1.564 - tableHeader.repaint();
1.565 - }
1.566 - }
1.567 -
1.568 - public void setSortingStatus (int column,
1.569 - int status)
1.570 - {
1.571 - Directive directive = getDirective(column);
1.572 - if (directive != EMPTY_DIRECTIVE) {
1.573 - sortingColumns.remove(directive);
1.574 - }
1.575 - if (status != NOT_SORTED) {
1.576 - sortingColumns.add(new Directive(column,
1.577 - status));
1.578 - }
1.579 - sortingStatusChanged();
1.580 - }
1.581 -
1.582 - protected Icon getHeaderRendererIcon (int column,
1.583 - int size)
1.584 - {
1.585 - Directive directive = getDirective(column);
1.586 - if (directive == EMPTY_DIRECTIVE) {
1.587 - return null;
1.588 - }
1.589 -
1.590 - if (directive.direction == DESCENDING) {
1.591 - return headerIconDown;
1.592 - } else {
1.593 - return headerIconUp;
1.594 - }
1.595 - }
1.596 -
1.597 - private void cancelSorting ()
1.598 - {
1.599 - sortingColumns.clear();
1.600 - sortingStatusChanged();
1.601 - }
1.602 -
1.603 - public void setColumnComparator (Class type,
1.604 - Comparator comparator)
1.605 - {
1.606 - if (comparator == null) {
1.607 - columnComparators.remove(type);
1.608 - } else {
1.609 - columnComparators.put(type,
1.610 - comparator);
1.611 - }
1.612 - }
1.613 -
1.614 - protected Comparator getComparator (int column)
1.615 - {
1.616 - Class columnType = tableModel.getColumnClass(column);
1.617 - Comparator comparator = (Comparator) columnComparators.get(columnType);
1.618 - if (comparator != null) {
1.619 - return comparator;
1.620 - }
1.621 - if (Comparable.class.isAssignableFrom(columnType)) {
1.622 - return COMPARABLE_COMAPRATOR;
1.623 - }
1.624 - return LEXICAL_COMPARATOR;
1.625 - }
1.626 -
1.627 - private Row[] getViewToModel ()
1.628 - {
1.629 - if (viewToModel == null) {
1.630 - int tableModelRowCount = tableModel.getRowCount();
1.631 - viewToModel = new Row[tableModelRowCount];
1.632 - for (int row = 0; row < tableModelRowCount; row++) {
1.633 - viewToModel[row] = new Row(row);
1.634 - }
1.635 -
1.636 - if (isSorting()) {
1.637 - Arrays.sort(viewToModel);
1.638 - }
1.639 - }
1.640 - return viewToModel;
1.641 - }
1.642 -
1.643 - public int modelIndex (int viewIndex)
1.644 - {
1.645 - if (viewIndex > -1 && viewIndex < getViewToModel().length) {
1.646 - return getViewToModel()[viewIndex].modelIndex;
1.647 - } else {
1.648 - return -1;
1.649 - }
1.650 - }
1.651 -
1.652 - private int[] getModelToView ()
1.653 - {
1.654 - if (modelToView == null) {
1.655 - int n = getViewToModel().length;
1.656 - modelToView = new int[n];
1.657 - for (int i = 0; i < n; i++) {
1.658 - modelToView[modelIndex(i)] = i;
1.659 - }
1.660 - }
1.661 - return modelToView;
1.662 - }
1.663 -
1.664 - // Metody rozhran� TableModel
1.665 -
1.666 - public int getRowCount ()
1.667 - {
1.668 - return (tableModel == null) ? 0 : tableModel.getRowCount();
1.669 - }
1.670 -
1.671 - public int getColumnCount ()
1.672 - {
1.673 - return (tableModel == null) ? 0 : tableModel.getColumnCount();
1.674 - }
1.675 -
1.676 - public String getColumnName (int column)
1.677 - {
1.678 - return tableModel.getColumnName(column);
1.679 - }
1.680 -
1.681 - public Class getColumnClass (int column)
1.682 - {
1.683 - return tableModel.getColumnClass(column);
1.684 - }
1.685 -
1.686 - public boolean isCellEditable (int row,
1.687 - int column)
1.688 - {
1.689 - return tableModel.isCellEditable(modelIndex(row),
1.690 - column);
1.691 - }
1.692 -
1.693 - public Object getValueAt (int row,
1.694 - int column)
1.695 - {
1.696 - return tableModel.getValueAt(modelIndex(row),
1.697 - column);
1.698 - }
1.699 -
1.700 - public void setValueAt (Object aValue,
1.701 - int row,
1.702 - int column)
1.703 - {
1.704 - tableModel.setValueAt(aValue,
1.705 - modelIndex(row),
1.706 - column);
1.707 - }
1.708 -
1.709 - // Pomocn� t��dy
1.710 -
1.711 - private class Row implements Comparable {
1.712 -
1.713 - private int modelIndex;
1.714 -
1.715 - public Row (int index)
1.716 - {
1.717 - this.modelIndex = index;
1.718 - }
1.719 -
1.720 - public int compareTo (Object o)
1.721 - {
1.722 - int row1 = modelIndex;
1.723 - int row2 = ((Row) o).modelIndex;
1.724 -
1.725 - for (Iterator it = sortingColumns.iterator(); it.hasNext();) {
1.726 - Directive directive = (Directive) it.next();
1.727 - int column = directive.column;
1.728 - Object o1 = tableModel.getValueAt(row1,
1.729 - column);
1.730 - Object o2 = tableModel.getValueAt(row2,
1.731 - column);
1.732 -
1.733 - int comparison = 0;
1.734 - // Define null less than everything, except
1.735 - // null.
1.736 - if (o1 == null && o2 == null) {
1.737 - comparison = 0;
1.738 - } else if (o1 == null) {
1.739 - comparison = -1;
1.740 - } else if (o2 == null) {
1.741 - comparison = 1;
1.742 - } else {
1.743 - comparison = getComparator(column).compare(o1,
1.744 - o2);
1.745 - }
1.746 - if (comparison != 0) {
1.747 - return directive.direction == DESCENDING ? -comparison : comparison;
1.748 - }
1.749 - }
1.750 - return 0;
1.751 - }
1.752 - }
1.753 -
1.754 - private class TableModelHandler implements TableModelListener {
1.755 -
1.756 - public void tableChanged (TableModelEvent e)
1.757 - {
1.758 - // If we're not sorting by anything, just pass the event
1.759 - // along.
1.760 - if ( !isSorting()) {
1.761 - clearSortingState();
1.762 - fireTableChanged(e);
1.763 - return;
1.764 - }
1.765 -
1.766 - // If the table structure has changed, cancel the
1.767 - // sorting; the
1.768 - // sorting columns may have been either moved or deleted
1.769 - // from
1.770 - // the model.
1.771 - if (e.getFirstRow() == TableModelEvent.HEADER_ROW) {
1.772 - cancelSorting();
1.773 - fireTableChanged(e);
1.774 - return;
1.775 - }
1.776 -
1.777 - // We can map a cell event through to the view without
1.778 - // widening
1.779 - // when the following conditions apply:
1.780 - //
1.781 - // a) all the changes are on one row (e.getFirstRow() ==
1.782 - // e.getLastRow()) and,
1.783 - // b) all the changes are in one column (column !=
1.784 - // TableModelEvent.ALL_COLUMNS) and,
1.785 - // c) we are not sorting on that column
1.786 - // (getSortingStatus(column) == NOT_SORTED) and,
1.787 - // d) a reverse lookup will not trigger a sort
1.788 - // (modelToView != null)
1.789 - //
1.790 - // Note: INSERT and DELETE events fail this test as they
1.791 - // have column == ALL_COLUMNS.
1.792 - //
1.793 - // The last check, for (modelToView != null) is to see
1.794 - // if modelToView
1.795 - // is already allocated. If we don't do this check;
1.796 - // sorting can become
1.797 - // a performance bottleneck for applications where cells
1.798 - // change rapidly in different parts of the table. If
1.799 - // cells
1.800 - // change alternately in the sorting column and then
1.801 - // outside of
1.802 - // it this class can end up re-sorting on alternate cell
1.803 - // updates -
1.804 - // which can be a performance problem for large tables.
1.805 - // The last
1.806 - // clause avoids this problem.
1.807 - int column = e.getColumn();
1.808 - if (e.getFirstRow() == e.getLastRow() && column != TableModelEvent.ALL_COLUMNS && getSortingStatus(column) == NOT_SORTED
1.809 - && modelToView != null) {
1.810 - int viewIndex = getModelToView()[e.getFirstRow()];
1.811 - fireTableChanged(new TableModelEvent(TableSorterModel.this,
1.812 - viewIndex,
1.813 - viewIndex,
1.814 - column,
1.815 - e.getType()));
1.816 - return;
1.817 - }
1.818 -
1.819 - // Something has happened to the data that may have
1.820 - // invalidated the row order.
1.821 - clearSortingState();
1.822 - fireTableDataChanged();
1.823 - return;
1.824 - }
1.825 - }
1.826 -
1.827 - private class MouseHandler extends MouseAdapter {
1.828 -
1.829 - public void mouseClicked (MouseEvent e)
1.830 - {
1.831 - JTableHeader h = (JTableHeader) e.getSource();
1.832 - TableColumnModel columnModel = h.getColumnModel();
1.833 - int viewColumn = columnModel.getColumnIndexAtX(e.getX());
1.834 - int column = columnModel.getColumn(viewColumn).getModelIndex();
1.835 - if (column != -1) {
1.836 - int status = getSortingStatus(column);
1.837 - if ( !e.isControlDown()) {
1.838 - cancelSorting();
1.839 - }
1.840 - // Cycle the sorting states through {NOT_SORTED,
1.841 - // ASCENDING, DESCENDING} or
1.842 - // {NOT_SORTED, DESCENDING, ASCENDING} depending
1.843 - // on whether shift is pressed.
1.844 - status = status + (e.isShiftDown() ? -1 : 1);
1.845 - status = (status + 4) % 3 - 1; // signed mod,
1.846 - // returning
1.847 - // {-1, 0, 1}
1.848 - setSortingStatus(column,
1.849 - status);
1.850 - }
1.851 - }
1.852 - }
1.853 -
1.854 - private class SortableHeaderRenderer implements TableCellRenderer {
1.855 -
1.856 - private TableCellRenderer tableCellRenderer;
1.857 -
1.858 - public SortableHeaderRenderer (TableCellRenderer tableCellRenderer)
1.859 - {
1.860 - this.tableCellRenderer = tableCellRenderer;
1.861 - }
1.862 -
1.863 - public Component getTableCellRendererComponent (JTable table,
1.864 - Object value,
1.865 - boolean isSelected,
1.866 - boolean hasFocus,
1.867 - int row,
1.868 - int column)
1.869 - {
1.870 - Component c = tableCellRenderer.getTableCellRendererComponent(table,
1.871 - value,
1.872 - isSelected,
1.873 - hasFocus,
1.874 - row,
1.875 - column);
1.876 - if (c instanceof JLabel) {
1.877 - JLabel l = (JLabel) c;
1.878 - l.setHorizontalTextPosition(JLabel.LEFT);
1.879 - int modelColumn = table.convertColumnIndexToModel(column);
1.880 - l.setIcon(getHeaderRendererIcon(modelColumn,
1.881 - l.getFont().getSize()));
1.882 - }
1.883 - return c;
1.884 - }
1.885 - }
1.886 -
1.887 - private static class Directive {
1.888 -
1.889 - private int column;
1.890 -
1.891 - private int direction;
1.892 -
1.893 - public Directive (int column,
1.894 - int direction)
1.895 - {
1.896 - this.column = column;
1.897 - this.direction = direction;
1.898 - }
1.899 - }
1.900 -
1.901 - public void fireTableColumnUpdated (int index)
1.902 - {
1.903 - for (int i = 0; i < getRowCount(); i++) {
1.904 - fireTableCellUpdated(i,
1.905 - index);
1.906 - }
1.907 - }
1.908 + }
1.909 }