ColumnListCanvas.java revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* ident "%Z%%M% %I% %E% SMI"
*
* Copyright (c) 2000 by Sun Microsystems, Inc.
* All rights reserved.
*/
/**
*
* Copyright 1995-1996 Active Software Inc.
*
* @version @(#)ColumnListCanvas.java 1.93 97/07/25
* @author Tilman Sporkert
*/
/**
* An internal widget for the ColumnList widget
*
* @author Tilman Sporkert
*/
// Padding
final static int LEFT_PAD = 4;
final static int RIGHT_PAD = 4;
// Editing
private CLChoice editchoice;
private boolean justCancelled;
private int editrow = -1;
private int editcolumn = -1;
private boolean[] textEditable;
private boolean applying;
private boolean cancelApply;
// double-buffering
private Dimension bufferSize;
int columns; // # of data columns
// there are actual columns + 1 columns managed
// but only columns are visible. The last
// column can be accessed only by addItem(),
// getItem(), and putItem(), and can be used to
// manage a random object together with the
// data row
int charWidth;
int rowHeight; // height of data row
int componentHeight = 0;
// height of largest component in list
int rowAscent;
int headerHeight;
int totalWidth; // total width of all colums
boolean dragging = false; // for resizing columns
int dragStart; // x position where drag started
int dragColumn; // which column is getting resized?
boolean showHeaders = true;
boolean showVerticalLines = false;
boolean showHorizontalLines = false;
int[] dimensions; // the dimensions of the headers
boolean autoWidth = true; // automatically expand columns to fit?
int records; // # of active records
int requestedChars = 0;
// request # of chars to display horizontally
int dispRows; // # of rows to show
int visibleRows = -1;
// this can be one more than dispRows
int scrollx = 0;
int scrollrow = 0;
int scrolly = 0;
// the selection
boolean highlightItems = false; // highlight new items?
boolean selectable = false;
int selectedRow = -1;
boolean editable = true;
// flag to track if the selection change has been canceled
private boolean cancelSelect;
private final static int COLOR_NONE = 0;
private final static int COLOR_FIRST = 4;
/**
* create a new ColumnListCanvas. Before it can be used
* in any reasonable fashion, setHeaders() should
* be called, followed
* by an optional call to setFormat()!
*
* @param parent The parent ColumnList
*/
columns = 0;
dimensions = null;
dispRows = 0;
records = 0;
}
public void setTextEditable(boolean value) {
textEditable[i] = value;
}
return;
}
public boolean getTextEditable(int column) {
return false;
return textEditable[column];
}
return new boolean[length];
}
return arr;
}
public void cancelApply() {
cancelApply = true;
}
public synchronized void cancelEdit() {
justCancelled = true;
} else {
editchoice = null;
justCancelled = true;
}
editrow = -1;
editcolumn = -1;
repaint();
}
}
public int getEditRow() {
return editrow;
}
public int getEditColumn() {
return editcolumn;
}
public boolean applyChanges() {
if (editchoice != null) {
cancelEdit();
return true;
return !cancelApply;
} else {
return true;
}
}
}
if (editchoice != null)
return false;
return false;
return false;
if (!getTextEditable(column))
return false;
int row = getSelectedRow();
if (row == -1)
return false;
editcolumn = column;
copyBuffer();
if (!choice.getEditable())
return false;
editchoice = choice;
editcolumn = column;
} else if (entry instanceof CLComponent) {
if (!comp.getEditable())
return false;
if (x != -1 && x < textX)
return false;
editcolumn = column;
copyBuffer();
}
}
selectRow(-1);
return true;
} else if (editchoice != null) {
return true;
} else {
return false;
}
}
int x = -scrollx;
for (int i = 0; i < column; i++)
x += dimensions[i];
x += LEFT_PAD;
x += width - w;
x += (width - w) / 2;
}
return x;
}
+ rowAscent;
}
/**
* ...
*
* @param ... ...
* @return ...
* @exception ...
*/
protected void finalize() {
if (colorThread != null)
colorThread.stop();
}
/**
* set the headers for the columns. THis also defines the
* # of columns. If the # of header columns
* changes, all current rows
* will be deleted, and the formatting options get reset
*
* @param headersIn array of column headers
*/
int newColumns;
newColumns = 0;
else
if (newColumns != columns) {
// # of columns change -> get rid of everything
delItems();
dimensions = null;
}
columns = 0;
else
dimensions = null;
repaint();
}
/**
* ...
*
* @param ... ...
* @return ...
* @exception ...
*/
public void setFormats(int[] formatIn) {
}
/**
* ...
*
* @param ... ...
* @return ...
* @exception ...
*/
else
}
/**
* ...
*
* @param ... ...
* @return ...
* @exception ...
*/
public void setSelectable(boolean selectable) {
this.selectable = selectable;
}
public void setEditable(boolean editable_in) {
}
/**
* ...
*
* @param ... ...
* @return ...
* @exception ...
*/
public void setHighlightItems(boolean highlightItems) {
this.highlightItems = highlightItems;
}
return;
if (highlight) {
if (highlightItems == true) {
if (colorThread == null) {
colorThread = new ColumnListThread(this);
colorThread.start();
} else {
}
}
} else {
}
}
public boolean getHighlighted(int row) {
return false;
return (rowColor != COLOR_NONE);
}
/**
* ...
*
* @param ... ...
* @return ...
* @exception ...
*/
public void setShowHeaders(boolean showHeaders) {
this.showHeaders = showHeaders;
repaint();
}
/**
* ...
*
* @param ... ...
* @return ...
* @exception ...
*/
public void setShowVerticalLines(boolean showVerticalLines) {
this.showVerticalLines = showVerticalLines;
repaint();
}
/**
* ...
*
* @param ... ...
* @return ...
* @exception ...
*/
public void setShowHorizontalLines(boolean showHorizontalLines) {
repaint();
}
/**
* ...
*
* @param ... ...
* @return ...
* @exception ...
*/
public void setAutoWidth(boolean autoWidth) {
}
// Scrollable
/**
* ...
*
* @param ... ...
* @return ...
* @exception ...
*/
public void scrollX(int x) {
if (scrollApply()) {
scrollx = x;
repaint();
} else {
}
}
/**
* Scroll vertically to y. Part of Scrollabel interface.
*
* @param y new vertical scroll position
*/
public void scrollY(int y) {
if (scrollApply()) {
scrolly = y;
if (rowHeight != 0)
else
scrollrow = 0;
repaint();
} else {
}
}
private boolean scrollApply() {
boolean status = true;
if (!applying) {
applying = true;
status = applyChanges();
// The Motif scrollbar gets locked down
// when a modal dialog is
// brought up while scrolling. To prevent getting infinite
// errors, we will cancel the edit here.
cancelEdit();
applying = false;
}
return status;
}
public Dimension scrollSize() {
if (dimensions == null)
else
}
return size;
}
/**
* ...
*
* @param ... ...
* @return ...
* @exception ...
*/
public int lineHeight() {
return rowHeight;
}
private synchronized void addMoreLabels() {
int c;
// have one extra for the "hidden" object
for (c = 0; c < columns; c++)
}
private void ensureCapacity(int row) {
}
private void growRecords(int row) {
// initialize all intermediate records
for (int c = 0; c < columns; c++)
records++;
}
}
/**
* ...
*
* @param ... ...
* @return ...
* @exception ...
*/
int c;
boolean newWidth = false;
// make sure we have enough labels...
// Make one extra entry
// Move other rows out of the way
}
for (c = 0; c < columns; c++)
// Fix selected row
if (selectedRow >= row)
++selectedRow;
// Call addItem to replace things
}
/**
* ...
*
* @param ... ...
* @return ...
* @exception ...
*/
}
/**
* ...
*
* @param ... ...
* @return ...
* @exception ...
*/
// make sure we have enough labels...
if (autoWidth)
for (int c = 0; c < columns; c++) {
if (values[c] instanceof CLComponent)
checkComponentCell(values[c]);
}
else
if (highlightItems == true) {
if (colorThread == null) {
colorThread = new ColumnListThread(this);
colorThread.start();
} else
} else
records++;
}
/**
* Adjust the widths of the columns for 'row' to make sure
* everything
* fits properly. If autoWidth is false, then this
* function has no effect
*
* @param row row number
*/
private void adjustColumnWidths(int row) {
return;
for (int c = 0; c < columns; c++)
adjustColumnWidths(labelRow[c], c);
}
/**
* If autoWidth is enabled, make sure "value" fits
* into the given column.
*
* @param value the value to be checked
* @param column column number
*/
return;
int w = labelWidth(value);
if (w > usableWidth) {
totalWidth += w - usableWidth;
}
}
/**
* If the object (to be put into a cell) is an AWT component, make
* sure it gets properly managed in the layout, and
* that the rows are
* high enough to hold it.
*
* @param ... ...
* @return ...
* @exception ...
*/
if (hasComponents == null)
if (componentHeight > rowHeight) {
}
}
}
}
/**
* ...
*
* @param ... ...
* @return ...
* @exception ...
*/
public synchronized void delItems() {
selectedRow = -1;
}
/**
* ...
*
* @param ... ...
* @return ...
* @exception ...
*/
return;
return;
int r, c;
for (c = 0; c < columns; c++) {
else if (labelRow[c] instanceof CLComponent)
}
}
if (selectedRow > end)
selectedRow -= diff;
else if (selectedRow > start)
// repaint all the time... could be optimized
repaint();
}
/**
* ...
*
* @param ... ...
* @return ...
* @exception ...
*/
(column < 0))
return null;
}
/**
* ...
*
* @param ... ...
* @return ...
* @exception ...
*/
(column < 0))
return false;
if (value instanceof CLComponent)
// don't do this on objects in the hidden column
}
repaint();
return true;
}
/**
* ...
*
* @param ... ...
* @return ...
* @exception ...
*/
(row2 < 0))
return false;
return true;
repaint();
return true;
}
if (w <= 0)
return /* NOI18N */"";
return text;
else
}
return lower;
return upper;
else
return lower;
}
return cur;
else
}
// drawString - calls g.drawString(str, x, y), but
// makes sure that str
// will fit into width
if (w <= 0)
return;
x += width - w;
x += (width - w) / 2;
g.drawString(str, x, y);
}
public FontMetrics getFontMetrics() {
return getFontMetrics(getFont());
}
/**
* ...
*
* @param ... ...
* @return ...
* @exception ...
*/
dimensions = null;
}
/**
* ...
*
* @param ... ...
* @return ...
* @exception ...
*/
paint(g);
}
/**
* Determines the width a label item needs.
*
* @param ... ...
* @return ...
* @exception ...
*/
return (0);
Graphics g = getBufferGraphics();
} else if (item instanceof CLComponent) {
if (s != null)
return s.width;
else
return 0;
} else {
return 0;
}
}
/**
* ...
*
* @param ... ...
* @return ...
* @exception ...
*/
private void cacheDimensions() {
if (dimensions != null)
return;
Graphics g = getBufferGraphics();
if (g == null)
return;
// figure out rowHeight (must be done before labelWidth is
// ever called, because CLComponent width calculation depends
// on rowHeight)
rowHeight++;
rowHeight--;
if (rowHeight < componentHeight) {
}
if (showHeaders)
else
headerHeight = 0;
// figure out column widths
totalWidth = 0;
for (int c = 0; c < columns; c++) {
// base size of columns on header string
if (autoWidth) {
// column should be the width of the widest data item
for (int r = 0; r < records; r++) {
}
}
dimensions[c] = width;
totalWidth += dimensions[c];
}
}
g = getGraphics();
}
g = buffer.getGraphics();
// first time? get the dimensions of the header panel
// how many rows fit?
// visibleRows can be one more than
// dispRows (last row partially visible)
// make sure we have enough labels...
int vertOffset = scrollrow;
g.setColor(getForeground());
// draw the column headers
int x = 0;
int colWidth;
if (showHeaders) {
for (int c = 0; c <= columns; c++) {
if (c == columns)
// last column fills up the rest
else
colWidth = dimensions[c];
// is the column for real, and some of it visible?
(left < usableWidth))) {
// now draw the thing...
g.setColor(getBackground());
headerHeight - 2);
// last column has no strings
if (c != columns)
headerHeight - 5,
getFormat(c));
}
if (c != columns)
x += dimensions[c];
}
}
// now paint the data
int y = headerHeight;
if ((r >= vertOffset) && (r <
(visibleRows + vertOffset))) {
x = 0;
intValue();
for (int c = 0; c < columns; c++) {
colWidth = dimensions[c];
// is the column for real, and some of it visible?
if ((colWidth > 0) &&
y + rowAscent,
getFormat(c));
else if (row[c] instanceof CLComponent)
getFormat(c));
// cb.validate();
} else
getFormat(c));
} else {
}
}
x += dimensions[c];
}
y += rowHeight;
if (showHorizontalLines) {
}
} else {
}
} // for each row
if (showVerticalLines) {
x = 0;
for (int c = 0; c < columns; c++) {
colWidth = dimensions[c];
// only draw if the line would be visible
if (right > usableWidth)
break;
x += dimensions[c];
}
}
copyBuffer();
}
// WORK-AROUND: sometimes size() calls return
// dimensions of 0 for width
// or height when they probably shouldn't
// (this is on Win95), and it
// causes an illegal argument exception in
// the createImage call below
else
}
// end of WORK-AROUND
}
bufferSize = size;
}
return buffer;
}
private Graphics getBufferGraphics() {
return null;
else
return buffer.getGraphics();
}
private void copyBuffer() {
Graphics g = getGraphics();
}
for (int i = 0; i < 3; i++) {
if (bufferSizeCache[i] != null &&
buffer = bufferCache[i];
bufferSize = bufferSizeCache[i];
break;
}
}
}
return;
int i;
for (i = 0; i < 3; i++) {
if (bufferSizeCache[i] == null)
break;
}
if (i < 3) {
bufferCache[i] = buffer;
} else {
}
}
/**
* ...
*
* @param ... ...
* @return ...
* @exception ...
*/
if (row == selectedRow)
return getBackground();
else
return origColor;
}
if (row == selectedRow) {
if (rowColor != COLOR_NONE)
else
return selectColor.darker();
else
return selectColor;
} else {
if (rowColor != COLOR_NONE)
else
else
return getBackground();
}
}
private boolean rowVisible(int row) {
}
public void updateView() {
parent.updateView();
}
/**
* @see sunsoft.jws.visual.designer.gui.ColumnList
*/
public void setDisplayRows(int rows) {
}
public void setVisibleChars(int chars) {
}
/**
* the minimum width is enough to fully display
* the first column, but not
* more than 200 pixels. The minimum height is the
* height to display the
* number of rows requested with setDisplayRows() (default is 3)
*
* @return Dimension
*/
public Dimension minimumSize() {
return preferredSize();
}
/**
* Calculate the preferred size. Standard AWT function.
*
* @return the preferred size of the ColumnListCanvas
*/
public Dimension preferredSize() {
if (dimensions == null)
else
if (requestedChars == 0)
return new Dimension(totalWidth,
else
}
/**
* select row, and make it visible
* only one row can be selected at a time - previously selected
* rows will be restored to normal
* to remove the selection, set the selected row to -1
*
* @param row index of row
* @return actual index of selected row, -1 if none
*/
if (selectedRow != row) {
int oldSelectedRow = selectedRow;
selectedRow = row;
else
selectedRow = -1;
// make sure we can see the new selection
// Tilman 05/21: Not tested if the makeVisible() call works
// repaint if anything is visible
repaint();
}
return selectedRow;
}
/**
* Get the index of the currently selected row
*
* @return index of selected row, -1 if none is selected
*/
public int getSelectedRow() {
return selectedRow;
}
/**
* ...
*
* @param ... ...
* @return ...
* @exception ...
*/
return -2;
if (rowVisible(row)) {
} else
return -1;
}
/**
* ...
*
* @param ... ...
* @return ...
* @exception ...
*/
int x = -scrollx;
for (int c = 0; c < columns; c++) {
x += dimensions[c];
dragColumn = c;
dragging = true;
break;
}
}
}
/**
* ...
*
* @param ... ...
* @return ...
* @exception ...
*/
private synchronized int mouseColumn(int mouseX) {
int x = -scrollx;
if (mouseX < x)
return -1;
for (int c = 0; c < columns; c++) {
x += dimensions[c];
if (mouseX < x)
return c;
}
return -1;
}
/**
* ...
*
* @param ... ...
* @return ...
* @exception ...
*/
private synchronized void dragColumn(int dragX) {
totalWidth += diff;
repaint();
}
}
//
// Workaround for an AWT bug on Windows95
// where we get a spurious
// mouse down event when the CLChoice menu is
// unmapped as the result
// of selection being made from a mouse down
// event inside the menu.
//
justCancelled = false;
return true;
}
justCancelled = false;
return true;
return true;
} else {
copyBuffer();
}
cancelApply = false;
if (!cancelApply) {
cancelEdit();
}
cancelEdit();
cancelApply = false;
if (!cancelApply) {
cancelEdit();
}
} else {
return super.handleEvent(evt);
}
return true;
}
int column) {
return;
parent.updateView();
} else if (item instanceof CLComponent) {
}
}
int x = -scrollx;
for (int c = 0; c < column; c++)
x += dimensions[c];
return x;
}
public int columnWidth(int column) {
return dimensions[column];
}
}
return rowHeight;
}
if (!applyChanges())
return false;
selectRow(-1);
} else if (editchoice != null) {
cancelEdit();
selectRow(-1);
}
if (y > headerHeight) {
int column = mouseColumn(x);
if (column != -1) {
return true;
}
}
if (selectable) {
cancelSelect = false;
if (e.clickCount == 1) {
if (row == getSelectedRow() &&
cancelEdit();
return true;
} else {
// Should make a beeping or
// clicking noise somehow.
}
}
if (!cancelSelect) {
}
} else if (e.clickCount == 2) {
}
}
}
} else if (y < headerHeight) {
startDrag(x);
}
return true;
}
/**
* ...
*
* @param ... ...
* @return ...
* @exception ...
*/
if (dragging) {
dragColumn(x);
return true;
}
return false;
}
/**
* ...
*
* @param ... ...
* @return ...
* @exception ...
*/
if (dragging) {
dragging = false;
parent.updateView();
return true;
}
return false;
}
boolean resizeCursor = false;
boolean checkedFrame = false;
if (!checkedFrame) {
checkedFrame = true;
while (c != null) {
if (c instanceof Frame) {
break;
} else
c = c.getParent();
}
}
}
return ourFrame;
}
boolean resizable = false;
if (y < headerHeight) {
for (int c = 0; c < columns; c++) {
x1 += dimensions[c];
resizable = true;
break;
}
}
}
if (resizable != resizeCursor) {
if (resizable)
else
}
return true;
} else
return false;
}
/**
* restore the cursor when exiting
*
* @param ... ...
* @return ...
*/
if (resizeCursor) {
resizeCursor = false;
}
return false;
}
/**
* ...
*
* @return ...
*/
public synchronized boolean updateRowColors() {
int r;
boolean isChanging = false;
boolean needsRepaint = false;
for (r = 0; r < records; r++) {
if (rowColor != COLOR_NONE) {
if (rowColor == 1)
needsRepaint = true;
isChanging = true;
}
}
if (needsRepaint)
repaint();
return isChanging;
}
/**
* ...
*/
void cancelSelect() {
cancelSelect = true;
}
}