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 * ColumnList.java 31 * 32 * Copyright 1995-1996 Active Software Inc. 33 * 34 * @version @(#)ColumnList.java 1.62 97/05/02 35 * @author Tilman Sporkert 36 */ 37 38 package sunsoft.jws.visual.rt.awt; 39 40 import sunsoft.jws.visual.rt.awt.GBLayout; 41 import sunsoft.jws.visual.rt.awt.GBConstraints; 42 import sunsoft.jws.visual.rt.awt.VJScrollbar; 43 44 import java.awt.*; 45 import java.util.Vector; 46 47 /* BEGIN JSTYLED */ 48 /** 49 * A Widget to display data in a row/column fashion, 50 * with scrollbars etc. 51 * 52 * A ColumnList has the following features/attributes: 53 * headers: An array of Strings. The size of 54 * this array determines the number 55 * of columns in the list. There will be one additional, hidden 56 * column that can be used for any Object. 57 * The length of the header string defines the initial width of the 58 * column. To make it wider, add spaces to the end of the string. 59 * If a header field is of the form "name=header", then only the 60 * "header" part will actually be used for the visible header. 61 * The "name" part is available through 62 * getNames() or getNameColumn() 63 * selectable: If true, records can be selected 64 * with the mouse. A LIST_EVENT gets posted. 65 * editable: If true, records can be edited with the mouse. 66 * Columns 67 * containing a checkbox are currently the only editable columns. 68 * highlight_items: If true, new entries will be 69 * highlighted in orange, slowly 70 * fading out. 71 * showHeaders: If set to false, the headers will not be shown. 72 * 73 * 74 * @author Tilman Sporkert 75 */ 76 77 /* END JSTYLED */ 78 public class ColumnList extends ScrollPanel { 79 80 // Entry attributes 81 static final int HIGHLIGHT = 1; 82 83 ColumnListCanvas canvas; 84 String[] names = null; 85 boolean[] keys = null; 86 int[] sortColumns = null; // references names 87 int validSortColumns = 0; 88 // how many of them were actually recognized? 89 boolean[] sortAscend = null; 90 91 // event type for getting a chance to cancel the selection of a row 92 public final static int CONFIRM_SELECT = 4863; 93 94 // event type for applying an edit 95 public final static int APPLY_EDIT = 4864; 96 97 98 /** 99 * create a new ColumnList with no information 100 * about the columns 101 */ ColumnList()102 public ColumnList() { 103 add(canvas = new ColumnListCanvas(this)); 104 setCanvasBackground(Color.white); 105 } 106 107 108 /** 109 * create a new ColumnList, with the given columns, and 110 * given visible 111 * rows. 112 * 113 */ ColumnList(String[] headers, boolean selectable, boolean highlight_items)114 public ColumnList(String[] headers, 115 boolean selectable, 116 boolean highlight_items) { 117 this(); 118 setHeaders(headers); 119 // setFormat(format); 120 setSelectable(selectable); 121 setHighlightItems(highlight_items); 122 } 123 124 125 /** 126 * Sets the column to be editable or not. 127 * If a column is editable, then 128 * all the strings that are in the column will 129 * be able to be modified. 130 * 131 */ setTextEditable(int column, boolean value)132 public void setTextEditable(int column, boolean value) { 133 canvas.setTextEditable(column, value); 134 } 135 136 /** 137 * Sets all the columns to be editable or not. If a column is 138 * editable, then all the strings that are in the column will 139 * be able to be modified. 140 * 141 */ setTextEditable(boolean value)142 public void setTextEditable(boolean value) { 143 canvas.setTextEditable(value); 144 } 145 146 /** 147 * Gets the current value of the textEditable attribute. 148 * 149 */ getTextEditable(int column)150 public boolean getTextEditable(int column) { 151 return canvas.getTextEditable(column); 152 } 153 154 /** 155 * Call this when a CONFIRM_SELECT event is received if you 156 * don't want the selection to be changed. 157 */ cancelSelect()158 public void cancelSelect() { 159 canvas.cancelSelect(); 160 } 161 162 /** 163 * Call this to edit the given column of the 164 * currently selected row. 165 * 166 */ startEdit(int column)167 public boolean startEdit(int column) { 168 return canvas.startEdit(column); 169 } 170 171 /** 172 * Call this to force edits to be applied. 173 */ applyChanges()174 public boolean applyChanges() { 175 return canvas.applyChanges(); 176 } 177 178 /** 179 * Call this when a APPLY_EDIT event is received if you 180 * don't want the change to be applied. 181 */ cancelApply()182 public void cancelApply() { 183 canvas.cancelApply(); 184 } 185 186 /** 187 * Call this when you want to cancel any edit that might 188 * currently be going on. 189 */ cancelEdit()190 public void cancelEdit() { 191 canvas.cancelEdit(); 192 } 193 getEditRow()194 public int getEditRow() { 195 return canvas.getEditRow(); 196 } 197 getEditColumn()198 public int getEditColumn() { 199 return canvas.getEditColumn(); 200 } 201 202 /** 203 * Sets the foreground color. 204 * 205 */ setCanvasForeground(Color fg)206 public void setCanvasForeground(Color fg) { 207 canvas.setForeground(fg); 208 canvas.repaint(); 209 } 210 211 212 /** 213 * Gets the current foreground color. 214 * 215 * @return Color 216 */ getCanvasForeground()217 public Color getCanvasForeground() { 218 return canvas.getForeground(); 219 } 220 221 222 /** 223 * Sets the background color. 224 * 225 */ setCanvasBackground(Color fg)226 public void setCanvasBackground(Color fg) { 227 canvas.setBackground(fg); 228 canvas.repaint(); 229 } 230 231 232 /** 233 * Gets the current background color. 234 * 235 * @return Color 236 */ getCanvasBackground()237 public Color getCanvasBackground() { 238 return canvas.getBackground(); 239 } 240 241 242 /** 243 * Sets the font attribute. 244 * 245 */ setCanvasFont(Font font)246 public void setCanvasFont(Font font) { 247 canvas.setFont(font); 248 canvas.repaint(); 249 } 250 251 252 /** 253 * Gets the font attribute. 254 * 255 */ getCanvasFont()256 public Font getCanvasFont() { 257 return canvas.getFont(); 258 } 259 260 preferredSize()261 public Dimension preferredSize() { 262 Dimension d = super.preferredSize(); 263 // Do NOT account for hbar height as 264 // we want preferredSize height to accomodate 265 // just the header and visibleRow data exactly 266 d.height -= hbar.preferredSize().height; 267 return d; 268 } 269 270 /** 271 * Set the desired number of rows to be displayed. 272 * This affects the 273 * minimumSize() and preferredSize() of the widget. 274 * The actual rows 275 * displayed by the widget depend on how the 276 * LayoutManager interprets 277 * those values. 278 * 279 */ setVisibleRows(int rows)280 public void setVisibleRows(int rows) { 281 setDisplayRows(rows); 282 } 283 284 285 // for backward compatibility setDisplayRows(int rows)286 public void setDisplayRows(int rows) { 287 canvas.setDisplayRows(rows); 288 } 289 290 291 /** 292 * Set the desired number of "visible" chars, i.e. 293 * the total width of 294 * the column list. Defaults to "all". 295 * 296 */ setVisibleChars(int chars)297 public void setVisibleChars(int chars) { 298 canvas.setVisibleChars(chars); 299 } 300 301 302 /** 303 * Sets the header strings. 304 * 305 */ setHeaders(String[] headers)306 public void setHeaders(String[] headers) { 307 String[] realHeaders = null; 308 309 if (headers != null) { 310 realHeaders = new String[headers.length]; 311 names = new String[headers.length]; 312 keys = new boolean[headers.length]; 313 boolean hasKeys = false; 314 for (int h = 0; h < headers.length; h++) { 315 keys[h] = false; 316 int offset = headers[h].indexOf(/* NOI18N */ '='); 317 if (offset > 0) { 318 names[h] = headers[h].substring(0, offset); 319 if (names[h].charAt(0) == /* NOI18N */ '*') { 320 keys[h] = true; 321 hasKeys = true; 322 names[h] = headers[h].substring(1, offset); 323 } 324 realHeaders[h] = headers[h].substring( 325 offset + 1); 326 } else { 327 realHeaders[h] = headers[h]; 328 names[h] = headers[h]; 329 } 330 } 331 if (!hasKeys) 332 keys = null; 333 } else { 334 keys = null; 335 } 336 337 canvas.setHeaders(realHeaders); 338 } 339 340 /* BEGIN JSTYLED */ 341 /** 342 * Set the sort order. Input is an array of 343 column names, optionally 344 * preceded with a '+' for Ascend (default) 345 or '-' for descend. 346 * This call should be made after setHeaders(), and 347 before adding items. 348 * Items should only be added with addItem(Object[] entry). 349 * 350 * If any of the names supplied do not match a 351 column name, then 352 * they will be silently ignored. 353 * 354 */ 355 /* 356 * Fix for Sun Bug # 4069218: incorrect sortNames 357 * causes array out of bounds 358 * error on addItem(...). 359 * -> If name is not recognized (i.e. getNameColumn() returns -1), 360 * Then that entry is *silently* ignored. 361 * -> Later we may want to throw some kind of exception. 362 * 363 */ 364 /* END JSTYLED */ setSort(String[] sortNames)365 public void setSort(String[] sortNames) { 366 if (sortNames != null && sortNames.length > 0) { 367 sortColumns = new int[sortNames.length]; 368 sortAscend = new boolean[sortNames.length]; 369 int acceptedIndex = 0; 370 int nameColumn; 371 boolean ascend; 372 for (int c = 0; c < sortNames.length; c++) { 373 374 String colName = null; 375 if (sortNames[c].startsWith(/* NOI18N */"+")) { 376 ascend = true; 377 colName = sortNames[c].substring(1); 378 } else if (sortNames[c].startsWith(/* NOI18N */"-")) { 379 colName = sortNames[c].substring(1); 380 ascend = false; 381 } else { 382 ascend = true; 383 colName = sortNames[c]; 384 } 385 nameColumn = getNameColumn(colName); 386 if (nameColumn != -1) { 387 // only process if recognized. 388 acceptedIndex ++; 389 sortColumns[acceptedIndex-1] = nameColumn; 390 sortAscend[acceptedIndex-1] = ascend; 391 } 392 } 393 // Need to remember the actual number of accepted sort columns. 394 validSortColumns = acceptedIndex; 395 } else { 396 sortColumns = null; 397 validSortColumns = 0; 398 sortAscend = null; 399 } 400 } 401 402 403 404 /** 405 * set column formating. There is one letter for each column, with 406 * l = left, c = center, r = right 407 * 408 */ setFormats(String formatStr)409 public void setFormats(String formatStr) { 410 int[] format = new int[formatStr.length()]; 411 for (int c = 0; c < formatStr.length(); c++) { 412 int f = formatStr.charAt(c); 413 if (f == /* NOI18N */ 'c') 414 format[c] = Label.CENTER; 415 else if (f == /* NOI18N */ 'r') 416 format[c] = Label.RIGHT; 417 else 418 format[c] = Label.LEFT; // default 419 } 420 canvas.setFormats(format); 421 } 422 423 424 /** 425 * Sets the selectable attribute. 426 * 427 */ setSelectable(boolean selectable)428 public void setSelectable(boolean selectable) { 429 canvas.setSelectable(selectable); 430 } 431 432 433 /** 434 * Sets the editable attribute. 435 * 436 */ setEditable(boolean editable)437 public void setEditable(boolean editable) { 438 canvas.setEditable(editable); 439 } 440 441 442 /** 443 * Sets the hightLightItems attribute. 444 * 445 */ setHighlightItems(boolean highlight_items)446 public void setHighlightItems(boolean highlight_items) { 447 canvas.setHighlightItems(highlight_items); 448 } 449 setHighlighted(int row, boolean highlight)450 public void setHighlighted(int row, boolean highlight) { 451 canvas.setHighlighted(row, highlight); 452 } 453 getHighlighted(int row)454 public boolean getHighlighted(int row) { 455 return canvas.getHighlighted(row); 456 } 457 458 /** 459 * Sets the showHeaders attribute. 460 * 461 */ setShowHeaders(boolean showHeaders)462 public void setShowHeaders(boolean showHeaders) { 463 canvas.setShowHeaders(showHeaders); 464 } 465 466 467 /** 468 * Sets the showVerticalLines attribute. 469 * 470 */ setShowVerticalLines(boolean showVerticalLines)471 public void setShowVerticalLines(boolean showVerticalLines) { 472 canvas.setShowVerticalLines(showVerticalLines); 473 } 474 475 476 /** 477 * Sets the showHorizontalLines attribute. 478 * 479 */ setShowHorizontalLines(boolean showHorizontalLines)480 public void setShowHorizontalLines(boolean showHorizontalLines) { 481 canvas.setShowHorizontalLines(showHorizontalLines); 482 } 483 484 485 /** 486 * Sets the autoWidth attribute. 487 * 488 */ setAutoWidth(boolean autoWidth)489 public void setAutoWidth(boolean autoWidth) { 490 canvas.setAutoWidth(autoWidth); 491 } 492 493 494 /** 495 * Adds an item to the list. If the list has no 496 * keys defined, the item 497 * will be appended at the end of the list. 498 * Otherwise, the existing entries 499 * will be searched for an entry with the same key values. 500 * If there is 501 * such an entry, it will get replaced. Otherwise, the 502 * record goes at the 503 * end. 504 * 505 * @param values the record 506 * @param updateView whether to update the view 507 * @return index of new record 508 */ addItem(Object[] values, boolean updateView)509 public int addItem(Object[] values, boolean updateView) { 510 boolean setSelectedRow = false; 511 if (keys != null) { 512 for (int r = 0; r < entries(); r++) 513 if (isEqualTo(values, r)) { 514 // found a matching entry 515 if (sortColumns != null && validSortColumns > 0) { 516 // when sorting, take out the old one, and put the new 517 // one in at its proper place 518 if (getSelectedRow() == r) 519 setSelectedRow = true; 520 canvas.delItems(r, r); 521 break; 522 } 523 // no sorting -> just replace 524 canvas.addItem(values, r); 525 if (updateView) 526 updateView(); 527 return r; 528 } 529 } 530 if (sortColumns != null && validSortColumns > 0) { 531 for (int r = 0; r < entries(); r++) { 532 for (int c = 0; c < validSortColumns; c++) { 533 int colIndex = sortColumns[c]; 534 int comp = values[colIndex].toString().compareTo( 535 getItem(r, colIndex).toString()); 536 if (!sortAscend[c]) 537 comp = -comp; 538 if (comp < 0) { 539 canvas.insertItem(values, r); 540 if (setSelectedRow) 541 selectRow(r); 542 if (updateView) 543 updateView(); 544 return r; 545 } else if (comp > 0) 546 break; 547 } 548 } 549 } 550 canvas.addItem(values); 551 if (setSelectedRow) 552 selectRow(entries() - 1); 553 if (updateView) 554 updateView(); 555 return (entries() - 1); 556 } 557 558 559 /** 560 * Adds an item to the list. 561 * 562 */ addItem(Object[] values)563 public void addItem(Object[] values) { 564 addItem(values, true); 565 } 566 567 568 /** 569 * Compares a row to the specified values. 570 * 571 */ isEqualTo(Object[] values, int r)572 private boolean isEqualTo(Object[] values, int r) { 573 for (int c = 0; c < getColumns(); c++) { 574 if (keys[c]) { 575 if (!((String) getItem(r, c)).equals((String) values[c])) 576 return false; 577 } 578 } 579 return true; 580 } 581 582 583 /** 584 * Adds an item at a specific location. An existing record will be 585 * replaced. You should not use this method if you have sorting 586 * enabled! 587 * 588 */ addItem(Object[] values, int row)589 public void addItem(Object[] values, int row) { 590 canvas.addItem(values, row); 591 updateView(); 592 } 593 594 595 /** 596 * Insert a new item at a specific location. 597 * Existing records will be 598 * moved back. You should not use this method if you have sorting 599 * enabled! 600 * 601 */ insertItem(Object[] values, int row)602 public void insertItem(Object[] values, int row) { 603 canvas.insertItem(values, row); 604 updateView(); 605 } 606 607 608 /** 609 * Deletes the items. 610 */ delItems()611 public void delItems() { 612 delItems(true); 613 } 614 delItems(boolean updateView)615 public void delItems(boolean updateView) { 616 canvas.delItems(); 617 if (updateView) 618 updateView(); 619 } 620 621 622 /** 623 * Delete the items. 624 * 625 */ delItems(int start, int end)626 public void delItems(int start, int end) { 627 canvas.delItems(start, end); 628 updateView(); 629 } 630 631 632 /** 633 * Delete an item. 634 * 635 */ delItem(Object[] values)636 public boolean delItem(Object[] values) { 637 if (keys != null) { 638 for (int r = 0; r < entries(); r++) 639 if (isEqualTo(values, r)) { 640 canvas.delItems(r, r); 641 updateView(); 642 return true; 643 } 644 } 645 return false; 646 } 647 648 649 /** 650 * Select a row. 651 * 652 */ selectRow(int row)653 public int selectRow(int row) { 654 return canvas.selectRow(row); 655 } 656 657 // for backwards compatibility highlight(int row)658 public void highlight(int row) { 659 canvas.selectRow(row); 660 } 661 662 /** 663 * Gets the selectedRow attribute. 664 */ getSelectedRow()665 public int getSelectedRow() { 666 return canvas.selectedRow; 667 } 668 getHighlightedRow()669 public int getHighlightedRow() { 670 return canvas.getSelectedRow(); 671 } 672 673 /** 674 * Gets the bounds. 675 */ getListBounds()676 public Rectangle getListBounds() { 677 return canvas.bounds(); 678 } 679 680 681 /** 682 * Gets the entries. 683 */ entries()684 public int entries() { 685 return canvas.records; 686 } 687 688 689 /** 690 * Gets the columns. 691 */ getColumns()692 public int getColumns() { 693 return canvas.columns; 694 } 695 696 697 /** 698 * Gets the names of all the columns. 699 */ getNames()700 public String[] getNames() { 701 return names; 702 } 703 704 705 /** 706 * Gets the column with the specified name. 707 * 708 */ getNameColumn(String name)709 public int getNameColumn(String name) { 710 for (int n = 0; n < names.length; n++) 711 if (names[n].equals(name)) 712 return n; 713 return -1; 714 } 715 716 717 /** 718 * Gets an item in the specified row and column. 719 * 720 */ getItem(int row, int column)721 public Object getItem(int row, int column) { 722 return canvas.getItem(row, column); 723 } 724 725 726 /** 727 * Gets the "Object" for a row. 728 * 729 */ getObject(int row)730 public Object getObject(int row) { 731 return canvas.getItem(row, canvas.columns); 732 } 733 734 /** 735 * Puts an item at a specific row/column location. 736 * Warning: If you are changing the value of a 737 * key column, another record 738 * that matches your keys will get deleted. 739 * If you are changing 740 * the value of a sort column, your record 741 * might get moved to a 742 * new position. 743 * The function returns the new row index. 744 * 745 */ putItem(int row, int column, Object value)746 public int putItem(int row, int column, Object value) { 747 Object oldValue = getItem(row, column); 748 if (!canvas.putItem(row, column, value)) 749 return -1; 750 751 // skip the checks if value didn't change (but not when value isn't 752 // representable as a string, for example hwhen an icon has no label) 753 if (value.toString() != null && 754 value.toString().equals(oldValue.toString())) 755 return row; 756 757 boolean setSelectedRow = false; 758 if (getSelectedRow() == row) 759 setSelectedRow = true; 760 761 // did we update a key column? 762 if (keys != null && keys.length > column && keys[column]) { 763 Object[] values = (Object []) canvas.labels.elementAt(row); 764 for (int r = 0; r < entries(); r++) 765 if (r != row && isEqualTo(values, r)) { 766 // found a matching entry at a different location 767 canvas.delItems(r, r); 768 if (r < row) 769 row--; // we just moved down one entry 770 break; 771 } 772 } 773 if (isSortColumn(column)) { 774 Object[] values = (Object []) canvas.labels.elementAt(row); 775 for (int r = 0; r < entries(); r++) { 776 for (int c = 0; c < sortColumns.length; c++) { 777 int colIndex = sortColumns[c]; 778 int comp = values[colIndex].toString().compareTo( 779 getItem(r, colIndex).toString()); 780 if (!sortAscend[c]) 781 comp = -comp; 782 if (comp < 0) { 783 if (r != row && r != row + 1) { 784 swapItems(r, row); 785 row = r; 786 } 787 if (setSelectedRow) 788 selectRow(row); 789 return row; 790 } else if (comp > 0) 791 break; 792 } 793 } 794 } 795 if (setSelectedRow) 796 selectRow(row); 797 return row; 798 } 799 800 isSortColumn(int column)801 private boolean isSortColumn(int column) { 802 if (sortColumns == null) 803 return false; 804 for (int c = 0; c < validSortColumns; c++) 805 if (sortColumns[c] == column) 806 return true; 807 return false; 808 } 809 810 811 /** 812 * Sets the object for a row 813 * 814 */ putObject(int row, Object value)815 public boolean putObject(int row, Object value) { 816 return canvas.putItem(row, canvas.columns, value); 817 } 818 819 820 /** 821 * Swaps the entries in two rows 822 * 823 */ swapItems(int row1, int row2)824 public boolean swapItems(int row1, int row2) { 825 return canvas.swapItems(row1, row2); 826 } 827 828 829 /** 830 * Gets the Y coordinate of the upper edge of a 831 * row in the column list. 832 * Returns -1 if the row is not visible. Returns -2 is the list is 833 * not layed out yet. 834 * 835 * @param row index of desired row 836 * @return Y coordinage of row 837 */ getRowY(int row)838 public int getRowY(int row) { 839 return canvas.getRowY(row); 840 } 841 842 843 /** 844 * Gets the row height of entries in the list 845 * 846 * @return height of a row 847 */ getRowHeight()848 public int getRowHeight() { 849 return canvas.rowHeight; 850 } 851 852 853 /** 854 * Calls repaint() on the ColumnListCanvas. Needed 855 * if an Object in the 856 * column list has been changed directly(without going through 857 * putItem). 858 */ needsRepaint()859 public void needsRepaint() { 860 canvas.repaint(); 861 } 862 863 864 /** 865 * Redraws everything, and re-evaluates the need for scroll bars 866 */ updateView()867 public void updateView() { 868 canvas.repaint(); 869 updateWindow(); 870 } 871 setHBarValue(int value)872 void setHBarValue(int value) { 873 hbar.setValue(value); 874 } 875 setVBarValue(int value)876 void setVBarValue(int value) { 877 vbar.setValue(value); 878 } 879 changeText(String text, int row, int column)880 public void changeText(String text, int row, int column) { 881 canvas.changeText(text, row, column); 882 } 883 } 884