Package org.formulacompiler.spreadsheet.internal

Source Code of org.formulacompiler.spreadsheet.internal.CellRange$Tiler

/*
* Copyright (c) 2006-2009 by Abacus Research AG, Switzerland.
* All rights reserved.
*
* This file is part of the Abacus Formula Compiler (AFC).
*
* For commercial licensing, please contact sales(at)formulacompiler.com.
*
* AFC is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AFC is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AFC.  If not, see <http://www.gnu.org/licenses/>.
*/

package org.formulacompiler.spreadsheet.internal;

import org.formulacompiler.compiler.internal.AbstractDescribable;
import org.formulacompiler.compiler.internal.DescriptionBuilder;
import org.formulacompiler.runtime.internal.spreadsheet.RangeAddressImpl;
import org.formulacompiler.runtime.spreadsheet.RangeAddress;
import org.formulacompiler.spreadsheet.Orientation;
import org.formulacompiler.spreadsheet.Spreadsheet;
import org.formulacompiler.spreadsheet.SpreadsheetException;

public abstract class CellRange extends AbstractDescribable implements Spreadsheet.Range, Iterable<CellIndex>
{


  public static CellRange getCellRange( CellIndex _from, CellIndex _to )
  {
    if (_from.equals( _to )) {
      return _from;
    }
    else {
      return new MultiCellRange( _from, _to );
    }
  }

  public static CellRange getEntireWorkbook( BaseSpreadsheet _spreadsheet )
  {
    return getCellRange( CellIndex.getTopLeft( _spreadsheet ), CellIndex.getBottomRight( _spreadsheet ) );
  }


  public abstract CellIndex getFrom();


  public abstract CellIndex getTo();


  public abstract CellRange clone( int _colOffset, int _rowOffset );


  public boolean overlaps( CellRange _other, Orientation _orientation )
  {
    int l1 = this.getFrom().getIndex( _orientation );
    int r1 = this.getTo().getIndex( _orientation );
    int l2 = _other.getFrom().getIndex( _orientation );
    int r2 = _other.getTo().getIndex( _orientation );
    return !(l2 > r1 || l1 > r2);
  }


  /**
   * Let's say range B2:B20 is called "Amount". Then, you can put the formula "=Amount*1.07" into,
   * say, D2:D20. It will be automatically infered that "Amount" here means the respective cell on
   * the same row from "Amount". So, when a cell formula references a range in a position where a
   * single value is expected, it calls that range's <code>getCellIndexRelativeTo(this)</code>.
   * This works for single-column and single-row ranges.
   * <p>
   * If the range consists of only one cell, this cell is returned.
   *
   * @param _cell base cell.
   * @return relative cell in the range.
   * @throws SpreadsheetException if range is not unidimensional.
   */
  public abstract CellIndex getCellIndexRelativeTo( CellIndex _cell ) throws SpreadsheetException;


  /**
   * Returns cell or range name in A1 format without symbols that indicate absolute reference.
   *
   * @return cell or range name without $ symbols.
   */
  public String getShortName()
  {
    DescriptionBuilder description = new DescriptionBuilder();
    description.pushContext( DescribeShortStyle.getInstance() );
    describeTo( description );
    return description.toString();
  }

  public RangeAddress getRangeAddress()
  {
    final CellIndex from = getFrom();
    final CellIndex to = getTo();
    return new RangeAddressImpl( from.getCellAddress(), to.getCellAddress() );
  }


  // Result lengths for tilingAround:
  public static final int NO_INTERSECTION = 0;
  public static final int CONTAINED = 1;
  public static final int FLOW_TILES = 3;
  public static final int TILES = 9;

  // Result indices for tilingAround with length is FLOW_TILES:
  public static final int FLOW_BEFORE = 0;
  public static final int FLOW_INNER = 1;
  public static final int FLOW_AFTER = 2;

  // Result indices for tilingAround with length is TILES:
  public static final int TILE_TL = 0;
  public static final int TILE_T = 1;
  public static final int TILE_TR = 2;
  public static final int TILE_L = 3;
  public static final int TILE_I = 4;
  public static final int TILE_R = 5;
  public static final int TILE_BL = 6;
  public static final int TILE_B = 7;
  public static final int TILE_BR = 8;

  /**
   * Returns either an empty array (no intersection), a 1-long array (containment), or a 9-long
   * array (tiling) (see CellRangeTiler).
   */
  public CellRange[] tilingAround( CellRange _inner )
  {
    if (_inner.contains( this )) {
      return new CellRange[] { this };
    }
    else if (_inner.overlaps( this, Orientation.VERTICAL ) && _inner.overlaps( this, Orientation.HORIZONTAL )) {
      return new Tiler( _inner, this ).tiling();
    }
    else {
      return new CellRange[ NO_INTERSECTION ];
    }
  }

