1 71 package com.sshtools.ui.awt.grid; 72 73 import java.awt.AWTEventMulticaster ; 74 import java.awt.BorderLayout ; 75 import java.awt.Color ; 76 import java.awt.Component ; 77 import java.awt.Cursor ; 78 import java.awt.Dimension ; 79 import java.awt.Font ; 80 import java.awt.FontMetrics ; 81 import java.awt.Frame ; 82 import java.awt.Graphics ; 83 import java.awt.Image ; 84 import java.awt.Panel ; 85 import java.awt.Scrollbar ; 86 import java.awt.Shape ; 87 import java.awt.SystemColor ; 88 import java.awt.event.ActionEvent ; 89 import java.awt.event.ActionListener ; 90 import java.awt.event.AdjustmentEvent ; 91 import java.awt.event.AdjustmentListener ; 92 import java.awt.event.MouseAdapter ; 93 import java.awt.event.MouseEvent ; 94 import java.awt.event.MouseMotionAdapter ; 95 import java.awt.event.WindowAdapter ; 96 import java.awt.event.WindowEvent ; 97 import java.text.SimpleDateFormat ; 98 import java.util.Date ; 99 import java.util.Hashtable ; 100 import java.util.Vector ; 101 102 import com.sshtools.ui.awt.ImageTextLabel; 103 import com.sshtools.ui.awt.UIUtil; 104 105 108 public class Grid extends Panel implements TableModelListener, AdjustmentListener { 109 110 public final static int AUTO_RESIZE_OFF = 0; 111 public final static int AUTO_RESIZE_EVENT = 1; 112 public final static int AUTO_RESIZE_FIRST_COLUMN = 2; 113 public final static int AUTO_RESIZE_LAST_COLUMN = 3; 114 115 private Dimension dPreferred; 118 119 protected Font fFont; 121 122 private FontMetrics fMetrics; 124 125 private Graphics gImage; 126 127 private Image iImage; 128 129 private int iWidth, iHeight; 131 132 private int iRowHeight, iFirstRow; 133 134 private int iGridWidth, iGridHeight; 135 136 private int iX, iY; 137 138 private int iColWidth[]; 144 145 private Scrollbar sbHoriz, sbVert; 149 150 private int iSbWidth, iSbHeight; 151 152 private boolean bDrag; 153 154 private int iXDrag, iColDrag; 155 156 private TableModel model; 157 158 private boolean[][] sel; 159 160 private int lastDragSel, lastShiftSel; 161 162 private boolean clearNextDrag; 163 164 private Color selectionBackground, selectionForeground; 165 166 private TableCellRenderer cellRenderer; 167 168 private Hashtable renderers, numberedRenderers; 169 170 private int autoResizeMode = 0; 171 172 private boolean showGrid; 173 174 private ActionListener listener; 175 176 180 public Grid() { 181 super(); 182 showGrid = false; 183 renderers = new Hashtable (); 184 numberedRenderers = new Hashtable (); 185 fFont = new Font ("Dialog", Font.PLAIN, 12); selectionBackground = Color.blue.darker(); 187 selectionForeground = Color.white; 188 setBackground(SystemColor.text); 189 setForeground(SystemColor.textText); 190 cellRenderer = new DefaultTableCellRenderer(); 191 setLayout(null); 192 sbHoriz = new Scrollbar (Scrollbar.HORIZONTAL); 193 sbHoriz.addAdjustmentListener(this); 194 add(sbHoriz); 195 sbVert = new Scrollbar (Scrollbar.VERTICAL); 196 sbVert.addAdjustmentListener(this); 197 dPreferred = new Dimension (480,320); 198 add(sbVert); 199 addMouseListener(new MouseAdapter () { 200 public void mouseClicked(MouseEvent e) { 201 requestFocus(); 202 int y = e.getY(); 203 int x = e.getX(); 204 if(y > iRowHeight) { 206 int row = rowForY(y); 207 if(row < model.getRowCount()) { 208 int col = columnForX(x); 209 boolean ctrl = ( e.getModifiers() & MouseEvent.CTRL_MASK ) != 0; 210 boolean shift = ( e.getModifiers() & MouseEvent.SHIFT_MASK ) != 0; 211 212 if(!ctrl) { 213 clearSel(); 214 } 215 216 if(shift) { 218 if(lastShiftSel != -1) { 219 int incr = lastShiftSel < row ? 1 : -1; 220 for(int j = lastShiftSel; j != ( row + incr) ; j += incr ) { 221 selRow(j, true); 222 } 223 } 224 else { 225 selRow(row, true); 226 lastShiftSel = row; 227 } 228 } 229 else { 230 boolean doSel = ctrl ? ( !sel[row][col] ) : true; 232 selRow(row, doSel); 233 lastShiftSel = doSel ? row : -1; 234 } 235 236 repaint(); 238 239 lastDragSel = -1; 241 } 242 } 243 } 244 245 public void mouseReleased(MouseEvent evt) { 246 if(lastDragSel != -1) { 247 clearNextDrag = true; 248 } 249 } 250 251 public void mouseExited(MouseEvent e) { 252 if (bDrag) { 253 setCursor(new Cursor (Cursor.DEFAULT_CURSOR)); 254 bDrag = false; 255 } 256 } 257 }); 258 addMouseMotionListener(new MouseMotionAdapter () { 259 public void mouseDragged(MouseEvent e) { 260 int x = e.getX(); 261 int y = e.getY(); 262 if (bDrag && x < iWidth) { 263 int w = x - iXDrag; 264 if (w < 0) { 265 w = 0; 266 } 267 iColWidth[iColDrag] = w; 268 adjustScroll(); 269 repaint(); 270 } 271 else { 272 if(y > iRowHeight) { 274 if(clearNextDrag) { 275 clearSel(); 276 clearNextDrag = false; 277 } 278 int row = rowForY(y); 279 if(row < model.getRowCount()) { 280 if(lastDragSel != -1) { 281 if(row < lastDragSel) { 283 for(int j = row + 1; j <= lastDragSel; j++) { 284 selRow(j, false); 285 } 286 selRow(row, true); 287 } 288 else { 289 for(int i = lastDragSel; i <= row; i++) { 290 selRow(i, true); 291 } 292 } 293 } 294 else { 295 selRow(row, true); 296 } 297 repaint(); 298 lastDragSel = row; 299 } 300 } 301 } 302 } 303 304 public void mouseMoved(MouseEvent e) { 305 int x = e.getX(); 306 int y = e.getY(); 307 if (y <= iRowHeight) { 308 int xb = x; 309 x += iX - iGridWidth; 310 int i = model.getColumnCount() - 1; 311 for (; i >= 0; i--) { 312 if (x > -7 && x < 7) { 313 break; 314 } 315 x += iColWidth[i]; 316 } 317 if (i >= 0) { 318 if (!bDrag) { 319 setCursor(new Cursor (Cursor.E_RESIZE_CURSOR)); 320 bDrag = true; 321 iXDrag = xb - iColWidth[i]; 322 iColDrag = i; 323 } 324 return; 325 } 326 } 327 if (bDrag) { 328 setCursor(new Cursor (Cursor.DEFAULT_CURSOR)); 329 bDrag = false; 330 } 331 } 332 333 }); 334 } 335 336 public void addActionListener(ActionListener l) { 337 listener = AWTEventMulticaster.add(listener, l); 338 } 339 340 public void removeActionListener(ActionListener l) { 341 listener = AWTEventMulticaster.remove(listener, l); 342 } 343 344 private void selRow(int r, boolean selected) { 345 boolean s[] = sel[r]; 347 for(int i = 0 ; i < s.length; i++) { 348 s[i] = selected; 349 } 350 if(listener != null) { 351 listener.actionPerformed(new ActionEvent (this, ActionEvent.ACTION_PERFORMED, "selection")); } 353 } 354 355 private int columnForX(int x) { 356 int w = 0; 357 for(int i = 0 ; i < iColWidth.length; i++) { 358 if(x < w) 359 return i - 1; 360 else 361 w += iColWidth[i]; 362 } 363 return -1; 364 } 365 366 private int rowForY(int y) { 367 return ( y - iRowHeight + iY ) / iRowHeight; 368 } 369 370 protected TableCellRenderer getRendererForColumn(int col) { 371 Integer i = new Integer (col); 372 TableCellRenderer r = (TableCellRenderer)numberedRenderers.get(i); 373 if(r == null) { 374 r = (TableCellRenderer)renderers.get(model.getColumnClass(col)); 375 if(r == null) { 376 r = cellRenderer; 377 } 378 } 379 return r; 380 } 381 382 387 public int getSelectedRow() { 388 for(int i = 0 ; i < sel.length; i++) { 390 for(int j = 0 ; j < sel[i].length; j++) { 391 if(sel[i][j]) { 392 return i; 393 } 394 } 395 } 396 return -1; 397 } 398 399 404 public void clearSelection() { 405 clearSel(); 406 repaint(); 407 } 408 409 414 public void setSelectionBackground(Color selectionBackground) { 415 this.selectionBackground = selectionBackground; 416 repaint(); 417 } 418 419 424 public Color getSelectionBackground() { 425 return selectionBackground; 426 } 427 428 433 public void setSelectionForeground(Color selectionForeground) { 434 this.selectionForeground = selectionForeground; 435 repaint(); 436 } 437 438 443 public Color getSelectionForeground() { 444 return selectionForeground; 445 } 446 447 453 public void setCellRenderer(Class columnClass, TableCellRenderer renderer) { 454 renderers.put(columnClass, renderer); 455 } 456 457 463 public void setCellRenderer(int column, TableCellRenderer renderer) { 464 numberedRenderers.put(new Integer (column), renderer); 465 } 466 467 private void clearSel() { 468 sel = new boolean[model.getRowCount()][model.getColumnCount()]; 469 } 470 471 477 public Grid(TableModel model) { 478 this(); 479 setModel(model); 480 } 481 482 487 public synchronized void setModel(TableModel model) { 488 if(this.model != null) { 489 this.model.removeTableModelListener(this); 490 } 491 this.model = model; 492 resetGrid(); 493 model.addTableModelListener(this); 494 } 495 496 private void resetGrid() { 497 iColWidth = new int[model == null ? 0 : model.getColumnCount()]; 498 for (int i = 0; i < iColWidth.length; i++) { 499 iColWidth[i] = 100; 500 } 501 iRowHeight = 0; 502 changed(); 503 } 504 505 public synchronized void setColumnWidths(int[] colWidth) { 506 this.iColWidth = colWidth; 507 adjustScroll(); 508 repaint(); 509 } 510 511 public static void main(String [] args) { 512 Frame frame = new Frame ("Test table"); TableModel model = new TestTableModel(1000); 514 Grid table = new Grid(model); 515 table.setCellRenderer(Image .class, new TestImageTableCellRenderer()); 516 frame.setLayout(new BorderLayout ()); 517 frame.add(table, BorderLayout.CENTER); 518 frame.setSize(new Dimension (800, 600)); 519 UIUtil.positionComponent(UIUtil.CENTER, frame); 520 frame.addWindowListener(new WindowAdapter () { 521 public void windowClosing(WindowEvent evt) { 522 System.exit(0); 523 } 524 }); 525 frame.setVisible(true); 526 } 527 528 533 537 545 public void setBounds(int x, int y, int w, int h) { 546 super.setBounds(x, y, w, h); 548 iSbHeight = sbHoriz.getPreferredSize().height; 549 iSbWidth = sbVert.getPreferredSize().width; 550 iHeight = h - iSbHeight; 551 iWidth = w - iSbWidth; 552 sbHoriz.setBounds(0, iHeight, iWidth, iSbHeight); 553 sbVert.setBounds(iWidth, 0, iSbWidth, iHeight); 554 adjustScroll(); 555 iImage = null; 556 repaint(); 557 } 558 559 563 public void update() { 564 adjustScroll(); 565 repaint(); 566 } 567 568 572 void adjustScroll() { 573 if (iRowHeight == 0) { return; } 574 int w = 0; 575 for (int i = 0; i < model.getColumnCount(); i++) { 576 w += iColWidth[i]; 577 } 578 iGridWidth = w; 579 iGridHeight = iRowHeight * (model.getRowCount() + 1); 580 sbHoriz.setValues(iX, iWidth, 0, iGridWidth); 581 int v = iY / iRowHeight, h = iHeight / iRowHeight; 582 sbVert.setValues(v, h, 0, model.getRowCount() + 1); 583 iX = sbHoriz.getValue(); 584 iY = iRowHeight * sbVert.getValue(); 585 } 586 587 592 public void paint(Graphics g) { 593 if (g == null) { return; } 594 if (model == null) { 595 super.paint(g); 596 return; 597 } 598 int cc = model.getColumnCount(); 599 int rc = model.getRowCount(); 600 if (iWidth <= 0 || iHeight <= 0) { return; } 601 g.setColor(SystemColor.control); 602 g.fillRect(iWidth, iHeight, iSbWidth, iSbHeight); 603 if (iImage == null) { 604 iImage = createImage(iWidth, iHeight); 605 gImage = iImage.getGraphics(); 606 gImage.setFont(fFont); 607 if (fMetrics == null) { 608 fMetrics = gImage.getFontMetrics(); 609 } 610 } 611 if (iRowHeight == 0) { 612 iRowHeight = fMetrics.getHeight() + 4; 613 adjustScroll(); 614 } 615 gImage.setColor(Color.white); 616 gImage.fillRect(0, 0, iWidth, iHeight); 617 gImage.setColor(Color.darkGray); 618 gImage.drawLine(0, iRowHeight, iWidth, iRowHeight); 619 int x = -iX; 620 for (int i = 0; i < cc; i++) { 621 int w = iColWidth[i]; 622 gImage.setColor(SystemColor.control); 623 gImage.fillRect(x + 1, 0, w - 2, iRowHeight); 624 gImage.setColor(Color.black); 625 gImage.drawString(model.getColumnName(i), x + 2, iRowHeight - 5); 626 gImage.setColor(Color.darkGray); 627 gImage.drawLine(x + w - 1, 0, x + w - 1, iRowHeight - 1); 628 gImage.setColor(Color.white); 629 gImage.drawLine(x + w, 0, x + w, iRowHeight - 1); 630 x += w; 631 } 632 gImage.setColor(SystemColor.control); 633 gImage.fillRect(0, 0, 1, iRowHeight); 634 gImage.fillRect(x + 1, 0, iWidth - x, iRowHeight); 635 gImage.drawLine(0, 0, 0, iRowHeight - 1); 636 int y = iRowHeight + 1 - iY; 637 int j = 0; 638 while (y < iRowHeight + 1) { 639 j++; 640 y += iRowHeight; 641 } 642 iFirstRow = j; 643 y = iRowHeight + 1; 644 boolean s; 645 Component component; 646 TableCellRenderer renderer; 647 for (; y < iHeight && j < rc; j++, y += iRowHeight) { 648 x = -iX; 649 for (int i = 0; i < cc; i++) { 650 int w = iColWidth[i]; 651 s = j < sel.length && i < sel[j].length ? sel[j][i] : false; 652 Color b = s ? selectionBackground : getBackground(), t = s ? selectionForeground : getForeground(); 653 gImage.setColor(b); 654 gImage.fillRect(x, y, w - 1, iRowHeight - 1); 655 gImage.setColor(t); 656 657 renderer = getRendererForColumn(i); 658 659 component = renderer.getTableCellRendererComponent(this, model.getValue(j, i), j, i, s); 660 component.setBounds(0, 0, w - 1, iRowHeight - 1); 662 gImage.translate(x , y); 663 Shape clip = gImage.getClip(); 664 gImage.setClip(0, 0, w -1 , iRowHeight - 1); 665 component.paint(gImage); 666 gImage.translate(-x , -y); 667 gImage.setClip(clip); 668 669 if(showGrid) { 671 gImage.setColor(Color.lightGray); 672 gImage.drawLine(x + w - 1, y, x + w - 1, y + iRowHeight - 1); 673 gImage.drawLine(x, y + iRowHeight - 1, x + w - 1, y + iRowHeight - 1); 674 } 675 x += w; 676 } 677 gImage.setColor(getBackground()); 678 gImage.fillRect(x, y, iWidth - x, iRowHeight - 1); 679 } 680 g.drawImage(iImage, 0, 0, this); 681 } 682 683 688 public void update(Graphics g) { 689 paint(g); 690 } 691 692 697 public Dimension preferredSize() { 698 return dPreferred == null ? super.preferredSize() : dPreferred; 699 } 700 701 706 public Dimension getPreferredSize() { 707 return dPreferred == null ? super.getPreferredSize() : dPreferred; 708 } 709 710 static class TestTableModel implements TableModel { 711 712 Image image; 713 int rows; 714 715 TestTableModel(int rows) { 716 this.rows = rows; 717 image = UIUtil.loadImage(TestTableModel.class, "test-image.png"); } 719 720 725 public int getRowCount() { 726 return rows; 727 } 728 729 734 public int getColumnCount() { 735 return 6; 736 } 737 738 743 public Object getValue(int r, int c) { 744 if(c == 0) { 745 return image; 746 } 747 else { 748 return r + "," + c; } 750 } 751 752 757 public String getColumnName(int c) { 758 if(c ==0) { 759 return Messages.getString("Grid.image"); } 761 else { 762 return String.valueOf(c); 763 } 764 } 765 766 771 public Class getColumnClass(int r) { 772 if(r == 0) { 773 return Image .class; 774 } 775 else { 776 return String .class; 777 } 778 } 779 780 783 public void addTableModelListener(TableModelListener l) { 784 786 } 787 788 791 public void removeTableModelListener(TableModelListener l) { 792 794 } 795 } 796 797 class DefaultTableCellRenderer extends ImageTextLabel implements TableCellRenderer { 798 799 800 SimpleDateFormat sdf = new SimpleDateFormat ("HH:mm:ss"); 802 public Component getTableCellRendererComponent(Grid grid, Object value, int row, int col, boolean sel) { 803 setBackground(sel ? grid.getSelectionBackground() : grid.getBackground()); 804 setForeground(sel ? grid.getSelectionForeground() : grid.getForeground()); 805 setFont(grid.getFont()); 806 if(value instanceof Integer || value instanceof Double || 807 value instanceof Long || value instanceof Float || 808 value instanceof Short || value instanceof Byte ) { 809 setHorizontalAlignment(RIGHT_ALIGNMENT); 810 setText(String.valueOf(value)); 811 } 812 else if(value instanceof Date ) { 813 setHorizontalAlignment(LEFT_ALIGNMENT); 814 setText(sdf.format((Date )value)); 815 } 816 else { 817 setHorizontalAlignment(LEFT_ALIGNMENT); 818 setText(String.valueOf(value)); 819 } 820 return this; 821 } 822 } 823 824 static class TestImageTableCellRenderer extends ImageTextLabel implements TableCellRenderer { 825 public Component getTableCellRendererComponent(Grid grid, Object value, int row, int col, boolean sel) { 826 setBackground(sel ? grid.getSelectionBackground() : grid.getBackground()); 827 setForeground(sel ? grid.getSelectionForeground() : grid.getForeground()); 828 setFont(grid.getFont()); 829 setImage((Image )value); 830 return this; 831 } 832 } 833 834 837 public void layoutChanged() { 838 resetGrid(); 839 } 840 841 844 public void changed() { 845 sel = new boolean[model == null ? 0 : model.getRowCount()][model == null ? 0 : model.getColumnCount()]; 846 rowsChanged(); 847 } 848 849 852 public void rowInserted(int row) { 853 rowsChanged(); 854 } 855 856 859 public void rowDeleted(int row) { 860 rowsChanged(); 861 } 862 863 866 public void rowChanged(int row) { 867 rowsChanged(); 868 } 869 870 private void rowsChanged() { 871 lastDragSel = -1; 872 clearNextDrag = true; 873 iImage = null; 874 adjustScroll(); 875 repaint(); 876 } 877 878 881 public void adjustmentValueChanged(AdjustmentEvent e) { 882 iX = sbHoriz.getValue(); 883 iY = iRowHeight * sbVert.getValue(); 884 repaint(); 885 } 886 887 890 public int[] getSelectedRows() { 891 Vector v = new Vector (); 892 for(int i = 0 ; i < sel.length; i++) { 893 for(int j = 0 ; j < sel[i].length; j++) { 894 if(sel[i][j]) { 895 v.addElement(new Integer (i)); 896 break; 897 } 898 } 899 } 900 int[] sel = new int[v.size()]; 901 int idx = 0; 902 for(int i = v.size() - 1; i >= 0 ; i--) { 903 sel[i] = ((Integer )v.elementAt(i)).intValue(); 904 } 905 return sel; 906 } 907 908 public void setScrollPosition(int i) { 909 sbVert.setValue(i); 910 adjustmentValueChanged(null); 911 } 912 913 public int getScrollPosition() { 914 return sbVert.getValue(); 915 } 916 917 public int getScrollBlockIncrement() { 918 return sbVert.getBlockIncrement(); 919 } 920 921 public int getScrollUnitIncrement() { 922 return sbVert.getUnitIncrement(); 923 } 924 925 928 public int getSelectedRowCount() { 929 return getSelectedRows().length; 930 } 931 932 935 public void setShowGrid(boolean showGrid) { 936 this.showGrid = showGrid; 937 repaint(); 938 } 939 } | Popular Tags |