1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * ident "%Z%%M% %I% %E% SMI" 24 * 25 * Copyright (c) 2000 by Sun Microsystems, Inc. 26 * All rights reserved. 27 */ 28 29 /** 30 * ColumnListCanvas.java 31 * 32 * Copyright 1995-1996 Active Software Inc. 33 * 34 * @version @(#)ColumnListCanvas.java 1.93 97/07/25 35 * @author Tilman Sporkert 36 */ 37 38 package sunsoft.jws.visual.rt.awt; 39 40 import sunsoft.jws.visual.rt.base.DesignerAccess; 41 import sunsoft.jws.visual.rt.base.Global; 42 43 import java.awt.Graphics; 44 import java.util.Vector; 45 import java.awt.*; 46 47 /** 48 * An internal widget for the ColumnList widget 49 * 50 * @author Tilman Sporkert 51 */ 52 class ColumnListCanvas extends VJPanel implements Scrollable { 53 // Padding 54 final static int LEFT_PAD = 4; 55 final static int RIGHT_PAD = 4; 56 57 // Editing 58 private EditLine editline; 59 private CLChoice editchoice; 60 private boolean justCancelled; 61 Window choiceMenuWindow; 62 TextList choiceMenu; 63 private int editrow = -1; 64 private int editcolumn = -1; 65 private boolean[] textEditable; 66 private boolean applying; 67 private boolean cancelApply; 68 69 // double-buffering 70 private Image buffer; 71 private Dimension bufferSize; 72 private Image[] bufferCache = new Image[3]; 73 private Dimension[] bufferSizeCache = new Dimension[3]; 74 75 ColumnList parent; 76 Frame ourFrame = null; 77 int columns; // # of data columns 78 // there are actual columns + 1 columns managed 79 // but only columns are visible. The last 80 // column can be accessed only by addItem(), 81 // getItem(), and putItem(), and can be used to 82 // manage a random object together with the 83 // data row 84 int charWidth; 85 int rowHeight; // height of data row 86 Component hasComponents = null; 87 int componentHeight = 0; 88 // height of largest component in list 89 int rowAscent; 90 int headerHeight; 91 int totalWidth; // total width of all colums 92 boolean dragging = false; // for resizing columns 93 int dragStart; // x position where drag started 94 int dragColumn; // which column is getting resized? 95 96 String[] headers; 97 boolean showHeaders = true; 98 boolean showVerticalLines = false; 99 boolean showHorizontalLines = false; 100 int[] formats = null; // Formatting mode for columns 101 int[] dimensions; // the dimensions of the headers 102 boolean autoWidth = true; // automatically expand columns to fit? 103 int records; // # of active records 104 Vector labels; // the actual data, as Label[] 105 Vector rowColors; // Attributes of a record 106 107 int requestedRows = 5; // requested # of rows to show 108 int requestedChars = 0; 109 // request # of chars to display horizontally 110 int dispRows; // # of rows to show 111 int visibleRows = -1; 112 // this can be one more than dispRows 113 114 int scrollx = 0; 115 int scrollrow = 0; 116 int scrolly = 0; 117 118 // the selection 119 boolean highlightItems = false; // highlight new items? 120 Thread colorThread = null; 121 boolean selectable = false; 122 int selectedRow = -1; 123 Color selectColor; 124 boolean editable = true; 125 126 // flag to track if the selection change has been canceled 127 private boolean cancelSelect; 128 129 private final static int COLOR_NONE = 0; 130 private final static int COLOR_FIRST = 4; 131 132 /** 133 * create a new ColumnListCanvas. Before it can be used 134 * in any reasonable fashion, setHeaders() should 135 * be called, followed 136 * by an optional call to setFormat()! 137 * 138 * @param parent The parent ColumnList 139 */ ColumnListCanvas(ColumnList parent)140 public ColumnListCanvas(ColumnList parent) { 141 setLayout(null); 142 this.parent = parent; 143 144 headers = new String[0]; 145 columns = 0; 146 147 labels = new Vector(); 148 rowColors = new Vector(); 149 150 dimensions = null; 151 152 dispRows = 0; 153 records = 0; 154 155 selectColor = new Color(0, 0, 128); 156 } 157 setTextEditable(boolean value)158 public void setTextEditable(boolean value) { 159 textEditable = ensureLength(textEditable, columns); 160 for (int i = 0; i < textEditable.length; i++) 161 textEditable[i] = value; 162 } 163 setTextEditable(int column, boolean value)164 public void setTextEditable(int column, boolean value) { 165 if (column < 0 || column >= columns) 166 return; 167 168 textEditable = ensureLength(textEditable, column+1); 169 textEditable[column] = value; 170 } 171 getTextEditable(int column)172 public boolean getTextEditable(int column) { 173 if (textEditable == null || column < 0 || 174 column >= textEditable.length) 175 return false; 176 177 return textEditable[column]; 178 } 179 ensureLength(boolean[] arr, int length)180 public boolean[] ensureLength(boolean[] arr, int length) { 181 if (arr == null) 182 return new boolean[length]; 183 184 if (arr.length < length) { 185 boolean[] newarr = new boolean[length]; 186 System.arraycopy(arr, 0, newarr, 0, arr.length); 187 arr = newarr; 188 } 189 190 return arr; 191 } 192 cancelApply()193 public void cancelApply() { 194 cancelApply = true; 195 } 196 cancelEdit()197 public synchronized void cancelEdit() { 198 if (editline != null || editchoice != null) { 199 selectRow(editrow); 200 201 if (editline != null) { 202 editline.destroy(); 203 editline = null; 204 justCancelled = true; 205 } else { 206 editchoice.cancelEdit(); 207 editchoice = null; 208 justCancelled = true; 209 } 210 211 editrow = -1; 212 editcolumn = -1; 213 repaint(); 214 } 215 } 216 getEditRow()217 public int getEditRow() { 218 return editrow; 219 } 220 getEditColumn()221 public int getEditColumn() { 222 return editcolumn; 223 } 224 applyChanges()225 public boolean applyChanges() { 226 if (editchoice != null) { 227 cancelEdit(); 228 return true; 229 } else if (editline != null) { 230 editline.applyChanges(); 231 return !cancelApply; 232 } else { 233 return true; 234 } 235 } 236 startEdit(int column)237 public boolean startEdit(int column) { 238 return startEdit(column, -1); 239 } 240 startEdit(int column, int x)241 private synchronized boolean startEdit(int column, int x) { 242 if (editchoice != null) 243 return false; 244 245 if (editline != null) 246 return false; 247 248 if (column < 0 || column >= columns) 249 return false; 250 251 if (!getTextEditable(column)) 252 return false; 253 254 int row = getSelectedRow(); 255 if (row == -1) 256 return false; 257 258 Object entry = ((Object[])labels.elementAt(row))[column]; 259 260 if (entry instanceof String) { 261 String str = (String)entry; 262 editline = new EditLine(this, str, textX(str, column), 263 textY(row)); 264 editrow = row; 265 editcolumn = column; 266 editline.paint(getBufferGraphics()); 267 copyBuffer(); 268 } else if (entry instanceof CLChoice) { 269 CLChoice choice = (CLChoice)entry; 270 if (!choice.getEditable()) 271 return false; 272 editchoice = choice; 273 editrow = row; 274 editcolumn = column; 275 } else if (entry instanceof CLComponent) { 276 CLComponent comp = (CLComponent)entry; 277 if (!comp.getEditable()) 278 return false; 279 280 String text = comp.getText(); 281 282 if (text != null) { 283 int textX = comp.textX() + columnX(column); 284 int textY = comp.textY() + rowY(row); 285 286 if (x != -1 && x < textX) 287 return false; 288 289 editline = new EditLine(this, text, textX, textY); 290 editrow = row; 291 editcolumn = column; 292 editline.paint(getBufferGraphics()); 293 copyBuffer(); 294 } 295 } 296 297 if (editline != null) { 298 selectRow(-1); 299 return true; 300 } else if (editchoice != null) { 301 return true; 302 } else { 303 return false; 304 } 305 } 306 textX(String str, int column)307 public int textX(String str, int column) { 308 int x = -scrollx; 309 for (int i = 0; i < column; i++) 310 x += dimensions[i]; 311 x += LEFT_PAD; 312 313 int format = getFormat(column); 314 if (format != Label.LEFT) { 315 int width = dimensions[column] - LEFT_PAD - RIGHT_PAD; 316 FontMetrics fm = getFontMetrics(getFont()); 317 int w = fm.stringWidth(str); 318 319 if (format == Label.RIGHT) 320 x += width - w; 321 else if (format == Label.CENTER) 322 x += (width - w) / 2; 323 } 324 325 return x; 326 } 327 textY(int row)328 public int textY(int row) { 329 return headerHeight + ((row - scrollrow) * rowHeight) 330 + rowAscent; 331 } 332 333 /** 334 * ... 335 * 336 * @param ... ... 337 * @return ... 338 * @exception ... 339 */ finalize()340 protected void finalize() { 341 if (colorThread != null) 342 colorThread.stop(); 343 } 344 345 346 /** 347 * set the headers for the columns. THis also defines the 348 * # of columns. If the # of header columns 349 * changes, all current rows 350 * will be deleted, and the formatting options get reset 351 * 352 * @param headersIn array of column headers 353 */ setHeaders(String[] headersIn)354 public synchronized void setHeaders(String[] headersIn) { 355 int newColumns; 356 357 if (headersIn == null) 358 newColumns = 0; 359 else 360 newColumns = headersIn.length; 361 362 if (newColumns != columns) { 363 // # of columns change -> get rid of everything 364 delItems(); 365 labels = new Vector(); 366 rowColors = new Vector(); 367 formats = null; 368 dimensions = null; 369 } 370 371 if (headersIn == null) 372 columns = 0; 373 else 374 columns = headersIn.length; 375 headers = headersIn; 376 dimensions = null; 377 cacheDimensions(); 378 repaint(); 379 } 380 381 382 /** 383 * ... 384 * 385 * @param ... ... 386 * @return ... 387 * @exception ... 388 */ setFormats(int[] formatIn)389 public void setFormats(int[] formatIn) { 390 formats = formatIn; 391 } 392 393 394 /** 395 * ... 396 * 397 * @param ... ... 398 * @return ... 399 * @exception ... 400 */ getFormat(int column)401 public int getFormat(int column) { 402 if ((formats == null) || (column < 0) || ( 403 column >= formats.length)) 404 return Label.LEFT; 405 else 406 return formats[column]; 407 } 408 409 410 /** 411 * ... 412 * 413 * @param ... ... 414 * @return ... 415 * @exception ... 416 */ setSelectable(boolean selectable)417 public void setSelectable(boolean selectable) { 418 this.selectable = selectable; 419 } 420 421 setEditable(boolean editable_in)422 public void setEditable(boolean editable_in) { 423 editable = editable_in; 424 } 425 426 /** 427 * ... 428 * 429 * @param ... ... 430 * @return ... 431 * @exception ... 432 */ setHighlightItems(boolean highlightItems)433 public void setHighlightItems(boolean highlightItems) { 434 this.highlightItems = highlightItems; 435 } 436 setHighlighted(int row, boolean highlight)437 public void setHighlighted(int row, boolean highlight) { 438 if (row < 0 || row >= records) 439 return; 440 441 if (highlight) { 442 rowColors.setElementAt(new Integer(COLOR_FIRST), row); 443 444 if (highlightItems == true) { 445 if (colorThread == null) { 446 colorThread = new ColumnListThread(this); 447 colorThread.start(); 448 } else { 449 colorThread.resume(); 450 } 451 } 452 } else { 453 rowColors.setElementAt(new Integer(COLOR_NONE), row); 454 } 455 } 456 getHighlighted(int row)457 public boolean getHighlighted(int row) { 458 if (row < 0 || row >= records) 459 return false; 460 461 int rowColor = ((Integer) rowColors.elementAt(row)).intValue(); 462 return (rowColor != COLOR_NONE); 463 } 464 465 466 /** 467 * ... 468 * 469 * @param ... ... 470 * @return ... 471 * @exception ... 472 */ setShowHeaders(boolean showHeaders)473 public void setShowHeaders(boolean showHeaders) { 474 this.showHeaders = showHeaders; 475 repaint(); 476 } 477 478 479 /** 480 * ... 481 * 482 * @param ... ... 483 * @return ... 484 * @exception ... 485 */ setShowVerticalLines(boolean showVerticalLines)486 public void setShowVerticalLines(boolean showVerticalLines) { 487 this.showVerticalLines = showVerticalLines; 488 repaint(); 489 } 490 491 492 /** 493 * ... 494 * 495 * @param ... ... 496 * @return ... 497 * @exception ... 498 */ setShowHorizontalLines(boolean showHorizontalLines)499 public void setShowHorizontalLines(boolean showHorizontalLines) { 500 this.showHorizontalLines = showHorizontalLines; 501 repaint(); 502 } 503 504 505 /** 506 * ... 507 * 508 * @param ... ... 509 * @return ... 510 * @exception ... 511 */ setAutoWidth(boolean autoWidth)512 public void setAutoWidth(boolean autoWidth) { 513 this.autoWidth = autoWidth; 514 } 515 516 517 // Scrollable 518 /** 519 * ... 520 * 521 * @param ... ... 522 * @return ... 523 * @exception ... 524 */ scrollX(int x)525 public void scrollX(int x) { 526 if (scrollApply()) { 527 scrollx = x; 528 repaint(); 529 } else { 530 parent.setHBarValue(scrollx); 531 } 532 } 533 534 535 /** 536 * Scroll vertically to y. Part of Scrollabel interface. 537 * 538 * @param y new vertical scroll position 539 */ scrollY(int y)540 public void scrollY(int y) { 541 if (scrollApply()) { 542 scrolly = y; 543 if (rowHeight != 0) 544 scrollrow = (y + rowHeight - 1) / rowHeight; 545 else 546 scrollrow = 0; 547 repaint(); 548 } else { 549 parent.setVBarValue(scrolly); 550 } 551 } 552 553 scrollApply()554 private boolean scrollApply() { 555 boolean status = true; 556 if (!applying) { 557 applying = true; 558 status = applyChanges(); 559 560 // The Motif scrollbar gets locked down 561 // when a modal dialog is 562 // brought up while scrolling. To prevent getting infinite 563 // errors, we will cancel the edit here. 564 if (!status && Global.isMotif()) 565 cancelEdit(); 566 567 applying = false; 568 } 569 return status; 570 } 571 scrollSize()572 public Dimension scrollSize() { 573 cacheDimensions(); 574 if (dimensions == null) 575 return new Dimension(100, 100); 576 else 577 return new Dimension(totalWidth, rowHeight * records); 578 } 579 viewSize(Dimension size)580 public Dimension viewSize(Dimension size) { 581 cacheDimensions(); 582 size.height -= headerHeight; 583 return size; 584 } 585 586 /** 587 * ... 588 * 589 * @param ... ... 590 * @return ... 591 * @exception ... 592 */ lineHeight()593 public int lineHeight() { 594 cacheDimensions(); 595 return rowHeight; 596 } 597 addMoreLabels()598 private synchronized void addMoreLabels() { 599 int c; 600 // have one extra for the "hidden" object 601 Object[] newLabels = new Object[columns + 1]; 602 labels.addElement(newLabels); 603 rowColors.addElement(new Integer(COLOR_NONE)); 604 for (c = 0; c < columns; c++) 605 newLabels[c] = /* NOI18N */""; 606 newLabels[columns] = null; 607 } 608 ensureCapacity(int row)609 private void ensureCapacity(int row) { 610 while (row >= labels.size()) 611 addMoreLabels(); 612 } 613 growRecords(int row)614 private void growRecords(int row) { 615 // initialize all intermediate records 616 while (row > records) { 617 Object[] labelRow = (Object[]) labels.elementAt(records); 618 for (int c = 0; c < columns; c++) 619 labelRow[c] = /* NOI18N */""; 620 labelRow[columns] = null; 621 rowColors.setElementAt(new Integer(COLOR_NONE), records); 622 records++; 623 } 624 } 625 626 627 /** 628 * ... 629 * 630 * @param ... ... 631 * @return ... 632 * @exception ... 633 */ insertItem(Object[] values, int row)634 public synchronized void insertItem(Object[] values, int row) { 635 int c; 636 boolean newWidth = false; 637 638 // make sure we have enough labels... 639 ensureCapacity(row); 640 growRecords(row); 641 642 // Make one extra entry 643 ensureCapacity(records + 1); 644 growRecords(records + 1); 645 646 // Move other rows out of the way 647 for (int pos = records-2; row <= pos; --pos) { 648 labels.setElementAt(labels.elementAt(pos), pos+1); 649 rowColors.setElementAt(rowColors.elementAt(pos), pos+1); 650 } 651 Object[] labelRow = new Object[columns+1]; 652 for (c = 0; c < columns; c++) 653 labelRow[c] = /* NOI18N */""; 654 labelRow[columns] = null; 655 labels.setElementAt(labelRow, row); 656 657 // Fix selected row 658 if (selectedRow >= row) 659 ++selectedRow; 660 661 // Call addItem to replace things 662 addItem(values, row); 663 } 664 665 666 /** 667 * ... 668 * 669 * @param ... ... 670 * @return ... 671 * @exception ... 672 */ addItem(Object[] values)673 public synchronized void addItem(Object[] values) { 674 addItem(values, records); 675 } 676 677 678 /** 679 * ... 680 * 681 * @param ... ... 682 * @return ... 683 * @exception ... 684 */ addItem(Object[] values, int row)685 public synchronized void addItem(Object[] values, int row) { 686 // make sure we have enough labels... 687 ensureCapacity(row); 688 growRecords(row); 689 690 if (autoWidth) 691 cacheDimensions(); 692 693 Object[] labelRow = (Object[]) labels.elementAt(row); 694 695 for (int c = 0; c < columns; c++) { 696 labelRow[c] = values[c]; 697 if (values[c] instanceof CLComponent) 698 ((CLComponent)values[c]).setCanvas(this, row, c); 699 checkComponentCell(values[c]); 700 } 701 if (values.length > columns) 702 labelRow[columns] = values[columns]; 703 else 704 labelRow[columns] = null; 705 706 adjustColumnWidths(row); 707 708 if (highlightItems == true) { 709 rowColors.setElementAt(new Integer(COLOR_FIRST), row); 710 if (colorThread == null) { 711 colorThread = new ColumnListThread(this); 712 colorThread.start(); 713 } else 714 colorThread.resume(); 715 } else 716 rowColors.setElementAt(new Integer(COLOR_NONE), row); 717 if (row >= records) 718 records++; 719 } 720 721 722 /** 723 * Adjust the widths of the columns for 'row' to make sure 724 * everything 725 * fits properly. If autoWidth is false, then this 726 * function has no effect 727 * 728 * @param row row number 729 */ adjustColumnWidths(int row)730 private void adjustColumnWidths(int row) { 731 if (!autoWidth || (dimensions == null)) 732 return; 733 734 Object[] labelRow = (Object[]) labels.elementAt(row); 735 for (int c = 0; c < columns; c++) 736 adjustColumnWidths(labelRow[c], c); 737 } 738 739 740 /** 741 * If autoWidth is enabled, make sure "value" fits 742 * into the given column. 743 * 744 * @param value the value to be checked 745 * @param column column number 746 */ adjustColumnWidths(Object value, int column)747 void adjustColumnWidths(Object value, int column) { 748 if (!autoWidth || (value == null) || (dimensions == null)) 749 return; 750 751 int w = labelWidth(value); 752 int usableWidth = dimensions[column]; 753 if (w > usableWidth) { 754 totalWidth += w - usableWidth; 755 dimensions[column] += w - usableWidth; 756 } 757 } 758 759 760 /** 761 * If the object (to be put into a cell) is an AWT component, make 762 * sure it gets properly managed in the layout, and 763 * that the rows are 764 * high enough to hold it. 765 * 766 * @param ... ... 767 * @return ... 768 * @exception ... 769 */ checkComponentCell(Object value)770 private void checkComponentCell(Object value) { 771 if (value instanceof Component) { 772 if (hasComponents == null) 773 hasComponents = (Component) value; 774 add((java.awt.Component) value); 775 ((java.awt.Component) value).hide(); 776 Dimension size = ((java.awt.Component) value). 777 preferredSize(); 778 if (size.height > componentHeight) { 779 componentHeight = size.height; 780 if (componentHeight > rowHeight) { 781 rowAscent += (componentHeight - rowHeight) / 2; 782 rowHeight = componentHeight + 2; 783 } 784 785 } 786 } 787 } 788 789 /** 790 * ... 791 * 792 * @param ... ... 793 * @return ... 794 * @exception ... 795 */ delItems()796 public synchronized void delItems() { 797 delItems(0, records - 1); 798 selectedRow = -1; 799 } 800 801 802 /** 803 * ... 804 * 805 * @param ... ... 806 * @return ... 807 * @exception ... 808 */ delItems(int start, int end)809 public synchronized void delItems(int start, int end) { 810 if ((start < 0) || (start >= records)) 811 return; 812 if (end < start) 813 return; 814 if (end > records) 815 end = records - 1; 816 int r, c; 817 int diff = end - start + 1; 818 for (r = start; r <= end; r++) { 819 Object[] labelRow = (Object[]) labels.elementAt(start); 820 for (c = 0; c < columns; c++) { 821 if (labelRow[c] instanceof Component) 822 remove((java.awt.Component) labelRow[c]); 823 else if (labelRow[c] instanceof CLComponent) 824 ((CLComponent)labelRow[c]).setCanvas(null, -1, -1); 825 } 826 827 labels.removeElementAt(start); 828 rowColors.removeElementAt(start); 829 } 830 records -= diff; 831 832 if (selectedRow > end) 833 selectedRow -= diff; 834 else if (selectedRow > start) 835 selectedRow = start - 1; 836 837 // repaint all the time... could be optimized 838 repaint(); 839 } 840 841 842 /** 843 * ... 844 * 845 * @param ... ... 846 * @return ... 847 * @exception ... 848 */ getItem(int row, int column)849 protected Object getItem(int row, int column) { 850 if ((row > records) || (row < 0) || (column > columns) || 851 (column < 0)) 852 return null; 853 return ((Object []) labels.elementAt(row))[column]; 854 } 855 856 857 /** 858 * ... 859 * 860 * @param ... ... 861 * @return ... 862 * @exception ... 863 */ putItem(int row, int column, Object value)864 protected synchronized boolean putItem(int row, int column, 865 Object value) { 866 if ((row > records) || (row < 0) || (column > columns) || 867 (column < 0)) 868 return false; 869 Object[] data = (Object []) labels.elementAt(row); 870 data[column] = value; 871 if (value instanceof CLComponent) 872 ((CLComponent)value).setCanvas(this, row, column); 873 874 if (column < columns) { 875 // don't do this on objects in the hidden column 876 checkComponentCell(value); 877 adjustColumnWidths(value, column); 878 } 879 880 repaint(); 881 return true; 882 } 883 884 885 /** 886 * ... 887 * 888 * @param ... ... 889 * @return ... 890 * @exception ... 891 */ swapItems(int row1, int row2)892 protected boolean swapItems(int row1, int row2) { 893 if ((row1 > records) || (row1 < 0) || (row2 > records) || 894 (row2 < 0)) 895 return false; 896 if (row1 == row2) 897 return true; 898 Object[] data1 = (Object []) labels.elementAt(row1); 899 Object[] data2 = (Object []) labels.elementAt(row2); 900 labels.setElementAt(data2, row1); 901 labels.setElementAt(data1, row2); 902 repaint(); 903 return true; 904 } 905 chopText(String text, int w)906 public String chopText(String text, int w) { 907 if (w <= 0) 908 return /* NOI18N */""; 909 910 FontMetrics fm = getFontMetrics(); 911 int len = text.length(); 912 int index = getTextCutoff(fm, w, text, len, 0, len); 913 if (index == len) 914 return text; 915 else 916 return text.substring(0, index); 917 } 918 getTextCutoff(FontMetrics fm, int textW, String str, int cur, int lower, int upper)919 private int getTextCutoff(FontMetrics fm, int textW, String str, 920 int cur, int lower, int upper) { 921 if (lower == upper) { 922 return lower; 923 } else if (lower == (upper-1)) { 924 int width = fm.stringWidth(str.substring(0, upper)); 925 if (width < textW) 926 return upper; 927 else 928 return lower; 929 } 930 931 int width = fm.stringWidth(str.substring(0, cur)); 932 if (width == textW) 933 return cur; 934 else if (width < textW) 935 return getTextCutoff(fm, textW, str, 936 cur + (upper-cur)/2, cur, upper); 937 else 938 return getTextCutoff(fm, textW, str, 939 cur - (cur-lower)/2, lower, cur); 940 } 941 942 // drawString - calls g.drawString(str, x, y), but 943 // makes sure that str 944 // will fit into width drawString(Graphics g, String str, int x, int y, int width, int format)945 public void drawString(Graphics g, String str, int x, int y, 946 int width, int format) { 947 str = chopText(str, width); 948 949 g.setFont(getFont()); 950 FontMetrics fm = g.getFontMetrics(); 951 int w = fm.stringWidth(str); 952 if (w <= 0) 953 return; 954 955 if (format == Label.RIGHT) 956 x += width - w; 957 else if (format == Label.CENTER) 958 x += (width - w) / 2; 959 g.drawString(str, x, y); 960 } 961 getFontMetrics()962 public FontMetrics getFontMetrics() { 963 return getFontMetrics(getFont()); 964 } 965 966 /** 967 * ... 968 * 969 * @param ... ... 970 * @return ... 971 * @exception ... 972 */ setFont(Font font)973 public void setFont(Font font) { 974 super.setFont(font); 975 dimensions = null; 976 cacheDimensions(); 977 } 978 979 980 /** 981 * ... 982 * 983 * @param ... ... 984 * @return ... 985 * @exception ... 986 */ update(Graphics g)987 public void update(Graphics g) { 988 paint(g); 989 } 990 991 992 /** 993 * Determines the width a label item needs. 994 * 995 * @param ... ... 996 * @return ... 997 * @exception ... 998 */ labelWidth(Object item)999 private int labelWidth(Object item) { 1000 if (item == null) 1001 return (0); 1002 else if (item instanceof Component) 1003 return ((Component) item).preferredSize().width + 1004 LEFT_PAD + RIGHT_PAD; 1005 else if (item instanceof String) { 1006 String str = (String)item; 1007 Graphics g = getBufferGraphics(); 1008 g.setFont(getFont()); 1009 FontMetrics fm = g.getFontMetrics(); 1010 return fm.stringWidth(str) + LEFT_PAD + RIGHT_PAD; 1011 } else if (item instanceof CLComponent) { 1012 Dimension s = ((CLComponent) item).size(); 1013 if (s != null) 1014 return s.width; 1015 else 1016 return 0; 1017 } else { 1018 return 0; 1019 } 1020 } 1021 1022 /** 1023 * ... 1024 * 1025 * @param ... ... 1026 * @return ... 1027 * @exception ... 1028 */ cacheDimensions()1029 private void cacheDimensions() { 1030 if (dimensions != null) 1031 return; 1032 1033 Graphics g = getBufferGraphics(); 1034 if (g == null) 1035 return; 1036 1037 g.setFont(getFont()); 1038 FontMetrics fm = g.getFontMetrics(); 1039 1040 // figure out rowHeight (must be done before labelWidth is 1041 // ever called, because CLComponent width calculation depends 1042 // on rowHeight) 1043 rowHeight = fm.getHeight() + 3; 1044 rowAscent = fm.getAscent() + 2; 1045 1046 if (Global.isWindows() && showHorizontalLines) 1047 rowHeight++; 1048 else if (Global.isMotif() && !showHorizontalLines) 1049 rowHeight--; 1050 1051 charWidth = fm.charWidth(/* NOI18N */ 'X'); 1052 1053 if ((componentHeight == 0) && (hasComponents != null)) 1054 componentHeight = hasComponents.preferredSize().height; 1055 1056 if (rowHeight < componentHeight) { 1057 rowAscent += (componentHeight - rowHeight) / 2; 1058 rowHeight = componentHeight; 1059 } 1060 if (showHeaders) 1061 headerHeight = rowHeight + 6; 1062 else 1063 headerHeight = 0; 1064 1065 // figure out column widths 1066 dimensions = new int[(columns == 0) ? 1 : columns]; 1067 totalWidth = 0; 1068 for (int c = 0; c < columns; c++) { 1069 // base size of columns on header string 1070 int width = fm.stringWidth(headers[c]) + 10; 1071 1072 if (autoWidth) { 1073 // column should be the width of the widest data item 1074 for (int r = 0; r < records; r++) { 1075 Object[] labelRow = (Object[]) labels.elementAt(r); 1076 int itemWidth = labelWidth(labelRow[c]); 1077 if (itemWidth > width) 1078 width += itemWidth - width; 1079 } 1080 } 1081 1082 dimensions[c] = width; 1083 totalWidth += dimensions[c]; 1084 } 1085 1086 } 1087 paint(Graphics g)1088 public void paint(Graphics g) { 1089 if (Global.isWindows()) 1090 g = getGraphics(); 1091 paint(g, null); 1092 } 1093 paint(Graphics g, Rectangle cliprect)1094 private synchronized void paint(Graphics g, Rectangle cliprect) { 1095 Image buffer = getBuffer(size()); 1096 g = buffer.getGraphics(); 1097 g.setFont(getFont()); 1098 1099 // first time? get the dimensions of the header panel 1100 cacheDimensions(); 1101 1102 // how many rows fit? 1103 Dimension canvasSize = size(); 1104 int usableHeight = canvasSize.height - headerHeight; 1105 int usableWidth = canvasSize.width; 1106 dispRows = usableHeight / rowHeight; 1107 1108 // visibleRows can be one more than 1109 // dispRows (last row partially visible) 1110 visibleRows = (usableHeight + rowHeight - 1) / rowHeight; 1111 // make sure we have enough labels... 1112 int horOffset = scrollx; 1113 int vertOffset = scrollrow; 1114 while ((visibleRows + vertOffset) > labels.size()) 1115 addMoreLabels(); 1116 1117 g.setColor(getForeground()); 1118 Color origColor = g.getColor(); 1119 Color dark = getBackground().darker(); 1120 Color veryDark = dark.darker(); 1121 1122 1123 // draw the column headers 1124 int x = 0; 1125 int colWidth; 1126 if (showHeaders) { 1127 for (int c = 0; c <= columns; c++) { 1128 1129 if (c == columns) 1130 // last column fills up the rest 1131 colWidth = usableWidth - x + horOffset; 1132 else 1133 colWidth = dimensions[c]; 1134 1135 int left = x - horOffset; 1136 int right = left + colWidth - 1; 1137 int bottom = headerHeight - 1; 1138 1139 // is the column for real, and some of it visible? 1140 if ((colWidth > 0) && ((right > 0) || 1141 (left < usableWidth))) { 1142 // now draw the thing... 1143 g.setColor(getBackground()); 1144 g.drawLine(left, 0, right, 0); // top 1145 g.drawLine(left, 0, left, bottom); // left 1146 1147 g.setColor(veryDark); 1148 g.drawLine(left, bottom, right, bottom); // bottom 1149 g.drawLine(right, 0, right, bottom); // right 1150 1151 g.setColor(dark); 1152 g.fillRect(left + 1, 1, colWidth - 2, 1153 headerHeight - 2); 1154 1155 g.setColor(origColor); 1156 1157 // last column has no strings 1158 if (c != columns) 1159 drawString(g, headers[c], left + LEFT_PAD, 1160 headerHeight - 5, 1161 colWidth - LEFT_PAD - RIGHT_PAD, 1162 getFormat(c)); 1163 } 1164 1165 if (c != columns) 1166 x += dimensions[c]; 1167 } 1168 } 1169 1170 // now paint the data 1171 int y = headerHeight; 1172 for (int r = 0; r < labels.size(); r++) { 1173 if ((r >= vertOffset) && (r < 1174 (visibleRows + vertOffset))) { 1175 x = 0; 1176 Object[] row = (Object[]) labels.elementAt(r); 1177 int rowColor = ((Integer) rowColors.elementAt(r)). 1178 intValue(); 1179 1180 Color stringForeground = 1181 getStringForeground(origColor, r, rowColor); 1182 Color stringBackground = 1183 getStringBackground(r, rowColor); 1184 1185 g.setColor(stringBackground); 1186 g.fillRect(0, y, usableWidth, rowHeight); 1187 g.setColor(stringForeground); 1188 1189 for (int c = 0; c < columns; c++) { 1190 colWidth = dimensions[c]; 1191 int left = x - horOffset; 1192 int right = left + colWidth - 1; 1193 1194 // is the column for real, and some of it visible? 1195 if ((colWidth > 0) && 1196 ((right > 0) || (left < usableWidth))) { 1197 if (row[c] != null) 1198 if (row[c] instanceof String) 1199 drawString(g, (String) row[c], 1200 left + LEFT_PAD, 1201 y + rowAscent, 1202 colWidth - LEFT_PAD - RIGHT_PAD, 1203 getFormat(c)); 1204 else if (row[c] instanceof CLComponent) 1205 ((CLComponent)row[c]).paint(g, left, y, 1206 colWidth, rowHeight, 1207 rowAscent, 1208 getFormat(c)); 1209 else if (row[c] instanceof Component) { 1210 Component cb = (Component) row[c]; 1211 Dimension size = cb.preferredSize(); 1212 size = new Dimension(size.width, 1213 size.height); 1214 if (size.width > (colWidth - 2)) 1215 size.width = colWidth - 2; 1216 cb.reshape(left + 2, y, 1217 size.width, rowHeight); 1218 cb.setBackground(stringBackground); 1219 cb.setForeground(stringForeground); 1220 cb.show(); 1221 // cb.validate(); 1222 } else 1223 drawString(g, row[c].toString(), 1224 left + LEFT_PAD, y + rowAscent, 1225 colWidth - LEFT_PAD - RIGHT_PAD, 1226 getFormat(c)); 1227 } else { 1228 if (row[c] != null) 1229 if (row[c] instanceof Component) { 1230 Component cb = (Component) row[c]; 1231 cb.hide(); 1232 } 1233 } 1234 x += dimensions[c]; 1235 } 1236 y += rowHeight; 1237 if (showHorizontalLines) { 1238 g.setColor(dark); 1239 g.drawLine(0, y - 1, usableWidth, y - 1); 1240 } 1241 g.setColor(origColor); 1242 } else { 1243 Object[] row = (Object[]) labels.elementAt(r); 1244 for (int c = 0; c < row.length; c++) 1245 if (row[c] instanceof Component) 1246 ((Component) row[c]).hide(); 1247 } 1248 } // for each row 1249 1250 1251 if (showVerticalLines) { 1252 g.setColor(dark); 1253 x = 0; 1254 for (int c = 0; c < columns; c++) { 1255 colWidth = dimensions[c]; 1256 int left = x - horOffset; 1257 int right = left + colWidth - 1; 1258 1259 // only draw if the line would be visible 1260 if (right > usableWidth) 1261 break; 1262 if ((colWidth > 0) && (right > 0)) 1263 g.drawLine(right, headerHeight, right, 1264 canvasSize.height); 1265 1266 x += dimensions[c]; 1267 } 1268 } 1269 1270 if (editline != null) 1271 editline.paint(g); 1272 1273 copyBuffer(); 1274 } 1275 getBuffer(Dimension size)1276 private Image getBuffer(Dimension size) { 1277 // WORK-AROUND: sometimes size() calls return 1278 // dimensions of 0 for width 1279 // or height when they probably shouldn't 1280 // (this is on Win95), and it 1281 // causes an illegal argument exception in 1282 // the createImage call below 1283 if (size.width == 0 || size.height == 0) { 1284 if (buffer != null && bufferSize != null) 1285 size = new Dimension(bufferSize); 1286 else 1287 size = new Dimension(1, 1); 1288 } 1289 // end of WORK-AROUND 1290 1291 if (buffer == null || bufferSize == null || 1292 (size.width != bufferSize.width) || 1293 (size.height != bufferSize.height)) { 1294 1295 getCachedBuffer(size); 1296 1297 if (buffer == null || bufferSize == null || 1298 (size.width != bufferSize.width) || 1299 (size.height != bufferSize.height)) { 1300 buffer = createImage(size.width, size.height); 1301 updateCache(buffer, size); 1302 } 1303 1304 bufferSize = size; 1305 } 1306 1307 return buffer; 1308 } 1309 getBufferGraphics()1310 private Graphics getBufferGraphics() { 1311 Image buffer = getBuffer(size()); 1312 if (buffer == null) 1313 return null; 1314 else 1315 return buffer.getGraphics(); 1316 } 1317 copyBuffer()1318 private void copyBuffer() { 1319 Graphics g = getGraphics(); 1320 Image buffer = getBuffer(size()); 1321 if (g != null && buffer != null) 1322 g.drawImage(buffer, 0, 0, this); 1323 } 1324 getCachedBuffer(Dimension size)1325 private void getCachedBuffer(Dimension size) { 1326 for (int i = 0; i < 3; i++) { 1327 if (bufferSizeCache[i] != null && 1328 bufferSizeCache[i].width == size.width && 1329 bufferSizeCache[i].height == size.height) { 1330 buffer = bufferCache[i]; 1331 bufferSize = bufferSizeCache[i]; 1332 break; 1333 } 1334 } 1335 } 1336 updateCache(Image buffer, Dimension size)1337 private void updateCache(Image buffer, Dimension size) { 1338 if (buffer == null) 1339 return; 1340 1341 int i; 1342 for (i = 0; i < 3; i++) { 1343 if (bufferSizeCache[i] == null) 1344 break; 1345 } 1346 1347 if (i < 3) { 1348 bufferCache[i] = buffer; 1349 bufferSizeCache[i] = new Dimension(size.width, size.height); 1350 } else { 1351 bufferCache[0] = bufferCache[1]; 1352 bufferCache[1] = bufferCache[2]; 1353 bufferCache[2] = buffer; 1354 1355 bufferSizeCache[0] = bufferSizeCache[1]; 1356 bufferSizeCache[1] = bufferSizeCache[2]; 1357 bufferSizeCache[2] = new Dimension(size.width, size.height); 1358 } 1359 } 1360 1361 /** 1362 * ... 1363 * 1364 * @param ... ... 1365 * @return ... 1366 * @exception ... 1367 */ getStringForeground(Color origColor, int row, int rowColor)1368 private Color getStringForeground(Color origColor, 1369 int row, int rowColor) { 1370 if (row == selectedRow) 1371 return getBackground(); 1372 else 1373 return origColor; 1374 } 1375 getStringBackground(int row, int rowColor)1376 private Color getStringBackground(int row, int rowColor) { 1377 Color bg = getBackground(); 1378 if (row == selectedRow) { 1379 if (rowColor != COLOR_NONE) 1380 if (bg == Color.white) 1381 return Color.magenta; 1382 else 1383 return selectColor.darker(); 1384 else 1385 return selectColor; 1386 } else { 1387 if (rowColor != COLOR_NONE) 1388 if (bg == Color.white) 1389 return Color.orange; 1390 else 1391 return bg.darker(); 1392 else 1393 return getBackground(); 1394 } 1395 1396 } 1397 rowVisible(int row)1398 private boolean rowVisible(int row) { 1399 return ((row >= scrollrow) && 1400 (row < (scrollrow + dispRows))); 1401 } 1402 1403 updateView()1404 public void updateView() { 1405 parent.updateView(); 1406 } 1407 1408 1409 /** 1410 * @see sunsoft.jws.visual.designer.gui.ColumnList 1411 */ setDisplayRows(int rows)1412 public void setDisplayRows(int rows) { 1413 requestedRows = rows; 1414 } 1415 1416 setVisibleChars(int chars)1417 public void setVisibleChars(int chars) { 1418 requestedChars = chars; 1419 } 1420 1421 1422 /** 1423 * the minimum width is enough to fully display 1424 * the first column, but not 1425 * more than 200 pixels. The minimum height is the 1426 * height to display the 1427 * number of rows requested with setDisplayRows() (default is 3) 1428 * 1429 * @return Dimension 1430 */ minimumSize()1431 public Dimension minimumSize() { 1432 return preferredSize(); 1433 } 1434 1435 /** 1436 * Calculate the preferred size. Standard AWT function. 1437 * 1438 * @return the preferred size of the ColumnListCanvas 1439 */ preferredSize()1440 public Dimension preferredSize() { 1441 cacheDimensions(); 1442 if (dimensions == null) 1443 return new Dimension(100, 100); 1444 else 1445 if (requestedChars == 0) 1446 return new Dimension(totalWidth, 1447 headerHeight + rowHeight * requestedRows); 1448 else 1449 return new Dimension(requestedChars * charWidth, 1450 headerHeight + rowHeight * requestedRows); 1451 } 1452 1453 1454 /** 1455 * select row, and make it visible 1456 * only one row can be selected at a time - previously selected 1457 * rows will be restored to normal 1458 * to remove the selection, set the selected row to -1 1459 * 1460 * @param row index of row 1461 * @return actual index of selected row, -1 if none 1462 */ selectRow(int row)1463 public int selectRow(int row) { 1464 if (selectedRow != row) { 1465 int oldSelectedRow = selectedRow; 1466 if (row < records) 1467 selectedRow = row; 1468 else 1469 selectedRow = -1; 1470 1471 // make sure we can see the new selection 1472 // Tilman 05/21: Not tested if the makeVisible() call works 1473 if ((selectedRow != -1) && (!rowVisible(selectedRow))) 1474 parent.makeVisible(selectedRow); 1475 1476 // repaint if anything is visible 1477 if (rowVisible(oldSelectedRow) || rowVisible(selectedRow)) 1478 repaint(); 1479 } 1480 return selectedRow; 1481 } 1482 1483 1484 /** 1485 * Get the index of the currently selected row 1486 * 1487 * @return index of selected row, -1 if none is selected 1488 */ getSelectedRow()1489 public int getSelectedRow() { 1490 return selectedRow; 1491 } 1492 1493 1494 /** 1495 * ... 1496 * 1497 * @param ... ... 1498 * @return ... 1499 * @exception ... 1500 */ getRowY(int row)1501 protected int getRowY(int row) { 1502 if ((dimensions == null) || (visibleRows == -1)) 1503 return -2; 1504 if (rowVisible(row)) { 1505 return headerHeight + rowHeight * (row - scrollrow); 1506 } else 1507 return -1; 1508 } 1509 1510 1511 /** 1512 * ... 1513 * 1514 * @param ... ... 1515 * @return ... 1516 * @exception ... 1517 */ startDrag(int startX)1518 private synchronized void startDrag(int startX) { 1519 int x = -scrollx; 1520 for (int c = 0; c < columns; c++) { 1521 x += dimensions[c]; 1522 if ((startX >= (x - 5)) && (startX <= (x + 5))) { 1523 dragColumn = c; 1524 dragging = true; 1525 dragStart = startX; 1526 break; 1527 } 1528 } 1529 } 1530 1531 1532 /** 1533 * ... 1534 * 1535 * @param ... ... 1536 * @return ... 1537 * @exception ... 1538 */ mouseColumn(int mouseX)1539 private synchronized int mouseColumn(int mouseX) { 1540 int x = -scrollx; 1541 if (mouseX < x) 1542 return -1; 1543 for (int c = 0; c < columns; c++) { 1544 x += dimensions[c]; 1545 if (mouseX < x) 1546 return c; 1547 } 1548 return -1; 1549 } 1550 1551 1552 /** 1553 * ... 1554 * 1555 * @param ... ... 1556 * @return ... 1557 * @exception ... 1558 */ dragColumn(int dragX)1559 private synchronized void dragColumn(int dragX) { 1560 int diff = dragX - dragStart; 1561 if (dimensions[dragColumn] + diff >= 5) { 1562 dimensions[dragColumn] += diff; 1563 totalWidth += diff; 1564 dragStart = dragX; 1565 repaint(); 1566 } 1567 } 1568 handleEvent(Event evt)1569 public boolean handleEvent(Event evt) { 1570 // 1571 // Workaround for an AWT bug on Windows95 1572 // where we get a spurious 1573 // mouse down event when the CLChoice menu is 1574 // unmapped as the result 1575 // of selection being made from a mouse down 1576 // event inside the menu. 1577 // 1578 if (editchoice == null && justCancelled && 1579 evt.id == Event.MOUSE_DOWN) { 1580 justCancelled = false; 1581 return true; 1582 } 1583 justCancelled = false; 1584 1585 if (editline != null && editline.handleEvent(evt)) 1586 return true; 1587 else if (editchoice != null && editchoice.handleEvent(evt)) 1588 return true; 1589 1590 if (evt.id == EditLine.REPAINT && evt.target == editline) { 1591 if (evt.arg != null) { 1592 paint(getGraphics(), (Rectangle)evt.arg); 1593 } else { 1594 editline.paint(getBufferGraphics()); 1595 copyBuffer(); 1596 } 1597 } else if (evt.id == EditLine.APPLY && evt.target == editline) { 1598 cancelApply = false; 1599 parent.postEvent(new Event(parent, ColumnList.APPLY_EDIT, 1600 evt.arg)); 1601 if (!cancelApply) { 1602 changeText((String)evt.arg, editrow, editcolumn); 1603 cancelEdit(); 1604 } else if (editline != null) { 1605 editline.cancelApply(); 1606 } 1607 } else if (evt.id == EditLine.CANCEL && 1608 evt.target == editline) { 1609 cancelEdit(); 1610 } else if (evt.id == CLChoice.APPLY && 1611 evt.target == editchoice) { 1612 cancelApply = false; 1613 parent.postEvent(new Event(parent, ColumnList.APPLY_EDIT, 1614 evt.arg)); 1615 if (!cancelApply) { 1616 changeText((String)evt.arg, editrow, editcolumn); 1617 cancelEdit(); 1618 } 1619 } else { 1620 return super.handleEvent(evt); 1621 } 1622 1623 return true; 1624 } 1625 changeText(String text, int row, int column)1626 public synchronized void changeText(String text, int row, 1627 int column) { 1628 if (row < 0 || row >= records || column < 0 || 1629 column >= columns) 1630 return; 1631 1632 Object[] data = (Object []) labels.elementAt(row); 1633 Object item = data[column]; 1634 1635 if (item instanceof String) { 1636 data[column] = text; 1637 adjustColumnWidths(text, column); 1638 parent.updateView(); 1639 } else if (item instanceof CLComponent) { 1640 ((CLComponent)item).setText(text, true); 1641 } 1642 } 1643 columnX(int column)1644 public int columnX(int column) { 1645 int x = -scrollx; 1646 for (int c = 0; c < column; c++) 1647 x += dimensions[c]; 1648 return x; 1649 } 1650 columnWidth(int column)1651 public int columnWidth(int column) { 1652 return dimensions[column]; 1653 } 1654 rowY(int row)1655 public int rowY(int row) { 1656 return headerHeight + ((row - scrollrow) * rowHeight); 1657 } 1658 rowHeight(int row)1659 public int rowHeight(int row) { 1660 return rowHeight; 1661 } 1662 mouseDown(Event e, int x, int y)1663 public boolean mouseDown(Event e, int x, int y) { 1664 if (editline != null) { 1665 if (!applyChanges()) 1666 return false; 1667 selectRow(-1); 1668 } else if (editchoice != null) { 1669 cancelEdit(); 1670 selectRow(-1); 1671 } 1672 1673 if (y > headerHeight) { 1674 int row = (y - headerHeight - 1) / rowHeight + scrollrow; 1675 if (row < records) { 1676 int column = mouseColumn(x); 1677 if (column != -1) { 1678 Object entry = ((Object[]) 1679 labels.elementAt(row))[column]; 1680 if ((entry instanceof CLComponent) && editable) { 1681 CLComponent comp = (CLComponent)entry; 1682 Event evt = new Event(e.target, e.when, e.id, 1683 x - columnX(column), 1684 y - rowY(row), e.key, 1685 e.modifiers, e.arg); 1686 evt.clickCount = e.clickCount; 1687 if (comp.mouseDown(evt)) 1688 return true; 1689 } 1690 } 1691 if (selectable) { 1692 cancelSelect = false; 1693 if (e.clickCount == 1) { 1694 if (row == getSelectedRow() && 1695 getTextEditable(column)) { 1696 cancelEdit(); 1697 if (startEdit(column, x)) { 1698 return true; 1699 } else { 1700 // Should make a beeping or 1701 // clicking noise somehow. 1702 } 1703 } 1704 1705 parent.postEvent(new Event(parent, 1706 ColumnList.CONFIRM_SELECT, 1707 new Integer(row))); 1708 if (!cancelSelect) { 1709 row = selectRow(row); 1710 parent.postEvent(new Event(parent, 1711 Event.LIST_SELECT, 1712 new Integer(row))); 1713 } 1714 } else if (e.clickCount == 2) { 1715 row = selectRow(row); 1716 parent.postEvent(new Event(parent, 1717 Event.ACTION_EVENT, 1718 new Integer(row))); 1719 } 1720 } 1721 } 1722 } else if (y < headerHeight) { 1723 startDrag(x); 1724 } 1725 return true; 1726 } 1727 1728 1729 /** 1730 * ... 1731 * 1732 * @param ... ... 1733 * @return ... 1734 * @exception ... 1735 */ mouseDrag(Event e, int x, int y)1736 public boolean mouseDrag(Event e, int x, int y) { 1737 if (dragging) { 1738 dragColumn(x); 1739 return true; 1740 } 1741 return false; 1742 } 1743 1744 1745 /** 1746 * ... 1747 * 1748 * @param ... ... 1749 * @return ... 1750 * @exception ... 1751 */ mouseUp(Event e, int x, int y)1752 public boolean mouseUp(Event e, int x, int y) { 1753 if (dragging) { 1754 dragging = false; 1755 parent.updateView(); 1756 return true; 1757 } 1758 return false; 1759 } 1760 1761 boolean resizeCursor = false; 1762 boolean checkedFrame = false; 1763 getFrame()1764 private Frame getFrame() { 1765 if (ourFrame == null) { 1766 if (!checkedFrame) { 1767 checkedFrame = true; 1768 Component c = parent; 1769 while (c != null) { 1770 if (c instanceof Frame) { 1771 ourFrame = (Frame) c; 1772 break; 1773 } else 1774 c = c.getParent(); 1775 } 1776 } 1777 } 1778 return ourFrame; 1779 } 1780 1781 mouseMove(Event e, int x, int y)1782 public boolean mouseMove(Event e, int x, int y) { 1783 if (getFrame() != null) { 1784 boolean resizable = false; 1785 1786 if (y < headerHeight) { 1787 int x1 = -scrollx; 1788 for (int c = 0; c < columns; c++) { 1789 x1 += dimensions[c]; 1790 if ((x >= (x1 - 5)) && (x <= (x1 + 5))) { 1791 resizable = true; 1792 break; 1793 } 1794 } 1795 } 1796 1797 if (resizable != resizeCursor) { 1798 if (resizable) 1799 ourFrame.setCursor(Frame.E_RESIZE_CURSOR); 1800 else 1801 ourFrame.setCursor(Frame.DEFAULT_CURSOR); 1802 1803 resizeCursor = resizable; 1804 } 1805 return true; 1806 } else 1807 return false; 1808 } 1809 1810 1811 /** 1812 * restore the cursor when exiting 1813 * 1814 * @param ... ... 1815 * @return ... 1816 */ mouseExit(Event e, int x, int y)1817 public boolean mouseExit(Event e, int x, int y) { 1818 if (resizeCursor) { 1819 ourFrame.setCursor(Frame.DEFAULT_CURSOR); 1820 resizeCursor = false; 1821 } 1822 return false; 1823 } 1824 1825 1826 /** 1827 * ... 1828 * 1829 * @return ... 1830 */ updateRowColors()1831 public synchronized boolean updateRowColors() { 1832 int r; 1833 boolean isChanging = false; 1834 boolean needsRepaint = false; 1835 for (r = 0; r < records; r++) { 1836 int rowColor = ((Integer) 1837 rowColors.elementAt(r)).intValue(); 1838 if (rowColor != COLOR_NONE) { 1839 if (rowColor == 1) 1840 needsRepaint = true; 1841 isChanging = true; 1842 rowColors.setElementAt(new Integer(rowColor - 1), r); 1843 } 1844 } 1845 if (needsRepaint) 1846 repaint(); 1847 return isChanging; 1848 } 1849 1850 1851 /** 1852 * ... 1853 */ cancelSelect()1854 void cancelSelect() { 1855 cancelSelect = true; 1856 } 1857 } 1858