File indexing completed on 2024-05-12 05:10:13
0001 /*************************************************************************** 0002 Copyright (C) 2003-2009 Robby Stephenson <robby@periapsis.org> 0003 ***************************************************************************/ 0004 0005 /*************************************************************************** 0006 * * 0007 * This program is free software; you can redistribute it and/or * 0008 * modify it under the terms of the GNU General Public License as * 0009 * published by the Free Software Foundation; either version 2 of * 0010 * the License or (at your option) version 3 or any later version * 0011 * accepted by the membership of KDE e.V. (or its successor approved * 0012 * by the membership of KDE e.V.), which shall act as a proxy * 0013 * defined in Section 14 of version 3 of the license. * 0014 * * 0015 * This program is distributed in the hope that it will be useful, * 0016 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0018 * GNU General Public License for more details. * 0019 * * 0020 * You should have received a copy of the GNU General Public License * 0021 * along with this program. If not, see <http://www.gnu.org/licenses/>. * 0022 * * 0023 ***************************************************************************/ 0024 0025 #include "tellicoxmlexporter.h" 0026 #include "tellico_xml.h" 0027 #include "../utils/bibtexhandler.h" // needed for cleaning text 0028 #include "../utils/string_utils.h" 0029 #include "../utils/urlfieldlogic.h" 0030 #include "../entrygroup.h" 0031 #include "../collections/bibtexcollection.h" 0032 #include "../images/imagefactory.h" 0033 #include "../images/image.h" 0034 #include "../images/imageinfo.h" 0035 #include "../core/filehandler.h" 0036 #include "../document.h" 0037 #include "../fieldformat.h" 0038 #include "../models/entrysortmodel.h" 0039 #include "../models/modelmanager.h" 0040 #include "../models/modeliterator.h" 0041 #include "../models/models.h" 0042 #include "../tellico_debug.h" 0043 0044 #include <KLocalizedString> 0045 #include <KConfigGroup> 0046 0047 #include <QDir> 0048 #include <QGroupBox> 0049 #include <QCheckBox> 0050 #include <QDomDocument> 0051 #include <QTextCodec> 0052 #include <QVBoxLayout> 0053 0054 #include <algorithm> 0055 0056 using namespace Tellico; 0057 using Tellico::Export::TellicoXMLExporter; 0058 0059 TellicoXMLExporter::TellicoXMLExporter(Tellico::Data::CollPtr coll) : Exporter(coll), 0060 m_includeImages(false), m_includeGroups(false), m_widget(nullptr), m_checkIncludeImages(nullptr) { 0061 setOptions(options() | Export::ExportImages | Export::ExportImageSize); // not included by default 0062 } 0063 0064 TellicoXMLExporter::~TellicoXMLExporter() { 0065 } 0066 0067 QString TellicoXMLExporter::formatString() const { 0068 return QStringLiteral("XML"); 0069 } 0070 0071 QString TellicoXMLExporter::fileFilter() const { 0072 return i18n("XML Files") + QLatin1String(" (*.xml)") + QLatin1String(";;") + i18n("All Files") + QLatin1String(" (*)"); 0073 } 0074 0075 bool TellicoXMLExporter::exec() { 0076 QDomDocument doc = exportXML(); 0077 if(doc.isNull()) { 0078 return false; 0079 } 0080 return FileHandler::writeTextURL(url(), doc.toString(), 0081 options() & ExportUTF8, 0082 options() & Export::ExportForce); 0083 } 0084 0085 QString TellicoXMLExporter::text() const { 0086 return exportXML().toString(); 0087 } 0088 0089 QDomDocument TellicoXMLExporter::exportXML() const { 0090 int exportVersion = XML::syntaxVersion; 0091 0092 if(exportVersion == 12 && !version12Needed()) { 0093 exportVersion = 11; 0094 } 0095 0096 QDomImplementation impl; 0097 // Bug 443845 - but do not just silent drop the invalid characters 0098 // since that drops emojis and unicode points with surrogate encoding 0099 // instead Tellico::removeControlCodes is used everywhere that 0100 // QDomDocument::createTextNode() is called 0101 // impl.setInvalidDataPolicy(QDomImplementation::DropInvalidChars); 0102 QDomDocumentType doctype = impl.createDocumentType(QStringLiteral("tellico"), 0103 XML::pubTellico(exportVersion), 0104 XML::dtdTellico(exportVersion)); 0105 //default namespace 0106 const QString& ns = XML::nsTellico; 0107 0108 QDomDocument dom = impl.createDocument(ns, QStringLiteral("tellico"), doctype); 0109 0110 // root tellico element 0111 QDomElement root = dom.documentElement(); 0112 0113 QString encodeStr = QStringLiteral("version=\"1.0\" encoding=\""); 0114 if(options() & Export::ExportUTF8) { 0115 encodeStr += QLatin1String("UTF-8"); 0116 } else { 0117 encodeStr += QLatin1String(QTextCodec::codecForLocale()->name()); 0118 } 0119 encodeStr += QLatin1Char('"'); 0120 0121 // createDocument creates a root node, insert the processing instruction before it 0122 dom.insertBefore(dom.createProcessingInstruction(QStringLiteral("xml"), encodeStr), root); 0123 0124 root.setAttribute(QStringLiteral("syntaxVersion"), exportVersion); 0125 0126 FieldFormat::Request format = (options() & Export::ExportFormatted ? 0127 FieldFormat::ForceFormat : 0128 FieldFormat::AsIsFormat); 0129 0130 exportCollectionXML(dom, root, format); 0131 0132 // clear image list 0133 m_images.clear(); 0134 0135 return dom; 0136 } 0137 0138 void TellicoXMLExporter::exportCollectionXML(QDomDocument& dom_, QDomElement& parent_, int format_) const { 0139 Data::CollPtr coll = collection(); 0140 if(!coll) { 0141 myWarning() << "no collection pointer!"; 0142 return; 0143 } 0144 0145 QDomElement collElem = dom_.createElement(QStringLiteral("collection")); 0146 collElem.setAttribute(QStringLiteral("type"), coll->type()); 0147 collElem.setAttribute(QStringLiteral("title"), coll->title()); 0148 0149 QDomElement fieldsElem = dom_.createElement(QStringLiteral("fields")); 0150 collElem.appendChild(fieldsElem); 0151 0152 foreach(Data::FieldPtr field, fields()) { 0153 exportFieldXML(dom_, fieldsElem, field); 0154 } 0155 0156 if(coll->type() == Data::Collection::Bibtex) { 0157 const Data::BibtexCollection* c = static_cast<const Data::BibtexCollection*>(coll.data()); 0158 if(!c->preamble().isEmpty()) { 0159 QDomElement preElem = dom_.createElement(QStringLiteral("bibtex-preamble")); 0160 preElem.appendChild(dom_.createTextNode(removeControlCodes(c->preamble()))); 0161 collElem.appendChild(preElem); 0162 } 0163 0164 QDomElement macrosElem = dom_.createElement(QStringLiteral("macros")); 0165 for(StringMap::ConstIterator macroIt = c->macroList().constBegin(); macroIt != c->macroList().constEnd(); ++macroIt) { 0166 if(!macroIt.value().isEmpty()) { 0167 QDomElement macroElem = dom_.createElement(QStringLiteral("macro")); 0168 macroElem.setAttribute(QStringLiteral("name"), macroIt.key()); 0169 macroElem.appendChild(dom_.createTextNode(removeControlCodes(macroIt.value()))); 0170 macrosElem.appendChild(macroElem); 0171 } 0172 } 0173 if(macrosElem.childNodes().count() > 0) { 0174 collElem.appendChild(macrosElem); 0175 } 0176 } 0177 0178 foreach(Data::EntryPtr entry, entries()) { 0179 exportEntryXML(dom_, collElem, entry, format_); 0180 } 0181 0182 if(!m_images.isEmpty() && (options() & Export::ExportImages)) { 0183 QDomElement imgsElem = dom_.createElement(QStringLiteral("images")); 0184 const QStringList imageIds = m_images.values(); 0185 foreach(const QString& id, m_images) { 0186 exportImageXML(dom_, imgsElem, id); 0187 } 0188 if(imgsElem.hasChildNodes()) { 0189 collElem.appendChild(imgsElem); 0190 } 0191 } 0192 0193 if(m_includeGroups) { 0194 exportGroupXML(dom_, collElem); 0195 } 0196 0197 parent_.appendChild(collElem); 0198 0199 // the borrowers and filters are in the tellico object, not the collection 0200 if(options() & Export::ExportComplete) { 0201 QDomElement bElem = dom_.createElement(QStringLiteral("borrowers")); 0202 foreach(Data::BorrowerPtr borrower, coll->borrowers()) { 0203 exportBorrowerXML(dom_, bElem, borrower); 0204 } 0205 if(bElem.hasChildNodes()) { 0206 parent_.appendChild(bElem); 0207 } 0208 0209 QDomElement fElem = dom_.createElement(QStringLiteral("filters")); 0210 foreach(FilterPtr filter, coll->filters()) { 0211 exportFilterXML(dom_, fElem, filter); 0212 } 0213 if(fElem.hasChildNodes()) { 0214 parent_.appendChild(fElem); 0215 } 0216 } 0217 } 0218 0219 void TellicoXMLExporter::exportFieldXML(QDomDocument& dom_, QDomElement& parent_, Tellico::Data::FieldPtr field_) const { 0220 QDomElement elem = dom_.createElement(QStringLiteral("field")); 0221 0222 elem.setAttribute(QStringLiteral("name"), field_->name()); 0223 elem.setAttribute(QStringLiteral("title"), field_->title()); 0224 elem.setAttribute(QStringLiteral("category"), field_->category()); 0225 elem.setAttribute(QStringLiteral("type"), field_->type()); 0226 elem.setAttribute(QStringLiteral("flags"), field_->flags()); 0227 elem.setAttribute(QStringLiteral("format"), field_->formatType()); 0228 0229 if(field_->type() == Data::Field::Choice) { 0230 elem.setAttribute(QStringLiteral("allowed"), field_->allowed().join(QLatin1String(";"))); 0231 } 0232 0233 // only save description if it's not equal to title, which is the default 0234 // title is never empty, so this indirectly checks for empty descriptions 0235 if(field_->description() != field_->title()) { 0236 elem.setAttribute(QStringLiteral("description"), field_->description()); 0237 } 0238 0239 for(StringMap::ConstIterator it = field_->propertyList().begin(); it != field_->propertyList().end(); ++it) { 0240 if(it.value().isEmpty()) { 0241 continue; 0242 } 0243 QDomElement e = dom_.createElement(QStringLiteral("prop")); 0244 e.setAttribute(QStringLiteral("name"), it.key()); 0245 e.appendChild(dom_.createTextNode(removeControlCodes(it.value()))); 0246 elem.appendChild(e); 0247 } 0248 0249 parent_.appendChild(elem); 0250 } 0251 0252 void TellicoXMLExporter::exportEntryXML(QDomDocument& dom_, QDomElement& parent_, Tellico::Data::EntryPtr entry_, int format_) const { 0253 QDomElement entryElem = dom_.createElement(QStringLiteral("entry")); 0254 entryElem.setAttribute(QStringLiteral("id"), QString::number(entry_->id())); 0255 0256 // iterate through every field for the entry 0257 foreach(Data::FieldPtr fIt, fields()) { 0258 QString fieldName = fIt->name(); 0259 0260 // Date fields are special, don't format in export 0261 QString fieldValue = (format_ == FieldFormat::ForceFormat && fIt->type() != Data::Field::Date) ? 0262 entry_->formattedField(fieldName, FieldFormat::ForceFormat) : 0263 entry_->field(fieldName); 0264 if(options() & ExportClean) { 0265 BibtexHandler::cleanText(fieldValue); 0266 } 0267 0268 // if empty, then no field element is added and just continue 0269 if(fieldValue.isEmpty()) { 0270 continue; 0271 } 0272 0273 // optionally, verify images exist 0274 if(fIt->type() == Data::Field::Image && (options() & Export::ExportVerifyImages)) { 0275 if(!ImageFactory::validImage(fieldValue)) { 0276 myDebug() << "entry: " << entry_->title(); 0277 myDebug() << "skipping image: " << fieldValue; 0278 continue; 0279 } 0280 } 0281 0282 if(fIt->type() == Data::Field::Table) { 0283 // who cares about grammar, just add an 's' to the name 0284 QDomElement parElem = dom_.createElement(fieldName + QLatin1Char('s')); 0285 entryElem.appendChild(parElem); 0286 0287 bool ok; 0288 int ncols = Tellico::toUInt(fIt->property(QStringLiteral("columns")), &ok); 0289 if(!ok || ncols < 1) { 0290 ncols = 1; 0291 } 0292 foreach(const QString& rowValue, FieldFormat::splitTable(fieldValue)) { 0293 QDomElement fieldElem = dom_.createElement(fieldName); 0294 parElem.appendChild(fieldElem); 0295 0296 QStringList columnValues = FieldFormat::splitRow(rowValue); 0297 if(ncols < columnValues.count()) { 0298 // need to combine all the last values, from ncols-1 to end 0299 QString lastValue = QStringList(columnValues.mid(ncols-1)).join(FieldFormat::columnDelimiterString()); 0300 columnValues = columnValues.mid(0, ncols); 0301 columnValues.replace(ncols-1, lastValue); 0302 } 0303 for(int col = 0; col < columnValues.count(); ++col) { 0304 QDomElement elem = dom_.createElement(QStringLiteral("column")); 0305 elem.appendChild(dom_.createTextNode(removeControlCodes(columnValues.at(col)))); 0306 fieldElem.appendChild(elem); 0307 } 0308 } 0309 continue; 0310 } 0311 0312 if(fIt->hasFlag(Data::Field::AllowMultiple)) { 0313 // if multiple versions are allowed, split them into separate elements 0314 // parent element if field contains multiple values, child of entryElem 0315 // who cares about grammar, just add an QLatin1Char('s') to the name 0316 QDomElement parElem = dom_.createElement(fieldName + QLatin1Char('s')); 0317 entryElem.appendChild(parElem); 0318 0319 // the space after the semi-colon is enforced when the field is set for the entry 0320 QStringList fields = FieldFormat::splitValue(fieldValue); 0321 for(QStringList::ConstIterator it = fields.constBegin(); it != fields.constEnd(); ++it) { 0322 // element for field value, child of either entryElem or ParentElem 0323 QDomElement fieldElem = dom_.createElement(fieldName); 0324 fieldElem.appendChild(dom_.createTextNode(removeControlCodes(*it))); 0325 parElem.appendChild(fieldElem); 0326 } 0327 } else { 0328 QDomElement fieldElem = dom_.createElement(fieldName); 0329 entryElem.appendChild(fieldElem); 0330 // Date fields get special treatment 0331 if(fIt->type() == Data::Field::Date) { 0332 // as of Tellico in KF5 (3.0), just forget about the calendar attribute for the moment, always use gregorian 0333 fieldElem.setAttribute(QStringLiteral("calendar"), QStringLiteral("gregorian")); 0334 #if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0)) 0335 QStringList s = fieldValue.split(QLatin1Char('-'), QString::KeepEmptyParts); 0336 #else 0337 QStringList s = fieldValue.split(QLatin1Char('-'), Qt::KeepEmptyParts); 0338 #endif 0339 if(s.count() > 0 && !s[0].isEmpty()) { 0340 QDomElement e = dom_.createElement(QStringLiteral("year")); 0341 fieldElem.appendChild(e); 0342 e.appendChild(dom_.createTextNode(s[0])); 0343 } 0344 if(s.count() > 1 && !s[1].isEmpty()) { 0345 QDomElement e = dom_.createElement(QStringLiteral("month")); 0346 fieldElem.appendChild(e); 0347 e.appendChild(dom_.createTextNode(s[1])); 0348 } 0349 if(s.count() > 2 && !s[2].isEmpty()) { 0350 QDomElement e = dom_.createElement(QStringLiteral("day")); 0351 fieldElem.appendChild(e); 0352 e.appendChild(dom_.createTextNode(s[2])); 0353 } 0354 } else if(fIt->type() == Data::Field::URL && 0355 fIt->property(QStringLiteral("relative")) == QLatin1String("true")) { 0356 // if a relative URL and url() is not empty, change the value! 0357 QUrl old_url = Data::Document::self()->URL().resolved(QUrl(fieldValue)); 0358 if(options() & Export::ExportAbsoluteLinks) { 0359 fieldElem.appendChild(dom_.createTextNode(old_url.url())); 0360 } else if(!url().isEmpty()) { 0361 QUrl new_url(url()); 0362 if(new_url.scheme() == old_url.scheme() && 0363 new_url.host() == old_url.host()) { 0364 // calculate a new relative url 0365 UrlFieldLogic logic; 0366 logic.setRelative(true); 0367 logic.setBaseUrl(url()); 0368 fieldElem.appendChild(dom_.createTextNode(logic.urlText(old_url))); 0369 } else { 0370 // use the absolute url here 0371 fieldElem.appendChild(dom_.createTextNode(old_url.url())); 0372 } 0373 } else { 0374 fieldElem.appendChild(dom_.createTextNode(removeControlCodes(fieldValue))); 0375 } 0376 } else { 0377 fieldElem.appendChild(dom_.createTextNode(removeControlCodes(fieldValue))); 0378 } 0379 } 0380 0381 if(fIt->type() == Data::Field::Image) { 0382 // possible to have more than one entry with the same image 0383 // only want to include it in the output xml once 0384 m_images.add(fieldValue); 0385 } 0386 } // end field loop 0387 0388 parent_.appendChild(entryElem); 0389 } 0390 0391 void TellicoXMLExporter::exportImageXML(QDomDocument& dom_, QDomElement& parent_, const QString& id_) const { 0392 if(id_.isEmpty()) { 0393 myDebug() << "empty image!"; 0394 return; 0395 } 0396 // myLog() << "id = " << id_; 0397 0398 QDomElement imgElem = dom_.createElement(QStringLiteral("image")); 0399 if(m_includeImages) { 0400 const Data::Image& img = ImageFactory::imageById(id_); 0401 if(img.isNull()) { 0402 return; 0403 } 0404 imgElem.setAttribute(QStringLiteral("format"), QLatin1String(img.format())); 0405 imgElem.setAttribute(QStringLiteral("id"), QString(img.id())); 0406 imgElem.setAttribute(QStringLiteral("width"), img.width()); 0407 imgElem.setAttribute(QStringLiteral("height"), img.height()); 0408 if(img.linkOnly()) { 0409 imgElem.setAttribute(QStringLiteral("link"), QStringLiteral("true")); 0410 } 0411 QByteArray imgText = img.byteArray().toBase64(); 0412 imgElem.appendChild(dom_.createTextNode(QLatin1String(imgText))); 0413 } else { 0414 const Data::ImageInfo& info = ImageFactory::imageInfo(id_); 0415 if(info.isNull()) { 0416 return; 0417 } 0418 imgElem.setAttribute(QStringLiteral("format"), QLatin1String(info.format)); 0419 imgElem.setAttribute(QStringLiteral("id"), QString(info.id)); 0420 // only load the images to read the size if necessary 0421 const bool loadImageIfNecessary = options() & Export::ExportImageSize; 0422 imgElem.setAttribute(QStringLiteral("width"), info.width(loadImageIfNecessary)); 0423 imgElem.setAttribute(QStringLiteral("height"), info.height(loadImageIfNecessary)); 0424 if(info.linkOnly) { 0425 imgElem.setAttribute(QStringLiteral("link"), QStringLiteral("true")); 0426 } 0427 } 0428 parent_.appendChild(imgElem); 0429 } 0430 0431 void TellicoXMLExporter::exportGroupXML(QDomDocument& dom_, QDomElement& parent_) const { 0432 Data::EntryList vec = entries(); 0433 bool exportAll = collection()->entries().count() == vec.count(); 0434 // iterate over each group, which are the first children 0435 for(ModelIterator gIt(ModelManager::self()->groupModel()); gIt.group(); ++gIt) { 0436 if(gIt.group()->isEmpty()) { 0437 continue; 0438 } 0439 QDomElement groupElem = dom_.createElement(QStringLiteral("group")); 0440 groupElem.setAttribute(QStringLiteral("title"), gIt.group()->groupName()); 0441 // now iterate over all entry items in the group 0442 Data::EntryList sorted = sortEntries(*gIt.group()); 0443 foreach(Data::EntryPtr eIt, sorted) { 0444 if(!exportAll && vec.indexOf(eIt) == -1) { 0445 continue; 0446 } 0447 QDomElement entryRefElem = dom_.createElement(QStringLiteral("entryRef")); 0448 entryRefElem.setAttribute(QStringLiteral("id"), QString::number(eIt->id())); 0449 groupElem.appendChild(entryRefElem); 0450 } 0451 if(groupElem.hasChildNodes()) { 0452 parent_.appendChild(groupElem); 0453 } 0454 } 0455 } 0456 0457 void TellicoXMLExporter::exportFilterXML(QDomDocument& dom_, QDomElement& parent_, Tellico::FilterPtr filter_) const { 0458 QDomElement filterElem = dom_.createElement(QStringLiteral("filter")); 0459 filterElem.setAttribute(QStringLiteral("name"), filter_->name()); 0460 0461 QString match = (filter_->op() == Filter::MatchAll) ? QStringLiteral("all") : QStringLiteral("any"); 0462 filterElem.setAttribute(QStringLiteral("match"), match); 0463 0464 foreach(FilterRule* rule, *filter_) { 0465 QDomElement ruleElem = dom_.createElement(QStringLiteral("rule")); 0466 ruleElem.setAttribute(QStringLiteral("field"), rule->fieldName()); 0467 ruleElem.setAttribute(QStringLiteral("pattern"), rule->pattern()); 0468 switch(rule->function()) { 0469 case FilterRule::FuncContains: 0470 ruleElem.setAttribute(QStringLiteral("function"), QStringLiteral("contains")); 0471 break; 0472 case FilterRule::FuncNotContains: 0473 ruleElem.setAttribute(QStringLiteral("function"), QStringLiteral("notcontains")); 0474 break; 0475 case FilterRule::FuncEquals: 0476 ruleElem.setAttribute(QStringLiteral("function"), QStringLiteral("equals")); 0477 break; 0478 case FilterRule::FuncNotEquals: 0479 ruleElem.setAttribute(QStringLiteral("function"), QStringLiteral("notequals")); 0480 break; 0481 case FilterRule::FuncRegExp: 0482 ruleElem.setAttribute(QStringLiteral("function"), QStringLiteral("regexp")); 0483 break; 0484 case FilterRule::FuncNotRegExp: 0485 ruleElem.setAttribute(QStringLiteral("function"), QStringLiteral("notregexp")); 0486 break; 0487 case FilterRule::FuncBefore: 0488 ruleElem.setAttribute(QStringLiteral("function"), QStringLiteral("before")); 0489 break; 0490 case FilterRule::FuncAfter: 0491 ruleElem.setAttribute(QStringLiteral("function"), QStringLiteral("after")); 0492 break; 0493 case FilterRule::FuncGreater: 0494 ruleElem.setAttribute(QStringLiteral("function"), QStringLiteral("greaterthan")); 0495 break; 0496 case FilterRule::FuncLess: 0497 ruleElem.setAttribute(QStringLiteral("function"), QStringLiteral("lessthan")); 0498 break; 0499 /* If anything is updated here, be sure to update xmlstatehandler */ 0500 } 0501 filterElem.appendChild(ruleElem); 0502 } 0503 0504 parent_.appendChild(filterElem); 0505 } 0506 0507 void TellicoXMLExporter::exportBorrowerXML(QDomDocument& dom_, QDomElement& parent_, 0508 Tellico::Data::BorrowerPtr borrower_) const { 0509 if(borrower_->isEmpty()) { 0510 return; 0511 } 0512 0513 QDomElement bElem = dom_.createElement(QStringLiteral("borrower")); 0514 parent_.appendChild(bElem); 0515 0516 bElem.setAttribute(QStringLiteral("name"), borrower_->name()); 0517 bElem.setAttribute(QStringLiteral("uid"), borrower_->uid()); 0518 0519 foreach(Data::LoanPtr it, borrower_->loans()) { 0520 QDomElement lElem = dom_.createElement(QStringLiteral("loan")); 0521 bElem.appendChild(lElem); 0522 0523 lElem.setAttribute(QStringLiteral("uid"), it->uid()); 0524 lElem.setAttribute(QStringLiteral("entryRef"), QString::number(it->entry()->id())); 0525 lElem.setAttribute(QStringLiteral("loanDate"), it->loanDate().toString(Qt::ISODate)); 0526 lElem.setAttribute(QStringLiteral("dueDate"), it->dueDate().toString(Qt::ISODate)); 0527 if(it->inCalendar()) { 0528 lElem.setAttribute(QStringLiteral("calendar"), QStringLiteral("true")); 0529 } 0530 0531 lElem.appendChild(dom_.createTextNode(it->note())); 0532 } 0533 } 0534 0535 QWidget* TellicoXMLExporter::widget(QWidget* parent_) { 0536 if(m_widget) { 0537 return m_widget; 0538 } 0539 0540 m_widget = new QWidget(parent_); 0541 QVBoxLayout* l = new QVBoxLayout(m_widget); 0542 0543 QGroupBox* gbox = new QGroupBox(i18n("Tellico XML Options"), m_widget); 0544 QVBoxLayout* vlay = new QVBoxLayout(gbox); 0545 0546 m_checkIncludeImages = new QCheckBox(i18n("Include images in XML document"), gbox); 0547 m_checkIncludeImages->setChecked(m_includeImages); 0548 m_checkIncludeImages->setWhatsThis(i18n("If checked, the images in the document will be included " 0549 "in the XML stream as base64 encoded elements.")); 0550 0551 vlay->addWidget(m_checkIncludeImages); 0552 0553 l->addWidget(gbox); 0554 l->addStretch(1); 0555 return m_widget; 0556 } 0557 0558 void TellicoXMLExporter::readOptions(KSharedConfigPtr config_) { 0559 KConfigGroup group(config_, QStringLiteral("ExportOptions - %1").arg(formatString())); 0560 m_includeImages = group.readEntry("Include Images", m_includeImages); 0561 } 0562 0563 void TellicoXMLExporter::saveOptions(KSharedConfigPtr config_) { 0564 m_includeImages = m_checkIncludeImages->isChecked(); 0565 0566 KConfigGroup group(config_, QStringLiteral("ExportOptions - %1").arg(formatString())); 0567 group.writeEntry("Include Images", m_includeImages); 0568 } 0569 0570 Tellico::Data::EntryList TellicoXMLExporter::sortEntries(const Data::EntryList& entries_) const { 0571 Data::EntryList sorted = entries_; 0572 0573 EntrySortModel* model = static_cast<EntrySortModel*>(ModelManager::self()->entryModel()); 0574 // have to go in reverse for sorting 0575 Data::FieldList fields; 0576 Data::FieldPtr field; 0577 if(model->tertiarySortColumn() > -1) { 0578 field = model->headerData(model->tertiarySortColumn(), Qt::Horizontal, FieldPtrRole).value<Data::FieldPtr>(); 0579 if(field) { 0580 fields << field; 0581 } else { 0582 myDebug() << "no field for tertiary sort column" << model->tertiarySortColumn(); 0583 } 0584 } 0585 if(model->secondarySortColumn() > -1) { 0586 field = model->headerData(model->secondarySortColumn(), Qt::Horizontal, FieldPtrRole).value<Data::FieldPtr>(); 0587 if(field) { 0588 fields << field; 0589 } else { 0590 myDebug() << "no field for secondary sort column" << model->secondarySortColumn(); 0591 } 0592 } 0593 if(model->sortColumn() > -1) { 0594 field = model->headerData(model->sortColumn(), Qt::Horizontal, FieldPtrRole).value<Data::FieldPtr>(); 0595 if(field) { 0596 fields << field; 0597 } else { 0598 myDebug() << "no field for primary sort column" << model->sortColumn(); 0599 } 0600 } 0601 0602 // now sort 0603 foreach(Data::FieldPtr field, fields) { 0604 std::sort(sorted.begin(), sorted.end(), Data::EntryCmp(field->name())); 0605 } 0606 0607 return sorted; 0608 } 0609 0610 bool TellicoXMLExporter::version12Needed() const { 0611 // version 12 is only necessary if the new filter rules are used 0612 foreach(FilterPtr filter, collection()->filters()) { 0613 foreach(FilterRule* rule, *filter) { 0614 if(rule->function() == FilterRule::FuncBefore || 0615 rule->function() == FilterRule::FuncAfter || 0616 rule->function() == FilterRule::FuncGreater || 0617 rule->function() == FilterRule::FuncLess) { 0618 return true; 0619 } 0620 } 0621 } 0622 return false; 0623 }