1 /*******************************************************************************************************
2  DkSettings.cpp
3  Created on:	07.07.2011
4 
5  nomacs is a fast and small image viewer with the capability of synchronizing multiple instances
6 
7  Copyright (C) 2011-2016 Markus Diem <markus@nomacs.org>
8  Copyright (C) 2011-2016 Stefan Fiel <stefan@nomacs.org>
9  Copyright (C) 2011-2016 Florian Kleber <florian@nomacs.org>
10 
11  This file is part of nomacs.
12 
13  nomacs is free software: you can redistribute it and/or modify
14  it under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  nomacs is distributed in the hope that it will be useful,
19  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  GNU General Public License for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with this program.  If not, see <http://www.gnu.org/licenses/>.
25 
26  *******************************************************************************************************/
27 
28 #include "DkSettings.h"
29 #include "DkUtils.h"
30 
31 #pragma warning(push, 0)	// no warnings from includes - begin
32 #include <iostream>
33 #include <cassert>
34 
35 #include <QImageReader>
36 #include <QScreen>
37 #include <QDesktopServices>
38 #include <QTranslator>
39 #include <QFileInfo>
40 #include <QDebug>
41 #include <QTableView>
42 #include <QStandardItemModel>
43 #include <QStandardItem>
44 #include <QAbstractTableModel>
45 #include <QStyledItemDelegate>
46 #include <QDir>
47 #include <QApplication>
48 #include <QThreadPool>
49 
50 #ifdef Q_OS_WIN
51 #include "Shobjidl.h"
52 #endif
53 #pragma warning(pop)		// no warnings from includes - end
54 
55 namespace nmc {
56 
DkSettings()57 DkSettings::DkSettings() {
58 
59 	// cache settings path
60 	mSettingsPath = settingsPath();
61 	init();
62 }
63 
init()64 void DkSettings::init() {
65 	scamDataDesc = QStringList() <<
66 		QT_TRANSLATE_NOOP("nmc::DkMetaData","Image Size") <<
67 		QT_TRANSLATE_NOOP("nmc::DkMetaData","Orientation") <<
68 		QT_TRANSLATE_NOOP("nmc::DkMetaData","Make") <<
69 		QT_TRANSLATE_NOOP("nmc::DkMetaData","Model") <<
70 		QT_TRANSLATE_NOOP("nmc::DkMetaData","Aperture Value") <<
71 		QT_TRANSLATE_NOOP("nmc::DkMetaData","ISO") <<
72 		QT_TRANSLATE_NOOP("nmc::DkMetaData","Flash") <<
73 		QT_TRANSLATE_NOOP("nmc::DkMetaData","Focal Length") <<
74 		QT_TRANSLATE_NOOP("nmc::DkMetaData","Exposure Mode") <<
75 		QT_TRANSLATE_NOOP("nmc::DkMetaData","Exposure Time") <<
76 		QT_TRANSLATE_NOOP("nmc::DkMetaData", "Compression");
77 
78 	sdescriptionDesc = QStringList() <<
79 		QT_TRANSLATE_NOOP("nmc::DkMetaData","Rating") <<
80 		QT_TRANSLATE_NOOP("nmc::DkMetaData","User Comment") <<
81 		QT_TRANSLATE_NOOP("nmc::DkMetaData","Date Time") <<
82 		QT_TRANSLATE_NOOP("nmc::DkMetaData","Date Time Original") <<
83 		QT_TRANSLATE_NOOP("nmc::DkMetaData","Image Description") <<
84 		QT_TRANSLATE_NOOP("nmc::DkMetaData","Creator") <<
85 		QT_TRANSLATE_NOOP("nmc::DkMetaData","Creator Title") <<
86 		QT_TRANSLATE_NOOP("nmc::DkMetaData","City") <<
87 		QT_TRANSLATE_NOOP("nmc::DkMetaData","Country") <<
88 		QT_TRANSLATE_NOOP("nmc::DkMetaData","Headline") <<
89 		QT_TRANSLATE_NOOP("nmc::DkMetaData","Caption") <<
90 		QT_TRANSLATE_NOOP("nmc::DkMetaData","Copyright") <<
91 		QT_TRANSLATE_NOOP("nmc::DkMetaData","Keywords") <<
92 		QT_TRANSLATE_NOOP("nmc::DkMetaData","Path") <<
93 		QT_TRANSLATE_NOOP("nmc::DkMetaData","File Size");
94 }
95 
dpiScaleFactor(QWidget * widget) const96 double DkSettings::dpiScaleFactor(QWidget *widget) const {
97 
98 	double dpi = 96.0;
99     if (widget) {
100         dpi = (double) widget->logicalDpiX();
101     } else {
102         QList<QScreen*> screens = QApplication::screens();
103         for(const QScreen* s : screens) {
104             if (s->logicalDotsPerInch() > dpi)
105 				dpi = s->logicalDotsPerInch();
106         }
107     }
108     if (dpi < 96.0) dpi = 96.0;
109     return dpi / 96.0;
110 }
111 
effectiveIconSize(QWidget * widget) const112 int DkSettings::effectiveIconSize(QWidget *widget) const {
113     return qRound(display_p.iconSize * dpiScaleFactor(widget));
114 }
115 
effectiveThumbSize(QWidget * widget) const116 int DkSettings::effectiveThumbSize(QWidget *widget) const {
117     return qRound(display_p.thumbSize * dpiScaleFactor(widget));
118 }
119 
effectiveThumbPreviewSize(QWidget * widget) const120 int DkSettings::effectiveThumbPreviewSize(QWidget *widget) const {
121     return qRound(display_p.thumbPreviewSize * dpiScaleFactor(widget));
122 }
123 
translatedCamData() const124 QStringList DkSettings::translatedCamData() const {
125 	return scamDataDesc;
126 }
127 
translatedDescriptionData() const128 QStringList DkSettings::translatedDescriptionData() const {
129 	return sdescriptionDesc;
130 }
131 
initFileFilters()132 void DkSettings::initFileFilters() {
133 
134 	if (!app_p.openFilters.empty())
135 		return;
136 
137 	QList<QByteArray> qtFormats = QImageReader::supportedImageFormats();
138 
139 	// formats we can save
140 	if (qtFormats.contains("png"))		app_p.saveFilters.append("PNG (*.png)");
141 	if (qtFormats.contains("jpg"))		app_p.saveFilters.append("JPEG (*.jpg *.jpeg *.jpe)");
142 	if (qtFormats.contains("jp2"))		app_p.saveFilters.append("JPEG 2000 (*.jp2 *.j2k *.jpf *.jpx *.jpm *.jpgx)");
143 	if (qtFormats.contains("tif"))		app_p.saveFilters.append("TIFF (*.tif *.tiff)");
144 	if (qtFormats.contains("bmp"))		app_p.saveFilters.append("Windows Bitmap (*.bmp)");
145 	if (qtFormats.contains("ppm"))		app_p.saveFilters.append("Portable Pixmap (*.ppm)");
146 	if (qtFormats.contains("xbm"))		app_p.saveFilters.append("X11 Bitmap (*.xbm)");
147 	if (qtFormats.contains("xpm"))		app_p.saveFilters.append("X11 Pixmap (*.xpm)");
148 	if (qtFormats.contains("dds"))		app_p.saveFilters.append("Direct Draw Surface (*.dds)");
149 	if (qtFormats.contains("wbmp"))		app_p.saveFilters.append("Wireless Bitmap (*.wbmp)");
150 	//if (qtFormats.contains("icns"))		app_p.saveFilters.append("Apple Icon Image (*.icns)");
151 
152 	if (qtFormats.contains("webp"))		app_p.saveFilters.append("WebP (*.webp)");
153 	if (qtFormats.contains("avif"))		app_p.saveFilters.append("AV1 Image File Format (*.avif)");
154 
155 #ifdef Q_OS_WIN
156 	if (qtFormats.contains("ico"))		app_p.saveFilters.append("Icon Files (*.ico)");
157 #endif
158 
159 	// formats we can load
160 	app_p.openFilters += app_p.saveFilters;
161 	if (qtFormats.contains("gif"))		app_p.openFilters.append("Graphic Interchange Format (*.gif)");
162 	if (qtFormats.contains("pbm"))		app_p.openFilters.append("Portable Bitmap (*.pbm)");
163 	if (qtFormats.contains("pgm"))		app_p.openFilters.append("Portable Graymap (*.pgm)");
164 	if (qtFormats.contains("tga"))		app_p.openFilters.append("Truvision Graphics Adapter (*.tga)");
165 	if (qtFormats.contains("mng"))		app_p.openFilters.append("Multi-Image Network Graphics (*.mng)");
166 	if (qtFormats.contains("cur"))		app_p.openFilters.append("Windows Cursor Files (*.cur)");
167 	if (qtFormats.contains("icns"))		app_p.openFilters.append("Apple Icon Image (*.icns)");
168 	if (qtFormats.contains("svgz"))		app_p.openFilters.append("Scalable Vector Graphics (*.svg *.svgz)");
169 	if (qtFormats.contains("avifs"))	app_p.openFilters.append("AVIF image sequence (*.avifs)");
170 
171 #ifndef Q_OS_WIN
172 	if (qtFormats.contains("ico"))		app_p.openFilters.append("Icon Files (*.ico)");
173 #endif
174 
175 #ifdef WITH_LIBRAW
176 	// raw format
177 	app_p.rawFilters.append("Nikon Raw (*.nef *.nrw)");
178 	app_p.rawFilters.append("Canon Raw (*.crw *.cr2 *.cr3)");
179 	app_p.rawFilters.append("Sony Raw (*.arw)");
180 	app_p.rawFilters.append("Digital Negativ (*.dng)");
181 	app_p.rawFilters.append("Panasonic Raw (*.raw *.rw2)");
182 	app_p.rawFilters.append("Minolta Raw (*.mrw)");
183 	app_p.rawFilters.append("Samsung Raw (*.srw)");
184 	app_p.rawFilters.append("Olympus Raw (*.orf)");
185 	app_p.rawFilters.append("Hasselblad Raw (*.3fr)");
186 	app_p.rawFilters.append("Sigma Raw (*.x3f)");
187 	app_p.rawFilters.append("Leaf Raw (*.mos)");
188 	app_p.rawFilters.append("Pentax Raw (*.pef)");
189 	app_p.rawFilters.append("Phase One (*.iiq)");
190 	app_p.rawFilters.append("Fujifilm Raw (*.raf)");
191 
192 	app_p.openFilters += app_p.rawFilters;
193 #endif
194 
195 	// stereo formats
196 	app_p.openFilters.append("JPEG Stereo (*.jps)");
197 	app_p.openFilters.append("PNG Stereo (*.pns)");
198 	app_p.openFilters.append("Multi Picture Object (*.mpo)");
199 
200 	// other formats
201 	app_p.openFilters.append("Adobe Photoshop (*.psd)");
202 	app_p.openFilters.append("Large Document Format (*.psb)");
203 
204 	// archive formats
205 	app_p.containerFilters.append("ZIP Archive (*.zip)");
206 	app_p.containerFilters.append("Microsoft Word Document (*.docx)");
207 	app_p.containerFilters.append("Microsoft PowerPoint Document (*.pptx)");
208 	app_p.containerFilters.append("Microsoft Excel Document (*.xlsx)");
209 	app_p.containerFilters.append("Comic Book Archive (*.cbz)");
210 	app_p.containerFilters.append("Krita (*.kra)");
211 
212 	app_p.openFilters += app_p.containerFilters;
213 
214 	app_p.containerRawFilters = "*.docx *.pptx *.xlsx *.zip";
215 
216     // exif filter as reported in #518 - afaik this is not a standard (typically it contains jpg/tiff)
217     app_p.openFilters.append("EXIF (*.exif)");
218 
219 	// finally: fabians filter & OpenCV vecs
220 	app_p.openFilters.append("OpenCV Haar Training (*.vec)");
221 	app_p.openFilters.append("Rohkost (*.roh)");
222 
223     // drif images
224     app_p.openFilters.append("Developers Raw Image Format (*.drif)");
225 
226 	// load user filters
227 	DefaultSettings settings;
228 	app_p.openFilters += settings.value("ResourceSettings/userFilters", QStringList()).toStringList();
229 
230 	for (int idx = 0; idx < app_p.openFilters.size(); idx++) {
231 
232 		QString cFilter = app_p.openFilters[idx];
233 		cFilter = cFilter.section(QRegExp("(\\(|\\))"), 1);
234 		cFilter = cFilter.replace(")", "");
235 		app_p.fileFilters += cFilter.split(" ");
236 	}
237 
238 	QString allFilters = app_p.fileFilters.join(" ");
239 
240 	// add unknown formats from Qt plugins
241 	for (int idx = 0; idx < qtFormats.size(); idx++) {
242 
243 		if (!allFilters.contains(qtFormats.at(idx))) {
244 			app_p.openFilters.append("Image Format (*." + qtFormats.at(idx) + ")");
245 			app_p.fileFilters.append("*." + qtFormats.at(idx));
246 		}
247 	}
248 
249 	app_p.openFilters.prepend("Image Files (" + app_p.fileFilters.join(" ") + ")");
250 
251 //#ifdef Q_OS_WIN
252 //	app_p.fileFilters.append("*.lnk");
253 //#endif
254 
255 }
256 
loadTranslation(const QString & fileName,QTranslator & translator)257 void DkSettings::loadTranslation(const QString& fileName, QTranslator& translator) {
258 
259 	QStringList translationDirs = getTranslationDirs();
260 
261 	for (int idx = 0; idx < translationDirs.size(); idx++) {
262 
263 		if (translator.load(fileName, translationDirs[idx])) {
264 			qDebugClean() << "translation loaded from: " << translationDirs[idx] << "/" << fileName;
265 			break;
266 		}
267 	}
268 }
269 
getTranslationDirs()270 QStringList DkSettings::getTranslationDirs() {
271 
272 	QStringList trDirs;
273 	trDirs << DkUtils::getTranslationPath();
274 	trDirs << qApp->applicationDirPath();
275 
276 	QStringList rDirs;
277 	rDirs << qApp->applicationDirPath();
278 	rDirs << QStandardPaths::standardLocations(QStandardPaths::DataLocation);
279 
280 	for (const QString& d : rDirs)
281 		trDirs << d + QDir::separator() + "translations";
282 
283 	trDirs.removeDuplicates();
284 
285 	return trDirs;
286 }
287 
load()288 void DkSettings::load() {
289 
290 	DefaultSettings s;
291 	load(s);
292 }
293 
load(QSettings & settings,bool defaults)294 void DkSettings::load(QSettings& settings, bool defaults) {
295 
296 	applyDefaultsFromFile();	// copies entries from "default.ini" to the user settings file
297 	setToDefaultSettings();
298 	qInfoClean() << "loading settings from: " << settings.fileName();
299 
300 	settings.beginGroup("AppSettings");
301 
302 	app_p.showMenuBar = settings.value("showMenuBar", app_p.showMenuBar).toBool();
303 	app_p.showToolBar = settings.value("showToolBar", app_p.showToolBar).toBool();
304 	app_p.showStatusBar = settings.value("showStatusBar", app_p.showStatusBar).toBool();
305 
306 	QBitArray tmpShow = settings.value("showFileInfoLabel", app_p.showFileInfoLabel).toBitArray();
307 	if (tmpShow.size() == app_p.showFileInfoLabel.size())
308 		app_p.showFileInfoLabel = tmpShow;
309 	tmpShow = settings.value("showScroller", app_p.showScroller).toBitArray();
310 	if (tmpShow.size() == app_p.showScroller.size())
311 		app_p.showScroller = tmpShow;
312 	tmpShow = settings.value("showFilePreview", app_p.showFilePreview).toBitArray();
313 	if (tmpShow.size() == app_p.showFilePreview.size())
314 		app_p.showFilePreview = tmpShow;
315 	tmpShow = settings.value("showMetaData", app_p.showMetaData).toBitArray();
316 	if (tmpShow.size() == app_p.showMetaData.size())
317 		app_p.showMetaData = tmpShow;
318 	tmpShow = settings.value("showPlayer", app_p.showPlayer).toBitArray();
319 	if (tmpShow.size() == app_p.showPlayer.size())
320 		app_p.showPlayer = tmpShow;
321 	tmpShow = settings.value("showHistogram", app_p.showHistogram).toBitArray();
322 	if (tmpShow.size() == app_p.showHistogram.size())
323 		app_p.showHistogram = tmpShow;
324 	tmpShow = settings.value("showOverview", app_p.showOverview).toBitArray();
325 	if (tmpShow.size() == app_p.showOverview.size())
326 		app_p.showOverview = tmpShow;
327 	tmpShow = settings.value("showComment", app_p.showComment).toBitArray();
328 	if (tmpShow.size() == app_p.showComment.size())
329 		app_p.showComment = tmpShow;
330 	tmpShow = settings.value("showExplorer", app_p.showExplorer).toBitArray();
331 	if (tmpShow.size() == app_p.showExplorer.size())
332 		app_p.showExplorer = tmpShow;
333 	tmpShow = settings.value("showMetaDataDock", app_p.showMetaDataDock).toBitArray();
334 	if (tmpShow.size() == app_p.showMetaDataDock.size())
335 		app_p.showMetaDataDock = tmpShow;
336 	tmpShow = settings.value("showEditDock", app_p.showEditDock).toBitArray();
337 	if (tmpShow.size() == app_p.showEditDock.size())
338 		app_p.showEditDock = tmpShow;
339 	tmpShow = settings.value("showHistoryDock", app_p.showHistoryDock).toBitArray();
340 	if (tmpShow.size() == app_p.showHistoryDock.size())
341 		app_p.showHistoryDock = tmpShow;
342 	tmpShow = settings.value("showLogDock", app_p.showLogDock).toBitArray();
343 	if (tmpShow.size() == app_p.showLogDock.size())
344 		app_p.showLogDock = tmpShow;
345 
346 	app_p.hideAllPanels = settings.value("hideAllPanels", app_p.hideAllPanels).toBool();
347 	app_p.closeOnEsc = settings.value("closeOnEsc", app_p.closeOnEsc).toBool();
348 	app_p.showRecentFiles = settings.value("showRecentFiles", app_p.showRecentFiles).toBool();
349 	app_p.useLogFile = settings.value("useLogFile", app_p.useLogFile).toBool();
350 	app_p.defaultJpgQuality = settings.value("defaultJpgQuality", app_p.defaultJpgQuality).toInt();
351 
352 	QStringList tmpFileFilters = app_p.fileFilters;
353 	QStringList tmpContainerFilters = app_p.containerRawFilters.split(" ");
354 	for (int idx = 0; idx < tmpContainerFilters.size(); idx++) {
355 		tmpFileFilters.removeAll(tmpContainerFilters.at(idx));
356 	}
357 	app_p.browseFilters = settings.value("browseFilters", tmpFileFilters).toStringList();
358 
359 	// double-check (if user removes all filters he can't browse anymore - so override this case)
360 	if (app_p.browseFilters.empty())
361 		app_p.browseFilters = tmpFileFilters;
362 
363 	app_p.registerFilters = settings.value("registerFilters", app_p.registerFilters).toStringList();
364 	app_p.advancedSettings = settings.value("advancedSettings", app_p.advancedSettings).toBool();
365 
366 	settings.endGroup();
367 	// Global Settings --------------------------------------------------------------------
368 	settings.beginGroup("GlobalSettings");
369 
370 	global_p.skipImgs = settings.value("skipImgs", global_p.skipImgs).toInt();
371 	global_p.checkOpenDuplicates = settings.value("checkOpenDuplicates", global_p.checkOpenDuplicates).toBool();
372 	global_p.extendedTabs = settings.value("extendedTabs", global_p.extendedTabs).toBool();
373 
374 	global_p.loop = settings.value("loop", global_p.loop).toBool();
375 	global_p.scanSubFolders = settings.value("scanRecursive", global_p.scanSubFolders).toBool();
376 	global_p.lastDir = settings.value("lastDir", global_p.lastDir).toString();
377 	global_p.searchHistory = settings.value("searchHistory", global_p.searchHistory).toStringList();
378 	global_p.recentFolders = settings.value("recentFolders", global_p.recentFolders).toStringList();
379 	global_p.pinnedFiles = settings.value("pinnedFiles", global_p.pinnedFiles).toStringList();
380 	global_p.recentFiles = settings.value("recentFiles", global_p.recentFiles).toStringList();
381 	global_p.logRecentFiles = settings.value("logRecentFiles", global_p.logRecentFiles).toBool();
382 	global_p.askToSaveDeletedFiles = settings.value("askToSaveDeletedFiles", global_p.askToSaveDeletedFiles).toBool();
383 	global_p.tmpPath = settings.value("tmpPath", global_p.tmpPath).toString();
384 	global_p.language = settings.value("language", global_p.language).toString();
385 	global_p.numThreads = settings.value("numThreads", global_p.numThreads).toInt();
386 
387 	global_p.sortMode = settings.value("sortMode", global_p.sortMode).toInt();
388 	global_p.sortDir = settings.value("sortDir", global_p.sortDir).toInt();
389 	global_p.setupPath = settings.value("setupPath", global_p.setupPath).toString();
390 	global_p.setupVersion = settings.value("setupVersion", global_p.setupVersion).toString();
391 	global_p.zoomOnWheel = settings.value("zoomOnWheel", global_p.zoomOnWheel).toBool();
392 	global_p.horZoomSkips = settings.value("horZoomSkips", global_p.horZoomSkips).toBool();
393 	global_p.doubleClickForFullscreen = settings.value("doubleClickForFullscreen", global_p.doubleClickForFullscreen).toBool();
394 	global_p.showBgImage = settings.value("showBgImage", global_p.showBgImage).toBool();
395 
396 	settings.endGroup();
397 	// Display Settings --------------------------------------------------------------------
398 	settings.beginGroup("DisplaySettings");
399 
400 	display_p.keepZoom = settings.value("keepZoom", display_p.keepZoom).toInt();
401 	display_p.invertZoom = settings.value("invertZoom", display_p.invertZoom).toBool();
402 	display_p.zoomToFit = settings.value("zoomToFit", display_p.zoomToFit).toBool();
403 	display_p.highlightColor = QColor::fromRgba(settings.value("highlightColorRGBA", display_p.highlightColor.rgba()).toInt());
404 	display_p.hudBgColor = QColor::fromRgba(settings.value("bgColorWidgetRGBA", display_p.hudBgColor.rgba()).toInt());
405 	display_p.hudFgdColor = QColor::fromRgba(settings.value("fontColorRGBA", display_p.hudFgdColor.rgba()).toInt());
406 	display_p.bgColor = QColor::fromRgba(settings.value("bgColorNoMacsRGBA", display_p.bgColor.rgba()).toInt());
407 	display_p.iconColor = QColor::fromRgba(settings.value("iconColorRGBA", display_p.iconColor.rgba()).toInt());
408 	display_p.bgColorFrameless = QColor::fromRgba(settings.value("bgColorFramelessRGBA", display_p.bgColorFrameless.rgba()).toInt());
409 	display_p.thumbSize = settings.value("thumbSize", display_p.thumbSize).toInt();
410 	display_p.iconSize = settings.value("iconSize", display_p.iconSize).toInt();
411 	display_p.thumbPreviewSize = settings.value("thumbPreviewSize", display_p.thumbPreviewSize).toInt();
412 	//display_p.saveThumb = settings.value("saveThumb", display_p.saveThumb).toBool();
413 	display_p.antiAliasing = settings.value("antiAliasing", display_p.antiAliasing).toBool();
414 	display_p.highQualityAntiAliasing = settings.value("highQualityAntiAliasing", display_p.highQualityAntiAliasing).toBool();
415 	display_p.showCrop = settings.value("showCrop", display_p.showCrop).toBool();
416 	display_p.histogramStyle = settings.value("histogramStyle", display_p.histogramStyle).toInt();
417 	display_p.tpPattern = settings.value("tpPattern", display_p.tpPattern).toBool();
418 	display_p.showNavigation = settings.value("showNavigation", display_p.showNavigation).toBool();
419 	display_p.themeName = settings.value("themeName312", display_p.themeName).toString();
420 	display_p.showBorder = settings.value("showBorder", display_p.showBorder).toBool();
421 	display_p.displaySquaredThumbs = settings.value("displaySquaredThumbs", display_p.displaySquaredThumbs).toBool();
422 	display_p.showThumbLabel = settings.value("showThumbLabel", display_p.showThumbLabel).toBool();
423 	display_p.showScrollBars = settings.value("showScrollBars", display_p.showScrollBars).toBool();
424 	display_p.animationDuration = settings.value("fadeSec", display_p.animationDuration).toFloat();
425 	display_p.alwaysAnimate = settings.value("alwaysAnimate", display_p.alwaysAnimate).toBool();
426 	display_p.transition = (TransitionMode)settings.value("transition", display_p.transition).toInt();
427 	display_p.defaultBackgroundColor = settings.value("useDefaultColor", display_p.defaultBackgroundColor).toBool();
428 	display_p.defaultIconColor = settings.value("defaultIconColor", display_p.defaultIconColor).toBool();
429 	display_p.interpolateZoomLevel = settings.value("interpolateZoomlevel", display_p.interpolateZoomLevel).toInt();
430 
431 	settings.endGroup();
432 	// MetaData Settings --------------------------------------------------------------------
433 	settings.beginGroup("MetaDataSettings");
434 
435 	meta_p.ignoreExifOrientation = settings.value("ignoreExifOrientation", meta_p.ignoreExifOrientation).toBool();
436 	meta_p.saveExifOrientation = settings.value("saveExifOrientation", meta_p.saveExifOrientation).toBool();
437 
438 	settings.endGroup();
439 	// SlideShow Settings --------------------------------------------------------------------
440 	settings.beginGroup("SlideShowSettings");
441 
442 	slideShow_p.filter = settings.value("filter", slideShow_p.filter).toInt();
443 	slideShow_p.time = settings.value("time", slideShow_p.time).toFloat();
444 	slideShow_p.showPlayer = settings.value("showPlayer", slideShow_p.showPlayer).toBool();
445 	slideShow_p.moveSpeed = settings.value("moveSpeed", slideShow_p.moveSpeed).toFloat();
446 	slideShow_p.backgroundColor = QColor::fromRgba(settings.value("backgroundColorRGBA", slideShow_p.backgroundColor.rgba()).toInt());
447 	slideShow_p.silentFullscreen = settings.value("silentFullscreen", slideShow_p.silentFullscreen).toBool();
448 	QBitArray tmpDisplay = settings.value("display", slideShow_p.display).toBitArray();
449 
450 	if (tmpDisplay.size() == slideShow_p.display.size())
451 		slideShow_p.display = tmpDisplay;
452 
453 	settings.endGroup();
454 	// Synchronize Settings --------------------------------------------------------------------
455 	settings.beginGroup("SynchronizeSettings");
456 
457 	sync_p.checkForUpdates = settings.value("checkForUpdates", sync_p.checkForUpdates).toBool();
458 	sync_p.disableUpdateInteraction = settings.value("disableUpdateInteraction", sync_p.disableUpdateInteraction).toBool();
459 	sync_p.updateDialogShown = settings.value("updateDialogShown", sync_p.updateDialogShown).toBool();
460 	sync_p.lastUpdateCheck = settings.value("lastUpdateCheck", sync_p.lastUpdateCheck).toDate();
461 	sync_p.syncAbsoluteTransform = settings.value("syncAbsoluteTransform", sync_p.syncAbsoluteTransform).toBool();
462 	sync_p.switchModifier = settings.value("switchModifier", sync_p.switchModifier).toBool();
463 	sync_p.syncActions = settings.value("syncActions", sync_p.syncActions).toBool();
464 
465 	settings.endGroup();
466 	// Resource Settings --------------------------------------------------------------------
467 	settings.beginGroup("ResourceSettings");
468 
469 	resources_p.cacheMemory = settings.value("cacheMemory", resources_p.cacheMemory).toFloat();
470 	resources_p.historyMemory = settings.value("historyMemory", resources_p.historyMemory).toFloat();
471 	resources_p.nativeDialog = settings.value("nativeDialog", resources_p.nativeDialog).toBool();
472 	resources_p.maxImagesCached = settings.value("maxImagesCached", resources_p.maxImagesCached).toInt();
473 	resources_p.waitForLastImg = settings.value("waitForLastImg", resources_p.waitForLastImg).toBool();
474 	resources_p.filterRawImages = settings.value("filterRawImages", resources_p.filterRawImages).toBool();
475 	resources_p.loadRawThumb = settings.value("loadRawThumb", resources_p.loadRawThumb).toInt();
476 	resources_p.filterDuplicats = settings.value("filterDuplicates", resources_p.filterDuplicats).toBool();
477 	resources_p.preferredExtension = settings.value("preferredExtension", resources_p.preferredExtension).toString();
478 	resources_p.gammaCorrection = settings.value("gammaCorrection", resources_p.gammaCorrection).toBool();
479 	resources_p.loadSavedImage = settings.value("loadSavedImage", resources_p.loadSavedImage).toInt();
480 
481 	if (sync_p.switchModifier) {
482 		global_p.altMod = Qt::ControlModifier;
483 		global_p.ctrlMod = Qt::AltModifier;
484 	}
485 	else {
486 		global_p.altMod = Qt::AltModifier;
487 		global_p.ctrlMod = Qt::ControlModifier;
488 	}
489 
490 	settings.endGroup();
491 
492 	if (global_p.numThreads != -1)
493 		QThreadPool::globalInstance()->setMaxThreadCount(global_p.numThreads);
494 	else
495 		global_p.numThreads = QThreadPool::globalInstance()->maxThreadCount();
496 
497 	// keep loaded settings in mind
498 	if (defaults) {
499 		app_d = app_p;
500 		global_d = global_p;
501 		display_d = display_p;
502 		slideShow_d = slideShow_p;
503 		sync_d = sync_p;
504 		meta_d = meta_p;
505 		resources_d = resources_p;
506 	}
507 }
508 
save(bool force)509 void DkSettings::save(bool force) {
510 	DefaultSettings s;
511 	save(s, force);
512 }
513 
save(QSettings & settings,bool force)514 void DkSettings::save(QSettings& settings, bool force) {
515 
516 	if (DkSettingsManager::param().app().privateMode)
517 		return;
518 
519 	settings.beginGroup("AppSettings");
520 	if (force ||app_p.showMenuBar != app_d.showMenuBar)
521 		settings.setValue("showMenuBar", app_p.showMenuBar);
522 
523 	if (app_p.currentAppMode != mode_frameless && app_p.currentAppMode != mode_frameless_fullscreen) {
524 
525 		if (force ||app_p.showToolBar != app_d.showToolBar)
526 			settings.setValue("showToolBar", app_p.showToolBar);
527 
528 		if (force ||app_p.showStatusBar != app_d.showStatusBar)
529 			settings.setValue("showStatusBar", app_p.showStatusBar);
530 	}
531 
532 	if (force ||app_p.showFileInfoLabel != app_d.showFileInfoLabel)
533 		settings.setValue("showFileInfoLabel", app_p.showFileInfoLabel);
534 	if (force ||app_p.showFilePreview != app_d.showFilePreview)
535 		settings.setValue("showFilePreview", app_p.showFilePreview);
536 	if (force ||app_p.showScroller != app_d.showScroller)
537 		settings.setValue("showScroller", app_p.showScroller);
538 	if (force ||app_p.showMetaData != app_d.showMetaData)
539 		settings.setValue("showMetaData", app_p.showMetaData);
540 	if (force ||app_p.showPlayer != app_d.showPlayer)
541 		settings.setValue("showPlayer", app_p.showPlayer);
542 	if (force ||app_p.showHistogram != app_d.showHistogram)
543 		settings.setValue("showHistogram", app_p.showHistogram);
544 	if (force ||app_p.showComment != app_d.showComment)
545 		settings.setValue("showComment", app_p.showComment);
546 	if (force ||app_p.showOverview != app_d.showOverview)
547 		settings.setValue("showOverview", app_p.showOverview);
548 	if (force ||app_p.showExplorer != app_d.showExplorer)
549 		settings.setValue("showExplorer", app_p.showExplorer);
550 	if (force ||app_p.showMetaDataDock != app_d.showMetaDataDock)
551 		settings.setValue("showMetaDataDock", app_p.showMetaDataDock);
552 	if (force ||app_p.showEditDock != app_d.showEditDock)
553 		settings.setValue("showEditDock", app_p.showEditDock);
554 	if (force ||app_p.showHistoryDock != app_d.showHistoryDock)
555 		settings.setValue("showHistoryDock", app_p.showHistoryDock);
556 	if (force || app_p.showLogDock != app_d.showLogDock)
557 		settings.setValue("showLogDock", app_p.showLogDock);
558 	if (force || app_p.hideAllPanels != app_d.hideAllPanels)
559 		settings.setValue("hideAllPanels", app_p.hideAllPanels);
560 	if (force ||app_p.advancedSettings != app_d.advancedSettings)
561 		settings.setValue("advancedSettings", app_p.advancedSettings);
562 	if (force ||app_p.closeOnEsc != app_d.closeOnEsc)
563 		settings.setValue("closeOnEsc", app_p.closeOnEsc);
564 	if (force ||app_p.showRecentFiles != app_d.showRecentFiles)
565 		settings.setValue("showRecentFiles", app_p.showRecentFiles);
566 	if (force ||app_p.useLogFile != app_d.useLogFile)
567 		settings.setValue("useLogFile", app_p.useLogFile);
568 	if (force ||app_p.browseFilters != app_d.browseFilters)
569 		settings.setValue("browseFilters", app_p.browseFilters);
570 	if (force ||app_p.registerFilters != app_d.registerFilters)
571 		settings.setValue("registerFilters", app_p.registerFilters);
572 
573 	// always save (user setting)
574 	settings.setValue("defaultJpgQuality", app_p.defaultJpgQuality);
575 	settings.setValue("appMode", app_p.appMode);
576 	settings.setValue("currentAppMode", app_p.currentAppMode);
577 
578 	settings.endGroup();
579 	// Global Settings --------------------------------------------------------------------
580 	settings.beginGroup("GlobalSettings");
581 
582 	if (force ||global_p.skipImgs != global_d.skipImgs)
583 		settings.setValue("skipImgs",global_p.skipImgs);
584 	if (force ||global_p.checkOpenDuplicates != global_d.checkOpenDuplicates)
585 		settings.setValue("checkOpenDuplicates",global_p.checkOpenDuplicates);
586 	if (force ||global_p.extendedTabs != global_d.extendedTabs)
587 		settings.setValue("extendedTabs", global_p.extendedTabs);
588 	if (force ||global_p.loop != global_d.loop)
589 		settings.setValue("loop",global_p.loop);
590 	if (force ||global_p.scanSubFolders != global_d.scanSubFolders)
591 		settings.setValue("scanRecursive",global_p.scanSubFolders);
592 	if (force ||global_p.lastDir != global_d.lastDir)
593 		settings.setValue("lastDir", global_p.lastDir);
594 	if (force ||global_p.searchHistory != global_d.searchHistory)
595 		settings.setValue("searchHistory", global_p.searchHistory);
596 	if (force ||global_p.recentFolders != global_d.recentFolders)
597 		settings.setValue("recentFolders", global_p.recentFolders);
598 	if (force ||global_p.recentFiles != global_d.recentFiles)
599 		settings.setValue("recentFiles", global_p.recentFiles);
600 	if (force || global_p.pinnedFiles != global_d.pinnedFiles)
601 		settings.setValue("pinnedFiles", global_p.pinnedFiles);
602 	if (force ||global_p.logRecentFiles != global_d.logRecentFiles)
603 		settings.setValue("logRecentFiles", global_p.logRecentFiles);
604 	if (force ||global_p.askToSaveDeletedFiles != global_d.askToSaveDeletedFiles)
605 		settings.setValue("askToSaveDeletedFiles", global_p.askToSaveDeletedFiles);
606 	if (force ||global_p.tmpPath != global_d.tmpPath)
607 		settings.setValue("tmpPath", global_p.tmpPath);
608 	if (force ||global_p.language != global_d.language)
609 		settings.setValue("language", global_p.language);
610 	if (force ||global_p.numThreads != global_d.numThreads)
611 		settings.setValue("numThreads", global_p.numThreads);
612 	if (force ||global_p.sortMode != global_d.sortMode)
613 		settings.setValue("sortMode", global_p.sortMode);
614 	if (force ||global_p.sortDir != global_d.sortDir)
615 		settings.setValue("sortDir", global_p.sortDir);
616 	if (force ||global_p.setupPath != global_d.setupPath)
617 		settings.setValue("setupPath", global_p.setupPath);
618 	if (force ||global_p.setupVersion != global_d.setupVersion)
619 		settings.setValue("setupVersion", global_p.setupVersion);
620 	if (force ||global_p.zoomOnWheel != global_d.zoomOnWheel)
621 		settings.setValue("zoomOnWheel", global_p.zoomOnWheel);
622 	if (force ||global_p.horZoomSkips != global_d.horZoomSkips)
623 		settings.setValue("horZoomSkips", global_p.horZoomSkips);
624 	if (force ||global_p.doubleClickForFullscreen != global_d.doubleClickForFullscreen)
625 		settings.setValue("doubleClickForFullscreen", global_p.doubleClickForFullscreen);
626 	if (force ||global_p.showBgImage != global_d.showBgImage)
627 		settings.setValue("showBgImage", global_p.showBgImage);
628 
629 	settings.endGroup();
630 	// Display Settings --------------------------------------------------------------------
631 	settings.beginGroup("DisplaySettings");
632 
633 	if (force ||display_p.keepZoom != display_d.keepZoom)
634 		settings.setValue("keepZoom",display_p.keepZoom);
635 	if (force ||display_p.invertZoom != display_d.invertZoom)
636 		settings.setValue("invertZoom",display_p.invertZoom);
637 	if (force ||display_p.zoomToFit != display_d.zoomToFit)
638 		settings.setValue("zoomToFit",display_p.zoomToFit);
639 	if (force ||display_p.highlightColor != display_d.highlightColor)
640 		settings.setValue("highlightColorRGBA", display_p.highlightColor.rgba());
641 	if (force ||display_p.hudBgColor != display_d.hudBgColor)
642 		settings.setValue("bgColorWidgetRGBA", display_p.hudBgColor.rgba());
643 	if (force ||display_p.hudFgdColor != display_d.hudFgdColor)
644 		settings.setValue("fontColorRGBA", display_p.hudFgdColor.rgba());
645 	if (force || display_p.bgColor != display_d.bgColor)
646 		settings.setValue("bgColorNoMacsRGBA", display_p.bgColor.rgba());
647 	if (force ||display_p.iconColor != display_d.iconColor)
648 		settings.setValue("iconColorRGBA", display_p.iconColor.rgba());
649 	if (force ||display_p.bgColorFrameless != display_d.bgColorFrameless)
650 		settings.setValue("bgColorFramelessRGBA", display_p.bgColorFrameless.rgba());
651 	if (force ||display_p.thumbSize != display_d.thumbSize)
652 		settings.setValue("thumbSize", display_p.thumbSize);
653 	if (force ||display_p.iconSize != display_d.iconSize)
654 		settings.setValue("iconSize", display_p.iconSize);
655 	if (force ||display_p.thumbPreviewSize != display_d.thumbPreviewSize)
656 		settings.setValue("thumbPreviewSize", display_p.thumbPreviewSize);
657 	//if (force ||display_p.saveThumb != display_d.saveThumb)
658 	//	settings.setValue("saveThumb", display_p.saveThumb);
659 	if (force ||display_p.antiAliasing != display_d.antiAliasing)
660 		settings.setValue("antiAliasing", display_p.antiAliasing);
661 	if (force || display_p.highQualityAntiAliasing != display_d.highQualityAntiAliasing)
662 		settings.setValue("highQualityAntiAliasing", display_p.highQualityAntiAliasing);
663 	if (force ||display_p.showCrop != display_d.showCrop)
664 		settings.setValue("showCrop", display_p.showCrop);
665 	if (force ||display_p.histogramStyle != display_d.histogramStyle)
666 		settings.setValue("histogramStyle", display_p.histogramStyle);
667 	if (force ||display_p.tpPattern != display_d.tpPattern)
668 		settings.setValue("tpPattern", display_p.tpPattern);
669 	if (force || display_p.showNavigation != display_d.showNavigation)
670 		settings.setValue("showNavigation", display_p.showNavigation);
671 	if (force || display_p.themeName != display_d.themeName)
672 		settings.setValue("themeName312", display_p.themeName);
673 	if (force ||display_p.showBorder != display_d.showBorder)
674 		settings.setValue("showBorder", display_p.showBorder);
675 	if (force ||display_p.displaySquaredThumbs != display_d.displaySquaredThumbs)
676 		settings.setValue("displaySquaredThumbs", display_p.displaySquaredThumbs);
677 	if (force ||display_p.showThumbLabel != display_d.showThumbLabel)
678 		settings.setValue("showThumbLabel", display_p.showThumbLabel);
679 	if (force || display_p.showScrollBars != display_d.showScrollBars)
680 		settings.setValue("showScrollBars", display_p.showScrollBars);
681 	if (force ||display_p.alwaysAnimate != display_d.alwaysAnimate)
682 		settings.setValue("alwaysAnimate", display_p.alwaysAnimate);
683 	if (force ||display_p.animationDuration != display_d.animationDuration)
684 		settings.setValue("fadeSec", display_p.animationDuration);
685 	if (force ||display_p.transition != display_d.transition)
686 		settings.setValue("transition", display_p.transition);
687 	if (force ||display_p.defaultBackgroundColor != display_d.defaultBackgroundColor)
688 		settings.setValue("useDefaultColor", display_p.defaultBackgroundColor);
689 	if (force ||display_p.defaultIconColor != display_d.defaultIconColor)
690 		settings.setValue("defaultIconColor", display_p.defaultIconColor);
691 	if (force ||display_p.interpolateZoomLevel != display_d.interpolateZoomLevel)
692 		settings.setValue("interpolateZoomlevel", display_p.interpolateZoomLevel);
693 
694 	settings.endGroup();
695 	// MetaData Settings --------------------------------------------------------------------
696 	settings.beginGroup("MetaDataSettings");
697 
698 	if (force ||meta_p.ignoreExifOrientation != meta_d.ignoreExifOrientation)
699 		settings.setValue("ignoreExifOrientation", meta_p.ignoreExifOrientation);
700 	if (force ||meta_p.saveExifOrientation != meta_d.saveExifOrientation)
701 		settings.setValue("saveExifOrientation", meta_p.saveExifOrientation);
702 
703 	settings.endGroup();
704 	// SlideShow Settings --------------------------------------------------------------------
705 	settings.beginGroup("SlideShowSettings");
706 
707 	if (force ||slideShow_p.filter != slideShow_d.filter)
708 		settings.setValue("filter", slideShow_p.filter);
709 	if (force ||slideShow_p.time != slideShow_d.time)
710 		settings.setValue("time", slideShow_p.time);
711 	if (force || slideShow_p.showPlayer != slideShow_d.showPlayer)
712 		settings.setValue("showPlayer", slideShow_p.showPlayer);
713 	if (force ||slideShow_p.moveSpeed != slideShow_d.moveSpeed)
714 		settings.setValue("moveSpeed", slideShow_p.moveSpeed);
715 	if (force ||slideShow_p.display != slideShow_d.display)
716 		settings.setValue("display", slideShow_p.display);
717 	if (force ||slideShow_p.backgroundColor != slideShow_d.backgroundColor)
718 		settings.setValue("backgroundColorRGBA", slideShow_p.backgroundColor.rgba());
719 	if (force ||slideShow_p.silentFullscreen != slideShow_d.silentFullscreen)
720 		settings.setValue("silentFullscreen", slideShow_p.silentFullscreen);
721 
722 	settings.endGroup();
723 	// Sync Settings --------------------------------------------------------------------
724 	settings.beginGroup("SynchronizeSettings");
725 
726 	//if (force ||sync_p.checkForUpdates != sync_d.checkForUpdates)
727 		settings.setValue("checkForUpdates", sync_p.checkForUpdates);
728 	//if (force || sync_p.disableUpdateInteraction != sync_d.disableUpdateInteraction)
729 		settings.setValue("disableUpdateInteraction", sync_p.disableUpdateInteraction);
730 	if (force ||sync_p.updateDialogShown != sync_d.updateDialogShown)
731 		settings.setValue("updateDialogShown", sync_p.updateDialogShown);
732 	if (force ||sync_p.lastUpdateCheck != sync_d.lastUpdateCheck)
733 		settings.setValue("lastUpdateCheck", sync_p.lastUpdateCheck);
734 	if (force ||sync_p.syncAbsoluteTransform != sync_d.syncAbsoluteTransform)
735 		settings.setValue("syncAbsoluteTransform", sync_p.syncAbsoluteTransform);
736 	if (force ||sync_p.switchModifier != sync_d.switchModifier)
737 		settings.setValue("switchModifier", sync_p.switchModifier);
738 	if (force ||sync_p.syncActions != sync_d.syncActions)
739 		settings.setValue("syncActions", sync_p.syncActions);
740 
741 	settings.endGroup();
742 	// Resource Settings --------------------------------------------------------------------
743 	settings.beginGroup("ResourceSettings");
744 
745 	if (force ||resources_p.cacheMemory != resources_d.cacheMemory)
746 		settings.setValue("cacheMemory", resources_p.cacheMemory);
747 	if (force ||resources_p.historyMemory != resources_d.historyMemory)
748 		settings.setValue("historyMemory", resources_p.historyMemory);
749 	if (force || resources_p.nativeDialog != resources_d.nativeDialog)
750 		settings.setValue("nativeDialog", resources_p.nativeDialog);
751 	if (force ||resources_p.maxImagesCached != resources_d.maxImagesCached)
752 		settings.setValue("maxImagesCached", resources_p.maxImagesCached);
753 	if (force ||resources_p.waitForLastImg != resources_d.waitForLastImg)
754 		settings.setValue("waitForLastImg", resources_p.waitForLastImg);
755 	if (force ||resources_p.filterRawImages != resources_d.filterRawImages)
756 		settings.setValue("filterRawImages", resources_p.filterRawImages);
757 	if (force ||resources_p.loadRawThumb != resources_d.loadRawThumb)
758 		settings.setValue("loadRawThumb", resources_p.loadRawThumb);
759 	if (force ||resources_p.filterDuplicats != resources_d.filterDuplicats)
760 		settings.setValue("filterDuplicates", resources_p.filterDuplicats);
761 	if (force ||resources_p.preferredExtension != resources_d.preferredExtension)
762 		settings.setValue("preferredExtension", resources_p.preferredExtension);
763 	if (force ||resources_p.gammaCorrection != resources_d.gammaCorrection)
764 		settings.setValue("gammaCorrection", resources_p.gammaCorrection);
765 	if (force || resources_p.loadSavedImage != resources_d.loadSavedImage)
766 		settings.setValue("loadSavedImage", resources_p.loadSavedImage);
767 
768 	settings.endGroup();
769 
770 	// keep loaded settings in mind
771 	app_d = app_p;
772 	global_d = global_p;
773 	display_d = display_p;
774 	slideShow_d = slideShow_p;
775 	sync_d = sync_p;
776 	meta_d = meta_p;
777 	resources_d = resources_p;
778 
779 	qDebug() << "settings saved to" << settingsPath();
780 }
781 
setToDefaultSettings()782 void DkSettings::setToDefaultSettings() {
783 
784 	app_p.showToolBar = true;
785 	app_p.showStatusBar = false;
786 	app_p.showMovieToolBar = false;
787 	app_p.showFileInfoLabel = QBitArray(mode_end, false);
788 	app_p.showFilePreview = QBitArray(mode_end, false);
789 	app_p.showScroller = QBitArray(mode_end, false);
790 	app_p.showMetaData = QBitArray(mode_end, false);
791 	app_p.showPlayer = QBitArray(mode_end, false);
792 	app_p.showHistogram = QBitArray(mode_end, false);
793 	app_p.showComment = QBitArray(mode_end, false);
794 	app_p.showOverview = QBitArray(mode_end, false);
795 	app_p.showExplorer = QBitArray(mode_end, false);
796 	app_p.showMetaDataDock = QBitArray(mode_end, false);
797 	app_p.showEditDock = QBitArray(mode_end, false);
798 	app_p.showHistoryDock = QBitArray(mode_end, false);
799 	app_p.showLogDock = QBitArray(mode_end, false);
800 	app_p.advancedSettings = false;
801 	app_p.closeOnEsc = false;
802 	app_p.hideAllPanels = false;
803 	app_p.showRecentFiles = true;
804 	app_p.browseFilters = QStringList();
805 	app_p.showMenuBar = true;
806 	app_p.useLogFile = false;
807 
808 	// now set default show options
809 	app_p.showFileInfoLabel.setBit(mode_default, false);
810 	app_p.showFileInfoLabel.setBit(mode_contrast, false);
811 
812 	app_p.appMode = 0;
813 	app_p.privateMode = false;
814 	app_p.defaultJpgQuality = 97;
815 
816 	global_p.skipImgs = 10;
817 	global_p.numFiles = 50;
818 	global_p.checkOpenDuplicates = true;
819 	global_p.extendedTabs = false;
820 	global_p.loop = true;
821 	global_p.scanSubFolders = false;
822 	global_p.lastDir = QString();
823 	global_p.lastSaveDir = QString();
824 	global_p.recentFiles = QStringList();
825 	global_p.pinnedFiles = QStringList();
826 	global_p.searchHistory = QStringList();
827 	global_p.recentFolders = QStringList();
828 	global_p.logRecentFiles = true;
829 	global_p.askToSaveDeletedFiles = false;
830 	global_p.tmpPath = "";
831 	global_p.language = "en";
832 	global_p.setupPath = "";
833 	global_p.setupVersion = "";
834 	global_p.numThreads = -1;
835 	global_p.sortMode = sort_filename;
836 	global_p.sortDir = sort_ascending;
837 	global_p.zoomOnWheel = true;
838 	global_p.horZoomSkips = true;
839 	global_p.doubleClickForFullscreen = true;
840 	global_p.showBgImage = true;
841 
842 #ifdef Q_OS_LINUX
843 	sync_p.switchModifier = true;
844 	global_p.altMod = Qt::ControlModifier;
845 	global_p.ctrlMod = Qt::AltModifier;
846 #else
847 	sync_p.switchModifier = false;
848 	global_p.altMod = Qt::AltModifier;
849 	global_p.ctrlMod = Qt::ControlModifier;
850 #endif
851 
852 	display_p.keepZoom = zoom_keep_same_size;
853 	display_p.invertZoom = false;
854 	display_p.zoomToFit = false;
855 	display_p.highlightColor = QColor(0, 204, 255);
856 	display_p.hudBgColor = QColor(0, 0, 0, 100);
857 	display_p.hudFgdColor = QColor(255, 255, 255);
858 	display_p.bgColor = QColor(100, 100, 100, 255);
859 	display_p.iconColor = QColor(100,100,100,255);
860 	display_p.bgColorFrameless = QColor(0, 0, 0, 180);
861 	display_p.thumbSize = 64;
862 	display_p.iconSize = 16;
863 	display_p.thumbPreviewSize = 64;
864 	display_p.antiAliasing = true;
865 	display_p.highQualityAntiAliasing = false;
866 	display_p.showCrop = false;
867 	display_p.histogramStyle = 0; // DkHistogram::DisplayMode::histogram_mode_simple
868 	display_p.tpPattern = false;
869 	display_p.showNavigation = true;
870 	display_p.themeName = "Light-Theme.css";
871 	display_p.showBorder = false;
872 	display_p.displaySquaredThumbs = true;
873 	display_p.showThumbLabel = false;
874 	display_p.showScrollBars = false;
875 	display_p.animationDuration = 0.5f;
876 	display_p.alwaysAnimate = false;
877 	display_p.transition = trans_swipe;
878 	display_p.defaultBackgroundColor = true;
879 	display_p.defaultIconColor = true;
880 	display_p.interpolateZoomLevel = 200;
881 
882 	slideShow_p.filter = 0;
883 	slideShow_p.time = 3.0;
884 	slideShow_p.showPlayer = true;
885 	slideShow_p.moveSpeed = 0;		// TODO: set to 1 for finishing slideshow
886 	slideShow_p.display = QBitArray(display_end, true);
887 	slideShow_p.backgroundColor = QColor(51, 51, 51, 255);
888 	slideShow_p.silentFullscreen = true;
889 
890 	meta_p.saveExifOrientation = true;
891 	meta_p.ignoreExifOrientation = false;
892 
893 	sync_p.checkForUpdates = !isPortable();	// installed version should only check for updates by default
894 	sync_p.disableUpdateInteraction = isPortable();	// installed version should only check for updates by default
895 	sync_p.updateDialogShown = false;
896 	sync_p.lastUpdateCheck = QDate(2018, 7, 14);	// ; )
897 	sync_p.syncAbsoluteTransform = true;
898 	sync_p.syncActions = false;
899 
900 	resources_p.cacheMemory = 256;
901 	resources_p.historyMemory = 128;
902 	resources_p.nativeDialog = true;
903 	resources_p.maxImagesCached = 5;
904 	resources_p.filterRawImages = true;
905 	resources_p.loadRawThumb = raw_thumb_always;
906 	resources_p.filterDuplicats = false;
907 	resources_p.preferredExtension = "*.jpg";
908 	resources_p.gammaCorrection = true;
909 	resources_p.loadSavedImage = ls_load_to_tab;
910 	resources_p.waitForLastImg = true;
911 
912 	qDebug() << "ok... default settings are set";
913 }
914 
applyDefaultsFromFile()915 void DkSettings::applyDefaultsFromFile() {
916 
917 	DefaultSettings ds;
918 
919 	if (ds.value("firstTime", true).toBool()) {
920 
921 		QString dsf = getDefaultSettingsFile();
922 		if (!QFileInfo(dsf).exists()) {
923 			qInfo() << "I could not find the default settings file: " << dsf;
924 		}
925 
926 		QSettings defaultSettings(dsf, QSettings::IniFormat);
927 		copySettings(defaultSettings, ds);
928 
929 		ds.setValue("firstTime", false);
930 
931 		qInfo() << "defaults loaded from" << dsf;
932 	}
933 }
934 
copySettings(const QSettings & src,QSettings & dst) const935 void DkSettings::copySettings(const QSettings & src, QSettings & dst) const {
936 
937 	// copy default settings
938 	if (src.allKeys().count() > 0) {
939 		QStringList keys = src.allKeys();
940 
941 		for (const QString& key : keys) {
942 			dst.setValue(key, src.value(key));
943 		}
944 	}
945 }
946 
getDefaultSettingsFile() const947 QString DkSettings::getDefaultSettingsFile() const {
948 
949 	return QFileInfo(QCoreApplication::applicationDirPath(), "default.ini").absoluteFilePath();
950 }
951 
setNumThreads(int numThreads)952 void DkSettings::setNumThreads(int numThreads) {
953 
954 	if (numThreads != global_p.numThreads) {
955 		global_p.numThreads = numThreads;
956 		QThreadPool::globalInstance()->setMaxThreadCount(numThreads);
957 	}
958 }
959 
isPortable()960 bool DkSettings::isPortable() {
961 
962 	QFileInfo fi(QCoreApplication::applicationDirPath(), "settings.ini");
963 	return fi.absoluteFilePath() == settingsPath();
964 }
965 
settingsPath() const966 QString DkSettings::settingsPath() const {
967 
968 	if (!mSettingsPath.isEmpty())
969 		return mSettingsPath;
970 
971 	QFileInfo fi(QCoreApplication::applicationDirPath(), "settings.ini");
972 
973 	if (fi.exists())
974 		return fi.absoluteFilePath();
975 
976 	fi = QFileInfo(DkUtils::getAppDataPath(), "settings.ini");
977 
978 	return fi.absoluteFilePath();
979 }
980 
app()981 DkSettings::App & DkSettings::app() {
982 	return app_p;
983 }
984 
global()985 DkSettings::Global & DkSettings::global() {
986 	return global_p;
987 }
988 
display()989 DkSettings::Display & DkSettings::display() {
990 	return display_p;
991 }
992 
slideShow()993 DkSettings::SlideShow & DkSettings::slideShow() {
994 	return slideShow_p;
995 }
996 
sync()997 DkSettings::Sync & DkSettings::sync() {
998 	return sync_p;
999 }
1000 
metaData()1001 DkSettings::MetaData & DkSettings::metaData() {
1002 	return meta_p;
1003 }
1004 
resources()1005 DkSettings::Resources & DkSettings::resources() {
1006 	return resources_p;
1007 }
1008 
DkSettingsManager()1009 DkSettingsManager::DkSettingsManager() {
1010 
1011 	mParams = new DkSettings();
1012 }
1013 
instance()1014 DkSettingsManager& DkSettingsManager::instance() {
1015 	static DkSettingsManager inst;
1016 	return inst;
1017 }
1018 
~DkSettingsManager()1019 DkSettingsManager::~DkSettingsManager() {
1020 
1021 	if (mParams) {
1022 		delete mParams;
1023 		mParams = 0;
1024 	}
1025 }
1026 
param()1027 DkSettings& DkSettingsManager::param() {
1028 	return instance().settings();
1029 }
1030 
settings()1031 DkSettings& DkSettingsManager::settings() {
1032 	return *mParams;
1033 }
1034 
init()1035 void DkSettingsManager::init() {
1036 
1037 	// init settings
1038 	param().initFileFilters();
1039 	DefaultSettings settings;
1040 
1041 	param().load(settings, true);	// load defaults
1042 
1043 	int mode = settings.value("AppSettings/appMode", param().app().appMode).toInt();
1044 	param().app().currentAppMode = mode;
1045 
1046 	// init debug
1047 	DkUtils::initializeDebug();
1048 
1049 	if (nmc::DkSettingsManager::param().app().useLogFile)
1050 		std::cout << "log is saved to: " << nmc::DkUtils::getLogFilePath().toStdString() << std::endl;
1051 
1052 	qInfo() << "Hi there";
1053 	qInfoClean() << "my name is " << QApplication::organizationName() << " | " << QApplication::applicationName()
1054 		<< " v" << QApplication::applicationVersion() << (nmc::DkSettingsManager::param().isPortable() ? " (portable)" : " (installed)");
1055 }
1056 
importSettings(const QString & settingsPath)1057 void DkSettingsManager::importSettings(const QString & settingsPath) {
1058 
1059 	QSettings settings(settingsPath, QSettings::IniFormat);
1060 	param().load(settings);
1061 	param().save(true);
1062 
1063 	qInfo() << "settings imported...";
1064 }
1065 
1066 // -------------------------------------------------------------------- DkFileFilterHandling
registerFileAssociations()1067 void DkFileFilterHandling::registerFileAssociations() {
1068 
1069 	DkFileFilterHandling fh;
1070 
1071 	// register file associations
1072 	QStringList rFilters = DkSettingsManager::param().app().openFilters;
1073 
1074 	// do not register containers such as *.pptx *.zip
1075 	for (const QString& filter : DkSettingsManager::param().app().containerFilters)
1076 		rFilters.removeAll(filter);
1077 
1078 	for (const QString& filter : rFilters) {
1079 
1080 		// remove the icon file -> otherwise icons might be destroyed (e.g. acrobat)
1081 		if (!filter.contains("ico")) {
1082 			fh.registerFileType(filter, QObject::tr("Image"), true);
1083 			qInfo() << "registering" << filter;
1084 		}
1085 	}
1086 
1087 	qInfo() << "files registered...";
1088 
1089 }
1090 
registerNomacs(bool showDefaultApps)1091 void DkFileFilterHandling::registerNomacs(bool showDefaultApps) {
1092 
1093 #ifdef Q_OS_WIN
1094 
1095 	// do not register if nomacs is portable
1096 	if (DkSettingsManager::param().isPortable() && !showDefaultApps)
1097 		return;
1098 
1099 	// TODO: this is still not working for me on win8??
1100 	QString capName = "Capabilities";
1101 	QString capPath = "Software\\" + QApplication::organizationName() + "\\" + QApplication::applicationName() + "\\" + capName;
1102 	QSettings settings("HKEY_CURRENT_USER\\" + capPath, QSettings::NativeFormat);
1103 
1104 	settings.setValue("ApplicationDescription", QObject::tr("nomacs - Image Lounge is a lightweight image viewer."));
1105 	settings.setValue("ApplicationName", QApplication::organizationName() + " " + QApplication::applicationName());
1106 	settings.setValue("ApplicationIcon", QApplication::applicationFilePath() + ",0");
1107 
1108 	settings.beginGroup("FileAssociations");
1109 	QStringList rFilters = DkSettingsManager::param().app().openFilters;
1110 
1111 	for (int idx = 0; idx < DkSettingsManager::param().app().containerFilters.size(); idx++)
1112 		rFilters.removeAll(DkSettingsManager::param().app().containerFilters.at(idx));
1113 
1114 	for (int idx = 0; idx < rFilters.size(); idx++) {
1115 
1116 		// remove the icon file -> otherwise icons might be destroyed (e.g. acrobat)
1117 		if (!rFilters.at(idx).contains("ico")) {
1118 			QStringList extList = getExtensions(rFilters.at(idx));
1119 
1120 			for (QString cExt : extList)
1121 				settings.setValue(cExt, "nomacs" + cExt + ".3");
1122 		}
1123 	}
1124 	settings.endGroup();
1125 
1126 	QString softwarePath = "HKEY_CURRENT_USER\\Software\\";
1127 	QSettings wsettings(softwarePath, QSettings::NativeFormat);
1128 
1129 	wsettings.beginGroup("RegisteredApplications");
1130 	wsettings.setValue("nomacs.ImageLounge." + QApplication::applicationVersion(), capPath);
1131 	wsettings.endGroup();
1132 
1133 	qDebug() << "nomacs registered ============================";
1134 
1135 	if (showDefaultApps) {
1136 		showDefaultSoftware();
1137 	}
1138 #endif
1139 
1140 }
1141 
showDefaultSoftware() const1142 void DkFileFilterHandling::showDefaultSoftware() const {
1143 
1144 #ifdef Q_OS_WIN
1145 	IApplicationActivationManager* manager = 0;
1146 	CoCreateInstance(CLSID_ApplicationActivationManager,
1147 		0,
1148 		CLSCTX_LOCAL_SERVER,
1149 		IID_IApplicationActivationManager,
1150 		(LPVOID*)&manager);
1151 
1152 	if (manager) {
1153 		DWORD pid = GetCurrentProcessId();
1154 		manager->ActivateApplication(
1155 			L"windows.immersivecontrolpanel_cw5n1h2txyewy"
1156 			L"!microsoft.windows.immersivecontrolpanel",
1157 			L"page=SettingsPageAppsDefaults", AO_NONE, &pid);
1158 		qDebug() << "launching application registration...";
1159 	}
1160 #endif
1161 }
1162 
registerProgID(const QString & ext,const QString & friendlyName,bool add)1163 QString DkFileFilterHandling::registerProgID(const QString& ext, const QString& friendlyName, bool add) {
1164 
1165 #ifdef Q_OS_WIN
1166 
1167 	QString nomacsPath = "HKEY_CURRENT_USER\\SOFTWARE\\Classes\\";
1168 	QString nomacsKey = "nomacs" + ext + ".3";
1169 
1170 	QSettings settings(nomacsPath, QSettings::NativeFormat);
1171 
1172 	if (add) {
1173 
1174 		QString iconID = getIconID(ext);
1175 
1176 		settings.beginGroup(nomacsKey);
1177 		settings.setValue("Default", friendlyName);
1178 		//settings.setValue("AppUserModelID", "nomacs.ImageLounge");
1179 		//settings.setValue("EditFlags", 1);
1180 		//settings.setValue("CurVer", nomacsKey);
1181 		settings.beginGroup("DefaultIcon");
1182 		settings.setValue("Default",QDir::toNativeSeparators(QCoreApplication::applicationFilePath()) + "," + iconID);
1183 		settings.endGroup();
1184 		settings.beginGroup("shell");
1185 		settings.beginGroup("open");
1186 		settings.beginGroup("command");
1187 		settings.setValue("Default", "\"" + QDir::toNativeSeparators(QCoreApplication::applicationFilePath()) + "\" \"%1\"");
1188 		settings.endGroup();
1189 		settings.endGroup();
1190 		settings.endGroup();
1191 
1192 		//qDebug() << nomacsKey << " written";
1193 	}
1194 	else
1195 		settings.remove(nomacsKey);
1196 
1197 	return nomacsKey;
1198 #else
1199 	return QString();
1200 #endif
1201 }
1202 
getIconID(const QString & ext) const1203 QString DkFileFilterHandling::getIconID(const QString& ext) const {
1204 
1205 	//qDebug() << "ID: " << ext;
1206 	if (ext.contains(".jpg") || ext.contains(".jpeg")) {
1207 		return "1";
1208 	}
1209 	else if (ext.contains(".gif") || ext.contains(".mng")) {
1210 		return "2";
1211 	}
1212 	else if (ext.contains(".png")) {
1213 		return "3";
1214 	}
1215 	else if (ext.contains(".tif") || ext.contains(".tiff") || ext.contains(".bmp") || ext.contains(".pgm") || ext.contains(".webp")) {
1216 		return "4";
1217 	}
1218 	else if (!DkSettingsManager::param().app().rawFilters.filter(ext).empty()) {
1219 		return "5";
1220 	}
1221 	else
1222 		return "0";
1223 }
1224 
registerExtension(const QString & ext,const QString & progKey,bool add)1225 void DkFileFilterHandling::registerExtension(const QString& ext, const QString& progKey, bool add) {
1226 
1227 #ifdef Q_OS_WIN
1228 
1229 	QSettings settings2("HKEY_CURRENT_USER\\SOFTWARE\\Classes\\", QSettings::NativeFormat);
1230 	settings2.beginGroup(ext);
1231 	//if (add)
1232 	//	settings2.setValue("Default", progKey);
1233 	settings2.beginGroup("OpenWithProgIds");
1234 	//settings.beginGroup("nomacs.exe");
1235 
1236 	if (add)
1237 		settings2.setValue(progKey, "");	// tell system that nomacs can handle this file type
1238 	else
1239 		settings2.remove(progKey);
1240 #endif
1241 }
1242 
registerFileType(const QString & filterString,const QString & attribute,bool add)1243 void DkFileFilterHandling::registerFileType(const QString& filterString, const QString& attribute, bool add) {
1244 
1245 #ifdef Q_OS_WIN
1246 
1247 	if (DkSettingsManager::param().app().privateMode)
1248 		return;
1249 
1250 	QString friendlyName;
1251 	QStringList extList = getExtensions(filterString, friendlyName);
1252 	friendlyName += attribute;
1253 
1254 	// register a new progID
1255 	QString progKey = registerProgID(extList.at(0), friendlyName, add);
1256 
1257 	// register the extension
1258 	for (int idx = 0; idx < extList.size(); idx++) {
1259 
1260 		//qDebug() << "registering: " << extList.at(idx);
1261 
1262 		registerExtension(extList.at(idx), progKey, add);
1263 		registerDefaultApp(extList.at(idx), progKey, add);
1264 		setAsDefaultApp(extList.at(idx), progKey, add);		// this is not working on Win8
1265 	}
1266 
1267 #endif
1268 }
1269 
getExtensions(const QString & filter) const1270 QStringList DkFileFilterHandling::getExtensions(const QString& filter) const {
1271 
1272 	QString dummy;
1273 	return getExtensions(filter, dummy);
1274 }
1275 
getExtensions(const QString & filter,QString & friendlyName) const1276 QStringList DkFileFilterHandling::getExtensions(const QString& filter, QString& friendlyName) const {
1277 
1278 	QStringList tmp = filter.split("(");
1279 
1280 	if (tmp.size() != 2) {
1281 		qDebug() << "WARNING: wrong filter string!";
1282 		return QStringList();
1283 	}
1284 
1285 	friendlyName = tmp.at(0);
1286 	QString filters = tmp.at(1);
1287 	filters.replace(")", "");
1288 	filters.replace("*", "");
1289 
1290 	QStringList extList = filters.split(" ");
1291 
1292 	if (extList.empty()) {
1293 		qDebug() << "nothing to do here, not registering: " << filter;
1294 		return QStringList();
1295 	}
1296 
1297 	return extList;
1298 }
1299 
registerDefaultApp(const QString & ext,const QString &,bool add)1300 void DkFileFilterHandling::registerDefaultApp(const QString& ext, const QString&, bool add) {
1301 
1302 #ifdef Q_OS_WIN
1303 
1304 	QSettings settings("HKEY_CURRENT_USER\\Software\\Classes\\Applications\\nomacs.exe", QSettings::NativeFormat);
1305 
1306 	if (add) {
1307 		settings.beginGroup("SupportedTypes");
1308 		settings.setValue(ext, "");
1309 		//qDebug() << ext << "registered...";
1310 	}
1311 	else
1312 		settings.remove(ext);
1313 #endif
1314 
1315 }
1316 
setAsDefaultApp(const QString & ext,const QString & progKey,bool add)1317 void DkFileFilterHandling::setAsDefaultApp(const QString& ext, const QString& progKey, bool add) {
1318 
1319 #ifdef Q_OS_WIN
1320 
1321 	QSettings settings("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts", QSettings::NativeFormat);
1322 	settings.beginGroup(ext);
1323 
1324 	if (add) {
1325 		// windows 7 only
1326 		settings.beginGroup("UserChoice");
1327 		settings.setValue("ProgId", progKey);
1328 		settings.endGroup();
1329 
1330 		settings.beginGroup("OpenWithProgids");
1331 		settings.setValue("nomacs" + ext + ".3","");
1332 		//qDebug() << "default app set";
1333 	}
1334 	else
1335 		settings.setValue("Default", "");
1336 #endif
1337 
1338 }
1339 
1340 // -------------------------------------------------------------------- DefaultSettings
1341 #ifdef Q_OS_WIN
1342 // read the settings from a file on Windows
DefaultSettings()1343 DefaultSettings::DefaultSettings() : QSettings(DkSettingsManager::instance().param().settingsPath(), QSettings::IniFormat) {}
1344 #else
DefaultSettings()1345 DefaultSettings::DefaultSettings() : QSettings() {}
1346 #endif
1347 
1348 // -------------------------------------------------------------------- DkThemeManager
getAvailableThemes() const1349 QStringList DkThemeManager::getAvailableThemes() const {
1350 
1351 	QDir td(themeDir());
1352 	td.setNameFilters(QStringList() << "*.css");
1353 
1354 	QStringList themes = td.entryList(QDir::Files, QDir::Name);
1355 
1356 	return themes;
1357 }
1358 
getCurrentThemeName() const1359 QString DkThemeManager::getCurrentThemeName() const {
1360 	return DkSettingsManager::param().display().themeName;
1361 }
1362 
themeDir() const1363 QString DkThemeManager::themeDir() const {
1364 
1365 	QStringList paths;
1366 	paths << QCoreApplication::applicationDirPath();
1367 	paths << QStandardPaths::standardLocations(QStandardPaths::DataLocation);
1368 
1369 	QDir themeDir;
1370 
1371 	for (const QString& p : paths) {
1372 		themeDir = QDir(p + QDir::separator() + "themes");
1373 
1374 		if (themeDir.exists())
1375 			break;
1376 	}
1377 
1378 	return themeDir.absolutePath();
1379 }
1380 
setCurrentTheme(const QString & themeName) const1381 void DkThemeManager::setCurrentTheme(const QString & themeName) const {
1382 	DkSettingsManager::param().display().themeName = themeName;
1383 }
1384 
loadTheme(const QString & themeName) const1385 QString DkThemeManager::loadTheme(const QString & themeName) const {
1386 
1387 	QString cssString;
1388 	QFileInfo tfi(themeDir(), themeName);
1389 	QFile theme(tfi.absoluteFilePath());
1390 
1391 	if (theme.open(QFile::ReadOnly)) {
1392 
1393 		QString ts = theme.readAll();
1394 		cssString = parseColors(ts);
1395 		cssString = cssString.trimmed();
1396 
1397 		qInfo() << "theme loaded from" << tfi.absoluteFilePath();
1398 	}
1399 	else
1400 		qInfo() << "could not load theme from" << tfi.absoluteFilePath();
1401 
1402 	return cssString;
1403 }
1404 
loadStylesheet() const1405 QString DkThemeManager::loadStylesheet() const {
1406 
1407 	QString cssString;
1408 
1409 	QFileInfo cssInfo(":/nomacs/stylesheet.css");
1410 	QFile file(cssInfo.absoluteFilePath());
1411 
1412 	if (file.open(QFile::ReadOnly)) {
1413 
1414 		cssString = file.readAll();
1415 		cssString = replaceColors(cssString);
1416 
1417 		qInfo() << "CSS loaded from: " << cssInfo.absoluteFilePath();
1418 	}
1419 
1420 	file.close();
1421 
1422 	return cssString;
1423 }
1424 
applyTheme() const1425 void DkThemeManager::applyTheme() const {
1426 
1427 	// add theme
1428 	QString cssString = loadTheme(getCurrentThemeName());
1429 
1430 	DkSettings::Display& dp = DkSettingsManager::param().display();
1431 
1432 	// NOTE: it is important, that default.css does not contain
1433 	// any line of code except for the color definitions
1434 	// otherwise, we change the default palette here...
1435 	if (!cssString.isEmpty()) {
1436 
1437 		cssString = replaceColors(cssString);
1438 
1439 		QPalette p = qApp->palette();
1440 
1441 		if (dp.themeBgdColor != QPalette().color(QPalette::Window)) {
1442 			p.setColor(QPalette::Window, dp.themeBgdColor);
1443 			p.setColor(QPalette::Base, dp.themeBgdColor);
1444 		}
1445 
1446 		p.setColor(QPalette::WindowText, dp.themeFgdColor);
1447 		p.setColor(QPalette::ButtonText, dp.themeFgdColor);
1448 
1449 		//p.setColor(QPalette::Button, QColor(0, 0, 0));
1450 
1451 		qApp->setPalette(p);
1452 	}
1453 
1454 	QString cs = loadStylesheet();
1455 	cs += cssString;
1456 
1457 	qApp->setStyleSheet(cs);
1458 }
1459 
cleanThemeName(const QString & theme) const1460 QString DkThemeManager::cleanThemeName(const QString & theme) const {
1461 
1462 	QString t = theme;
1463 	t = t.replace(".css", "");
1464 	t = t.replace("-", " ");
1465 
1466 	return t;
1467 }
1468 
cleanThemeNames(const QStringList & themes) const1469 QStringList DkThemeManager::cleanThemeNames(const QStringList & themes) const {
1470 
1471 	QStringList ctn;
1472 
1473 	for (const QString& t : themes)
1474 		ctn << cleanThemeName(t);
1475 
1476 	return ctn;
1477 }
1478 
parseColors(const QString & styleSheet) const1479 QString DkThemeManager::parseColors(const QString & styleSheet) const {
1480 
1481 	QStringList cs = styleSheet.split("--nomacs-color-def");
1482 
1483 	if (cs.size() == 3) {
1484 
1485 		// we expect something like this:
1486 		/* overload color settings of nomacs */
1487 		//	--nomacs-color-def
1488 		//		HIGHLIGHT_COLOR:	#ff0;
1489 		//		WINDOW_COLOR:		#333;
1490 		//	--nomacs-color-def
1491 		QStringList cols = cs[1].split(";");
1492 
1493 		for (auto str : cols) {
1494 
1495 			str = str.simplified();
1496 
1497 			// igonre blanks
1498 			if (str.isEmpty())
1499 				continue;
1500 
1501 			QStringList kv = str.split(":");
1502 
1503 			if (kv.size() != 2) {
1504 				qWarning() << "could not parse color from" << str;
1505 				qWarning() << "I expected a line like this: HUD_BACKGROUND_COLOR: #f00;";
1506 				continue;
1507 			}
1508 
1509 			QString cc = kv[1].simplified();
1510 
1511 			if (kv[0] == "HIGHLIGHT_COLOR" && cc != "default")
1512 				DkSettingsManager::param().display().highlightColor.setNamedColor(cc);
1513 			else if (kv[0] == "HUD_BACKGROUND_COLOR" && cc != "default")
1514 				DkSettingsManager::param().display().hudBgColor.setNamedColor(cc);
1515 			else if (kv[0] == "HUD_FOREGROUND_COLOR" && cc != "default")
1516 				DkSettingsManager::param().display().hudFgdColor.setNamedColor(cc);
1517 			else if (kv[0] == "BACKGROUND_COLOR") {
1518 
1519 				QColor c;
1520 				c.setNamedColor(cc);
1521 
1522 				if (cc == "default")
1523 					c = QPalette().color(QPalette::Window);
1524 
1525 				if (DkSettingsManager::param().display().defaultBackgroundColor)
1526 						DkSettingsManager::param().display().bgColor = c;
1527 				DkSettingsManager::param().display().themeBgdColor = c;
1528 			}
1529 			else if (kv[0] == "FOREGROUND_COLOR" && cc != "default")
1530 				DkSettingsManager::param().display().themeFgdColor.setNamedColor(cc);
1531 			else if (kv[0] == "ICON_COLOR" && cc != "default") {
1532 				if (DkSettingsManager::param().display().defaultIconColor)
1533 					DkSettingsManager::param().display().iconColor.setNamedColor(cc);
1534 			}
1535 			else if (cc != "default")
1536 				qWarning() << "could not parse color:" << str;
1537 		}
1538 
1539 		return cs[0] + cs[2];
1540 	}
1541 
1542 	return styleSheet;
1543 }
1544 
replaceColors(const QString & cssString) const1545 QString DkThemeManager::replaceColors(const QString & cssString) const {
1546 
1547 	QString cs = cssString;
1548 
1549 	QColor hc = DkSettingsManager::param().display().highlightColor;
1550 	hc.setAlpha(150);
1551 
1552 	// replace color placeholders
1553 	cs.replace("HIGHLIGHT_COLOR", DkUtils::colorToString(DkSettingsManager::param().display().highlightColor));
1554 	cs.replace("HIGHLIGHT_LIGHT", DkUtils::colorToString(hc));
1555 	cs.replace("HUD_BACKGROUND_COLOR", DkUtils::colorToString(DkSettingsManager::param().display().hudBgColor));
1556 	cs.replace("HUD_FOREGROUND_COLOR", DkUtils::colorToString(DkSettingsManager::param().display().hudFgdColor));
1557 	cs.replace("BACKGROUND_COLOR", DkUtils::colorToString(DkSettingsManager::param().display().bgColor));
1558 	cs.replace("FOREGROUND_COLOR", DkUtils::colorToString(DkSettingsManager::param().display().themeFgdColor));
1559 	cs.replace("WINDOW_COLOR", DkUtils::colorToString(QPalette().color(QPalette::Window)));
1560 
1561 	return cs;
1562 }
1563 
1564 // -------------------------------------------------------------------- DkZoomConfig
DkZoomConfig()1565 DkZoomConfig::DkZoomConfig() {
1566 
1567 	mLevels = defaultLevels();
1568 
1569 	DefaultSettings ds;
1570 	loadSettings(ds);
1571 }
1572 
instance()1573 DkZoomConfig& DkZoomConfig::instance() {
1574 	static DkZoomConfig inst;
1575 	return inst;
1576 }
1577 
~DkZoomConfig()1578 DkZoomConfig::~DkZoomConfig() {
1579 
1580 	DefaultSettings ds;
1581 	saveSettings(ds);
1582 }
1583 
nextFactor(double currentFactor,double delta) const1584 double DkZoomConfig::nextFactor(double currentFactor, double delta) const {
1585 
1586 	// do nothing?
1587 	if (!mUseLevels)
1588 		return delta;
1589 
1590 	assert(currentFactor != 0.0);
1591 
1592 	if (currentFactor == 0.0)
1593 		return 1.0;
1594 
1595 	if (delta > 1) {
1596 		for (double l : mLevels) {
1597 
1598 			if (currentFactor < l) {
1599 				return l / currentFactor;
1600 			}
1601 		}
1602 	}
1603 	else if (delta < 1) {
1604 
1605 		for (int idx = mLevels.size() - 1; idx >= 0; idx--) {
1606 
1607 			if (currentFactor > mLevels[idx]) {
1608 				return mLevels[idx] / currentFactor;
1609 			}
1610 		}
1611 	}
1612 
1613 	// do nothing
1614 	return 1.0;
1615 }
1616 
defaultLevels() const1617 QVector<double> DkZoomConfig::defaultLevels() const {
1618 
1619 	QVector<double> levels;
1620 
1621 	levels << 0.0001;
1622 	levels << 0.001;
1623 	levels << 0.01;
1624 	levels << 0.05;
1625 	levels << 0.1;
1626 	levels << 0.125;
1627 	levels << 0.166;
1628 	levels << 0.25;
1629 	levels << 0.333;
1630 	levels << 0.5;
1631 	levels << 0.66;
1632 	levels << 1;
1633 	levels << 1.5;
1634 	levels << 2;
1635 	levels << 3;
1636 	levels << 4;
1637 	levels << 5;
1638 	levels << 6;
1639 	levels << 7;
1640 	levels << 8;
1641 	levels << 12;
1642 	levels << 16;
1643 	levels << 32;
1644 	levels << 64;
1645 	levels << 128;
1646 
1647 	return levels;
1648 }
1649 
useLevels() const1650 bool DkZoomConfig::useLevels() const {
1651 	return mUseLevels;
1652 }
1653 
setUseLevels(bool useLevels)1654 void DkZoomConfig::setUseLevels(bool useLevels) {
1655 	mUseLevels = useLevels;
1656 }
1657 
setLevels(const QString & levelStr)1658 bool DkZoomConfig::setLevels(const QString & levelStr) {
1659 
1660 	QVector<double> levels;
1661 	QStringList levelList = levelStr.split(",");
1662 
1663 	bool ok = false;
1664 	for (const QString& s : levelList) {
1665 		levels << s.toDouble(&ok);
1666 		if (!ok)
1667 			break;
1668 	}
1669 
1670 	if (ok && checkLevels(levels)) {
1671 		mLevels = levels;
1672 		return true;
1673 	}
1674 
1675 	return false;
1676 }
1677 
levelsToString() const1678 QString DkZoomConfig::levelsToString() const {
1679 
1680 	QStringList levelStr;
1681 	for (double l : mLevels)
1682 		levelStr << QString::number(l);
1683 
1684 	return levelStr.join(",");
1685 }
1686 
setLevelsToDefault()1687 void DkZoomConfig::setLevelsToDefault() {
1688 
1689 	mLevels = defaultLevels();
1690 }
1691 
checkLevels(const QVector<double> & levels)1692 bool DkZoomConfig::checkLevels(const QVector<double>& levels) {
1693 
1694 	if (levels.isEmpty())
1695 		return false;
1696 
1697 	double last = 0;
1698 
1699 	// levels must be monotonically increasing
1700 	for (double l : levels) {
1701 		if (l < last)
1702 			return false;
1703 	}
1704 
1705 	return true;
1706 }
1707 
loadSettings(QSettings & settings)1708 void DkZoomConfig::loadSettings(QSettings & settings) {
1709 
1710 	settings.beginGroup("zooming");
1711 	QString levelStr = settings.value("zoomLevels").toString();
1712 	mUseLevels = settings.value("useLevels").toBool();
1713 	settings.endGroup();
1714 
1715 	if (!setLevels(levelStr))
1716 		qWarning() << "illegal zoom levels when loading from settings:" << levelStr;
1717 }
1718 
saveSettings(QSettings & settings) const1719 void DkZoomConfig::saveSettings(QSettings & settings) const {
1720 
1721 	settings.beginGroup("zooming");
1722 	settings.setValue("zoomLevels", levelsToString());
1723 	settings.setValue("useLevels", mUseLevels);
1724 	settings.endGroup();
1725 }
1726 
1727 }
1728