Package gov.nasa.arc.mct.table.model

Source Code of gov.nasa.arc.mct.table.model.TableStructure$TableRow

/*******************************************************************************
* Mission Control Technologies, Copyright (c) 2009-2012, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* The MCT platform is 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.
*
* MCT includes source code licensed under additional open source licenses. See
* the MCT Open Source Licenses file included with this distribution or the About
* MCT Licenses dialog available at runtime from the MCT Help menu for additional
* information.
*******************************************************************************/
package gov.nasa.arc.mct.table.model;

import gov.nasa.arc.mct.components.AbstractComponent;
import gov.nasa.arc.mct.services.component.ComponentRegistry;
import gov.nasa.arc.mct.table.access.ServiceAccess;
import gov.nasa.arc.mct.table.policy.TableViewPolicy;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
* Implements a data structure that maintains the structure of a tabular
* array of objects.
*/
public class TableStructure {
 
  private static final Logger logger = LoggerFactory.getLogger(TableStructure.class);
 
  /** The type of table, 0-dimensional, 1-dimensional, or 2-dimensional. */
  private TableType type;
 
  /** The root component. */
  private AbstractComponent rootComponent;

  /** The maximum number of columns of any row. */
  private int columnCount = 0;
 
  /**
   * Creates a tabular structure of a given dimensionality.
   *
   * @param type the type of tabular structure, 0-dimensional, 1-dimensional,
   *   or 2-dimensional
   * @param rootComponent the root of the table structure
   */
  public TableStructure(TableType type, AbstractComponent rootComponent) {
    this.type = type;
    this.rootComponent = rootComponent;
    buildTable();
    updateColumnCount();
  }
 
  /**
   * Tells the structure that children have been added to or removed from
   * the root component of the structure.
   */
  public void notifyTableStructureChanged() {
    updateColumnCount();
  }
 
  private void updateColumnCount() {
    if (type != TableType.TWO_DIMENSIONAL) {
      columnCount = 1;
    } else {
      columnCount = 1; // We always pretend to have at least one column, so that we can drag-and-drop.
      for (List<TableCell> row : rowList) {
        if (row.size() > columnCount) {
          columnCount = row.size();
        }
      }
    }
  }
 
  /**
   * Gets the number of rows in the tabular structure.
   *
   * @return the number of rows
   */
  public int getRowCount() {
    if (type == TableType.ZERO_DIMENSIONAL) {
      return 1;
    } else {
      return Math.max(1, rowList.size());
    }
  }
 
  /**
   * Gets the number of columns in the tabular structure. The number
   * of columns is the maximum number of elements in any row.
   *
   * @return the number of columns
   */
  public int getColumnCount() {
    return Math.max(1, columnCount);
  }
   
  /**
   * Tests whether the table structure is a skeleton, ready for values to be
   * dropped in to flesh out the table cells and columns. A skeleton table
   * structure is a 2-D table that doesn't yet have any values.
   *
   * @return true, if the table is a skeleton
   */
  public boolean isSkeleton() {
    return type==TableType.TWO_DIMENSIONAL && rowList.size() == 0;
  }
 
  /**
   * Gets a value in the tabular array.
   *
   * @param rowIndex the row for which to get the value
   * @param columnIndex the column for which to get the value
   * @return the value at the row and column position, or null if there is no value at that position
   * @throws ArrayIndexOutOfBoundsException
   */
 
  public AbstractComponent getValue(int rowIndex, int columnIndex) {
   
    try {
     
      if (rowIndex < 0 || rowIndex >= getRowCount()) {
        logger.warn("Row index " + rowIndex + " > " + (getRowCount() - 1));
      }
   
      if (columnIndex < 0 || columnIndex >= columnCount) {
        logger.warn("Column index " + columnIndex + " > " + (columnCount - 1));
      }
   
      if (rowList.size() > 0) {
        TableRow row = rowList.get(rowIndex);
        if (row.size() > 0 && columnIndex < row.size()) {
          return row.get(columnIndex).getValue();
        } else {
          return null; // Not all rows are same width, so pad with nulls
        }
      } else {
        return null;     // Not all rows are same width, so pad with nulls
      }
    } catch (IndexOutOfBoundsException outOfBoundsException) {
      logger.warn("IndexOutOfBoundsException: {0}", outOfBoundsException);
      return null;
    }
  }
 
