File indexing completed on 2024-05-12 15:55:35

0001 // SPDX-FileCopyrightText: 2003 Lukáš Tinkl <lukas@kde.org>
0002 // SPDX-FileCopyrightText: 2003-2007 Dirk Mueller <mueller@kde.org>
0003 // SPDX-FileCopyrightText: 2003-2005 Stephan Binner <binner@kde.org>
0004 // SPDX-FileCopyrightText: 2003-2022 Jesper K. Pedersen <jesper.pedersen@kdab.com>
0005 // SPDX-FileCopyrightText: 2006-2008 Tuomas Suutari <tuomas@nepnep.net>
0006 // SPDX-FileCopyrightText: 2007 Rafael Fernández López <ereslibre@kde.org>
0007 // SPDX-FileCopyrightText: 2007-2009 Laurent Montel <montel@kde.org>
0008 // SPDX-FileCopyrightText: 2007-2010 Jan Kundrát <jkt@flaska.net>
0009 // SPDX-FileCopyrightText: 2008 David Faure <faure@kde.org>
0010 // SPDX-FileCopyrightText: 2008 Henner Zeller <h.zeller@acm.org>
0011 // SPDX-FileCopyrightText: 2009-2012 Miika Turkia <miika.turkia@gmail.com>
0012 // SPDX-FileCopyrightText: 2010 Pino Toscano <pino@kde.org>
0013 // SPDX-FileCopyrightText: 2010 Wes Hardaker <kpa@capturedonearth.com>
0014 // SPDX-FileCopyrightText: 2011 Andreas Neustifter <andreas.neustifter@gmail.com>
0015 // SPDX-FileCopyrightText: 2012-2023 Johannes Zarl-Zierl <johannes@zarl-zierl.at>
0016 // SPDX-FileCopyrightText: 2014-2022 Tobias Leupold <tl@stonemx.de>
0017 // SPDX-FileCopyrightText: 2018 Antoni Bella Pérez <antonibella5@yahoo.com>
0018 // SPDX-FileCopyrightText: 2019 Robert Krawitz <rlk@alum.mit.edu>
0019 //
0020 // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0021 
0022 #include "SettingsData.h"
0023 
0024 #include "Logging.h"
0025 
0026 #include <KConfig>
0027 #include <KConfigGroup>
0028 #include <KLocalizedString>
0029 #include <KSharedConfig>
0030 #include <QStringList>
0031 #include <QThread>
0032 #include <type_traits>
0033 
0034 namespace
0035 {
0036 // when used from an application with different component name
0037 // (e.g. kpa-thumbnailtool), we need to explicitly set the component name:
0038 const QString configFile = QString::fromLatin1("kphotoalbumrc");
0039 }
0040 #define STR(x) QString::fromLatin1(x)
0041 
0042 #define cfgValue(GROUP, OPTION, DEFAULT) \
0043     KSharedConfig::openConfig(configFile)->group(GROUP).readEntry(OPTION, DEFAULT)
0044 
0045 #define setValue(GROUP, OPTION, VALUE)                                            \
0046     do {                                                                          \
0047         KConfigGroup group = KSharedConfig::openConfig(configFile)->group(GROUP); \
0048         group.writeEntry(OPTION, VALUE);                                          \
0049         group.sync();                                                             \
0050     } while (0)
0051 
0052 #define getValueFunc_(TYPE, FUNC, GROUP, OPTION, DEFAULT)           \
0053     TYPE SettingsData::FUNC() const                                 \
0054     {                                                               \
0055         return static_cast<TYPE>(cfgValue(GROUP, OPTION, DEFAULT)); \
0056     }
0057 
0058 #define setValueFunc_(FUNC, TYPE, GROUP, OPTION, VALUE) \
0059     void SettingsData::FUNC(const TYPE v)               \
0060     {                                                   \
0061         setValue(GROUP, OPTION, VALUE);                 \
0062     }
0063 
0064 #define getValueFunc(TYPE, FUNC, GROUP, DEFAULT) getValueFunc_(TYPE, FUNC, #GROUP, #FUNC, DEFAULT)
0065 #define setValueFunc(FUNC, TYPE, GROUP, OPTION) setValueFunc_(FUNC, TYPE, #GROUP, #OPTION, v)
0066 
0067 // TODO(mfwitten): document parameters.
0068 #define property_(GET_TYPE, GET_FUNC, GET_VALUE, SET_FUNC, SET_TYPE, SET_VALUE, GROUP, OPTION, GET_DEFAULT_1, GET_DEFAULT_2, GET_DEFAULT_2_TYPE) \
0069     GET_TYPE SettingsData::GET_FUNC() const                                                                                                      \
0070     {                                                                                                                                            \
0071         const KConfigGroup g = KSharedConfig::openConfig(configFile)->group(GROUP);                                                              \
0072                                                                                                                                                  \
0073         if (!g.hasKey(OPTION))                                                                                                                   \
0074             return GET_DEFAULT_1;                                                                                                                \
0075                                                                                                                                                  \
0076         GET_DEFAULT_2_TYPE v = g.readEntry(OPTION, static_cast<GET_DEFAULT_2_TYPE>(GET_DEFAULT_2));                                              \
0077         return static_cast<GET_TYPE>(GET_VALUE);                                                                                                 \
0078     }                                                                                                                                            \
0079     setValueFunc_(SET_FUNC, SET_TYPE, GROUP, OPTION, SET_VALUE)
0080 
0081 #define property(GET_TYPE, GET_FUNC, SET_FUNC, SET_TYPE, SET_VALUE, GROUP, OPTION, GET_DEFAULT) \
0082     getValueFunc_(GET_TYPE, GET_FUNC, GROUP, OPTION, GET_DEFAULT)                               \
0083         setValueFunc_(SET_FUNC, SET_TYPE, GROUP, OPTION, SET_VALUE)
0084 
0085 #define property_copy(GET_FUNC, SET_FUNC, TYPE, GROUP, GET_DEFAULT) \
0086     property(TYPE, GET_FUNC, SET_FUNC, TYPE, v, #GROUP, #GET_FUNC, GET_DEFAULT)
0087 
0088 #define property_ref_(GET_FUNC, SET_FUNC, TYPE, GROUP, GET_DEFAULT) \
0089     property(TYPE, GET_FUNC, SET_FUNC, TYPE &, v, GROUP, #GET_FUNC, GET_DEFAULT)
0090 
0091 #define property_ref(GET_FUNC, SET_FUNC, TYPE, GROUP, GET_DEFAULT) \
0092     property(TYPE, GET_FUNC, SET_FUNC, TYPE &, v, #GROUP, #GET_FUNC, GET_DEFAULT)
0093 
0094 #define property_enum(GET_FUNC, SET_FUNC, TYPE, GROUP, GET_DEFAULT) \
0095     property(TYPE, GET_FUNC, SET_FUNC, TYPE, static_cast<int>(v), #GROUP, #GET_FUNC, static_cast<int>(GET_DEFAULT))
0096 
0097 #define property_sset(GET_FUNC, SET_FUNC, GROUP, GET_DEFAULT) \
0098     property_(StringSet, GET_FUNC, (StringSet { v.begin(), v.end() }), SET_FUNC, StringSet &, (QStringList { v.begin(), v.end() }), #GROUP, #GET_FUNC, GET_DEFAULT, QStringList(), QStringList)
0099 
0100 /**
0101  * smoothScale() is called from the image loading thread, therefore we need
0102  * to cache it this way, rather than going to KConfig.
0103  */
0104 static bool _smoothScale = true;
0105 
0106 using namespace Settings;
0107 
0108 const WindowType Settings::MainWindow = "MainWindow";
0109 const WindowType Settings::AnnotationDialog = "AnnotationDialog";
0110 
0111 SettingsData *SettingsData::s_instance = nullptr;
0112 
0113 SettingsData *SettingsData::instance()
0114 {
0115     if (!s_instance)
0116         qFatal("SettingsData: instance called before loading a setup!");
0117 
0118     return s_instance;
0119 }
0120 
0121 bool SettingsData::ready()
0122 {
0123     return s_instance;
0124 }
0125 
0126 void SettingsData::setup(const QString &imageDirectory, DB::UIDelegate &delegate)
0127 {
0128     if (!s_instance)
0129         s_instance = new SettingsData(imageDirectory, delegate);
0130 }
0131 
0132 SettingsData::SettingsData(const QString &imageDirectory, DB::UIDelegate &delegate)
0133     : m_trustTimeStamps(false)
0134     , m_hasAskedAboutTimeStamps(false)
0135     , m_UI(delegate)
0136 {
0137     m_hasAskedAboutTimeStamps = false;
0138 
0139     const QString s = STR("/");
0140     m_imageDirectory = imageDirectory.endsWith(s) ? imageDirectory : imageDirectory + s;
0141 
0142     _smoothScale = cfgValue("Viewer", "smoothScale", true);
0143 
0144     // Split the list of Exif comments that should be stripped automatically to a list
0145 
0146     QStringList commentsToStrip = cfgValue("General", "commentsToStrip", QString::fromLatin1("Exif_JPEG_PICTURE-,-OLYMPUS DIGITAL CAMERA-,-JENOPTIK DIGITAL CAMERA-,-")).split(QString::fromLatin1("-,-"), Qt::SkipEmptyParts);
0147     for (QString &comment : commentsToStrip)
0148         comment.replace(QString::fromLatin1(",,"), QString::fromLatin1(","));
0149 
0150     m_EXIFCommentsToStrip = commentsToStrip;
0151 }
0152 
0153 /////////////////
0154 //// General ////
0155 /////////////////
0156 
0157 // clang-format off
0158 property_copy(useEXIFRotate, setUseEXIFRotate, bool, General, true)
0159 property_copy(useEXIFComments, setUseEXIFComments, bool, General, true)
0160 property_copy(stripEXIFComments, setStripEXIFComments, bool, General, true)
0161 property_copy(commentsToStrip, setCommentsToStrip, QString, General, "" /* see constructor */)
0162 property_copy(searchForImagesOnStart, setSearchForImagesOnStart, bool, General, true)
0163 property_copy(ignoreFileExtension, setIgnoreFileExtension, bool, General, false)
0164 property_copy(skipSymlinks, setSkipSymlinks, bool, General, false)
0165 property_copy(skipRawIfOtherMatches, setSkipRawIfOtherMatches, bool, General, false)
0166 property_copy(useRawThumbnail, setUseRawThumbnail, bool, General, true)
0167 property_copy(useRawThumbnailSize, setUseRawThumbnailSize, QSize, General, QSize(1024, 768))
0168 property_copy(useCompressedIndexXML, setUseCompressedIndexXML, bool, General, true)
0169 property_copy(compressBackup, setCompressBackup, bool, General, true)
0170 property_copy(showSplashScreen, setShowSplashScreen, bool, General, true)
0171 property_copy(showHistogram, setShowHistogram, bool, General, true)
0172 property_copy(autoSave, setAutoSave, int, General, 5)
0173 property_copy(backupCount, setBackupCount, int, General, 5)
0174 property_enum(tTimeStamps, setTTimeStamps, TimeStampTrust, General, Always)
0175 property_copy(excludeDirectories, setExcludeDirectories, QString, General, QString::fromLatin1("xml,ThumbNails,.thumbs"))
0176 property_copy(browserUseNaturalSortOrder, setBrowserUseNaturalSortOrder, bool, General, true);
0177 #ifdef KPA_ENABLE_REMOTECONTROL
0178 property_copy(recentAndroidAddress, setRecentAndroidAddress, QString, General, QString())
0179 property_copy(listenForAndroidDevicesOnStartup, setListenForAndroidDevicesOnStartup, bool, General, false)
0180 #endif
0181 getValueFunc(QString, colorScheme, General, QString())
0182 void SettingsData::setColorScheme(const QString &path) {
0183     if (path != colorScheme())
0184     {
0185         setValue("General", "colorScheme", path);
0186         Q_EMIT colorSchemeChanged();
0187     }
0188 }
0189 
0190 getValueFunc(QSize, histogramSize, General, QSize(15, 30))
0191 getValueFunc(ViewSortType, viewSortType, General, static_cast<int>(SortLastUse))
0192 getValueFunc(AnnotationDialog::MatchType, matchType, General, static_cast<int>(AnnotationDialog::MatchFromWordStart))
0193 getValueFunc(bool, histogramUseLinearScale, General, false)
0194 
0195     // clang-format on
0196     void SettingsData::setHistogramUseLinearScale(const bool useLinearScale)
0197 {
0198     if (useLinearScale == histogramUseLinearScale())
0199         return;
0200 
0201     setValue("General", "histogramUseLinearScale", useLinearScale);
0202     Q_EMIT histogramScaleChanged();
0203 }
0204 
0205 void SettingsData::setHistogramSize(const QSize &size)
0206 {
0207     if (size == histogramSize())
0208         return;
0209 
0210     setValue("General", "histogramSize", size);
0211     Q_EMIT histogramSizeChanged(size);
0212 }
0213 
0214 void SettingsData::setViewSortType(const ViewSortType tp)
0215 {
0216     if (tp == viewSortType())
0217         return;
0218 
0219     setValue("General", "viewSortType", static_cast<int>(tp));
0220     Q_EMIT viewSortTypeChanged(tp);
0221 }
0222 void SettingsData::setMatchType(const AnnotationDialog::MatchType mt)
0223 {
0224     if (mt == matchType())
0225         return;
0226 
0227     setValue("General", "matchType", static_cast<int>(mt));
0228     Q_EMIT matchTypeChanged(mt);
0229 }
0230 
0231 bool SettingsData::trustTimeStamps()
0232 {
0233     if (tTimeStamps() == Always)
0234         return true;
0235     else if (tTimeStamps() == Never)
0236         return false;
0237     else {
0238         if (!m_hasAskedAboutTimeStamps) {
0239             const QString txt = i18n("When reading time information of images, their Exif info is used. "
0240                                      "Exif info may, however, not be supported by your KPhotoAlbum installation, "
0241                                      "or no valid information may be in the file. "
0242                                      "As a backup, KPhotoAlbum may use the timestamp of the image - this may, "
0243                                      "however, not be valid in case the image is scanned in. "
0244                                      "So the question is, should KPhotoAlbum trust the time stamp on your images?");
0245             const QString logMsg = QString::fromUtf8("Trust timestamps for this session?");
0246             auto answer = uiDelegate().questionYesNo(DB::LogMessage { BaseLog(), logMsg }, txt, i18n("Trust Time Stamps?"));
0247             if (answer == DB::UserFeedback::Confirm)
0248                 m_trustTimeStamps = true;
0249             else
0250                 m_trustTimeStamps = false;
0251             m_hasAskedAboutTimeStamps = true;
0252         }
0253         return m_trustTimeStamps;
0254     }
0255 }
0256 
0257 ////////////////////////////////
0258 //// File Version Detection ////
0259 ////////////////////////////////
0260 
0261 // clang-format off
0262 property_copy(detectModifiedFiles, setDetectModifiedFiles, bool, FileVersionDetection, true)
0263 property_copy(modifiedFileComponent, setModifiedFileComponent, QString, FileVersionDetection, "^(.*)-edited.([^.]+)$")
0264 property_copy(originalFileComponent, setOriginalFileComponent, QString, FileVersionDetection, "\\1.\\2")
0265 property_copy(moveOriginalContents, setMoveOriginalContents, bool, FileVersionDetection, false)
0266 property_copy(autoStackNewFiles, setAutoStackNewFiles, bool, FileVersionDetection, true)
0267 property_copy(copyFileComponent, setCopyFileComponent, QString, FileVersionDetection, "(.[^.]+)$")
0268 property_copy(copyFileReplacementComponent, setCopyFileReplacementComponent, QString, FileVersionDetection, "-edited\\1")
0269 property_copy(loadOptimizationPreset, setLoadOptimizationPreset, int, FileVersionDetection, 0)
0270 property_copy(overlapLoadMD5, setOverlapLoadMD5, bool, FileVersionDetection, false)
0271 property_copy(preloadThreadCount, setPreloadThreadCount, int, FileVersionDetection, 1)
0272 property_copy(thumbnailPreloadThreadCount, setThumbnailPreloadThreadCount, int, FileVersionDetection, 1)
0273 property_copy(thumbnailBuilderThreadCount, setThumbnailBuilderThreadCount, int, FileVersionDetection, 0)
0274     // clang-format on
0275 
0276     ////////////////////
0277     //// Thumbnails ////
0278     ////////////////////
0279 
0280     // clang-format off
0281 //property_copy(displayLabels, setDisplayLabels, bool, Thumbnails, true)
0282 getValueFunc_(bool, displayLabels, groupForDatabase("Thumbnails"), "displayLabels", true)
0283 //property_copy(displayCategories, setDisplayCategories, bool, Thumbnails, false)
0284 getValueFunc_(bool, displayCategories, groupForDatabase("Thumbnails"), "displayCategories", false)
0285 
0286     // clang-format on
0287 
0288     void SettingsData::setDisplayLabels(bool value)
0289 {
0290     const bool changed = value != displayLabels();
0291     setValue(groupForDatabase("Thumbnails"), "displayLabels", value);
0292     if (changed)
0293         Q_EMIT displayLabelsChanged(value);
0294 }
0295 
0296 void SettingsData::setDisplayCategories(bool value)
0297 {
0298     const bool changed = value != displayCategories();
0299     setValue(groupForDatabase("Thumbnails"), "displayCategories", value);
0300     if (changed)
0301         Q_EMIT displayCategoriesChanged(value);
0302 }
0303 // clang-format off
0304 property_copy(autoShowThumbnailView, setAutoShowThumbnailView, int, Thumbnails, 20)
0305 property_copy(showNewestThumbnailFirst, setShowNewestFirst, bool, Thumbnails, false)
0306 property_copy(thumbnailDisplayGrid, setThumbnailDisplayGrid, bool, Thumbnails, false)
0307 property_copy(previewSize, setPreviewSize, int, Thumbnails, 256)
0308 property_copy(thumbnailSpace, setThumbnailSpace, int, Thumbnails, 4)
0309 // not available via GUI, but should be consistent (and maybe confgurable for powerusers):
0310 property_copy(minimumThumbnailSize, setMinimumThumbnailSize, int, Thumbnails, 32)
0311 property_copy(maximumThumbnailSize, setMaximumThumbnailSize, int, Thumbnails, 4096)
0312 property_enum(thumbnailAspectRatio, setThumbnailAspectRatio, ThumbnailAspectRatio, Thumbnails, Aspect_3_2)
0313 property_copy(incrementalThumbnails, setIncrementalThumbnails, bool, Thumbnails, true)
0314 
0315 // database specific so that changing it doesn't invalidate the thumbnail cache for other databases:
0316 getValueFunc_(int, thumbnailSize, groupForDatabase("Thumbnails"), "thumbSize", 256)
0317     // clang-format on
0318 
0319     void SettingsData::setThumbnailSize(int value)
0320 {
0321     // enforce limits:
0322     value = qBound(minimumThumbnailSize(), value, maximumThumbnailSize());
0323 
0324     if (value != thumbnailSize())
0325         Q_EMIT thumbnailSizeChanged(value);
0326     setValue(groupForDatabase("Thumbnails"), "thumbSize", value);
0327 }
0328 
0329 int SettingsData::actualThumbnailSize() const
0330 {
0331     // this is database specific since it's a derived value of thumbnailSize
0332     int retval = cfgValue(groupForDatabase("Thumbnails"), "actualThumbSize", 0);
0333     // if no value has been set, use thumbnailSize
0334     if (retval == 0)
0335         retval = thumbnailSize();
0336     return retval;
0337 }
0338 
0339 void SettingsData::setActualThumbnailSize(int value)
0340 {
0341     // enforce limits:
0342     value = qBound(minimumThumbnailSize(), value, thumbnailSize());
0343 
0344     if (value != actualThumbnailSize()) {
0345         setValue(groupForDatabase("Thumbnails"), "actualThumbSize", value);
0346         Q_EMIT actualThumbnailSizeChanged(value);
0347     }
0348 }
0349 
0350 ////////////////
0351 //// Viewer ////
0352 ////////////////
0353 
0354 // clang-format off
0355 property_ref(viewerSize, setViewerSize, QSize, Viewer, QSize(1024, 768))
0356 property_ref(slideShowSize, setSlideShowSize, QSize, Viewer, QSize(1024, 768))
0357 property_copy(launchViewerFullScreen, setLaunchViewerFullScreen, bool, Viewer, false)
0358 property_copy(launchSlideShowFullScreen, setLaunchSlideShowFullScreen, bool, Viewer, true)
0359 property_copy(showInfoBox, setShowInfoBox, bool, Viewer, true)
0360 property_copy(showLabel, setShowLabel, bool, Viewer, true)
0361 property_copy(showDescription, setShowDescription, bool, Viewer, true)
0362 property_copy(showDate, setShowDate, bool, Viewer, true)
0363 property_copy(showImageSize, setShowImageSize, bool, Viewer, true)
0364 property_copy(showRating, setShowRating, bool, Viewer, true)
0365 property_copy(showTime, setShowTime, bool, Viewer, true)
0366 property_copy(showFilename, setShowFilename, bool, Viewer, false)
0367 property_copy(showEXIF, setShowEXIF, bool, Viewer, true)
0368 property_copy(slideShowInterval, setSlideShowInterval, int, Viewer, 5)
0369 property_copy(viewerCacheSize, setViewerCacheSize, int, Viewer, 195)
0370 property_copy(infoBoxWidth, setInfoBoxWidth, int, Viewer, 400)
0371 property_copy(infoBoxHeight, setInfoBoxHeight, int, Viewer, 300)
0372 property_enum(infoBoxPosition, setInfoBoxPosition, Position, Viewer, Bottom)
0373 property_enum(viewerStandardSize, setViewerStandardSize, StandardViewSize, Viewer, FullSize)
0374 //property_enum(videoBackend, setVideoBackend, VideoBackend, Viewer, VideoBackend::NotConfigured)
0375 setValueFunc_(setVideoBackend, VideoBackend, "Viewer", "videoBackend", static_cast<int>(v))
0376     // clang-format on
0377 
0378     VideoBackend SettingsData::videoBackend() const
0379 {
0380     auto value = static_cast<VideoBackend>(cfgValue("Viewer", "videoBackend", static_cast<int>(VideoBackend::NotConfigured)));
0381     // validate input:
0382     switch (value) {
0383     case VideoBackend::NotConfigured:
0384     case VideoBackend::Phonon:
0385     case VideoBackend::QtAV:
0386     case VideoBackend::VLC:
0387         break;
0388     default:
0389         qCWarning(BaseLog) << "Ignoring invalid configuration value for Viewer.videoBackend...";
0390         value = VideoBackend::NotConfigured;
0391     }
0392     return value;
0393 }
0394 
0395 bool SettingsData::smoothScale() const
0396 {
0397     return _smoothScale;
0398 }
0399 
0400 void SettingsData::setSmoothScale(bool b)
0401 {
0402     _smoothScale = b;
0403     setValue("Viewer", "smoothScale", b);
0404 }
0405 
0406 ////////////////////
0407 //// Categories ////
0408 ////////////////////
0409 
0410 // clang-format off
0411 //property_ref(untaggedCategory, setUntaggedCategory, QString, General, i18n("Events"))
0412 getValueFunc_(QString, untaggedCategory, "General", "untaggedCategory", i18n("Events"))
0413     void SettingsData::setUntaggedCategory(const QString &value)
0414 {
0415     const bool changed = value != untaggedCategory();
0416     setValue("General", "untaggedCategory", value);
0417     if (changed)
0418         Q_EMIT untaggedTagChanged(value, untaggedTag());
0419 }
0420 
0421 //property_ref(untaggedTag, setUntaggedTag, QString, General, i18n("untagged"))
0422 getValueFunc_(QString, untaggedTag, "General", "untaggedTag", i18n("untagged"))
0423     void SettingsData::setUntaggedTag(const QString &value)
0424 {
0425     const bool changed = value != untaggedTag();
0426     setValue("General", "untaggedTag", value);
0427     if (changed)
0428         Q_EMIT untaggedTagChanged(untaggedCategory(), value);
0429 }
0430 
0431 property_copy(untaggedImagesTagVisible, setUntaggedImagesTagVisible, bool, General, false)
0432     // clang-format on
0433 
0434     //////////////
0435     //// Exif ////
0436     //////////////
0437 
0438     // clang-format off
0439 property_sset(exifForViewer, setExifForViewer, Exif, StringSet())
0440 property_sset(exifForDialog, setExifForDialog, Exif, StringSet())
0441 property_ref(iptcCharset, setIptcCharset, QString, Exif, QString())
0442     // clang-format on
0443 
0444     /////////////////////
0445     //// Exif Import ////
0446     /////////////////////
0447 
0448     // clang-format off
0449 property_copy(updateExifData, setUpdateExifData, bool, ExifImport, true)
0450 property_copy(updateImageDate, setUpdateImageDate, bool, ExifImport, false)
0451 property_copy(useModDateIfNoExif, setUseModDateIfNoExif, bool, ExifImport, true)
0452 property_copy(updateOrientation, setUpdateOrientation, bool, ExifImport, false)
0453 property_copy(updateDescription, setUpdateDescription, bool, ExifImport, false)
0454     // clang-format on
0455 
0456     ///////////////////////
0457     //// Miscellaneous ////
0458     ///////////////////////
0459 
0460     // clang-format off
0461     property_ref_(HTMLBaseDir, setHTMLBaseDir, QString, groupForDatabase("HTML Settings"), QString::fromLatin1("%1/public_html").arg(QString::fromLocal8Bit(qgetenv("HOME"))))
0462 property_ref_(HTMLBaseURL, setHTMLBaseURL, QString, groupForDatabase("HTML Settings"), STR("file://%1").arg(HTMLBaseDir()))
0463 property_ref_(HTMLDestURL, setHTMLDestURL, QString, groupForDatabase("HTML Settings"), STR("file://%1").arg(HTMLBaseDir()))
0464 property_ref_(HTMLCopyright, setHTMLCopyright, QString, groupForDatabase("HTML Settings"), QString())
0465 property_ref_(HTMLDate, setHTMLDate, int, groupForDatabase("HTML Settings"), true)
0466 property_ref_(HTMLTheme, setHTMLTheme, int, groupForDatabase("HTML Settings"), -1)
0467 property_ref_(HTMLKimFile, setHTMLKimFile, int, groupForDatabase("HTML Settings"), true)
0468 property_ref_(HTMLInlineMovies, setHTMLInlineMovies, int, groupForDatabase("HTML Settings"), true)
0469 property_ref_(HTML5Video, setHTML5Video, int, groupForDatabase("HTML Settings"), true)
0470 property_ref_(HTML5VideoGenerate, setHTML5VideoGenerate, int, groupForDatabase("HTML Settings"), true)
0471 property_ref_(HTMLThumbSize, setHTMLThumbSize, int, groupForDatabase("HTML Settings"), 128)
0472 property_ref_(HTMLNumOfCols, setHTMLNumOfCols, int, groupForDatabase("HTML Settings"), 5)
0473 property_ref_(HTMLSizes, setHTMLSizes, QString, groupForDatabase("HTML Settings"), QString())
0474 property_ref_(HTMLIncludeSelections, setHTMLIncludeSelections, QString, groupForDatabase("HTML Settings"), QString())
0475     // clang-format on
0476 
0477     QDate SettingsData::fromDate() const
0478 {
0479     QString date = cfgValue("Miscellaneous", "fromDate", QString());
0480     return date.isEmpty() ? QDate(QDate::currentDate().year(), 1, 1) : QDate::fromString(date, Qt::ISODate);
0481 }
0482 
0483 void SettingsData::setFromDate(const QDate &date)
0484 {
0485     if (date.isValid())
0486         setValue("Miscellaneous", "fromDate", date.toString(Qt::ISODate));
0487 }
0488 
0489 QDate SettingsData::toDate() const
0490 {
0491     QString date = cfgValue("Miscellaneous", "toDate", QString());
0492     return date.isEmpty() ? QDate(QDate::currentDate().year() + 1, 1, 1) : QDate::fromString(date, Qt::ISODate);
0493 }
0494 
0495 void SettingsData::setToDate(const QDate &date)
0496 {
0497     if (date.isValid())
0498         setValue("Miscellaneous", "toDate", date.toString(Qt::ISODate));
0499 }
0500 
0501 QString SettingsData::imageDirectory() const
0502 {
0503     return m_imageDirectory;
0504 }
0505 
0506 QString SettingsData::groupForDatabase(const char *setting) const
0507 {
0508     return STR("%1 - %2").arg(STR(setting), imageDirectory());
0509 }
0510 
0511 QVariantMap SettingsData::currentLock() const
0512 {
0513     // duplicating logic from ImageSearchInfo here is not ideal
0514     // FIXME(jzarl): review the whole database view lock mechanism
0515     const auto group = groupForDatabase("Privacy Settings");
0516     QVariantMap keyValuePairs;
0517     keyValuePairs[STR("label")] = cfgValue(group, "label", {});
0518     keyValuePairs[STR("description")] = cfgValue(group, "description", {});
0519     // reading a QVariant containing a stringlist is asking too much of cfgValue:
0520     const auto config = KSharedConfig::openConfig(configFile)->group(group);
0521     const QStringList categories = config.readEntry<QStringList>(QString::fromUtf8("categories"), QStringList());
0522     keyValuePairs[STR("categories")] = QVariant(categories);
0523     for (QStringList::ConstIterator it = categories.constBegin(); it != categories.constEnd(); ++it) {
0524         keyValuePairs[*it] = cfgValue(group, *it, {});
0525     }
0526     return keyValuePairs;
0527 }
0528 
0529 void SettingsData::setCurrentLock(const QVariantMap &pairs, bool exclude)
0530 {
0531     for (QVariantMap::const_iterator it = pairs.cbegin(); it != pairs.cend(); ++it) {
0532         setValue(groupForDatabase("Privacy Settings"), it.key(), it.value());
0533     }
0534     setValue(groupForDatabase("Privacy Settings"), "exclude", exclude);
0535 }
0536 
0537 bool SettingsData::lockExcludes() const
0538 {
0539     return cfgValue(groupForDatabase("Privacy Settings"), "exclude", false);
0540 }
0541 
0542 getValueFunc_(bool, locked, groupForDatabase("Privacy Settings"), "locked", false)
0543 
0544     void SettingsData::setLocked(bool lock, bool force)
0545 {
0546     if (lock == locked() && !force)
0547         return;
0548 
0549     setValue(groupForDatabase("Privacy Settings"), "locked", lock);
0550     Q_EMIT locked(lock, lockExcludes());
0551 }
0552 
0553 void SettingsData::setWindowGeometry(WindowType win, const QRect &geometry)
0554 {
0555     setValue("Window Geometry", win, geometry);
0556 }
0557 
0558 QRect SettingsData::windowGeometry(WindowType win) const
0559 {
0560     return cfgValue("Window Geometry", win, QRect());
0561 }
0562 
0563 double Settings::SettingsData::getThumbnailAspectRatio() const
0564 {
0565     double ratio = 1.0;
0566     switch (Settings::SettingsData::instance()->thumbnailAspectRatio()) {
0567     case Settings::Aspect_16_9:
0568         ratio = 9.0 / 16;
0569         break;
0570     case Settings::Aspect_4_3:
0571         ratio = 3.0 / 4;
0572         break;
0573     case Settings::Aspect_3_2:
0574         ratio = 2.0 / 3;
0575         break;
0576     case Settings::Aspect_9_16:
0577         ratio = 16 / 9.0;
0578         break;
0579     case Settings::Aspect_3_4:
0580         ratio = 4 / 3.0;
0581         break;
0582     case Settings::Aspect_2_3:
0583         ratio = 3 / 2.0;
0584         break;
0585     case Settings::Aspect_1_1:
0586         ratio = 1.0;
0587         break;
0588     }
0589     return ratio;
0590 }
0591 
0592 QStringList Settings::SettingsData::EXIFCommentsToStrip()
0593 {
0594     return m_EXIFCommentsToStrip;
0595 }
0596 
0597 void Settings::SettingsData::setEXIFCommentsToStrip(QStringList EXIFCommentsToStrip)
0598 {
0599     m_EXIFCommentsToStrip = EXIFCommentsToStrip;
0600 }
0601 
0602 bool Settings::SettingsData::getOverlapLoadMD5() const
0603 {
0604     switch (Settings::SettingsData::instance()->loadOptimizationPreset()) {
0605     case Settings::LoadOptimizationSlowNVME:
0606     case Settings::LoadOptimizationFastNVME:
0607         return true;
0608     case Settings::LoadOptimizationManual:
0609         return Settings::SettingsData::instance()->overlapLoadMD5();
0610     case Settings::LoadOptimizationHardDisk:
0611     case Settings::LoadOptimizationNetwork:
0612     case Settings::LoadOptimizationSataSSD:
0613     default:
0614         return false;
0615     }
0616 }
0617 
0618 int Settings::SettingsData::getPreloadThreadCount() const
0619 {
0620     switch (Settings::SettingsData::instance()->loadOptimizationPreset()) {
0621     case Settings::LoadOptimizationManual:
0622         return Settings::SettingsData::instance()->preloadThreadCount();
0623     case Settings::LoadOptimizationSlowNVME:
0624     case Settings::LoadOptimizationFastNVME:
0625     case Settings::LoadOptimizationSataSSD:
0626         return qMax(1, qMin(16, QThread::idealThreadCount()));
0627     case Settings::LoadOptimizationHardDisk:
0628     case Settings::LoadOptimizationNetwork:
0629     default:
0630         return 1;
0631     }
0632 }
0633 
0634 int Settings::SettingsData::getThumbnailPreloadThreadCount() const
0635 {
0636     switch (Settings::SettingsData::instance()->loadOptimizationPreset()) {
0637     case Settings::LoadOptimizationManual:
0638         return Settings::SettingsData::instance()->thumbnailPreloadThreadCount();
0639     case Settings::LoadOptimizationSlowNVME:
0640     case Settings::LoadOptimizationFastNVME:
0641     case Settings::LoadOptimizationSataSSD:
0642         return qMax(1, qMin(16, QThread::idealThreadCount() / 2));
0643     case Settings::LoadOptimizationHardDisk:
0644     case Settings::LoadOptimizationNetwork:
0645     default:
0646         return 1;
0647     }
0648 }
0649 
0650 int Settings::SettingsData::getThumbnailBuilderThreadCount() const
0651 {
0652     switch (Settings::SettingsData::instance()->loadOptimizationPreset()) {
0653     case Settings::LoadOptimizationManual:
0654         return Settings::SettingsData::instance()->thumbnailBuilderThreadCount();
0655     case Settings::LoadOptimizationSlowNVME:
0656     case Settings::LoadOptimizationFastNVME:
0657     case Settings::LoadOptimizationSataSSD:
0658     case Settings::LoadOptimizationHardDisk:
0659     case Settings::LoadOptimizationNetwork:
0660     default:
0661         return qMax(1, qMin(16, QThread::idealThreadCount() - 1));
0662     }
0663 }
0664 
0665 DB::UIDelegate &SettingsData::uiDelegate() const
0666 {
0667     return m_UI;
0668 }
0669 
0670 // vi:expandtab:tabstop=4 shiftwidth=4:
0671 
0672 #include "moc_SettingsData.cpp"