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
42using namespace Calligra::Sheets;
43
44class SheetModel::Private
45{
46public:
47 Sheet* sheet;
48};
49
50SheetModel::SheetModel(Sheet* sheet)
51 : QAbstractTableModel(sheet)
52 , d(new Private)
53{
54 d->sheet = sheet;
55}
56
57SheetModel::~SheetModel()
58{
59 delete d;
60}
61
62int 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
70QVariant 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
145Qt::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
164QVariant SheetModel::headerData(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
177QModelIndex 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
195int 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
203bool 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
247bool 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
293bool 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
299Sheet* SheetModel::sheet() const
300{
301 return d->sheet;
302}
303