  /**
   * Sets a value at a row and column position in the tabular
   * array.
   *
   * @param rowIndex the row for which to set the value
   * @param columnIndex the column for which to set the value
   * @param isInsertRow true, if the value should be inserted in a new row prior to the indicated row
   * @param isInsertColumn true, if the value should be inserted in a new column prior to the indicated row
   * @param value the new value
   */
  public void setValue(int rowIndex, int columnIndex, boolean isInsertRow, boolean isInsertColumn, AbstractComponent value) {
    assert canSetValue(rowIndex, columnIndex, isInsertRow, isInsertColumn);
    assert type != TableType.ZERO_DIMENSIONAL;
   
    // Refuse values which cannot be placed in tables
    // TODO: User notification? Or disallow drop to begin with?
    if (!canEmbedInTable(value)) return;
   
 
    if (type == TableType.ONE_DIMENSIONAL) {
     
      // Determine where in the root component we want to add the component
      int componentIndex;
      if (rowIndex < rowList.size()) {
        componentIndex = rowList.get(rowIndex).get(0).getIndex();
      } else {
        componentIndex = rootComponent.getComponents().size(); //Add it to the end
      }
     
      // Remove the old component, if there is one
      if (!isInsertRow) {
        TableCell cell = rowList.get(rowIndex).get(columnIndex);
        AbstractComponent toBeRemoved = cell.getValue();
        rootComponent.removeDelegateComponent(toBeRemoved);
      }
      rootComponent.addDelegateComponents(componentIndex, Collections.<AbstractComponent> singletonList(value));
     
    } else {
     
      if (isInsertRow) {
        // Should insert new child. Create a collection of the same type as
        // the root object.
        int componentIndex;
        if (rowIndex < rowList.size()) {
          componentIndex = rowList.get(rowIndex).getIndex();
        } else {
          componentIndex = rootComponent.getComponents().size();
        }
        AbstractComponent newChild = ServiceAccess.getService(ComponentRegistry.class).newCollection(Collections.singleton(value));
        rootComponent.addDelegateComponents(componentIndex, Collections.singleton(newChild));
      } else { //Insert column, or overwrite cell
        TableRow row = rowList.get(rowIndex);
       
        int componentIndex;
        AbstractComponent targetComponent;
        if (!isInsertColumn && columnIndex < row.size()) {
        }
        if (columnIndex < row.size()) {
          targetComponent = row.get(columnIndex).getParent();
          componentIndex  = row.get(columnIndex).getIndex();
          if (!isInsertColumn) {
            targetComponent.removeDelegateComponent(row.get(columnIndex).getValue());
          }
        } else {
          targetComponent = row.get(row.size()-1).getParent();
          componentIndex  = targetComponent.getComponents().size();
        }
        targetComponent.addDelegateComponents(componentIndex, Collections.singleton(value));
       
      }
     
      updateColumnCount(); // in case we added a new column
    }
   
    buildTable();
  }
 
  /**
   * Tests whether a value can be set at a position. We can only set values
   * where existing values already exist, or where they are within the bounds
   * of the matrix and would extend a row or column. That is, we cannot allow gaps to
   * exist within an object.
   *
   * @param rowIndex the row index at which to set the value
   * @param columnIndex the column index at which to set the value
   * @param isInsertRow true, if the value should be inserted in a new row prior to the indicated row
   * @param isInsertColumn true, if the value should be inserted in a new column prior to the indicated row
   * @return true, if the value can be set at the position
   */
  public boolean canSetValue(int rowIndex, int columnIndex, boolean isInsertRow, boolean isInsertColumn) {
    if (isInsertRow && isInsertColumn) {
      return false;
    }
    if (rowIndex < 0 || columnIndex < 0) {
      return false;
    }
    if (rowIndex > rowList.size() || columnIndex > columnCount) {
      return false;
    }
   
    // Cannot modify a single element table.
    if (type == TableType.ZERO_DIMENSIONAL) {
      return false;
    }
   
    // Can only set values in column zero for a one dimensional table.
    if (type == TableType.ONE_DIMENSIONAL) {
      if (columnIndex != 0) {
        return false;
      }
      if (isInsertRow) {
        return 0<=rowIndex && rowIndex <= rowList.size();
      } else {
        return 0<=rowIndex && rowIndex < rowList.size();
      }
    }
   
    // Two dimensional case. We have to ensure there is an existing value at the position, or
    // that the position is within the bounds of the matrix and just past the last value.
   
    // Special case of an empty table. We can only insert a row into 0, 0.
    if (rowList.size() == 0) {
      return rowIndex==0 && columnIndex==0 && isInsertRow;
    }
   
    // Can only insert rows at column zero.
    if (isInsertRow) {
      return columnIndex==0 && 0<=rowIndex && rowIndex <= getRowCount();
    }
   
    // Otherwise must set value in an existing row.
    if (rowIndex < 0 || rowIndex >= getRowCount()) {
      return false;
    }

    List<TableCell> row = rowList.get(rowIndex);
    if (isInsertColumn) {
      return 0<=columnIndex && columnIndex <= row.size();
    } else {
      return 0<=columnIndex && columnIndex <= row.size() && columnIndex < columnCount;
    }
  }
 
