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 "MapModel.h"
21
22#include "Map.h"
23#include "ModelSupport.h"
24#include "Sheet.h"
25#include "SheetModel.h"
26
27#include "commands/SheetCommands.h"
28
29#include <KoIcon.h>
30
31using namespace Calligra::Sheets;
32
33class MapModel::Private
34{
35public:
36 Map* map;
37
38public:
39 bool isSheetIndex(const QModelIndex& index, const MapModel* mapModel) const;
40};
41
42bool MapModel::Private::isSheetIndex(const QModelIndex& index, const MapModel* mapModel) const
43{
44 if (!index.parent().isValid()) {
45 return false;
46 }
47 // If it is a cell, the parent's (the sheet's) model has to be this model.
48 if (index.parent().model() != mapModel || index.parent().internalPointer() != map) {
49 return false;
50 }
51 // If it is a cell, the parent (the sheet) has no parent.
52 if (index.parent().parent().isValid()) {
53 return false;
54 }
55 // Do not exceed the sheet list.
56 if (index.parent().row() >= map->count()) {
57 return false;
58 }
59 // The index' (the cell's) model has to match the sheet model.
60 if (index.model() != map->sheet(index.parent().row())->model()) {
61 return false;
62 }
63 return true;
64}
65
66
67MapModel::MapModel(Map* map)
68 : QAbstractListModel(map)
69 , d(new Private)
70{
71 d->map = map;
72 connect(d->map, SIGNAL(sheetAdded(Sheet*)),
73 this, SLOT(addSheet(Sheet*)));
74 connect(d->map, SIGNAL(sheetRemoved(Sheet*)),
75 this, SLOT(removeSheet(Sheet*)));
76}
77
78MapModel::~MapModel()
79{
80 delete d;
81}
82
83QVariant MapModel::data(const QModelIndex &index, int role) const
84{
85 if (!index.isValid()) {
86 return QVariant();
87 }
88 // Propagation to sheet model
89 if (d->isSheetIndex(index, this)) {
90 return d->map->sheet(index.parent().row())->model()->data(index, role);
91 }
92 if (index.row() >= d->map->count()) {
93 return QVariant();
94 }
95 //
96 const Sheet* const sheet = d->map->sheet(index.row());
97 switch (role) {
98 case Qt::DisplayRole:
99 case Qt::EditRole:
100 return QVariant(sheet->sheetName());
101 case Qt::DecorationRole:
102 return QVariant(koIcon("x-office-spreadsheet"));
103 case VisibilityRole:
104 return QVariant(!sheet->isHidden());
105 case ProtectionRole:
106 return QVariant(sheet->isProtected());
107 default:
108 break;
109 }
110 return QVariant();
111}
112
113Qt::ItemFlags MapModel::flags(const QModelIndex &index) const
114{
115 if (!index.isValid()) {
116 return Qt::NoItemFlags;
117 }
118 // Propagation to sheet model
119 if (d->isSheetIndex(index, this)) {
120 return d->map->sheet(index.parent().row())->model()->flags(index);
121 }
122 if (index.row() >= d->map->count()) {
123 return Qt::NoItemFlags;
124 }
125
126 Qt::ItemFlags flags = Qt::ItemIsEnabled;
127 if (!d->map->isProtected()) {
128 flags |= Qt::ItemIsSelectable;
129 const Sheet* const sheet = d->map->sheet(index.row());
130 if (!sheet->isProtected()) {
131 flags |= Qt::ItemIsEditable;
132 }
133 }
134 return flags;
135}
136
137QVariant MapModel::headerData(int section, Qt::Orientation orientation, int role) const
138{
139 Q_UNUSED(orientation)
140 if (section == 0 && role == Qt::DisplayRole) {
141 return QVariant(i18n("Sheet name"));
142 }
143 return QVariant();
144}
145
146QModelIndex MapModel::index(int row, int column, const QModelIndex &parent) const
147{
148 QModelIndex index;
149 if (parent.isValid()) {
150 // If it is a cell, the parent's (the sheet's) model has to be this model.
151 if (parent.model() != this || parent.internalPointer() != d->map) {
152 return QModelIndex();
153 }
154 // If it is a cell, the parent (the sheet) has no parent.
155 if (parent.parent().isValid()) {
156 return QModelIndex();
157 }
158 // Do not exceed the sheet list.
159 if (parent.row() >= d->map->count()) {
160 return QModelIndex();
161 }
162 Sheet* const sheet = d->map->sheet(index.parent().row());
163 index = sheet->model()->index(row, column, parent);
164 } else {
165 index = createIndex(row, column, d->map);
166 }
167 return index;
168}
169
170int MapModel::rowCount(const QModelIndex &parent) const
171{
172 if (parent.isValid()) {
173 return 0;
174 }
175 return d->map->count();
176}
177
178bool MapModel::setData(const QModelIndex &index, const QVariant &value, int role)
179{
180 // Propagation to sheet model
181 if (d->isSheetIndex(index, this)) {
182 return d->map->sheet(index.parent().row())->model()->setData(index, value, role);
183 }
184
185 if (index.isValid() && index.row() < d->map->count()) {
186 Sheet* const sheet(d->map->sheet(index.row()));
187 switch (role) {
188 case Qt::EditRole: {
189 const QString name(value.toString());
190 if (!name.isEmpty()) {
191 KUndo2Command* const command = new RenameSheetCommand(sheet, name);
192 emit addCommandRequested(command);
193 emit dataChanged(index, index);
194 return true;
195 }
196 break;
197 }
198 case VisibilityRole:
199 setHidden(sheet, value.toBool());
200 break;
201 case ProtectionRole:
202 break;
203 default:
204 break;
205 }
206 }
207 return false;
208}
209
210bool MapModel::setHidden(Sheet* sheet, bool hidden)
211{
212 KUndo2Command* command;
213 if (hidden && !sheet->isHidden()) {
214 command = new HideSheetCommand(sheet);
215 } else if (!hidden && sheet->isHidden()) {
216 command = new ShowSheetCommand(sheet);
217 } else {
218 return false; // nothing to do
219 }
220 emit addCommandRequested(command);
221 return true;
222}
223
224Map* MapModel::map() const
225{
226 return d->map;
227}
228
229void MapModel::addSheet(Sheet* sheet)
230{
231 kDebug() << "Added sheet:" << sheet->sheetName();
232 emit layoutChanged();
233}
234
235void MapModel::removeSheet(Sheet *sheet)
236{
237 kDebug() << "Removed sheet:" << sheet->sheetName();
238 emit layoutChanged();
239}
240
241#include "MapModel.moc"
242