1 /*
2  *  This file is part of RawTherapee.
3  *
4  *  Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
5  *
6  *  RawTherapee is free software: you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation, either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  RawTherapee is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with RawTherapee.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 #include "options.h"
20 #include <cstdio>
21 #include <glib/gstdio.h>
22 #include <sstream>
23 #include <iostream>
24 #include "multilangmgr.h"
25 #include "addsetids.h"
26 #include "guiutils.h"
27 #include "version.h"
28 #include "../rtengine/metadata.h"
29 
30 #ifdef _OPENMP
31 #include <omp.h>
32 #endif
33 
34 
35 
36 #ifdef WIN32
37 #include <windows.h>
38 // for GCC32
39 #ifndef _WIN32_IE
40 #define _WIN32_IE 0x0600
41 #endif
42 #include <Shlobj.h>
43 #endif
44 
45 // User's settings directory, including images' profiles if used
46 Glib::ustring Options::rtdir;
47 // User's cached datas' directory
48 Glib::ustring Options::cacheBaseDir;
49 
50 Options options;
51 Glib::ustring versionString = RTVERSION;
52 Glib::ustring paramFileExtension = ".arp";
53 
54 
RenameOptions()55 Options::RenameOptions::RenameOptions()
56 {
57     pattern = "%f.%e";
58     sidecars = "";
59     name_norm = 0;
60     ext_norm = 0;
61     allow_whitespace = false;
62     on_existing = 0;
63     progressive_number = 1;
64 }
65 
66 
Options()67 Options::Options()
68 {
69     defProfError = 0;
70     setDefaults();
71 }
72 
73 const char *DefaultLanguage = "English (US)";
74 
checkProfilePath(Glib::ustring & path)75 inline bool Options::checkProfilePath(Glib::ustring &path)
76 {
77     if (path.empty()) {
78         return false;
79     }
80 
81     Glib::ustring p = getUserProfilePath();
82 
83     if (!p.empty() && Glib::file_test(path + paramFileExtension, Glib::FILE_TEST_EXISTS)) {
84         return true;
85     }
86 
87     p = getGlobalProfilePath();
88 
89     return !p.empty() && Glib::file_test(path + paramFileExtension, Glib::FILE_TEST_EXISTS);
90 }
91 
checkDirPath(Glib::ustring & path,Glib::ustring errString)92 bool Options::checkDirPath(Glib::ustring &path, Glib::ustring errString)
93 {
94     if (Glib::file_test(path, Glib::FILE_TEST_EXISTS) && Glib::file_test(path, Glib::FILE_TEST_IS_DIR)) {
95         return true;
96     } else {
97         if (!errString.empty()) {
98             std::cerr << errString << std::endl;
99         }
100 
101         return false;
102     }
103 }
104 
updatePaths()105 void Options::updatePaths()
106 {
107 
108     Glib::ustring tmpPath;
109 
110     userProfilePath = "";
111     globalProfilePath = "";
112 
113     if (Glib::path_is_absolute(profilePath)) {
114         // absolute path
115         if (!checkDirPath(profilePath, "")) {
116             g_mkdir_with_parents(profilePath.c_str(), 511);
117 
118             if (!checkDirPath(profilePath, "")) {  // had problems with mkdir_with_parents return value on OS X, just check dir again
119                 Glib::ustring msg = Glib::ustring::compose("Creation of the user's processing profile directory \"%1\" failed!\n", profilePath);
120                 throw Error(msg);
121             }
122         }
123 
124         if (checkDirPath(profilePath, "Error: the user's processing profile path doesn't point to a directory or doesn't exist!\n")) {
125             userProfilePath = profilePath;
126             tmpPath = Glib::build_filename(argv0, "profiles");
127 
128             if (checkDirPath(tmpPath, "Error: the global's processing profile path doesn't point to a directory or doesn't exist!\n")) {
129                 if (userProfilePath != tmpPath) {
130                     globalProfilePath = tmpPath;
131                 }
132             }
133         } else {
134             tmpPath = Glib::build_filename(argv0, "profiles");
135 
136             if (checkDirPath(tmpPath, "Error: the global's processing profile path doesn't point to a directory or doesn't exist!\n")) {
137                 globalProfilePath = tmpPath;
138             }
139         }
140     } else {
141         // relative paths
142         tmpPath = Glib::build_filename(rtdir, profilePath);
143 
144         if (!checkDirPath(tmpPath, "")) {
145             g_mkdir_with_parents(tmpPath.c_str(), 511);
146 
147             if (!checkDirPath(tmpPath, "")) {
148                 Glib::ustring msg = Glib::ustring::compose("Creation of the user's processing profile directory \"%1\" failed!\n", tmpPath.c_str());
149                 throw Error(msg);
150             }
151         }
152 
153         if (checkDirPath(tmpPath, "Error: the user's processing profile path doesn't point to a directory!\n")) {
154             userProfilePath = tmpPath;
155         }
156 
157         tmpPath = Glib::build_filename(argv0, "profiles");
158 
159         if (checkDirPath(tmpPath, "Error: the user's processing profile path doesn't point to a directory or doesn't exist!\n")) {
160             globalProfilePath = tmpPath;
161         }
162     }
163 
164     Glib::ustring preferredPath = getPreferredProfilePath();
165 
166     // Paths are updated only if the user or global profile path is set
167     if (lastRgbCurvesDir.empty() || !Glib::file_test(lastRgbCurvesDir, Glib::FILE_TEST_EXISTS) || !Glib::file_test(lastRgbCurvesDir, Glib::FILE_TEST_IS_DIR)) {
168         lastRgbCurvesDir = preferredPath;
169     }
170 
171     if (lastLabCurvesDir.empty() || !Glib::file_test(lastLabCurvesDir, Glib::FILE_TEST_EXISTS) || !Glib::file_test(lastLabCurvesDir, Glib::FILE_TEST_IS_DIR)) {
172         lastLabCurvesDir = preferredPath;
173     }
174 
175     if (lastPFCurvesDir.empty() || !Glib::file_test(lastPFCurvesDir, Glib::FILE_TEST_EXISTS) || !Glib::file_test(lastPFCurvesDir, Glib::FILE_TEST_IS_DIR)) {
176         lastPFCurvesDir = preferredPath;
177     }
178 
179     if (lastHsvCurvesDir.empty() || !Glib::file_test(lastHsvCurvesDir, Glib::FILE_TEST_EXISTS) || !Glib::file_test(lastHsvCurvesDir, Glib::FILE_TEST_IS_DIR)) {
180         lastHsvCurvesDir = preferredPath;
181     }
182 
183     if (lastToneCurvesDir.empty() || !Glib::file_test(lastToneCurvesDir, Glib::FILE_TEST_EXISTS) || !Glib::file_test(lastToneCurvesDir, Glib::FILE_TEST_IS_DIR)) {
184         lastToneCurvesDir = preferredPath;
185     }
186 
187     if (lastProfilingReferenceDir.empty() || !Glib::file_test(lastProfilingReferenceDir, Glib::FILE_TEST_EXISTS) || !Glib::file_test(lastProfilingReferenceDir, Glib::FILE_TEST_IS_DIR)) {
188         lastProfilingReferenceDir = preferredPath;
189     }
190 
191     if (loadSaveProfilePath.empty() || !Glib::file_test(loadSaveProfilePath, Glib::FILE_TEST_EXISTS) || !Glib::file_test(loadSaveProfilePath, Glib::FILE_TEST_IS_DIR)) {
192         loadSaveProfilePath = preferredPath;
193     }
194 
195     if (lastICCProfCreatorDir.empty() || !Glib::file_test(lastICCProfCreatorDir, Glib::FILE_TEST_EXISTS) || !Glib::file_test(lastICCProfCreatorDir, Glib::FILE_TEST_IS_DIR)) {
196         lastICCProfCreatorDir = preferredPath;
197     }
198 }
199 
getPreferredProfilePath()200 Glib::ustring Options::getPreferredProfilePath()
201 {
202     if (!userProfilePath.empty()) {
203         return userProfilePath;
204     } else if (!globalProfilePath.empty()) {
205         return globalProfilePath;
206     } else {
207         return "";
208     }
209 }
210 
211 /** @brief Get the absolute path of the given filename or the "Neutral" special value
212   *
213   *@param profName  path + filename of the procparam to look for. A filename without path can be provided for backward compatibility.
214   *                 In this case, this parameter will be updated with the new format.
215   *@return Send back the absolute path of the given filename or "Neutral" if "Neutral" has been set to profName. Implementor will have
216   *        to test for this particular value. If the absolute path is invalid (e.g. the file doesn't exist), it will return an empty string.
217   */
findProfilePath(Glib::ustring & profName)218 Glib::ustring Options::findProfilePath(Glib::ustring &profName)
219 {
220     if (profName.empty()) {
221         return "";
222     }
223 
224     if (profName == DEFPROFILE_INTERNAL) {
225         return profName;
226     }
227 
228     if (profName == DEFPROFILE_DYNAMIC) {
229         return profName;
230     }
231 
232     Glib::ustring p = profName.substr(0, 4);
233 
234     if (p == "${U}") {
235         // the path starts by the User virtual path
236         p = getUserProfilePath();
237         Glib::ustring fullPath = Glib::build_filename(p, profName.substr(5) + paramFileExtension);
238 
239         if (!p.empty() && Glib::file_test(fullPath, Glib::FILE_TEST_EXISTS)) {
240             return Glib::path_get_dirname(fullPath);
241         }
242     } else if (p == "${G}") {
243         // the path starts by the User virtual path
244         p = getGlobalProfilePath();
245         Glib::ustring fullPath = Glib::build_filename(p, profName.substr(5) + paramFileExtension);
246 
247         if (!p.empty() && Glib::file_test(fullPath, Glib::FILE_TEST_EXISTS)) {
248             return Glib::path_get_dirname(fullPath);
249         }
250     } else {
251         // compatibility case -> convert the path to the new format
252         p = getUserProfilePath();
253         Glib::ustring fullPath = Glib::build_filename(p, profName + paramFileExtension);
254 
255         if (!p.empty() && Glib::file_test(fullPath, Glib::FILE_TEST_EXISTS)) {
256             // update the profile path
257             profName = Glib::build_filename("${U}", profName);
258             return Glib::path_get_dirname(fullPath);
259         }
260 
261         p = getGlobalProfilePath();
262         fullPath = Glib::build_filename(p, profName + paramFileExtension);
263 
264         if (!p.empty() && Glib::file_test(fullPath, Glib::FILE_TEST_EXISTS)) {
265             profName = Glib::build_filename("${G}", profName);
266             return Glib::path_get_dirname(fullPath);
267         }
268     }
269 
270     return "";
271 
272 }
273 
setDefaults()274 void Options::setDefaults()
275 {
276     windowWidth = 1200;
277     windowHeight = 680;
278     windowX = 0;
279     windowY = 0;
280     windowMaximized = true;
281     windowMonitor = 0;
282     meowMonitor = -1;
283     meowFullScreen = false;
284     meowMaximized = true;
285     meowWidth = 1200;
286     meowHeight = 680;
287     meowX = 0;
288     meowY = 0;
289     saveAsDialogWidth = 920;
290     saveAsDialogHeight = 680;
291     saveFormat.format = "jpg";
292     saveFormat.jpegQuality = 92;
293     saveFormat.jpegSubSamp = 2;
294     saveFormat.pngBits = 8;
295     saveFormat.tiffBits = 16;
296     saveFormat.tiffFloat = false;
297     saveFormat.tiffUncompressed = true;
298     saveFormat.saveParams = true;
299 
300     saveFormatBatch.format = "jpg";
301     saveFormatBatch.jpegQuality = 92;
302     saveFormatBatch.jpegSubSamp = 2;
303     saveFormatBatch.pngBits = 8;
304     saveFormatBatch.tiffBits = 16;
305     saveFormatBatch.tiffFloat = false;
306     saveFormatBatch.tiffUncompressed = true;
307     saveFormatBatch.saveParams = true;
308 
309     savePathTemplate = "%p1/converted/%f";
310     savePathFolder = "";
311     saveUsePathTemplate = true;
312     defProfRaw = DEFPROFILE_RAW;
313     defProfImg = DEFPROFILE_IMG;
314     dateFormat = "%Y-%m-%d";
315     adjusterMinDelay = 100;
316     adjusterMaxDelay = 200;
317     startupDir = STARTUPDIR_LAST;
318     startupPath = "";
319     useBundledProfiles = true;
320     detailWindowWidth = -1;
321     detailWindowHeight = -1;
322     dirBrowserWidth = 260;
323     dirBrowserHeight = 350;
324     dirBrowserSortType = Gtk::SORT_ASCENDING;
325     preferencesWidth = 800;
326     preferencesHeight = 600;
327     toolPanelWidth = 400;
328     browserToolPanelWidth = 465;
329     browserToolPanelHeight = 600;
330     browserToolPanelOpened = true;
331     browserDirPanelOpened = true;
332     editorFilmStripOpened = true;
333     inspectorDirPanelOpened = true;
334     historyPanelWidth = 330;
335     fontFamily = "default";
336     fontSize = 10;
337     CPFontFamily = "default";
338     CPFontSize = 8;
339     pseudoHiDPISupport = false;
340     lastScale = 5;
341     panAccelFactor = 5;
342     rememberZoomAndPan = true;
343     fbShowDateTime = true;
344     fbShowBasicExif = true;
345     fbShowExpComp = false;
346 #ifdef WIN32
347     // use windows setting for visibility of hidden files/folders
348     SHELLFLAGSTATE sft = { 0 };
349     SHGetSettings(&sft, SSF_SHOWALLOBJECTS);
350     fbShowHidden = sft.fShowAllObjects;
351 #else
352     fbShowHidden = false;
353 #endif
354     navRGBUnit = NavigatorUnit::PERCENT;
355     navLCHUnit = NavigatorUnit::PERCENT;
356     multiUser = true;
357     profilePath = "profiles";
358     loadSaveProfilePath = "";           // will be corrected in load as otherwise construction fails
359     lastCopyMovePath = "";
360     version = "0.0.0.0";                // temporary value; will be correctly set in RTWindow::on_realize
361     thumbSize = 160;
362     thumbSizeTab = 160;
363     thumbSizeQueue = 160;
364     sameThumbSize = false;               // preferring speed of switch between file browser and single editor tab
365     thumbnailOrder = ThumbnailOrder::FILENAME;
366     showHistory = true;
367     showInfo = true;
368     cropPPI = 600;
369     showClippedHighlights = false;
370     showClippedShadows = false;
371     highlightThreshold = 253;           // was 254
372     shadowThreshold = 8;                // was 0
373     bgcolor = 1;
374     language = DefaultLanguage;
375     languageAutoDetect = langMgr.isOSLanguageDetectSupported();
376     lastSaveAsPath = "";
377     overwriteOutputFile = false;        // if TRUE, existing output JPGs/PNGs are overwritten, instead of adding ..-1.jpg, -2.jpg etc.
378     theme = "RawTherapee";
379     maxThumbnailHeight = 250;
380     maxThumbnailWidth = 800;
381     maxCacheEntries = 20000;
382     thumbInterp = 1;
383     autoSuffix = true;
384     forceFormatOpts = true;
385     saveMethodNum = 0;              // 0->immediate, 1->putToQueuHead, 2->putToQueueTail
386     saveParamsFile = true;              // was false, but saving the procparams files next to the file make more sense when reorganizing file tree than in a cache
387     saveParamsCache = false;            // there's no need to save the procparams files in a cache if saveParamsFile is true
388     paramsLoadLocation = PLL_Input;     // was PLL_Cache
389     params_out_embed = false;
390     params_sidecar_strip_extension = false;
391     procQueueEnabled = false;
392     gimpDir = "";
393     psDir = "";
394     customEditorProg = "";
395     CPBKeys = CPBKT_TID;
396     editorToSendTo = 1;
397     editor_out_dir = EDITOR_OUT_DIR_TEMP;
398     editor_custom_out_dir = "";
399     editor_float32 = false;
400     editor_bypass_output_profile = false;
401     favoriteDirs.clear();
402     tpOpen.clear();
403     autoSaveTpOpen = true;
404     //crvOpen.clear ();
405     parseExtensions.clear();
406     favorites.clear();
407     parseExtensionsEnabled.clear();
408     parsedExtensions.clear();
409     parsedExtensionsSet.clear();
410     thumbnailZoomRatios.clear();
411     thumbnailZoomRatios.push_back(0.2);
412     thumbnailZoomRatios.push_back(0.3);
413     thumbnailZoomRatios.push_back(0.45);
414     thumbnailZoomRatios.push_back(0.6);
415     thumbnailZoomRatios.push_back(0.8);
416     thumbnailZoomRatios.push_back(1.0);
417     overlayedFileNames = false;
418     filmStripOverlayedFileNames = false;
419     internalThumbIfUntouched = true;    // if TRUE, only fast, internal preview images are taken if the image is not edited yet
420     showFileNames = true;
421     filmStripShowFileNames = false;
422     tabbedUI = false;
423     mainNBVertical = true;
424     multiDisplayMode = 0;
425     histogramPosition = 1;
426     histogramRed = true;
427     histogramGreen = true;
428     histogramBlue = true;
429     histogramLuma = false;
430     histogramChroma = false;
431     //histogramRAW = false;
432     histogramBar = true;
433     histogramHeight = 200;
434     histogramDrawMode = 0;
435     histogram_scaling_factor = 10.0;
436     histogramScopeType = ScopeType::HISTOGRAM;
437     histogramShowOptionButtons = false;
438     histogramTraceBrightness = 1;
439     curvebboxpos = 1;
440     prevdemo = PD_Sidecar;
441     rgbDenoiseThreadLimit = 0;
442 #if defined( _OPENMP ) && defined( __x86_64__ )
443     clutCacheSize = omp_get_num_procs();
444 #else
445     clutCacheSize = 1;
446 #endif
447     thumb_update_thread_limit = 0;
448     thumb_delay_update = false;
449     thumb_lazy_caching = true;
450     filledProfile = false;
451     maxInspectorBuffers = 2; //  a rather conservative value for low specced systems...
452     inspectorDelay = 0;
453     serializeTiffRead = true;
454     denoiseZoomedOut = true;
455     wb_preview_mode = WB_BEFORE_HIGH_DETAIL;
456 
457     FileBrowserToolbarSingleRow = false;
458     hideTPVScrollbar = false;
459     whiteBalanceSpotSize = 8;
460     showFilmStripToolBar = false;
461     menuGroupRank = true;
462     menuGroupLabel = true;
463     menuGroupFileOperations = true;
464     menuGroupProfileOperations = true;
465     menuGroupExtProg = true;
466 
467     ICCPC_primariesPreset = "sRGB",
468     ICCPC_redPrimaryX = 0.6400;
469     ICCPC_redPrimaryY = 0.3300;
470     ICCPC_greenPrimaryX = 0.3000;
471     ICCPC_greenPrimaryY = 0.6000;
472     ICCPC_bluePrimaryX = 0.1500;
473     ICCPC_bluePrimaryY = 0.0600;
474     ICCPC_gammaPreset = "Custom";
475     ICCPC_gamma = 2.4;
476     ICCPC_slope = 12.92;
477     ICCPC_profileVersion = "v4";
478     ICCPC_illuminant = "DEF";
479     ICCPC_description = "";
480     ICCPC_copyright = Options::getICCProfileCopyright();
481     ICCPC_appendParamsToDesc = false;
482 
483     fastexport_bypass_sharpening         = true;
484     fastexport_bypass_defringe           = true;
485     fastexport_bypass_dirpyrDenoise      = true;
486     fastexport_bypass_localContrast    = true;
487     fastexport_raw_bayer_method                  = "fast";
488     //fastexport_bypass_raw_bayer_all_enhance    = true;
489     fastexport_bypass_raw_bayer_dcb_iterations   = true;
490     fastexport_bypass_raw_bayer_dcb_enhance      = true;
491     fastexport_bypass_raw_bayer_lmmse_iterations = true;
492     fastexport_bypass_raw_bayer_linenoise        = true;
493     fastexport_bypass_raw_bayer_greenthresh      = true;
494     fastexport_raw_xtrans_method                 = "fast";
495     fastexport_bypass_raw_ccSteps        = true;
496     fastexport_bypass_raw_ca             = true;
497     fastexport_bypass_raw_df             = true;
498     fastexport_bypass_raw_ff             = true;
499     fastexport_icm_input_profile         = "(camera)";
500     fastexport_icm_working_profile       = "ProPhoto";
501     fastexport_icm_output_profile        = options.rtSettings.srgb;
502     fastexport_icm_outputIntent          = rtengine::RI_RELATIVE;
503     fastexport_icm_outputBPC             = true;
504     fastexport_resize_enabled            = true;
505     fastexport_resize_scale              = 1;
506     fastexport_resize_appliesTo          = "Cropped area";
507     fastexport_resize_dataspec           = 3;
508     fastexport_resize_width              = 900;
509     fastexport_resize_height             = 900;
510     fastexport_use_fast_pipeline         = true;
511 
512     clutsDir = "./cluts";
513 
514     cutOverlayBrush = std::vector<double> (4);
515     cutOverlayBrush[3] = 0.667;  // :-p
516 
517     navGuideBrush = std::vector<double> (4);
518     //default to red
519     navGuideBrush[0] = 1.0;
520     navGuideBrush[1] = 0.0;
521     navGuideBrush[2] = 0.0;
522     navGuideBrush[3] = 1.0;
523 
524     sndEnable = true;
525     sndLngEditProcDoneSecs = 3.0;
526 #ifdef __linux__
527     sndBatchQueueDone = "complete";
528     sndLngEditProcDone = "window-attention";
529 #endif
530 
531     rtSettings.darkFramesPath = "";
532     rtSettings.flatFieldsPath = "";
533 #ifdef WIN32
534     const gchar* sysRoot = g_getenv("SystemRoot");  // Returns e.g. "c:\Windows"
535 
536     if (sysRoot != NULL) {
537         rtSettings.iccDirectory = Glib::ustring(sysRoot) + Glib::ustring("\\System32\\spool\\drivers\\color");
538     } else {
539         rtSettings.iccDirectory = "C:\\WINDOWS\\System32\\spool\\drivers\\color";
540     }
541 
542 #elif defined __APPLE__
543     rtSettings.iccDirectory = "/library/ColorSync/Profiles/Displays";
544 #else
545     rtSettings.iccDirectory = "/usr/share/color/icc";
546 #endif
547 
548     rtSettings.monitorIccDirectory = rtSettings.iccDirectory;
549 
550     rtSettings.printerProfile = Glib::ustring();
551     rtSettings.printerIntent = rtengine::RI_RELATIVE;
552     rtSettings.printerBPC = true;
553     rtSettings.monitorProfile = Glib::ustring();
554     rtSettings.monitorIntent = rtengine::RI_RELATIVE;
555     rtSettings.monitorBPC = true;
556     rtSettings.autoMonitorProfile = false;
557     rtSettings.adobe = "RTv2_Medium"; // put the name of yours profiles (here windows)
558     rtSettings.prophoto = "RTv2_Large"; // these names appear in the menu "output profile"
559     rtSettings.widegamut = "RTv2_Wide";
560     rtSettings.srgb = "RTv4_sRGB";
561     rtSettings.bruce = "RTv2_Bruce";
562     rtSettings.beta = "RTv2_Beta";
563     rtSettings.best = "RTv2_Best";
564     rtSettings.rec2020 = "RTv2_Rec2020";
565     rtSettings.ACESp0 = "RTv2_ACES-AP0";
566     rtSettings.ACESp1 = "RTv2_ACES-AP1";
567     rtSettings.verbose = false;
568 
569     rtSettings.HistogramWorking = false;
570 
571     // #4327 - Noise Reduction settings removed from Preferences
572     rtSettings.nrauto = 10; // between 2 and 20
573     rtSettings.nrautomax = 40; // between 5 and 100
574     rtSettings.nrhigh = 0.9;//0.45; // between 0.1 and 0.9
575     rtSettings.nrwavlevel = 2;//1; // integer between 0 and 2
576     rtSettings.leveldnv = 2;
577     rtSettings.leveldnti = 0;
578     rtSettings.leveldnaut = 0;
579     rtSettings.leveldnliss = 0;
580     rtSettings.leveldnautsimpl = 0;
581 
582     lastIccDir = rtSettings.iccDirectory;
583     lastDarkframeDir = rtSettings.darkFramesPath;
584     lastFlatfieldDir = rtSettings.flatFieldsPath;
585 
586     // There is no reasonable default for curves. We can still suppose that they will take place
587     // in a subdirectory of the user's own ProcParams presets, i.e. in a subdirectory
588     // of the one pointed to by the "profile" field.
589     // The following fields will then be initialized when "profile" will have its final value,
590     // at the end of the "updatePaths" method.
591     lastRgbCurvesDir = "";
592     lastLabCurvesDir = "";
593     lastPFCurvesDir = "";
594     lastHsvCurvesDir = "";
595     lastToneCurvesDir = "";
596     lastProfilingReferenceDir = "";
597     lastLensProfileDir = "";
598     lastICCProfCreatorDir = "";
599     gimpPluginShowInfoDialog = true;
600     maxRecentFolders = 15;
601     rtSettings.lensfunDbDirectory = ""; // set also in main.cc and main-cli.cc
602 
603     rtSettings.thumbnail_inspector_mode = rtengine::Settings::ThumbnailInspectorMode::JPEG;
604     rtSettings.thumbnail_inspector_raw_curve = rtengine::Settings::ThumbnailInspectorRawCurve::LINEAR;
605     thumbnail_inspector_zoom_fit = false;
606     thumbnail_inspector_show_info = false;
607     thumbnail_inspector_enable_cms = false;
608     thumbnail_inspector_show_histogram = false;
609     thumbnail_inspector_hover = false;
610 
611     thumbnail_rating_mode = Options::ThumbnailRatingMode::XMP;
612 #if defined WIN32 || defined __APPLE__
613     rtSettings.xmp_sidecar_style = rtengine::Settings::XmpSidecarStyle::STD;
614 #else
615     rtSettings.xmp_sidecar_style = rtengine::Settings::XmpSidecarStyle::EXT;
616 #endif
617     rtSettings.metadata_xmp_sync = rtengine::Settings::MetadataXmpSync::READ;
618     rtSettings.exiftool_path = "exiftool";
619 #ifdef WIN32
620     rtSettings.exiftool_path += ".exe";
621 #endif
622 
623     browser_width_for_inspector = 0;
624 
625     batch_queue_use_profile = false;
626     batch_queue_profile_path = "";
627 
628     toolpanels_disable = false;
629     adjuster_force_linear = false;
630 
631     error_message_duration = 5000;
632     max_error_messages = 3;
633 
634     falseColorsMap = {
635         {2, "#FFFFFF"},
636         {10, "#0000FF"},
637         {20, "#2290FF"},
638         {42, "#4B4B4B"},
639         {48, "#FF11FC"},
640         {52, "#7B7B7B"},
641         {58, "#00FF00"},
642         {78, "#ADADAD"},
643         {84, "#AEAE00"},
644         {94, "#FFFF00"},
645         {100, "#FF7F00"},
646         {108, "#FF0000"}
647     };
648 
649     renaming = RenameOptions();
650     sidecar_autosave_interval = 0;
651 }
652 
copyFrom(Options * other)653 Options* Options::copyFrom(Options* other)
654 {
655     *this = *other;
656     return this;
657 }
658 
filterOutParsedExtensions()659 void Options::filterOutParsedExtensions()
660 {
661     parsedExtensions.clear();
662     parsedExtensionsSet.clear();
663 
664     for (unsigned int i = 0; i < parseExtensions.size(); i++)
665         if (parseExtensionsEnabled[i]) {
666             parsedExtensions.push_back(parseExtensions[i].lowercase());
667             parsedExtensionsSet.emplace(parseExtensions[i].lowercase());
668         }
669 }
670 
readFromFile(Glib::ustring fname)671 void Options::readFromFile(Glib::ustring fname)
672 {
673     setlocale(LC_NUMERIC, "C");  // to set decimal point to "."
674 
675     Glib::KeyFile keyFile;
676 
677     if (!Glib::file_test(fname, Glib::FILE_TEST_EXISTS)) {
678         Glib::ustring msg = Glib::ustring::compose("Options file %1 does not exist", fname);
679         throw Error(msg);
680     }
681 
682     try {
683         if (keyFile.load_from_file(fname)) {
684 
685 // --------------------------------------------------------------------------------------------------------
686 
687             if (keyFile.has_group("General")) {
688                 if (keyFile.has_key("General", "TabbedEditor")) {
689                     tabbedUI = keyFile.get_boolean("General", "TabbedEditor");
690                 }
691 
692                 if (keyFile.has_key("General", "StartupDirectory")) {
693                     if (keyFile.get_string("General", "StartupDirectory") == "home") {
694                         startupDir = STARTUPDIR_HOME;
695                     } else if (keyFile.get_string("General", "StartupDirectory") == "current") {
696                         startupDir = STARTUPDIR_CURRENT;
697                     } else if (keyFile.get_string("General", "StartupDirectory") == "last") {
698                         startupDir = STARTUPDIR_LAST;
699                     } else if (keyFile.get_string("General", "StartupDirectory") == "custom") {
700                         startupDir = STARTUPDIR_CUSTOM;
701                     }
702                 }
703 
704                 if (keyFile.has_key("General", "StartupPath")) {
705                     startupPath = keyFile.get_string("General", "StartupPath");
706                 }
707 
708                 if (keyFile.has_key("General", "DateFormat")) {
709                     dateFormat = keyFile.get_string("General", "DateFormat");
710                 }
711 
712                 if (keyFile.has_key("General", "AdjusterMinDelay")) {
713                     adjusterMinDelay = keyFile.get_integer("General", "AdjusterMinDelay");
714                 }
715 
716                 if (keyFile.has_key("General", "AdjusterMaxDelay")) {
717                     adjusterMaxDelay = keyFile.get_integer("General", "AdjusterMaxDelay");
718                 }
719 
720                 if (keyFile.has_key("General", "MultiUser")) {
721                     multiUser = keyFile.get_boolean("General", "MultiUser");
722                 }
723 
724                 if (keyFile.has_key("General", "Version")) {
725                     version = keyFile.get_string("General", "Version");
726                 }
727 
728                 if (keyFile.has_key("General", "Language")) {
729                     language = keyFile.get_string("General", "Language");
730                 }
731 
732                 if (keyFile.has_key("General", "LanguageAutoDetect")) {
733                     languageAutoDetect = keyFile.get_boolean("General", "LanguageAutoDetect");
734                 }
735 
736                 if (keyFile.has_key("General", "Theme")) {
737                     theme = keyFile.get_string("General", "Theme");
738                 }
739 
740                 if (keyFile.has_key("General", "DarkFramesPath")) {
741                     rtSettings.darkFramesPath = keyFile.get_string("General", "DarkFramesPath");
742                 }
743 
744                 if (keyFile.has_key("General", "FlatFieldsPath")) {
745                     rtSettings.flatFieldsPath = keyFile.get_string("General", "FlatFieldsPath");
746                 }
747 
748                 if (keyFile.has_key("General", "Verbose")) {
749                     rtSettings.verbose = keyFile.get_boolean("General", "Verbose");
750                 }
751 
752                 if (keyFile.has_key("General", "ErrorMessageDuration")) {
753                     error_message_duration = keyFile.get_integer("General", "ErrorMessageDuration");
754                 }
755 
756                 if (keyFile.has_key("General", "MaxErrorMessages")) {
757                     max_error_messages = keyFile.get_integer("General", "MaxErrorMessages");
758                 }
759             }
760 
761             if (keyFile.has_group("External Editor")) {
762                 if (keyFile.has_key("External Editor", "EditorKind")) {
763                     editorToSendTo = keyFile.get_integer("External Editor", "EditorKind");
764                 }
765 
766                 if (keyFile.has_key("External Editor", "GimpDir")) {
767                     gimpDir = keyFile.get_string("External Editor", "GimpDir");
768                 }
769 
770                 if (keyFile.has_key("External Editor", "PhotoshopDir")) {
771                     psDir = keyFile.get_string("External Editor", "PhotoshopDir");
772                 }
773 
774                 if (keyFile.has_key("External Editor", "CustomEditor")) {
775                     customEditorProg = keyFile.get_string("External Editor", "CustomEditor");
776                 }
777 
778                 if (keyFile.has_key("External Editor", "OutputDir")) {
779                     int v = keyFile.get_integer("External Editor", "OutputDir");
780                     if (v < int(EDITOR_OUT_DIR_TEMP) || v > int(EDITOR_OUT_DIR_CUSTOM)) {
781                         editor_out_dir = EDITOR_OUT_DIR_TEMP;
782                     } else {
783                         editor_out_dir = EditorOutDir(v);
784                     }
785                 }
786 
787                 if (keyFile.has_key("External Editor", "CustomOutputDir")) {
788                     editor_custom_out_dir = keyFile.get_string("External Editor", "CustomOutputDir");
789                 }
790 
791                 if (keyFile.has_key("External Editor", "Float32")) {
792                     editor_float32 = keyFile.get_boolean("External Editor", "Float32");
793                 }
794 
795                 if (keyFile.has_key("External Editor", "BypassOutputProfile")) {
796                     editor_bypass_output_profile = keyFile.get_boolean("External Editor", "BypassOutputProfile");
797                 }
798             }
799 
800             if (keyFile.has_group("Output")) {
801                 if (keyFile.has_key("Output", "Format")) {
802                     saveFormat.format = keyFile.get_string("Output", "Format");
803                 }
804 
805                 if (keyFile.has_key("Output", "JpegQuality")) {
806                     saveFormat.jpegQuality = keyFile.get_integer("Output", "JpegQuality");
807                 }
808 
809                 if (keyFile.has_key("Output", "JpegSubSamp")) {
810                     saveFormat.jpegSubSamp = keyFile.get_integer("Output", "JpegSubSamp");
811                 }
812 
813                 if (keyFile.has_key("Output", "PngBps")) {
814                     saveFormat.pngBits = keyFile.get_integer("Output", "PngBps");
815                 }
816 
817                 if (keyFile.has_key("Output", "TiffBps")) {
818                     saveFormat.tiffBits = keyFile.get_integer("Output", "TiffBps");
819                 }
820 
821                 if (keyFile.has_key ("Output", "TiffFloat")) {
822                     saveFormat.tiffFloat = keyFile.get_boolean ("Output", "TiffFloat");
823                 }
824 
825                 if (keyFile.has_key("Output", "TiffUncompressed")) {
826                     saveFormat.tiffUncompressed = keyFile.get_boolean("Output", "TiffUncompressed");
827                 }
828 
829                 if (keyFile.has_key("Output", "SaveProcParams")) {
830                     saveFormat.saveParams = keyFile.get_boolean("Output", "SaveProcParams");
831                 }
832 
833 
834                 if (keyFile.has_key("Output", "FormatBatch")) {
835                     saveFormatBatch.format = keyFile.get_string("Output", "FormatBatch");
836                 }
837 
838                 if (keyFile.has_key("Output", "JpegQualityBatch")) {
839                     saveFormatBatch.jpegQuality = keyFile.get_integer("Output", "JpegQualityBatch");
840                 }
841 
842                 if (keyFile.has_key("Output", "JpegSubSampBatch")) {
843                     saveFormatBatch.jpegSubSamp = keyFile.get_integer("Output", "JpegSubSampBatch");
844                 }
845 
846                 if (keyFile.has_key("Output", "PngBpsBatch")) {
847                     saveFormatBatch.pngBits = keyFile.get_integer("Output", "PngBpsBatch");
848                 }
849 
850                 if (keyFile.has_key("Output", "TiffBpsBatch")) {
851                     saveFormatBatch.tiffBits = keyFile.get_integer("Output", "TiffBpsBatch");
852                 }
853 
854                 if (keyFile.has_key ("Output", "TiffFloatBatch")) {
855                     saveFormatBatch.tiffFloat = keyFile.get_boolean ("Output", "TiffFloatBatch");
856                 }
857 
858                 if (keyFile.has_key("Output", "TiffUncompressedBatch")) {
859                     saveFormatBatch.tiffUncompressed = keyFile.get_boolean("Output", "TiffUncompressedBatch");
860                 }
861 
862                 if (keyFile.has_key("Output", "SaveProcParamsBatch")) {
863                     saveFormatBatch.saveParams = keyFile.get_boolean("Output", "SaveProcParamsBatch");
864                 }
865 
866                 if (keyFile.has_key("Output", "Path")) {
867                     savePathTemplate = keyFile.get_string("Output", "Path");
868                 }
869 
870                 if (keyFile.has_key("Output", "PathTemplate")) {
871                     savePathTemplate = keyFile.get_string("Output", "PathTemplate");
872                 }
873 
874                 if (keyFile.has_key("Output", "PathFolder")) {
875                     savePathFolder = keyFile.get_string("Output", "PathFolder");
876                 }
877 
878                 if (keyFile.has_key("Output", "AutoSuffix")) {
879                     autoSuffix = keyFile.get_boolean("Output", "AutoSuffix");
880                 }
881 
882                 if (keyFile.has_key("Output", "ForceFormatOpts")) {
883                     forceFormatOpts = keyFile.get_boolean("Output", "ForceFormatOpts");
884                 }
885 
886                 if (keyFile.has_key("Output", "SaveMethodNum")) {
887                     saveMethodNum = keyFile.get_integer("Output", "SaveMethodNum");
888                 }
889 
890                 if (keyFile.has_key("Output", "UsePathTemplate")) {
891                     saveUsePathTemplate = keyFile.get_boolean("Output", "UsePathTemplate");
892                 }
893 
894                 if (keyFile.has_key("Output", "LastSaveAsPath")) {
895                     lastSaveAsPath = keyFile.get_string("Output", "LastSaveAsPath");
896                 }
897 
898                 if (keyFile.has_key("Output", "OverwriteOutputFile")) {
899                     overwriteOutputFile = keyFile.get_boolean("Output", "OverwriteOutputFile");
900                 }
901 
902                 if (keyFile.has_key("Output", "BatchQueueUseProfile")) {
903                     batch_queue_use_profile = keyFile.get_boolean("Output", "BatchQueueUseProfile");
904                 }
905 
906                 if (keyFile.has_key("Output", "BatchQueueProfile")) {
907                     batch_queue_profile_path = keyFile.get_string("Output", "BatchQueueProfile");
908                 }
909 
910                 if (keyFile.has_key("Output", "ProcParamsAutosaveInterval")) {
911                     sidecar_autosave_interval = keyFile.get_integer("Output", "ProcParamsAutosaveInterval");
912                 }
913             }
914 
915             if (keyFile.has_group("Profiles")) {
916                 if (keyFile.has_key("Profiles", "Directory")) {
917                     profilePath = keyFile.get_string("Profiles", "Directory");
918                 }
919 
920                 if (keyFile.has_key("Profiles", "UseBundledProfiles")) {
921                     useBundledProfiles = keyFile.get_boolean("Profiles", "UseBundledProfiles");
922                 }
923 
924                 if (keyFile.has_key("Profiles", "LoadSaveProfilePath")) {
925                     loadSaveProfilePath = keyFile.get_string("Profiles", "LoadSaveProfilePath");
926                 }
927 
928                 if (keyFile.has_key("Profiles", "RawDefault")) {
929                     defProfRaw = keyFile.get_string("Profiles", "RawDefault");
930                 }
931 
932                 if (keyFile.has_key("Profiles", "ImgDefault")) {
933                     defProfImg = keyFile.get_string("Profiles", "ImgDefault");
934                 }
935 
936                 if (keyFile.has_key("Profiles", "FilledProfile")) {
937                     filledProfile = keyFile.get_boolean("Profiles", "FilledProfile");
938                 }
939 
940                 if (keyFile.has_key("Profiles", "SaveParamsWithFile")) {
941                     saveParamsFile = keyFile.get_boolean("Profiles", "SaveParamsWithFile");
942                 }
943 
944                 if (keyFile.has_key("Profiles", "SaveParamsToCache")) {
945                     saveParamsCache = keyFile.get_boolean("Profiles", "SaveParamsToCache");
946                 }
947 
948                 if (keyFile.has_key("Profiles", "LoadParamsFromLocation")) {
949                     paramsLoadLocation = (PPLoadLocation)keyFile.get_integer("Profiles", "LoadParamsFromLocation");
950                 }
951 
952                 if (keyFile.has_key("Profiles", "EmbedParamsInMetadata")) {
953                     params_out_embed = keyFile.get_boolean("Profiles", "EmbedParamsInMetadata");
954                 }
955 
956                 if (keyFile.has_key("Profiles", "ParamsSidecarStripExtension")) {
957                     params_sidecar_strip_extension = keyFile.get_boolean("Profiles", "ParamsSidecarStripExtension");
958                 }
959 
960                 if (keyFile.has_key("Profiles", "CustomProfileBuilder")) {
961                     CPBPath = keyFile.get_string("Profiles", "CustomProfileBuilder");  // for backward compatibility only
962                 }
963 
964                 if (keyFile.has_key("Profiles", "CustomProfileBuilderPath")) {
965                     CPBPath = keyFile.get_string("Profiles", "CustomProfileBuilderPath");
966                 }
967 
968                 if (keyFile.has_key("Profiles", "CustomProfileBuilderKeys")) {
969                     CPBKeys = (CPBKeyType)keyFile.get_integer("Profiles", "CustomProfileBuilderKeys");
970                 }
971             }
972 
973             if (keyFile.has_group("File Browser")) {
974                 if (keyFile.has_key("File Browser", "ThumbnailSize")) {
975                     thumbSize = keyFile.get_integer("File Browser", "ThumbnailSize");
976                 }
977 
978                 if (keyFile.has_key("File Browser", "ThumbnailSizeTab")) {
979                     thumbSizeTab = keyFile.get_integer("File Browser", "ThumbnailSizeTab");
980                 }
981 
982                 if (keyFile.has_key("File Browser", "ThumbnailSizeQueue")) {
983                     thumbSizeQueue = keyFile.get_integer("File Browser", "ThumbnailSizeQueue");
984                 }
985 
986                 if (keyFile.has_key("File Browser", "SameThumbSize")) {
987                     sameThumbSize = keyFile.get_integer("File Browser", "SameThumbSize");
988                 }
989 
990                 if (keyFile.has_key("File Browser", "ThumbnailOrder")) {
991                     thumbnailOrder = ThumbnailOrder(keyFile.get_integer("File Browser", "ThumbnailOrder"));
992                 }
993 
994                 if (keyFile.has_key("File Browser", "BrowserShowsDate")) {
995                     fbShowDateTime = keyFile.get_boolean("File Browser", "BrowserShowsDate");
996                 }
997 
998                 if (keyFile.has_key("File Browser", "BrowserShowsExif")) {
999                     fbShowBasicExif = keyFile.get_boolean("File Browser", "BrowserShowsExif");
1000                 }
1001 
1002                 if (keyFile.has_key("File Browser", "BrowserShowsExpComp")) {
1003                     fbShowExpComp = keyFile.get_boolean("File Browser", "BrowserShowsExpComp");
1004                 }
1005 
1006 #ifndef WIN32
1007                 if (keyFile.has_key("File Browser", "BrowserShowsHidden")) {
1008                     fbShowHidden = keyFile.get_boolean("File Browser", "BrowserShowsHidden");
1009                 }
1010 #endif
1011 
1012                 if (keyFile.has_key("File Browser", "MaxPreviewHeight")) {
1013                     maxThumbnailHeight = keyFile.get_integer("File Browser", "MaxPreviewHeight");
1014                 }
1015 
1016                 if (keyFile.has_key("File Browser", "MaxPreviewWidth")) {
1017                     maxThumbnailWidth = keyFile.get_integer("File Browser", "MaxPreviewWidth");
1018                 }
1019 
1020                 if (keyFile.has_key("File Browser", "MaxCacheEntries")) {
1021                     maxCacheEntries = keyFile.get_integer("File Browser", "MaxCacheEntries");
1022                 }
1023 
1024                 if (keyFile.has_key("File Browser", "ParseExtensions")) {
1025                     auto l = keyFile.get_string_list("File Browser", "ParseExtensions");
1026                     if (!l.empty()) {
1027                         parseExtensions = l;
1028                     }
1029                 }
1030 
1031                 if (keyFile.has_key("File Browser", "ParseExtensionsEnabled")) {
1032                     auto l = keyFile.get_integer_list("File Browser", "ParseExtensionsEnabled");
1033                     if (!l.empty()) {
1034                         parseExtensionsEnabled = l;
1035                     }
1036                 }
1037 
1038                 if (keyFile.has_key("File Browser", "ThumbnailInterpolation")) {
1039                     thumbInterp = keyFile.get_integer("File Browser", "ThumbnailInterpolation");
1040                 }
1041 
1042                 if (keyFile.has_key("File Browser", "FavoriteDirs")) {
1043                     favoriteDirs = keyFile.get_string_list("File Browser", "FavoriteDirs");
1044                 }
1045 
1046                 if (keyFile.has_key("File Browser", "ThumbnailZoomRatios")) {
1047                     thumbnailZoomRatios = keyFile.get_double_list("File Browser", "ThumbnailZoomRatios");
1048                 }
1049 
1050                 if (keyFile.has_key("File Browser", "OverlayedFileNames")) {
1051                     overlayedFileNames = keyFile.get_boolean("File Browser", "OverlayedFileNames");
1052                 }
1053 
1054                 if (keyFile.has_key("File Browser", "FilmStripOverlayedFileNames")) {
1055                     filmStripOverlayedFileNames = keyFile.get_boolean("File Browser", "FilmStripOverlayedFileNames");
1056                 }
1057 
1058                 if (keyFile.has_key("File Browser", "ShowFileNames")) {
1059                     showFileNames = keyFile.get_boolean("File Browser", "ShowFileNames");
1060                 }
1061 
1062                 if (keyFile.has_key("File Browser", "FilmStripShowFileNames")) {
1063                     filmStripShowFileNames = keyFile.get_boolean("File Browser", "FilmStripShowFileNames");
1064                 }
1065 
1066                 if (keyFile.has_key("File Browser", "InternalThumbIfUntouched")) {
1067                     internalThumbIfUntouched = keyFile.get_boolean("File Browser", "InternalThumbIfUntouched");
1068                 }
1069 
1070                 if (keyFile.has_key("File Browser", "menuGroupRank")) {
1071                     menuGroupRank = keyFile.get_boolean("File Browser", "menuGroupRank");
1072                 }
1073 
1074                 if (keyFile.has_key("File Browser", "menuGroupLabel")) {
1075                     menuGroupLabel = keyFile.get_boolean("File Browser", "menuGroupLabel");
1076                 }
1077 
1078                 if (keyFile.has_key("File Browser", "menuGroupFileOperations")) {
1079                     menuGroupFileOperations = keyFile.get_boolean("File Browser", "menuGroupFileOperations");
1080                 }
1081 
1082                 if (keyFile.has_key("File Browser", "menuGroupProfileOperations")) {
1083                     menuGroupProfileOperations = keyFile.get_boolean("File Browser", "menuGroupProfileOperations");
1084                 }
1085 
1086                 if (keyFile.has_key("File Browser", "menuGroupExtProg")) {
1087                     menuGroupExtProg = keyFile.get_boolean("File Browser", "menuGroupExtProg");
1088                 }
1089 
1090                 if (keyFile.has_key("File Browser", "MaxRecentFolders")) {
1091                     maxRecentFolders = keyFile.get_integer("File Browser", "MaxRecentFolders");
1092                 }
1093 
1094                 recentFolders.reserve(maxRecentFolders + 10);  // reserve some more than maxRecentFolders, because at runtime it stores more than that
1095 
1096                 if (keyFile.has_key("File Browser", "RecentFolders")) {
1097                     recentFolders = keyFile.get_string_list("File Browser", "RecentFolders");
1098                 }
1099 
1100                 if (keyFile.has_key("File Browser", "ThumbnailRatingMode")) {
1101                     auto s = keyFile.get_string("File Browser", "ThumbnailRatingMode");
1102                     if (s == "procparams") {
1103                         thumbnail_rating_mode = ThumbnailRatingMode::PROCPARAMS;
1104                     } else if (s == "xmp") {
1105                         thumbnail_rating_mode = ThumbnailRatingMode::XMP;
1106                     } else {
1107                         thumbnail_rating_mode = ThumbnailRatingMode::PROCPARAMS;
1108                     }
1109                 }
1110             }
1111 
1112             if (keyFile.has_group("Clipping Indication")) {
1113                 if (keyFile.has_key("Clipping Indication", "HighlightThreshold")) {
1114                     highlightThreshold = keyFile.get_integer("Clipping Indication", "HighlightThreshold");
1115                 }
1116 
1117                 if (keyFile.has_key("Clipping Indication", "ShadowThreshold")) {
1118                     shadowThreshold = keyFile.get_integer("Clipping Indication", "ShadowThreshold");
1119                 }
1120             }
1121 
1122             if (keyFile.has_group("Performance")) {
1123                 if (keyFile.has_key("Performance", "RgbDenoiseThreadLimit")) {
1124                     rgbDenoiseThreadLimit = keyFile.get_integer("Performance", "RgbDenoiseThreadLimit");
1125                 }
1126 
1127                 if (keyFile.has_key("Performance", "ClutCacheSize")) {
1128                     clutCacheSize = keyFile.get_integer("Performance", "ClutCacheSize");
1129                 }
1130 
1131                 if (keyFile.has_key("Performance", "MaxInspectorBuffers")) {
1132                     maxInspectorBuffers = keyFile.get_integer("Performance", "MaxInspectorBuffers");
1133                 }
1134 
1135                 if (keyFile.has_key("Performance", "InspectorDelay")) {
1136                     inspectorDelay = keyFile.get_integer("Performance", "InspectorDelay");
1137                 }
1138 
1139                 if (keyFile.has_key("Performance", "PreviewDemosaicFromSidecar")) {
1140                     prevdemo = (prevdemo_t)keyFile.get_integer("Performance", "PreviewDemosaicFromSidecar");
1141                 }
1142 
1143                 if (keyFile.has_key("Performance", "SerializeTiffRead")) {
1144                     serializeTiffRead = keyFile.get_boolean("Performance", "SerializeTiffRead");
1145                 }
1146 
1147                 if (keyFile.has_key("Performance", "DenoiseZoomedOut")) {
1148                     denoiseZoomedOut = keyFile.get_boolean("Performance", "DenoiseZoomedOut");
1149                 }
1150 
1151                 if (keyFile.has_key("Performance", "WBPreviewMode")) {
1152                     int v = keyFile.get_integer("Performance", "WBPreviewMode");
1153                     wb_preview_mode = WBPreviewMode(rtengine::LIM(v, int(WB_AFTER), int(WB_BEFORE_HIGH_DETAIL)));
1154                 }
1155 
1156                 if (keyFile.has_key("Performance", "ThumbUpdateThreadLimit")) {
1157                     thumb_update_thread_limit = keyFile.get_integer("Performance", "ThumbUpdateThreadLimit");
1158                 }
1159 
1160                 if (keyFile.has_key("Performance", "ThumbDelayUpdate")) {
1161                     thumb_delay_update = keyFile.get_boolean("Performance", "ThumbDelayUpdate");
1162                 }
1163 
1164                 if (keyFile.has_key("Performance", "ThumbLazyCaching")) {
1165                     thumb_lazy_caching = keyFile.get_boolean("Performance", "ThumbLazyCaching");
1166                 }
1167             }
1168 
1169             if (keyFile.has_group("Inspector")) {
1170                 if (keyFile.has_key("Inspector", "Mode")) {
1171                     rtSettings.thumbnail_inspector_mode = static_cast<rtengine::Settings::ThumbnailInspectorMode>(keyFile.get_integer("Inspector", "Mode"));
1172                 }
1173 
1174                 if (keyFile.has_key("Inspector", "RawCurve")) {
1175                     rtSettings.thumbnail_inspector_raw_curve = static_cast<rtengine::Settings::ThumbnailInspectorRawCurve>(keyFile.get_integer("Inspector", "RawCurve"));
1176                 }
1177 
1178                 if (keyFile.has_key("Inspector", "ZoomFit")) {
1179                     thumbnail_inspector_zoom_fit = keyFile.get_boolean("Inspector", "ZoomFit");
1180                 }
1181 
1182                 if (keyFile.has_key("Inspector", "ShowInfo")) {
1183                     thumbnail_inspector_show_info = keyFile.get_boolean("Inspector", "ShowInfo");
1184                 }
1185 
1186                 if (keyFile.has_key("Inspector", "ShowHistogram")) {
1187                     thumbnail_inspector_show_histogram = keyFile.get_boolean("Inspector", "ShowHistogram");
1188                 }
1189 
1190                 if (keyFile.has_key("Inspector", "EnableCMS")) {
1191                     thumbnail_inspector_enable_cms = keyFile.get_boolean("Inspector", "EnableCMS");
1192                 }
1193 
1194                 if (keyFile.has_key("Inspector", "BrowserWidth")) {
1195                     browser_width_for_inspector = keyFile.get_integer("Inspector", "BrowserWidth");
1196                 }
1197 
1198                 if (keyFile.has_key("Inspector", "ThumbnailHover")) {
1199                     thumbnail_inspector_hover = keyFile.get_boolean("Inspector", "ThumbnailHover");
1200                 }
1201             }
1202 
1203             if (keyFile.has_group("GUI")) {
1204                 if (keyFile.has_key("GUI", "Favorites")) {
1205                     favorites = keyFile.get_string_list("GUI", "Favorites");
1206                 }
1207 
1208                 if (keyFile.has_key("GUI", "WindowWidth")) {
1209                     windowWidth = keyFile.get_integer("GUI", "WindowWidth");
1210                 }
1211 
1212                 if (keyFile.has_key("GUI", "WindowHeight")) {
1213                     windowHeight = keyFile.get_integer("GUI", "WindowHeight");
1214                 }
1215 
1216                 if (keyFile.has_key("GUI", "WindowX")) {
1217                     windowX = keyFile.get_integer("GUI", "WindowX");
1218                 }
1219 
1220                 if (keyFile.has_key("GUI", "WindowY")) {
1221                     windowY = keyFile.get_integer("GUI", "WindowY");
1222                 }
1223 
1224                 if (keyFile.has_key("GUI", "WindowMonitor")) {
1225                     windowMonitor = keyFile.get_integer("GUI", "WindowMonitor");
1226                 }
1227 
1228                 if (keyFile.has_key("GUI", "MeowMonitor")) {
1229                     meowMonitor = keyFile.get_integer("GUI", "MeowMonitor");
1230                 }
1231 
1232                 if (keyFile.has_key("GUI", "MeowFullScreen")) {
1233                     meowFullScreen = keyFile.get_boolean("GUI", "MeowFullScreen");
1234                 }
1235 
1236                 if (keyFile.has_key("GUI", "MeowMaximized")) {
1237                     meowMaximized = keyFile.get_boolean("GUI", "MeowMaximized");
1238                 }
1239 
1240                 if (keyFile.has_key("GUI", "MeowWidth")) {
1241                     meowWidth = keyFile.get_integer("GUI", "MeowWidth");
1242                 }
1243 
1244                 if (keyFile.has_key("GUI", "MeowHeight")) {
1245                     meowHeight = keyFile.get_integer("GUI", "MeowHeight");
1246                 }
1247 
1248                 if (keyFile.has_key("GUI", "MeowX")) {
1249                     meowX = keyFile.get_integer("GUI", "MeowX");
1250                 }
1251 
1252                 if (keyFile.has_key("GUI", "MeowY")) {
1253                     meowY = keyFile.get_integer("GUI", "MeowY");
1254                 }
1255 
1256                 if (keyFile.has_key("GUI", "WindowMaximized")) {
1257                     windowMaximized = keyFile.get_boolean("GUI", "WindowMaximized");
1258                 }
1259 
1260                 if (keyFile.has_key("GUI", "DetailWindowWidth")) {
1261                     detailWindowWidth = keyFile.get_integer("GUI", "DetailWindowWidth");
1262                 }
1263 
1264                 if (keyFile.has_key("GUI", "DetailWindowHeight")) {
1265                     detailWindowHeight = keyFile.get_integer("GUI", "DetailWindowHeight");
1266                 }
1267 
1268                 if (keyFile.has_key("GUI", "DirBrowserWidth")) {
1269                     dirBrowserWidth = keyFile.get_integer("GUI", "DirBrowserWidth");
1270                 }
1271 
1272                 if (keyFile.has_key("GUI", "DirBrowserHeight")) {
1273                     dirBrowserHeight = keyFile.get_integer("GUI", "DirBrowserHeight");
1274                 }
1275 
1276                 if (keyFile.has_key("GUI", "SortType")) {
1277                     dirBrowserSortType = static_cast<Gtk::SortType>(keyFile.get_integer("GUI", "SortType"));
1278                 }
1279 
1280                 if (keyFile.has_key("GUI", "PreferencesWidth")) {
1281                     preferencesWidth = keyFile.get_integer("GUI", "PreferencesWidth");
1282                 }
1283 
1284                 if (keyFile.has_key("GUI", "PreferencesHeight")) {
1285                     preferencesHeight = keyFile.get_integer("GUI", "PreferencesHeight");
1286                 }
1287 
1288                 if (keyFile.has_key("GUI", "SaveAsDialogWidth")) {
1289                     saveAsDialogWidth = keyFile.get_integer("GUI", "SaveAsDialogWidth");
1290                 }
1291 
1292                 if (keyFile.has_key("GUI", "SaveAsDialogHeight")) {
1293                     saveAsDialogHeight = keyFile.get_integer("GUI", "SaveAsDialogHeight");
1294                 }
1295 
1296                 if (keyFile.has_key("GUI", "ToolPanelWidth")) {
1297                     toolPanelWidth = keyFile.get_integer("GUI", "ToolPanelWidth");
1298                 }
1299 
1300                 if (keyFile.has_key("GUI", "BrowserToolPanelWidth")) {
1301                     browserToolPanelWidth = keyFile.get_integer("GUI", "BrowserToolPanelWidth");
1302                 }
1303 
1304                 if (keyFile.has_key("GUI", "BrowserToolPanelHeight")) {
1305                     browserToolPanelHeight = keyFile.get_integer("GUI", "BrowserToolPanelHeight");
1306                 }
1307 
1308                 if (keyFile.has_key("GUI", "BrowserToolPanelOpened")) {
1309                     browserToolPanelOpened = keyFile.get_boolean("GUI", "BrowserToolPanelOpened");
1310                 }
1311 
1312                 if (keyFile.has_key("GUI", "BrowserDirPanelOpened")) {
1313                     browserDirPanelOpened = keyFile.get_boolean("GUI", "BrowserDirPanelOpened");
1314                 }
1315 
1316                 if (keyFile.has_key("GUI", "EditorFilmStripOpened")) {
1317                     editorFilmStripOpened = keyFile.get_boolean("GUI", "EditorFilmStripOpened");
1318                 }
1319 
1320                 if (keyFile.has_key("GUI", "InspectorDirPanelOpened")) {
1321                     inspectorDirPanelOpened = keyFile.get_boolean("GUI", "InspectorDirPanelOpened");
1322                 }
1323 
1324                 if (keyFile.has_key("GUI", "HistoryPanelWidth")) {
1325                     historyPanelWidth = keyFile.get_integer("GUI", "HistoryPanelWidth");
1326                 }
1327 
1328                 if (keyFile.has_key("GUI", "FontFamily")) {
1329                     fontFamily = keyFile.get_string("GUI", "FontFamily");
1330                 }
1331 
1332                 if (keyFile.has_key("GUI", "FontSize")) {
1333                     fontSize = keyFile.get_integer("GUI", "FontSize");
1334                 }
1335 
1336                 if (keyFile.has_key("GUI", "CPFontFamily")) {
1337                     CPFontFamily = keyFile.get_string("GUI", "CPFontFamily");
1338                 }
1339 
1340                 if (keyFile.has_key("GUI", "CPFontSize")) {
1341                     CPFontSize = keyFile.get_integer("GUI", "CPFontSize");
1342                 }
1343 
1344                 if (keyFile.has_key("GUI", "PseudoHiDPISupport")) {
1345                 	pseudoHiDPISupport = keyFile.get_boolean("GUI", "PseudoHiDPISupport");
1346                 }
1347 
1348                 if (keyFile.has_key("GUI", "LastPreviewScale")) {
1349                     lastScale = keyFile.get_integer("GUI", "LastPreviewScale");
1350                 }
1351 
1352                 if (keyFile.has_key("GUI", "PanAccelFactor")) {
1353                     panAccelFactor = keyFile.get_integer("GUI", "PanAccelFactor");
1354                 }
1355 
1356                 if (keyFile.has_key("GUI", "RememberZoomAndPan")) {
1357                     rememberZoomAndPan = keyFile.get_boolean("GUI", "RememberZoomAndPan");
1358                 }
1359 
1360                 if (keyFile.has_key("GUI", "ShowHistory")) {
1361                     showHistory = keyFile.get_boolean("GUI", "ShowHistory");
1362                 }
1363 
1364                 if (keyFile.has_key("GUI", "ShowInfo")) {
1365                     showInfo = keyFile.get_boolean("GUI", "ShowInfo");
1366                 }
1367 
1368                 if (keyFile.has_key("GUI", "MainNBVertical")) {
1369                     mainNBVertical = keyFile.get_boolean("GUI", "MainNBVertical");
1370                 }
1371 
1372                 if (keyFile.has_key("GUI", "ShowClippedHighlights")) {
1373                     showClippedHighlights = keyFile.get_boolean("GUI", "ShowClippedHighlights");
1374                 }
1375 
1376                 if (keyFile.has_key("GUI", "ShowClippedShadows")) {
1377                     showClippedShadows = keyFile.get_boolean("GUI", "ShowClippedShadows");
1378                 }
1379 
1380                 if (keyFile.has_key("GUI", "FrameColor")) {
1381                     bgcolor = rtengine::LIM(keyFile.get_integer("GUI", "FrameColor"), 1, 3);
1382                 }
1383 
1384                 if (keyFile.has_key("GUI", "ProcessingQueueEnbled")) {
1385                     procQueueEnabled = keyFile.get_boolean("GUI", "ProcessingQueueEnbled");
1386                 }
1387 
1388                 if (keyFile.has_key("GUI", "ToolPanelsExpanded")) {
1389                     tpOpen = keyFile.get_integer_list("GUI", "ToolPanelsExpanded");
1390                 }
1391 
1392                 if (keyFile.has_key("GUI", "ToolPanelsExpandedAutoSave")) {
1393                     autoSaveTpOpen = keyFile.get_boolean("GUI", "ToolPanelsExpandedAutoSave");
1394                 }
1395 
1396                 if (keyFile.has_key("GUI", "MultiDisplayMode")) {
1397                     multiDisplayMode = keyFile.get_integer("GUI", "MultiDisplayMode");
1398                 }
1399 
1400                 //if (keyFile.has_key ("GUI", "CurvePanelsExpanded")) crvOpen = keyFile.get_integer_list ("GUI", "CurvePanelsExpanded");
1401                 if (keyFile.has_key("GUI", "CutOverlayBrush")) {
1402                     cutOverlayBrush = keyFile.get_double_list("GUI", "CutOverlayBrush");
1403                 }
1404 
1405                 if (keyFile.has_key("GUI", "NavGuideBrush")) {
1406                     navGuideBrush = keyFile.get_double_list("GUI", "NavGuideBrush");
1407                 }
1408 
1409                 if (keyFile.has_key("GUI", "HistogramPosition")) {
1410                     histogramPosition = keyFile.get_integer("GUI", "HistogramPosition");
1411                 }
1412 
1413                 if (keyFile.has_key("GUI", "HistogramRed")) {
1414                     histogramRed = keyFile.get_boolean("GUI", "HistogramRed");
1415                 }
1416 
1417                 if (keyFile.has_key("GUI", "HistogramGreen")) {
1418                     histogramGreen = keyFile.get_boolean("GUI", "HistogramGreen");
1419                 }
1420 
1421                 if (keyFile.has_key("GUI", "HistogramBlue")) {
1422                     histogramBlue = keyFile.get_boolean("GUI", "HistogramBlue");
1423                 }
1424 
1425                 if (keyFile.has_key("GUI", "HistogramLuma")) {
1426                     histogramLuma = keyFile.get_boolean("GUI", "HistogramLuma");
1427                 }
1428 
1429                 if (keyFile.has_key("GUI", "HistogramChroma")) {
1430                     histogramChroma = keyFile.get_boolean("GUI", "HistogramChroma");
1431                 }
1432 
1433                 if (keyFile.has_key("GUI", "HistogramRAW")) {
1434                     //histogramRAW = keyFile.get_boolean("GUI", "HistogramRAW");
1435                     if (keyFile.get_boolean("GUI", "HistogramRAW")) {
1436                         histogramScopeType = ScopeType::HISTOGRAM_RAW;
1437                     }
1438                 }
1439 
1440                 if (keyFile.has_key("GUI", "HistogramBar")) {
1441                     histogramBar = keyFile.get_boolean("GUI", "HistogramBar");
1442                 }
1443 
1444                 if (keyFile.has_key ("GUI", "HistogramHeight")) {
1445                     histogramHeight = keyFile.get_integer ("GUI", "HistogramHeight");
1446                 }
1447 
1448                 if (keyFile.has_key ("GUI", "HistogramDrawMode")) {
1449                     histogramDrawMode = keyFile.get_integer ("GUI", "HistogramDrawMode");
1450                 }
1451 
1452                 if (keyFile.has_key("GUI", "HistogramScalingFactor")) {
1453                     histogram_scaling_factor = keyFile.get_double("GUI", "HistogramScalingFactor");
1454                 }
1455 
1456                 if (keyFile.has_key("GUI", "NavigatorRGBUnit")) {
1457                     navRGBUnit = (NavigatorUnit)keyFile.get_integer("GUI", "NavigatorRGBUnit");
1458                 }
1459 
1460                 if (keyFile.has_key("GUI", "NavigatorLCHUnit")) {
1461                     navLCHUnit = (NavigatorUnit)keyFile.get_integer("GUI", "NavigatorLCHUnit");
1462                 }
1463 
1464                 if (keyFile.has_key("GUI", "HistogramScopeType")) {
1465                     histogramScopeType = static_cast<ScopeType>(keyFile.get_integer("GUI", "HistogramScopeType"));
1466                 }
1467 
1468                 if (keyFile.has_key("GUI", "HistogramShowOptionButtons")) {
1469                     histogramShowOptionButtons = keyFile.get_boolean("GUI", "HistogramShowOptionButtons");
1470                 }
1471 
1472                 if (keyFile.has_key("GUI", "HistogramTraceBrightness")) {
1473                     histogramTraceBrightness = keyFile.get_double("GUI", "HistogramTraceBrightness");
1474                 }
1475 
1476                 if (keyFile.has_key("GUI", "ShowFilmStripToolBar")) {
1477                     showFilmStripToolBar = keyFile.get_boolean("GUI", "ShowFilmStripToolBar");
1478                 }
1479 
1480                 if (keyFile.has_key("GUI", "FileBrowserToolbarSingleRow")) {
1481                     FileBrowserToolbarSingleRow = keyFile.get_boolean("GUI", "FileBrowserToolbarSingleRow");
1482                 }
1483 
1484                 if (keyFile.has_key("GUI", "HideTPVScrollbar")) {
1485                     hideTPVScrollbar = keyFile.get_boolean("GUI", "HideTPVScrollbar");
1486                 }
1487 
1488                 if (keyFile.has_key("GUI", "HistogramWorking")) {
1489                     rtSettings.HistogramWorking = keyFile.get_boolean("GUI", "HistogramWorking");
1490                 }
1491 
1492                 if (keyFile.has_key("GUI", "CurveBBoxPosition")) {
1493                     curvebboxpos = keyFile.get_integer("GUI", "CurveBBoxPosition");
1494                 }
1495 
1496                 if (keyFile.has_key("GUI", "ToolPanelsDisable")) {
1497                     toolpanels_disable = keyFile.get_boolean("GUI", "ToolPanelsDisable");
1498                 }
1499 
1500                 if (keyFile.has_key("GUI", "AdjusterForceLinear")) {
1501                     adjuster_force_linear = keyFile.get_boolean("GUI", "AdjusterForceLinear");
1502                 }
1503             }
1504 
1505             if (keyFile.has_group("Crop Settings")) {
1506                 if (keyFile.has_key("Crop Settings", "PPI")) {
1507                     cropPPI = keyFile.get_integer("Crop Settings", "PPI");
1508                 }
1509             }
1510 
1511             if (keyFile.has_group("Color Management")) {
1512                 if (keyFile.has_key("Color Management", "ICCDirectory")) {
1513                     rtSettings.iccDirectory = keyFile.get_string("Color Management", "ICCDirectory");
1514                 }
1515                 if (keyFile.has_key("Color Management", "MonitorICCDirectory")) {
1516                     rtSettings.monitorIccDirectory = keyFile.get_string("Color Management", "MonitorICCDirectory");
1517                 } else {
1518                     rtSettings.monitorIccDirectory = rtSettings.iccDirectory;
1519                 }
1520 
1521                 if (keyFile.has_key("Color Management", "PrinterIntent")) {
1522                     rtSettings.printerIntent = static_cast<rtengine::RenderingIntent>(keyFile.get_integer("Color Management", "PrinterIntent"));
1523                 }
1524 
1525                 if (keyFile.has_key("Color Management", "PrinterBPC")) {
1526                     rtSettings.printerBPC = keyFile.get_boolean("Color Management", "PrinterBPC");
1527                 }
1528 
1529                 if (keyFile.has_key("Color Management", "PrinterProfile")) {
1530                     rtSettings.printerProfile = keyFile.get_string("Color Management", "PrinterProfile");
1531                 }
1532 
1533                 if (keyFile.has_key("Color Management", "MonitorProfile")) {
1534                     rtSettings.monitorProfile = keyFile.get_string("Color Management", "MonitorProfile");
1535                 }
1536 
1537                 if (keyFile.has_key("Color Management", "AutoMonitorProfile")) {
1538                     rtSettings.autoMonitorProfile = keyFile.get_boolean("Color Management", "AutoMonitorProfile");
1539                 }
1540 
1541                 if (keyFile.has_key("Color Management", "Intent")) {
1542                     rtSettings.monitorIntent = static_cast<rtengine::RenderingIntent>(keyFile.get_integer("Color Management", "Intent"));
1543                 }
1544 
1545                 if (keyFile.has_key("Color Management", "MonitorBPC")) {
1546                     rtSettings.monitorBPC = keyFile.get_boolean("Color Management", "MonitorBPC");
1547                 }
1548 
1549                 if (keyFile.has_key("Color Management", "WhiteBalanceSpotSize")) {
1550                     whiteBalanceSpotSize = keyFile.get_integer("Color Management", "WhiteBalanceSpotSize");
1551                 }
1552 
1553                 if (keyFile.has_key("Color Management", "ClutsDirectory")) {
1554                     clutsDir = keyFile.get_string("Color Management", "ClutsDirectory");
1555                 }
1556             }
1557 
1558             if (keyFile.has_group("ICC Profile Creator")) {
1559                 if (keyFile.has_key("ICC Profile Creator", "PimariesPreset")) {
1560                     ICCPC_primariesPreset = keyFile.get_string("ICC Profile Creator", "PimariesPreset");
1561                 }
1562                 if (keyFile.has_key("ICC Profile Creator", "RedPrimaryX")) {
1563                     ICCPC_redPrimaryX = keyFile.get_double("ICC Profile Creator", "RedPrimaryX");
1564                 }
1565                 if (keyFile.has_key("ICC Profile Creator", "RedPrimaryY")) {
1566                     ICCPC_redPrimaryY = keyFile.get_double("ICC Profile Creator", "RedPrimaryY");
1567                 }
1568                 if (keyFile.has_key("ICC Profile Creator", "GreenPrimaryX")) {
1569                     ICCPC_greenPrimaryX = keyFile.get_double("ICC Profile Creator", "GreenPrimaryX");
1570                 }
1571                 if (keyFile.has_key("ICC Profile Creator", "GreenPrimaryY")) {
1572                     ICCPC_greenPrimaryY = keyFile.get_double("ICC Profile Creator", "GreenPrimaryY");
1573                 }
1574                 if (keyFile.has_key("ICC Profile Creator", "BluePrimaryX")) {
1575                     ICCPC_bluePrimaryX = keyFile.get_double("ICC Profile Creator", "BluePrimaryX");
1576                 }
1577                 if (keyFile.has_key("ICC Profile Creator", "BluePrimaryY")) {
1578                     ICCPC_bluePrimaryY = keyFile.get_double("ICC Profile Creator", "BluePrimaryY");
1579                 }
1580                 if (keyFile.has_key("ICC Profile Creator", "GammaPreset")) {
1581                     ICCPC_gammaPreset = keyFile.get_string("ICC Profile Creator", "GammaPreset");
1582                 }
1583                 if (keyFile.has_key("ICC Profile Creator", "Gamma")) {
1584                     ICCPC_gamma = keyFile.get_double("ICC Profile Creator", "Gamma");
1585                 }
1586                 if (keyFile.has_key("ICC Profile Creator", "Slope")) {
1587                     ICCPC_slope = keyFile.get_double("ICC Profile Creator", "Slope");
1588                 }
1589                 if (keyFile.has_key("ICC Profile Creator", "ProfileVersion")) {
1590                     ICCPC_profileVersion = keyFile.get_string("ICC Profile Creator", "ProfileVersion");
1591                 }
1592                 if (keyFile.has_key("ICC Profile Creator", "Illuminant")) {
1593                     ICCPC_illuminant = keyFile.get_string("ICC Profile Creator", "Illuminant");
1594                 }
1595                 if (keyFile.has_key("ICC Profile Creator", "Description")) {
1596                     ICCPC_description = keyFile.get_string("ICC Profile Creator", "Description");
1597                 }
1598                 if (keyFile.has_key("ICC Profile Creator", "Copyright")) {
1599                     ICCPC_copyright = keyFile.get_string("ICC Profile Creator", "Copyright");
1600                 }
1601                 if (keyFile.has_key("ICC Profile Creator", "AppendParamsToDesc")) {
1602                     ICCPC_appendParamsToDesc = keyFile.get_boolean("ICC Profile Creator", "AppendParamsToDesc");
1603                 }
1604             }
1605 
1606             if (keyFile.has_group("Sounds")) {
1607                 if (keyFile.has_key("Sounds", "Enable")) {
1608                     sndEnable = keyFile.get_boolean("Sounds", "Enable");
1609                 }
1610 
1611                 if (keyFile.has_key("Sounds", "BatchQueueDone")) {
1612                     sndBatchQueueDone = keyFile.get_string("Sounds", "BatchQueueDone");
1613                 }
1614 
1615                 if (keyFile.has_key("Sounds", "LngEditProcDone")) {
1616                     sndLngEditProcDone = keyFile.get_string("Sounds", "LngEditProcDone");
1617                 }
1618 
1619                 if (keyFile.has_key("Sounds", "LngEditProcDoneSecs")) {
1620                     sndLngEditProcDoneSecs = keyFile.get_double("Sounds", "LngEditProcDoneSecs");
1621                 }
1622             }
1623 
1624             if (keyFile.has_group("Fast Export")) {
1625                 if (keyFile.has_key("Fast Export", "fastexport_bypass_sharpening")) {
1626                     fastexport_bypass_sharpening = keyFile.get_boolean("Fast Export", "fastexport_bypass_sharpening");
1627                 }
1628 
1629                 if (keyFile.has_key("Fast Export", "fastexport_bypass_defringe")) {
1630                     fastexport_bypass_defringe = keyFile.get_boolean("Fast Export", "fastexport_bypass_defringe");
1631                 }
1632 
1633                 if (keyFile.has_key("Fast Export", "fastexport_bypass_dirpyrDenoise")) {
1634                     fastexport_bypass_dirpyrDenoise = keyFile.get_boolean("Fast Export", "fastexport_bypass_dirpyrDenoise");
1635                 }
1636 
1637                 if (keyFile.has_key("Fast Export", "fastexport_bypass_localContrast")) {
1638                     fastexport_bypass_localContrast = keyFile.get_boolean("Fast Export", "fastexport_bypass_localContrast");
1639                 }
1640 
1641                 if (keyFile.has_key("Fast Export", "fastexport_raw_dmethod")) {
1642                     fastexport_raw_bayer_method = keyFile.get_string("Fast Export", "fastexport_raw_dmethod");
1643                 }
1644 
1645                 if (keyFile.has_key("Fast Export", "fastexport_raw_bayer_method")) {
1646                     fastexport_raw_bayer_method = keyFile.get_string("Fast Export", "fastexport_raw_bayer_method");
1647                 }
1648 
1649 //if (keyFile.has_key ("Fast Export", "fastexport_bypass_raw_bayer_all_enhance" )) fastexport_bypass_raw_bayer_all_enhance = keyFile.get_boolean ("Fast Export", "fastexport_bypass_raw_all_enhance" );
1650                 if (keyFile.has_key("Fast Export", "fastexport_bypass_raw_dcb_iterations")) {
1651                     fastexport_bypass_raw_bayer_dcb_iterations = keyFile.get_boolean("Fast Export", "fastexport_bypass_raw_dcb_iterations");
1652                 }
1653 
1654                 if (keyFile.has_key("Fast Export", "fastexport_bypass_raw_bayer_dcb_iterations")) {
1655                     fastexport_bypass_raw_bayer_dcb_iterations = keyFile.get_boolean("Fast Export", "fastexport_bypass_raw_bayer_dcb_iterations");
1656                 }
1657 
1658                 if (keyFile.has_key("Fast Export", "fastexport_bypass_raw_dcb_enhance")) {
1659                     fastexport_bypass_raw_bayer_dcb_enhance = keyFile.get_boolean("Fast Export", "fastexport_bypass_raw_dcb_enhance");
1660                 }
1661 
1662                 if (keyFile.has_key("Fast Export", "fastexport_bypass_raw_bayer_dcb_enhance")) {
1663                     fastexport_bypass_raw_bayer_dcb_enhance = keyFile.get_boolean("Fast Export", "fastexport_bypass_raw_bayer_dcb_enhance");
1664                 }
1665 
1666                 if (keyFile.has_key("Fast Export", "fastexport_bypass_raw_lmmse_iterations")) {
1667                     fastexport_bypass_raw_bayer_lmmse_iterations = keyFile.get_boolean("Fast Export", "fastexport_bypass_raw_lmmse_iterations");
1668                 }
1669 
1670                 if (keyFile.has_key("Fast Export", "fastexport_bypass_raw_bayer_lmmse_iterations")) {
1671                     fastexport_bypass_raw_bayer_lmmse_iterations = keyFile.get_boolean("Fast Export", "fastexport_bypass_raw_bayer_lmmse_iterations");
1672                 }
1673 
1674                 if (keyFile.has_key("Fast Export", "fastexport_bypass_raw_linenoise")) {
1675                     fastexport_bypass_raw_bayer_linenoise = keyFile.get_boolean("Fast Export", "fastexport_bypass_raw_linenoise");
1676                 }
1677 
1678                 if (keyFile.has_key("Fast Export", "fastexport_bypass_raw_bayer_linenoise")) {
1679                     fastexport_bypass_raw_bayer_linenoise = keyFile.get_boolean("Fast Export", "fastexport_bypass_raw_bayer_linenoise");
1680                 }
1681 
1682                 if (keyFile.has_key("Fast Export", "fastexport_bypass_raw_greenthresh")) {
1683                     fastexport_bypass_raw_bayer_greenthresh = keyFile.get_boolean("Fast Export", "fastexport_bypass_raw_greenthresh");
1684                 }
1685 
1686                 if (keyFile.has_key("Fast Export", "fastexport_bypass_raw_bayer_greenthresh")) {
1687                     fastexport_bypass_raw_bayer_greenthresh = keyFile.get_boolean("Fast Export", "fastexport_bypass_raw_bayer_greenthresh");
1688                 }
1689 
1690                 if (keyFile.has_key("Fast Export", "fastexport_raw_xtrans_method")) {
1691                     fastexport_raw_xtrans_method = keyFile.get_string("Fast Export", "fastexport_raw_xtrans_method");
1692                 }
1693 
1694                 if (keyFile.has_key("Fast Export", "fastexport_bypass_raw_ccSteps")) {
1695                     fastexport_bypass_raw_ccSteps = keyFile.get_boolean("Fast Export", "fastexport_bypass_raw_ccSteps");
1696                 }
1697 
1698                 if (keyFile.has_key("Fast Export", "fastexport_bypass_raw_ca")) {
1699                     fastexport_bypass_raw_ca = keyFile.get_boolean("Fast Export", "fastexport_bypass_raw_ca");
1700                 }
1701 
1702                 if (keyFile.has_key("Fast Export", "fastexport_bypass_raw_df")) {
1703                     fastexport_bypass_raw_df = keyFile.get_boolean("Fast Export", "fastexport_bypass_raw_df");
1704                 }
1705 
1706                 if (keyFile.has_key("Fast Export", "fastexport_bypass_raw_ff")) {
1707                     fastexport_bypass_raw_ff = keyFile.get_boolean("Fast Export", "fastexport_bypass_raw_ff");
1708                 }
1709 
1710                 if (keyFile.has_key("Fast Export", "fastexport_icm_input")) {
1711                     fastexport_icm_input_profile = keyFile.get_string("Fast Export", "fastexport_icm_input");
1712                 }
1713 
1714                 if (keyFile.has_key("Fast Export", "fastexport_icm_working")) {
1715                     fastexport_icm_working_profile = keyFile.get_string("Fast Export", "fastexport_icm_working");
1716                 }
1717 
1718                 if (keyFile.has_key("Fast Export", "fastexport_icm_output")) {
1719                     fastexport_icm_output_profile = keyFile.get_string("Fast Export", "fastexport_icm_output");
1720                 }
1721 
1722                 if (keyFile.has_key("Fast Export", "fastexport_icm_output_intent")) {
1723                     fastexport_icm_outputIntent = static_cast<rtengine::RenderingIntent>(keyFile.get_integer("Fast Export", "fastexport_icm_output_intent"));
1724                 }
1725 
1726                 if (keyFile.has_key("Fast Export", "fastexport_icm_output_bpc")) {
1727                     fastexport_icm_outputBPC = keyFile.get_boolean("Fast Export", "fastexport_icm_output_bpc");
1728                 }
1729 
1730                 if (keyFile.has_key("Fast Export", "fastexport_resize_enabled")) {
1731                     fastexport_resize_enabled = keyFile.get_boolean("Fast Export", "fastexport_resize_enabled");
1732                 }
1733 
1734                 if (keyFile.has_key("Fast Export", "fastexport_resize_scale")) {
1735                     fastexport_resize_scale = keyFile.get_double("Fast Export", "fastexport_resize_scale");
1736                 }
1737 
1738                 if (keyFile.has_key("Fast Export", "fastexport_resize_appliesTo")) {
1739                     fastexport_resize_appliesTo = keyFile.get_string("Fast Export", "fastexport_resize_appliesTo");
1740                 }
1741 
1742                 if (keyFile.has_key("Fast Export", "fastexport_resize_dataspec")) {
1743                     fastexport_resize_dataspec = keyFile.get_integer("Fast Export", "fastexport_resize_dataspec");
1744                 }
1745 
1746                 if (keyFile.has_key("Fast Export", "fastexport_resize_width")) {
1747                     fastexport_resize_width = keyFile.get_integer("Fast Export", "fastexport_resize_width");
1748                 }
1749 
1750                 if (keyFile.has_key("Fast Export", "fastexport_resize_height")) {
1751                     fastexport_resize_height = keyFile.get_integer("Fast Export", "fastexport_resize_height");
1752                 }
1753 
1754                 if (keyFile.has_key("Fast Export", "fastexport_use_fast_pipeline")) {
1755                     fastexport_use_fast_pipeline = keyFile.get_integer("Fast Export", "fastexport_use_fast_pipeline");
1756                 }
1757             }
1758 
1759             if (keyFile.has_group("Dialogs")) {
1760                 safeDirGet(keyFile, "Dialogs", "LastIccDir", lastIccDir);
1761                 safeDirGet(keyFile, "Dialogs", "LastDarkframeDir", lastDarkframeDir);
1762                 safeDirGet(keyFile, "Dialogs", "LastFlatfieldDir", lastFlatfieldDir);
1763                 safeDirGet(keyFile, "Dialogs", "LastRgbCurvesDir", lastRgbCurvesDir);
1764                 safeDirGet(keyFile, "Dialogs", "LastLabCurvesDir", lastLabCurvesDir);
1765                 safeDirGet(keyFile, "Dialogs", "LastPFCurvesDir", lastPFCurvesDir);
1766                 safeDirGet(keyFile, "Dialogs", "LastHsvCurvesDir", lastHsvCurvesDir);
1767 
1768                 safeDirGet(keyFile, "Dialogs", "LastToneCurvesDir", lastToneCurvesDir);
1769                 safeDirGet(keyFile, "Dialogs", "LastProfilingReferenceDir", lastProfilingReferenceDir);
1770                 safeDirGet(keyFile, "Dialogs", "LastLensProfileDir", lastLensProfileDir);
1771                 safeDirGet(keyFile, "Dialogs", "LastICCProfCreatorDir", lastICCProfCreatorDir);
1772                 safeDirGet(keyFile, "Dialogs", "LastCopyMovePath", lastCopyMovePath);
1773 
1774                 if (keyFile.has_key("Dialogs", "GimpPluginShowInfoDialog")) {
1775                     gimpPluginShowInfoDialog = keyFile.get_boolean("Dialogs", "GimpPluginShowInfoDialog");
1776                 }
1777             }
1778 
1779             if (keyFile.has_group("Lensfun")) {
1780                 if (keyFile.has_key("Lensfun", "DBDirectory")) {
1781                     rtSettings.lensfunDbDirectory = keyFile.get_string("Lensfun", "DBDirectory");
1782                 }
1783             }
1784 
1785             if (keyFile.has_group("Metadata")) {
1786                 if (keyFile.has_key("Metadata", "XMPSidecarStyle")) {
1787                     std::string val = keyFile.get_string("Metadata", "XMPSidecarStyle");
1788                     if (val == "ext") {
1789                         rtSettings.xmp_sidecar_style = rtengine::Settings::XmpSidecarStyle::EXT;
1790                     } else {
1791                         rtSettings.xmp_sidecar_style = rtengine::Settings::XmpSidecarStyle::STD;
1792                     }
1793                 }
1794                 if (keyFile.has_key("Metadata", "XMPSynchronization")) {
1795                     std::string val = keyFile.get_string("Metadata", "XMPSynchronization");
1796                     if (val == "read") {
1797                         rtSettings.metadata_xmp_sync = rtengine::Settings::MetadataXmpSync::READ;
1798                     } else if (val == "readwrite") {
1799                         rtSettings.metadata_xmp_sync = rtengine::Settings::MetadataXmpSync::READ_WRITE;
1800                     } else {
1801                         rtSettings.metadata_xmp_sync = rtengine::Settings::MetadataXmpSync::NONE;
1802                     }
1803                 }
1804                 if (keyFile.has_key("Metadata", "ExiftoolPath")) {
1805                     rtSettings.exiftool_path = keyFile.get_string("Metadata", "ExiftoolPath");
1806                 }
1807             }
1808 
1809             if (keyFile.has_group("False Colors Map")) {
1810                 const Glib::ustring g = "False Colors Map";
1811                 falseColorsMap.clear();
1812                 for (auto key : keyFile.get_keys(g)) {
1813                     if (key.find("IRE_") == 0) {
1814                         size_t end = 0;
1815                         std::string s = key.substr(4);
1816                         int ire = std::stoi(s, &end);
1817                         if (end >= s.size()) {
1818                             falseColorsMap[ire] = keyFile.get_string(g, key);
1819                         }
1820                     }
1821                 }
1822                 if (falseColorsMap.empty() ||
1823                     falseColorsMap.rbegin()->first < 108) {
1824                     falseColorsMap[108] = "#000000";
1825                 }
1826             }
1827 
1828             if (keyFile.has_group("Renaming")) {
1829                 const char *g = "Renaming";
1830                 if (keyFile.has_key(g, "Pattern")) {
1831                     renaming.pattern = keyFile.get_string(g, "Pattern");
1832                 }
1833                 if (keyFile.has_key(g, "Sidecars")) {
1834                     renaming.sidecars = keyFile.get_string(g, "Sidecars");
1835                 }
1836                 if (keyFile.has_key(g, "NameNormalization")) {
1837                     renaming.name_norm = keyFile.get_integer(g, "NameNormalization");
1838                 }
1839                 if (keyFile.has_key(g, "ExtNormalization")) {
1840                     renaming.ext_norm = keyFile.get_integer(g, "ExtNormalization");
1841                 }
1842                 if (keyFile.has_key(g, "AllowWhitespace")) {
1843                     renaming.allow_whitespace = keyFile.get_boolean(g, "AllowWhitespace");
1844                 }
1845                 if (keyFile.has_key(g, "OnExisting")) {
1846                     renaming.on_existing = keyFile.get_integer(g, "OnExisting");
1847                 }
1848                 if (keyFile.has_key(g, "ProgressiveNumber")) {
1849                     renaming.progressive_number = keyFile.get_integer(g, "ProgressiveNumber");
1850                 }
1851             }
1852 
1853 // --------------------------------------------------------------------------------------------------------
1854 
1855             filterOutParsedExtensions();
1856 
1857             return;
1858 
1859         }
1860     } catch (Glib::Error &err) {
1861         Glib::ustring msg = Glib::ustring::compose("Options::readFromFile / Error code %1 while reading values from \"%2\":\n%3", err.code(), fname, err.what());
1862 
1863         if (options.rtSettings.verbose) {
1864             printf("%s\n", msg.c_str());
1865         }
1866 
1867         throw Error(msg);
1868     } catch (...) {
1869         Glib::ustring msg = Glib::ustring::compose("Options::readFromFile / Unknown exception while trying to load \"%1\"!", fname);
1870 
1871         if (options.rtSettings.verbose) {
1872             printf("%s\n", msg.c_str());
1873         }
1874 
1875         throw Error(msg);
1876     }
1877 }
1878 
safeDirGet(const Glib::KeyFile & keyFile,const Glib::ustring & section,const Glib::ustring & entryName,Glib::ustring & destination)1879 bool Options::safeDirGet(const Glib::KeyFile& keyFile, const Glib::ustring& section,
1880                          const Glib::ustring& entryName, Glib::ustring& destination)
1881 {
1882     try {
1883 
1884         if (keyFile.has_key(section, entryName) && !keyFile.get_string(section, entryName).empty()) {
1885             destination = keyFile.get_string(section, entryName);
1886             return true;
1887         }
1888 
1889     } catch (Glib::KeyFileError&) {}
1890 
1891     return false;
1892 }
1893 
saveToFile(Glib::ustring fname)1894 void Options::saveToFile(Glib::ustring fname)
1895 {
1896 
1897     Glib::ustring keyData;
1898 
1899     try {
1900 
1901         Glib::KeyFile keyFile;
1902 
1903         keyFile.set_boolean("General", "TabbedEditor", tabbedUI);
1904 
1905         if (startupDir == STARTUPDIR_HOME) {
1906             keyFile.set_string("General", "StartupDirectory", "home");
1907         } else if (startupDir == STARTUPDIR_CURRENT) {
1908             keyFile.set_string("General", "StartupDirectory", "current");
1909         } else if (startupDir == STARTUPDIR_CUSTOM) {
1910             keyFile.set_string("General", "StartupDirectory", "custom");
1911         } else if (startupDir == STARTUPDIR_LAST) {
1912             keyFile.set_string("General", "StartupDirectory", "last");
1913         }
1914 
1915         keyFile.set_string("General", "StartupPath", startupPath);
1916         keyFile.set_string("General", "DateFormat", dateFormat);
1917         keyFile.set_integer("General", "AdjusterMinDelay", adjusterMinDelay);
1918         keyFile.set_integer("General", "AdjusterMaxDelay", adjusterMaxDelay);
1919         keyFile.set_boolean("General", "MultiUser", multiUser);
1920         keyFile.set_string("General", "Language", language);
1921         keyFile.set_boolean("General", "LanguageAutoDetect", languageAutoDetect);
1922         keyFile.set_string("General", "Theme", theme);
1923         keyFile.set_string("General", "Version", RTVERSION);
1924         keyFile.set_string("General", "DarkFramesPath", rtSettings.darkFramesPath);
1925         keyFile.set_string("General", "FlatFieldsPath", rtSettings.flatFieldsPath);
1926         keyFile.set_boolean("General", "Verbose", rtSettings.verbose);
1927         keyFile.set_integer("General", "ErrorMessageDuration", error_message_duration);
1928         keyFile.set_integer("General", "MaxErrorMessages", max_error_messages);
1929         keyFile.set_integer("External Editor", "EditorKind", editorToSendTo);
1930         keyFile.set_string("External Editor", "GimpDir", gimpDir);
1931         keyFile.set_string("External Editor", "PhotoshopDir", psDir);
1932         keyFile.set_string("External Editor", "CustomEditor", customEditorProg);
1933         keyFile.set_integer("External Editor", "OutputDir", int(editor_out_dir));
1934         keyFile.set_string("External Editor", "CustomOutputDir", editor_custom_out_dir);
1935         keyFile.set_boolean("External Editor", "Float32", editor_float32);
1936         keyFile.set_boolean("External Editor", "BypassOutputProfile", editor_bypass_output_profile);
1937 
1938         keyFile.set_boolean("File Browser", "BrowserShowsDate", fbShowDateTime);
1939         keyFile.set_boolean("File Browser", "BrowserShowsExif", fbShowBasicExif);
1940         keyFile.set_boolean("File Browser", "BrowserShowsExpComp", fbShowExpComp);
1941 #ifndef WIN32
1942         keyFile.set_boolean("File Browser", "BrowserShowsHidden", fbShowHidden);
1943 #endif
1944         keyFile.set_integer("File Browser", "ThumbnailSize", thumbSize);
1945         keyFile.set_integer("File Browser", "ThumbnailSizeTab", thumbSizeTab);
1946         keyFile.set_integer("File Browser", "ThumbnailSizeQueue", thumbSizeQueue);
1947         keyFile.set_integer("File Browser", "SameThumbSize", sameThumbSize);
1948         keyFile.set_integer("File Browser", "ThumbnailOrder", int(thumbnailOrder));
1949         keyFile.set_integer("File Browser", "MaxPreviewHeight", maxThumbnailHeight);
1950         keyFile.set_integer("File Browser", "MaxPreviewWidth", maxThumbnailWidth);
1951         keyFile.set_integer("File Browser", "MaxCacheEntries", maxCacheEntries);
1952         Glib::ArrayHandle<Glib::ustring> pext = parseExtensions;
1953         keyFile.set_string_list("File Browser", "ParseExtensions", pext);
1954         Glib::ArrayHandle<int> pextena = parseExtensionsEnabled;
1955         keyFile.set_integer_list("File Browser", "ParseExtensionsEnabled", pextena);
1956         keyFile.set_integer("File Browser", "ThumbnailInterpolation", thumbInterp);
1957         Glib::ArrayHandle<Glib::ustring> pfav = favoriteDirs;
1958         keyFile.set_string_list("File Browser", "FavoriteDirs", pfav);
1959         Glib::ArrayHandle<double> ptzoom = thumbnailZoomRatios;
1960         keyFile.set_double_list("File Browser", "ThumbnailZoomRatios", ptzoom);
1961         keyFile.set_boolean("File Browser", "OverlayedFileNames", overlayedFileNames);
1962         keyFile.set_boolean("File Browser", "FilmStripOverlayedFileNames", filmStripOverlayedFileNames);
1963         keyFile.set_boolean("File Browser", "ShowFileNames", showFileNames);
1964         keyFile.set_boolean("File Browser", "FilmStripShowFileNames", filmStripShowFileNames);
1965         keyFile.set_boolean("File Browser", "InternalThumbIfUntouched", internalThumbIfUntouched);
1966         keyFile.set_boolean("File Browser", "menuGroupRank", menuGroupRank);
1967         keyFile.set_boolean("File Browser", "menuGroupLabel", menuGroupLabel);
1968         keyFile.set_boolean("File Browser", "menuGroupFileOperations", menuGroupFileOperations);
1969         keyFile.set_boolean("File Browser", "menuGroupProfileOperations", menuGroupProfileOperations);
1970         keyFile.set_boolean("File Browser", "menuGroupExtProg", menuGroupExtProg);
1971         keyFile.set_integer("File Browser", "MaxRecentFolders", maxRecentFolders);
1972         {
1973             std::vector<Glib::ustring> temp;
1974             temp.reserve(maxRecentFolders);
1975 
1976             for (unsigned int i = 0; i < std::min(recentFolders.size(), maxRecentFolders); i++) {
1977                 temp.push_back(recentFolders[i]);
1978             }
1979 
1980             keyFile.set_string_list("File Browser", "RecentFolders", temp);
1981         }
1982         switch (thumbnail_rating_mode) {
1983         case ThumbnailRatingMode::XMP:
1984             keyFile.set_string("File Browser", "ThumbnailRatingMode", "xmp");
1985             break;
1986         default: // ThumbnailRatingMode::PROCPARAMS
1987             keyFile.set_string("File Browser", "ThumbnailRatingMode", "procparams");
1988             break;
1989         }
1990         keyFile.set_integer("Clipping Indication", "HighlightThreshold", highlightThreshold);
1991         keyFile.set_integer("Clipping Indication", "ShadowThreshold", shadowThreshold);
1992 
1993         keyFile.set_integer("Performance", "RgbDenoiseThreadLimit", rgbDenoiseThreadLimit);
1994         keyFile.set_integer("Performance", "ClutCacheSize", clutCacheSize);
1995         keyFile.set_integer("Performance", "MaxInspectorBuffers", maxInspectorBuffers);
1996         keyFile.set_integer("Performance", "InspectorDelay", inspectorDelay);
1997         keyFile.set_integer("Performance", "PreviewDemosaicFromSidecar", prevdemo);
1998         keyFile.set_boolean("Performance", "SerializeTiffRead", serializeTiffRead);
1999         keyFile.set_boolean("Performance", "DenoiseZoomedOut", denoiseZoomedOut);
2000         keyFile.set_integer("Performance", "ThumbUpdateThreadLimit", thumb_update_thread_limit);
2001         keyFile.set_boolean("Performance", "ThumbDelayUpdate", thumb_delay_update);
2002         keyFile.set_boolean("Performance", "ThumbLazyCaching", thumb_lazy_caching);
2003 
2004         keyFile.set_integer("Performance", "WBPreviewMode", wb_preview_mode);
2005         keyFile.set_integer("Inspector", "Mode", int(rtSettings.thumbnail_inspector_mode));
2006         keyFile.set_integer("Inspector", "RawCurve", int(rtSettings.thumbnail_inspector_raw_curve));
2007         keyFile.set_boolean("Inspector", "ZoomFit", thumbnail_inspector_zoom_fit);
2008         keyFile.set_boolean("Inspector", "ShowInfo", thumbnail_inspector_show_info);
2009         keyFile.set_boolean("Inspector", "ShowHistogram", thumbnail_inspector_show_histogram);
2010         keyFile.set_boolean("Inspector", "EnableCMS", thumbnail_inspector_enable_cms);
2011         keyFile.set_integer("Inspector", "BrowserWidth", browser_width_for_inspector);
2012         keyFile.set_boolean("Inspector", "ThumbnailHover", thumbnail_inspector_hover);
2013 
2014         keyFile.set_string("Output", "Format", saveFormat.format);
2015         keyFile.set_integer("Output", "JpegQuality", saveFormat.jpegQuality);
2016         keyFile.set_integer("Output", "JpegSubSamp", saveFormat.jpegSubSamp);
2017         keyFile.set_integer("Output", "PngBps", saveFormat.pngBits);
2018         keyFile.set_integer("Output", "TiffBps", saveFormat.tiffBits);
2019         keyFile.set_boolean("Output", "TiffFloat", saveFormat.tiffFloat);
2020         keyFile.set_boolean("Output", "TiffUncompressed", saveFormat.tiffUncompressed);
2021         keyFile.set_boolean("Output", "SaveProcParams", saveFormat.saveParams);
2022 
2023         keyFile.set_string("Output", "FormatBatch", saveFormatBatch.format);
2024         keyFile.set_integer("Output", "JpegQualityBatch", saveFormatBatch.jpegQuality);
2025         keyFile.set_integer("Output", "JpegSubSampBatch", saveFormatBatch.jpegSubSamp);
2026         keyFile.set_integer("Output", "PngBpsBatch", saveFormatBatch.pngBits);
2027         keyFile.set_integer("Output", "TiffBpsBatch", saveFormatBatch.tiffBits);
2028         keyFile.set_boolean("Output", "TiffFloatBatch", saveFormatBatch.tiffFloat);
2029         keyFile.set_boolean("Output", "TiffUncompressedBatch", saveFormatBatch.tiffUncompressed);
2030         keyFile.set_boolean("Output", "SaveProcParamsBatch", saveFormatBatch.saveParams);
2031 
2032         keyFile.set_string("Output", "PathTemplate", savePathTemplate);
2033         keyFile.set_string("Output", "PathFolder", savePathFolder);
2034         keyFile.set_boolean("Output", "AutoSuffix", autoSuffix);
2035         keyFile.set_boolean("Output", "ForceFormatOpts", forceFormatOpts);
2036         keyFile.set_integer("Output", "SaveMethodNum", saveMethodNum);
2037         keyFile.set_boolean("Output", "UsePathTemplate", saveUsePathTemplate);
2038         keyFile.set_string("Output", "LastSaveAsPath", lastSaveAsPath);
2039         keyFile.set_boolean("Output", "OverwriteOutputFile", overwriteOutputFile);
2040         keyFile.set_boolean("Output", "BatchQueueUseProfile", batch_queue_use_profile);
2041         keyFile.set_string("Output", "BatchQueueProfile", batch_queue_profile_path);
2042         keyFile.set_integer("Output", "ProcParamsAutosaveInterval", sidecar_autosave_interval);
2043 
2044         keyFile.set_string("Profiles", "Directory", profilePath);
2045         keyFile.set_boolean("Profiles", "UseBundledProfiles", useBundledProfiles);
2046         keyFile.set_string("Profiles", "LoadSaveProfilePath", loadSaveProfilePath);
2047         keyFile.set_string("Profiles", "RawDefault", defProfRaw);
2048         keyFile.set_string("Profiles", "ImgDefault", defProfImg);
2049         keyFile.set_boolean("Profiles", "FilledProfile", filledProfile);
2050         keyFile.set_boolean("Profiles", "SaveParamsWithFile", saveParamsFile);
2051         keyFile.set_boolean("Profiles", "SaveParamsToCache", saveParamsCache);
2052         keyFile.set_integer("Profiles", "LoadParamsFromLocation", paramsLoadLocation);
2053         keyFile.set_boolean("Profiles", "EmbedParamsInMetadata", params_out_embed);
2054         keyFile.set_boolean("Profiles", "ParamsSidecarStripExtension", params_sidecar_strip_extension);
2055         keyFile.set_string("Profiles", "CustomProfileBuilderPath", CPBPath);
2056         keyFile.set_integer("Profiles", "CustomProfileBuilderKeys", CPBKeys);
2057 
2058         Glib::ArrayHandle<Glib::ustring> ahfavorites = favorites;
2059         keyFile.set_string_list("GUI", "Favorites", ahfavorites);
2060         keyFile.set_integer("GUI", "WindowWidth", windowWidth);
2061         keyFile.set_integer("GUI", "WindowHeight", windowHeight);
2062         keyFile.set_integer("GUI", "WindowX", windowX);
2063         keyFile.set_integer("GUI", "WindowY", windowY);
2064         keyFile.set_integer("GUI", "WindowMonitor", windowMonitor);
2065         keyFile.set_integer("GUI", "MeowMonitor", meowMonitor);
2066         keyFile.set_boolean("GUI", "MeowFullScreen", meowFullScreen);
2067         keyFile.set_boolean("GUI", "MeowMaximized", meowMaximized);
2068         keyFile.set_integer("GUI", "MeowWidth", meowWidth);
2069         keyFile.set_integer("GUI", "MeowHeight", meowHeight);
2070         keyFile.set_integer("GUI", "MeowX", meowX);
2071         keyFile.set_integer("GUI", "MeowY", meowY);
2072         keyFile.set_boolean("GUI", "WindowMaximized", windowMaximized);
2073         keyFile.set_integer("GUI", "DetailWindowWidth", detailWindowWidth);
2074         keyFile.set_integer("GUI", "DetailWindowHeight", detailWindowHeight);
2075         keyFile.set_integer("GUI", "DirBrowserWidth", dirBrowserWidth);
2076         keyFile.set_integer("GUI", "DirBrowserHeight", dirBrowserHeight);
2077         keyFile.set_integer("GUI", "SortType", dirBrowserSortType);
2078         keyFile.set_integer("GUI", "PreferencesWidth", preferencesWidth);
2079         keyFile.set_integer("GUI", "PreferencesHeight", preferencesHeight);
2080         keyFile.set_integer("GUI", "SaveAsDialogWidth", saveAsDialogWidth);
2081         keyFile.set_integer("GUI", "SaveAsDialogHeight", saveAsDialogHeight);
2082         keyFile.set_integer("GUI", "ToolPanelWidth", toolPanelWidth);
2083         keyFile.set_integer("GUI", "BrowserToolPanelWidth", browserToolPanelWidth);
2084         keyFile.set_integer("GUI", "BrowserToolPanelHeight", browserToolPanelHeight);
2085         keyFile.set_boolean("GUI", "BrowserToolPanelOpened", browserToolPanelOpened);
2086         keyFile.set_boolean("GUI", "EditorFilmStripOpened", editorFilmStripOpened);
2087         keyFile.set_boolean("GUI", "BrowserDirPanelOpened", browserDirPanelOpened);
2088         keyFile.set_boolean("GUI", "InspectorDirPanelOpened", inspectorDirPanelOpened);
2089         keyFile.set_integer("GUI", "HistoryPanelWidth", historyPanelWidth);
2090         keyFile.set_string("GUI", "FontFamily", fontFamily);
2091         keyFile.set_integer("GUI", "FontSize", fontSize);
2092         keyFile.set_string("GUI", "CPFontFamily", CPFontFamily);
2093         keyFile.set_integer("GUI", "CPFontSize", CPFontSize);
2094         keyFile.set_boolean("GUI", "PseudoHiDPISupport", pseudoHiDPISupport);
2095         keyFile.set_integer("GUI", "LastPreviewScale", lastScale);
2096         keyFile.set_integer("GUI", "PanAccelFactor", panAccelFactor);
2097         keyFile.set_boolean("GUI", "RememberZoomAndPan", rememberZoomAndPan);
2098         keyFile.set_boolean("GUI", "ShowHistory", showHistory);
2099         keyFile.set_boolean("GUI", "ShowInfo", showInfo);
2100         keyFile.set_boolean("GUI", "MainNBVertical", mainNBVertical);
2101         keyFile.set_boolean("GUI", "ShowClippedHighlights", showClippedHighlights);
2102         keyFile.set_boolean("GUI", "ShowClippedShadows", showClippedShadows);
2103         keyFile.set_integer("GUI", "FrameColor", bgcolor);
2104         keyFile.set_boolean("GUI", "ProcessingQueueEnbled", procQueueEnabled);
2105         Glib::ArrayHandle<int> tpopen = tpOpen;
2106         keyFile.set_integer_list ("GUI", "ToolPanelsExpanded", tpopen);
2107         keyFile.set_boolean ("GUI", "ToolPanelsExpandedAutoSave", autoSaveTpOpen);
2108         keyFile.set_integer ("GUI", "MultiDisplayMode", multiDisplayMode);
2109         keyFile.set_double_list ("GUI", "CutOverlayBrush", cutOverlayBrush);
2110         keyFile.set_double_list ("GUI", "NavGuideBrush", navGuideBrush);
2111         keyFile.set_integer ("GUI", "HistogramPosition", histogramPosition);
2112         keyFile.set_boolean ("GUI", "HistogramRed", histogramRed);
2113         keyFile.set_boolean ("GUI", "HistogramGreen", histogramGreen);
2114         keyFile.set_boolean ("GUI", "HistogramBlue", histogramBlue);
2115         keyFile.set_boolean ("GUI", "HistogramLuma", histogramLuma);
2116         keyFile.set_boolean ("GUI", "HistogramChroma", histogramChroma);
2117         //keyFile.set_boolean ("GUI", "HistogramRAW", histogramRAW);
2118         keyFile.set_boolean ("GUI", "HistogramBar", histogramBar);
2119         keyFile.set_integer ("GUI", "HistogramHeight", histogramHeight);
2120         keyFile.set_integer ("GUI", "HistogramDrawMode", histogramDrawMode);
2121         keyFile.set_double("GUI", "HistogramScalingFactor", histogram_scaling_factor);
2122         keyFile.set_integer("GUI", "HistogramScopeType", rtengine::toUnderlying(histogramScopeType));
2123         keyFile.set_boolean("GUI", "HistogramShowOptionButtons", histogramShowOptionButtons);
2124         keyFile.set_double("GUI", "HistogramTraceBrightness", histogramTraceBrightness);
2125         keyFile.set_integer ("GUI", "NavigatorRGBUnit", (int)navRGBUnit);
2126         keyFile.set_integer ("GUI", "NavigatorLCHUnit", (int)navLCHUnit);
2127         keyFile.set_boolean ("GUI", "ShowFilmStripToolBar", showFilmStripToolBar);
2128         keyFile.set_boolean ("GUI", "FileBrowserToolbarSingleRow", FileBrowserToolbarSingleRow);
2129         keyFile.set_boolean ("GUI", "HideTPVScrollbar", hideTPVScrollbar);
2130         keyFile.set_boolean ("GUI", "HistogramWorking", rtSettings.HistogramWorking);
2131         keyFile.set_integer ("GUI", "CurveBBoxPosition", curvebboxpos);
2132         keyFile.set_boolean("GUI", "ToolPanelsDisable", toolpanels_disable);
2133         keyFile.set_boolean("GUI", "AdjusterForceLinear", adjuster_force_linear);
2134 
2135         //Glib::ArrayHandle<int> crvopen = crvOpen;
2136         //keyFile.set_integer_list ("GUI", "CurvePanelsExpanded", crvopen);
2137 
2138         keyFile.set_integer("Crop Settings", "PPI", cropPPI);
2139 
2140         keyFile.set_string("Color Management", "PrinterProfile", rtSettings.printerProfile);
2141         keyFile.set_integer("Color Management", "PrinterIntent", rtSettings.printerIntent);
2142         keyFile.set_boolean("Color Management", "PrinterBPC", rtSettings.printerBPC);
2143 
2144         keyFile.set_string("Color Management", "ICCDirectory", rtSettings.iccDirectory);
2145         keyFile.set_string("Color Management", "MonitorICCDirectory", rtSettings.monitorIccDirectory);
2146         keyFile.set_string("Color Management", "MonitorProfile", rtSettings.monitorProfile);
2147         keyFile.set_boolean("Color Management", "AutoMonitorProfile", rtSettings.autoMonitorProfile);
2148         keyFile.set_integer("Color Management", "Intent", rtSettings.monitorIntent);
2149         keyFile.set_boolean("Color Management", "MonitorBPC", rtSettings.monitorBPC);
2150 
2151         keyFile.set_integer("Color Management", "WhiteBalanceSpotSize", whiteBalanceSpotSize);
2152         keyFile.set_string("Color Management", "ClutsDirectory", clutsDir);
2153 
2154         keyFile.set_string("ICC Profile Creator", "PimariesPreset", ICCPC_primariesPreset);
2155         keyFile.set_double("ICC Profile Creator", "RedPrimaryX", ICCPC_redPrimaryX);
2156         keyFile.set_double("ICC Profile Creator", "RedPrimaryY", ICCPC_redPrimaryY);
2157         keyFile.set_double("ICC Profile Creator", "GreenPrimaryX", ICCPC_greenPrimaryX);
2158         keyFile.set_double("ICC Profile Creator", "GreenPrimaryY", ICCPC_greenPrimaryY);
2159         keyFile.set_double("ICC Profile Creator", "BluePrimaryX", ICCPC_bluePrimaryX);
2160         keyFile.set_double("ICC Profile Creator", "BluePrimaryY", ICCPC_bluePrimaryY);
2161         keyFile.set_string("ICC Profile Creator", "GammaPreset", ICCPC_gammaPreset);
2162         keyFile.set_double("ICC Profile Creator", "Gamma", ICCPC_gamma);
2163         keyFile.set_double("ICC Profile Creator", "Slope", ICCPC_slope);
2164         keyFile.set_string("ICC Profile Creator", "ProfileVersion", ICCPC_profileVersion);
2165         keyFile.set_string("ICC Profile Creator", "Illuminant", ICCPC_illuminant);
2166         keyFile.set_string("ICC Profile Creator", "Description", ICCPC_description);
2167         keyFile.set_string("ICC Profile Creator", "Copyright", ICCPC_copyright);
2168         keyFile.set_boolean("ICC Profile Creator", "AppendParamsToDesc", ICCPC_appendParamsToDesc);
2169 
2170         keyFile.set_boolean("Sounds", "Enable", sndEnable);
2171         keyFile.set_string("Sounds", "BatchQueueDone", sndBatchQueueDone);
2172         keyFile.set_string("Sounds", "LngEditProcDone", sndLngEditProcDone);
2173         keyFile.set_double("Sounds", "LngEditProcDoneSecs", sndLngEditProcDoneSecs);
2174 
2175         keyFile.set_boolean("Fast Export", "fastexport_bypass_sharpening", fastexport_bypass_sharpening);
2176         keyFile.set_boolean("Fast Export", "fastexport_bypass_defringe", fastexport_bypass_defringe);
2177         keyFile.set_boolean("Fast Export", "fastexport_bypass_dirpyrDenoise", fastexport_bypass_dirpyrDenoise);
2178         keyFile.set_boolean("Fast Export", "fastexport_bypass_localContrast", fastexport_bypass_localContrast);
2179         keyFile.set_string("Fast Export", "fastexport_raw_bayer_method", fastexport_raw_bayer_method);
2180         //keyFile.set_boolean ("Fast Export", "fastexport_bypass_bayer_raw_all_enhance" , fastexport_bypass_raw_bayer_all_enhance);
2181         keyFile.set_boolean("Fast Export", "fastexport_bypass_raw_bayer_dcb_iterations", fastexport_bypass_raw_bayer_dcb_iterations);
2182         keyFile.set_boolean("Fast Export", "fastexport_bypass_raw_bayer_dcb_enhance", fastexport_bypass_raw_bayer_dcb_enhance);
2183         keyFile.set_boolean("Fast Export", "fastexport_bypass_raw_bayer_lmmse_iterations", fastexport_bypass_raw_bayer_lmmse_iterations);
2184         keyFile.set_boolean("Fast Export", "fastexport_bypass_raw_bayer_linenoise", fastexport_bypass_raw_bayer_linenoise);
2185         keyFile.set_boolean("Fast Export", "fastexport_bypass_raw_bayer_greenthresh", fastexport_bypass_raw_bayer_greenthresh);
2186         keyFile.set_string("Fast Export", "fastexport_raw_xtrans_method", fastexport_raw_xtrans_method);
2187         keyFile.set_boolean("Fast Export", "fastexport_bypass_raw_ccSteps", fastexport_bypass_raw_ccSteps);
2188         keyFile.set_boolean("Fast Export", "fastexport_bypass_raw_ca", fastexport_bypass_raw_ca);
2189         keyFile.set_boolean("Fast Export", "fastexport_bypass_raw_df", fastexport_bypass_raw_df);
2190         keyFile.set_boolean("Fast Export", "fastexport_bypass_raw_ff", fastexport_bypass_raw_ff);
2191         keyFile.set_string("Fast Export", "fastexport_icm_input", fastexport_icm_input_profile);
2192         keyFile.set_string("Fast Export", "fastexport_icm_working", fastexport_icm_working_profile);
2193         keyFile.set_string("Fast Export", "fastexport_icm_output", fastexport_icm_output_profile);
2194         keyFile.set_integer("Fast Export", "fastexport_icm_output_intent", fastexport_icm_outputIntent);
2195         keyFile.set_boolean("Fast Export", "fastexport_icm_output_bpc", fastexport_icm_outputBPC);
2196         keyFile.set_boolean("Fast Export", "fastexport_resize_enabled", fastexport_resize_enabled);
2197         keyFile.set_double("Fast Export", "fastexport_resize_scale", fastexport_resize_scale);
2198         keyFile.set_string("Fast Export", "fastexport_resize_appliesTo", fastexport_resize_appliesTo);
2199         keyFile.set_integer("Fast Export", "fastexport_resize_dataspec", fastexport_resize_dataspec);
2200         keyFile.set_integer("Fast Export", "fastexport_resize_width", fastexport_resize_width);
2201         keyFile.set_integer("Fast Export", "fastexport_resize_height", fastexport_resize_height);
2202         keyFile.set_integer("Fast Export", "fastexport_use_fast_pipeline", fastexport_use_fast_pipeline);
2203 
2204         keyFile.set_string("Dialogs", "LastIccDir", lastIccDir);
2205         keyFile.set_string("Dialogs", "LastDarkframeDir", lastDarkframeDir);
2206         keyFile.set_string("Dialogs", "LastFlatfieldDir", lastFlatfieldDir);
2207         keyFile.set_string("Dialogs", "LastRgbCurvesDir", lastRgbCurvesDir);
2208         keyFile.set_string("Dialogs", "LastLabCurvesDir", lastLabCurvesDir);
2209         keyFile.set_string("Dialogs", "LastPFCurvesDir", lastPFCurvesDir);
2210         keyFile.set_string("Dialogs", "LastHsvCurvesDir", lastHsvCurvesDir);
2211         keyFile.set_string("Dialogs", "LastToneCurvesDir", lastToneCurvesDir);
2212         keyFile.set_string("Dialogs", "LastProfilingReferenceDir", lastProfilingReferenceDir);
2213         keyFile.set_string("Dialogs", "LastLensProfileDir", lastLensProfileDir);
2214         keyFile.set_string("Dialogs", "LastICCProfCreatorDir", lastICCProfCreatorDir);
2215         keyFile.set_string("Dialogs", "LastCopyMovePath", lastCopyMovePath);
2216         keyFile.set_boolean("Dialogs", "GimpPluginShowInfoDialog", gimpPluginShowInfoDialog);
2217 
2218         keyFile.set_string("Lensfun", "DBDirectory", rtSettings.lensfunDbDirectory);
2219 
2220         switch (rtSettings.xmp_sidecar_style) {
2221         case rtengine::Settings::XmpSidecarStyle::EXT:
2222             keyFile.set_string("Metadata", "XMPSidecarStyle", "ext");
2223             break;
2224         default:
2225             keyFile.set_string("Metadata", "XMPSidecarStyle", "std");
2226         }
2227 
2228         switch (rtSettings.metadata_xmp_sync) {
2229         case rtengine::Settings::MetadataXmpSync::READ:
2230             keyFile.set_string("Metadata", "XMPSynchronization", "read");
2231             break;
2232         case rtengine::Settings::MetadataXmpSync::READ_WRITE:
2233             keyFile.set_string("Metadata", "XMPSynchronization", "readwrite");
2234             break;
2235         default:
2236             keyFile.set_string("Metadata", "XMPSynchronization", "none");
2237         }
2238 
2239         keyFile.set_string("Metadata", "ExiftoolPath", rtSettings.exiftool_path);
2240 
2241         for (auto &p : falseColorsMap) {
2242             keyFile.set_string("False Colors Map", "IRE_" + std::to_string(p.first), p.second);
2243         }
2244 
2245         keyFile.set_string("Renaming", "Pattern", renaming.pattern);
2246         keyFile.set_string("Renaming", "Sidecars", renaming.sidecars);
2247         keyFile.set_integer("Renaming", "NameNormalization", renaming.name_norm);
2248         keyFile.set_integer("Renaming", "ExtNormalization", renaming.ext_norm);
2249         keyFile.set_boolean("Renaming", "AllowWhitespace", renaming.allow_whitespace);
2250         keyFile.set_integer("Renaming", "OnExisting", renaming.on_existing);
2251         keyFile.set_integer("Renaming", "ProgressiveNumber", renaming.progressive_number);
2252 
2253         keyData = keyFile.to_data();
2254 
2255     } catch (Glib::KeyFileError &e) {
2256         throw Error(e.what());
2257     }
2258 
2259     FILE *f = g_fopen(fname.c_str(), "wt");
2260 
2261     if (f == nullptr) {
2262         std::cout << "Warning! Unable to save your preferences to: " << fname << std::endl;
2263         Glib::ustring msg_ = Glib::ustring::compose(M("MAIN_MSG_WRITEFAILED"), fname.c_str());
2264         throw Error(msg_);
2265     } else {
2266         fprintf(f, "%s", keyData.c_str());
2267         fclose(f);
2268     }
2269 
2270     if (options.rtSettings.verbose) {
2271         std::cout << "options saved to " << fname << std::endl;
2272     }
2273 }
2274 
load(bool lightweight,int verbose)2275 void Options::load(bool lightweight, int verbose)
2276 {
2277     if (verbose >= 0) {
2278         options.rtSettings.verbose = verbose;
2279     }
2280 
2281     // Find the application data path
2282 
2283     const gchar* path;
2284     Glib::ustring dPath;
2285 
2286     path = g_getenv("ART_SETTINGS");
2287 
2288     if (path != nullptr) {
2289         rtdir = Glib::ustring(path);
2290 
2291         if (!Glib::path_is_absolute(rtdir)) {
2292             Glib::ustring msg = Glib::ustring::compose("Settings path %1 is not absolute", rtdir);
2293             throw Error(msg);
2294         }
2295     } else {
2296 #ifdef WIN32
2297         WCHAR pathW[MAX_PATH] = {0};
2298 
2299         if (SHGetSpecialFolderPathW(NULL, pathW, CSIDL_LOCAL_APPDATA, false)) {
2300             char pathA[MAX_PATH];
2301             WideCharToMultiByte(CP_UTF8, 0, pathW, -1, pathA, MAX_PATH, 0, 0);
2302             rtdir = Glib::build_filename(Glib::ustring(pathA), Glib::ustring(CACHEFOLDERNAME));
2303         }
2304 
2305 #else
2306         rtdir = Glib::build_filename(Glib::ustring(g_get_user_config_dir()), Glib::ustring(CACHEFOLDERNAME));
2307 #endif
2308     }
2309 
2310     if (options.rtSettings.verbose) {
2311         printf("Settings directory (rtdir) = %s\n", rtdir.c_str());
2312     }
2313 
2314     // Set the cache folder in RT's base folder
2315     cacheBaseDir = Glib::build_filename(argv0, "mycache");
2316 
2317     // Read the global option file (the one located in the application's base folder)
2318     try {
2319         options.readFromFile(Glib::build_filename(argv0, "options"));
2320     } catch (Options::Error &) {
2321         // ignore errors here
2322     }
2323 
2324     if (!options.multiUser && path == nullptr) {
2325         rtdir = Glib::build_filename(argv0, "mysettings");
2326     }
2327 
2328     // Modify the path of the cache folder to the one provided in ART_CACHE environment variable
2329     path = g_getenv("ART_CACHE");
2330 
2331     if (path != nullptr) {
2332         cacheBaseDir = Glib::ustring(path);
2333 
2334         if (!Glib::path_is_absolute(cacheBaseDir)) {
2335             Glib::ustring msg = Glib::ustring::compose("Cache base dir %1 is not absolute", cacheBaseDir);
2336             throw Error(msg);
2337         }
2338     }
2339     // No environment variable provided, so falling back to the multi user mode, if enabled
2340     else if (options.multiUser) {
2341 #ifdef WIN32
2342         cacheBaseDir = Glib::build_filename(rtdir, "cache");
2343 #else
2344         cacheBaseDir = Glib::build_filename(Glib::ustring(g_get_user_cache_dir()), Glib::ustring(CACHEFOLDERNAME));
2345 #endif
2346     }
2347 
2348     // Read the user option file (the one located somewhere in the user's home folder)
2349     // Those values supersets those of the global option file
2350     try {
2351         options.readFromFile(Glib::build_filename(rtdir, "options"));
2352         if (verbose >= 0) {
2353             options.rtSettings.verbose = verbose;
2354         }
2355     } catch (Options::Error &) {
2356         // If the local option file does not exist or is broken, and the local cache folder does not exist, recreate it
2357         if (!g_mkdir_with_parents(rtdir.c_str(), 511)) {
2358             // Save the option file
2359             options.saveToFile(Glib::build_filename(rtdir, "options"));
2360         }
2361     }
2362 
2363 #ifdef __APPLE__
2364 
2365     if (options.multiUser) {
2366         // make sure .local/share exists on OS X so we don't get problems with recently-used.xbel
2367         g_mkdir_with_parents(g_get_user_data_dir(), 511);
2368     }
2369 
2370 #endif
2371 
2372     if (options.rtSettings.verbose) {
2373         printf("Cache directory (cacheBaseDir) = %s\n", cacheBaseDir.c_str());
2374     }
2375 
2376     // Update profile's path and recreate it if necessary
2377     options.updatePaths();
2378 
2379     // Check default Raw and Img procparams existence
2380     if (options.defProfRaw.empty()) {
2381         options.defProfRaw = DEFPROFILE_RAW;
2382     } else {
2383         if (!options.findProfilePath(options.defProfRaw).empty()) {
2384             if (options.rtSettings.verbose) {
2385                 std::cout << "Default profile for raw images \"" << options.defProfRaw << "\" found" << std::endl;
2386             }
2387         } else {
2388             if (options.defProfRaw != DEFPROFILE_RAW) {
2389                 options.setDefProfRawMissing(true);
2390 
2391                 Glib::ustring dpr(DEFPROFILE_RAW);
2392 
2393                 if (options.findProfilePath(dpr).empty()) {
2394                     options.setBundledDefProfRawMissing(true);
2395                 }
2396             } else {
2397                 options.setBundledDefProfRawMissing(true);
2398             }
2399         }
2400     }
2401 
2402     if (options.defProfImg.empty()) {
2403         options.defProfImg = DEFPROFILE_IMG;
2404     } else {
2405         if (!options.findProfilePath(options.defProfImg).empty()) {
2406             if (options.rtSettings.verbose) {
2407                 std::cout << "Default profile for non-raw images \"" << options.defProfImg << "\" found" << std::endl;
2408             }
2409         } else {
2410             if (options.defProfImg != DEFPROFILE_IMG) {
2411                 options.setDefProfImgMissing(true);
2412 
2413                 Glib::ustring dpi(DEFPROFILE_IMG);
2414 
2415                 if (options.findProfilePath(dpi).empty()) {
2416                     options.setBundledDefProfImgMissing(true);
2417                 }
2418             } else {
2419                 options.setBundledDefProfImgMissing(true);
2420             }
2421         }
2422     }
2423 
2424     // We handle languages using a hierarchy of translations.  The top of the hierarchy is default.  This includes a default translation for all items
2425     // (most likely using simple English).  The next level is the language: for instance, English, French, Chinese, etc.  This file should contain a
2426     // generic translation for all items which differ from default.  Finally there is the locale.  This is region-specific items which differ from the
2427     // language file.  These files must be name in the format <Language> (<LC>), where Language is the name of the language which it inherits from,
2428     // and LC is the local code.  Some examples of this would be English (US) (American English), French (FR) (France French), French (CA) (Canadian
2429     // French), etc.
2430     //
2431     // Each level will only contain the differences between itself and its parent translation.  For instance, English (UK) or English (CA) may
2432     // include the translation "HISTORY_MSG_34;Avoid Colour Clipping" where English would translate it as "HISTORY_MSG_34;Avoid Color Clipping" (note
2433     // the difference in the spelling of 'colour').
2434     //
2435     // It is important that when naming the translation files, that you stick to the format <Language> or <Language> (<LC>).  We depend on that to figure
2436     // out which are the parent translations.  Furthermore, there must be a file <Language> for each locale <Language> (<LC>) -- you cannot have
2437     // 'French (CA)' unless there is a file 'French'.
2438 
2439     Glib::ustring defaultTranslation = Glib::build_filename(argv0, "languages", "default");
2440     Glib::ustring languageTranslation = "";
2441     Glib::ustring localeTranslation = "";
2442 
2443     if (options.languageAutoDetect) {
2444         options.language = langMgr.getOSUserLanguage();
2445     }
2446 
2447     if (!options.language.empty()) {
2448         std::vector<Glib::ustring> langPortions = Glib::Regex::split_simple(" ", options.language);
2449 
2450         if (langPortions.size() >= 1) {
2451             languageTranslation = Glib::build_filename(argv0, "languages", langPortions.at(0));
2452         }
2453 
2454         if (langPortions.size() >= 2) {
2455             localeTranslation = Glib::build_filename(argv0, "languages", options.language);
2456         }
2457     }
2458 
2459     langMgr.load(options.language, {localeTranslation, languageTranslation, defaultTranslation});
2460 
2461     rtengine::init(&options.rtSettings, argv0, rtdir, !lightweight);
2462 }
2463 
save()2464 void Options::save()
2465 {
2466     options.saveToFile(Glib::build_filename(rtdir, "options"));
2467 }
2468 
2469 /*
2470  * return true if ext is a parsed extension (retained or not)
2471  */
is_parse_extention(Glib::ustring fname)2472 bool Options::is_parse_extention(Glib::ustring fname)
2473 {
2474     Glib::ustring ext = getExtension(fname).lowercase();
2475 
2476     if (!ext.empty()) {
2477         // there is an extension to the filename
2478 
2479         // look out if it has one of the listed extensions (selected or not)
2480         for (unsigned int i = 0; i < parseExtensions.size(); i++) {
2481             if (ext == parseExtensions[i]) {
2482                 return true;
2483             }
2484         }
2485     }
2486 
2487     return false;
2488 }
2489 
2490 /*
2491  * return true if fname ends with one of the retained image file extensions
2492  */
has_retained_extention(const Glib::ustring & fname)2493 bool Options::has_retained_extention(const Glib::ustring& fname)
2494 {
2495     return parsedExtensionsSet.find(getExtension(fname).lowercase()) != parsedExtensionsSet.end();
2496 }
2497 
2498 // Pattern matches "5.1" from "5.1-23-g12345678", when comparing option.version to RTVERSION
is_new_version()2499 bool Options::is_new_version() {
2500     const std::string vs[] = {versionString, version};
2501     std::vector<std::string> vMajor;
2502 
2503     for (const auto& v : vs) {
2504         vMajor.emplace_back(v, 0, v.find_first_not_of("0123456789."));
2505     }
2506 
2507     return vMajor.size() == 2 && vMajor[0] != vMajor[1];
2508 }
2509 
2510 /*
2511  * return true if ext is an enabled extension
2512  */
is_extention_enabled(const Glib::ustring & ext)2513 bool Options::is_extention_enabled(const Glib::ustring& ext)
2514 {
2515     return parsedExtensionsSet.find(ext.lowercase()) != parsedExtensionsSet.end();
2516 }
2517 
getUserProfilePath()2518 Glib::ustring Options::getUserProfilePath()
2519 {
2520     return userProfilePath;
2521 }
2522 
getGlobalProfilePath()2523 Glib::ustring Options::getGlobalProfilePath()
2524 {
2525     return globalProfilePath;
2526 }
2527 
is_defProfRawMissing()2528 bool Options::is_defProfRawMissing()
2529 {
2530     return defProfError & rtengine::toUnderlying(DefProfError::defProfRawMissing);
2531 }
is_defProfImgMissing()2532 bool Options::is_defProfImgMissing()
2533 {
2534     return defProfError & rtengine::toUnderlying(DefProfError::defProfImgMissing);
2535 }
setDefProfRawMissing(bool value)2536 void Options::setDefProfRawMissing(bool value)
2537 {
2538     if (value) {
2539         defProfError |= rtengine::toUnderlying(DefProfError::defProfRawMissing);
2540     } else {
2541         defProfError &= ~rtengine::toUnderlying(DefProfError::defProfRawMissing);
2542     }
2543 }
setDefProfImgMissing(bool value)2544 void Options::setDefProfImgMissing(bool value)
2545 {
2546     if (value) {
2547         defProfError |= rtengine::toUnderlying(DefProfError::defProfImgMissing);
2548     } else {
2549         defProfError &= ~rtengine::toUnderlying(DefProfError::defProfImgMissing);
2550     }
2551 }
is_bundledDefProfRawMissing()2552 bool Options::is_bundledDefProfRawMissing()
2553 {
2554     return defProfError & rtengine::toUnderlying(DefProfError::bundledDefProfRawMissing);
2555 }
is_bundledDefProfImgMissing()2556 bool Options::is_bundledDefProfImgMissing()
2557 {
2558     return defProfError & rtengine::toUnderlying(DefProfError::bundledDefProfImgMissing);
2559 }
setBundledDefProfRawMissing(bool value)2560 void Options::setBundledDefProfRawMissing(bool value)
2561 {
2562     if (value) {
2563         defProfError |= rtengine::toUnderlying(DefProfError::bundledDefProfRawMissing);
2564     } else {
2565         defProfError &= ~rtengine::toUnderlying(DefProfError::bundledDefProfRawMissing);
2566     }
2567 }
setBundledDefProfImgMissing(bool value)2568 void Options::setBundledDefProfImgMissing(bool value)
2569 {
2570     if (value) {
2571         defProfError |= rtengine::toUnderlying(DefProfError::bundledDefProfImgMissing);
2572     } else {
2573         defProfError &= ~rtengine::toUnderlying(DefProfError::bundledDefProfImgMissing);
2574     }
2575 }
getICCProfileCopyright()2576 Glib::ustring Options::getICCProfileCopyright()
2577 {
2578     Glib::Date now;
2579     now.set_time_current();
2580     return Glib::ustring::compose("Copyright RawTherapee %1, CC0", now.get_year());
2581 }
2582 
2583 
getParamFile(const Glib::ustring & fname)2584 Glib::ustring Options::getParamFile(const Glib::ustring &fname)
2585 {
2586     if (params_sidecar_strip_extension) {
2587         return removeExtension(fname) + paramFileExtension;
2588     } else {
2589         return fname + paramFileExtension;
2590     }
2591 }
2592 
2593 
getXmpSidecarFile(const Glib::ustring & fname)2594 Glib::ustring Options::getXmpSidecarFile(const Glib::ustring &fname)
2595 {
2596     return rtengine::Exiv2Metadata::xmpSidecarPath(fname);
2597 }
2598