/* * Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED * 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 Business Objects 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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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. */ /* * ListTupleTableModel.java * Created: Feb 28, 2001 * By: Michael Cheng */ package org.openquark.gems.client.valueentry; import java.util.List; import org.openquark.cal.compiler.FieldName; import org.openquark.cal.compiler.TypeConsApp; import org.openquark.cal.compiler.TypeExpr; import org.openquark.cal.valuenode.ListValueNode; import org.openquark.cal.valuenode.NTupleValueNode; import org.openquark.cal.valuenode.RecordValueNode; import org.openquark.cal.valuenode.ValueNode; /** * The table model for handling lists, lists of tuples and lists of records * * Note: Do not use this table model for types other than lists (which includes lists of tuples). * * Creation date: (28/02/01 1:17:20 PM) * @author Michael Cheng */ class ListTupleTableModel extends ListTableModelBase { private static final long serialVersionUID = -5931490046618373666L; /** The ith value of elementTypeArrayParam gives the type for the ith column in the array.*/ private final TypeExpr[] elementTypeExprArray; /** * Whether the columns of this table are consolidated. * * If true, this causes the model to have one column whose elements are the list element value nodes. * otherwise, for lists of tuples and records, the model columns represent individual fields of the record/tuple elements. */ private boolean consolidatedColumns = false; /** * ListTupleTableModel constructor. * @param listValueNode * @param valueEditorHierarchyManager */ public ListTupleTableModel(ListValueNode listValueNode, ValueEditorHierarchyManager valueEditorHierarchyManager, boolean consolidatedColumns) { super(listValueNode, valueEditorHierarchyManager.getValueEditorManager()); if (listValueNode == null) { throw new NullPointerException ("argument listValueNode cannot be null."); } // Initialize elementTypeArray. int nElements = getNElements(); elementTypeExprArray = new TypeExpr[nElements]; for (int i = 0; i < nElements; i++) { elementTypeExprArray[i] = getElementType(i); } this.consolidatedColumns = consolidatedColumns; } @Override public int getColumnCount() { if (!consolidatedColumns) { if (elementTypeExprArray.length == 0 && isListRecord()) { // Special case: list of records with no fields has one column (with header) return 1; } else { return elementTypeExprArray.length; } } else { return 1; } } @Override public int getRowCount() { if (elementTypeExprArray.length == 0 && isListRecord()) { // Special case: if this is a list of records with no fields, return super.getRowCount(); } else { return super.getRowCount(); } } @Override public String getColumnName(int col) { TypeConsApp listTypeConsApp = ((TypeConsApp) getListValueNode().getTypeExpr()); if (!consolidatedColumns && isListRecord()) { // Special case: if this is a list of records, use record field names as column names List<FieldName> fieldNames = listTypeConsApp.getArg(0).rootRecordType().getHasFieldNames(); if (fieldNames.size() == 0) { return ValueEditorMessages.getString("VE_NoFieldsColumnName"); } else { return (fieldNames.get(col)).getCalSourceForm(); } } else { TypeExpr columnType = getElementType(col); if (columnType.rootRecordType() != null && columnType.rootRecordType().getNHasFields() > 0) { // Special case: Column names for record types with more than 0 fields are labeled "{Record}" for clarity return ValueEditorMessages.getString("VE_RecordColumnName"); } else { return valueEditorManager.getTypeName(columnType); } } } /** * Return the TypeExpr for the ith column in the array (ie: the ith element in the elementTypeExprArray). * @param col column index of element to retrieve type for * @return TypeExpr */ @Override public TypeExpr getElementType (int col) { TypeConsApp listTypeConsApp = ((TypeConsApp) getListValueNode().getTypeExpr()); if (!consolidatedColumns && isListRecord()) { //this handles the case of lists of tuples as well as lists of general records // Special case: in the case of a list of records, index the record fields alphabetically List<FieldName> fieldNames = listTypeConsApp.getArg(0).rootRecordType().getHasFieldNames(); if (fieldNames.isEmpty()) { // Special case: record has no fields. The type of this column is the record type return ((TypeConsApp) getListValueNode().getTypeExpr()).getArg(0).rootRecordType(); } return listTypeConsApp.getArg(0).rootRecordType().getHasFieldType(fieldNames.get(col)); } else { return listTypeConsApp.getArg(col); } } @Override public int getNElements() { TypeConsApp listTypeConsApp = ((TypeConsApp) getListValueNode().getTypeExpr()); if (!consolidatedColumns && isListRecord()) { // Special case: in the case of a list of record, index the record fields return listTypeConsApp.getArg(0).rootRecordType().getNHasFields(); } else { return listTypeConsApp.getNArgs(); } } public Object getValueAt(int row, int col) { ValueNode rowValueNode = getListValueNode().getValueAt(row); if (!consolidatedColumns && isListRecord()) { if (rowValueNode instanceof RecordValueNode) { // A list of records if (elementTypeExprArray.length == 0) { return ValueEditorMessages.getString("VE_NoFieldsValue"); } else { return ((RecordValueNode)rowValueNode).getValueAt(col); } } else if (rowValueNode instanceof NTupleValueNode) { // A list of tuples. return ((NTupleValueNode)rowValueNode).getValueAt(col); } else { throw new IllegalStateException("Can't handle list of records where list elements are of type: " + rowValueNode.getClass()); } } else { // Just a list. return rowValueNode; } } /** * Returns true if the data type in this model is a List of Records, * otherwise returns false. * Note that this will also be true if the type of the data is a List of Tuples. * @return boolean */ public boolean isListRecord() { // Note: Always assume that typeExpr is a List. TypeConsApp listTypeConsApp = (TypeConsApp) getListValueNode().getTypeExpr(); return listTypeConsApp.getArg(0).rootRecordType() != null; } /** * Sets the value at the indicated row and col. */ @Override public void setValueAt(Object value, int row, int col) { // Need to check if it's just a list, or a list of records if (!consolidatedColumns && isListRecord()) { ValueNode rowValueNode = getListValueNode().getValueAt(row); if (rowValueNode instanceof RecordValueNode) { // A list of records. ((RecordValueNode)rowValueNode).setValueNodeAt(col, (ValueNode) value); } else if (rowValueNode instanceof NTupleValueNode) { // A list of tuples. ((NTupleValueNode)rowValueNode).setValueNodeAt(col, (ValueNode) value); } else { throw new IllegalStateException("Can't handle list of records where list elements are of type: " + rowValueNode.getClass()); } } else { // Just a list. getListValueNode().setValueNodeAt(row, (ValueNode)value); } fireTableCellUpdated(row, col); } /** * @return whether the model is set to consolidate columns (for tuple and record types) */ public boolean isConsolidatingColumns() { return consolidatedColumns; } /** * Set the model to consolidate columns for tuple and record types * @param consolidatedColumns new value for consolidation flag */ public void setConsolidatingColumns(boolean consolidatedColumns) { this.consolidatedColumns = consolidatedColumns; fireTableStructureChanged(); } /** * @see javax.swing.table.TableModel#isCellEditable(int, int) */ @Override public boolean isCellEditable(int row, int column) { if (isListRecord() && elementTypeExprArray.length == 0 && !isConsolidatingColumns()) { // If it's modeling an empty record, don't allow editing of any columns return false; } else { return super.isCellEditable(row, column); } } }