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