/* * Copyright 2013 serso aka se.solovyev * * 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. * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Contact details * * Email: se.solovyev@gmail.com * Site: http://se.solovyev.org */ package org.solovyev.android.calculator.matrix; import android.content.Context; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import android.widget.EditText; import android.widget.TableLayout; import android.widget.TableRow; import android.widget.TextView; import javax.annotation.Nonnull; import javax.annotation.Nullable; /** * User: Solovyev_S * Date: 12.10.12 * Time: 15:41 */ public class MatrixView extends TableLayout { /* ********************************************************************** * * CONSTANTS * ********************************************************************** */ private static final CharSequence DEFAULT_CELL_TEXT = "0"; private static final int NUMBER_INDEX = -1; /* ********************************************************************** * * FIELDS * ********************************************************************** */ private int rows = 0; private int cols = 0; @Nullable private CharSequence defaultCellText = DEFAULT_CELL_TEXT; private boolean initialized = false; /* ********************************************************************** * * CONSTRUCTORS * ********************************************************************** */ public MatrixView(Context context) { super(context); } public MatrixView(Context context, AttributeSet attrs) { super(context, attrs); } /* ********************************************************************** * * METHODS * ********************************************************************** */ public int getRows() { return rows; } public int getCols() { return cols; } public void setMatrixCols(int newCols) { setMatrixDimensions(rows, newCols); } public void setMatrixRows(int newRows) { setMatrixDimensions(newRows, cols); } public void setMatrixDimensions(int newRows, int newCols) { if (newRows <= 1) { throw new IllegalArgumentException("Number of rows must be more than 1: " + newRows); } if (newCols <= 1) { throw new IllegalArgumentException("Number of columns must be more than 1: " + newCols); } final boolean rowsChanged = this.rows != newRows; final boolean colsChanged = this.cols != newCols; if (rowsChanged || colsChanged) { if (!initialized) { addRow(NUMBER_INDEX, 0); initialized = true; } if (this.cols > newCols) { removeCols(newCols); } else if (this.cols < newCols) { addCols(newCols); } this.cols = newCols; if (this.rows > newRows) { removeRows(newRows); } else if (this.rows < newRows) { addRows(newRows); } this.rows = newRows; } } public void setMatrix(@Nonnull Object[][] matrix) { final int rows = matrix.length; final int cols = matrix[0].length; setMatrixDimensions(rows, cols); for (int row = 0; row < rows; row++) { for (int col = 0; col < cols; col++) { setCell(row, col, matrix[row][col]); } } } @Nonnull public String[][] toMatrix() { final String[][] result = new String[rows][cols]; for (int row = 0; row < rows; row++) { for (int col = 0; col < cols; col++) { final TextView cellTextView = (TextView) getCell(this, row, col); if (cellTextView != null) { result[row][col] = cellTextView.getText().toString(); } } } return result; } private void setCell(int row, int col, @Nullable Object o) { final TextView cellTextView = (TextView) getCell(this, row, col); if (cellTextView != null) { if (o == null) { cellTextView.setText(null); } else { cellTextView.setText(String.valueOf(o)); } } } /* ********************************************************************** * * PRIVATE METHODS * ********************************************************************** */ private void addRows(int newRows) { for (int row = this.rows; row < newRows; row++) { addRow(row, cols); } } private void removeRows(int newRows) { for (int row = this.rows - 1; row >= newRows; row--) { removeRow(row); } } private void addCols(int newCols) { for (int row = NUMBER_INDEX; row < rows; row++) { final ViewGroup rowView = getRow(row); if (rowView != null) { for (int col = this.cols; col < newCols; col++) { rowView.addView(createCellView(row, col)); } } } } private void removeCols(int newCols) { for (int row = NUMBER_INDEX; row < rows; row++) { final ViewGroup rowView = getRow(row); if (rowView != null) { for (int col = this.cols - 1; col >= newCols; col--) { final View cellView = getCell(rowView, row, col); if (cellView != null) { rowView.removeView(cellView); } } } } } private void addRow(int row, int newCols) { this.addView(createRowView(row, newCols)); } private void removeRow(int row) { final View rowView = getRow(row); if (rowView != null) { this.removeView(rowView); } } @Nullable private TableRow getRow(int row) { return (TableRow) this.findViewWithTag(getRowTag(row)); } @Nullable private View getCell(@Nonnull View view, int row, int col) { return view.findViewWithTag(getCellTag(row, col)); } @Nonnull private String getRowTag(int row) { if (row != NUMBER_INDEX) { return "row_" + row; } else { return "row_index"; } } @Nonnull private View createRowView(int row, int cols) { final ViewGroup rowView = new TableRow(this.getContext()); rowView.setTag(getRowTag(row)); if (row != NUMBER_INDEX) { rowView.addView(createCellView(row, NUMBER_INDEX)); } else { // empty cell rowView.addView(new View(this.getContext())); } for (int col = 0; col < cols; col++) { rowView.addView(createCellView(row, col)); } return rowView; } @Nonnull private View createCellView(int row, int col) { final TextView result; if (row != NUMBER_INDEX && col != NUMBER_INDEX) { result = new EditText(this.getContext()); result.setText(defaultCellText); } else { result = new TextView(this.getContext()); if (row == NUMBER_INDEX) { result.setText(String.valueOf(col + 1)); } else { result.setText(String.valueOf(row + 1)); } } result.setTag(getCellTag(row, col)); return result; } @Nonnull private String getCellTag(int row, int col) { if (row != NUMBER_INDEX) { return "cell_" + row + "_" + col; } else { return "cell_index_" + col; } } }