  /**
   * Returns either an empty array (no intersection), a 1-long array (containment), a 3-long array
   * (flow tiling), or a 9-long array (full tiling) (see CellRangeTiler).
   * <p>
   * A flow tiiling contains either null, or the tile in the sequence B I A, where B is before, I
   * is inner, A is after.
   */
  public CellRange[] tilingAround( CellRange _inner, Orientation _flow )
  {
    if (_inner.contains( this )) {
      return new CellRange[] { _inner };
    }
    else if (_inner.overlaps( this, Orientation.VERTICAL ) && _inner.overlaps( this, Orientation.HORIZONTAL )) {
      final CellRange[] tiling = new Tiler( _inner, this ).tiling();
      return (_flow == Orientation.VERTICAL) ? detectFlowTilingIn( tiling, TILE_T, TILE_B ) : detectFlowTilingIn(
          tiling, TILE_L, TILE_R );
    }
    else {
      return new CellRange[ NO_INTERSECTION ];
    }
  }

  private CellRange[] detectFlowTilingIn( CellRange[] _tiling, int _tileBefore, int _tileAfter )
  {
    for (int iTile = 0; iTile < _tiling.length; iTile++) {
      if (iTile != TILE_I && iTile != _tileBefore && iTile != _tileAfter) {
        if (_tiling[ iTile ] != null) return _tiling;
      }
    }
    return new CellRange[] { _tiling[ _tileBefore ], _tiling[ TILE_I ], _tiling[ _tileAfter ] };
  }


  /**
   * Computes a 3x3 tiling of a range "tiled" so that the inner tile contains its intersection with
   * a range "inner". All the tiles are either null, or the respective part of "tiled". The
   * resulting array contains the tiles, with the following figure read left-to-right, then
   * top-to-bottom:
   *
   * <pre>
   *  TL T  TR
   *  L  I  R
   *  BL B  BR
   * </pre>
   *
   * where I is the inner intersection, and L, R, T, B are left, right, top, bottom.
   */
  @SuppressWarnings( "unqualified-field-access" )
  final static class Tiler
  {
    private final CellIndex i_tl;
    private final CellIndex i_br;
    private final CellIndex t_tl;
    private final CellIndex t_br;
    private final BaseSpreadsheet ss;
    private final int si;
    private final CellRange[] results;

    /**
     * The intersection of _inner and _tiled must not be empty.
     */
    public Tiler( CellRange _inner, CellRange _tiled )
    {
      super();
      i_tl = _inner.getFrom();
      i_br = _inner.getTo();
      t_tl = _tiled.getFrom();
      t_br = _tiled.getTo();
      ss = i_tl.spreadsheet;
      si = i_tl.getSheetIndex();
      results = new CellRange[ TILES ];
    }

    public CellRange[] tiling()
    {
      intersect();
      return results;
    }

    private void intersect()
    {
      int i_b;
      if (t_br.getRowIndex() > i_br.getRowIndex()) {
        intersectRow( TILE_BL, TILE_B, TILE_BR, i_br.getRowIndex() + 1, t_br.getRowIndex() );
        i_b = i_br.getRowIndex();
      }
      else {
        i_b = t_br.getRowIndex();
      }
      if (t_tl.getRowIndex() < i_tl.getRowIndex()) {
        intersectRow( TILE_TL, TILE_T, TILE_TR, t_tl.getRowIndex(), i_tl.getRowIndex() - 1 );
        intersectRow( TILE_L, TILE_I, TILE_R, i_tl.getRowIndex(), i_b );
      }
      else {
        intersectRow( TILE_L, TILE_I, TILE_R, t_tl.getRowIndex(), i_b );
      }
    }

    private void intersectRow( int _left, int _mid, int _right, int _top, int _bottom )
    {
      int i_r;
      if (t_br.getColumnIndex() > i_br.getColumnIndex()) {
        results[ _right ] = cr( i_br.getColumnIndex() + 1, t_br.getColumnIndex(), _top, _bottom );
        i_r = i_br.getColumnIndex();
      }
      else {
        i_r = t_br.getColumnIndex();
      }
      if (t_tl.getColumnIndex() < i_tl.getColumnIndex()) {
        results[ _left ] = cr( t_tl.getColumnIndex(), i_tl.getColumnIndex() - 1, _top, _bottom );
        results[ _mid ] = cr( i_tl.getColumnIndex(), i_r, _top, _bottom );
      }
      else {
        results[ _mid ] = cr( t_tl.getColumnIndex(), i_r, _top, _bottom );
      }
    }

    private CellRange cr( int l, int r, int t, int b )
    {
      return getCellRange( new CellIndex( ss, si, l, t ), new CellIndex( ss, si, r, b ) );
    }

  }

}
TOP

Related Classes of org.formulacompiler.spreadsheet.internal.CellRange$Tiler

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.