File indexing completed on 2024-04-28 16:21:31

0001 /* This file is part of the KDE project
0002    Copyright 2009 Stefan Nikolaus stefan.nikolaus@kdemail.net
0003 
0004    This library is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU Library General Public
0006    License as published by the Free Software Foundation; either
0007    version 2 of the License, or (at your option) any later version.
0008 
0009    This library is distributed in the hope that it will be useful,
0010    but WITHOUT ANY WARRANTY; without even the implied warranty of
0011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012    Library General Public License for more details.
0013 
0014    You should have received a copy of the GNU Library General Public License
0015    along with this library; see the file COPYING.LIB.  If not, write to
0016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017    Boston, MA 02110-1301, USA.
0018 */
0019 
0020 #include "SheetModel.h"
0021 
0022 // Sheets
0023 #include "Binding.h"
0024 #include "Cell.h"
0025 #include "CellStorage.h"
0026 #include "Condition.h"
0027 #include "database/Database.h"
0028 #include "Formula.h"
0029 #include "Map.h"
0030 #include "ModelSupport.h"
0031 #include "Sheet.h"
0032 #include "Style.h"
0033 #include "Validity.h"
0034 #include "Value.h"
0035 #include "ValueFormatter.h"
0036 
0037 // Qt
0038 #include <QBrush>
0039 #include <QItemSelectionRange>
0040 #include <QSize>
0041 
0042 using namespace Calligra::Sheets;
0043 
0044 class Q_DECL_HIDDEN SheetModel::Private
0045 {
0046 public:
0047     Sheet* sheet;
0048 };
0049 
0050 SheetModel::SheetModel(Sheet* sheet)
0051         : QAbstractTableModel(sheet)
0052         , d(new Private)
0053 {
0054     d->sheet = sheet;
0055 }
0056 
0057 SheetModel::~SheetModel()
0058 {
0059     delete d;
0060 }
0061 
0062 int SheetModel::columnCount(const QModelIndex& parent) const
0063 {
0064     if (parent.isValid() && parent.internalPointer() != d->sheet->map()) {
0065         return 0;
0066     }
0067     return KS_colMax;
0068 }
0069 
0070 QVariant SheetModel::data(const QModelIndex& index, int role) const
0071 {
0072     if (!index.isValid()) {
0073         return QVariant();
0074     }
0075     if (index.model() != this) {
0076         return QVariant();
0077     }
0078     if (index.internalPointer() != d->sheet) {
0079         return QVariant();
0080     }
0081     if (index.parent().isValid()) {
0082         if (index.parent().internalPointer() != d->sheet->map()) {
0083             return QVariant();
0084         }
0085     }
0086     // NOTE Model indices start from 0, while Calligra Sheets column/row indices start from 1.
0087     const Cell cell = Cell(d->sheet, index.column() + 1, index.row() + 1).masterCell();
0088     const Style style = cell.effectiveStyle();
0089     if (role == Qt::DisplayRole) {
0090         // Display a formula if warranted.  If not, simply display the value.
0091         if (cell.isFormula() && d->sheet->getShowFormula() &&
0092                 !(d->sheet->isProtected() && style.hideFormula())) {
0093             return QVariant(cell.userInput());
0094         } else if (d->sheet->getHideZero() && cell.value().isNumber() && cell.value().asFloat() == 0.0) {
0095             // Hide zero.
0096             return QVariant();
0097         } else if (!cell.isEmpty()) {
0098             // Format the value appropriately and set the display text.
0099             // The format of the resulting value is used below to determine the alignment.
0100             Value value = d->sheet->map()->formatter()->formatText(cell.value(), style.formatType(),
0101                           style.precision(), style.floatFormat(),
0102                           style.prefix(), style.postfix(),
0103                           style.currency().symbol());
0104             return value.asString();
0105         }
0106     } else if (role == Qt::EditRole) {
0107         return cell.userInput();
0108     } else if (role == Qt::ToolTipRole) {
0109         return cell.comment();
0110     } else if (role == Qt::SizeHintRole) {
0111         // TODO
0112     } else if (role == Qt::FontRole) {
0113         return style.font();
0114     } else if (role == Qt::TextAlignmentRole) {
0115         // TODO
0116     } else if (role == Qt::BackgroundRole) {
0117         return style.backgroundBrush();
0118     } else if (role == Qt::BackgroundColorRole) {
0119         return style.backgroundColor();
0120     } else if (role == Qt::ForegroundRole) {
0121         return style.fontColor();
0122     }
0123     const int column = index.column() + 1;
0124     const int row = index.row() + 1;
0125     CellStorage *const storage = d->sheet->cellStorage();
0126     switch (role) {
0127     case UserInputRole:
0128         return storage->userInput(column, row);
0129     case FormulaRole: {
0130         QVariant data;
0131         data.setValue(storage->formula(column, row));
0132         return data;
0133     }
0134     case ValueRole: {
0135         QVariant data;
0136         data.setValue(storage->value(column, row));
0137         return data;
0138     }
0139     case LinkRole:
0140         return storage->link(column, row);
0141     }
0142     return QVariant();
0143 }
0144 
0145 Qt::ItemFlags SheetModel::flags(const QModelIndex& index) const
0146 {
0147     if (!index.isValid()) {
0148         return Qt::NoItemFlags;
0149     }
0150     if (index.model() != this) {
0151         return Qt::NoItemFlags;
0152     }
0153     if (index.internalPointer() != d->sheet) {
0154         return Qt::NoItemFlags;
0155     }
0156     if (index.parent().isValid()) {
0157         if (index.parent().internalPointer() != d->sheet->map()) {
0158             return Qt::NoItemFlags;
0159         }
0160     }
0161     return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled;
0162 }
0163 
0164 QVariant SheetModel::headerData(int section, Qt::Orientation orientation, int role) const
0165 {
0166     // NOTE Model indices start from 0, while Calligra Sheets column/row indices start from 1.
0167     if (role == Qt::DisplayRole) {
0168         if (orientation == Qt::Horizontal) {
0169             return Cell::columnName(section + 1);
0170         } else {
0171             return QString::number(section + 1);
0172         }
0173     }
0174     return QVariant();
0175 }
0176 
0177 QModelIndex SheetModel::index(int row, int column, const QModelIndex &parent) const
0178 {
0179     if (parent.isValid() && parent.internalPointer() != d->sheet->map()) {
0180         return QModelIndex();
0181     }
0182     // A cell in our sheet?
0183     if (!parent.isValid()) {
0184         return createIndex(row, column, d->sheet);
0185         // Embedded in a MapModel?
0186     } else if (parent.internalPointer() == d->sheet->map()) {
0187         return createIndex(row, column, d->sheet);
0188         // A sub-table?
0189     } else if (parent.internalPointer() == this) {
0190         // TODO sub-tables
0191     }
0192     return QModelIndex();
0193 }
0194 
0195 int SheetModel::rowCount(const QModelIndex& parent) const
0196 {
0197     if (parent.isValid() && parent.internalPointer() != d->sheet->map()) {
0198         return 0;
0199     }
0200     return KS_rowMax;
0201 }
0202 
0203 bool SheetModel::setData(const QModelIndex& index, const QVariant& value, int role)
0204 {
0205     if (!index.isValid()) {
0206         return false;
0207     }
0208     if (index.model() != this) {
0209         return false;
0210     }
0211     if (index.internalPointer() != d->sheet) {
0212         return false;
0213     }
0214     if (index.parent().isValid()) {
0215         if (index.parent().internalPointer() != d->sheet->map()) {
0216             return false;
0217         }
0218     }
0219     // NOTE Model indices start from 0, while Calligra Sheets column/row indices start from 1.
0220     const int column = index.column() + 1;
0221     const int row = index.row() + 1;
0222     Cell cell = Cell(sheet(), index.column() + 1, index.row() + 1).masterCell();
0223     CellStorage *const storage = d->sheet->cellStorage();
0224     switch (role) {
0225     case Qt::EditRole:
0226         cell.parseUserInput(value.toString());
0227         break;
0228     case UserInputRole:
0229         storage->setUserInput(column, row, value.toString());
0230         break;
0231     case FormulaRole:
0232         storage->setFormula(column, row, value.value<Formula>());
0233         break;
0234     case ValueRole:
0235         storage->setValue(column, row, value.value<Value>());
0236         break;
0237     case LinkRole:
0238         storage->setLink(column, row, value.toString());
0239         break;
0240     default:
0241         return false;
0242     }
0243     emit dataChanged(index, index);
0244     return true;
0245 }
0246 
0247 bool SheetModel::setData(const QItemSelectionRange &range, const QVariant &value, int role)
0248 {
0249     const Region region(toRange(range), d->sheet);
0250     CellStorage *const storage = d->sheet->cellStorage();
0251     switch (role) {
0252     case CommentRole:
0253         storage->setComment(region, value.toString());
0254         break;
0255     case ConditionRole:
0256         storage->setConditions(region, value.value<Conditions>());
0257         break;
0258     case FusionedRangeRole:
0259         // TODO
0260 //         storage->setFusion(region, value.value<bool>());
0261         break;
0262     case LockedRangeRole:
0263         // TODO
0264 //         storage->setMatrix(region, value.value<bool>());
0265         break;
0266     case NamedAreaRole: {
0267         QString namedAreaName = value.toString();
0268         if (namedAreaName.isEmpty())
0269             return false;
0270         storage->emitInsertNamedArea(region, namedAreaName);
0271         break;
0272     }
0273     case SourceRangeRole:
0274         storage->setBinding(region, value.value<Binding>());
0275         break;
0276     case StyleRole:
0277         // TODO
0278 //         storage->setStyle(region, value.value<Style>());
0279         break;
0280     case TargetRangeRole:
0281         storage->setDatabase(region, value.value<Database>());
0282         break;
0283     case ValidityRole:
0284         storage->setValidity(region, value.value<Validity>());
0285         break;
0286     default:
0287         return false;
0288     }
0289     emit dataChanged(range.topLeft(), range.bottomRight());
0290     return true;
0291 }
0292 
0293 bool SheetModel::setData(const QModelIndex &topLeft, const QModelIndex &bottomRight,
0294                          const QVariant &value, int role)
0295 {
0296     return setData(QItemSelectionRange(topLeft, bottomRight), value, role);
0297 }
0298 
0299 Sheet* SheetModel::sheet() const
0300 {
0301     return d->sheet;
0302 }