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

0001 /* This file is part of the KDE project
0002    Copyright 2007 Stefan Nikolaus <stefan.nikolaus@kdemail.net>
0003    Copyright 2005-2006 Inge Wallin <inge@lysator.liu.se>
0004    Copyright 2004 Ariya Hidayat <ariya@kde.org>
0005    Copyright 2002-2003 Norbert Andres <nandres@web.de>
0006    Copyright 2000-2002 Laurent Montel <montel@kde.org>
0007    Copyright 2002 John Dailey <dailey@vt.edu>
0008    Copyright 2002 Phillip Mueller <philipp.mueller@gmx.de>
0009    Copyright 2000 Werner Trobin <trobin@kde.org>
0010    Copyright 1999-2000 Simon Hausmann <hausmann@kde.org>
0011    Copyright 1999 David Faure <faure@kde.org>
0012    Copyright 1998-2000 Torben Weis <weis@kde.org>
0013 
0014    This library is free software; you can redistribute it and/or
0015    modify it under the terms of the GNU Library General Public
0016    License as published by the Free Software Foundation; either
0017    version 2 of the License, or (at your option) any later version.
0018 
0019    This library is distributed in the hope that it will be useful,
0020    but WITHOUT ANY WARRANTY; without even the implied warranty of
0021    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0022    Library General Public License for more details.
0023 
0024    You should have received a copy of the GNU Library General Public License
0025    along with this library; see the file COPYING.LIB.  If not, write to
0026    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0027    Boston, MA 02110-1301, USA.
0028 */
0029 
0030 // Local
0031 #include "NamedAreaManager.h"
0032 
0033 #include <KoXmlReader.h>
0034 
0035 // Qt
0036 #include <QDomElement>
0037 #include <QHash>
0038 
0039 // Sheets
0040 #include "CellStorage.h"
0041 #include "FormulaStorage.h"
0042 #include "LoadingInfo.h"
0043 #include "Map.h"
0044 #include "Region.h"
0045 #include "Sheet.h"
0046 #include "Util.h"
0047 
0048 using namespace Calligra::Sheets;
0049 
0050 struct NamedArea {
0051     QString name;
0052     Sheet* sheet;
0053     QRect range;
0054 };
0055 
0056 class Q_DECL_HIDDEN NamedAreaManager::Private
0057 {
0058 public:
0059     const Map* map;
0060     QHash<QString, NamedArea> namedAreas;
0061 };
0062 
0063 NamedAreaManager::NamedAreaManager(const Map* map)
0064         : d(new Private)
0065 {
0066     d->map = map;
0067     connect(this, SIGNAL(namedAreaAdded(QString)),
0068             this, SIGNAL(namedAreaModified(QString)));
0069     connect(this, SIGNAL(namedAreaRemoved(QString)),
0070             this, SIGNAL(namedAreaModified(QString)));
0071 }
0072 
0073 NamedAreaManager::~NamedAreaManager()
0074 {
0075     delete d;
0076 }
0077 
0078 const Map *NamedAreaManager::map() const
0079 {
0080     return d->map;
0081 }
0082 
0083 void NamedAreaManager::insert(const Region& region, const QString& name)
0084 {
0085     // NOTE Stefan: Only contiguous regions are supported (OpenDocument compatibility).
0086     Q_ASSERT(!name.isEmpty());
0087     NamedArea namedArea;
0088     namedArea.range = region.lastRange();
0089     namedArea.sheet = region.lastSheet();
0090     namedArea.name = name;
0091     namedArea.sheet->cellStorage()->setNamedArea(Region(region.lastRange(), region.lastSheet()), name);
0092     d->namedAreas[name] = namedArea;
0093     emit namedAreaAdded(name);
0094 }
0095 
0096 void NamedAreaManager::remove(const QString& name)
0097 {
0098     if (!d->namedAreas.contains(name))
0099         return;
0100     NamedArea namedArea = d->namedAreas.value(name);
0101     namedArea.sheet->cellStorage()->removeNamedArea(Region(namedArea.range, namedArea.sheet), name);
0102     d->namedAreas.remove(name);
0103     emit namedAreaRemoved(name);
0104     const QList<Sheet*> sheets = namedArea.sheet->map()->sheetList();
0105     foreach(Sheet* sheet, sheets) {
0106         const QString tmp = '\'' + name + '\'';
0107         const FormulaStorage* const storage = sheet->formulaStorage();
0108         for (int c = 0; c < storage->count(); ++c) {
0109             if (storage->data(c).expression().contains(tmp)) {
0110                 Cell(sheet, storage->col(c), storage->row(c)).makeFormula();
0111             }
0112         }
0113     }
0114 }
0115 
0116 void NamedAreaManager::remove(Sheet* sheet)
0117 {
0118     const QList<NamedArea> namedAreas = d->namedAreas.values();
0119     for (int i = 0; i < namedAreas.count(); ++i) {
0120         if (namedAreas[i].sheet == sheet)
0121             remove(namedAreas[i].name);
0122     }
0123 }
0124 
0125 Calligra::Sheets::Region NamedAreaManager::namedArea(const QString& name) const
0126 {
0127     if (!d->namedAreas.contains(name))
0128         return Region();
0129     const NamedArea namedArea = d->namedAreas.value(name);
0130     return Region(namedArea.range, namedArea.sheet);
0131 }
0132 
0133 Sheet* NamedAreaManager::sheet(const QString& name) const
0134 {
0135     if (!d->namedAreas.contains(name))
0136         return 0;
0137     return d->namedAreas.value(name).sheet;
0138 }
0139 
0140 bool NamedAreaManager::contains(const QString& name) const
0141 {
0142     return d->namedAreas.contains(name);
0143 }
0144 
0145 QList<QString> NamedAreaManager::areaNames() const
0146 {
0147     return d->namedAreas.keys();
0148 }
0149 
0150 void NamedAreaManager::regionChanged(const Region& region)
0151 {
0152     Sheet* sheet;
0153     QList< QPair<QRectF, QString> > namedAreas;
0154     Region::ConstIterator end(region.constEnd());
0155     for (Region::ConstIterator it = region.constBegin(); it != end; ++it) {
0156         sheet = (*it)->sheet();
0157         namedAreas = sheet->cellStorage()->namedAreas(Region((*it)->rect(), sheet));
0158         for (int j = 0; j < namedAreas.count(); ++j) {
0159             Q_ASSERT(d->namedAreas.contains(namedAreas[j].second));
0160             d->namedAreas[namedAreas[j].second].range = namedAreas[j].first.toRect();
0161             emit namedAreaModified(namedAreas[j].second);
0162         }
0163     }
0164 }
0165 
0166 void NamedAreaManager::updateAllNamedAreas()
0167 {
0168     QList< QPair<QRectF, QString> > namedAreas;
0169     const QRect rect(QPoint(1, 1), QPoint(KS_colMax, KS_rowMax));
0170     const QList<Sheet*> sheets = d->map->sheetList();
0171     for (int i = 0; i < sheets.count(); ++i) {
0172         namedAreas = sheets[i]->cellStorage()->namedAreas(Region(rect, sheets[i]));
0173         for (int j = 0; j < namedAreas.count(); ++j) {
0174             Q_ASSERT(d->namedAreas.contains(namedAreas[j].second));
0175             d->namedAreas[namedAreas[j].second].range = namedAreas[j].first.toRect();
0176             emit namedAreaModified(namedAreas[j].second);
0177         }
0178     }
0179 }
0180 
0181 void NamedAreaManager::loadXML(const KoXmlElement& parent)
0182 {
0183     KoXmlElement element;
0184     forEachElement(element, parent) {
0185         if (element.tagName() == "reference") {
0186             Sheet* sheet = 0;
0187             QString tabname;
0188             QString refname;
0189             int left = 0;
0190             int right = 0;
0191             int top = 0;
0192             int bottom = 0;
0193             KoXmlElement sheetName = element.namedItem("tabname").toElement();
0194             if (!sheetName.isNull())
0195                 sheet = d->map->findSheet(sheetName.text());
0196             if (!sheet)
0197                 continue;
0198             KoXmlElement referenceName = element.namedItem("refname").toElement();
0199             if (!referenceName.isNull())
0200                 refname = referenceName.text();
0201             KoXmlElement rect = element.namedItem("rect").toElement();
0202             if (!rect.isNull()) {
0203                 bool ok;
0204                 if (rect.hasAttribute("left-rect"))
0205                     left = rect.attribute("left-rect").toInt(&ok);
0206                 if (rect.hasAttribute("right-rect"))
0207                     right = rect.attribute("right-rect").toInt(&ok);
0208                 if (rect.hasAttribute("top-rect"))
0209                     top = rect.attribute("top-rect").toInt(&ok);
0210                 if (rect.hasAttribute("bottom-rect"))
0211                     bottom = rect.attribute("bottom-rect").toInt(&ok);
0212             }
0213             insert(Region(QRect(QPoint(left, top), QPoint(right, bottom)), sheet), refname);
0214         }
0215     }
0216 }
0217 
0218 QDomElement NamedAreaManager::saveXML(QDomDocument& doc) const
0219 {
0220     QDomElement element = doc.createElement("areaname");
0221     const QList<NamedArea> namedAreas = d->namedAreas.values();
0222     for (int i = 0; i < namedAreas.count(); ++i) {
0223         QDomElement e = doc.createElement("reference");
0224         QDomElement tabname = doc.createElement("tabname");
0225         tabname.appendChild(doc.createTextNode(namedAreas[i].sheet->sheetName()));
0226         e.appendChild(tabname);
0227 
0228         QDomElement refname = doc.createElement("refname");
0229         refname.appendChild(doc.createTextNode(namedAreas[i].name));
0230         e.appendChild(refname);
0231 
0232         QDomElement rect = doc.createElement("rect");
0233         rect.setAttribute("left-rect", QString::number((namedAreas[i].range).left()));
0234         rect.setAttribute("right-rect", QString::number((namedAreas[i].range).right()));
0235         rect.setAttribute("top-rect", QString::number((namedAreas[i].range).top()));
0236         rect.setAttribute("bottom-rect", QString::number((namedAreas[i].range).bottom()));
0237         e.appendChild(rect);
0238         element.appendChild(e);
0239     }
0240     return element;
0241 }