swift
guiapplication.cpp
1 // SPDX-FileCopyrightText: Copyright (C) 2016 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
4 #include "gui/guiapplication.h"
5 
6 #include <QAction>
7 #include <QApplication>
8 #include <QCloseEvent>
9 #include <QCommandLineParser>
10 #include <QDesktopServices>
11 #include <QDir>
12 #include <QEventLoop>
13 #include <QFont>
14 #include <QGuiApplication>
15 #include <QIcon>
16 #include <QKeySequence>
17 #include <QMainWindow>
18 #include <QMenu>
19 #include <QMessageBox>
20 #include <QSettings>
21 #include <QStringBuilder>
22 #include <QStringList>
23 #include <QStyle>
24 #include <QStyleFactory>
25 #include <QToolBar>
26 #include <QUrl>
27 #include <QWhatsThis>
28 #include <QWidget>
29 #include <Qt>
30 #include <QtGlobal>
31 
32 #include "config/buildconfig.h"
34 #include "core/data/globalsetup.h"
35 #include "core/db/infodatareader.h"
36 #include "core/setupreader.h"
37 #include "core/webdataservices.h"
42 #include "gui/guiutility.h"
43 #include "gui/registermetadata.h"
44 #include "gui/splashscreen.h"
45 #include "misc/datacache.h"
46 #include "misc/logcategories.h"
47 #include "misc/loghandler.h"
48 #include "misc/logmessage.h"
49 #include "misc/metadatautils.h"
50 #include "misc/settingscache.h"
51 #include "misc/slot.h"
52 #include "misc/stringutils.h"
53 #include "misc/swiftdirectories.h"
54 #include "misc/verify.h"
55 
56 using namespace swift::config;
57 using namespace swift::misc;
58 using namespace swift::misc::db;
59 using namespace swift::misc::network;
60 using namespace swift::gui::components;
61 using namespace swift::core;
62 using namespace swift::core::data;
63 using namespace swift::core::context;
64 
65 swift::gui::CGuiApplication *sGui = nullptr; // set by constructor
66 
67 namespace swift::gui
68 {
69  CGuiApplication *CGuiApplication::instance() { return qobject_cast<CGuiApplication *>(CApplication::instance()); }
70 
71  const QStringList &CGuiApplication::getLogCategories()
72  {
73  static const QStringList l(CApplication::getLogCategories() + QStringList { CLogCategories::guiComponent() });
74  return l;
75  }
76 
77  const QString &CGuiApplication::settingsOrganization()
78  {
79  static const QString o("swift-project.org");
80  return o;
81  }
82 
83  bool CGuiApplication::removeAllWindowsSwiftRegistryEntries()
84  {
85  if (!CBuildConfig::isRunningOnWindowsNtPlatform()) { return false; }
86 
87  // On Windows, NativeFormat settings are stored in the following registry paths:
88  // HKEY_CURRENT_USER\Software\MySoft\Star Runner.
89  // HKEY_CURRENT_USER\Software\MySoft\OrganizationDefaults.
90  // HKEY_LOCAL_MACHINE\Software\MySoft\Star Runner.
91  // HKEY_LOCAL_MACHINE\Software\MySoft\OrganizationDefaults.
92 
93  QSettings s1("HKEY_CURRENT_USER\\Software\\" + settingsOrganization(), QSettings::NativeFormat);
94  s1.remove("");
95 
96  QSettings s2("HKEY_LOCAL_MACHINE\\Software\\" + settingsOrganization(), QSettings::NativeFormat);
97  s2.remove("");
98 
99  return true;
100  }
101 
102  CGuiApplication::CGuiApplication(const QString &applicationName, CApplicationInfo::Application application,
103  const QPixmap &icon)
104  : CApplication(applicationName, application, false)
105  {
106  this->addWindowModeOption();
107  this->addWindowResetSizeOption();
108  this->addWindowScaleSizeOption();
109 
110  // notify when app goes down
111  connect(qGuiApp, &QGuiApplication::lastWindowClosed, this, &CGuiApplication::gracefulShutdown);
112 
113  if (!sGui)
114  {
116  CApplication::init(false); // base class without metadata
117  CGuiApplication::adjustPalette();
119  this->settingsChanged();
120  this->setCurrentFontValues(); // most likely the default font and not any stylesheet font at this time
121  sGui = this;
122 
123  connect(&m_styleSheetUtility, &CStyleSheetUtility::styleSheetsChanged, this,
124  &CGuiApplication::onStyleSheetsChanged, Qt::QueuedConnection);
125  connect(this, &CGuiApplication::startUpCompleted, this, &CGuiApplication::superviseWindowMinSizes,
126  Qt::QueuedConnection);
127  }
128  }
129 
131 
133  {
134  CApplication::registerMetadata();
136  }
137 
139  {
140  m_cmdWindowMode = QCommandLineOption(
141  { "w", "window" }, QCoreApplication::translate("main", "Windows: (n)ormal, (f)rameless, (t)ool."),
142  "windowtype");
143  this->addParserOption(m_cmdWindowMode);
144  }
145 
147  {
148  m_cmdWindowSizeReset = QCommandLineOption(
149  { { "r", "resetsize" }, QCoreApplication::translate("main", "Reset window size (ignore saved values).") });
150  this->addParserOption(m_cmdWindowSizeReset);
151  }
152 
154  {
155  // just added here to display it in help
156  // parseScaleFactor() is used since it is needed upfront (before application is created)
157  m_cmdWindowScaleSize =
158  QCommandLineOption("scale", QCoreApplication::translate("main", "Scale: number."), "scalevalue");
159  this->addParserOption(m_cmdWindowScaleSize);
160  }
161 
163  {
164  m_cmdWindowStateMinimized = QCommandLineOption(
165  { { "m", "minimized" }, QCoreApplication::translate("main", "Start minimized in system tray.") });
166  this->addParserOption(m_cmdWindowStateMinimized);
167  }
168 
169  Qt::WindowState CGuiApplication::getWindowState() const
170  {
171  if (m_cmdWindowStateMinimized.valueName() == "empty") { return Qt::WindowNoState; }
172  if (m_parser.isSet(m_cmdWindowStateMinimized)) { return Qt::WindowMinimized; }
173  return Qt::WindowNoState;
174  }
175 
177  {
178  if (this->isParserOptionSet(m_cmdWindowMode))
179  {
180  const QString v(this->getParserValue(m_cmdWindowMode));
182  }
183  else { return CEnableForFramelessWindow::WindowNormal; }
184  }
185 
186  void CGuiApplication::splashScreen(const QPixmap &pixmap)
187  {
188  if (m_splashScreen)
189  {
190  m_splashScreen.reset(); // delete old one
191  }
192 
193  QFont splashFont;
194  splashFont.setFamily("Arial");
195  // splashFont.setBold(true);
196  splashFont.setPointSize(10);
197  splashFont.setStretch(100);
198 
199  m_splashScreen.reset(new CSplashScreen(pixmap.scaled(256, 256), splashFont));
200  m_splashScreen->show();
201  m_splashScreen->showStatusMessage("Version " + CBuildConfig::getVersionString());
202  }
203 
205  {
206  if (this->isShuttingDown()) { return; }
207  QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
208  }
209 
211 
213  {
215  }
216 
218  {
219  if (this->getGlobalSetup().isSwiftVersionMinimumMappingVersion()) { return true; }
220 
221  const QString msg =
222  QStringLiteral("Your are using swift version: '%1'.\nCreating mappings requires at least '%2'.")
223  .arg(CBuildConfig::getVersionString(), this->getGlobalSetup().getMappingMinimumVersionString());
224  QMessageBox::warning(CGuiApplication::mainApplicationWindow(), "Version check", msg, QMessageBox::Close);
225  return false;
226  }
227 
229  {
230  return qobject_cast<QMainWindow *>(CGuiApplication::mainApplicationWidget());
231  }
232 
234  {
235  IMainWindowAccess *m = qobject_cast<IMainWindowAccess *>(mainApplicationWidget());
236  return m;
237  }
238 
240  {
241  if (!mainWidget) { return; }
242  if (m_uiSetupCompleted) { return; }
243  m_uiSetupCompleted = true;
244 
245  const QString name = this->setExtraWindowTitle("", mainWidget);
246  mainWidget->setObjectName(QCoreApplication::applicationName());
247  mainWidget->setWindowIcon(m_windowIcon);
248  mainWidget->setWindowIconText(name);
251  emit this->uiObjectTreeReady();
252  }
253 
254  void CGuiApplication::addWindowFlags(Qt::WindowFlags flags)
255  {
257  if (maw)
258  {
259  Qt::WindowFlags windowFlags = maw->windowFlags();
260  windowFlags |= flags;
261  maw->setWindowFlags(windowFlags);
262  }
263  else
264  {
265  QPointer<CGuiApplication> myself(this);
267  if (!myself) { return; }
268  this->addWindowFlags(flags);
269  });
270  }
271  }
272 
273  QString CGuiApplication::setExtraWindowTitle(const QString &extraInfo, QWidget *mainWindowWidget) const
274  {
275  QString name(this->getApplicationNameVersionDetailed());
276  if (!extraInfo.isEmpty()) { name = extraInfo % u' ' % name; }
277  if (!mainWindowWidget) { return name; }
278  mainWindowWidget->setWindowTitle(name);
279  return name;
280  }
281 
282  void CGuiApplication::setWindowIcon(const QPixmap &icon)
283  {
284  instance()->m_windowIcon = icon;
285  QApplication::setWindowIcon(icon);
286  }
287 
288  void CGuiApplication::exit(int retcode) { CApplication::exit(retcode); }
289 
290  void CGuiApplication::highDpiScreenSupport(const QString &scaleFactor)
291  {
292  // https://lists.qt-project.org/pipermail/development/2019-September/037434.html
293  // QSize s = CGuiUtility::physicalScreenSizeOs();
294  QString sf = scaleFactor.trimmed().isEmpty() ? defaultScaleFactorString() : scaleFactor;
295  if (sf.contains('/'))
296  {
297  const double sfd = parseFraction(scaleFactor, -1);
298  sf = sfd < 0 ? "1.0" : QString::number(sfd, 'f', 8);
299  }
300 
301  sf = cleanNumber(sf);
302 
303  // qputenv("QT_ENABLE_HIGHDPI_SCALING", "1");
304  QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::Floor);
305 
306  const QByteArray sfa = sf.toLatin1();
307  qputenv("QT_SCALE_FACTOR", sfa);
308  }
309 
311 
313  {
314  const QWidget *w = CGuiApplication::mainApplicationWidget();
315  if (!w) return QGuiApplication::primaryScreen();
316 
317  const QWindow *win = w->windowHandle();
318 
319  if (!win) return QGuiApplication::primaryScreen();
320 
321  QScreen *screen = win->screen();
322 
323  return screen ? screen : QGuiApplication::primaryScreen();
324  }
325 
327  {
328  const QScreen *s = currentScreen();
329  if (s) return s->geometry();
330  return {};
331  }
332 
334  {
335  if (!QGuiApplication::modalWindow()) { return; }
336  QGuiApplication::modalWindow()->raise();
337  }
338 
339  const QString &CGuiApplication::fileForWindowGeometryAndStateSettings()
340  {
341  static const QString filename = [] {
342  QString dir =
343  CFileUtils::appendFilePaths(CSwiftDirectories::normalizedApplicationDataDirectory(), "settings/qgeom");
344  return CFileUtils::appendFilePaths(
345  dir, QFileInfo(QCoreApplication::applicationFilePath()).completeBaseName() + ".ini");
346  }();
347  return filename;
348  }
349 
350  int CGuiApplication::hashForStateSettingsSchema(const QMainWindow *window)
351  {
352  size_t hash = 0;
353  for (auto obj : window->findChildren<QToolBar *>(QString(), Qt::FindDirectChildrenOnly))
354  {
355  hash ^= qHash(obj->objectName());
356  }
357  for (auto obj : window->findChildren<QDockWidget *>(QString(), Qt::FindDirectChildrenOnly))
358  {
359  hash ^= qHash(obj->objectName());
360  }
361  return static_cast<int>((hash & 0xffff) ^ (hash >> 16));
362  }
363 
364  bool CGuiApplication::saveWindowGeometryAndState(const QMainWindow *window) const
365  {
366  if (!window) { return false; }
367  QSettings settings(fileForWindowGeometryAndStateSettings(), QSettings::IniFormat);
368  settings.setValue("geometry", window->saveGeometry());
369  settings.setValue("windowState", window->saveState(hashForStateSettingsSchema(window)));
370  return true;
371  }
372 
374  {
375  QByteArray ba;
376  QSettings settings(fileForWindowGeometryAndStateSettings(), QSettings::IniFormat);
377  settings.setValue("geometry", ba);
378  settings.setValue("windowState", ba);
379  }
380 
382  {
383  if (!window) { return false; }
384  const QSettings settings(fileForWindowGeometryAndStateSettings(), QSettings::IniFormat);
385  const QString location = settings.fileName();
386  CLogMessage(this).info(u"GUI settings are here: '%1'") << location;
387 
388  const QByteArray g = settings.value("geometry").toByteArray();
389  const QByteArray s = settings.value("windowState").toByteArray();
390  if (g.isEmpty() || s.isEmpty()) { return false; }
391 
392  // block for subscriber
393  {
394  const auto pattern = CLogPattern().withSeverity(CStatusMessage::SeverityError);
395  const QString parameter = m_cmdWindowSizeReset.names().first();
396  CLogSubscriber logSub(this, [&](const CStatusMessage &message) {
397  // handles an error in restoreGeometry/State
398  const int ret =
399  QMessageBox::critical(sGui->mainApplicationWidget(), sGui->getApplicationNameAndVersion(),
400  QStringLiteral("Restoring the window state/geometry failed!\n"
401  "You need to reset the window size (command -%1).\n\n"
402  "Original msg: %2\n\n"
403  "We can try to reset the values and restart\n"
404  "Do you want to try?")
405  .arg(parameter, message.getMessage()),
406  QMessageBox::Yes | QMessageBox::No);
407  if (ret == QMessageBox::Yes)
408  {
410  this->restartApplication();
411  }
412  // most likely crashing if we do nothing
413  });
414  logSub.changeSubscription(pattern);
415 
416  window->restoreGeometry(g);
417  window->restoreState(s, hashForStateSettingsSchema(window));
418  }
419  return true;
420  }
421 
423  {
424  CApplication::onStartUpCompleted();
425  this->setCurrentFontValues();
426 
427  const QString metricInfo = CGuiUtility::metricsInfo();
428  CLogMessage(this).info(metricInfo);
429 
430  // window size
431  if (m_minWidthChars > 0 || m_minHeightChars > 0)
432  {
433  const QSizeF fontMetricEstSize = CGuiUtility::fontMetricsEstimateSize(m_minWidthChars, m_minHeightChars);
434  QWidget *mw = CGuiUtility::mainApplicationWidget();
435  if (mw)
436  {
437  // setMinimumSizeInCharacters sets m_minHeightChars/m_minWidthChars
438  QSize cs = mw->size();
439  if (m_minWidthChars > 0) { cs.setWidth(qRound(fontMetricEstSize.width())); }
440  if (m_minHeightChars > 0) { cs.setHeight(qRound(fontMetricEstSize.height())); }
441  mw->resize(cs);
442  }
443  }
444  if (m_saveMainWidgetState && !this->isSet(m_cmdWindowSizeReset))
445  {
446  const Qt::KeyboardModifiers km = QGuiApplication::queryKeyboardModifiers();
447  const bool shiftAlt = km.testFlag(Qt::ShiftModifier) && km.testFlag(Qt::AltModifier);
448  if (!shiftAlt) { this->restoreWindowGeometryAndState(); }
449  }
450 
451  if (m_splashScreen)
452  {
453  m_splashScreen->close(); // GUI
454  m_splashScreen.reset();
455  }
456  }
457 
458  double CGuiApplication::parseScaleFactor(int argc, char *argv[])
459  {
460  for (int i = 1; i < argc; ++i)
461  {
462  if (qstrcmp(argv[i], "--scale") == 0 || qstrcmp(argv[i], "-scale") == 0)
463  {
464  if (i + 1 >= argc) { return -1.0; } // no value
465  const QString factor(argv[i + 1]);
466  bool ok;
467  const double f = factor.toDouble(&ok);
468  return ok ? f : -1.0;
469  }
470  }
471  return -1.0;
472  }
473 
474  QString CGuiApplication::scaleFactor(int argc, char *argv[])
475  {
476  for (int i = 1; i < argc; ++i)
477  {
478  if (qstrcmp(argv[i], "--scale") == 0 || qstrcmp(argv[i], "-scale") == 0)
479  {
480  if (i + 1 >= argc) { return QString(); } // no value
481  const QString factor(argv[i + 1]);
482  return factor.trimmed();
483  }
484  }
485  return QString();
486  }
487 
489  {
490  if (!CBuildConfig::isRunningOnWindowsNtPlatform()) { return "1.0"; }
491 
492  // On windows
493  // Qt 5.14.1 default is device ratio 3
494  // Qt 5.14.0 default device ratio was 2
495 
496  // 2/3 (0.66667) => device ratio 3
497  // 0.75 => device ratio 2.25
498  // 0.8 => device ratio 2.4
499  // 1.00 => device ratio 3
500 
501  // currently NOT used
502  return "1.0";
503  }
504 
505  void CGuiApplication::cmdLineErrorMessage(const QString &text, const QString &informativeText) const
506  {
507  QMessageBox errorBox(QMessageBox::Critical, QGuiApplication::applicationDisplayName(), "<b>" + text + "</b>");
508  if (informativeText.length() < 300)
509  errorBox.setInformativeText(informativeText);
510  else
511  errorBox.setDetailedText(informativeText);
512 
513  errorBox.addButton(QMessageBox::Abort);
514 
515  errorBox.exec();
516  }
517 
519  {
520  if (msgs.isEmpty()) { return; }
521  if (!msgs.hasErrorMessages()) { return; }
522  static const CPropertyIndexList propertiesSingle({ CStatusMessage::IndexMessage });
523  static const CPropertyIndexList propertiesMulti(
524  { CStatusMessage::IndexSeverityAsString, CStatusMessage::IndexMessage });
525  const QString msgsHtml = msgs.toHtml(msgs.size() > 1 ? propertiesMulti : propertiesSingle);
526  QMessageBox::critical(nullptr, QGuiApplication::applicationDisplayName(),
527  "<html><head><body>" + msgsHtml + "</body></html>", QMessageBox::Abort,
528  QMessageBox::NoButton);
529  }
530 
531  bool CGuiApplication::isCmdWindowSizeResetSet() const { return this->isParserOptionSet(m_cmdWindowSizeReset); }
532 
534  {
536  SWIFT_VERIFY_X(m, Q_FUNC_INFO, "No access interface");
537  if (!m) { return false; }
538  return m->displayInStatusBar(message);
539  }
540 
541  bool CGuiApplication::displayInOverlayWindow(const CStatusMessage &message, std::chrono::milliseconds timeout)
542  {
543  if (message.isEmpty()) { return false; }
545  SWIFT_VERIFY_X(m, Q_FUNC_INFO, "No access interface");
546  if (!m) { return IMainWindowAccess::displayInOverlayWindow(message, timeout); }
547  return m->displayInOverlayWindow(message, timeout);
548  }
549 
550  bool CGuiApplication::displayInOverlayWindow(const CStatusMessageList &messages, std::chrono::milliseconds timeout)
551  {
552  if (messages.isEmpty()) { return false; }
554  SWIFT_VERIFY_X(m, Q_FUNC_INFO, "No access interface");
555  if (!m) { return IMainWindowAccess::displayInOverlayWindow(messages, timeout); }
556  return m->displayInOverlayWindow(messages, timeout);
557  }
558 
559  bool CGuiApplication::displayInOverlayWindow(const QString &html, std::chrono::milliseconds timeout)
560  {
561  if (html.isEmpty()) { return false; }
563  SWIFT_VERIFY_X(m, Q_FUNC_INFO, "No access interface");
564  if (!m) { return IMainWindowAccess::displayInOverlayWindow(html, timeout); }
565  return m->displayInOverlayWindow(html, timeout);
566  }
567 
569  {
570  QMenu *sm = menu.addMenu(CIcons::appSettings16(), "Settings");
571  sm->setIcon(CIcons::appSettings16());
572  QAction *a = sm->addAction(CIcons::disk16(), "Settings directory");
573  bool c = connect(a, &QAction::triggered, this, [=]() {
574  if (!sGui || sGui->isShuttingDown()) { return; }
575  const QString path(QDir::toNativeSeparators(CSettingsCache::persistentStore()));
576  if (QDir(path).exists()) { QDesktopServices::openUrl(QUrl::fromLocalFile(path)); }
577  });
578  Q_ASSERT_X(c, Q_FUNC_INFO, "Connect failed");
579 
580  a = sm->addAction("Reset settings");
581  c = connect(a, &QAction::triggered, this, [=] {
582  if (!sGui || sGui->isShuttingDown()) { return; }
583  CSettingsCache::instance()->clearAllValues();
584  CLogMessage(this).info(u"Cleared all settings!");
585  });
586  Q_ASSERT_X(c, Q_FUNC_INFO, "Connect failed");
587 
588  a = sm->addAction("List settings files");
589  c = connect(a, &QAction::triggered, this, [=]() {
590  if (!sGui || sGui->isShuttingDown()) { return; }
591  const QStringList files(CSettingsCache::instance()->enumerateStore());
592  CLogMessage(this).info(files.join("\n"));
593  });
594  Q_ASSERT_X(c, Q_FUNC_INFO, "Connect failed");
595 
596  sm = menu.addMenu("Cache");
597  sm->setIcon(CIcons::appSettings16());
598  a = sm->addAction(CIcons::disk16(), "Cache directory");
599  c = connect(a, &QAction::triggered, this, [=]() {
600  const QString path(QDir::toNativeSeparators(CDataCache::persistentStore()));
601  if (QDir(path).exists()) { QDesktopServices::openUrl(QUrl::fromLocalFile(path)); }
602  });
603  Q_ASSERT_X(c, Q_FUNC_INFO, "Connect failed");
604 
605  a = sm->addAction("Reset cache");
606  c = connect(a, &QAction::triggered, this, [=]() {
607  if (!sGui || sGui->isShuttingDown()) { return; }
608  const QStringList files = CApplication::clearCaches();
609  CLogMessage(this).info(u"Cleared caches! " % QString::number(files.size()) + " files");
610  });
611  Q_ASSERT_X(c, Q_FUNC_INFO, "Connect failed");
612 
613  a = sm->addAction("List cache files");
614  c = connect(a, &QAction::triggered, this, [=]() {
615  if (!sGui || sGui->isShuttingDown()) { return; }
616  const QStringList files(CDataCache::instance()->enumerateStore());
617  CLogMessage(this).info(files.join("\n"));
618  });
619  Q_ASSERT_X(c, Q_FUNC_INFO, "Connect failed");
620 
621  a = menu.addAction(CIcons::disk16(), "Log directory");
622  c = connect(a, &QAction::triggered, this, [=]() {
623  if (!sGui || sGui->isShuttingDown()) { return; }
624  this->openStandardLogDirectory();
625  });
626  Q_ASSERT_X(c, Q_FUNC_INFO, "Connect failed");
627 
628  a = menu.addAction(CIcons::disk16(), "Crash dumps directory");
629  c = connect(a, &QAction::triggered, this, [=]() {
630  if (!sGui || sGui->isShuttingDown()) { return; }
631  this->openStandardCrashDumpDirectory();
632  });
633  Q_ASSERT_X(c, Q_FUNC_INFO, "Connect failed");
634 
635  a = menu.addAction(CIcons::swift24(), "Check for updates");
636  c = connect(a, &QAction::triggered, this, &CGuiApplication::checkNewVersionMenu);
637  Q_ASSERT_X(c, Q_FUNC_INFO, "Connect failed");
638  Q_UNUSED(c)
639  }
640 
642  {
643  QMenu *sm = menu.addMenu("Style sheet");
644  QAction *aReload = sm->addAction(CIcons::refresh16(), "Reload");
645  bool c = connect(aReload, &QAction::triggered, this, [=]() {
646  if (!sGui || sGui->isShuttingDown()) { return; }
647  this->reloadStyleSheets();
648  });
649  Q_ASSERT_X(c, Q_FUNC_INFO, "Connect failed");
650 
651  QAction *aOpen = sm->addAction(CIcons::text16(), "Open qss file");
652  c = connect(aOpen, &QAction::triggered, this, [=]() {
653  if (!sGui || sGui->isShuttingDown()) { return; }
654  this->openStandardWidgetStyleSheet();
655  });
656  Q_ASSERT_X(c, Q_FUNC_INFO, "Connect failed");
657  Q_UNUSED(c)
658  }
659 
661  {
663  addMenuForStyleSheets(menu);
664  QAction *a = nullptr;
665  bool c = false;
666 
667  menu.addSeparator();
668  a = menu.addAction("E&xit");
669  // a->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Q)); // avoid accidentally closing
670  c = connect(
671  a, &QAction::triggered, this,
672  [=]() {
673  // a close event might already trigger a shutdown
674  if (!sGui || sGui->isShuttingDown()) { return; }
675  if (!CGuiApplication::mainApplicationWidget()) { return; }
677 
678  // T596, do not shutdown here, as close can be canceled
679  // if shutdown is called, there is no way back
680  // this->gracefulShutdown();
681  },
682  Qt::QueuedConnection);
683  Q_ASSERT_X(c, Q_FUNC_INFO, "Connect failed");
684  Q_UNUSED(c)
685  }
686 
688  {
689  QMenu *sm = menu.addMenu("JSON files/Templates");
690  QAction *a = sm->addAction("JSON bootstrap");
691  bool c = connect(
692  a, &QAction::triggered, this,
693  [=]() {
694  if (!sGui || sGui->isShuttingDown()) { return; }
695  const CGlobalSetup s = this->getGlobalSetup();
696  CLogMessage(this).info(s.toJsonString());
697  },
698  Qt::QueuedConnection);
699  Q_ASSERT_X(c, Q_FUNC_INFO, "Connect failed");
700 
701  a = sm->addAction("JSON version update info (for info only)");
702  c = connect(
703  a, &QAction::triggered, this,
704  [=]() {
705  if (!sGui || sGui->isShuttingDown()) { return; }
706  const CUpdateInfo info = this->getUpdateInfo();
707  CLogMessage(this).info(info.toJsonString());
708  },
709  Qt::QueuedConnection);
710  Q_ASSERT_X(c, Q_FUNC_INFO, "Connect failed");
711 
712  if (this->hasWebDataServices())
713  {
714  a = menu.addAction("Services log.(console)");
715  c = connect(
716  a, &QAction::triggered, this,
717  [=]() {
718  if (!sGui || sGui->isShuttingDown()) { return; }
719  CLogMessage(this).info(this->getWebDataServices()->getReadersLog());
720  },
721  Qt::QueuedConnection);
722  Q_ASSERT_X(c, Q_FUNC_INFO, "Connect failed");
723 
724  a = sm->addAction("JSON DB info (for info only)");
725  c = connect(
726  a, &QAction::triggered, this,
727  [=]() {
728  if (!sGui || sGui->isShuttingDown()) { return; }
729  if (!this->getWebDataServices()->getDbInfoDataReader()) { return; }
731  CLogMessage(this).info(u"DB info:\n" % info.toJsonString());
732  },
733  Qt::QueuedConnection);
734  Q_ASSERT_X(c, Q_FUNC_INFO, "Connect failed");
735 
736  a = sm->addAction("JSON shared info (for info only)");
737  c = connect(
738  a, &QAction::triggered, this,
739  [=]() {
740  if (!sGui || sGui->isShuttingDown()) { return; }
741  if (!this->getWebDataServices()->getDbInfoDataReader()) { return; }
743  CLogMessage(this).info(u"Shared info:\n" % info.toJsonString());
744  },
745  Qt::QueuedConnection);
746  Q_ASSERT_X(c, Q_FUNC_INFO, "Connect failed");
747  }
748 
749  a = menu.addAction("Metadata (slow)");
750  c = connect(
751  a, &QAction::triggered, this,
752  [=]() {
753  if (!sGui || sGui->isShuttingDown()) { return; }
755  },
756  Qt::QueuedConnection);
757  Q_ASSERT_X(c, Q_FUNC_INFO, "Connect failed");
758  Q_UNUSED(c)
759  }
760 
762  {
763  QPointer<QWidget> w = CGuiApplication::mainApplicationWidget();
764  if (!w) { return; }
765  const QSize iconSize = CIcons::empty16().size();
766  static QPixmap iconEmpty;
767 
768  QPixmap icon = w->style()->standardIcon(QStyle::SP_TitleBarMaxButton).pixmap(iconSize);
769  QAction *a = menu.addAction(icon.isNull() ? iconEmpty : icon.scaled(iconSize), "Fullscreen");
770  bool c = connect(a, &QAction::triggered, this, [=]() {
771  if (!w) { return; }
772  w->showFullScreen();
773  });
774  Q_ASSERT_X(c, Q_FUNC_INFO, "Connect failed");
775 
776  icon = w->style()->standardIcon(QStyle::SP_TitleBarMinButton).pixmap(iconSize);
777  a = menu.addAction(icon.isNull() ? iconEmpty : icon.scaled(iconSize), "Minimize");
778  c = connect(a, &QAction::triggered, this, [=]() {
779  if (!w) { return; }
780  w->showMinimized();
781  });
782  Q_ASSERT_X(c, Q_FUNC_INFO, "Connect failed");
783 
784  icon = w->style()->standardIcon(QStyle::SP_TitleBarNormalButton).pixmap(iconSize);
785  a = menu.addAction(icon.isNull() ? iconEmpty : icon.scaled(iconSize), "Normal");
786  c = connect(a, &QAction::triggered, this, [=]() {
787  if (!w) { return; }
788  w->showNormal();
789  });
790  Q_ASSERT_X(c, Q_FUNC_INFO, "Connect failed");
791 
792  a = menu.addAction("Toggle stay on top");
793  c = connect(a, &QAction::triggered, this, [=]() {
794  if (!w) { return; }
795  this->toggleStayOnTop();
796  });
797  Q_ASSERT_X(c, Q_FUNC_INFO, "Connect failed");
798 
799  a = menu.addAction("Toggle to front or back");
800  c = connect(a, &QAction::triggered, this, &CGuiApplication::windowToFrontBackToggle);
801  Q_ASSERT_X(c, Q_FUNC_INFO, "connect failed");
802 
803  a = menu.addAction("Window to front");
804  c = connect(a, &QAction::triggered, this, &CGuiApplication::windowToFront);
805  Q_ASSERT_X(c, Q_FUNC_INFO, "connect failed");
806 
807  a = menu.addAction("Window to back");
808  c = connect(a, &QAction::triggered, this, &CGuiApplication::windowToBack);
809  Q_ASSERT_X(c, Q_FUNC_INFO, "connect failed");
810 
811  a = menu.addAction("Toggle normal or minimized");
812  c = connect(a, &QAction::triggered, this, [=]() {
813  if (!w) { return; }
815  });
816  Q_ASSERT_X(c, Q_FUNC_INFO, "Connect failed");
817  Q_UNUSED(c)
818  }
819 
821  {
822  if (url.isEmpty() || this->isShuttingDown()) { return; }
823  QDesktopServices::openUrl(url);
824  }
825 
827  {
828  QPointer<QWidget> w = mainApplicationWidget();
829  if (!w) { return; }
830  QAction *a = menu.addAction(w->style()->standardIcon(QStyle::SP_TitleBarContextHelpButton), "Online help");
831 
832  bool c = connect(a, &QAction::triggered, this, [=]() {
833  if (!sGui || sGui->isShuttingDown()) { return; }
834  this->showHelp();
835  });
836  Q_ASSERT_X(c, Q_FUNC_INFO, "Connect failed");
837 
838  a = menu.addAction(QApplication::windowIcon(), "About swift");
839  c = connect(a, &QAction::triggered, this, [=]() {
840  if (!w) { return; }
841  CAboutDialog dialog(w);
842  dialog.exec();
843  });
844  Q_ASSERT_X(c, Q_FUNC_INFO, "Connect failed");
845  Q_UNUSED(c)
846 
847  // https://joekuan.wordpress.com/2015/09/23/list-of-qt-icons/
848  a = menu.addAction(QApplication::style()->standardIcon(QStyle::SP_TitleBarMenuButton), "About Qt");
849  c = connect(a, &QAction::triggered, this, []() { QApplication::aboutQt(); });
850  Q_ASSERT_X(c, Q_FUNC_INFO, "Connect failed");
851  Q_UNUSED(c)
852  }
853 
854  void CGuiApplication::showHelp(const QString &context) const
855  {
856  if (this->isShuttingDown()) { return; }
857  const CGlobalSetup gs = this->getGlobalSetup();
858  const CUrl helpPage = gs.getHelpPageUrl(context);
859  if (helpPage.isEmpty())
860  {
861  CLogMessage(this).warning(u"No help page");
862  return;
863  }
864  QDesktopServices::openUrl(helpPage);
865  }
866 
867  void CGuiApplication::showHelp(const QObject *qObject) const
868  {
869  if (this->isShuttingDown()) { return; }
870  if (!qObject || qObject->objectName().isEmpty()) { this->showHelp(); }
871  else { this->showHelp(qObject->objectName()); }
872  }
873 
874  bool CGuiApplication::triggerShowHelp(const QWidget *widget, QEvent *event)
875  {
876  if (!widget) { return false; }
877  if (!event) { return false; }
878  const QEvent::Type t = event->type();
879  if (t != QEvent::EnterWhatsThisMode) { return false; }
880  QWhatsThis::leaveWhatsThisMode();
881  event->accept();
882  if (!widget->isVisible()) { return true; } // ignore invisble ones
883  const QPointer<const QWidget> wp(widget);
884  QTimer::singleShot(0, sGui, [=] {
885  if (!wp || !sGui || sGui->isShuttingDown()) { return; }
886  sGui->showHelp(widget);
887  });
888  return true;
889  }
890 
891  const CStyleSheetUtility &CGuiApplication::getStyleSheetUtility() const { return m_styleSheetUtility; }
892 
894  {
895  QString currentWidgetStyle(QApplication::style()->metaObject()->className());
896  if (currentWidgetStyle.startsWith('Q')) { currentWidgetStyle.remove(0, 1); }
897  return currentWidgetStyle.replace("Style", "");
898  }
899 
900  bool CGuiApplication::reloadStyleSheets() { return m_styleSheetUtility.read(); }
901 
903  {
905  return QDesktopServices::openUrl(QUrl::fromLocalFile(fn));
906  }
907 
909  {
910  const QString path(QDir::toNativeSeparators(CSwiftDirectories::logDirectory()));
911  if (!QDir(path).exists()) { return false; }
912  return QDesktopServices::openUrl(QUrl::fromLocalFile(path));
913  }
914 
916  {
917  const QString path(QDir::toNativeSeparators(CSwiftDirectories::crashpadDatabaseDirectory()));
918  if (!QDir(path).exists()) { return false; }
919  return QDesktopServices::openUrl(QUrl::fromLocalFile(path));
920  }
921 
922  bool CGuiApplication::updateFont(const QString &fontFamily, const QString &fontSize, const QString &fontStyle,
923  const QString &fontWeight, const QString &fontColor)
924  {
925  return m_styleSheetUtility.updateFont(fontFamily, fontSize, fontStyle, fontWeight, fontColor);
926  }
927 
928  bool CGuiApplication::updateFont(const QString &qss) { return m_styleSheetUtility.updateFont(qss); }
929 
930  bool CGuiApplication::resetFont() { return m_styleSheetUtility.resetFont(); }
931 
932  void CGuiApplication::setMinimumSizeInCharacters(int widthChars, int heightChars)
933  {
934  m_minWidthChars = widthChars;
935  m_minHeightChars = heightChars;
936  }
937 
939  {
940  if (msgs.hasErrorMessages())
941  {
943  if (sGui)
944  {
945  static const QString style = sGui->getStyleSheetUtility().styles(
947  dialog.setStyleSheet(style);
948  }
949 
950  dialog.exec();
951  }
952  }
953 
954  QDialog::DialogCode CGuiApplication::showCloseDialog(QMainWindow *mainWindow, QCloseEvent *closeEvent)
955  {
956  this->saveSettingsOnShutdown(false); // saving itself will be handled in dialog
957  const bool needsDialog = this->hasUnsavedSettings();
958  if (!needsDialog) { return QDialog::Accepted; }
959  if (!m_closeDialog)
960  {
961  m_closeDialog = new CApplicationCloseDialog(mainWindow);
962  if (mainWindow && !mainWindow->windowTitle().isEmpty())
963  {
964  m_closeDialog->setWindowTitle(mainWindow->windowTitle());
965  m_closeDialog->setModal(true);
966  }
967  }
968 
969  // dialog will handle the saving
970  const auto c = static_cast<QDialog::DialogCode>(m_closeDialog->exec());
971 
972  // settings already saved when reaching here
973  switch (c)
974  {
975  case QDialog::Rejected:
976  if (closeEvent) { closeEvent->ignore(); }
977  break;
978  default: break;
979  }
980  return c;
981  }
982 
983  bool CGuiApplication::parsingHookIn() { return true; }
984 
986  {
987  // Nothing to do here
988  }
989 
990  void CGuiApplication::checkNewVersion(bool onlyIfNew)
991  {
992  if (!m_updateDialog)
993  {
994  // without parent stylesheet is not inherited
996  }
997 
998  if (onlyIfNew && !m_updateDialog->isNewVersionAvailable()) { return; }
999  const int result = m_updateDialog->exec();
1000  if (result != QDialog::Accepted) { return; }
1001  }
1002 
1004  {
1005  const QWidget *w = CGuiApplication::mainApplicationWidget();
1006  if (!w) { return QStringLiteral("Font info not available"); }
1007  return QStringLiteral("Family: '%1', average width: %2")
1008  .arg(w->font().family())
1009  .arg(w->fontMetrics().averageCharWidth());
1010  }
1011 
1013  {
1014  QMainWindow *w = CGuiApplication::mainApplicationWindow();
1015  if (!w) { return false; }
1016  const bool onTop = CGuiUtility::toggleStayOnTop(w);
1017  CLogMessage(w).info(onTop ? QStringLiteral("Window on top") : QStringLiteral("Window not always on top"));
1018  emit this->alwaysOnTop(onTop);
1019  m_frontBack = onTop;
1020  return onTop;
1021  }
1022 
1024  {
1025  if (this->isShuttingDown()) { return; }
1026  QMainWindow *w = CGuiApplication::mainApplicationWindow();
1027  if (!w) { return; }
1028 
1029  m_frontBack = true;
1030  w->showNormal(); // bring window to top on OSX
1031  w->raise(); // bring window from minimized state on OSX
1032 
1033  // if (!CGuiUtility::staysOnTop(w)) { CGuiUtility::stayOnTop(true, w); emit this->alwaysOnTop(true); }
1034  w->activateWindow(); // bring window to front/unminimize on windows
1035  }
1036 
1038  {
1039  if (this->isShuttingDown()) { return; }
1040  QMainWindow *w = CGuiApplication::mainApplicationWindow();
1041  if (!w) { return; }
1042 
1043  m_frontBack = false;
1044  if (CGuiUtility::staysOnTop(w))
1045  {
1046  CGuiUtility::stayOnTop(false, w);
1047  emit this->alwaysOnTop(false);
1048  }
1049  w->lower();
1050  }
1051 
1053  {
1054  if (this->isShuttingDown()) { return; }
1055  QMainWindow *w = CGuiApplication::mainApplicationWindow();
1056  if (!w) { return; }
1057  if (w->isMinimized())
1058  {
1059  this->windowToFront();
1060  return;
1061  }
1062  if (w->isMaximized())
1063  {
1064  this->windowToBack();
1065  return;
1066  }
1067  if (CGuiUtility::staysOnTop(w))
1068  {
1069  this->windowToBack();
1070  return;
1071  }
1072 
1073  if (m_frontBack) { this->windowToBack(); }
1074  else { this->windowToFront(); }
1075  }
1076 
1078  {
1079  if (this->isShuttingDown()) { return; }
1080  QMainWindow *w = CGuiApplication::mainApplicationWindow();
1081  if (!w) { return; }
1082  if (m_normalizeMinimize) { w->showMinimized(); }
1083  else
1084  {
1085  // trick here is to minimize first and the normalize from minimized state
1086  w->showMinimized();
1087  w->showNormal();
1088  }
1089  m_normalizeMinimize = !m_normalizeMinimize;
1090  }
1091 
1093  {
1094  if (!m_updateSetting.get()) { return; }
1095  QTimer::singleShot(delayedMs, this, [=] {
1096  if (!sGui || sGui->isShuttingDown()) { return; }
1097  if (m_updateDialog) { return; } // already checked elsewhere
1098  this->checkNewVersion(true);
1099  });
1100  }
1101 
1103  {
1104  if (m_shutdown) { return; }
1105  if (m_shutdownInProgress) { return; }
1106 
1107  CLogMessage(this).info(u"Graceful shutdown of GUI application started");
1108  if (m_saveMainWidgetState)
1109  {
1110  CLogMessage(this).info(u"Graceful shutdown, saving geometry");
1112  }
1113 
1114  // shut down whole infrastructure
1115  CApplication::gracefulShutdown();
1116 
1117  // precautions to avoid hanging closing swift
1118  const QStringList modals = CGuiUtility::closeAllModalWidgetsGetTitles();
1119  if (modals.count() > 0)
1120  {
1121  // that is a pretty normal situation
1122  CLogMessage(this).info(u"Graceful shutdown, still %1 modal widget(s), closed: %2")
1123  << modals.count() << modals.join(", ");
1124  }
1125 
1128  const QStringList docks =
1130  if (docks.count() > 0)
1131  {
1132  // that should not happen
1133  CLogMessage(this).warning(u"Graceful shutdown, still %1 floating dock widget(s), closed: %2")
1134  << docks.count() << docks.join(", ");
1135  }
1136  }
1137 
1138  void CGuiApplication::settingsChanged()
1139  {
1140  // changing widget style is slow, so I try to prevent setting it when nothing changed
1141  const QString widgetStyle = m_guiSettings.get().getWidgetStyle();
1142  const QString currentWidgetStyle(this->getWidgetStyle());
1143  Q_ASSERT_X(CThreadUtils::thisIsMainThread(), Q_FUNC_INFO, "Wrong thread");
1144  if (!stringCompare(widgetStyle, currentWidgetStyle, Qt::CaseInsensitive))
1145  {
1146  const QStringList availableStyles = QStyleFactory::keys();
1147  if (availableStyles.contains(widgetStyle))
1148  {
1149  // changing style freezes the application, so it must not be done in flight mode
1150  if (this->getIContextNetwork() && this->getIContextNetwork()->isConnected())
1151  {
1152  CLogMessage(this).validationError(u"Cannot change style while connected to network");
1153  }
1154  else
1155  {
1156  // QStyle *style = QApplication::setStyle(widgetStyle);
1157  QStyle *style = QStyleFactory::create(widgetStyle);
1158  // That can crash
1159  QApplication::setStyle(style); // subject of crash
1160  if (style)
1161  {
1162  CLogMessage(this).info(u"Changed style to '%1', req.: '%2'")
1163  << style->objectName() << widgetStyle;
1164  }
1165  else { CLogMessage(this).error(u"Unable to set requested style '%1'") << widgetStyle; }
1166  }
1167  } // valid style
1168  }
1169  }
1170 
1171  void CGuiApplication::checkNewVersionMenu() { this->checkNewVersion(false); }
1172 
1173  void CGuiApplication::adjustPalette()
1174  {
1175  // only way to change link color
1176  // https://stackoverflow.com/q/5497799/356726
1177  // Ref T84
1178  QPalette newPalette(qApp->palette());
1179  const QColor linkColor(135, 206, 250);
1180  newPalette.setColor(QPalette::Link, linkColor);
1181  newPalette.setColor(QPalette::LinkVisited, linkColor);
1182  qApp->setPalette(newPalette);
1183  }
1184 
1185  void CGuiApplication::onStyleSheetsChanged()
1186  {
1187  const QFont f = CGuiUtility::currentFont();
1188  if (f.pointSize() != m_fontPointSize || f.family() != m_fontFamily)
1189  {
1190  emit this->fontChanged();
1191  CLogMessage(this).info(this->getFontInfo());
1192  }
1193  emit this->styleSheetsChanged();
1194  }
1195 
1196  void CGuiApplication::setCurrentFontValues()
1197  {
1198  const QFont font = CGuiUtility::currentFont();
1199  m_fontFamily = font.family();
1200  m_fontPointSize = font.pointSize();
1201  }
1202 
1203  void CGuiApplication::superviseWindowMinSizes() { CGuiUtility::superviseMainWindowMinSizes(); }
1204 } // namespace swift::gui
static constexpr bool isRunningOnWindowsNtPlatform()
Running on Windows NT platform?
QString getParserValue(const QString &option) const
Delegates to QCommandLineParser::value.
std::atomic_bool m_shutdown
Is being shutdown?
Definition: application.h:579
void restartApplication(const QStringList &newArguments={}, const QStringList &removeArguments={})
Stop and restart application.
bool isParserOptionSet(const QString &option) const
Delegates to QCommandLineParser::isSet.
data::CGlobalSetup getGlobalSetup() const
Global setup.
QCommandLineParser m_parser
cmd parser
Definition: application.h:568
bool hasUnsavedSettings() const
Unsaved settings.
bool hasWebDataServices() const
Web data services available?
const context::IContextNetwork * getIContextNetwork() const
Direct access to contexts if a CCoreFacade has been initialized.
bool addParserOption(const QCommandLineOption &option)
bool isShuttingDown() const
Is application shutting down?
bool isSet(const QCommandLineOption &option) const
Flag set or explicitly set to true.
std::atomic_bool m_shutdownInProgress
shutdown in progress?
Definition: application.h:581
const QString & getApplicationNameVersionDetailed() const
Version, name beta and dev info.
CWebDataServices * getWebDataServices() const
Get the web data services.
const QString & getApplicationNameAndVersion() const
Application name and version.
void saveSettingsOnShutdown(bool saveSettings)
Save settings on shutdown.
void startUpCompleted(bool success)
Startup has been completed Will be triggered shortly before starting the event loop.
swift::core::db::CInfoDataReader * getDbInfoDataReader() const
DB info data reader.
swift::core::db::CInfoDataReader * getSharedInfoDataReader() const
Shared info data reader.
Global settings for readers, debug flags, etc.
Definition: globalsetup.h:31
swift::misc::network::CUrl getHelpPageUrl(const QString &context={}) const
Help page URL.
Definition: globalsetup.cpp:44
swift::misc::db::CDbInfoList getInfoObjects() const
Get info list (either shared or from DB)
static WindowMode stringToWindowMode(const QString &s)
String to window mode.
GUI application, a specialized version of swift::core::CApplication for GUI applications.
bool openStandardWidgetStyleSheet()
Opens the standard stylesheet.
static void modalWindowToFront()
Bring any modal dialog to front.
bool isCmdWindowSizeResetSet() const
Window size reset mode set.
QString setExtraWindowTitle(const QString &extraInfo, QWidget *mainWindowWidget=mainApplicationWidget()) const
Set window title.
QString getFontInfo() const
Info about font.
static swift::gui::IMainWindowAccess * mainWindowAccess()
Main window access interface.
void onCoreFacadeStarted()
Called when facade/contexts have been started.
void registerMainApplicationWidget(QWidget *mainWidget)
Register main application window widget if this is known.
void addWindowResetSizeOption()
CMD line arguments (reset size store)
void addWindowStateOption()
CMD line arguments.
void processEventsToRefreshGui() const
Allow the GUI to refresh by processing events, call the event loop.
Qt::WindowState getWindowState() const
Window state.
static QString scaleFactor(int argc, char *argv[])
Get the scale factor.
bool hasMinimumMappingVersion() const
Minimum mapping version check.
void addWindowModeOption()
CMD line arguments.
static QRect currentScreenGeometry()
Current screen resolution.
void triggerNewVersionCheck(int delayedMs)
Trigger new version check.
bool openStandardCrashDumpDirectory()
Opens the standard dumps directory.
static CGuiApplication * instance()
Similar to.
void windowToFront()
Window to front/back.
CEnableForFramelessWindow::WindowMode getWindowMode() const
Window mode (window flags)
void addMenuHelp(QMenu &menu)
Help operations.
void addMenuForStyleSheets(QMenu &menu)
Add menu for style sheets.
bool reloadStyleSheets()
Reload style sheets.
void cmdLineErrorMessage(const QString &text, const QString &informativeText) const
print messages generated during parsing / cmd handling
static void exit(int retcode=0)
Exit application, perform graceful shutdown and exit.
void addMenuFile(QMenu &menu)
File menu.
void addMenuInternals(QMenu &menu)
Internals menu.
bool displayInOverlayWindow(const swift::misc::CStatusMessage &message, std::chrono::milliseconds timeout=std::chrono::milliseconds(0))
direct access to main application window
void checkNewVersion(bool onlyIfNew)
Check for a new version (update)
void splashScreen(const QPixmap &pixmap)
Add a splash screen based on resource, empty means remove splash screen.
void addWindowScaleSizeOption()
CMD line arguments (scale size on DPI screens)
bool restoreWindowGeometryAndState(QMainWindow *window=CGuiApplication::mainApplicationWindow())
Restore widget's geometry and state.
void fontChanged()
Font has been changed.
const CStyleSheetUtility & getStyleSheetUtility() const
Style sheet handling.
bool saveWindowGeometryAndState(const QMainWindow *window=CGuiApplication::mainApplicationWindow()) const
Save widget's geometry and state.
QDialog::DialogCode showCloseDialog(QMainWindow *mainWindow, QCloseEvent *closeEvent)
Show close dialog.
void windowToBack()
Window to front/back.
void gracefulShutdown()
Graceful shutdown.
void onStartUpCompleted()
Startup completed.
bool toggleStayOnTop()
Toggle stay on top.
void windowToFrontBackToggle()
Window to front/back.
static bool triggerShowHelp(const QWidget *widget, QEvent *event)
Static version used with dialogs.
static void registerMetadata()
Register metadata.
static void setWindowIcon(const QPixmap &icon)
Set icon.
bool resetFont()
Reset the font to default.
void displaySetupLoadFailure(swift::misc::CStatusMessageList msgs)
Display the failures caused by loading the setup file.
void windowMinimizeNormalToggle()
Window minimize/normalize.
void addMenuForSettingsAndCache(QMenu &menu)
Add menu items for settings and cache.
bool updateFont(const QString &fontFamily, const QString &fontSize, const QString &fontStyle, const QString &fontWeight, const QString &fontColor)
Update the fonts.
bool displayInStatusBar(const swift::misc::CStatusMessage &message)
direct access to main application window
void alwaysOnTop(bool onTop)
always on top
static double parseScaleFactor(int argc, char *argv[])
Parse scale factor if any.
static QWidget * mainApplicationWidget()
Main application window widget.
static QMainWindow * mainApplicationWindow()
Main application window.
bool parsingHookIn()
Handle parsing of special GUI cmd arguments.
void uiObjectTreeReady()
Object tree ready (means ui->setupUi() completed)
void openUrl(const swift::misc::network::CUrl &url)
Open a given URL.
bool openStandardLogDirectory()
Opens the standard log directory.
static bool isUsingHighDpiScreenSupport()
Uses the high DPI support?
void addMenuWindow(QMenu &menu)
Window operations.
void initMainApplicationWidget(QWidget *mainWidget)
Init the main application window based on information in this application.
static QScreen * currentScreen()
Current screen.
void showHelp(const QString &context={}) const
Show help page (online help)
void addWindowFlags(Qt::WindowFlags flags)
Set window flag on main application window.
QString getWidgetStyle() const
Current widget style.
void styleSheetsChanged()
Style sheet changed.
static QString defaultScaleFactorString()
Get a default scale factor.
static void highDpiScreenSupport(const QString &scaleFactor={})
Support for high DPI screens.
void setMinimumSizeInCharacters(int widthChars, int heightChars)
Set minimum width/height in characters.
void resetWindowGeometryAndState()
Reset the saved values.
static bool stayOnTop(bool onTop, QWidget *widget)
Window flags / stay on top.
Definition: guiutility.cpp:594
static QStringList deleteLaterAllDockWidgetsGetTitles(QWidget *parent, bool floatingOnly)
"deleteLater" all dock widgets
static bool staysOnTop(QWidget *widget)
Window on top?
Definition: guiutility.cpp:554
static void registerMainApplicationWidget(QWidget *mainWidget)
Register main application window widget if this is known.
Definition: guiutility.cpp:87
static QSizeF fontMetricsEstimateSize(int xCharacters, int yCharacters, bool withRatio=false)
Estimate size based on current font.
Definition: guiutility.cpp:765
static void superviseMainWindowMinSizes(qreal wRatio=0.85, qreal hRatio=0.85)
Make sure that the min.sizes to not exceed the screen resolution.
Definition: guiutility.cpp:839
static QString metricsInfo()
Some info about font metrics.
Definition: guiutility.cpp:800
static bool isUsingHighDpiScreenSupport()
Using high DPI screen support.
Definition: guiutility.cpp:825
static QWidget * mainApplicationWidget()
Main application window widget.
Definition: guiutility.cpp:92
static QStringList closeAllModalWidgetsGetTitles()
Close all modal widgets and get titles.
static QFont currentFont()
Main window font or default font.
Definition: guiutility.cpp:738
static bool toggleStayOnTop(QWidget *widget)
Toggle window flags / stay on top.
Definition: guiutility.cpp:575
Own splash screen.
Definition: splashscreen.h:22
Reads and provides style sheets.
static const QString & fileNameStandardWidget()
File name for standard widgets.
bool updateFont(const QFont &font)
Update the fonts.
static void setQSysInfoProperties(QWidget *widget, bool withChildWidgets)
Set QSysInfo properties for given widget (which can be used in stylesheet)
bool read()
Read the *.qss files.
static const QString & fileNameAndPathStandardWidget()
Full file path and name for standard widgets.
void styleSheetsChanged()
Sheets have been changed.
QString styles(const QStringList &fileNames) const
Multiple styles concatenated.
static const QString & fileNameFonts()
File name fonts.qss.
Direct acccess to main window`s status bar, info bar and such.
virtual bool displayInOverlayWindow(const swift::misc::CStatusMessage &message, std::chrono::milliseconds timeout=std::chrono::milliseconds(0))
Display in overlay window.
virtual bool displayInStatusBar(const swift::misc::CStatusMessage &message)
Display in status bar.
Setup dialog, if loading the boostrap file fails.
bool isNewVersionAvailable() const
A new version existing?
Application
Enumeration of application roles.
QString toJsonString(QJsonDocument::JsonFormat format=QJsonDocument::Indented) const
Convenience function JSON as string.
Class for emitting a log message.
Definition: logmessage.h:27
Value class for matching log messages based on their categories.
Definition: logpattern.h:49
CLogPattern withSeverity(CStatusMessage::StatusSeverity severity) const
Returns a CLogPattern which will match the same messages as this one, but only with a given severity.
Definition: logpattern.cpp:130
A helper class for subscribing to log messages matching a particular pattern, with the ability to cha...
Definition: loghandler.h:220
void changeSubscription(const CLogPattern &pattern)
Change the pattern which you want to subscribe to.
Derived & warning(const char16_t(&format)[N])
Set the severity to warning, providing a format string.
bool isEmpty() const
Message empty.
Derived & validationError(const char16_t(&format)[N])
Set the severity to error, providing a format string, and adding the validation category.
Derived & error(const char16_t(&format)[N])
Set the severity to error, providing a format string.
Derived & info(const char16_t(&format)[N])
Set the severity to info, providing a format string.
Value object encapsulating a list of property indexes.
size_type size() const
Returns number of elements in the sequence.
Definition: sequence.h:273
bool isEmpty() const
Synonym for empty.
Definition: sequence.h:285
Streamable status message, e.g.
QString getMessage() const
Message.
Status messages, e.g. from Core -> GUI.
QString toHtml(const CPropertyIndexList &indexes=simpleHtmlOutput()) const
Specialized version to convert to HTML.
bool hasErrorMessages() const
Error messages.
Value object encapsulating a list of info objects.
Definition: dbinfolist.h:27
Update info, i.e. artifacts and distributions.
Definition: updateinfo.h:24
Value object encapsulating information of a location, kind of simplified CValueObject compliant versi...
Definition: url.h:27
bool isEmpty() const
Empty.
Definition: url.cpp:54
SWIFT_GUI_EXPORT swift::gui::CGuiApplication * sGui
Single instance of GUI application object.
size_t qHash(const std::string &key, uint seed)
std::string qHash
Definition: metaclass.h:86
Core data traits (aka cached values) and classes.
Backend services of the swift project, like dealing with the network or the simulators.
Definition: actionbind.cpp:7
High level reusable GUI components.
Definition: aboutdialog.cpp:13
GUI related classes.
void registerMetadata()
Register metadata for GUI.
Free functions in swift::misc.
QString getAllUserMetatypesTypes(const QString &separator)
Get all user metatypes.
SWIFT_MISC_EXPORT QString cleanNumber(const QString &number)
Remove leading 0, trailing 0, " ", and "." from a number.
QMetaObject::Connection connectOnce(T *sender, F signal, U *receiver, G &&slot, Qt::ConnectionType type=Qt::AutoConnection)
Wrapper around QObject::connect which disconnects after the signal has been emitted once.
Definition: slot.h:27
SWIFT_MISC_EXPORT double parseFraction(const QString &fraction, double failDefault=std::numeric_limits< double >::quiet_NaN())
Parse a fraction like 2/3.
SWIFT_MISC_EXPORT bool stringCompare(const QString &c1, const QString &c2, Qt::CaseSensitivity cs)
String compare.
QString className(const QObject *object)
Class name as from QMetaObject::className with namespace.
QString applicationName()
Get application name.
Definition: filelogger.cpp:23
auto singleShot(int msec, QObject *target, F &&task)
Starts a single-shot timer which will call a task in the thread of the given object when it times out...
Definition: threadutils.h:30
#define SWIFT_VERIFY_X(COND, WHERE, WHAT)
A weaker kind of assert.
Definition: verify.h:26