1 19 20 package org.netbeans.modules.versioning.util; 21 22 import java.awt.*; 23 import java.awt.event.*; 24 import java.util.*; 25 import java.util.List ; 26 27 import javax.swing.*; 28 import javax.swing.event.TableModelEvent ; 29 import javax.swing.event.TableModelListener ; 30 import javax.swing.table.*; 31 32 83 84 public final class TableSorter extends AbstractTableModel { 85 protected TableModel tableModel; 86 87 public static final int DESCENDING = -1; 88 public static final int NOT_SORTED = 0; 89 public static final int ASCENDING = 1; 90 91 private static Directive EMPTY_DIRECTIVE = new Directive(-1, NOT_SORTED); 92 93 public static final Comparator COMPARABLE_COMAPRATOR = new Comparator<Comparable >() { 94 public int compare(Comparable o1, Comparable o2) { 95 return o1.compareTo(o2); 96 } 97 }; 98 public static final Comparator LEXICAL_COMPARATOR = new Comparator() { 99 public int compare(Object o1, Object o2) { 100 return o1.toString().compareTo(o2.toString()); 101 } 102 }; 103 104 private final Icon ICON_ASCENDING = new ImageIcon(org.openide.util.Utilities.loadImage("org/netbeans/modules/openide/explorer/columnsSortedAsc.gif", true)); private final Icon ICON_DESCENDING = new ImageIcon(org.openide.util.Utilities.loadImage("org/netbeans/modules/openide/explorer/columnsSortedDesc.gif", true)); 107 private Row[] viewToModel; 108 private int[] modelToView; 109 110 private JTableHeader tableHeader; 111 private MouseListener mouseListener; 112 private TableModelListener tableModelListener; 113 private Map<Object , Comparator> columnComparators = new HashMap<Object , Comparator>(); 115 private List <Directive> sortingColumns = new ArrayList<Directive>(); 116 117 public TableSorter() { 118 this.mouseListener = new MouseHandler(); 119 this.tableModelListener = new TableModelHandler(); 120 } 121 122 public TableSorter(TableModel tableModel) { 123 this(); 124 setTableModel(tableModel); 125 } 126 127 public TableSorter(TableModel tableModel, JTableHeader tableHeader) { 128 this(); 129 setTableHeader(tableHeader); 130 setTableModel(tableModel); 131 } 132 133 private void clearSortingState() { 134 viewToModel = null; 135 modelToView = null; 136 } 137 138 public TableModel getTableModel() { 139 return tableModel; 140 } 141 142 public final void setTableModel(TableModel tableModel) { 143 if (this.tableModel != null) { 144 this.tableModel.removeTableModelListener(tableModelListener); 145 } 146 147 this.tableModel = tableModel; 148 if (this.tableModel != null) { 149 this.tableModel.addTableModelListener(tableModelListener); 150 } 151 152 clearSortingState(); 153 fireTableStructureChanged(); 154 } 155 156 public JTableHeader getTableHeader() { 157 return tableHeader; 158 } 159 160 public void setTableHeader(JTableHeader tableHeader) { 161 if (this.tableHeader != null) { 162 this.tableHeader.removeMouseListener(mouseListener); 163 TableCellRenderer defaultRenderer = this.tableHeader.getDefaultRenderer(); 164 if (defaultRenderer instanceof SortableHeaderRenderer) { 165 this.tableHeader.setDefaultRenderer(((SortableHeaderRenderer) defaultRenderer).tableCellRenderer); 166 } 167 } 168 this.tableHeader = tableHeader; 169 if (this.tableHeader != null) { 170 this.tableHeader.addMouseListener(mouseListener); 171 this.tableHeader.setDefaultRenderer( 172 new SortableHeaderRenderer(this.tableHeader.getDefaultRenderer())); 173 } 174 } 175 176 public boolean isSorting() { 177 return sortingColumns.size() != 0; 178 } 179 180 private Directive getDirective(int column) { 181 for (int i = 0; i < sortingColumns.size(); i++) { 182 Directive directive = sortingColumns.get(i); 183 if (directive.column == column) { 184 return directive; 185 } 186 } 187 return EMPTY_DIRECTIVE; 188 } 189 190 public int getSortingStatus(int column) { 191 return getDirective(column).direction; 192 } 193 194 private void sortingStatusChanged() { 195 clearSortingState(); 196 fireTableDataChanged(); 197 if (tableHeader != null) { 198 tableHeader.repaint(); 199 } 200 } 201 202 public void setSortingStatus(int column, int status) { 203 Directive directive = getDirective(column); 204 if (directive != EMPTY_DIRECTIVE) { 205 sortingColumns.remove(directive); 206 } 207 if (status != NOT_SORTED) { 208 sortingColumns.add(new Directive(column, status)); 209 } 210 sortingStatusChanged(); 211 } 212 213 protected Icon getHeaderRendererIcon(int column, int size) { 214 Directive directive = getDirective(column); 215 if (directive == EMPTY_DIRECTIVE) { 216 return null; 217 } 218 return directive.direction == ASCENDING ? ICON_ASCENDING : ICON_DESCENDING; 219 } 220 221 private void cancelSorting() { 222 sortingColumns.clear(); 223 sortingStatusChanged(); 224 } 225 226 public void setColumnComparator(Class type, Comparator comparator) { 227 if (comparator == null) { 228 columnComparators.remove(type); 229 } else { 230 columnComparators.put(type, comparator); 231 } 232 } 233 234 241 public void setColumnComparator(int column, Comparator comparator) { 242 if (comparator == null) { 243 columnComparators.remove(Integer.valueOf(column)); 244 } else { 245 columnComparators.put(Integer.valueOf(column), comparator); 246 } 247 } 248 249 protected Comparator getComparator(int column) { 250 Class columnType = tableModel.getColumnClass(column); 251 Comparator comparator = columnComparators.get(columnType); 252 if (comparator != null) { 253 return comparator; 254 } 255 if (Comparable .class.isAssignableFrom(columnType)) { 256 return COMPARABLE_COMAPRATOR; 257 } 258 return LEXICAL_COMPARATOR; 259 } 260 261 private Row[] getViewToModel() { 262 if (viewToModel == null) { 263 int tableModelRowCount = tableModel.getRowCount(); 264 viewToModel = new Row[tableModelRowCount]; 265 for (int row = 0; row < tableModelRowCount; row++) { 266 viewToModel[row] = new Row(row); 267 } 268 269 if (isSorting()) { 270 Arrays.sort(viewToModel); 271 } 272 } 273 return viewToModel; 274 } 275 276 public int modelIndex(int viewIndex) { 277 return getViewToModel()[viewIndex].modelIndex; 278 } 279 280 private int[] getModelToView() { 281 if (modelToView == null) { 282 int n = getViewToModel().length; 283 modelToView = new int[n]; 284 for (int i = 0; i < n; i++) { 285 modelToView[modelIndex(i)] = i; 286 } 287 } 288 return modelToView; 289 } 290 291 293 public int getRowCount() { 294 return (tableModel == null) ? 0 : tableModel.getRowCount(); 295 } 296 297 public int getColumnCount() { 298 return (tableModel == null) ? 0 : tableModel.getColumnCount(); 299 } 300 301 public String getColumnName(int column) { 302 return tableModel.getColumnName(column); 303 } 304 305 public Class getColumnClass(int column) { 306 return tableModel.getColumnClass(column); 307 } 308 309 public boolean isCellEditable(int row, int column) { 310 return tableModel.isCellEditable(modelIndex(row), column); 311 } 312 313 public Object getValueAt(int row, int column) { 314 return tableModel.getValueAt(modelIndex(row), column); 315 } 316 317 public void setValueAt(Object aValue, int row, int column) { 318 tableModel.setValueAt(aValue, modelIndex(row), column); 319 } 320 321 323 private class Row implements Comparable { 324 private int modelIndex; 325 326 public Row(int index) { 327 this.modelIndex = index; 328 } 329 330 public int compareTo(Object o) { 331 int row1 = modelIndex; 332 int row2 = ((Row) o).modelIndex; 333 334 for (Iterator<Directive> it = sortingColumns.iterator(); it.hasNext();) { 335 Directive directive = it.next(); 336 int column = directive.column; 337 Object o1 = tableModel.getValueAt(row1, column); 338 Object o2 = tableModel.getValueAt(row2, column); 339 340 int comparison = 0; 341 if (o1 == null && o2 == null) { 343 comparison = 0; 344 } else if (o1 == null) { 345 comparison = -1; 346 } else if (o2 == null) { 347 comparison = 1; 348 } else { 349 Comparator comparator = columnComparators.get(Integer.valueOf(column)); 350 if (comparator != null) { 351 comparison = comparator.compare(Integer.valueOf(row1), Integer.valueOf(row2)); 352 } else { 353 comparison = getComparator(column).compare(o1, o2); 354 } 355 } 356 if (comparison != 0) { 357 return directive.direction == DESCENDING ? -comparison : comparison; 358 } 359 } 360 return 0; 361 } 362 } 363 364 private class TableModelHandler implements TableModelListener { 365 public void tableChanged(TableModelEvent e) { 366 if (!isSorting()) { 368 clearSortingState(); 369 fireTableChanged(e); 370 return; 371 } 372 373 if (e.getFirstRow() == TableModelEvent.HEADER_ROW) { 377 cancelSorting(); 378 fireTableChanged(e); 379 return; 380 } 381 382 int column = e.getColumn(); 401 if (e.getFirstRow() == e.getLastRow() 402 && column != TableModelEvent.ALL_COLUMNS 403 && getSortingStatus(column) == NOT_SORTED 404 && modelToView != null) { 405 int viewIndex = getModelToView()[e.getFirstRow()]; 406 fireTableChanged(new TableModelEvent (TableSorter.this, 407 viewIndex, viewIndex, 408 column, e.getType())); 409 return; 410 } 411 412 clearSortingState(); 414 fireTableDataChanged(); 415 } 416 } 417 418 private class MouseHandler extends MouseAdapter { 419 public void mouseClicked(MouseEvent e) { 420 JTableHeader h = (JTableHeader) e.getSource(); 421 TableColumnModel columnModel = h.getColumnModel(); 422 int viewColumn = columnModel.getColumnIndexAtX(e.getX()); 423 int column = columnModel.getColumn(viewColumn).getModelIndex(); 424 if (column != -1) { 425 int status = getSortingStatus(column); 426 if (!e.isControlDown()) { 427 cancelSorting(); 428 } 429 status += e.isShiftDown() ? -1 : 1; 432 status = (status + 4) % 3 - 1; setSortingStatus(column, status); 434 } 435 } 436 } 437 438 private class SortableHeaderRenderer implements TableCellRenderer { 439 private TableCellRenderer tableCellRenderer; 440 441 public SortableHeaderRenderer(TableCellRenderer tableCellRenderer) { 442 this.tableCellRenderer = tableCellRenderer; 443 } 444 445 public Component getTableCellRendererComponent(JTable table, 446 Object value, 447 boolean isSelected, 448 boolean hasFocus, 449 int row, 450 int column) { 451 Component c = tableCellRenderer.getTableCellRendererComponent(table, 452 value, isSelected, hasFocus, row, column); 453 if (c instanceof JLabel) { 454 JLabel l = (JLabel) c; 455 int modelColumn = table.convertColumnIndexToModel(column); 456 Directive directive = getDirective(modelColumn); 457 if (directive != EMPTY_DIRECTIVE) { 458 l.setFont(l.getFont().deriveFont(Font.BOLD)); 459 } 460 l.setHorizontalTextPosition(JLabel.LEFT); 461 l.setIcon(getHeaderRendererIcon(modelColumn, l.getFont().getSize())); 462 } 463 return c; 464 } 465 } 466 467 private static class Directive { 468 private int column; 469 private int direction; 470 471 public Directive(int column, int direction) { 472 this.column = column; 473 this.direction = direction; 474 } 475 } 476 } 477 | Popular Tags |