File indexing completed on 2025-01-05 03:57:18
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2009-06-20 0007 * Description : metadata template manager. 0008 * 0009 * SPDX-FileCopyrightText: 2009-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0010 * SPDX-FileCopyrightText: 2009-2010 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> 0011 * 0012 * SPDX-License-Identifier: GPL-2.0-or-later 0013 * 0014 * ============================================================ */ 0015 0016 #include "templatemanager.h" 0017 0018 // Qt includes 0019 0020 #include <QFile> 0021 #include <QDomDocument> 0022 #include <QDomElement> 0023 #include <QMutex> 0024 #include <QTextStream> 0025 #if QT_VERSION < QT_VERSION_CHECK(6,0,0) 0026 #include <QTextCodec> 0027 #endif 0028 #include <QStandardPaths> 0029 0030 // Local includes 0031 0032 #include "template.h" 0033 0034 namespace Digikam 0035 { 0036 0037 class Q_DECL_HIDDEN TemplateManager::Private 0038 { 0039 public: 0040 0041 explicit Private() 0042 : modified(false), 0043 mutex () 0044 { 0045 } 0046 0047 bool modified; 0048 0049 QList<Template> pList; 0050 QString file; 0051 0052 QMutex mutex; 0053 }; 0054 0055 class Q_DECL_HIDDEN TemplateManagerCreator 0056 { 0057 public: 0058 0059 TemplateManager object; 0060 }; 0061 0062 Q_GLOBAL_STATIC(TemplateManagerCreator, creator) 0063 0064 TemplateManager* TemplateManager::defaultManager() 0065 { 0066 return &creator->object; 0067 } 0068 0069 TemplateManager::TemplateManager() 0070 : d(new Private) 0071 { 0072 d->file = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QLatin1String("/template.xml"); 0073 0074 load(); 0075 } 0076 0077 TemplateManager::~TemplateManager() 0078 { 0079 save(); 0080 clear(); 0081 delete d; 0082 } 0083 0084 bool TemplateManager::load() 0085 { 0086 d->modified = false; 0087 0088 QFile file(d->file); 0089 0090 if (!file.open(QIODevice::ReadOnly)) 0091 { 0092 return false; 0093 } 0094 0095 QDomDocument doc(QLatin1String("templatelist")); 0096 0097 if (!doc.setContent(&file)) 0098 { 0099 return false; 0100 } 0101 0102 QDomElement docElem = doc.documentElement(); 0103 0104 if (docElem.tagName() != QLatin1String("templatelist")) 0105 { 0106 return false; 0107 } 0108 0109 for (QDomNode n = docElem.firstChild() ; !n.isNull() ; n = n.nextSibling()) 0110 { 0111 QDomElement e = n.toElement(); 0112 0113 if (e.isNull()) 0114 { 0115 continue; 0116 } 0117 0118 if (e.tagName() != QLatin1String("template")) 0119 { 0120 continue; 0121 } 0122 0123 Template t; 0124 IptcCoreLocationInfo locationInf; 0125 IptcCoreContactInfo contactInf; 0126 0127 for (QDomNode n2 = e.firstChild() ; !n2.isNull() ; n2 = n2.nextSibling()) 0128 { 0129 QDomElement e2 = n2.toElement(); 0130 0131 if (e2.isNull()) 0132 { 0133 continue; 0134 } 0135 0136 QString name2 = e2.tagName(); 0137 QString val2 = e2.attribute(QLatin1String("value")); 0138 0139 if (name2 == QLatin1String("templatetitle")) 0140 { 0141 t.setTemplateTitle(val2); 0142 } 0143 else if (name2 == QLatin1String("authorsposition")) 0144 { 0145 t.setAuthorsPosition(val2); 0146 } 0147 else if (name2 == QLatin1String("credit")) 0148 { 0149 t.setCredit(val2); 0150 } 0151 else if (name2 == QLatin1String("source")) 0152 { 0153 t.setSource(val2); 0154 } 0155 else if (name2 == QLatin1String("instructions")) 0156 { 0157 t.setInstructions(val2); 0158 } 0159 else if (name2 == QLatin1String("authors")) 0160 { 0161 QStringList list; 0162 0163 for (QDomNode n3 = e2.firstChild() ; !n3.isNull() ; n3 = n3.nextSibling()) 0164 { 0165 QDomElement e3 = n3.toElement(); 0166 QString key = e3.tagName(); 0167 QString val = e3.attribute(QLatin1String("value")); 0168 0169 if (key == QLatin1String("name")) 0170 { 0171 if (val.isEmpty()) 0172 { 0173 continue; 0174 } 0175 0176 list.append(val); 0177 } 0178 } 0179 0180 t.setAuthors(list); 0181 } 0182 else if (name2 == QLatin1String("copyright")) 0183 { 0184 MetaEngine::AltLangMap copyrights; 0185 0186 for (QDomNode n3 = e2.firstChild() ; !n3.isNull() ; n3 = n3.nextSibling()) 0187 { 0188 QDomElement e3 = n3.toElement(); 0189 QString key = e3.tagName(); 0190 QString val = e3.attribute(QLatin1String("value")); 0191 copyrights.insert(key, val); 0192 } 0193 0194 t.setCopyright(copyrights); 0195 } 0196 else if (name2 == QLatin1String("rightusageterms")) 0197 { 0198 MetaEngine::AltLangMap usages; 0199 0200 for (QDomNode n3 = e2.firstChild() ; !n3.isNull() ; n3 = n3.nextSibling()) 0201 { 0202 QDomElement e3 = n3.toElement(); 0203 QString key = e3.tagName(); 0204 QString val = e3.attribute(QLatin1String("value")); 0205 usages.insert(key, val); 0206 } 0207 0208 t.setRightUsageTerms(usages); 0209 } 0210 else if (name2 == QLatin1String("locationcountry")) 0211 { 0212 locationInf.country = val2; 0213 } 0214 else if (name2 == QLatin1String("locationcountrycode")) 0215 { 0216 locationInf.countryCode = val2; 0217 } 0218 else if (name2 == QLatin1String("locationprovincestate")) 0219 { 0220 locationInf.provinceState = val2; 0221 } 0222 else if (name2 == QLatin1String("locationcity")) 0223 { 0224 locationInf.city = val2; 0225 } 0226 else if (name2 == QLatin1String("locationlocation")) 0227 { 0228 locationInf.location = val2; 0229 } 0230 else if (name2 == QLatin1String("contactcity")) 0231 { 0232 contactInf.city = val2; 0233 } 0234 else if (name2 == QLatin1String("contactcountry")) 0235 { 0236 contactInf.country = val2; 0237 } 0238 else if (name2 == QLatin1String("contactaddress")) 0239 { 0240 contactInf.address = val2; 0241 } 0242 else if (name2 == QLatin1String("contactpostalcode")) 0243 { 0244 contactInf.postalCode = val2; 0245 } 0246 else if (name2 == QLatin1String("contactprovincestate")) 0247 { 0248 contactInf.provinceState = val2; 0249 } 0250 else if (name2 == QLatin1String("contactemail")) 0251 { 0252 contactInf.email = val2; 0253 } 0254 else if (name2 == QLatin1String("contactphone")) 0255 { 0256 contactInf.phone = val2; 0257 } 0258 else if (name2 == QLatin1String("contactweburl")) 0259 { 0260 contactInf.webUrl = val2; 0261 } 0262 else if (name2 == QLatin1String("subjects")) 0263 { 0264 QStringList list; 0265 0266 for (QDomNode n3 = e2.firstChild() ; !n3.isNull() ; n3 = n3.nextSibling()) 0267 { 0268 QDomElement e3 = n3.toElement(); 0269 QString key = e3.tagName(); 0270 QString val = e3.attribute(QLatin1String("value")); 0271 0272 if (key == QLatin1String("subject")) 0273 { 0274 if (val.isEmpty()) 0275 { 0276 continue; 0277 } 0278 0279 list.append(val); 0280 } 0281 } 0282 0283 t.setIptcSubjects(list); 0284 } 0285 } 0286 0287 t.setLocationInfo(locationInf); 0288 t.setContactInfo(contactInf); 0289 insertPrivate(t); 0290 } 0291 0292 return true; 0293 } 0294 0295 bool TemplateManager::save() 0296 { 0297 // If not modified don't save the file 0298 0299 if (!d->modified) 0300 { 0301 return true; 0302 } 0303 0304 QDomDocument doc(QLatin1String("templatelist")); 0305 doc.setContent(QLatin1String("<!DOCTYPE XMLTemplateList><templatelist version=\"2.0\" client=\"digikam\" encoding=\"UTF-8\"/>")); 0306 QDomElement docElem = doc.documentElement(); 0307 0308 { 0309 QMutexLocker lock(&d->mutex); 0310 0311 Q_FOREACH (const Template& t, d->pList) 0312 { 0313 QDomElement elem = doc.createElement(QLatin1String("template")); 0314 0315 QDomElement templatetitle = doc.createElement(QLatin1String("templatetitle")); 0316 templatetitle.setAttribute(QLatin1String("value"), t.templateTitle()); 0317 elem.appendChild(templatetitle); 0318 0319 QDomElement authorsposition = doc.createElement(QLatin1String("authorsposition")); 0320 authorsposition.setAttribute(QLatin1String("value"), t.authorsPosition()); 0321 elem.appendChild(authorsposition); 0322 0323 QDomElement credit = doc.createElement(QLatin1String("credit")); 0324 credit.setAttribute(QLatin1String("value"), t.credit()); 0325 elem.appendChild(credit); 0326 0327 QDomElement source = doc.createElement(QLatin1String("source")); 0328 source.setAttribute(QLatin1String("value"), t.source()); 0329 elem.appendChild(source); 0330 0331 QDomElement instructions = doc.createElement(QLatin1String("instructions")); 0332 instructions.setAttribute(QLatin1String("value"), t.instructions()); 0333 elem.appendChild(instructions); 0334 0335 QDomElement authors = doc.createElement(QLatin1String("authors")); 0336 elem.appendChild(authors); 0337 0338 Q_FOREACH (const QString& name, t.authors()) 0339 { 0340 QDomElement e = doc.createElement(QLatin1String("name")); 0341 e.setAttribute(QLatin1String("value"), name); 0342 authors.appendChild(e); 0343 } 0344 0345 QDomElement copyright = doc.createElement(QLatin1String("copyright")); 0346 elem.appendChild(copyright); 0347 MetaEngine::AltLangMap rights = t.copyright(); 0348 MetaEngine::AltLangMap::const_iterator it; 0349 0350 for (it = rights.constBegin() ; it != rights.constEnd() ; ++it) 0351 { 0352 QDomElement e = doc.createElement(it.key()); 0353 e.setAttribute(QLatin1String("value"), it.value()); 0354 copyright.appendChild(e); 0355 } 0356 0357 QDomElement rightusageterms = doc.createElement(QLatin1String("rightusageterms")); 0358 elem.appendChild(rightusageterms); 0359 MetaEngine::AltLangMap usages = t.rightUsageTerms(); 0360 MetaEngine::AltLangMap::const_iterator it2; 0361 0362 for (it2 = usages.constBegin() ; it2 != usages.constEnd() ; ++it2) 0363 { 0364 QDomElement e = doc.createElement(it2.key()); 0365 e.setAttribute(QLatin1String("value"), it2.value()); 0366 rightusageterms.appendChild(e); 0367 } 0368 0369 docElem.appendChild(elem); 0370 0371 QDomElement locationcountry = doc.createElement(QLatin1String("locationcountry")); 0372 locationcountry.setAttribute(QLatin1String("value"), t.locationInfo().country); 0373 elem.appendChild(locationcountry); 0374 0375 QDomElement locationcountrycode = doc.createElement(QLatin1String("locationcountrycode")); 0376 locationcountrycode.setAttribute(QLatin1String("value"), t.locationInfo().countryCode); 0377 elem.appendChild(locationcountrycode); 0378 0379 QDomElement locationprovincestate = doc.createElement(QLatin1String("locationprovincestate")); 0380 locationprovincestate.setAttribute(QLatin1String("value"), t.locationInfo().provinceState); 0381 elem.appendChild(locationprovincestate); 0382 0383 QDomElement locationcity = doc.createElement(QLatin1String("locationcity")); 0384 locationcity.setAttribute(QLatin1String("value"), t.locationInfo().city); 0385 elem.appendChild(locationcity); 0386 0387 QDomElement locationlocation = doc.createElement(QLatin1String("locationlocation")); 0388 locationlocation.setAttribute(QLatin1String("value"), t.locationInfo().location); 0389 elem.appendChild(locationlocation); 0390 0391 QDomElement contactcity = doc.createElement(QLatin1String("contactcity")); 0392 contactcity.setAttribute(QLatin1String("value"), t.contactInfo().city); 0393 elem.appendChild(contactcity); 0394 0395 QDomElement contactcountry = doc.createElement(QLatin1String("contactcountry")); 0396 contactcountry.setAttribute(QLatin1String("value"), t.contactInfo().country); 0397 elem.appendChild(contactcountry); 0398 0399 QDomElement contactaddress = doc.createElement(QLatin1String("contactaddress")); 0400 contactaddress.setAttribute(QLatin1String("value"), t.contactInfo().address); 0401 elem.appendChild(contactaddress); 0402 0403 QDomElement contactpostalcode = doc.createElement(QLatin1String("contactpostalcode")); 0404 contactpostalcode.setAttribute(QLatin1String("value"), t.contactInfo().postalCode); 0405 elem.appendChild(contactpostalcode); 0406 0407 QDomElement contactprovincestate = doc.createElement(QLatin1String("contactprovincestate")); 0408 contactprovincestate.setAttribute(QLatin1String("value"), t.contactInfo().provinceState); 0409 elem.appendChild(contactprovincestate); 0410 0411 QDomElement contactemail = doc.createElement(QLatin1String("contactemail")); 0412 contactemail.setAttribute(QLatin1String("value"), t.contactInfo().email); 0413 elem.appendChild(contactemail); 0414 0415 QDomElement contactphone = doc.createElement(QLatin1String("contactphone")); 0416 contactphone.setAttribute(QLatin1String("value"), t.contactInfo().phone); 0417 elem.appendChild(contactphone); 0418 0419 QDomElement contactweburl = doc.createElement(QLatin1String("contactweburl")); 0420 contactweburl.setAttribute(QLatin1String("value"), t.contactInfo().webUrl); 0421 elem.appendChild(contactweburl); 0422 0423 QDomElement subjects = doc.createElement(QLatin1String("subjects")); 0424 elem.appendChild(subjects); 0425 0426 Q_FOREACH (const QString& subject, t.IptcSubjects()) 0427 { 0428 QDomElement e = doc.createElement(QLatin1String("subject")); 0429 e.setAttribute(QLatin1String("value"), subject); 0430 subjects.appendChild(e); 0431 } 0432 } 0433 } 0434 0435 QFile file(d->file); 0436 0437 if (!file.open(QIODevice::WriteOnly)) 0438 { 0439 return false; 0440 } 0441 0442 QTextStream stream(&file); 0443 #if QT_VERSION < QT_VERSION_CHECK(6,0,0) 0444 // In Qt5 only. Qt6 uses UTF-8 by default. 0445 stream.setCodec(QTextCodec::codecForName("UTF-8")); 0446 #endif 0447 stream.setAutoDetectUnicode(true); 0448 stream << doc.toString(); 0449 file.close(); 0450 0451 return true; 0452 } 0453 0454 void TemplateManager::insert(const Template& t) 0455 { 0456 if (t.isNull()) 0457 { 0458 return; 0459 } 0460 0461 d->modified = true; 0462 insertPrivate(t); 0463 } 0464 0465 void TemplateManager::remove(const Template& t) 0466 { 0467 if (t.isNull()) 0468 { 0469 return; 0470 } 0471 0472 d->modified = true; 0473 removePrivate(t); 0474 } 0475 0476 void TemplateManager::insertPrivate(const Template& t) 0477 { 0478 if (t.isNull()) 0479 { 0480 return; 0481 } 0482 0483 { 0484 QMutexLocker lock(&d->mutex); 0485 d->pList.append(t); 0486 } 0487 0488 Q_EMIT signalTemplateAdded(t); 0489 } 0490 0491 void TemplateManager::removePrivate(const Template& t) 0492 { 0493 if (t.isNull()) 0494 { 0495 return; 0496 } 0497 0498 { 0499 QMutexLocker lock(&d->mutex); 0500 0501 for (QList<Template>::iterator it = d->pList.begin() ; it != d->pList.end() ; ++it) 0502 { 0503 if (it->templateTitle() == t.templateTitle()) 0504 { 0505 it = d->pList.erase(it); 0506 break; 0507 } 0508 } 0509 } 0510 0511 Q_EMIT signalTemplateRemoved(t); 0512 } 0513 0514 void TemplateManager::clear() 0515 { 0516 QList<Template> oldTemplates = d->pList; 0517 0518 { 0519 QMutexLocker lock(&d->mutex); 0520 d->pList.clear(); 0521 } 0522 0523 Q_FOREACH (const Template& t, d->pList) 0524 { 0525 Q_EMIT signalTemplateRemoved(t); 0526 } 0527 } 0528 0529 QList<Template> TemplateManager::templateList() const 0530 { 0531 return d->pList; 0532 } 0533 0534 Template TemplateManager::findByTitle(const QString& title) const 0535 { 0536 QMutexLocker lock(&d->mutex); 0537 0538 Q_FOREACH (const Template& t, d->pList) 0539 { 0540 if (t.templateTitle() == title) 0541 { // cppcheck-suppress useStlAlgorithm 0542 return t; 0543 } 0544 } 0545 0546 return Template(); 0547 } 0548 0549 Template TemplateManager::findByContents(const Template& tref) const 0550 { 0551 QMutexLocker lock(&d->mutex); 0552 0553 Q_FOREACH (const Template& t, d->pList) 0554 { 0555 if (t == tref) 0556 { // cppcheck-suppress useStlAlgorithm 0557 return t; 0558 } 0559 } 0560 0561 return Template(); 0562 } 0563 0564 Template TemplateManager::fromIndex(int index) const 0565 { 0566 QMutexLocker lock(&d->mutex); 0567 0568 if ((index >= 0) && (index < d->pList.size())) 0569 { 0570 return d->pList.at(index); 0571 } 0572 0573 return Template(); 0574 } 0575 0576 } // namespace Digikam 0577 0578 #include "moc_templatemanager.cpp"