xref: /titanic_41/usr/src/cmd/krb5/kadmin/gui/visualrt/sunsoft/jws/visual/rt/awt/ColumnList.java (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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