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