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

0001 /* This file is part of the KDE project
0002    Copyright 2007 Stefan Nikolaus <stefan.nikolaus@kdemail.net>
0003     Copyright (C) 2008 Thomas Zander <zander@kde.org>
0004 
0005    This library is free software; you can redistribute it and/or
0006    modify it under the terms of the GNU Library General Public
0007    License as published by the Free Software Foundation; either
0008    version 2 of the License, or (at your option) any later version.
0009 
0010    This library is distributed in the hope that it will be useful,
0011    but WITHOUT ANY WARRANTY; without even the implied warranty of
0012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013    Library General Public License for more details.
0014 
0015    You should have received a copy of the GNU Library General Public License
0016    along with this library; see the file COPYING.LIB.  If not, write to
0017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018    Boston, MA 02110-1301, USA.
0019 */
0020 
0021 #include "Binding.h"
0022 #include "BindingModel.h"
0023 
0024 #include <QRect>
0025 
0026 #include "SheetsDebug.h"
0027 
0028 #include "CellStorage.h"
0029 #include "Map.h"
0030 #include "Sheet.h"
0031 #include "Value.h"
0032 
0033 using namespace Calligra::Sheets;
0034 
0035 class Q_DECL_HIDDEN Binding::Private : public QSharedData
0036 {
0037 public:
0038     BindingModel* model;
0039     Private(Binding *q) : model(new BindingModel(q)) {}
0040     ~Private() { delete model; }
0041 };
0042 
0043 
0044 Binding::Binding()
0045     : d(new Private(this))
0046 {
0047 }
0048 
0049 Binding::Binding(const Region& region)
0050     : d(new Private(this))
0051 {
0052     Q_ASSERT(region.isValid());
0053     d->model->setRegion(region);
0054 }
0055 
0056 Binding::Binding(const Binding& other)
0057     : d(other.d)
0058 {
0059 }
0060 
0061 Binding::~Binding()
0062 {
0063 }
0064 
0065 bool Binding::isEmpty() const
0066 {
0067     return d->model->region().isEmpty();
0068 }
0069 
0070 QAbstractItemModel* Binding::model() const
0071 {
0072     return d->model;
0073 }
0074 
0075 const Calligra::Sheets::Region& Binding::region() const
0076 {
0077     return d->model->region();
0078 }
0079 
0080 void Binding::setRegion(const Region& region)
0081 {
0082     d->model->setRegion(region);
0083 }
0084 
0085 void Binding::update(const Region& region)
0086 {
0087     QRect rect;
0088     Region changedRegion;
0089     const QPoint offset = d->model->region().firstRange().topLeft();
0090     const QRect range = d->model->region().firstRange();
0091     const Sheet* sheet = d->model->region().firstSheet();
0092     Region::ConstIterator end(region.constEnd());
0093     for (Region::ConstIterator it = region.constBegin(); it != end; ++it) {
0094         if (sheet != (*it)->sheet())
0095             continue;
0096         rect = range & (*it)->rect();
0097         rect.translate(-offset.x(), -offset.y());
0098         if (rect.isValid()) {
0099             d->model->emitDataChanged(rect);
0100             changedRegion.add(rect, (*it)->sheet());
0101         }
0102     }
0103     d->model->emitChanged(changedRegion);
0104 }
0105 
0106 void Binding::operator=(const Binding & other)
0107 {
0108     d = other.d;
0109 }
0110 
0111 bool Binding::operator==(const Binding& other) const
0112 {
0113     return d == other.d;
0114 }
0115 
0116 bool Binding::operator<(const Binding& other) const
0117 {
0118     return d < other.d;
0119 }
0120 
0121 QHash<QString, QVector<QRect> > BindingModel::cellRegion() const
0122 {
0123     QHash<QString, QVector<QRect> > answer;
0124     Region::ConstIterator end = m_region.constEnd();
0125     for (Region::ConstIterator it = m_region.constBegin(); it != end; ++it) {
0126         if (!(*it)->isValid()) {
0127             continue;
0128         }
0129         answer[(*it)->name()].append((*it)->rect());
0130     }
0131     return answer;
0132 }
0133 
0134 bool BindingModel::setCellRegion(const QString& regionName)
0135 {
0136     Q_ASSERT(m_region.isValid());
0137     Q_ASSERT(m_region.firstSheet());
0138     const Map* const map = m_region.firstSheet()->map();
0139     const Region region = Region(regionName, map);
0140     if (!region.isValid()) {
0141         debugSheets << qPrintable(regionName) << "is not a valid region.";
0142         return false;
0143     }
0144     // Clear the old binding.
0145     Region::ConstIterator end = m_region.constEnd();
0146     for (Region::ConstIterator it = m_region.constBegin(); it != end; ++it) {
0147         if (!(*it)->isValid()) {
0148             continue;
0149         }
0150         // FIXME Stefan: This may also clear other bindings!
0151         (*it)->sheet()->cellStorage()->setBinding(Region((*it)->rect(), (*it)->sheet()), Binding());
0152     }
0153     // Set the new region
0154     m_region = region;
0155     end = m_region.constEnd();
0156     for (Region::ConstIterator it = m_region.constBegin(); it != end; ++it) {
0157         if (!(*it)->isValid()) {
0158             continue;
0159         }
0160         (*it)->sheet()->cellStorage()->setBinding(Region((*it)->rect(), (*it)->sheet()), *m_binding);
0161     }
0162     return true;
0163 }
0164 
0165 
0166 /////// BindingModel
0167 
0168 BindingModel::BindingModel(Binding* binding, QObject *parent)
0169         : QAbstractTableModel(parent)
0170         , m_binding(binding)
0171 {
0172 }
0173 
0174 bool BindingModel::isCellRegionValid(const QString& regionName) const
0175 {
0176     Q_CHECK_PTR(m_region.firstSheet());
0177     Q_CHECK_PTR(m_region.firstSheet()->map());
0178     return Region(regionName, m_region.firstSheet()->map()).isValid();
0179 }
0180 
0181 void BindingModel::emitChanged(const Region& region)
0182 {
0183     emit changed(region);
0184 }
0185 
0186 void BindingModel::emitDataChanged(const QRect& rect)
0187 {
0188     const QPoint tl = rect.topLeft();
0189     const QPoint br = rect.bottomRight();
0190     //debugSheetsUI << "emit QAbstractItemModel::dataChanged" << QString("%1:%2").arg(tl).arg(br);
0191     emit dataChanged(index(tl.y(), tl.x()), index(br.y(), br.x()));
0192 }
0193 
0194 QVariant BindingModel::data(const QModelIndex& index, int role) const
0195 {
0196     if ((m_region.isEmpty()) || (role != Qt::EditRole && role != Qt::DisplayRole))
0197         return QVariant();
0198     const QPoint offset = m_region.firstRange().topLeft();
0199     const Sheet* sheet = m_region.firstSheet();
0200     int row = offset.y() + index.row();
0201     int column = offset.x() + index.column();
0202     Value value = sheet->cellStorage()->value(column, row);
0203 
0204     switch (role) {
0205         case Qt::DisplayRole: {
0206             // return the in the cell displayed test
0207             Cell c(sheet, column, row);
0208             bool showFormula = false;
0209             return c.displayText(Style(), &value, &showFormula);
0210         }
0211         case Qt::EditRole: {
0212             // return the actual cell value
0213             // KoChart::Value is either:
0214             //  - a double (interpreted as a value)
0215             //  - a QString (interpreted as a label)
0216             //  - a QDateTime (interpreted as a date/time value)
0217             //  - Invalid (interpreted as empty)
0218             QVariant variant;
0219             switch (value.type()) {
0220                 case Value::Float:
0221                 case Value::Integer:
0222                     if (value.format() == Value::fmt_DateTime ||
0223                             value.format() == Value::fmt_Date ||
0224                             value.format() == Value::fmt_Time) {
0225                         variant.setValue<QDateTime>(value.asDateTime(sheet->map()->calculationSettings()));
0226                         break;
0227                     } // fall through
0228                 case Value::Boolean:
0229                 case Value::Complex:
0230                 case Value::Array:
0231                     variant.setValue<double>(numToDouble(value.asFloat()));
0232                     break;
0233                 case Value::String:
0234                 case Value::Error:
0235                     variant.setValue<QString>(value.asString());
0236                     break;
0237                 case Value::Empty:
0238                 case Value::CellRange:
0239                 default:
0240                     break;
0241             }
0242             return variant;
0243         }
0244     }
0245     //debugSheets << index.column() <<"," << index.row() <<"," << variant;
0246     return QVariant();
0247 }
0248 
0249 const Calligra::Sheets::Region& BindingModel::region() const
0250 {
0251     return m_region;
0252 }
0253 
0254 QVariant BindingModel::headerData(int section, Qt::Orientation orientation, int role) const
0255 {
0256     if ((m_region.isEmpty()) || (role != Qt::EditRole && role != Qt::DisplayRole))
0257         return QVariant();
0258     const QPoint offset = m_region.firstRange().topLeft();
0259     const int col = (orientation == Qt::Vertical) ? offset.x() : offset.x() + section;
0260     const int row = (orientation == Qt::Vertical) ? offset.y() + section : offset.y();
0261     const Sheet* sheet = m_region.firstSheet();
0262     const Value value = sheet->cellStorage()->value(col, row);
0263     return value.asVariant();
0264 }
0265 
0266 int BindingModel::rowCount(const QModelIndex& parent) const
0267 {
0268     Q_UNUSED(parent);
0269     return m_region.isEmpty() ? 0 : m_region.firstRange().height();
0270 }
0271 
0272 int BindingModel::columnCount(const QModelIndex& parent) const
0273 {
0274     Q_UNUSED(parent);
0275     return m_region.isEmpty() ? 0 : m_region.firstRange().width();
0276 }
0277 
0278 void BindingModel::setRegion(const Region& region)
0279 {
0280     m_region = region;
0281 }