diff --git a/src/blackcore/application.cpp b/src/blackcore/application.cpp
index 05bd95f64..07fe3e141 100644
--- a/src/blackcore/application.cpp
+++ b/src/blackcore/application.cpp
@@ -102,7 +102,7 @@ namespace BlackCore
Q_ASSERT_X(!sApp, Q_FUNC_INFO, "already initialized");
Q_ASSERT_X(QCoreApplication::instance(), Q_FUNC_INFO, "no application object");
- // init skiped when called from CGuiApplication
+ // init skipped when called from CGuiApplication
if (init)
{
this->init(true);
@@ -133,8 +133,6 @@ namespace BlackCore
//
// Translations
- const QFile file(":blackmisc/translations/blackmisc_i18n_de.qm");
- CLogMessage(this).debug() << (file.exists() ? "Found translations in resources" : "No translations in resources");
QTranslator translator;
if (translator.load("blackmisc_i18n_de", ":blackmisc/translations/")) { CLogMessage(this).debug() << "Translator loaded"; }
QCoreApplication::instance()->installTranslator(&translator);
@@ -315,7 +313,7 @@ namespace BlackCore
// parse if needed, parsing contains its own error handling
if (!this->m_parsed)
{
- const bool s = this->parse();
+ const bool s = this->parseAndStartupCheck();
if (!s) { return false; }
}
@@ -985,15 +983,24 @@ namespace BlackCore
return this->m_parser.value(option).trimmed();
}
- bool CApplication::parse()
+ bool CApplication::parseAndStartupCheck()
{
- if (this->m_parsed) { return m_parsed; }
+ if (this->m_parsed) { return m_parsed; } // already done
+
+ // checks
if (CBuildConfig::isLifetimeExpired())
{
this->cmdLineErrorMessage("Program exired " + CBuildConfig::getEol().toString());
return false;
}
+ const QStringList verifyErrors = CDirectoryUtils::verifyRuntimeDirectoriesAndFiles();
+ if (!verifyErrors.isEmpty())
+ {
+ this->cmdLineErrorMessage("Missing runtime directories/files: " + verifyErrors.join(", "));
+ return false;
+ }
+
if (this->m_singleApplication && this->m_alreadyRunning)
{
this->cmdLineErrorMessage("Program must only run once");
@@ -1036,7 +1043,7 @@ namespace BlackCore
bool CApplication::cmdLineErrorMessage(const QString &errorMessage, bool retry) const
{
- Q_UNUSED(retry); // onyl works with UI version
+ Q_UNUSED(retry); // only works with UI version
fputs(qPrintable(errorMessage), stderr);
fputs("\n\n", stderr);
fputs(qPrintable(this->m_parser.helpText()), stderr);
@@ -1045,7 +1052,7 @@ namespace BlackCore
bool CApplication::cmdLineErrorMessage(const CStatusMessageList &msgs, bool retry) const
{
- Q_UNUSED(retry); // onyl works with UI version
+ Q_UNUSED(retry); // only works with UI version
if (msgs.isEmpty()) { return false; }
if (!msgs.hasErrorMessages()) { return false; }
CApplication::cmdLineErrorMessage(
diff --git a/src/blackcore/application.h b/src/blackcore/application.h
index a578d218c..6ccd305d6 100644
--- a/src/blackcore/application.h
+++ b/src/blackcore/application.h
@@ -290,7 +290,7 @@ namespace BlackCore
//! \note in some cases (error, version, help) application is terminated during this step
//! \sa parsingHookIn
//! \return true means to continue, false to stop
- bool parse();
+ bool parseAndStartupCheck();
//! @}
//! Display error message
diff --git a/src/blackgui/guiapplication.cpp b/src/blackgui/guiapplication.cpp
index 36255709d..fe06888bd 100644
--- a/src/blackgui/guiapplication.cpp
+++ b/src/blackgui/guiapplication.cpp
@@ -263,9 +263,23 @@ namespace BlackGui
bool CGuiApplication::cmdLineErrorMessage(const QString &errorMessage, bool retry) const
{
const QString helpText(beautifyHelpMessage(this->m_parser.helpText()));
+ constexpr int MaxLength = 60;
+
+ QString htmlMsg;
+ if (errorMessage.length() > MaxLength)
+ {
+ htmlMsg = "
" + errorMessage.left(MaxLength) + "..." + "
" +
+ "Details: " + errorMessage + "
";
+ }
+ else
+ {
+ htmlMsg = "" + errorMessage + "
";
+ }
+ htmlMsg += helpText + "";
+
const int r = QMessageBox::warning(nullptr,
QGuiApplication::applicationDisplayName(),
- "" + errorMessage + "
" + helpText + "", QMessageBox::Abort, retry ? QMessageBox::Retry : QMessageBox::NoButton);
+ htmlMsg, QMessageBox::Abort, retry ? QMessageBox::Retry : QMessageBox::NoButton);
return (r == QMessageBox::Retry);
}
@@ -279,7 +293,7 @@ namespace BlackGui
const QString msgsHtml = msgs.toHtml(msgs.size() > 1 ? propertiesMulti : propertiesSingle);
const int r = QMessageBox::critical(nullptr,
QGuiApplication::applicationDisplayName(),
- "" + msgsHtml + "
" + helpText + "", QMessageBox::Abort, retry ? QMessageBox::Retry : QMessageBox::NoButton);
+ "" + msgsHtml + "
" + helpText + "", QMessageBox::Abort, retry ? QMessageBox::Retry : QMessageBox::NoButton);
return (r == QMessageBox::Retry);
}
diff --git a/src/blackmisc/directoryutils.cpp b/src/blackmisc/directoryutils.cpp
index 1b8482abc..9879e5be9 100644
--- a/src/blackmisc/directoryutils.cpp
+++ b/src/blackmisc/directoryutils.cpp
@@ -327,6 +327,34 @@ namespace BlackMisc
return dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks);
}
+ QStringList CDirectoryUtils::verifyRuntimeDirectoriesAndFiles()
+ {
+ QStringList failed;
+ QDir d(CDirectoryUtils::binDirectory());
+ if (!d.isReadable()) { failed.append(d.absolutePath()); }
+
+ d = QDir(CDirectoryUtils::imagesDirectory());
+ if (!d.isReadable()) { failed.append(d.absolutePath()); }
+
+ d = QDir(CDirectoryUtils::stylesheetsDirectory());
+ if (!d.isReadable()) { failed.append(d.absolutePath()); }
+
+ d = QDir(CDirectoryUtils::applicationDataDirectory());
+ if (!d.isReadable()) { failed.append(d.absolutePath()); }
+
+ // check if the executables are avialable
+ QString fn = CDirectoryUtils::executableFilePath(CBuildConfig::swiftCoreExecutableName());
+ if (!QFile::exists(fn)) { failed.append(fn); }
+
+ fn = CDirectoryUtils::executableFilePath(CBuildConfig::swiftDataExecutableName());
+ if (!QFile::exists(fn)) { failed.append(fn); }
+
+ fn = CDirectoryUtils::executableFilePath(CBuildConfig::swiftGuiExecutableName());
+ if (!QFile::exists(fn)) { failed.append(fn); }
+
+ return failed;
+ }
+
QSet CDirectoryUtils::fileNamesToQSet(const QFileInfoList &fileInfoList)
{
QSet sl;
diff --git a/src/blackmisc/directoryutils.h b/src/blackmisc/directoryutils.h
index 701b5bf33..1526a6e85 100644
--- a/src/blackmisc/directoryutils.h
+++ b/src/blackmisc/directoryutils.h
@@ -100,7 +100,7 @@ namespace BlackMisc
//! \remark In BlackMisc so it can also be used from BlackMisc classes
static const QString &logDirectory();
- //! Directory for log files
+ //! Directory for crashpad files
static const QString &crashpadDirectory();
//! Virtually the inverse operation of CDirectoryUtils::normalizedApplicationDirectory
@@ -109,6 +109,9 @@ namespace BlackMisc
//! All sub directories of given dir
static QStringList getSubDirectories(const QString &rootDir);
+ //! Check if the (most important) runtime directories are available
+ static QStringList verifyRuntimeDirectoriesAndFiles();
+
//! Result of directory comparison
struct DirComparison
{
diff --git a/src/swiftcore/main.cpp b/src/swiftcore/main.cpp
index da59c9d1f..26cb5ac47 100644
--- a/src/swiftcore/main.cpp
+++ b/src/swiftcore/main.cpp
@@ -35,7 +35,7 @@ int main(int argc, char *argv[])
a.addVatlibOptions();
a.addParserOption({{"r", "start"}, QCoreApplication::translate("main", "Start the server.")});
a.addParserOption({{"c", "coreaudio"}, QCoreApplication::translate("main", "Audio in core.")});
- if (!a.parse()) { return EXIT_FAILURE; }
+ if (!a.parseAndStartupCheck()) { return EXIT_FAILURE; }
const QString dBusAdress(a.getCmdDBusAddressValue());
a.useContexts(a.isParserOptionSet("coreaudio") ?
diff --git a/src/swiftdata/main.cpp b/src/swiftdata/main.cpp
index 7a0e2a0bc..8c6f92543 100644
--- a/src/swiftdata/main.cpp
+++ b/src/swiftdata/main.cpp
@@ -30,7 +30,7 @@ int main(int argc, char *argv[])
CGuiApplication a(CApplicationInfo::swiftMappingTool(), CApplicationInfo::MappingTool, CIcons::swiftDatabase48());
a.setSignalStartupAutomatically(false); // application will signal startup on its own
a.splashScreen(CIcons::swiftDatabase256());
- if (!a.parse()) { return EXIT_FAILURE; }
+ if (!a.parseAndStartupCheck()) { return EXIT_FAILURE; }
a.useWebDataServices(BlackCore::CWebReaderFlags::AllSwiftDbReaders, CDatabaseReaderConfigList::forMappingTool());
if (!a.start())
{
diff --git a/src/swiftguistandard/main.cpp b/src/swiftguistandard/main.cpp
index 6066a09bc..7b379cae9 100644
--- a/src/swiftguistandard/main.cpp
+++ b/src/swiftguistandard/main.cpp
@@ -29,7 +29,7 @@ int main(int argc, char *argv[])
CSwiftGuiStdApplication a;
a.setSignalStartupAutomatically(false); // application will signal startup on its own
a.splashScreen(CIcons::swift256());
- if (!a.parse()) { return EXIT_FAILURE; }
+ if (!a.parseAndStartupCheck()) { return EXIT_FAILURE; }
if (!a.hasSetupReader() || !a.start())
{
a.gracefulShutdown();
diff --git a/src/swiftlauncher/main.cpp b/src/swiftlauncher/main.cpp
index d79ef561c..3d0630f45 100644
--- a/src/swiftlauncher/main.cpp
+++ b/src/swiftlauncher/main.cpp
@@ -35,7 +35,7 @@ int main(int argc, char *argv[])
Q_UNUSED(qa);
CGuiApplication a(CApplicationInfo::swiftLauncher(), CApplicationInfo::Laucher, CIcons::swiftLauncher1024());
a.addParserOption({{"i", "installer"}, QCoreApplication::translate("main", "Installer setup.") });
- if (!a.parse()) { return EXIT_FAILURE; }
+ if (!a.parseAndStartupCheck()) { return EXIT_FAILURE; }
a.useWebDataServices(BlackCore::CWebReaderFlags::AllSwiftDbReaders, CDatabaseReaderConfigList::forLauncher());
if (!a.start())
{