File indexing completed on 2025-01-19 03:53:36
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2008-05-12 0007 * Description : Access to copy-right info of an item in the database 0008 * 0009 * SPDX-FileCopyrightText: 2008-2013 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> 0010 * SPDX-FileCopyrightText: 2009-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0011 * 0012 * SPDX-License-Identifier: GPL-2.0-or-later 0013 * 0014 * ============================================================ */ 0015 0016 #include "itemcopyright.h" 0017 0018 // Qt includes 0019 0020 #include <QLocale> 0021 0022 // Local includes 0023 0024 #include "coredb.h" 0025 #include "coredbaccess.h" 0026 #include "itemscanner.h" 0027 #include "template.h" 0028 0029 namespace Digikam 0030 { 0031 0032 class Q_DECL_HIDDEN ItemCopyrightCache 0033 { 0034 public: 0035 0036 explicit ItemCopyrightCache(ItemCopyright* const obj) 0037 : object(obj), 0038 0039 // read all properties 0040 0041 infos (CoreDbAccess().db()->getItemCopyright(obj->m_id, QString())) 0042 { 0043 // set this as cache 0044 0045 object->m_cache = this; 0046 } 0047 0048 ~ItemCopyrightCache() 0049 { 0050 object->m_cache = nullptr; 0051 } 0052 0053 private: 0054 0055 ItemCopyright* object; 0056 0057 public: 0058 0059 QList<CopyrightInfo> infos; 0060 }; 0061 0062 // ------------------------------------------------------------------------------------------- 0063 0064 ItemCopyright::ItemCopyright(qlonglong imageid) 0065 : m_id (imageid), 0066 m_cache(nullptr) 0067 { 0068 } 0069 0070 ItemCopyright::ItemCopyright() 0071 : m_id (0), 0072 m_cache(nullptr) 0073 { 0074 } 0075 0076 ItemCopyright::ItemCopyright(const ItemCopyright& other) 0077 : m_id (other.m_id), 0078 m_cache(nullptr) 0079 { 0080 // the cache is only short-lived, to keep complexity low 0081 } 0082 0083 ItemCopyright::~ItemCopyright() 0084 { 0085 delete m_cache; 0086 m_cache = nullptr; 0087 } 0088 0089 ItemCopyright& ItemCopyright::operator=(const ItemCopyright& other) 0090 { 0091 if (this != &other) 0092 { 0093 delete m_cache; 0094 m_cache = nullptr; 0095 m_id = other.m_id; 0096 } 0097 0098 return *this; 0099 } 0100 0101 void ItemCopyright::replaceFrom(const ItemCopyright& source) 0102 { 0103 if (!m_id) 0104 { 0105 return; 0106 } 0107 0108 CoreDbAccess access; 0109 access.db()->removeItemCopyrightProperties(m_id); 0110 0111 if (!source.m_id) 0112 { 0113 return; 0114 } 0115 0116 QList<CopyrightInfo> infos = access.db()->getItemCopyright(source.m_id, QString()); 0117 0118 Q_FOREACH (const CopyrightInfo& info, infos) 0119 { 0120 access.db()->setItemCopyrightProperty(m_id, info.property, info.value, 0121 info.extraValue, CoreDB::PropertyNoConstraint); 0122 } 0123 } 0124 0125 QStringList ItemCopyright::creator() const 0126 { 0127 QList<CopyrightInfo> infos = copyrightInfos(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreCreator)); 0128 QStringList list; 0129 0130 Q_FOREACH (const CopyrightInfo& info, infos) 0131 { 0132 list << info.value; 0133 } 0134 0135 return list; 0136 } 0137 0138 void ItemCopyright::setCreator(const QString& creator, ReplaceMode mode) 0139 { 0140 CoreDB::CopyrightPropertyUnique uniqueness; 0141 0142 if (mode == ReplaceAllEntries) 0143 { 0144 uniqueness = CoreDB::PropertyUnique; 0145 } 0146 else 0147 { 0148 uniqueness = CoreDB::PropertyNoConstraint; 0149 } 0150 0151 CoreDbAccess().db()->setItemCopyrightProperty(m_id, ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreCreator), 0152 creator, QString(), uniqueness); 0153 } 0154 0155 void ItemCopyright::removeCreators() 0156 { 0157 removeProperties(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreCreator)); 0158 } 0159 0160 QString ItemCopyright::provider() const 0161 { 0162 return readSimpleProperty(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreProvider)); 0163 } 0164 0165 void ItemCopyright::setProvider(const QString& provider) 0166 { 0167 setSimpleProperty(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreProvider), provider); 0168 } 0169 0170 void ItemCopyright::removeProvider() 0171 { 0172 removeProperties(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreProvider)); 0173 } 0174 0175 QString ItemCopyright::copyrightNotice(const QString& languageCode) 0176 { 0177 return readLanguageProperty(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreCopyrightNotice), languageCode); 0178 } 0179 0180 MetaEngine::AltLangMap ItemCopyright::allCopyrightNotices() 0181 { 0182 return readLanguageProperties(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreCopyrightNotice)); 0183 } 0184 0185 void ItemCopyright::setCopyrightNotice(const QString& notice, const QString& languageCode, ReplaceMode mode) 0186 { 0187 setLanguageProperty(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreCopyrightNotice), notice, languageCode, mode); 0188 } 0189 0190 void ItemCopyright::removeCopyrightNotices() 0191 { 0192 removeProperties(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreCopyrightNotice)); 0193 } 0194 0195 QString ItemCopyright::rightsUsageTerms(const QString& languageCode) 0196 { 0197 return readLanguageProperty(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreRightsUsageTerms), languageCode); 0198 } 0199 0200 MetaEngine::AltLangMap ItemCopyright::allRightsUsageTerms() 0201 { 0202 return readLanguageProperties(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreRightsUsageTerms)); 0203 } 0204 0205 void ItemCopyright::setRightsUsageTerms(const QString& term, const QString& languageCode, ReplaceMode mode) 0206 { 0207 setLanguageProperty(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreRightsUsageTerms), term, languageCode, mode); 0208 } 0209 0210 void ItemCopyright::removeRightsUsageTerms() 0211 { 0212 removeProperties(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreRightsUsageTerms)); 0213 } 0214 0215 QString ItemCopyright::source() 0216 { 0217 return readSimpleProperty(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreSource)); 0218 } 0219 0220 void ItemCopyright::setSource(const QString& source) 0221 { 0222 setSimpleProperty(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreSource), source); 0223 } 0224 0225 void ItemCopyright::removeSource() 0226 { 0227 removeProperties(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreSource)); 0228 } 0229 0230 QString ItemCopyright::creatorJobTitle() const 0231 { 0232 return readSimpleProperty(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreCreatorJobTitle)); 0233 } 0234 0235 void ItemCopyright::setCreatorJobTitle(const QString& title) 0236 { 0237 setSimpleProperty(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreCreatorJobTitle), title); 0238 } 0239 0240 void ItemCopyright::removeCreatorJobTitle() 0241 { 0242 removeProperties(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreCreatorJobTitle)); 0243 } 0244 0245 QString ItemCopyright::instructions() 0246 { 0247 return readSimpleProperty(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreInstructions)); 0248 } 0249 0250 void ItemCopyright::setInstructions(const QString& instructions) 0251 { 0252 setSimpleProperty(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreInstructions), instructions); 0253 } 0254 0255 void ItemCopyright::removeInstructions() 0256 { 0257 removeProperties(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreInstructions)); 0258 } 0259 0260 IptcCoreContactInfo ItemCopyright::contactInfo() 0261 { 0262 IptcCoreContactInfo info; 0263 info.city = readSimpleProperty(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreContactInfoCity)); 0264 info.country = readSimpleProperty(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreContactInfoCountry)); 0265 info.address = readSimpleProperty(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreContactInfoAddress)); 0266 info.postalCode = readSimpleProperty(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreContactInfoPostalCode)); 0267 info.provinceState = readSimpleProperty(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreContactInfoProvinceState)); 0268 info.email = readSimpleProperty(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreContactInfoEmail)); 0269 info.phone = readSimpleProperty(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreContactInfoPhone)); 0270 info.webUrl = readSimpleProperty(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreContactInfoWebUrl)); 0271 0272 return info; 0273 } 0274 0275 void ItemCopyright::setContactInfo(const IptcCoreContactInfo& info) 0276 { 0277 setSimpleProperty(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreContactInfoCity), info.city); 0278 setSimpleProperty(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreContactInfoCountry), info.country); 0279 setSimpleProperty(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreContactInfoAddress), info.address); 0280 setSimpleProperty(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreContactInfoPostalCode), info.postalCode); 0281 setSimpleProperty(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreContactInfoProvinceState), info.provinceState); 0282 setSimpleProperty(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreContactInfoEmail), info.email); 0283 setSimpleProperty(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreContactInfoPhone), info.phone); 0284 setSimpleProperty(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreContactInfoWebUrl), info.webUrl); 0285 } 0286 0287 void ItemCopyright::removeContactInfo() 0288 { 0289 removeProperties(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreContactInfoCity)); 0290 removeProperties(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreContactInfoCountry)); 0291 removeProperties(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreContactInfoAddress)); 0292 removeProperties(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreContactInfoPostalCode)); 0293 removeProperties(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreContactInfoProvinceState)); 0294 removeProperties(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreContactInfoEmail)); 0295 removeProperties(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreContactInfoPhone)); 0296 removeProperties(ItemScanner::iptcCorePropertyName(MetadataInfo::IptcCoreContactInfoWebUrl)); 0297 } 0298 0299 void ItemCopyright::fillTemplate(Template& t) 0300 { 0301 ItemCopyrightCache cache(this); 0302 0303 t.setAuthors(author()); 0304 t.setAuthorsPosition(authorsPosition()); 0305 t.setCredit(credit()); 0306 t.setCopyright(allCopyrightNotices()); 0307 t.setRightUsageTerms(allRightsUsageTerms()); 0308 t.setSource(source()); 0309 t.setInstructions(instructions()); 0310 t.setContactInfo(contactInfo()); 0311 } 0312 0313 void ItemCopyright::setFromTemplate(const Template& t) 0314 { 0315 Q_FOREACH (const QString& author, t.authors()) // krazy:exclude=foreach 0316 { 0317 setAuthor(author, ItemCopyright::AddEntryToExisting); 0318 } 0319 0320 setCredit(t.credit()); 0321 0322 MetaEngine::AltLangMap copyrights = t.copyright(); 0323 MetaEngine::AltLangMap::const_iterator it; 0324 0325 for (it = copyrights.constBegin() ; it != copyrights.constEnd() ; ++it) 0326 { 0327 setRights(it.value(), it.key(), ItemCopyright::AddEntryToExisting); 0328 } 0329 0330 MetaEngine::AltLangMap usages = t.rightUsageTerms(); 0331 MetaEngine::AltLangMap::const_iterator it2; 0332 0333 for (it2 = usages.constBegin() ; it2 != usages.constEnd() ; ++it2) 0334 { 0335 setRightsUsageTerms(it2.value(), it2.key(), ItemCopyright::AddEntryToExisting); 0336 } 0337 0338 setSource(t.source()); 0339 setAuthorsPosition(t.authorsPosition()); 0340 setInstructions(t.instructions()); 0341 setContactInfo(t.contactInfo()); 0342 } 0343 0344 void ItemCopyright::removeAll() 0345 { 0346 ItemCopyrightCache cache(this); 0347 0348 removeCreators(); 0349 removeProvider(); 0350 removeCopyrightNotices(); 0351 removeRightsUsageTerms(); 0352 removeSource(); 0353 removeCreatorJobTitle(); 0354 removeInstructions(); 0355 removeContactInfo(); 0356 } 0357 0358 CopyrightInfo ItemCopyright::copyrightInfo(const QString& property) const 0359 { 0360 if (m_cache) 0361 { 0362 Q_FOREACH (const CopyrightInfo& info, m_cache->infos) 0363 { 0364 if (info.property == property) 0365 { // cppcheck-suppress useStlAlgorithm 0366 return info; 0367 } 0368 } 0369 } 0370 else 0371 { 0372 QList<CopyrightInfo> infos = CoreDbAccess().db()->getItemCopyright(m_id, property); 0373 0374 if (!infos.isEmpty()) 0375 { 0376 return infos.first(); 0377 } 0378 } 0379 0380 return CopyrightInfo(); 0381 } 0382 0383 QList<CopyrightInfo> ItemCopyright::copyrightInfos(const QString& property) const 0384 { 0385 if (m_cache) 0386 { 0387 QList<CopyrightInfo> infos; 0388 0389 Q_FOREACH (const CopyrightInfo& info, m_cache->infos) 0390 { 0391 if (info.property == property) 0392 { 0393 infos << info; 0394 } 0395 } 0396 0397 return infos; 0398 } 0399 else 0400 { 0401 return CoreDbAccess().db()->getItemCopyright(m_id, property); 0402 } 0403 } 0404 0405 QString ItemCopyright::readSimpleProperty(const QString& property) const 0406 { 0407 return copyrightInfo(property).value; 0408 } 0409 0410 void ItemCopyright::setSimpleProperty(const QString& property, const QString& value) 0411 { 0412 CoreDbAccess().db()->setItemCopyrightProperty(m_id, property, value, QString(), CoreDB::PropertyUnique); 0413 } 0414 0415 QString ItemCopyright::readLanguageProperty(const QString& property, const QString& languageCode) 0416 { 0417 QList<CopyrightInfo> infos = copyrightInfos(property); 0418 int index = languageMatch(infos, languageCode); 0419 0420 if (index == -1) 0421 { 0422 return QString(); 0423 } 0424 else 0425 { 0426 return infos.at(index).value; 0427 } 0428 } 0429 0430 MetaEngine::AltLangMap ItemCopyright::readLanguageProperties(const QString& property) 0431 { 0432 MetaEngine::AltLangMap map; 0433 QList<CopyrightInfo> infos = copyrightInfos(property); 0434 0435 Q_FOREACH (const CopyrightInfo& info, infos) 0436 { 0437 map[info.extraValue] = info.value; 0438 } 0439 0440 return map; 0441 } 0442 0443 void ItemCopyright::setLanguageProperty(const QString& property, const QString& value, 0444 const QString& languageCode, ReplaceMode mode) 0445 { 0446 CoreDB::CopyrightPropertyUnique uniqueness; 0447 0448 if (mode == ReplaceAllEntries) 0449 { 0450 uniqueness = CoreDB::PropertyUnique; 0451 } 0452 else if (mode == ReplaceLanguageEntry) 0453 { 0454 uniqueness = CoreDB::PropertyExtraValueUnique; 0455 } 0456 else 0457 { 0458 uniqueness = CoreDB::PropertyNoConstraint; 0459 } 0460 0461 QString language = languageCode; 0462 0463 if (language.isNull()) 0464 { 0465 language = QLatin1String("x-default"); 0466 } 0467 0468 CoreDbAccess().db()->setItemCopyrightProperty(m_id, property, value, language, uniqueness); 0469 } 0470 0471 void ItemCopyright::removeProperties(const QString& property) 0472 { 0473 // if we have a cache, find out if anything need to be done at all 0474 0475 if (m_cache && copyrightInfo(property).isNull()) 0476 { 0477 return; 0478 } 0479 0480 CoreDbAccess().db()->removeItemCopyrightProperties(m_id, property); 0481 } 0482 0483 void ItemCopyright::removeLanguageProperty(const QString& property, const QString& languageCode) 0484 { 0485 if (m_cache && copyrightInfo(property).isNull()) 0486 { 0487 return; 0488 } 0489 0490 CoreDbAccess().db()->removeItemCopyrightProperties(m_id, property, languageCode); 0491 } 0492 0493 int ItemCopyright::languageMatch(const QList<CopyrightInfo>& infos, const QString& languageCode) const 0494 { 0495 QString langCode; 0496 QString fullCode = languageCode; 0497 0498 if (languageCode.isNull()) 0499 { 0500 // find local language 0501 0502 QString spec = QLocale().name().toLower(); 0503 langCode = spec.left(spec.indexOf(QLatin1Char('_'))) + QLatin1Char('-'); 0504 fullCode = spec.replace(QLatin1Char('_'), QLatin1Char('-')); 0505 } 0506 else if (languageCode == QLatin1String("x-default")) 0507 { 0508 langCode = languageCode; 0509 } 0510 else 0511 { 0512 // en-us => en- 0513 0514 langCode = languageCode.section(QLatin1Char('-'), 0, 0, QString::SectionIncludeTrailingSep); 0515 } 0516 0517 int fullCodeMatch, langCodeMatch, defaultCodeMatch, firstMatch; 0518 fullCodeMatch = -1; 0519 langCodeMatch = -1; 0520 defaultCodeMatch = -1; 0521 firstMatch = -1; 0522 0523 (void)firstMatch; // Remove clang warning. 0524 0525 if (infos.isEmpty()) 0526 { 0527 return -1; 0528 } 0529 else 0530 { 0531 firstMatch = 0; // index of first entry - at least we have one 0532 } 0533 0534 // First we search for a full match 0535 // Second for a match of the language code 0536 // Third for the default code 0537 // Fourth we return the first comment 0538 0539 QLatin1String defaultCode("x-default"); 0540 0541 for (int i = 0 ; i < infos.size() ; ++i) 0542 { 0543 const CopyrightInfo& info = infos.at(i); 0544 0545 if (info.extraValue == fullCode) 0546 { 0547 fullCodeMatch = i; 0548 break; 0549 } 0550 else if (info.extraValue.startsWith(langCode) && (langCodeMatch == -1)) 0551 { 0552 langCodeMatch = i; 0553 } 0554 else if (info.extraValue == defaultCode) 0555 { 0556 defaultCodeMatch = i; 0557 } 0558 } 0559 0560 int chosen = fullCodeMatch; 0561 0562 if (chosen == -1) 0563 { 0564 chosen = langCodeMatch; 0565 } 0566 0567 if (chosen == -1) 0568 { 0569 chosen = defaultCodeMatch; 0570 } 0571 0572 if (chosen == -1) 0573 { 0574 chosen = firstMatch; 0575 } 0576 0577 return chosen; 0578 } 0579 0580 } // namespace Digikam