1 /* ============================================================
2 *
3 * This file is a part of digiKam project
4 * https://www.digikam.org
5 *
6 * Date : 2009-09-08
7 * Description : global macros, variables and flags
8 *
9 * Copyright (C) 2009-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
10 *
11 * This program is free software; you can redistribute it
12 * and/or modify it under the terms of the GNU General
13 * Public License as published by the Free Software Foundation;
14 * either version 2, or (at your option)
15 * any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * ============================================================ */
23
24 #include "digikam_globals.h"
25
26 // Qt includes
27
28 #include <QObject>
29 #include <QDir>
30 #include <QList>
31 #include <QImageReader>
32 #include <QImageWriter>
33 #include <QByteArray>
34 #include <QShortcut>
35 #include <QApplication>
36 #include <QStandardPaths>
37 #include <QLibrary>
38 #include <QSysInfo>
39 #include <QMimeType>
40 #include <QMimeDatabase>
41
42 // KDE includes
43
44 #include <klocalizedstring.h>
45
46 // Local includes
47
48 #include "digikam_config.h"
49 #include "digikam_debug.h"
50 #include "drawdecoder.h"
51 #include "rawcameradlg.h"
52
53 // Windows includes
54
55 #ifdef HAVE_DRMINGW
56 # include <windows.h>
57 #endif
58
59 namespace Digikam
60 {
61
defineShortcut(QWidget * const w,const QKeySequence & key,const QObject * receiver,const char * slot)62 QShortcut* defineShortcut(QWidget* const w, const QKeySequence& key, const QObject* receiver, const char* slot)
63 {
64 QShortcut* const s = new QShortcut(w);
65 s->setKey(key);
66 s->setContext(Qt::WidgetWithChildrenShortcut);
67 QObject::connect(s, SIGNAL(activated()), receiver, slot);
68
69 return s;
70 }
71
supportedImageMimeTypes(QIODevice::OpenModeFlag mode,QString & allTypes)72 QStringList supportedImageMimeTypes(QIODevice::OpenModeFlag mode, QString& allTypes)
73 {
74 QStringList formats;
75 QList<QByteArray> supported;
76
77 switch (mode)
78 {
79 case QIODevice::ReadOnly:
80 {
81 supported = QImageReader::supportedImageFormats();
82 break;
83 }
84
85 case QIODevice::WriteOnly:
86 {
87 supported = QImageWriter::supportedImageFormats();
88 break;
89 }
90
91 case QIODevice::ReadWrite:
92 {
93 supported = QImageWriter::supportedImageFormats() + QImageReader::supportedImageFormats();
94 break;
95 }
96
97 default:
98 {
99 qCDebug(DIGIKAM_GENERAL_LOG) << "Unsupported mode!";
100 break;
101 }
102 }
103
104 foreach (const QByteArray& frm, supported)
105 {
106 if (QString::fromLatin1(frm).contains(QLatin1String("tif"), Qt::CaseInsensitive) ||
107 QString::fromLatin1(frm).contains(QLatin1String("tiff"), Qt::CaseInsensitive))
108 {
109 continue;
110 }
111
112 if (QString::fromLatin1(frm).contains(QLatin1String("jpg"), Qt::CaseInsensitive) ||
113 QString::fromLatin1(frm).contains(QLatin1String("jpeg"), Qt::CaseInsensitive))
114 {
115 continue;
116 }
117
118 #ifdef HAVE_JASPER
119
120 if (QString::fromLatin1(frm).contains(QLatin1String("jp2"), Qt::CaseInsensitive) ||
121 QString::fromLatin1(frm).contains(QLatin1String("j2k"), Qt::CaseInsensitive) ||
122 QString::fromLatin1(frm).contains(QLatin1String("jpx"), Qt::CaseInsensitive) ||
123 QString::fromLatin1(frm).contains(QLatin1String("jpc"), Qt::CaseInsensitive) ||
124 QString::fromLatin1(frm).contains(QLatin1String("pgx"), Qt::CaseInsensitive))
125 {
126 continue;
127 }
128
129 #endif // HAVE_JASPER
130
131 #ifdef HAVE_X265
132
133 if (QString::fromLatin1(frm).contains(QLatin1String("heic"), Qt::CaseInsensitive) ||
134 QString::fromLatin1(frm).contains(QLatin1String("heif"), Qt::CaseInsensitive))
135 {
136 continue;
137 }
138
139 #endif // HAVE_X265
140
141 #ifdef HAVE_IMAGE_MAGICK
142
143 if (QString::fromLatin1(frm).contains(QLatin1String("fts"), Qt::CaseInsensitive) ||
144 QString::fromLatin1(frm).contains(QLatin1String("fit"), Qt::CaseInsensitive) ||
145 QString::fromLatin1(frm).contains(QLatin1String("fits"), Qt::CaseInsensitive))
146 {
147 continue;
148 }
149
150 #endif // HAVE_IMAGE_MAGICK
151
152 formats.append(i18n("%1 Image (%2)", QString::fromLatin1(frm).toUpper(), QLatin1String("*.") + QLatin1String(frm)));
153 allTypes.append(QString::fromLatin1("*.%1 ").arg(QLatin1String(frm)));
154 }
155
156 formats.append(i18n("TIFF Image (*.tiff *.tif)"));
157 allTypes.append(QLatin1String("*.tiff *.tif "));
158 formats.append(i18n("JPEG Image (*.jpg *.jpeg *.jpe)"));
159 allTypes.append(QLatin1String("*.jpg *.jpeg *.jpe "));
160
161 #ifdef HAVE_JASPER
162
163 formats.append(i18n("JPEG2000 Image (*.jp2 *.j2k *.jpx *.pgx)"));
164 allTypes.append(QLatin1String("*.jp2 *.j2k *.jpx *.pgx "));
165
166 #endif // HAVE_JASPER
167
168 formats << i18n("Progressive Graphics file (*.pgf)");
169 allTypes.append(QLatin1String("*.pgf "));
170
171 #ifdef HAVE_X265
172
173 formats << i18n("High Efficiency Image Coding (*.heic *.heif)");
174 allTypes.append(QLatin1String("*.heic *.heif "));
175
176 #endif // HAVE_X265
177
178 #ifdef HAVE_IMAGE_MAGICK
179
180 formats << i18n("Flexible Image Transport System (*.fts *.fit *.fits)");
181 allTypes.append(QLatin1String("*.fts *.fit *.fits "));
182
183 #endif // HAVE_IMAGE_MAGICK
184
185 if (mode != QIODevice::WriteOnly)
186 {
187 formats << i18n("Raw Images (%1)", DRawDecoder::rawFiles());
188 allTypes.append(DRawDecoder::rawFiles());
189 formats << i18n("All supported files (%1)", allTypes);
190 }
191
192 return formats;
193 }
194
isReadableImageFile(const QString & filePath)195 bool isReadableImageFile(const QString& filePath)
196 {
197 QFileInfo info(filePath);
198
199 if (info.isFile() && !info.isSymLink() && !info.isDir() && !info.isRoot())
200 {
201 QString path = info.absoluteFilePath();
202 QMimeType mtype = QMimeDatabase().mimeTypeForFile(path);
203 QString suffix = info.suffix().toUpper();
204
205 // Add extra check of the image extensions that are still
206 // unknown in older Qt versions or have an application mime type.
207
208 if (mtype.name().startsWith(QLatin1String("image/")) ||
209 (suffix == QLatin1String("PGF")) ||
210 (suffix == QLatin1String("KRA")) ||
211 (suffix == QLatin1String("CR3")) ||
212 (suffix == QLatin1String("HEIC")) ||
213 (suffix == QLatin1String("HEIF")) ||
214 DRawDecoder::rawFiles().contains(suffix))
215 {
216 return true;
217 }
218 }
219
220 return false;
221 }
222
showRawCameraList()223 void showRawCameraList()
224 {
225 RawCameraDlg* const dlg = new RawCameraDlg(qApp->activeWindow());
226 dlg->show();
227 }
228
isRunningInAppImageBundle()229 bool isRunningInAppImageBundle()
230 {
231 QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
232
233 if (env.contains(QLatin1String("APPIMAGE_ORIGINAL_LD_LIBRARY_PATH")) &&
234 env.contains(QLatin1String("APPIMAGE_ORIGINAL_QT_PLUGIN_PATH")) &&
235 env.contains(QLatin1String("APPIMAGE_ORIGINAL_XDG_DATA_DIRS")) &&
236 env.contains(QLatin1String("APPIMAGE_ORIGINAL_PATH")))
237 {
238 return true;
239 }
240
241 return false;
242 }
243
adjustedEnvironmentForAppImage()244 QProcessEnvironment adjustedEnvironmentForAppImage()
245 {
246 QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
247
248 // If we are running into AppImage bundle, switch env var to the right values.
249
250 if (isRunningInAppImageBundle())
251 {
252 qCDebug(DIGIKAM_GENERAL_LOG) << "Adjusting environment variables for AppImage bundle";
253
254 if (!env.value(QLatin1String("APPIMAGE_ORIGINAL_LD_LIBRARY_PATH")).isEmpty())
255 {
256 env.insert(QLatin1String("LD_LIBRARY_PATH"),
257 env.value(QLatin1String("APPIMAGE_ORIGINAL_LD_LIBRARY_PATH")));
258 }
259 else
260 {
261 env.remove(QLatin1String("LD_LIBRARY_PATH"));
262 }
263
264 if (!env.value(QLatin1String("APPIMAGE_ORIGINAL_QT_PLUGIN_PATH")).isEmpty())
265 {
266 env.insert(QLatin1String("QT_PLUGIN_PATH"),
267 env.value(QLatin1String("APPIMAGE_ORIGINAL_QT_PLUGIN_PATH")));
268 }
269 else
270 {
271 env.remove(QLatin1String("QT_PLUGIN_PATH"));
272 }
273
274 if (!env.value(QLatin1String("APPIMAGE_ORIGINAL_XDG_DATA_DIRS")).isEmpty())
275 {
276 env.insert(QLatin1String("XDG_DATA_DIRS"),
277 env.value(QLatin1String("APPIMAGE_ORIGINAL_XDG_DATA_DIRS")));
278 }
279 else
280 {
281 env.remove(QLatin1String("XDG_DATA_DIRS"));
282 }
283
284 if (!env.value(QLatin1String("APPIMAGE_ORIGINAL_PATH")).isEmpty())
285 {
286 env.insert(QLatin1String("PATH"),
287 env.value(QLatin1String("APPIMAGE_ORIGINAL_PATH")));
288 }
289 else
290 {
291 env.remove(QLatin1String("PATH"));
292 }
293
294 if (!env.value(QLatin1String("APPIMAGE_ORIGINAL_KDE_FULL_SESSION")).isEmpty())
295 {
296 env.insert(QLatin1String("KDE_FULL_SESSION"),
297 env.value(QLatin1String("APPIMAGE_ORIGINAL_KDE_FULL_SESSION")));
298 }
299 else
300 {
301 env.remove(QLatin1String("KDE_FULL_SESSION"));
302 }
303
304 if (!env.value(QLatin1String("APPIMAGE_ORIGINAL_DESKTOP_SESSION")).isEmpty())
305 {
306 env.insert(QLatin1String("DESKTOP_SESSION"),
307 env.value(QLatin1String("APPIMAGE_ORIGINAL_DESKTOP_SESSION")));
308 }
309 else
310 {
311 env.remove(QLatin1String("DESKTOP_SESSION"));
312 }
313
314 if (!env.value(QLatin1String("APPIMAGE_ORIGINAL_XDG_CURRENT_DESKTOP")).isEmpty())
315 {
316 env.insert(QLatin1String("XDG_CURRENT_DESKTOP"),
317 env.value(QLatin1String("APPIMAGE_ORIGINAL_XDG_CURRENT_DESKTOP")));
318 }
319 else
320 {
321 env.remove(QLatin1String("XDG_CURRENT_DESKTOP"));
322 }
323
324 if (!env.value(QLatin1String("APPIMAGE_ORIGINAL_XDG_SESSION_DESKTOP")).isEmpty())
325 {
326 env.insert(QLatin1String("XDG_SESSION_DESKTOP"),
327 env.value(QLatin1String("APPIMAGE_ORIGINAL_XDG_SESSION_DESKTOP")));
328 }
329 else
330 {
331 env.remove(QLatin1String("XDG_SESSION_DESKTOP"));
332 }
333 }
334
335 return env;
336 }
337
tryInitDrMingw()338 void tryInitDrMingw()
339 {
340
341 #ifdef HAVE_DRMINGW
342
343 qCDebug(DIGIKAM_GENERAL_LOG) << "Loading DrMinGw run-time...";
344
345 QRegExp versionRegExp(QLatin1String("(\\d+[.]*\\d*)"));
346 QSysInfo::productVersion().indexOf(versionRegExp);
347 double version = versionRegExp.capturedTexts().constFirst().toDouble();
348
349 if (
350 ((version < 2000.0) && (version < 10.0)) ||
351 ((version > 2000.0) && (version < 2016.0))
352 )
353 {
354 qCDebug(DIGIKAM_GENERAL_LOG) << "DrMinGw: unsupported Windows version" << version;
355 return;
356 }
357
358 QString appPath = QCoreApplication::applicationDirPath();
359 QString excFile = QDir::toNativeSeparators(appPath + QLatin1String("/exchndl.dll"));
360
361 HMODULE hModExc = LoadLibraryW((LPCWSTR)excFile.utf16());
362
363 if (!hModExc)
364 {
365 qCDebug(DIGIKAM_GENERAL_LOG) << "DrMinGw: cannot init crash handler dll.";
366 return;
367 }
368
369 // No need to call ExcHndlInit since the crash handler is installed on DllMain
370
371 auto myExcHndlSetLogFileNameA = reinterpret_cast<BOOL (APIENTRY*)(const char*)>
372 (GetProcAddress(hModExc, "ExcHndlSetLogFileNameA"));
373
374 if (!myExcHndlSetLogFileNameA)
375 {
376 qCDebug(DIGIKAM_GENERAL_LOG) << "DrMinGw: cannot init customized crash file.";
377 return;
378 }
379
380 // Set the log file path to %LocalAppData%\digikam_crash.log
381
382 QString logPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
383 QString logFile = QDir::toNativeSeparators(logPath + QLatin1String("/digikam_crash.log"));
384 myExcHndlSetLogFileNameA(logFile.toLocal8Bit().data());
385
386 qCDebug(DIGIKAM_GENERAL_LOG) << "DrMinGw run-time loaded.";
387 qCDebug(DIGIKAM_GENERAL_LOG) << "DrMinGw crash-file will be located at: " << logFile;
388
389 #endif // HAVE_DRMINGW
390
391 }
392
toolButtonStyleSheet()393 QString toolButtonStyleSheet()
394 {
395 return QLatin1String("QToolButton { padding: 1px; background-color: "
396 " qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, "
397 " stop: 0 rgba(100, 100, 100, 50%), "
398 " stop: 1 rgba(170, 170, 170, 50%)); "
399 "border: 1px solid rgba(170, 170, 170, 10%); } "
400
401 "QToolButton:hover { border-color: white; } "
402
403 "QToolButton:pressed { background-color: "
404 " qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, "
405 " stop: 0 rgba(40, 40, 40, 50%), "
406 " stop: 1 rgba(90, 90, 90, 50%)); "
407 "border-color: white; } "
408
409 "QToolButton:checked { background-color: "
410 " qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, "
411 " stop: 0 rgba(40, 40, 40, 50%), "
412 " stop: 1 rgba(90, 90, 90, 50%)); } "
413
414 "QToolButton:disabled { background-color: "
415 " qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, "
416 " stop: 0 rgba(40, 40, 40, 50%), "
417 " stop: 1 rgba(50, 50, 50, 50%)); }");
418 }
419
macOSBundlePrefix()420 QString macOSBundlePrefix()
421 {
422 return QString::fromUtf8("/Applications/digiKam.org/digikam.app/Contents/");
423 }
424
425 } // namespace Digikam
426