1 /* 2 * Copyright 2012 AndroidPlot.com 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.androidplot.ui; 18 19 import android.graphics.RectF; 20 21 import java.util.Iterator; 22 23 /** 24 * Encapsulates the visual aspects of a table; number of rows and columns 25 * and the height and width in pixels of each element within the table. 26 * There is no support (yet) for variable size cells within a table; all 27 * cells within a table share the same dimensions. 28 * 29 * The DynamicTableModel provides an Iterator implementation which returns a RectF 30 * of each subsequent cell, based on the order of the plot. Tables with 31 * an order of COLUMN_MAJOR are traversed left to right column by column until 32 * the end of the row is reached, then proceeding to the next row. 33 * Tables with an order of ROW_MAJOR are traversed top to bottom row by row 34 * until the end of the row is reached, then proceeding to the next column. 35 */ 36 public class DynamicTableModel extends TableModel { 37 38 //private float cellWidth; 39 //private float cellHeight; 40 //private TableSizingMethod rowSizingMethod; 41 //private TableSizingMethod columnSizingMethod; 42 43 44 private int numRows; 45 private int numColumns; 46 47 private Float cellWidth; 48 private Float cellHeight; 49 50 private CellSizingMethod rowSizingMethod; 51 private CellSizingMethod columnSizingMethod; 52 53 /** 54 * Convenience method. Sets order to ROW_MAJOR. 55 * @param numColumns 56 * @param numRows 57 */ DynamicTableModel(int numColumns, int numRows)58 public DynamicTableModel(int numColumns, int numRows) { 59 this(numColumns, numRows, TableOrder.ROW_MAJOR); 60 61 } 62 DynamicTableModel(int numColumns, int numRows, TableOrder order)63 public DynamicTableModel(int numColumns, int numRows, TableOrder order) { 64 super(order); 65 this.numColumns = numColumns; 66 //this.cellWidth = cellWidth; 67 //this.rowSizingMethod = rowSizingMethod; 68 this.numRows = numRows; 69 //this.cellHeight = cellHeight; 70 //this.columnSizingMethod = columnSizingMethod; 71 //this.order = order; 72 } 73 74 /*public DynamicTableModel(Number colVal, CellSizingMethod colSzMethod, Number rowVal, CellSizingMethod rowSzMethod, TableOrder order) { 75 if(colVal == null || rowVal == null) { 76 throw new NullPointerException(); 77 } 78 columnSizingMethod = colSzMethod; 79 switch(columnSizingMethod) { 80 case FILL: 81 numColumns = colVal.intValue(); 82 break; 83 case FIXED: 84 cellWidth = colVal.floatValue(); 85 break; 86 } 87 rowSzMethod = rowSzMethod; 88 }*/ 89 90 @Override getIterator(RectF tableRect, int totalElements)91 public TableModelIterator getIterator(RectF tableRect, int totalElements) { 92 return new TableModelIterator(this, tableRect, totalElements); 93 } 94 95 /** 96 * Calculates the dimensions of a single element of this table with 97 * tableRect representing the overall dimensions of the table. 98 * @param tableRect Dimensions/position of the table 99 * @return a RectF representing the first (top-left) element in 100 * the tableRect passed in. 101 */ getCellRect(RectF tableRect, int numElements)102 public RectF getCellRect(RectF tableRect, int numElements) { 103 RectF cellRect = new RectF(); 104 cellRect.left = tableRect.left; 105 cellRect.top = tableRect.top; 106 //cellRect.bottom = getElementHeightPix(tableRect); 107 cellRect.bottom = tableRect.top + calculateCellSize(tableRect, TableModel.Axis.ROW, numElements); 108 //cellRect.right = getElementWidthPix(tableRect); 109 cellRect.right = tableRect.left + calculateCellSize(tableRect, TableModel.Axis.COLUMN, numElements); 110 return cellRect; 111 } 112 113 /** 114 * Figure out the size of a single cell across the specified axis. 115 * @param tableRect 116 * @param axis 117 * @param numElementsInTable 118 * @return 119 */ calculateCellSize(RectF tableRect, Axis axis, int numElementsInTable)120 private float calculateCellSize(RectF tableRect, 121 Axis axis, 122 int numElementsInTable) { 123 //float elementSizeInPix = 0; 124 int axisElements = 0; 125 126 float axisSizePix = 0; 127 switch (axis) { 128 case ROW: 129 //elementSizeInPix = cellHeight; 130 axisElements = numRows; 131 axisSizePix = tableRect.height(); 132 break; 133 case COLUMN: 134 //elementSizeInPix = cellWidth; 135 axisElements = numColumns; 136 axisSizePix = tableRect.width(); 137 break; 138 } 139 //if (elementSizeInPix != 0) { 140 // return elementSizeInPix; 141 if(axisElements != 0) { 142 return axisSizePix / axisElements; 143 } else { 144 return axisSizePix / numElementsInTable; 145 } 146 } 147 148 149 getNumRows()150 public int getNumRows() { 151 return numRows; 152 } 153 setNumRows(int numRows)154 public void setNumRows(int numRows) { 155 this.numRows = numRows; 156 } 157 getNumColumns()158 public int getNumColumns() { 159 return numColumns; 160 } 161 setNumColumns(int numColumns)162 public void setNumColumns(int numColumns) { 163 this.numColumns = numColumns; 164 } 165 166 /* public void setCellWidth(Float cellWidth) { 167 this.cellWidth = cellWidth; 168 } 169 170 public Float getCellWidth() { 171 return cellWidth; 172 } 173 174 public Float getCellHeight() { 175 return cellHeight; 176 } 177 178 public void setCellHeight(Float cellHeight) { 179 this.cellHeight = cellHeight; 180 }*/ 181 182 private class TableModelIterator implements Iterator<RectF> { 183 private boolean isOk = true; 184 int lastColumn = 0; // most recent column iterated 185 int lastRow = 0; // most recent row iterated 186 int lastElement = 0; // last element index iterated 187 private DynamicTableModel dynamicTableModel; 188 private RectF tableRect; 189 private RectF lastElementRect; 190 private int totalElements; 191 private TableOrder order; 192 193 private int calculatedNumElements; 194 private int calculatedRows; // number of rows to be iterated 195 private int calculatedColumns; // number of columns to be iterated 196 TableModelIterator(DynamicTableModel dynamicTableModel, RectF tableRect, int totalElements)197 public TableModelIterator(DynamicTableModel dynamicTableModel, RectF tableRect, int totalElements) { 198 this.dynamicTableModel = dynamicTableModel; 199 this.tableRect = tableRect; 200 this.totalElements = totalElements; 201 order = dynamicTableModel.getOrder(); 202 203 // unlimited columns: 204 if(dynamicTableModel.getNumColumns() == 0 && dynamicTableModel.getNumRows() >= 1) { 205 calculatedRows = dynamicTableModel.getNumRows(); 206 207 // round up: 208 calculatedColumns = new Float((totalElements / (float) calculatedRows) + 0.5).intValue(); 209 } else if(dynamicTableModel.getNumRows() == 0 && dynamicTableModel.getNumColumns() >= 1) { 210 //order = TableOrder.ROW_MAJOR; 211 calculatedColumns = dynamicTableModel.getNumColumns(); 212 calculatedRows = new Float((totalElements / (float) calculatedColumns) + 0.5).intValue(); 213 // unlimited rows and columns (impossible) so default a single row with n columns: 214 }else if(dynamicTableModel.getNumColumns() == 0 && dynamicTableModel.getNumRows() == 0) { 215 calculatedRows = 1; 216 calculatedColumns = totalElements; 217 } else { 218 //order = dynamicTableModel.getOrder(); 219 calculatedRows = dynamicTableModel.getNumRows(); 220 calculatedColumns = dynamicTableModel.getNumColumns(); 221 } 222 calculatedNumElements = calculatedRows * calculatedColumns; 223 lastElementRect = dynamicTableModel.getCellRect(tableRect, totalElements); 224 } 225 226 @Override hasNext()227 public boolean hasNext() { 228 return isOk && lastElement < calculatedNumElements; 229 } 230 231 @Override next()232 public RectF next() { 233 if(!hasNext()) { 234 isOk = false; 235 throw new IndexOutOfBoundsException(); 236 } 237 238 if (lastElement == 0) { 239 lastElement++; 240 return lastElementRect; 241 } 242 243 RectF nextElementRect = new RectF(lastElementRect); 244 245 switch (order) { 246 case ROW_MAJOR: 247 if (dynamicTableModel.getNumColumns() > 0 && lastColumn >= (dynamicTableModel.getNumColumns() - 1)) { 248 // move to the begining of the next row down:// move to the begining of the next row down: 249 nextElementRect.offsetTo(tableRect.left, lastElementRect.bottom); 250 lastColumn = 0; 251 lastRow++; 252 } else { 253 // move to the next column over: 254 nextElementRect.offsetTo(lastElementRect.right, lastElementRect.top); 255 lastColumn++; 256 } 257 break; 258 case COLUMN_MAJOR: 259 if (dynamicTableModel.getNumRows() > 0 && lastRow >= (dynamicTableModel.getNumRows() - 1)) { 260 // move to the top of the next column over: 261 nextElementRect.offsetTo(lastElementRect.right, tableRect.top); 262 lastRow = 0; 263 lastColumn++; 264 } else { 265 // move to the next row down: 266 nextElementRect.offsetTo(lastElementRect.left, lastElementRect.bottom); 267 lastRow++; 268 } 269 break; 270 // unknown/unsupported enum val: 271 default: 272 isOk = false; 273 throw new IllegalArgumentException(); 274 } 275 lastElement++; 276 lastElementRect = nextElementRect; 277 return nextElementRect; 278 279 } 280 281 @Override remove()282 public void remove() { 283 throw new UnsupportedOperationException(); 284 } 285 } 286 } 287