/* * Copyright (c) 2011, grossmann * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the jo-widgets.org nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL jo-widgets.org BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ package org.jowidgets.impl.model.table; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import org.jowidgets.api.model.table.IDefaultTableColumn; import org.jowidgets.api.model.table.ISimpleTableModel; import org.jowidgets.api.model.table.ITableCellBuilder; import org.jowidgets.common.color.IColorConstant; import org.jowidgets.common.image.IImageConstant; import org.jowidgets.common.model.ITableCell; import org.jowidgets.common.model.ITableDataModelListener; import org.jowidgets.common.model.ITableDataModelObservable; import org.jowidgets.tools.controller.TableDataModelObservable; import org.jowidgets.util.Assert; class SimpleTableModel extends DefaultTableColumnModel implements ISimpleTableModel, ITableDataModelObservable { private final TableDataModelObservable dataModelObservable; private final ArrayList<ArrayList<ITableCell>> data; private final IColorConstant evenBackgroundColor; private final IColorConstant oddBackgroundColor; private final boolean cellsEditableDefault; private ArrayList<Integer> selection; private boolean fireDataChanged; private boolean fireSelectionChanged; SimpleTableModel( final int rowCount, final int columnCount, final boolean cellsEditableDefault, final IColorConstant evenBackgroundColor, final IColorConstant oddBackgroundColor) { super(columnCount); this.dataModelObservable = new TableDataModelObservable(); this.cellsEditableDefault = cellsEditableDefault; this.evenBackgroundColor = evenBackgroundColor; this.oddBackgroundColor = oddBackgroundColor; this.selection = new ArrayList<Integer>(); this.data = new ArrayList<ArrayList<ITableCell>>(); final ITableCellBuilder cellBuilder = cellBuilder(); for (int rowIndex = 0; rowIndex < rowCount; rowIndex++) { final ArrayList<ITableCell> row = new ArrayList<ITableCell>(); data.add(row); for (int columnIndex = 0; columnIndex < columnCount; columnIndex++) { row.add(cellBuilder.build()); } } this.fireDataChanged = false; this.fireSelectionChanged = false; } @Override public void modifyModelStart() { super.modifyModelStart(); } @Override public void modifyModelEnd() { super.modifyModelEnd(); if (fireDataChanged && isFireEvents()) { dataModelObservable.fireDataChanged(); } if (fireSelectionChanged && isFireEvents()) { dataModelObservable.fireSelectionChanged(); } fireDataChanged = false; fireSelectionChanged = false; } @Override public int getRowCount() { return data.size(); } @Override public ITableCell getCell(final int rowIndex, final int columnIndex) { final TableCell result = new TableCell(data.get(rowIndex).get(columnIndex)); if (result.getBackgroundColor() == null) { if (rowIndex % 2 == 0) { result.setBackgroundColor(evenBackgroundColor); } else { result.setBackgroundColor(oddBackgroundColor); } } return result; } @Override public int getFirstSelectedRow() { final ArrayList<Integer> currentSelection = getSelection(); if (currentSelection.size() > 0) { return Collections.min(currentSelection).intValue(); } return -1; } @Override public int getLastSelectedRow() { final ArrayList<Integer> currentSelection = getSelection(); if (currentSelection.size() > 0) { return Collections.max(currentSelection).intValue(); } return -1; } @Override public ArrayList<ITableCell> getRow(final int rowIndex) { final ArrayList<ITableCell> result = new ArrayList<ITableCell>(); for (int columnIndex = 0; columnIndex < getColumnCount(); columnIndex++) { result.add(data.get(rowIndex).get(columnIndex)); } return result; } @Override public ArrayList<String> getRowTexts(final int rowIndex) { final ArrayList<String> result = new ArrayList<String>(); for (int columnIndex = 0; columnIndex < getColumnCount(); columnIndex++) { result.add(data.get(rowIndex).get(columnIndex).getText()); } return result; } @Override public void setCell(final int rowIndex, final int columnIndex, final ITableCell cell) { Assert.paramNotNull(cell, "cell"); data.get(rowIndex).set(columnIndex, cell); if (isEventsFreezed()) { fireDataChanged = true; } else if (isFireEvents()) { dataModelObservable.fireRowsChanged(new int[] {rowIndex}); } } @Override public void setRow(final int rowIndex, final ITableCell... cells) { Assert.paramNotNull(cells, "cells"); for (int i = 0; i < cells.length; i++) { data.get(rowIndex).set(i, cells[i]); } if (isEventsFreezed()) { fireDataChanged = true; } else if (isFireEvents()) { dataModelObservable.fireRowsChanged(new int[] {rowIndex}); } } @Override public void addRows(final int startRowIndex, final int rowCount) { final int[] rowIndices = new int[rowCount]; final ITableCellBuilder cellBuilder = cellBuilder(); final int columnCount = getColumnCount(); for (int i = 0; i < rowCount; i++) { rowIndices[i] = startRowIndex + i; final ArrayList<ITableCell> row = new ArrayList<ITableCell>(); data.add(startRowIndex, row); for (int columnIndex = 0; columnIndex < columnCount; columnIndex++) { row.add(cellBuilder.build()); } } if (isEventsFreezed()) { fireDataChanged = true; } else if (isFireEvents()) { dataModelObservable.fireRowsAdded(rowIndices); } } @Override public void addRow(final int rowIndex, final ITableCell... cells) { Assert.paramNotNull(cells, "cells"); final ITableCellBuilder cellBuilder = cellBuilder(); final int columnCount = getColumnCount(); final ArrayList<ITableCell> row = new ArrayList<ITableCell>(); data.add(rowIndex, row); for (int columnIndex = 0; columnIndex < columnCount; columnIndex++) { if (columnIndex < cells.length) { row.add(cells[columnIndex]); } else { row.add(cellBuilder.build()); } } if (isEventsFreezed()) { fireDataChanged = true; } else if (isFireEvents()) { dataModelObservable.fireRowsAdded(new int[] {rowIndex}); } } @Override public void removeRow(final int index) { data.remove(index); final boolean selectionChanged = selection.remove(Integer.valueOf(index)); if (isEventsFreezed()) { fireDataChanged = true; } else if (isFireEvents()) { dataModelObservable.fireRowsRemoved(new int[] {index}); } if (selectionChanged) { if (isEventsFreezed()) { fireSelectionChanged = true; } else if (isFireEvents()) { dataModelObservable.fireSelectionChanged(); } } } @Override public void removeRows(final int fromIndex, final int toIndex) { if (fromIndex > toIndex) { throw new IllegalArgumentException("From index must be less or equal than to index."); } final int[] indices = new int[1 + toIndex - fromIndex]; boolean selectionChanged = false; for (int i = 0; i < indices.length; i++) { indices[i] = fromIndex + i; data.remove(fromIndex); selectionChanged = selectionChanged || selection.remove(Integer.valueOf(fromIndex + i)); } if (isEventsFreezed()) { fireDataChanged = true; } else if (isFireEvents()) { dataModelObservable.fireRowsRemoved(indices); } if (selectionChanged) { if (isEventsFreezed()) { fireSelectionChanged = true; } else if (isFireEvents()) { dataModelObservable.fireSelectionChanged(); } } } @Override public void removeRows(final int... rows) { Assert.paramNotNull(rows, "rows"); //If rows is sorted, for each already removed row the //index must be reduced by one Arrays.sort(rows); int removedRowCount = 0; boolean selectionChanged = false; for (final int row : rows) { data.remove(row - removedRowCount); selectionChanged = selection.remove(Integer.valueOf(row)) || selectionChanged; removedRowCount++; } if (isEventsFreezed()) { fireDataChanged = true; } else if (isFireEvents()) { dataModelObservable.fireRowsRemoved(rows); } if (selectionChanged) { if (isEventsFreezed()) { fireSelectionChanged = true; } else if (isFireEvents()) { dataModelObservable.fireSelectionChanged(); } } } @Override public void removeAllRows() { final boolean selectionChanged = selection.size() > 0; data.clear(); if (isEventsFreezed()) { fireDataChanged = true; } else if (isFireEvents()) { dataModelObservable.fireDataChanged(); } if (selectionChanged) { if (isEventsFreezed()) { fireSelectionChanged = true; } else if (isFireEvents()) { dataModelObservable.fireSelectionChanged(); } } } @Override public ArrayList<Integer> getSelection() { return new ArrayList<Integer>(selection); } @Override public void setSelection(Collection<Integer> selection) { if (selection == null) { selection = new ArrayList<Integer>(); } if (!this.selection.equals(selection)) { this.selection = new ArrayList<Integer>(selection); if (isFireEvents()) { dataModelObservable.fireSelectionChanged(); } } } @Override public ITableDataModelObservable getTableDataModelObservable() { return this; } @Override public void addDataModelListener(final ITableDataModelListener listener) { dataModelObservable.addDataModelListener(listener); } @Override public void removeDataModelListener(final ITableDataModelListener listener) { dataModelObservable.removeDataModelListener(listener); } //////////////////////////////////////////////////////////////////////////////////////////////// //Overridden from column model start //////////////////////////////////////////////////////////////////////////////////////////////// @Override public void addColumn(final int columnIndex, final IDefaultTableColumn column) { if (data != null) { final ITableCellBuilder cellBuilder = cellBuilder(); for (int rowIndex = 0; rowIndex < data.size(); rowIndex++) { data.get(rowIndex).add(columnIndex, cellBuilder.build()); } } super.addColumn(columnIndex, column); } @Override public void removeColumns(final int... columnIndices) { Assert.paramNotNull(columnIndices, "columnIndices"); //If rows is sorted, for each already removed row the //index must be reduced by one Arrays.sort(columnIndices); for (int rowIndex = 0; rowIndex < data.size(); rowIndex++) { int removedColumnCount = 0; for (final int columnIndex : columnIndices) { data.get(rowIndex).remove(columnIndex - removedColumnCount); removedColumnCount++; } } super.removeColumns(columnIndices); } //////////////////////////////////////////////////////////////////////////////////////////////// //Overridden from column model end //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //Convenience methods start //////////////////////////////////////////////////////////////////////////////////////////////// @Override public void addRow() { addRows(getRowCount(), 1); } @Override public void addRow(final int rowIndex) { addRows(rowIndex, 1); } @Override public void addRow(final ITableCell... cells) { addRow(getRowCount(), cells); } @Override public void addRow(final ITableCellBuilder... cellBuilders) { addRow(getRowCount(), cellBuilders); } @Override public void addRow(final int rowIndex, final ITableCellBuilder... cellBuilders) { Assert.paramNotNull(cellBuilders, "cellBuilders"); final ITableCell[] cells = new ITableCell[cellBuilders.length]; for (int i = 0; i < cellBuilders.length; i++) { cells[i] = cellBuilders[i].build(); } addRow(rowIndex, cells); } @Override public void addRow(final String... cellTexts) { addRow(getRowCount(), cellTexts); } @Override public void addRow(final int rowIndex, final String... cellTexts) { Assert.paramNotNull(cellTexts, "cellTexts"); final ITableCell[] cells = new ITableCell[cellTexts.length]; for (int i = 0; i < cellTexts.length; i++) { cells[i] = cellBuilder().setText(cellTexts[i]).build(); } addRow(rowIndex, cells); } @Override public void addRow(final List<String> cellTexts) { addRow(getRowCount(), cellTexts); } @Override public void addRow(final int rowIndex, final List<String> cellTexts) { Assert.paramNotNull(cellTexts, "cellTexts"); final ITableCell[] cells = new ITableCell[cellTexts.size()]; int i = 0; for (final String cellText : cellTexts) { cells[i] = cellBuilder().setText(cellText).build(); i++; } addRow(rowIndex, cells); } @Override public void setCell(final int rowIndex, final int columnIndex, final ITableCellBuilder cellBuilder) { setCell(rowIndex, columnIndex, cellBuilder.build()); } @Override public void setCell(final int rowIndex, final int columnIndex, final String text) { setCell(rowIndex, columnIndex, cellBuilder().setText(text)); } @Override public void setCell(final int rowIndex, final int columnIndex, final String text, final IImageConstant icon) { setCell(rowIndex, columnIndex, cellBuilder().setText(text).setIcon(icon)); } @Override public void setCell(final int rowIndex, final int columnIndex, final String text, final boolean editable) { setCell(rowIndex, columnIndex, cellBuilder().setText(text).setEditable(editable)); } @Override public void setRow(final int rowIndex, final ITableCellBuilder... cellBuilders) { Assert.paramNotNull(cellBuilders, "cellBuilders"); final ITableCell[] cells = new ITableCell[cellBuilders.length]; for (int columnIndex = 0; columnIndex < getColumnCount(); columnIndex++) { cells[columnIndex] = cellBuilders[columnIndex].build(); } } @Override public void setCellEditable(final int rowIndex, final int columnIndex, final boolean editable) { final TableCell cell = new TableCell(getCell(rowIndex, columnIndex)); cell.setEditable(editable); setCell(rowIndex, columnIndex, cell); } @Override public void setCellText(final int rowIndex, final int columnIndex, final String text) { final TableCell cell = new TableCell(getCell(rowIndex, columnIndex)); cell.setText(text); setCell(rowIndex, columnIndex, cell); } @Override public void setCellTooltipText(final int rowIndex, final int columnIndex, final String tooltipText) { final TableCell cell = new TableCell(getCell(rowIndex, columnIndex)); cell.setToolTipText(tooltipText); setCell(rowIndex, columnIndex, cell); } @Override public void setCellIcon(final int rowIndex, final int columnIndex, final IImageConstant icon) { final TableCell cell = new TableCell(getCell(rowIndex, columnIndex)); cell.setIcon(icon); setCell(rowIndex, columnIndex, cell); } @Override public void setRowTexts(final int rowIndex, final String... cellTexts) { Assert.paramNotNull(cellTexts, "cellTexts"); final ITableCell[] cells = new ITableCell[cellTexts.length]; for (int columnIndex = 0; columnIndex < getColumnCount(); columnIndex++) { final TableCell cell = new TableCell(getCell(rowIndex, columnIndex)); cell.setText(cellTexts[columnIndex]); cells[columnIndex] = cell; } setRow(rowIndex, cells); } @Override public void setRowTexts(final int rowIndex, final List<String> cellTexts) { Assert.paramNotNull(cellTexts, "cellTexts"); final ITableCell[] cells = new ITableCell[cellTexts.size()]; int columnIndex = 0; for (final String cellText : cellTexts) { final TableCell cell = new TableCell(getCell(rowIndex, columnIndex)); cell.setText(cellText); cells[columnIndex] = cell; columnIndex++; } setRow(rowIndex, cells); } @Override public void removeRows(final List<Integer> rows) { final int[] rowsArray = new int[rows.size()]; int index = 0; for (final Integer row : rows) { rowsArray[index] = row.intValue(); index++; } removeRows(rowsArray); } //////////////////////////////////////////////////////////////////////////////////////////////// //Convenience methods end //////////////////////////////////////////////////////////////////////////////////////////////// private ITableCellBuilder cellBuilder() { return new TableCellBuilder().setEditable(cellsEditableDefault); } }