1/* This file is part of the KDE project
2 Copyright (C) 2003,2004 Ariya Hidayat <ariya@kde.org>
3 Copyright (C) 2005 Tomas Mecir <mecirt@gmail.com>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; only
8 version 2 of the License.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21// Local
22#include "Function.h"
23
24#include "Value.h"
25
26using namespace Calligra::Sheets;
27
28class Function::Private
29{
30public:
31 QString name;
32 QString alternateName;
33 FunctionPtr ptr;
34 int paramMin, paramMax;
35 bool acceptArray;
36 bool ne; // need FunctionExtra* when called ?
37};
38
39Function::Function(const QString& name, FunctionPtr ptr)
40 : d(new Private)
41{
42 d->name = name;
43 d->ptr = ptr;
44 d->acceptArray = false;
45 d->paramMin = 1;
46 d->paramMax = 1;
47 d->ne = false;
48}
49
50Function::~Function()
51{
52 delete d;
53}
54
55QString Function::name() const
56{
57 return d->name;
58}
59
60QString Function::alternateName() const
61{
62 return d->alternateName;
63}
64
65void Function::setAlternateName(const QString &name)
66{
67 d->alternateName = name;
68}
69
70void Function::setParamCount(int min, int max)
71{
72 d->paramMin = min;
73 d->paramMax = (max == 0) ? min : max;
74}
75
76bool Function::paramCountOkay(int count)
77{
78 // less than needed
79 if (count < d->paramMin) return false;
80 // no upper limit
81 if (d->paramMax == -1) return true;
82 // more than needed
83 if (count > d->paramMax) return false;
84 // okay otherwise
85 return true;
86}
87
88void Function::setAcceptArray(bool accept)
89{
90 d->acceptArray = accept;
91}
92
93bool Function::needsExtra()
94{
95 return d->ne;
96}
97void Function::setNeedsExtra(bool extra)
98{
99 d->ne = extra;
100}
101
102Value Function::exec(valVector args, ValueCalc *calc, FuncExtra *extra)
103{
104 // check number of parameters
105 if (!paramCountOkay(args.count()))
106 return Value::errorVALUE();
107
108 if (extra)
109 extra->function = this;
110
111 // do we need to perform array expansion ?
112 bool mustExpandArray = false;
113 if (!d->acceptArray)
114 for (int i = 0; i < args.count(); ++i) {
115 if (args[i].isArray())
116 mustExpandArray = true;
117 }
118
119 if (!d->ptr) return Value::errorVALUE();
120
121 // perform the actual array expansion if need be
122
123 if (mustExpandArray) {
124 // compute number of rows/cols of the result
125 int rows = 0;
126 int cols = 0;
127 for (int i = 0; i < args.count(); ++i) {
128 int x = 1;
129 if (extra) x = extra->ranges[i].rows();
130 if (x > rows) rows = x;
131 if (extra) x = extra->ranges[i].columns();
132 if (x > cols) cols = x;
133 }
134 // allocate the resulting array
135 Value res(Value::Array);
136 // perform the actual computation for each element of the array
137 for (int row = 0; row < rows; ++row)
138 for (int col = 0; col < cols; ++col) {
139 // fill in the parameter vector
140 valVector vals(args.count());
141 FuncExtra extra2 = *extra;
142 for (int i = 0; i < args.count(); ++i) {
143 int r = extra->ranges[i].rows();
144 int c = extra->ranges[i].columns();
145 vals[i] = args[i].isArray() ?
146 args[i].element(col % c, row % r) : args[i];
147
148 // adjust the FuncExtra structure to refer to the correct cells
149 extra2.ranges[i].col1 += col;
150 extra2.ranges[i].row1 += row;
151 extra2.ranges[i].col2 = extra2.ranges[i].col1;
152 extra2.ranges[i].row2 = extra2.ranges[i].row1;
153 }
154 // execute the function on each element
155 res.setElement(col, row, exec(vals, calc, &extra2));
156 }
157 return res;
158 } else
159 // call the function
160 return (*d->ptr)(args, calc, extra);
161}
162
163FunctionCaller::FunctionCaller(FunctionPtr ptr, const valVector &args, ValueCalc *calc, FuncExtra *extra)
164 : m_ptr(ptr), m_args(args), m_calc(calc), m_extra(extra)
165{
166}
167
168Value FunctionCaller::exec()
169{
170 return (*m_ptr)(m_args, m_calc, m_extra);
171}
172
173Value FunctionCaller::exec(const valVector &args)
174{
175 return (*m_ptr)(args, m_calc, m_extra);
176}
177