File indexing completed on 2024-05-19 04:26:17

0001 /*
0002  *  SPDX-FileCopyrightText: 2010 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kis_image_config.h"
0008 
0009 #include <ksharedconfig.h>
0010 
0011 #include <KoConfig.h>
0012 #include <KoColorProfile.h>
0013 #include <KoColorSpaceRegistry.h>
0014 #include <KoColorConversionTransformation.h>
0015 #include <kis_properties_configuration.h>
0016 
0017 #include "kis_debug.h"
0018 
0019 #include <QThread>
0020 #include <QApplication>
0021 #include <QColor>
0022 #include <QDir>
0023 
0024 #include "kis_global.h"
0025 #include <cmath>
0026 #include <QTemporaryFile>
0027 
0028 #ifdef Q_OS_MACOS
0029 #include <errno.h>
0030 #include "KisMacosSecurityBookmarkManager.h"
0031 #endif
0032 
0033 KisImageConfig::KisImageConfig(bool readOnly)
0034     : m_config(KSharedConfig::openConfig()->group(QString()))
0035     , m_readOnly(readOnly)
0036 {
0037     if (!readOnly) {
0038         KIS_SAFE_ASSERT_RECOVER_RETURN(qApp->thread() == QThread::currentThread());
0039     }
0040 #ifdef Q_OS_MACOS
0041     // clear /var/folders/ swap path set by old broken Krita swap implementation in order to use new default swap dir.
0042     QString swap = m_config.readEntry("swaplocation", "");
0043     if (swap.startsWith("/var/folders/")) {
0044         m_config.deleteEntry("swaplocation");
0045     }
0046 #endif
0047 }
0048 
0049 KisImageConfig::~KisImageConfig()
0050 {
0051     if (m_readOnly) return;
0052 
0053     if (qApp->thread() != QThread::currentThread()) {
0054         dbgKrita << "KisImageConfig: requested config synchronization from nonGUI thread! Called from" << kisBacktrace();
0055         return;
0056     }
0057 
0058     m_config.sync();
0059 }
0060 
0061 bool KisImageConfig::enableProgressReporting(bool requestDefault) const
0062 {
0063     return !requestDefault ?
0064         m_config.readEntry("enableProgressReporting", true) : true;
0065 }
0066 
0067 void KisImageConfig::setEnableProgressReporting(bool value)
0068 {
0069     m_config.writeEntry("enableProgressReporting", value);
0070 }
0071 
0072 bool KisImageConfig::enablePerfLog(bool requestDefault) const
0073 {
0074     return !requestDefault ?
0075         m_config.readEntry("enablePerfLog", false) :false;
0076 }
0077 
0078 void KisImageConfig::setEnablePerfLog(bool value)
0079 {
0080     m_config.writeEntry("enablePerfLog", value);
0081 }
0082 
0083 qreal KisImageConfig::transformMaskOffBoundsReadArea() const
0084 {
0085     return m_config.readEntry("transformMaskOffBoundsReadArea", 0.5);
0086 }
0087 
0088 int KisImageConfig::updatePatchHeight() const
0089 {
0090     int patchHeight = m_config.readEntry("updatePatchHeight", 512);
0091     if (patchHeight <= 0) return 512;
0092     return patchHeight;
0093 }
0094 
0095 void KisImageConfig::setUpdatePatchHeight(int value)
0096 {
0097     m_config.writeEntry("updatePatchHeight", value);
0098 }
0099 
0100 int KisImageConfig::updatePatchWidth() const
0101 {
0102     int patchWidth = m_config.readEntry("updatePatchWidth", 512);
0103     if (patchWidth <= 0) return 512;
0104     return patchWidth;
0105 }
0106 
0107 void KisImageConfig::setUpdatePatchWidth(int value)
0108 {
0109     m_config.writeEntry("updatePatchWidth", value);
0110 }
0111 
0112 qreal KisImageConfig::maxCollectAlpha() const
0113 {
0114     return m_config.readEntry("maxCollectAlpha", 2.5);
0115 }
0116 
0117 qreal KisImageConfig::maxMergeAlpha() const
0118 {
0119     return m_config.readEntry("maxMergeAlpha", 1.);
0120 }
0121 
0122 qreal KisImageConfig::maxMergeCollectAlpha() const
0123 {
0124     return m_config.readEntry("maxMergeCollectAlpha", 1.5);
0125 }
0126 
0127 qreal KisImageConfig::schedulerBalancingRatio() const
0128 {
0129     /**
0130      * updates-queue-size / strokes-queue-size
0131      */
0132     return m_config.readEntry("schedulerBalancingRatio", 100.);
0133 }
0134 
0135 void KisImageConfig::setSchedulerBalancingRatio(qreal value)
0136 {
0137     m_config.writeEntry("schedulerBalancingRatio", value);
0138 }
0139 
0140 int KisImageConfig::maxSwapSize(bool requestDefault) const
0141 {
0142     return !requestDefault ?
0143         m_config.readEntry("maxSwapSize", 4096) : 4096; // in MiB
0144 }
0145 
0146 void KisImageConfig::setMaxSwapSize(int value)
0147 {
0148     m_config.writeEntry("maxSwapSize", value);
0149 }
0150 
0151 int KisImageConfig::swapSlabSize() const
0152 {
0153     return m_config.readEntry("swapSlabSize", 64); // in MiB
0154 }
0155 
0156 void KisImageConfig::setSwapSlabSize(int value)
0157 {
0158     m_config.writeEntry("swapSlabSize", value);
0159 }
0160 
0161 int KisImageConfig::swapWindowSize() const
0162 {
0163     return m_config.readEntry("swapWindowSize", 16); // in MiB
0164 }
0165 
0166 void KisImageConfig::setSwapWindowSize(int value)
0167 {
0168     m_config.writeEntry("swapWindowSize", value);
0169 }
0170 
0171 int KisImageConfig::tilesHardLimit() const
0172 {
0173     qreal hp = qreal(memoryHardLimitPercent()) / 100.0;
0174     qreal pp = qreal(memoryPoolLimitPercent()) / 100.0;
0175 
0176     return totalRAM() * hp * (1 - pp);
0177 }
0178 
0179 int KisImageConfig::tilesSoftLimit() const
0180 {
0181     qreal sp = qreal(memorySoftLimitPercent()) / 100.0;
0182 
0183     return tilesHardLimit() * sp;
0184 }
0185 
0186 int KisImageConfig::poolLimit() const
0187 {
0188     qreal hp = qreal(memoryHardLimitPercent()) / 100.0;
0189     qreal pp = qreal(memoryPoolLimitPercent()) / 100.0;
0190 
0191     return totalRAM() * hp * pp;
0192 }
0193 
0194 qreal KisImageConfig::memoryHardLimitPercent(bool requestDefault) const
0195 {
0196     return !requestDefault ?
0197         m_config.readEntry("memoryHardLimitPercent", 50.) : 50.;
0198 }
0199 
0200 void KisImageConfig::setMemoryHardLimitPercent(qreal value)
0201 {
0202     m_config.writeEntry("memoryHardLimitPercent", value);
0203 }
0204 
0205 qreal KisImageConfig::memorySoftLimitPercent(bool requestDefault) const
0206 {
0207     return !requestDefault ?
0208         m_config.readEntry("memorySoftLimitPercent", 2.) : 2.;
0209 }
0210 
0211 void KisImageConfig::setMemorySoftLimitPercent(qreal value)
0212 {
0213     m_config.writeEntry("memorySoftLimitPercent", value);
0214 }
0215 
0216 qreal KisImageConfig::memoryPoolLimitPercent(bool requestDefault) const
0217 {
0218     return !requestDefault ?
0219         m_config.readEntry("memoryPoolLimitPercent", 0.0) : 0.0;
0220 }
0221 
0222 void KisImageConfig::setMemoryPoolLimitPercent(qreal value)
0223 {
0224     m_config.writeEntry("memoryPoolLimitPercent", value);
0225 }
0226 
0227 QString KisImageConfig::safelyGetWritableTempLocation(const QString &suffix, const QString &configKey, bool requestDefault) const
0228 {
0229 #ifdef Q_OS_MACOS
0230     // On OSX, QDir::tempPath() gives us a folder we cannot reply upon (usually
0231     // something like /var/folders/.../...) and that will have vanished when we
0232     // try to create the tmp file in KisMemoryWindow::KisMemoryWindow using
0233     // swapFileTemplate. thus, we just pick the home folder if swapDir does not
0234     // tell us otherwise.
0235 
0236     // the other option here would be to use a "garbled name" temp file (i.e. no name
0237     // KRITA_SWAP_FILE_XXXXXX) in an obscure /var/folders place, which is not
0238     // nice to the user. having a clearly named swap file in the home folder is
0239     // much nicer to Krita's users.
0240 
0241     // NOTE: QStandardPaths::AppLocalDataLocation on macos sandboxed envs
0242     // does not return writable locations at all times, using QDir static methods
0243     // will always return locations inside the sandbox Container
0244 
0245     // furthermore, this is just a default and swapDir can always be configured
0246     // to another location.
0247 
0248     QString swap;
0249 
0250     KisMacosSecurityBookmarkManager *bookmarkmngr = KisMacosSecurityBookmarkManager::instance();
0251     if ( bookmarkmngr->isSandboxed() ) {
0252         QDir sandboxHome = QDir::home();
0253         if (sandboxHome.cd("tmp")) {
0254             swap = sandboxHome.path();
0255         }
0256     } else {
0257         swap = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + '/' + suffix;
0258     }
0259 #else
0260     Q_UNUSED(suffix);
0261     QString swap = QDir::tempPath();
0262 #endif
0263     if (requestDefault) {
0264        return swap;
0265     }
0266     const QString configuredSwap = m_config.readEntry(configKey, swap);
0267     if (!configuredSwap.isEmpty()) {
0268         swap = configuredSwap;
0269     }
0270 
0271     QString chosenLocation;
0272     QStringList proposedSwapLocations;
0273 
0274     proposedSwapLocations << swap;
0275     proposedSwapLocations << QDir::tempPath();
0276     proposedSwapLocations << QDir::homePath();
0277 
0278     Q_FOREACH (const QString location, proposedSwapLocations) {
0279         if (!QFileInfo(location).isWritable()) continue;
0280 
0281         /**
0282          * On NTFS, isWritable() doesn't check for attributes due to performance
0283          * reasons, so we should try it in a brute-force way...
0284          * (yes, there is a hacky-global-variable workaround, but let's be safe)
0285          */
0286         QTemporaryFile tempFile;
0287         tempFile.setFileTemplate(location + '/' + "krita_test_swap_location");
0288         if (tempFile.open() && !tempFile.fileName().isEmpty()) {
0289             chosenLocation = location;
0290             break;
0291         }
0292     }
0293 
0294     if (chosenLocation.isEmpty()) {
0295         qCritical() << "CRITICAL: no writable location for a swap file found! Tried the following paths:" << proposedSwapLocations;
0296         qCritical() << "CRITICAL: hope I don't crash...";
0297         chosenLocation = swap;
0298     }
0299 
0300     if (chosenLocation != swap) {
0301         qWarning() << "WARNING: configured swap location is not writable, using a fall-back location" << swap << "->" << chosenLocation;
0302     }
0303 
0304     return chosenLocation;
0305 }
0306 
0307 
0308 QString KisImageConfig::swapDir(bool requestDefault)
0309 {
0310     return safelyGetWritableTempLocation("swap", "swaplocation", requestDefault);
0311 }
0312 
0313 void KisImageConfig::setSwapDir(const QString &swapDir)
0314 {
0315     m_config.writeEntry("swaplocation", swapDir);
0316 }
0317 
0318 int KisImageConfig::numberOfOnionSkins() const
0319 {
0320     return m_config.readEntry("numberOfOnionSkins", 10);
0321 }
0322 
0323 void KisImageConfig::setNumberOfOnionSkins(int value)
0324 {
0325     m_config.writeEntry("numberOfOnionSkins", value);
0326 }
0327 
0328 int KisImageConfig::onionSkinTintFactor() const
0329 {
0330     return m_config.readEntry("onionSkinTintFactor", 192);
0331 }
0332 
0333 void KisImageConfig::setOnionSkinTintFactor(int value)
0334 {
0335     m_config.writeEntry("onionSkinTintFactor", value);
0336 }
0337 
0338 int KisImageConfig::onionSkinOpacity(int offset) const
0339 {
0340     int value = m_config.readEntry("onionSkinOpacity_" + QString::number(offset), -1);
0341 
0342     return value;
0343 }
0344 
0345 void KisImageConfig::setOnionSkinOpacity(int offset, int value)
0346 {
0347     m_config.writeEntry("onionSkinOpacity_" + QString::number(offset), value);
0348 }
0349 
0350 bool KisImageConfig::onionSkinState(int offset) const
0351 {
0352     bool enableByDefault = (qAbs(offset) <= 2);
0353     return m_config.readEntry("onionSkinState_" + QString::number(offset), enableByDefault);
0354 }
0355 
0356 void KisImageConfig::setOnionSkinState(int offset, bool value)
0357 {
0358     m_config.writeEntry("onionSkinState_" + QString::number(offset), value);
0359 }
0360 
0361 QColor KisImageConfig::onionSkinTintColorBackward() const
0362 {
0363     return m_config.readEntry("onionSkinTintColorBackward", QColor(Qt::red));
0364 }
0365 
0366 void KisImageConfig::setOnionSkinTintColorBackward(const QColor &value)
0367 {
0368     m_config.writeEntry("onionSkinTintColorBackward", value);
0369 }
0370 
0371 QColor KisImageConfig::onionSkinTintColorForward() const
0372 {
0373     return m_config.readEntry("oninSkinTintColorForward", QColor(Qt::green));
0374 }
0375 
0376 void KisImageConfig::setOnionSkinTintColorForward(const QColor &value)
0377 {
0378     m_config.writeEntry("oninSkinTintColorForward", value);
0379 }
0380 
0381 bool KisImageConfig::autoKeyEnabled(bool requestDefault) const
0382 {
0383     return !requestDefault ?
0384         m_config.readEntry("lazyFrameCreationEnabled", true) : true;
0385 }
0386 
0387 void KisImageConfig::setAutoKeyEnabled(bool value)
0388 {
0389     m_config.writeEntry("lazyFrameCreationEnabled", value);
0390 }
0391 
0392 bool KisImageConfig::autoKeyModeDuplicate(bool requestDefault) const
0393 {
0394     return !requestDefault ?
0395         m_config.readEntry("lazyFrameModeDuplicate", true) : true;
0396 }
0397 
0398 void KisImageConfig::setAutoKeyModeDuplicate(bool value)
0399 {
0400     m_config.writeEntry("lazyFrameModeDuplicate", value);
0401 }
0402 
0403 #if defined Q_OS_LINUX
0404 #include <sys/sysinfo.h>
0405 #elif defined Q_OS_FREEBSD || defined Q_OS_NETBSD || defined Q_OS_OPENBSD
0406 #include <sys/sysctl.h>
0407 #elif defined Q_OS_WIN
0408 #include <windows.h>
0409 #elif defined Q_OS_MACOS
0410 #include <sys/types.h>
0411 #include <sys/sysctl.h>
0412 #endif
0413 
0414 int KisImageConfig::totalRAM()
0415 {
0416     // let's think that default memory size is 1000MiB
0417     int totalMemory = 1000; // MiB
0418     int error = 1;
0419 
0420 #if defined Q_OS_LINUX
0421     struct sysinfo info;
0422 
0423     error = sysinfo(&info);
0424     if(!error) {
0425         totalMemory = info.totalram * info.mem_unit / (1UL << 20);
0426     }
0427 #elif defined Q_OS_FREEBSD || defined Q_OS_NETBSD || defined Q_OS_OPENBSD
0428     u_long physmem;
0429 #   if defined HW_PHYSMEM64 // NetBSD only
0430     int mib[] = {CTL_HW, HW_PHYSMEM64};
0431 #   else
0432     int mib[] = {CTL_HW, HW_PHYSMEM};
0433 #   endif
0434     size_t len = sizeof(physmem);
0435 
0436     error = sysctl(mib, 2, &physmem, &len, 0, 0);
0437     if(!error) {
0438         totalMemory = physmem >> 20;
0439     }
0440 #elif defined Q_OS_WIN
0441     MEMORYSTATUSEX status;
0442     status.dwLength = sizeof(status);
0443     error  = !GlobalMemoryStatusEx(&status);
0444 
0445     if (!error) {
0446         totalMemory = status.ullTotalPhys >> 20;
0447     }
0448 
0449     // For 32 bit windows, the total memory available is at max the 2GB per process memory limit.
0450 #   if defined ENV32BIT
0451     totalMemory = qMin(totalMemory, 2000);
0452 #   endif
0453 #elif defined Q_OS_MACOS
0454     int mib[2] = { CTL_HW, HW_MEMSIZE };
0455     u_int namelen = sizeof(mib) / sizeof(mib[0]);
0456     uint64_t size;
0457     size_t len = sizeof(size);
0458 
0459     errno = 0;
0460     if (sysctl(mib, namelen, &size, &len, 0, 0) >= 0) {
0461         totalMemory = size >> 20;
0462         error = 0;
0463     }
0464     else {
0465         dbgKrita << "sysctl(\"hw.memsize\") raised error" << strerror(errno);
0466     }
0467 #endif
0468 
0469     if (error) {
0470         warnKrita << "Cannot get the size of your RAM. Using 1 GiB by default.";
0471     }
0472 
0473     return totalMemory;
0474 }
0475 
0476 bool KisImageConfig::showAdditionalOnionSkinsSettings(bool requestDefault) const
0477 {
0478     return !requestDefault ?
0479         m_config.readEntry("showAdditionalOnionSkinsSettings", true) : true;
0480 }
0481 
0482 void KisImageConfig::setShowAdditionalOnionSkinsSettings(bool value)
0483 {
0484     m_config.writeEntry("showAdditionalOnionSkinsSettings", value);
0485 }
0486 
0487 int KisImageConfig::defaultFrameColorLabel() const
0488 {
0489     return m_config.readEntry("defaultFrameColorLabel", 0);
0490 }
0491 
0492 void KisImageConfig::setDefaultFrameColorLabel(int label)
0493 {
0494     m_config.writeEntry("defaultFrameColorLabel", label);
0495 }
0496 
0497 KisProofingConfigurationSP KisImageConfig::defaultProofingconfiguration()
0498 {
0499     KisProofingConfiguration *proofingConfig= new KisProofingConfiguration();
0500     proofingConfig->proofingProfile = m_config.readEntry("defaultProofingProfileName", "Chemical proof");
0501     proofingConfig->proofingModel = m_config.readEntry("defaultProofingProfileModel", "CMYKA");
0502     proofingConfig->proofingDepth = m_config.readEntry("defaultProofingProfileDepth", "U8");
0503     proofingConfig->intent = (KoColorConversionTransformation::Intent)m_config.readEntry("defaultProofingProfileIntent", 3);
0504     if (m_config.readEntry("defaultProofingBlackpointCompensation", true)) {
0505         proofingConfig->conversionFlags  |= KoColorConversionTransformation::ConversionFlag::BlackpointCompensation;
0506     } else {
0507         proofingConfig->conversionFlags  = proofingConfig->conversionFlags & ~KoColorConversionTransformation::ConversionFlag::BlackpointCompensation;
0508     }
0509     QColor def(Qt::green);
0510     m_config.readEntry("defaultProofingGamutwarning", def);
0511     KoColor col(KoColorSpaceRegistry::instance()->rgb8());
0512     col.fromQColor(def);
0513     col.setOpacity(1.0);
0514     proofingConfig->warningColor = col;
0515     proofingConfig->adaptationState = (double)m_config.readEntry("defaultProofingAdaptationState", 1.0);
0516     return toQShared(proofingConfig);
0517 }
0518 
0519 void KisImageConfig::setDefaultProofingConfig(const KoColorSpace *proofingSpace, int proofingIntent, bool blackPointCompensation, KoColor warningColor, double adaptationState)
0520 {
0521     if (!proofingSpace || !proofingSpace->profile()) {
0522         return;
0523     }
0524 
0525     m_config.writeEntry("defaultProofingProfileName", proofingSpace->profile()->name());
0526     m_config.writeEntry("defaultProofingProfileModel", proofingSpace->colorModelId().id());
0527     m_config.writeEntry("defaultProofingProfileDepth", proofingSpace->colorDepthId().id());
0528     m_config.writeEntry("defaultProofingProfileIntent", proofingIntent);
0529     m_config.writeEntry("defaultProofingBlackpointCompensation", blackPointCompensation);
0530     QColor c;
0531     c = warningColor.toQColor();
0532     m_config.writeEntry("defaultProofingGamutwarning", c);
0533     m_config.writeEntry("defaultProofingAdaptationState",adaptationState);
0534 }
0535 
0536 bool KisImageConfig::useLodForColorizeMask(bool requestDefault) const
0537 {
0538     return !requestDefault ?
0539         m_config.readEntry("useLodForColorizeMask", false) : false;
0540 }
0541 
0542 void KisImageConfig::setUseLodForColorizeMask(bool value)
0543 {
0544     m_config.writeEntry("useLodForColorizeMask", value);
0545 }
0546 
0547 int KisImageConfig::maxNumberOfThreads(bool defaultValue) const
0548 {
0549     return (defaultValue ? QThread::idealThreadCount() : m_config.readEntry("maxNumberOfThreads", QThread::idealThreadCount()));
0550 }
0551 
0552 void KisImageConfig::setMaxNumberOfThreads(int value)
0553 {
0554     if (value == QThread::idealThreadCount()) {
0555         m_config.deleteEntry("maxNumberOfThreads");
0556     } else {
0557         m_config.writeEntry("maxNumberOfThreads", value);
0558     }
0559 }
0560 
0561 int KisImageConfig::frameRenderingClones(bool defaultValue) const
0562 {
0563     const int defaultClonesCount = qMax(1, maxNumberOfThreads(defaultValue) / 2);
0564     return defaultValue ? defaultClonesCount : m_config.readEntry("frameRenderingClones", defaultClonesCount);
0565 }
0566 
0567 void KisImageConfig::setFrameRenderingClones(int value)
0568 {
0569     m_config.writeEntry("frameRenderingClones", value);
0570 }
0571 
0572 int KisImageConfig::frameRenderingTimeout(bool defaultValue) const
0573 {
0574     const int defaultFrameRenderingTimeout = 30000; // 30 ms
0575     return defaultValue ? defaultFrameRenderingTimeout : m_config.readEntry("frameRenderingTimeout", defaultFrameRenderingTimeout);
0576 }
0577 
0578 void KisImageConfig::setFrameRenderingTimeout(int value)
0579 {
0580     m_config.writeEntry("frameRenderingTimeout", value);
0581 }
0582 
0583 int KisImageConfig::fpsLimit(bool defaultValue) const
0584 {
0585     int limit = defaultValue ? 100 : m_config.readEntry("fpsLimit", 100);
0586     return limit > 0 ? limit : 1;
0587 }
0588 
0589 void KisImageConfig::setFpsLimit(int value)
0590 {
0591     m_config.writeEntry("fpsLimit", value);
0592 }
0593 
0594 bool KisImageConfig::useOnDiskAnimationCacheSwapping(bool defaultValue) const
0595 {
0596     return defaultValue ? true : m_config.readEntry("useOnDiskAnimationCacheSwapping", true);
0597 }
0598 
0599 void KisImageConfig::setUseOnDiskAnimationCacheSwapping(bool value)
0600 {
0601     m_config.writeEntry("useOnDiskAnimationCacheSwapping", value);
0602 }
0603 
0604 QString KisImageConfig::animationCacheDir(bool defaultValue) const
0605 {
0606     return safelyGetWritableTempLocation("animation_cache", "animationCacheDir", defaultValue);
0607 }
0608 
0609 void KisImageConfig::setAnimationCacheDir(const QString &value)
0610 {
0611     m_config.writeEntry("animationCacheDir", value);
0612 }
0613 
0614 bool KisImageConfig::useAnimationCacheFrameSizeLimit(bool defaultValue) const
0615 {
0616     return defaultValue ? true : m_config.readEntry("useAnimationCacheFrameSizeLimit", true);
0617 }
0618 
0619 void KisImageConfig::setUseAnimationCacheFrameSizeLimit(bool value)
0620 {
0621     m_config.writeEntry("useAnimationCacheFrameSizeLimit", value);
0622 }
0623 
0624 int KisImageConfig::animationCacheFrameSizeLimit(bool defaultValue) const
0625 {
0626     return defaultValue ? 2500 : m_config.readEntry("animationCacheFrameSizeLimit", 2500);
0627 }
0628 
0629 void KisImageConfig::setAnimationCacheFrameSizeLimit(int value)
0630 {
0631     m_config.writeEntry("animationCacheFrameSizeLimit", value);
0632 }
0633 
0634 bool KisImageConfig::useAnimationCacheRegionOfInterest(bool defaultValue) const
0635 {
0636     return defaultValue ? true : m_config.readEntry("useAnimationCacheRegionOfInterest", true);
0637 }
0638 
0639 void KisImageConfig::setUseAnimationCacheRegionOfInterest(bool value)
0640 {
0641     m_config.writeEntry("useAnimationCacheRegionOfInterest", value);
0642 }
0643 
0644 qreal KisImageConfig::animationCacheRegionOfInterestMargin(bool defaultValue) const
0645 {
0646     return defaultValue ? 0.25 : m_config.readEntry("animationCacheRegionOfInterestMargin", 0.25);
0647 }
0648 
0649 void KisImageConfig::setAnimationCacheRegionOfInterestMargin(qreal value)
0650 {
0651     m_config.writeEntry("animationCacheRegionOfInterestMargin", value);
0652 }
0653 
0654 qreal KisImageConfig::selectionOutlineOpacity(bool defaultValue) const
0655 {
0656     return defaultValue ? 1.0 : m_config.readEntry("selectionOutlineOpacity", 1.0);
0657 }
0658 
0659 void KisImageConfig::setSelectionOutlineOpacity(qreal value)
0660 {
0661     m_config.writeEntry("selectionOutlineOpacity", value);
0662 }
0663 
0664 QColor KisImageConfig::selectionOverlayMaskColor(bool defaultValue) const
0665 {
0666     QColor def(255, 0, 0, 128);
0667     return (defaultValue ? def : m_config.readEntry("selectionOverlayMaskColor", def));
0668 }
0669 
0670 void KisImageConfig::setSelectionOverlayMaskColor(const QColor &color)
0671 {
0672     m_config.writeEntry("selectionOverlayMaskColor", color);
0673 }
0674 
0675 int KisImageConfig::maxBrushSize(bool defaultValue) const
0676 {
0677     return !defaultValue ? m_config.readEntry("maximumBrushSize", 1000) : 1000;
0678 }
0679 
0680 void KisImageConfig::setMaxBrushSize(int value)
0681 {
0682     m_config.writeEntry("maximumBrushSize", value);
0683 }
0684 
0685 int KisImageConfig::maxMaskingBrushSize() const
0686 {
0687     return qMin(15000, 3 * maxBrushSize());
0688 }
0689 
0690 bool KisImageConfig::renameMergedLayers(bool defaultValue) const
0691 {
0692     return defaultValue ? true : m_config.readEntry("renameMergedLayers", true);
0693 }
0694 
0695 void KisImageConfig::setRenameMergedLayers(bool value)
0696 {
0697     m_config.writeEntry("renameMergedLayers", value);
0698 }
0699 
0700 QString KisImageConfig::exportConfigurationXML(const QString &exportConfigId, bool defaultValue) const
0701 {
0702     return (defaultValue ? QString() : m_config.readEntry("ExportConfiguration-" + exportConfigId, QString()));
0703 }
0704 
0705 bool KisImageConfig::hasExportConfiguration(const QString &exportConfigID)
0706 {
0707     return m_config.hasKey("ExportConfiguration-" + exportConfigID);
0708 }
0709 
0710 KisPropertiesConfigurationSP KisImageConfig::exportConfiguration(const QString &exportConfigId, bool defaultValue) const
0711 {
0712     KisPropertiesConfigurationSP cfg = new KisPropertiesConfiguration();
0713     const QString xmlData = exportConfigurationXML(exportConfigId, defaultValue);
0714     cfg->fromXML(xmlData);
0715     return cfg;
0716 }
0717 
0718 void KisImageConfig::setExportConfiguration(const QString &exportConfigId, KisPropertiesConfigurationSP properties)
0719 {
0720     const QString exportConfig = properties->toXML();
0721     QString configId = "ExportConfiguration-" + exportConfigId;
0722     m_config.writeEntry(configId, exportConfig);
0723 }
0724 
0725 void KisImageConfig::resetConfig()
0726 {
0727     KConfigGroup config = KSharedConfig::openConfig()->group(QString());
0728     config.deleteGroup();
0729 }