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