/* | |
* Copyright 2012 AndroidPlot.com | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
package com.androidplot.ui; | |
import android.graphics.RectF; | |
import java.util.Iterator; | |
/** | |
* Encapsulates the visual aspects of a table; number of rows and columns | |
* and the height and width in pixels of each element within the table. | |
* There is no support (yet) for variable size cells within a table; all | |
* cells within a table share the same dimensions. | |
* | |
* The DynamicTableModel provides an Iterator implementation which returns a RectF | |
* of each subsequent cell, based on the order of the plot. Tables with | |
* an order of COLUMN_MAJOR are traversed left to right column by column until | |
* the end of the row is reached, then proceeding to the next row. | |
* Tables with an order of ROW_MAJOR are traversed top to bottom row by row | |
* until the end of the row is reached, then proceeding to the next column. | |
*/ | |
public class DynamicTableModel extends TableModel { | |
//private float cellWidth; | |
//private float cellHeight; | |
//private TableSizingMethod rowSizingMethod; | |
//private TableSizingMethod columnSizingMethod; | |
private int numRows; | |
private int numColumns; | |
private Float cellWidth; | |
private Float cellHeight; | |
private CellSizingMethod rowSizingMethod; | |
private CellSizingMethod columnSizingMethod; | |
/** | |
* Convenience method. Sets order to ROW_MAJOR. | |
* @param numColumns | |
* @param numRows | |
*/ | |
public DynamicTableModel(int numColumns, int numRows) { | |
this(numColumns, numRows, TableOrder.ROW_MAJOR); | |
} | |
public DynamicTableModel(int numColumns, int numRows, TableOrder order) { | |
super(order); | |
this.numColumns = numColumns; | |
//this.cellWidth = cellWidth; | |
//this.rowSizingMethod = rowSizingMethod; | |
this.numRows = numRows; | |
//this.cellHeight = cellHeight; | |
//this.columnSizingMethod = columnSizingMethod; | |
//this.order = order; | |
} | |
/*public DynamicTableModel(Number colVal, CellSizingMethod colSzMethod, Number rowVal, CellSizingMethod rowSzMethod, TableOrder order) { | |
if(colVal == null || rowVal == null) { | |
throw new NullPointerException(); | |
} | |
columnSizingMethod = colSzMethod; | |
switch(columnSizingMethod) { | |
case FILL: | |
numColumns = colVal.intValue(); | |
break; | |
case FIXED: | |
cellWidth = colVal.floatValue(); | |
break; | |
} | |
rowSzMethod = rowSzMethod; | |
}*/ | |
@Override | |
public TableModelIterator getIterator(RectF tableRect, int totalElements) { | |
return new TableModelIterator(this, tableRect, totalElements); | |
} | |
/** | |
* Calculates the dimensions of a single element of this table with | |
* tableRect representing the overall dimensions of the table. | |
* @param tableRect Dimensions/position of the table | |
* @return a RectF representing the first (top-left) element in | |
* the tableRect passed in. | |
*/ | |
public RectF getCellRect(RectF tableRect, int numElements) { | |
RectF cellRect = new RectF(); | |
cellRect.left = tableRect.left; | |
cellRect.top = tableRect.top; | |
//cellRect.bottom = getElementHeightPix(tableRect); | |
cellRect.bottom = tableRect.top + calculateCellSize(tableRect, TableModel.Axis.ROW, numElements); | |
//cellRect.right = getElementWidthPix(tableRect); | |
cellRect.right = tableRect.left + calculateCellSize(tableRect, TableModel.Axis.COLUMN, numElements); | |
return cellRect; | |
} | |
/** | |
* Figure out the size of a single cell across the specified axis. | |
* @param tableRect | |
* @param axis | |
* @param numElementsInTable | |
* @return | |
*/ | |
private float calculateCellSize(RectF tableRect, | |
Axis axis, | |
int numElementsInTable) { | |
//float elementSizeInPix = 0; | |
int axisElements = 0; | |
float axisSizePix = 0; | |
switch (axis) { | |
case ROW: | |
//elementSizeInPix = cellHeight; | |
axisElements = numRows; | |
axisSizePix = tableRect.height(); | |
break; | |
case COLUMN: | |
//elementSizeInPix = cellWidth; | |
axisElements = numColumns; | |
axisSizePix = tableRect.width(); | |
break; | |
} | |
//if (elementSizeInPix != 0) { | |
// return elementSizeInPix; | |
if(axisElements != 0) { | |
return axisSizePix / axisElements; | |
} else { | |
return axisSizePix / numElementsInTable; | |
} | |
} | |
public int getNumRows() { | |
return numRows; | |
} | |
public void setNumRows(int numRows) { | |
this.numRows = numRows; | |
} | |
public int getNumColumns() { | |
return numColumns; | |
} | |
public void setNumColumns(int numColumns) { | |
this.numColumns = numColumns; | |
} | |
/* public void setCellWidth(Float cellWidth) { | |
this.cellWidth = cellWidth; | |
} | |
public Float getCellWidth() { | |
return cellWidth; | |
} | |
public Float getCellHeight() { | |
return cellHeight; | |
} | |
public void setCellHeight(Float cellHeight) { | |
this.cellHeight = cellHeight; | |
}*/ | |
private class TableModelIterator implements Iterator<RectF> { | |
private boolean isOk = true; | |
int lastColumn = 0; // most recent column iterated | |
int lastRow = 0; // most recent row iterated | |
int lastElement = 0; // last element index iterated | |
private DynamicTableModel dynamicTableModel; | |
private RectF tableRect; | |
private RectF lastElementRect; | |
private int totalElements; | |
private TableOrder order; | |
private int calculatedNumElements; | |
private int calculatedRows; // number of rows to be iterated | |
private int calculatedColumns; // number of columns to be iterated | |
public TableModelIterator(DynamicTableModel dynamicTableModel, RectF tableRect, int totalElements) { | |
this.dynamicTableModel = dynamicTableModel; | |
this.tableRect = tableRect; | |
this.totalElements = totalElements; | |
order = dynamicTableModel.getOrder(); | |
// unlimited columns: | |
if(dynamicTableModel.getNumColumns() == 0 && dynamicTableModel.getNumRows() >= 1) { | |
calculatedRows = dynamicTableModel.getNumRows(); | |
// round up: | |
calculatedColumns = new Float((totalElements / (float) calculatedRows) + 0.5).intValue(); | |
} else if(dynamicTableModel.getNumRows() == 0 && dynamicTableModel.getNumColumns() >= 1) { | |
//order = TableOrder.ROW_MAJOR; | |
calculatedColumns = dynamicTableModel.getNumColumns(); | |
calculatedRows = new Float((totalElements / (float) calculatedColumns) + 0.5).intValue(); | |
// unlimited rows and columns (impossible) so default a single row with n columns: | |
}else if(dynamicTableModel.getNumColumns() == 0 && dynamicTableModel.getNumRows() == 0) { | |
calculatedRows = 1; | |
calculatedColumns = totalElements; | |
} else { | |
//order = dynamicTableModel.getOrder(); | |
calculatedRows = dynamicTableModel.getNumRows(); | |
calculatedColumns = dynamicTableModel.getNumColumns(); | |
} | |
calculatedNumElements = calculatedRows * calculatedColumns; | |
lastElementRect = dynamicTableModel.getCellRect(tableRect, totalElements); | |
} | |
@Override | |
public boolean hasNext() { | |
return isOk && lastElement < calculatedNumElements; | |
} | |
@Override | |
public RectF next() { | |
if(!hasNext()) { | |
isOk = false; | |
throw new IndexOutOfBoundsException(); | |
} | |
if (lastElement == 0) { | |
lastElement++; | |
return lastElementRect; | |
} | |
RectF nextElementRect = new RectF(lastElementRect); | |
switch (order) { | |
case ROW_MAJOR: | |
if (dynamicTableModel.getNumColumns() > 0 && lastColumn >= (dynamicTableModel.getNumColumns() - 1)) { | |
// move to the begining of the next row down:// move to the begining of the next row down: | |
nextElementRect.offsetTo(tableRect.left, lastElementRect.bottom); | |
lastColumn = 0; | |
lastRow++; | |
} else { | |
// move to the next column over: | |
nextElementRect.offsetTo(lastElementRect.right, lastElementRect.top); | |
lastColumn++; | |
} | |
break; | |
case COLUMN_MAJOR: | |
if (dynamicTableModel.getNumRows() > 0 && lastRow >= (dynamicTableModel.getNumRows() - 1)) { | |
// move to the top of the next column over: | |
nextElementRect.offsetTo(lastElementRect.right, tableRect.top); | |
lastRow = 0; | |
lastColumn++; | |
} else { | |
// move to the next row down: | |
nextElementRect.offsetTo(lastElementRect.left, lastElementRect.bottom); | |
lastRow++; | |
} | |
break; | |
// unknown/unsupported enum val: | |
default: | |
isOk = false; | |
throw new IllegalArgumentException(); | |
} | |
lastElement++; | |
lastElementRect = nextElementRect; | |
return nextElementRect; | |
} | |
@Override | |
public void remove() { | |
throw new UnsupportedOperationException(); | |
} | |
} | |
} |