// Copyright 1996, Marimba Inc. All Rights Reserved.


// @(#)SparseTableWidget.java, 1.16, 12/19/96





package marimba.gui;





import java.awt.*;


import java.util.*;





import marimba.persist.*;


import marimba.io.*;








/**


 * Sparse multi-column table widget.


 * This means that the content does not draw the data that is


 * not visible. This is done by using the method getData.


 * This method returns the rows and columns that the content


 * asks for.


 *


 * IMPORTANT: to make this possible every row has the same height!


 *


 * You can also use this sparse table for displaying your own


 * data without using widgets all the time, by setting the number


 * of rows and columns manually and overriding getData in your


 * subclass.


 *


 * @see #getData


 * @see SparseTableContent


 *


 * @author	Klaas Waslander


 * @version 	1.16, 12/19/96


 */ 


public class SparseTableWidget extends TableWidget {


    final static int  defaultRowHeight = 25;





    /**


     * The height of every row.


     * @see #getRowHeight


     * @see #setRowHeight


     */


    public int  rowHeight = defaultRowHeight;








    /**


     * Get the properties of a sparse table.


     */


    public void getProperties(PropertyList list) {


	super.getProperties(list);


	list.setInteger("rowHeight", rowHeight, defaultRowHeight);


    }





    /**


     * Set the properties of a sparse table.


     */


    public void setProperties(PropertyList list) {


	super.setProperties(list);


	rowHeight = Math.max(1, list.getInteger("rowHeight", defaultRowHeight));


    }





    /**


     * Get the height of a row.


     * @see #rowHeight


     */


    public int getRowHeight() {


	return rowHeight;


    }





    /**


     * Set the height of every row to the given number of pixels.


     * @see #rowHeight


     */


    public void setRowHeight(int rowHeight) {


	// do nothing if the given rowHeight is invalid


	if (rowHeight < 0) {


	    paramError("setRowHeight(int)","rowHeight must be greater than zero");


	    return;


	}





	this.rowHeight = rowHeight;


    }





    /**


     * Allocate a sparse content container.


     */


    public Widget newContent() {


	SparseTableContent  result = new SparseTableContent();


	result.lineMode = LOWERED;


	return result;


    }





    /**


     * Get the data for the specified rows and columns, using the display


     * index of the rows and column.


     * Returns an array with for every row a Vector with strings or Widgets.


     *


     * SparseTableContent uses this method as a callback function to get


     * the appropriate data for the current table view.


     *


     * If you want to return your own data in a subclass of sparse table,


     * make sure to fill the rowMap array with the appropriate actual and


     * display index for every row to make sorting possible.


     *


     * @see SparseTableContent


     */


    public synchronized Vector[] getData(int firstRow, int lastRow, int firstCol, int lastCol) {


	// System.out.println("SPARSETABLE - getData("+firstRow+","+lastRow+","+firstCol+","+lastCol+")");





	// do nothing if one of the parameters is incorrect


	if (firstRow < 0 || firstRow > lastRow || (rowCount > 0 && lastRow >= rowCount) ||


		firstCol < 0 || firstCol > lastCol || (columnCount > 0 && lastCol >= columnCount)) {


	    paramError("getData(int,int,int,int)", "invalid row and column area specified: ("+firstRow+","+lastRow+","+firstCol+","+lastCol+")");





	    // return error strings for every cell


	    Vector[]  errorResult = new Vector[lastRow-firstRow+1];


	    for (int rowNumber = firstRow; rowNumber <= lastRow; rowNumber++) {


		Vector  newRow = new Vector();


		errorResult[rowNumber - firstRow] = newRow;


		for (int colNumber = 0; colNumber < columnCount; colNumber++) {


		    newRow.addElement("getData ERROR");


		}


	    }


	    return  errorResult;


	}





	Vector[]  result = new Vector[lastRow-firstRow+1];


	for (int rowNumber = firstRow; rowNumber <= lastRow; rowNumber++) {


	    Vector  rowData = getRowData(getRowIndex(rowNumber));


	    Vector  rowView = new Vector();


	    for (int colNumber = firstCol; colNumber < rowData.size() && colNumber <= lastCol; colNumber++) {


		rowView.addElement(rowData.elementAt(getColumnIndex(colNumber)));


	    }


	    result[rowNumber-firstRow] = rowView;


	}


	return result;


    }





    /**


     * Focus the content at the row with the given actual index.


     */


    public void focusAtRow(int rowIndex) {


	if (rowIndex < 0 || rowIndex >= rowCount) {


	    paramError("focusAtRow(int)","invalid row index specified");


	    return;


	}


	int  rowPos = rowIndex * (rowHeight + rowPadding * 2);


	focusContent(-content.tx, rowPos, 1, rowHeight + rowPadding * 2 + 2);


    }





    /**


     * Flush the content's cache when sorting.


     */


    public void sortOnColumnAt(int colIndex, int mode) {


	((SparseTableContent)content).flush();


	super.sortOnColumnAt(colIndex, mode);


    }





    /**


     * Flush the content's cache when switching columns.


     */


    public void switchColumns(int colIndex1, int colIndex2) {


	((SparseTableContent)content).flush();


	super.switchColumns(colIndex1, colIndex2);


    }





    /**


     * Flush the content's cache when unsorting.


     */


    public void unSort() {


	((SparseTableContent)content).flush();


	super.unSort();


    }


}


