1 | /* This file is part of the KDE project |
2 | Copyright 2009 Stefan Nikolaus stefan.nikolaus@kdemail.net |
3 | |
4 | This library is free software; you can redistribute it and/or |
5 | modify it under the terms of the GNU Library General Public |
6 | License as published by the Free Software Foundation; either |
7 | version 2 of the License, or (at your option) any later version. |
8 | |
9 | This library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | Library General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Library General Public License |
15 | along with this library; see the file COPYING.LIB. If not, write to |
16 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
17 | Boston, MA 02110-1301, USA. |
18 | */ |
19 | |
20 | #include "SheetModel.h" |
21 | |
22 | // KSpread |
23 | #include "Binding.h" |
24 | #include "Cell.h" |
25 | #include "CellStorage.h" |
26 | #include "Condition.h" |
27 | #include "database/Database.h" |
28 | #include "Formula.h" |
29 | #include "Map.h" |
30 | #include "ModelSupport.h" |
31 | #include "Sheet.h" |
32 | #include "Style.h" |
33 | #include "Validity.h" |
34 | #include "Value.h" |
35 | #include "ValueFormatter.h" |
36 | |
37 | // Qt |
38 | #include <QBrush> |
39 | #include <QItemSelectionRange> |
40 | #include <QSize> |
41 | |
42 | using namespace Calligra::Sheets; |
43 | |
44 | class SheetModel::Private |
45 | { |
46 | public: |
47 | Sheet* sheet; |
48 | }; |
49 | |
50 | SheetModel::SheetModel(Sheet* sheet) |
51 | : QAbstractTableModel(sheet) |
52 | , d(new Private) |
53 | { |
54 | d->sheet = sheet; |
55 | } |
56 | |
57 | SheetModel::~SheetModel() |
58 | { |
59 | delete d; |
60 | } |
61 | |
62 | int SheetModel::columnCount(const QModelIndex& parent) const |
63 | { |
64 | if (parent.isValid() && parent.internalPointer() != d->sheet->map()) { |
65 | return 0; |
66 | } |
67 | return KS_colMax; |
68 | } |
69 | |
70 | QVariant SheetModel::data(const QModelIndex& index, int role) const |
71 | { |
72 | if (!index.isValid()) { |
73 | return QVariant(); |
74 | } |
75 | if (index.model() != this) { |
76 | return QVariant(); |
77 | } |
78 | if (index.internalPointer() != d->sheet) { |
79 | return QVariant(); |
80 | } |
81 | if (index.parent().isValid()) { |
82 | if (index.parent().internalPointer() != d->sheet->map()) { |
83 | return QVariant(); |
84 | } |
85 | } |
86 | // NOTE Model indices start from 0, while KSpread column/row indices start from 1. |
87 | const Cell cell = Cell(d->sheet, index.column() + 1, index.row() + 1).masterCell(); |
88 | const Style style = cell.effectiveStyle(); |
89 | if (role == Qt::DisplayRole) { |
90 | // Display a formula if warranted. If not, simply display the value. |
91 | if (cell.isFormula() && d->sheet->getShowFormula() && |
92 | !(d->sheet->isProtected() && style.hideFormula())) { |
93 | return QVariant(cell.userInput()); |
94 | } else if (d->sheet->getHideZero() && cell.value().isNumber() && cell.value().asFloat() == 0.0) { |
95 | // Hide zero. |
96 | return QVariant(); |
97 | } else if (!cell.isEmpty()) { |
98 | // Format the value appropriately and set the display text. |
99 | // The format of the resulting value is used below to determine the alignment. |
100 | Value value = d->sheet->map()->formatter()->formatText(cell.value(), style.formatType(), |
101 | style.precision(), style.floatFormat(), |
102 | style.prefix(), style.postfix(), |
103 | style.currency().symbol()); |
104 | return value.asString(); |
105 | } |
106 | } else if (role == Qt::EditRole) { |
107 | return cell.userInput(); |
108 | } else if (role == Qt::ToolTipRole) { |
109 | return cell.comment(); |
110 | } else if (role == Qt::SizeHintRole) { |
111 | // TODO |
112 | } else if (role == Qt::FontRole) { |
113 | return style.font(); |
114 | } else if (role == Qt::TextAlignmentRole) { |
115 | // TODO |
116 | } else if (role == Qt::BackgroundRole) { |
117 | return style.backgroundBrush(); |
118 | } else if (role == Qt::BackgroundColorRole) { |
119 | return style.backgroundColor(); |
120 | } else if (role == Qt::ForegroundRole) { |
121 | return style.fontColor(); |
122 | } |
123 | const int column = index.column() + 1; |
124 | const int row = index.row() + 1; |
125 | CellStorage *const storage = d->sheet->cellStorage(); |
126 | switch (role) { |
127 | case UserInputRole: |
128 | return storage->userInput(column, row); |
129 | case FormulaRole: { |
130 | QVariant data; |
131 | data.setValue(storage->formula(column, row)); |
132 | return data; |
133 | } |
134 | case ValueRole: { |
135 | QVariant data; |
136 | data.setValue(storage->value(column, row)); |
137 | return data; |
138 | } |
139 | case LinkRole: |
140 | return storage->link(column, row); |
141 | } |
142 | return QVariant(); |
143 | } |
144 | |
145 | Qt::ItemFlags SheetModel::flags(const QModelIndex& index) const |
146 | { |
147 | if (!index.isValid()) { |
148 | return Qt::NoItemFlags; |
149 | } |
150 | if (index.model() != this) { |
151 | return Qt::NoItemFlags; |
152 | } |
153 | if (index.internalPointer() != d->sheet) { |
154 | return Qt::NoItemFlags; |
155 | } |
156 | if (index.parent().isValid()) { |
157 | if (index.parent().internalPointer() != d->sheet->map()) { |
158 | return Qt::NoItemFlags; |
159 | } |
160 | } |
161 | return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled; |
162 | } |
163 | |
164 | QVariant SheetModel::(int section, Qt::Orientation orientation, int role) const |
165 | { |
166 | // NOTE Model indices start from 0, while KSpread column/row indices start from 1. |
167 | if (role == Qt::DisplayRole) { |
168 | if (orientation == Qt::Horizontal) { |
169 | return Cell::columnName(section + 1); |
170 | } else { |
171 | return QString::number(section + 1); |
172 | } |
173 | } |
174 | return QVariant(); |
175 | } |
176 | |
177 | QModelIndex SheetModel::index(int row, int column, const QModelIndex &parent) const |
178 | { |
179 | if (parent.isValid() && parent.internalPointer() != d->sheet->map()) { |
180 | return QModelIndex(); |
181 | } |
182 | // A cell in our sheet? |
183 | if (!parent.isValid()) { |
184 | return createIndex(row, column, d->sheet); |
185 | // Embedded in a MapModel? |
186 | } else if (parent.internalPointer() == d->sheet->map()) { |
187 | return createIndex(row, column, d->sheet); |
188 | // A sub-table? |
189 | } else if (parent.internalPointer() == this) { |
190 | // TODO sub-tables |
191 | } |
192 | return QModelIndex(); |
193 | } |
194 | |
195 | int SheetModel::rowCount(const QModelIndex& parent) const |
196 | { |
197 | if (parent.isValid() && parent.internalPointer() != d->sheet->map()) { |
198 | return 0; |
199 | } |
200 | return KS_rowMax; |
201 | } |
202 | |
203 | bool SheetModel::setData(const QModelIndex& index, const QVariant& value, int role) |
204 | { |
205 | if (!index.isValid()) { |
206 | return false; |
207 | } |
208 | if (index.model() != this) { |
209 | return false; |
210 | } |
211 | if (index.internalPointer() != d->sheet) { |
212 | return false; |
213 | } |
214 | if (index.parent().isValid()) { |
215 | if (index.parent().internalPointer() != d->sheet->map()) { |
216 | return false; |
217 | } |
218 | } |
219 | // NOTE Model indices start from 0, while KSpread column/row indices start from 1. |
220 | const int column = index.column() + 1; |
221 | const int row = index.row() + 1; |
222 | Cell cell = Cell(sheet(), index.column() + 1, index.row() + 1).masterCell(); |
223 | CellStorage *const storage = d->sheet->cellStorage(); |
224 | switch (role) { |
225 | case Qt::EditRole: |
226 | cell.parseUserInput(value.toString()); |
227 | break; |
228 | case UserInputRole: |
229 | storage->setUserInput(column, row, value.toString()); |
230 | break; |
231 | case FormulaRole: |
232 | storage->setFormula(column, row, value.value<Formula>()); |
233 | break; |
234 | case ValueRole: |
235 | storage->setValue(column, row, value.value<Value>()); |
236 | break; |
237 | case LinkRole: |
238 | storage->setLink(column, row, value.toString()); |
239 | break; |
240 | default: |
241 | return false; |
242 | } |
243 | emit dataChanged(index, index); |
244 | return true; |
245 | } |
246 | |
247 | bool SheetModel::setData(const QItemSelectionRange &range, const QVariant &value, int role) |
248 | { |
249 | const Region region(toRange(range), d->sheet); |
250 | CellStorage *const storage = d->sheet->cellStorage(); |
251 | switch (role) { |
252 | case CommentRole: |
253 | storage->setComment(region, value.toString()); |
254 | break; |
255 | case ConditionRole: |
256 | storage->setConditions(region, value.value<Conditions>()); |
257 | break; |
258 | case FusionedRangeRole: |
259 | // TODO |
260 | // storage->setFusion(region, value.value<bool>()); |
261 | break; |
262 | case LockedRangeRole: |
263 | // TODO |
264 | // storage->setMatrix(region, value.value<bool>()); |
265 | break; |
266 | case NamedAreaRole: { |
267 | QString namedAreaName = value.toString(); |
268 | if (namedAreaName.isEmpty()) |
269 | return false; |
270 | storage->emitInsertNamedArea(region, namedAreaName); |
271 | break; |
272 | } |
273 | case SourceRangeRole: |
274 | storage->setBinding(region, value.value<Binding>()); |
275 | break; |
276 | case StyleRole: |
277 | // TODO |
278 | // storage->setStyle(region, value.value<Style>()); |
279 | break; |
280 | case TargetRangeRole: |
281 | storage->setDatabase(region, value.value<Database>()); |
282 | break; |
283 | case ValidityRole: |
284 | storage->setValidity(region, value.value<Validity>()); |
285 | break; |
286 | default: |
287 | return false; |
288 | } |
289 | emit dataChanged(range.topLeft(), range.bottomRight()); |
290 | return true; |
291 | } |
292 | |
293 | bool SheetModel::setData(const QModelIndex &topLeft, const QModelIndex &bottomRight, |
294 | const QVariant &value, int role) |
295 | { |
296 | return setData(QItemSelectionRange(topLeft, bottomRight), value, role); |
297 | } |
298 | |
299 | Sheet* SheetModel::sheet() const |
300 | { |
301 | return d->sheet; |
302 | } |
303 | |