/* ====================================================================
Licensed to the Apache Software Foundation (ASF) Under one or more
contributor license agreements. See the NOTICE file distributed with
this work for Additional information regarding copyright ownership.
The ASF licenses this file to You 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.
==================================================================== */
namespace HH.WMS.Utils.NPOI.SS.Util
{
using System;
using System.Text;
using System.Collections;
using HH.WMS.Utils.NPOI.SS.Formula;
public class AreaReference
{
/** The Char (!) that Separates sheet names from cell references */
private const char SHEET_NAME_DELIMITER = '!';
/** The Char (:) that Separates the two cell references in a multi-cell area reference */
private const char CELL_DELIMITER = ':';
/** The Char (') used to quote sheet names when they contain special Chars */
private const char SPECIAL_NAME_DELIMITER = '\'';
private CellReference _firstCell;
private CellReference _lastCell;
private bool _isSingleCell;
/**
* Create an area ref from a string representation. Sheet names containing special Chars should be
* delimited and escaped as per normal syntax rules for formulas.
* The area reference must be contiguous (i.e. represent a single rectangle, not a Union of rectangles)
*/
public AreaReference(String reference)
{
if (!IsContiguous(reference))
{
throw new ArgumentException(
"References passed to the AreaReference must be contiguous, " +
"use generateContiguous(ref) if you have non-contiguous references");
}
String[] parts = SeparateAreaRefs(reference);
String part0 = parts[0];
if (parts.Length == 1)
{
// TODO - probably shouldn't initialize area ref when text is really a cell ref
// Need to fix some named range stuff to get rid of this
_firstCell = new CellReference(part0);
_lastCell = _firstCell;
_isSingleCell = true;
return;
}
if (parts.Length != 2)
{
throw new ArgumentException("Bad area ref '" + reference + "'");
}
String part1 = parts[1];
if (IsPlainColumn(part0))
{
if (!IsPlainColumn(part1))
{
throw new Exception("Bad area ref '" + reference + "'");
}
// Special handling for whole-column references
// Represented internally as x$1 to x$65536
// which is the maximum range of rows
bool firstIsAbs = CellReference.IsPartAbsolute(part0);
bool lastIsAbs = CellReference.IsPartAbsolute(part1);
int col0 = CellReference.ConvertColStringToIndex(part0);
int col1 = CellReference.ConvertColStringToIndex(part1);
_firstCell = new CellReference(0, col0, true, firstIsAbs);
_lastCell = new CellReference(0xFFFF, col1, true, lastIsAbs);
_isSingleCell = false;
// TODO - whole row refs
}
else
{
_firstCell = new CellReference(part0);
_lastCell = new CellReference(part1);
_isSingleCell = part0.Equals(part1);
}
}
private bool IsPlainColumn(String refPart)
{
for (int i = refPart.Length - 1; i >= 0; i--)
{
int ch = refPart[i];
if (ch == '$' && i == 0)
{
continue;
}
if (ch < 'A' || ch > 'Z')
{
return false;
}
}
return true;
}
public static AreaReference GetWholeRow(String start, String end)
{
return new AreaReference("$A" + start + ":$IV" + end);
}
public static AreaReference GetWholeColumn(String start, String end)
{
return new AreaReference(start + "$1:" + end + "$65536");
}
/**
* Creates an area ref from a pair of Cell References.
*/
public AreaReference(CellReference topLeft, CellReference botRight)
{
//_firstCell = topLeft;
//_lastCell = botRight;
//_isSingleCell = false;
bool swapRows = topLeft.Row > botRight.Row;
bool swapCols = topLeft.Col > botRight.Col;
if (swapRows || swapCols)
{
int firstRow;
int lastRow;
int firstColumn;
int lastColumn;
bool firstRowAbs;
bool lastRowAbs;
bool firstColAbs;
bool lastColAbs;
if (swapRows)
{
firstRow = botRight.Row;
firstRowAbs = botRight.IsRowAbsolute;
lastRow = topLeft.Row;
lastRowAbs = topLeft.IsRowAbsolute;
}
else
{
firstRow = topLeft.Row;
firstRowAbs = topLeft.IsRowAbsolute;
lastRow = botRight.Row;
lastRowAbs = botRight.IsRowAbsolute;
}
if (swapCols)
{
firstColumn = botRight.Col;
firstColAbs = botRight.IsColAbsolute;
lastColumn = topLeft.Col;
lastColAbs = topLeft.IsColAbsolute;
}
else
{
firstColumn = topLeft.Col;
firstColAbs = topLeft.IsColAbsolute;
lastColumn = botRight.Col;
lastColAbs = botRight.IsColAbsolute;
}
_firstCell = new CellReference(firstRow, firstColumn, firstRowAbs, firstColAbs);
_lastCell = new CellReference(lastRow, lastColumn, lastRowAbs, lastColAbs);
}
else
{
_firstCell = topLeft;
_lastCell = botRight;
}
_isSingleCell = false;
}
/**
* is the reference for a contiguous (i.e.
* Unbroken) area, or is it made up of
* several different parts?
* (If it Is, you will need to call
* ....
*/
public static bool IsContiguous(String reference)
{
if (reference.IndexOf(',') == -1)
{
return true;
}
return false;
}
/**
* is the reference for a whole-column reference,
* such as C:C or D:G ?
*/
public static bool IsWholeColumnReference(CellReference topLeft, CellReference botRight)
{
// These are represented as something like
// C$1:C$65535 or D$1:F$0
// i.e. absolute from 1st row to 0th one
if (topLeft.Row == 0 && topLeft.IsRowAbsolute &&
(botRight.Row == -1 || botRight.Row == 65535) && botRight.IsRowAbsolute)
{
return true;
}
return false;
}
public bool IsWholeColumnReference()
{
return IsWholeColumnReference(_firstCell, _lastCell);
}
/**
* Takes a non-contiguous area reference, and
* returns an array of contiguous area references.
*/
public static AreaReference[] GenerateContiguous(String reference)
{
ArrayList refs = new ArrayList();
String st = reference;
string[] token = st.Split(',');
foreach (string t in token)
{
refs.Add(
new AreaReference(t)
);
}
return (AreaReference[])refs.ToArray(typeof(AreaReference));
}
/**
* @return
Result | Comment |
---|---|
A1:A1 | Single cell area reference without sheet |
A1:$C$1 | Multi-cell area reference without sheet |
Sheet1!A$1:B4 | Standard sheet name |
'O''Brien''s Sales'!B5:C6' | Sheet name with special Chars |