Skip to content
45 changes: 29 additions & 16 deletions main/HSSF/UserModel/OperationEvaluatorFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,31 +82,44 @@ public static ValueEval evaluate(OperationPtg ptg, ValueEval[] args,
}
Function result = _instancesByPtgClass[ptg];

FreeRefFunction udfFunc = null;
if(result == null)
{
if(ptg is AbstractFunctionPtg) {
AbstractFunctionPtg fptg = (AbstractFunctionPtg)ptg;
int functionIndex = fptg.FunctionIndex;
switch(functionIndex)
{
case FunctionMetadataRegistry.FUNCTION_INDEX_INDIRECT:
udfFunc = Indirect.instance;
break;
case FunctionMetadataRegistry.FUNCTION_INDEX_EXTERNAL:
udfFunc = UserDefinedFunction.instance;
break;
default:
result = FunctionEval.GetBasicFunction(functionIndex);
break;
}
}
}

if(result != null)
{
IEvaluationSheet evalSheet = ec.GetWorkbook().GetSheet(ec.SheetIndex);
IEvaluationCell evalCell = evalSheet.GetCell(ec.RowIndex, ec.ColumnIndex);

if(evalCell.IsPartOfArrayFormulaGroup && result is IArrayFunction)
return ((IArrayFunction) result).EvaluateArray(args, ec.RowIndex, ec.ColumnIndex);
if(evalCell != null && (evalCell.IsPartOfArrayFormulaGroup || ec.IsArraymode)
&& result is ArrayFunction)

return result.Evaluate(args, ec.RowIndex, (short) ec.ColumnIndex);
}
return ((IArrayFunction) result).EvaluateArray(args, ec.RowIndex, ec.ColumnIndex);

if(ptg is AbstractFunctionPtg)
return result.Evaluate(args, ec.RowIndex, ec.ColumnIndex);
}
else if(udfFunc != null)
{
AbstractFunctionPtg fptg = (AbstractFunctionPtg)ptg;
int functionIndex = fptg.FunctionIndex;
switch(functionIndex)
{
case FunctionMetadataRegistry.FUNCTION_INDEX_INDIRECT:
return Indirect.instance.Evaluate(args, ec);
case FunctionMetadataRegistry.FUNCTION_INDEX_EXTERNAL:
return UserDefinedFunction.instance.Evaluate(args, ec);
}

return FunctionEval.GetBasicFunction(functionIndex).Evaluate(args, ec.RowIndex, (short) ec.ColumnIndex);
return udfFunc.Evaluate(args, ec);
}

