File indexing completed on 2024-05-19 16:08:03
0001 /* This file is part of the KDE project 0002 Copyright 2007 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 "Database.h" 0021 0022 #include <QString> 0023 0024 #include <KoXmlNS.h> 0025 #include <KoXmlWriter.h> 0026 0027 #include "DatabaseSource.h" 0028 #include "Filter.h" 0029 #include "FilterPopup.h" 0030 #include "Map.h" 0031 #include "Region.h" 0032 #include "odf/SheetsOdf.h" 0033 0034 using namespace Calligra::Sheets; 0035 0036 class Sort; 0037 class SubtotalRules; 0038 0039 class Q_DECL_HIDDEN Database::Private : public QSharedData 0040 { 0041 public: 0042 Private() 0043 : source(0) 0044 , sort(0) 0045 , filter(new Filter()) 0046 , subtotalRules(0) 0047 , isSelection(false) 0048 , onUpdateKeepStyles(false) 0049 , onUpdateKeepSize(true) 0050 , hasPersistentData(true) 0051 , orientation(Row) 0052 , containsHeader(true) 0053 , displayFilterButtons(false) 0054 , refreshDelay(0) { 0055 } 0056 0057 Private(const Private& other) 0058 : QSharedData(other) 0059 , source(/*other.source ? new DatabaseSource(*other.source) : */0) 0060 , sort(/*other.sort ? new Sort(*other.sort) : */0) 0061 , filter(other.filter ? new Filter(*other.filter) : 0) 0062 , subtotalRules(/*other.subtotalRules ? new SubtotalRules(*other.subtotalRules) : */0) 0063 , name(other.name) 0064 , isSelection(other.isSelection) 0065 , onUpdateKeepStyles(other.onUpdateKeepStyles) 0066 , onUpdateKeepSize(other.onUpdateKeepSize) 0067 , hasPersistentData(other.hasPersistentData) 0068 , orientation(other.orientation) 0069 , containsHeader(other.containsHeader) 0070 , displayFilterButtons(other.displayFilterButtons) 0071 , targetRangeAddress(other.targetRangeAddress) 0072 , refreshDelay(other.refreshDelay) { 0073 } 0074 0075 virtual ~Private() { 0076 // delete source; 0077 // delete sort; 0078 delete filter; 0079 // delete subtotalRules; 0080 } 0081 0082 DatabaseSource* source; 0083 Sort* sort; 0084 Filter* filter; 0085 SubtotalRules* subtotalRules; 0086 QString name; 0087 bool isSelection : 1; 0088 bool onUpdateKeepStyles : 1; 0089 bool onUpdateKeepSize : 1; 0090 bool hasPersistentData : 1; 0091 enum { Row, Column } orientation : 1; 0092 bool containsHeader : 1; 0093 bool displayFilterButtons : 1; 0094 Region targetRangeAddress; 0095 int refreshDelay; 0096 0097 private: 0098 void operator=(const Private&); 0099 }; 0100 0101 Database::Database() 0102 : d(new Private) 0103 { 0104 } 0105 0106 Database::Database(const QString& name) 0107 : d(new Private) 0108 { 0109 d->name = name; 0110 } 0111 0112 Database::Database(const Database& other) 0113 : d(other.d) 0114 { 0115 } 0116 0117 Database::~Database() 0118 { 0119 } 0120 0121 bool Database::isEmpty() const 0122 { 0123 return d->name.isNull(); // it may be empty though 0124 } 0125 0126 const QString& Database::name() const 0127 { 0128 return d->name; 0129 } 0130 0131 void Database::setName(const QString& name) 0132 { 0133 d->name = name; 0134 } 0135 0136 Qt::Orientation Database::orientation() const 0137 { 0138 return d->orientation == Private::Row ? Qt::Vertical : Qt::Horizontal; 0139 } 0140 0141 bool Database::containsHeader() const 0142 { 0143 return d->containsHeader; 0144 } 0145 0146 void Database::setContainsHeader(bool enable) 0147 { 0148 d->containsHeader = enable; 0149 } 0150 0151 bool Database::displayFilterButtons() const 0152 { 0153 return d->displayFilterButtons; 0154 } 0155 0156 void Database::setDisplayFilterButtons(bool enable) 0157 { 0158 d->displayFilterButtons = enable; 0159 } 0160 0161 const Calligra::Sheets::Region& Database::range() const 0162 { 0163 return d->targetRangeAddress; 0164 } 0165 0166 void Database::setRange(const Region& region) 0167 { 0168 Q_ASSERT(region.isContiguous()); 0169 d->targetRangeAddress = region; 0170 } 0171 0172 const Filter& Database::filter() const 0173 { 0174 return *d->filter; 0175 } 0176 0177 void Database::setFilter(const Filter& filter) 0178 { 0179 if (*d->filter == filter) 0180 return; 0181 delete d->filter; 0182 d->filter = new Filter(filter); 0183 } 0184 0185 bool Database::loadOdf(const KoXmlElement& element, const Map* map) 0186 { 0187 if (element.hasAttributeNS(KoXmlNS::table, "name")) 0188 d->name = element.attributeNS(KoXmlNS::table, "name", QString()); 0189 if (element.hasAttributeNS(KoXmlNS::table, "is-selection")) { 0190 if (element.attributeNS(KoXmlNS::table, "is-selection", "false") == "true") 0191 d->isSelection = true; 0192 else 0193 d->isSelection = false; 0194 } 0195 if (element.hasAttributeNS(KoXmlNS::table, "on-update-keep-styles")) { 0196 if (element.attributeNS(KoXmlNS::table, "on-update-keep-styles", "false") == "true") 0197 d->onUpdateKeepStyles = true; 0198 else 0199 d->onUpdateKeepStyles = false; 0200 } 0201 if (element.hasAttributeNS(KoXmlNS::table, "on-update-keep-size")) { 0202 if (element.attributeNS(KoXmlNS::table, "on-update-keep-size", "true") == "false") 0203 d->onUpdateKeepSize = false; 0204 else 0205 d->onUpdateKeepSize = true; 0206 } 0207 if (element.hasAttributeNS(KoXmlNS::table, "has-persistent-data")) { 0208 if (element.attributeNS(KoXmlNS::table, "has-persistent-data", "true") == "false") 0209 d->hasPersistentData = false; 0210 else 0211 d->hasPersistentData = true; 0212 } 0213 if (element.hasAttributeNS(KoXmlNS::table, "orientation")) { 0214 if (element.attributeNS(KoXmlNS::table, "orientation", "row") == "column") 0215 d->orientation = Private::Column; 0216 else 0217 d->orientation = Private::Row; 0218 } 0219 if (element.hasAttributeNS(KoXmlNS::table, "contains-header")) { 0220 if (element.attributeNS(KoXmlNS::table, "contains-header", "true") == "false") 0221 d->containsHeader = false; 0222 else 0223 d->containsHeader = true; 0224 } 0225 if (element.hasAttributeNS(KoXmlNS::table, "display-filter-buttons")) { 0226 if (element.attributeNS(KoXmlNS::table, "display-filter-buttons", "false") == "true") 0227 d->displayFilterButtons = true; 0228 else 0229 d->displayFilterButtons = false; 0230 } 0231 if (element.hasAttributeNS(KoXmlNS::table, "target-range-address")) { 0232 const QString address = element.attributeNS(KoXmlNS::table, "target-range-address", QString()); 0233 // only absolute addresses allowed; no fallback sheet needed 0234 d->targetRangeAddress = Region(Odf::loadRegion(address), map); 0235 if (!d->targetRangeAddress.isValid()) 0236 return false; 0237 } 0238 if (element.hasAttributeNS(KoXmlNS::table, "refresh-delay")) { 0239 bool ok = false; 0240 d->refreshDelay = element.attributeNS(KoXmlNS::table, "refresh-delay", QString()).toInt(&ok); 0241 if (!ok || d->refreshDelay < 0) 0242 return false; 0243 } 0244 KoXmlElement child; 0245 forEachElement(child, element) { 0246 if (child.namespaceURI() != KoXmlNS::table) 0247 continue; 0248 if (child.localName() == "database-source-sql") { 0249 // TODO 0250 } else if (child.localName() == "database-source-table") { 0251 // TODO 0252 } else if (child.localName() == "database-source-query") { 0253 // TODO 0254 } else if (child.localName() == "sort") { 0255 // TODO 0256 } else if (child.localName() == "filter") { 0257 d->filter = new Filter(); 0258 if (!d->filter->loadOdf(child, map)) { 0259 delete d->filter; 0260 d->filter = 0; 0261 return false; 0262 } 0263 } else if (child.localName() == "subtotal-rules") { 0264 // TODO 0265 } 0266 } 0267 return true; 0268 } 0269 0270 void Database::saveOdf(KoXmlWriter& xmlWriter) const 0271 { 0272 if (d->targetRangeAddress.isEmpty()) 0273 return; 0274 xmlWriter.startElement("table:database-range"); 0275 if (!d->name.isNull()) 0276 xmlWriter.addAttribute("table:name", d->name); 0277 if (d->isSelection) 0278 xmlWriter.addAttribute("table:is-selection", "true"); 0279 if (d->onUpdateKeepStyles) 0280 xmlWriter.addAttribute("table:on-update-keep-styles", "true"); 0281 if (!d->onUpdateKeepSize) 0282 xmlWriter.addAttribute("table:on-update-keep-size", "false"); 0283 if (!d->hasPersistentData) 0284 xmlWriter.addAttribute("table:has-persistent-data", "false"); 0285 if (d->orientation == Private::Column) 0286 xmlWriter.addAttribute("table:orientation", "column"); 0287 if (!d->containsHeader) 0288 xmlWriter.addAttribute("table:contains-header", "false"); 0289 if (d->displayFilterButtons) 0290 xmlWriter.addAttribute("table:display-filter-buttons", "true"); 0291 xmlWriter.addAttribute("table:target-range-address", Odf::saveRegion(d->targetRangeAddress.name())); 0292 if (d->refreshDelay) 0293 xmlWriter.addAttribute("table:refresh-delay", d->refreshDelay); 0294 // TODO 0295 // if (d->source) 0296 // d->source->saveOdf(xmlWriter); 0297 // if (d->sort) 0298 // d->sort->saveOdf(xmlWriter); 0299 if (d->filter) 0300 d->filter->saveOdf(xmlWriter); 0301 // if (d->subtotalRules) 0302 // d->subtotalRules->saveOdf(xmlWriter); 0303 xmlWriter.endElement(); 0304 } 0305 0306 void Database::operator=(const Database & other) 0307 { 0308 d = other.d; 0309 } 0310 0311 bool Database::operator==(const Database& other) const 0312 { 0313 // NOTE Stefan: Don't compare targetRangeAddress. 0314 if (d->name != other.d->name) 0315 return false; 0316 if (d->isSelection != other.d->isSelection) 0317 return false; 0318 if (d->onUpdateKeepStyles != other.d->onUpdateKeepStyles) 0319 return false; 0320 if (d->onUpdateKeepSize != other.d->onUpdateKeepSize) 0321 return false; 0322 if (d->hasPersistentData != other.d->hasPersistentData) 0323 return false; 0324 if (d->orientation != other.d->orientation) 0325 return false; 0326 if (d->containsHeader != other.d->containsHeader) 0327 return false; 0328 if (d->displayFilterButtons != other.d->displayFilterButtons) 0329 return false; 0330 if (d->refreshDelay != other.d->refreshDelay) 0331 return false; 0332 // if (*d->source != *other.d->source) 0333 // return false; 0334 // if (*d->sort != *other.d->sort) 0335 // return false; 0336 if (*d->filter != *other.d->filter) 0337 return false; 0338 // if (*d->subtotalRules != *other.d->subtotalRules) 0339 // return false; 0340 return true; 0341 } 0342 0343 bool Database::operator<(const Database& other) const 0344 { 0345 return (d < other.d); 0346 } 0347 0348 void Database::dump() const 0349 { 0350 if (d->filter) d->filter->dump(); 0351 }