kspread

Binding.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE project
00002    Copyright 2007 Stefan Nikolaus <stefan.nikolaus@kdemail.net>
00003     Copyright (C) 2008 Thomas Zander <zander@kde.org>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018    Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include "Binding.h"
00022 #include "BindingModel.h"
00023 
00024 #include <QRect>
00025 
00026 #include <kdebug.h>
00027 
00028 #include "CellStorage.h"
00029 #include "Map.h"
00030 #include "Sheet.h"
00031 #include "Value.h"
00032 
00033 using namespace KSpread;
00034 
00035 class Binding::Private : public QSharedData
00036 {
00037 public:
00038     Private() : model(0) {}
00039     ~Private() { delete model; }
00040 
00041     BindingModel* model;
00042 };
00043 
00044 
00045 Binding::Binding()
00046     : d(new Private)
00047 {
00048 }
00049 
00050 Binding::Binding(const Region& region)
00051     : d(new Private)
00052 {
00053     Q_ASSERT(region.isValid());
00054     d->model = new BindingModel(this);
00055     d->model->setRegion(region);
00056 }
00057 
00058 Binding::Binding(const Binding& other)
00059     : d(other.d)
00060 {
00061 }
00062 
00063 Binding::~Binding()
00064 {
00065 }
00066 
00067 bool Binding::isEmpty() const
00068 {
00069     return d->model->region().isEmpty();
00070 }
00071 
00072 QAbstractItemModel* Binding::model() const
00073 {
00074     return d->model;
00075 }
00076 
00077 const KSpread::Region& Binding::region() const
00078 {
00079     return d->model->region();
00080 }
00081 
00082 void Binding::setRegion(const Region& region)
00083 {
00084     d->model->setRegion(region);
00085 }
00086 
00087 void Binding::update(const Region& region)
00088 {
00089     QRect rect;
00090     Region changedRegion;
00091     const QPoint offset = d->model->region().firstRange().topLeft();
00092     const QRect range = d->model->region().firstRange();
00093     const Sheet* sheet = d->model->region().firstSheet();
00094     Region::ConstIterator end(region.constEnd());
00095     for (Region::ConstIterator it = region.constBegin(); it != end; ++it)
00096     {
00097         if (sheet != (*it)->sheet())
00098             continue;
00099         rect = range & (*it)->rect();
00100         rect.translate( -offset.x(), -offset.y() );
00101         if (rect.isValid())
00102         {
00103             d->model->emitDataChanged(rect);
00104             changedRegion.add(rect, (*it)->sheet());
00105         }
00106     }
00107     d->model->emitChanged(changedRegion);
00108 }
00109 
00110 void Binding::operator=(const Binding& other)
00111 {
00112     d = other.d;
00113 }
00114 
00115 bool Binding::operator==(const Binding& other) const
00116 {
00117     return d == other.d;
00118 }
00119 
00120 bool Binding::operator<(const Binding& other) const
00121 {
00122     return d < other.d;
00123 }
00124 
00125 QHash<QString, QVector<QRect> > BindingModel::cellRegion() const
00126 {
00127     QHash<QString, QVector<QRect> > answer;
00128     Region::ConstIterator end = m_region.constEnd();
00129     for (Region::ConstIterator it = m_region.constBegin(); it != end; ++it) {
00130         if (!(*it)->isValid()) {
00131             continue;
00132         }
00133         answer[(*it)->name()].append((*it)->rect());
00134     }
00135     return answer;
00136 }
00137 
00138 bool BindingModel::setCellRegion(const QString& regionName)
00139 {
00140     Q_ASSERT(m_region.isValid());
00141     Q_ASSERT(m_region.firstSheet());
00142     const Map* const map = m_region.firstSheet()->map();
00143     const Region region = Region(regionName, map);
00144     if (!region.isValid()) {
00145         kDebug() << qPrintable(regionName) << "is not a valid region.";
00146         return false;
00147     }
00148     // Clear the old binding.
00149     Region::ConstIterator end = m_region.constEnd();
00150     for (Region::ConstIterator it = m_region.constBegin(); it != end; ++it) {
00151         if (!(*it)->isValid()) {
00152             continue;
00153         }
00154         // FIXME Stefan: This may also clear other bindings!
00155         (*it)->sheet()->cellStorage()->setBinding(Region((*it)->rect(), (*it)->sheet()), Binding());
00156     }
00157     // Set the new region
00158     m_region = region;
00159     end = m_region.constEnd();
00160     for (Region::ConstIterator it = m_region.constBegin(); it != end; ++it) {
00161         if (!(*it)->isValid()) {
00162             continue;
00163         }
00164         (*it)->sheet()->cellStorage()->setBinding(Region((*it)->rect(), (*it)->sheet()), *m_binding);
00165     }
00166     return true;
00167 }
00168 
00169 
00171 
00172 BindingModel::BindingModel(Binding* binding, QObject *parent)
00173     : QAbstractTableModel(parent)
00174     , m_binding(binding)
00175 {
00176 }
00177 
00178 bool BindingModel::isCellRegionValid(const QString& regionName) const
00179 {
00180     Q_CHECK_PTR(m_region.firstSheet());
00181     Q_CHECK_PTR(m_region.firstSheet()->map());
00182     return Region(regionName, m_region.firstSheet()->map()).isValid();
00183 }
00184 
00185 QString BindingModel::regionAddress() const
00186 {
00187     return m_region.name();
00188 }
00189 
00190 void BindingModel::emitChanged(const Region& region)
00191 {
00192     emit changed(region);
00193 }
00194 
00195 void BindingModel::emitDataChanged(const QRect& rect)
00196 {
00197     const QPoint tl = rect.topLeft();
00198     const QPoint br = rect.bottomRight();
00199     kDebug() << "emit QAbstractItemModel::dataChanged(" << index(tl.y(), tl.x()) << ", " << index(br.y(), br.x()) << ");";
00200     emit dataChanged(index(tl.y(), tl.x()), index(br.y(), br.x()));
00201 }
00202 
00203 QVariant BindingModel::data(const QModelIndex& index, int role) const
00204 {
00205     if ((m_region.isEmpty()) || (role != Qt::EditRole && role != Qt::DisplayRole))
00206         return QVariant();
00207     const QPoint offset = m_region.firstRange().topLeft();
00208     const Sheet* sheet = m_region.firstSheet();
00209     const Value value = sheet->cellStorage()->value(offset.x() + index.column(),
00210                                                      offset.y() + index.row());
00211     // KoChart::Value is either:
00212     //  - a double (interpreted as a value)
00213     //  - a QString (interpreted as a label)
00214     //  - a QDateTime (interpreted as a date/time value)
00215     //  - Invalid (interpreted as empty)
00216     QVariant variant;
00217     switch (value.type())
00218     {
00219         case Value::Float:
00220         case Value::Integer:
00221             if (value.format() == Value::fmt_DateTime ||
00222                  value.format() == Value::fmt_Date ||
00223                  value.format() == Value::fmt_Time)
00224             {
00225                 variant.setValue<QDateTime>(value.asDateTime(sheet->map()->calculationSettings()));
00226                 break;
00227             }
00228         case Value::Boolean:
00229         case Value::Complex:
00230         case Value::Array:
00231             variant.setValue<double>(numToDouble (value.asFloat()));
00232             break;
00233         case Value::String:
00234         case Value::Error:
00235             variant.setValue<QString>(value.asString());
00236             break;
00237         case Value::Empty:
00238         case Value::CellRange:
00239         default:
00240             break;
00241     }
00242     //kDebug() << index.column() <<"," << index.row() <<"," << variant;
00243     return variant;
00244 }
00245 
00246 const KSpread::Region& BindingModel::region() const
00247 {
00248     return m_region;
00249 }
00250 
00251 QVariant BindingModel::headerData(int section, Qt::Orientation orientation, int role) const
00252 {
00253     if ( (m_region.isEmpty()) || (role != Qt::EditRole && role != Qt::DisplayRole))
00254         return QVariant();
00255     const QPoint offset = m_region.firstRange().topLeft();
00256     const int col = (orientation == Qt::Vertical) ? offset.x() : offset.x() + section;
00257     const int row = (orientation == Qt::Vertical) ? offset.y() + section : offset.y();
00258     const Sheet* sheet = m_region.firstSheet();
00259     const Value value = sheet->cellStorage()->value(col, row);
00260     return value.asVariant();
00261 }
00262 
00263 int BindingModel::rowCount(const QModelIndex& parent) const
00264 {
00265     Q_UNUSED(parent);
00266     return m_region.isEmpty() ? 0 : m_region.firstRange().height();
00267 }
00268 
00269 int BindingModel::columnCount(const QModelIndex& parent) const
00270 {
00271     Q_UNUSED(parent);
00272     return m_region.isEmpty() ? 0 : m_region.firstRange().width();
00273 }
00274 
00275 void BindingModel::setRegion(const Region& region)
00276 {
00277     m_region = region;
00278 }
00279 
00280 #include "BindingModel.moc"