  /**
   * Get the component that will be modified by insertion at the given location.
   * @param rowIndex the row index.
   * @param columnIndex the column index.
   * @param isInsertRow boolean flag to check for whether can insert row.
   * @param isInsertColumn boolean flag to check for whether can insert column.
   * @return the component whose children will change by this insertion.
   */
  public AbstractComponent getModifiedComponent(int rowIndex, int columnIndex, boolean isInsertRow, boolean isInsertColumn) {
    assert canSetValue(rowIndex, columnIndex, isInsertRow, isInsertColumn);
    assert type != TableType.ZERO_DIMENSIONAL;
   
    if (rowIndex == rowList.size()) {
      return rootComponent;
    }
   
    if (columnIndex == rowList.get(rowIndex).size()) {
      return rowList.get(rowIndex).get(columnIndex - 1).getParent();
    }
   
    // Otherwise, we'll modify the parent of a cell
    return rowList.get(rowIndex).get(columnIndex).getParent();

  }

  /**
   * Gets the type of tabular structure.
   *
   * @return the type of tabular structure.
   */
  public TableType getType() {
    return type;
  }
 
  /**
   * Determine if this component is displayable as a cell within a table.
   * @param comp the abstract component.
   * @return true if the component can be displayed in a table, false if it should be skipped.
   */
  private boolean canEmbedInTable(AbstractComponent comp) {
    return TableViewPolicy.canEmbedInTable(comp);
  }

  private ArrayList<TableRow> rowList;

  private void buildTable () {
    rowList = new ArrayList<TableRow>();

    if (type == TableType.ZERO_DIMENSIONAL) {

      TableRow row = new TableRow();
      row.add(new TableCell(rootComponent, null, 0));
      rowList.add(row);

    } else if (type == TableType.ONE_DIMENSIONAL) {

      int index = 0;
      for (AbstractComponent child : rootComponent.getComponents()) {
        if (canEmbedInTable(child)) {
          TableRow row = new TableRow();
          row.setIndex(index);
          row.add(new TableCell(child, rootComponent, index));
          rowList.add(row);
        }
        index++;
      }

    } else if (type == TableType.TWO_DIMENSIONAL) {

      int parentIndex = 0;
      for (AbstractComponent child : rootComponent.getComponents()) {
        int index = 0;
        TableRow row = new TableRow();
        row.setIndex(parentIndex);
        for (AbstractComponent grandChild : child.getComponents()) {
          if (canEmbedInTable(grandChild)) {
            row.add(new TableCell(grandChild, child, index));
          }
          index++;
        }
        if (!row.isEmpty()) rowList.add(row);
        parentIndex++;
      }

    }
  }
 
  private class TableRow extends ArrayList<TableCell> {
    private static final long serialVersionUID = 6852306825313602935L;
    private int  index = -1;
    public  void setIndex(int index) { this.index=index; }
    public  int  getIndex()          { return index;     }
  }
 
  private class TableCell {
    AbstractComponent value;
    AbstractComponent parent;
    int               index;
   
    public TableCell(AbstractComponent value, AbstractComponent parent, int index) {
      this.value  = value;
      this.parent = parent;
      this.index  = index;
    }
   
    public AbstractComponent getValue() { return value; }
    public int               getIndex() { return index; }
    public AbstractComponent getParent(){ return parent;}
   
  }
 
}
TOP

Related Classes of gov.nasa.arc.mct.table.model.TableStructure$TableRow

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.