diff --git a/connector/syncthingnotifier.cpp b/connector/syncthingnotifier.cpp index 66e3d68..596de35 100644 --- a/connector/syncthingnotifier.cpp +++ b/connector/syncthingnotifier.cpp @@ -41,6 +41,9 @@ SyncthingNotifier::SyncthingNotifier(const SyncthingConnection &connection, QObj connect(&connection, &SyncthingConnection::dirCompleted, this, &SyncthingNotifier::emitSyncComplete); connect(&connection, &SyncthingConnection::newDevAvailable, this, &SyncthingNotifier::handleNewDevEvent); connect(&connection, &SyncthingConnection::newDirAvailable, this, &SyncthingNotifier::handleNewDirEvent); + if (m_process) { + connect(m_process, &QProcess::errorOccurred, this, &SyncthingNotifier::handleSyncthingProcessError); + } } void SyncthingNotifier::handleStatusChangedEvent(SyncthingStatus newStatus) @@ -92,6 +95,24 @@ void SyncthingNotifier::handleNewDirEvent(DateTime when, const QString &devId, c emit newDir(devId, dirId, message); } +void SyncthingNotifier::handleSyncthingProcessError(QProcess::ProcessError processError) +{ + if (!(m_enabledNotifications & SyncthingHighLevelNotification::SyncthingProcessError)) { + return; + } + + switch(processError) { + case QProcess::FailedToStart: + emit syncthingProcessError(tr("Failed to start Syncthing"), tr("Maybe the configured binary path is wrong or the binary is not marked as executable.")); + break; + case QProcess::Crashed: + emit syncthingProcessError(tr("Syncthing crashed with exit code %1").arg(m_process->exitCode()), QString()); + break; + default: + emit syncthingProcessError(tr("Syncthing launcher error occurred"), m_process->errorString()); + } +} + /*! * \brief Returns whether a "disconnected" notification should be shown. * \todo Unify with InternalError::isRelevant(). diff --git a/connector/syncthingnotifier.h b/connector/syncthingnotifier.h index 2162c53..3c918eb 100644 --- a/connector/syncthingnotifier.h +++ b/connector/syncthingnotifier.h @@ -4,6 +4,7 @@ #include "./global.h" #include +#include namespace CppUtilities { class DateTime; @@ -29,6 +30,7 @@ enum class SyncthingHighLevelNotification { RemoteSyncComplete = 0x4, NewDevice = 0x8, NewDir = 0x10, + SyncthingProcessError = 0x20, }; /// \cond @@ -90,11 +92,14 @@ Q_SIGNALS: void newDevice(const QString &devId, const QString &message); ///! \brief Emitted when a new directory is shared with us. void newDir(const QString &devId, const QString &dirId, const QString &message); + ///! \brief Emitted when the Syncthing process fails to start or crashes. + void syncthingProcessError(const QString &message, const QString &additionalInfo); private Q_SLOTS: void handleStatusChangedEvent(SyncthingStatus newStatus); void handleNewDevEvent(CppUtilities::DateTime when, const QString &devId, const QString &address); void handleNewDirEvent(CppUtilities::DateTime when, const QString &devId, const SyncthingDev *dev, const QString &dirId, const QString &dirLabel); + void handleSyncthingProcessError(QProcess::ProcessError syncthingProcessError); private: bool isDisconnectRelevant() const; diff --git a/tray/gui/trayicon.cpp b/tray/gui/trayicon.cpp index 3e0a033..7480252 100644 --- a/tray/gui/trayicon.cpp +++ b/tray/gui/trayicon.cpp @@ -86,6 +86,7 @@ TrayIcon::TrayIcon(const QString &connectionConfig, QObject *parent) connect(this, &TrayIcon::messageClicked, this, &TrayIcon::handleMessageClicked); connect(&connection, &SyncthingConnection::error, this, &TrayIcon::showInternalError); connect(&connection, &SyncthingConnection::newNotification, this, &TrayIcon::showSyncthingNotification); + connect(¬ifier, &SyncthingNotifier::syncthingProcessError, this, &TrayIcon::showLauncherError); connect(¬ifier, &SyncthingNotifier::disconnected, this, &TrayIcon::showDisconnected); connect(¬ifier, &SyncthingNotifier::syncComplete, this, &TrayIcon::showSyncComplete); connect(¬ifier, &SyncthingNotifier::newDevice, this, &TrayIcon::showNewDev); @@ -191,13 +192,12 @@ void TrayIcon::handleErrorsCleared() m_errorsAction->setVisible(false); } -void TrayIcon::showInternalError( - const QString &errorMsg, SyncthingErrorCategory category, int networkError, const QNetworkRequest &request, const QByteArray &response) +void TrayIcon::showInternalError(const QString &errorMessage, SyncthingErrorCategory category, int networkError, const QNetworkRequest &request, const QByteArray &response) { if (!InternalError::isRelevant(m_trayMenu.widget().connection(), category, networkError)) { return; } - InternalError error(errorMsg, request.url(), response); + InternalError error(errorMessage, request.url(), response); #ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS if (m_dbusNotificationsEnabled) { m_dbusNotifier.showInternalError(error); @@ -205,12 +205,25 @@ void TrayIcon::showInternalError( #endif { m_messageClickedAction = TrayIconMessageClickedAction::ShowInternalErrors; - showMessage(tr("Error"), errorMsg, QSystemTrayIcon::Critical); + showMessage(tr("Error"), errorMessage, QSystemTrayIcon::Critical); } InternalErrorsDialog::addError(move(error)); m_errorsAction->setVisible(true); } +void TrayIcon::showLauncherError(const QString &errorMessage, const QString &additionalInfo) +{ +#ifdef QT_UTILITIES_SUPPORT_DBUS_NOTIFICATIONS + if (m_dbusNotificationsEnabled) { + m_dbusNotifier.showLauncherError(errorMessage, additionalInfo); + } else +#endif + { + m_messageClickedAction = TrayIconMessageClickedAction::None; + showMessage(tr("Launcher error"), QStringList({errorMessage, additionalInfo}).join(QChar('\n')), QSystemTrayIcon::Critical); + } +} + void TrayIcon::showSyncthingNotification(CppUtilities::DateTime when, const QString &message) { if (m_notifyOnSyncthingErrors) { diff --git a/tray/gui/trayicon.h b/tray/gui/trayicon.h index f0bb559..3e2b3d8 100644 --- a/tray/gui/trayicon.h +++ b/tray/gui/trayicon.h @@ -33,7 +33,8 @@ public: public slots: void showInternalError( - const QString &errorMsg, Data::SyncthingErrorCategory category, int networkError, const QNetworkRequest &request, const QByteArray &response); + const QString &errorMessage, Data::SyncthingErrorCategory category, int networkError, const QNetworkRequest &request, const QByteArray &response); + void showLauncherError(const QString &errorMessage, const QString &additionalInfo); void showSyncthingNotification(CppUtilities::DateTime when, const QString &message); void showInternalErrorsDialog(); void updateStatusIconAndText(); diff --git a/widgets/misc/dbusstatusnotifier.cpp b/widgets/misc/dbusstatusnotifier.cpp index e5dc24b..92aa372 100644 --- a/widgets/misc/dbusstatusnotifier.cpp +++ b/widgets/misc/dbusstatusnotifier.cpp @@ -23,6 +23,7 @@ DBusStatusNotifier::DBusStatusNotifier(QObject *parent) : QObject(parent) , m_disconnectedNotification(QStringLiteral(APP_NAME), QStringLiteral("network-disconnect"), 5000) , m_internalErrorNotification(QStringLiteral(APP_NAME) + tr(" - internal error"), NotificationIcon::Critical, 5000) + , m_launcherErrorNotification(QStringLiteral(APP_NAME) + tr(" - launcher error"), NotificationIcon::Critical, 5000) , m_syncthingNotification(tr("Syncthing notification"), NotificationIcon::Warning, 10000) , m_syncCompleteNotification(QStringLiteral(APP_NAME), NotificationIcon::Information, 5000) , m_newDevNotification(QStringLiteral(APP_NAME) + tr(" - new device"), NotificationIcon::Information, 5000) @@ -37,6 +38,10 @@ DBusStatusNotifier::DBusStatusNotifier(QObject *parent) m_internalErrorNotification.setActions(QStringList({ QStringLiteral("details"), tr("View details") })); connect(&m_internalErrorNotification, &DBusNotification::actionInvoked, this, &DBusStatusNotifier::errorDetailsRequested); + m_internalErrorNotification.setApplicationName(QStringLiteral(APP_NAME)); + m_internalErrorNotification.setActions(QStringList({ QStringLiteral("details"), tr("View details") })); + connect(&m_internalErrorNotification, &DBusNotification::actionInvoked, this, &DBusStatusNotifier::errorDetailsRequested); + m_syncthingNotification.setApplicationName(QStringLiteral(APP_NAME)); m_syncthingNotification.setActions(QStringList({ QStringLiteral("show"), tr("Show"), QStringLiteral("dismiss"), tr("Dismiss") })); connect(&m_syncthingNotification, &DBusNotification::actionInvoked, this, &DBusStatusNotifier::handleSyncthingNotificationAction); @@ -61,7 +66,8 @@ void DBusStatusNotifier::setIcons(const StatusIcons &icons) if (!icons.isValid) { return; } - m_syncthingNotification.setImage(makeImage(icons.error)); + m_launcherErrorNotification.setImage(makeImage(icons.error)); + m_syncthingNotification.setImage(m_launcherErrorNotification.image()); m_syncthingNotification.setImage(makeImage(icons.notify)); m_syncCompleteNotification.setImage(makeImage(icons.syncComplete)); m_newDevNotification.setImage(makeImage(icons.newItem)); @@ -76,6 +82,7 @@ void DBusStatusNotifier::handleSyncthingNotificationAction(const QString &action emit showNotificationsRequested(); } } + } // namespace QtGui #endif diff --git a/widgets/misc/dbusstatusnotifier.h b/widgets/misc/dbusstatusnotifier.h index ce13c47..81e301b 100644 --- a/widgets/misc/dbusstatusnotifier.h +++ b/widgets/misc/dbusstatusnotifier.h @@ -8,6 +8,7 @@ #include #include +#include namespace Data { enum class SyncthingErrorCategory; @@ -26,6 +27,7 @@ public Q_SLOTS: void showDisconnect(); void hideDisconnect(); void showInternalError(const InternalError &error); + void showLauncherError(const QString &errorMessage, const QString &additionalInfo); void showSyncthingNotification(CppUtilities::DateTime when, const QString &message); void showSyncComplete(const QString &message); void showNewDev(const QString &devId, const QString &message); @@ -45,6 +47,7 @@ private Q_SLOTS: private: QtUtilities::DBusNotification m_disconnectedNotification; QtUtilities::DBusNotification m_internalErrorNotification; + QtUtilities::DBusNotification m_launcherErrorNotification; QtUtilities::DBusNotification m_syncthingNotification; QtUtilities::DBusNotification m_syncCompleteNotification; QtUtilities::DBusNotification m_newDevNotification; @@ -66,6 +69,11 @@ inline void DBusStatusNotifier::showInternalError(const InternalError &error) m_internalErrorNotification.update(error.message); } +inline void QtGui::DBusStatusNotifier::showLauncherError(const QString &errorMessage, const QString &additionalInfo) +{ + m_launcherErrorNotification.update(QStringList({errorMessage, additionalInfo}).join(QStringLiteral("\n "))); +} + inline void DBusStatusNotifier::showSyncthingNotification(CppUtilities::DateTime when, const QString &message) { Q_UNUSED(when) diff --git a/widgets/settings/notificationsoptionpage.ui b/widgets/settings/notificationsoptionpage.ui index e954890..d7e0aea 100644 --- a/widgets/settings/notificationsoptionpage.ui +++ b/widgets/settings/notificationsoptionpage.ui @@ -65,6 +65,13 @@ + + + + errors of Syncthing launcher + + + diff --git a/widgets/settings/settings.cpp b/widgets/settings/settings.cpp index a3df17b..33b37f5 100644 --- a/widgets/settings/settings.cpp +++ b/widgets/settings/settings.cpp @@ -160,6 +160,7 @@ void restore() auto ¬ifyOn = v.notifyOn; notifyOn.disconnect = settings.value(QStringLiteral("notifyOnDisconnect"), notifyOn.disconnect).toBool(); notifyOn.internalErrors = settings.value(QStringLiteral("notifyOnErrors"), notifyOn.internalErrors).toBool(); + notifyOn.launcherErrors = settings.value(QStringLiteral("notifyOnLauncherErrors"), notifyOn.launcherErrors).toBool(); notifyOn.localSyncComplete = settings.value(QStringLiteral("notifyOnLocalSyncComplete"), notifyOn.localSyncComplete).toBool(); notifyOn.remoteSyncComplete = settings.value(QStringLiteral("notifyOnRemoteSyncComplete"), notifyOn.remoteSyncComplete).toBool(); notifyOn.syncthingErrors = settings.value(QStringLiteral("showSyncthingNotifications"), notifyOn.syncthingErrors).toBool(); @@ -248,6 +249,7 @@ void save() const auto ¬ifyOn = v.notifyOn; settings.setValue(QStringLiteral("notifyOnDisconnect"), notifyOn.disconnect); settings.setValue(QStringLiteral("notifyOnErrors"), notifyOn.internalErrors); + settings.setValue(QStringLiteral("notifyOnLauncherErrors"), notifyOn.launcherErrors); settings.setValue(QStringLiteral("notifyOnLocalSyncComplete"), notifyOn.localSyncComplete); settings.setValue(QStringLiteral("notifyOnRemoteSyncComplete"), notifyOn.remoteSyncComplete); settings.setValue(QStringLiteral("showSyncthingNotifications"), notifyOn.syncthingErrors); @@ -325,6 +327,9 @@ void Settings::apply(SyncthingNotifier ¬ifier) const if (notifyOn.newDirectoryShared) { notifications |= SyncthingHighLevelNotification::NewDir; } + if (notifyOn.launcherErrors) { + notifications |= SyncthingHighLevelNotification::SyncthingProcessError; + } notifier.setEnabledNotifications(notifications); notifier.setIgnoreInavailabilityAfterStart(ignoreInavailabilityAfterStart); } diff --git a/widgets/settings/settingsdialog.cpp b/widgets/settings/settingsdialog.cpp index 70bedbf..9e20fdb 100644 --- a/widgets/settings/settingsdialog.cpp +++ b/widgets/settings/settingsdialog.cpp @@ -374,6 +374,7 @@ bool NotificationsOptionPage::apply() auto ¬ifyOn(settings.notifyOn); notifyOn.disconnect = ui()->notifyOnDisconnectCheckBox->isChecked(); notifyOn.internalErrors = ui()->notifyOnErrorsCheckBox->isChecked(); + notifyOn.launcherErrors = ui()->notifyOnLauncherErrorsCheckBox->isChecked(); notifyOn.localSyncComplete = ui()->notifyOnLocalSyncCompleteCheckBox->isChecked(); notifyOn.remoteSyncComplete = ui()->notifyOnRemoteSyncCompleteCheckBox->isChecked(); notifyOn.syncthingErrors = ui()->showSyncthingNotificationsCheckBox->isChecked(); @@ -395,6 +396,7 @@ void NotificationsOptionPage::reset() const auto ¬ifyOn = values().notifyOn; ui()->notifyOnDisconnectCheckBox->setChecked(notifyOn.disconnect); ui()->notifyOnErrorsCheckBox->setChecked(notifyOn.internalErrors); + ui()->notifyOnLauncherErrorsCheckBox->setChecked(notifyOn.launcherErrors); ui()->notifyOnLocalSyncCompleteCheckBox->setChecked(notifyOn.localSyncComplete); ui()->notifyOnRemoteSyncCompleteCheckBox->setChecked(notifyOn.remoteSyncComplete); ui()->showSyncthingNotificationsCheckBox->setChecked(notifyOn.syncthingErrors);