throw new RuntimeException("Unexpected operation ptg class (" + ptg.GetType().Name + ")");
}
}
Expand Down
2 changes: 1 addition & 1 deletion main/SS/Formula/Eval/OperandResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ private static ValueEval ChooseSingleElementFromAreaInternal(AreaEval ae,
// multi-column, multi-row area
if (ae.ContainsRow(srcCellRow) && ae.ContainsColumn(srcCellCol))
{
return ae.GetAbsoluteValue(ae.FirstRow, ae.FirstColumn);
return ae.GetAbsoluteValue(srcCellRow, srcCellCol);
}
throw EvaluationException.InvalidValue();
}
Expand Down
33 changes: 33 additions & 0 deletions main/SS/Formula/Functions/ArrayMode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/* ====================================================================
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.
==================================================================== */

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace NPOI.SS.Formula.Functions
{
/// <summary>
/// Interface for those functions that evaluate arguments in array mode depending on context.
/// </summary>
public interface IArrayMode
{

}
}
2 changes: 1 addition & 1 deletion main/SS/Formula/Functions/Index.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ namespace NPOI.SS.Formula.Functions
*
* @author Josh Micich
*/
public class Index : Function2Arg, Function3Arg, Function4Arg
public class Index : Function2Arg, Function3Arg, Function4Arg, IArrayMode
{

public ValueEval Evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1)
Expand Down
33 changes: 31 additions & 2 deletions main/SS/Formula/WorkbookEvaluator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -424,11 +424,12 @@ private ValueEval EvaluateAny(IEvaluationCell srcCell, int sheetIndex,
{
return ErrorEval.CIRCULAR_REF_ERROR;
}
OperationEvaluationContext ec = new OperationEvaluationContext(this, _workbook, sheetIndex, rowIndex, columnIndex, tracker);

try
{
Ptg[] ptgs = _workbook.GetFormulaTokens(srcCell);
OperationEvaluationContext ec = new OperationEvaluationContext
(this, _workbook, sheetIndex, rowIndex, columnIndex, tracker);
if (evalListener == null)
{
result = EvaluateFormula(ec, ptgs);
Expand Down Expand Up @@ -725,11 +726,39 @@ public ValueEval EvaluateFormula(OperationEvaluationContext ec, Ptg[] ptgs)
ValueEval[] ops = new ValueEval[numops];

// storing the ops in reverse order since they are popping
bool areaArg = false; // whether one of the operands is an area
for (int j = numops - 1; j >= 0; j--)
{
ValueEval p = (ValueEval)stack.Pop();
ops[j] = p;
if(p is AreaEval)
{
areaArg = true;
}
}
bool arrayMode = false;
if(areaArg)
for(int ii = i; ii < iSize; ii++)
{
if(ptgs[ii] is FuncVarPtg)
{
FuncVarPtg f = (FuncVarPtg)ptgs[ii];
try
{
Functions.Function func = FunctionEval.GetBasicFunction(f.FunctionIndex);
if(func != null && func is IArrayMode) {
arrayMode = true;
}
}
catch(NotImplementedException ne)
{
//FunctionEval.getBasicFunction can throw NotImplementedException
// if the fucntion is not yet supported.
}
break;
}
}
ec.IsArraymode = arrayMode;
// logDebug("Invoke " + operation + " (nAgs=" + numops + ")");
opResult = OperationEvaluatorFactory.Evaluate(optg, ops, ec);
}
Expand Down Expand Up @@ -854,7 +883,7 @@ public static ValueEval DereferenceResult(ValueEval evaluationResult, OperationE
IEvaluationSheet evalSheet = ec.GetWorkbook().GetSheet(ec.SheetIndex);
IEvaluationCell evalCell = evalSheet.GetCell(ec.RowIndex, ec.ColumnIndex);

if (evalCell.IsPartOfArrayFormulaGroup && evaluationResult is AreaEval eval)
if (evalCell != null && evalCell.IsPartOfArrayFormulaGroup && evaluationResult is AreaEval eval)
{
value = OperandResolver.GetElementFromArray(eval, evalCell);
}
Expand Down
70 changes: 63 additions & 7 deletions ooxml/XSSF/Model/SharedStringsTable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ namespace NPOI.XSSF.Model
using System.IO;
using NPOI.OpenXml4Net.OPC;
using System.Xml;
using NPOI.Util;
using NPOI.XSSF.UserModel;
using NPOI.SS.UserModel;
using System.Text;

/**
Expand Down Expand Up @@ -523,18 +526,28 @@ private static String GetKey(CT_Rst st)
return st.XmlText;
}

/**
* Return a string item by index
*
* @param idx index of item to return.
* @return the item at the specified position in this Shared String table.
*/
/// <summary>
/// Return a string item by index
/// </summary>
/// <param name="idx">index of item to return.</param>
/// <returns>the item at the specified position in this Shared String table.</returns>
[Obsolete("use GetItemAt(int idx) instead. Removal at POI 4.2")]
public CT_Rst GetEntryAt(int idx)
{
EnsureLoaded();
return strings[idx];
}

/// <summary>
/// Return a string item by index
/// </summary>
/// <param name="idx">index of item to return.</param>
/// <returns>the item at the specified position in this Shared String table.</returns>
public IRichTextString GetItemAt(int idx)
{
return new XSSFRichTextString(strings[idx]);
}

/**
* Return an integer representing the total count of strings in the workbook. This count does not
* include any numbers, it counts only the total of text strings in the workbook.
Expand Down Expand Up @@ -577,6 +590,8 @@ public int UniqueCount
* @param st the entry to add
* @return index the index of Added entry
*/
[Obsolete("use <code>addSharedStringItem(RichTextString string)</code> instead")]
[Removal(Version = "4.2")]
public int AddEntry(CT_Rst st)
{
EnsureLoaded();
Expand All @@ -600,11 +615,33 @@ public int AddEntry(CT_Rst st)
return idx;
}

/**
* Add an entry to this Shared String table (a new value is appended to the end).
*
* <p>
* If the Shared String table already contains this string entry, its index is returned.
* Otherwise a new entry is added.
* </p>
*
* @param string the entry to add
* @since POI 4.0.0
* @return index the index of added entry
*/
public int AddSharedStringItem(IRichTextString str)
{
if(!(str is XSSFRichTextString)){
throw new ArgumentException("Only XSSFRichTextString argument is supported");
}
return AddEntry(((XSSFRichTextString) str).GetCTRst());
}

/**
* Provide low-level access to the underlying array of CT_Rst beans
*
* @return array of CT_Rst beans
*/
[Obsolete("use <code>getSharedStringItems</code> instead")]
[Removal(Version = "4.2")]
public IList<CT_Rst> Items
{
get
Expand All @@ -615,8 +652,27 @@ public IList<CT_Rst> Items
}

/**
* Write this table out as XML.
* Provide access to the strings in the SharedStringsTable
*
* @return list of shared string instances
*/
public IList<IRichTextString> SharedStringItems
{
get
{
List<IRichTextString> items = new List<IRichTextString>();
foreach(CT_Rst rst in strings)
{
items.Add(new XSSFRichTextString(rst));
}
return items.AsReadOnly();
}
}

/**
*
* this table out as XML.
*
* @param out The stream to write to.
* @throws IOException if an error occurs while writing.
*/
Expand Down
2 changes: 1 addition & 1 deletion ooxml/XSSF/UserModel/Extensions/XSSFCellBorder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ public XSSFColor GetBorderColor(BorderSide side)

if (borderPr != null && borderPr.IsSetColor())
{
XSSFColor clr = new XSSFColor(borderPr.color, _indexedColorMap);
XSSFColor clr = XSSFColor.From(borderPr.color, _indexedColorMap);
if (_theme != null)
{
_theme.InheritFromThemeAsRequired(clr);
Expand Down
24 changes: 20 additions & 4 deletions ooxml/XSSF/UserModel/Extensions/XSSFCellFill.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public XSSFColor GetFillBackgroundColor()
if (ptrn == null) return null;

CT_Color CT_Color = ptrn.bgColor;
return CT_Color == null ? null : new XSSFColor(CT_Color, _indexedColorMap);
return XSSFColor.From(CT_Color, _indexedColorMap);
}

/**
Expand All @@ -84,7 +84,15 @@ public void SetFillBackgroundColor(int index)
public void SetFillBackgroundColor(XSSFColor color)
{
CT_PatternFill ptrn = EnsureCTPatternFill();
ptrn.bgColor = (color.GetCTColor());

if(color == null)
{
ptrn.UnsetBgColor();
}
else
{
ptrn.bgColor = (color.GetCTColor());
}
}

/**
Expand All @@ -98,7 +106,7 @@ public XSSFColor GetFillForegroundColor()
if (ptrn == null) return null;

CT_Color ctColor = ptrn.fgColor;
return ctColor == null ? null : new XSSFColor(ctColor, _indexedColorMap);
return XSSFColor.From(ctColor, _indexedColorMap);
}

/**
Expand All @@ -121,7 +129,15 @@ public void SetFillForegroundColor(int index)
public void SetFillForegroundColor(XSSFColor color)
{
CT_PatternFill ptrn = EnsureCTPatternFill();
ptrn.fgColor = color.GetCTColor();

if(color == null)
{
ptrn.UnsetFgColor();
}
else
{
ptrn.fgColor = color.GetCTColor();
}
}

/**
Expand Down
2 changes: 1 addition & 1 deletion ooxml/XSSF/UserModel/XSSFBorderFormatting.cs
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ private static short GetIndexedColor(XSSFColor color)

private XSSFColor GetColor(CT_BorderPr pr)
{
return pr == null ? null : new XSSFColor(pr.color, _colorMap);
return pr == null ? null : XSSFColor.From(pr.color, _colorMap);
}
#endregion
}
Expand Down
Loading
Loading