211 lines
8.3 KiB
C++
211 lines
8.3 KiB
C++
/*
|
|
* Copyright (C) by Cédric Bellegarde <gnumdk@gmail.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* for more details.
|
|
*/
|
|
|
|
#include "systray.h"
|
|
|
|
#include "common/restartmanager.h"
|
|
#include "gui/accountmanager.h"
|
|
#include "gui/application.h"
|
|
#include "gui/folderman.h"
|
|
#include "gui/networkinformation.h"
|
|
#include "libsync/theme.h"
|
|
|
|
#include <QApplication>
|
|
#include <QDesktopServices>
|
|
#include <QMenu>
|
|
#include <QMetaObject>
|
|
|
|
using namespace Qt::Literals::StringLiterals;
|
|
|
|
namespace OCC {
|
|
|
|
namespace {
|
|
void showSettingsAfterTrayEvent()
|
|
{
|
|
auto *app = ocApp();
|
|
QMetaObject::invokeMethod(app, [app] { app->showSettings(); }, Qt::QueuedConnection);
|
|
}
|
|
}
|
|
|
|
Systray::Systray(QObject *parent)
|
|
: QSystemTrayIcon(parent)
|
|
{
|
|
connect(this, &QSystemTrayIcon::activated, this, [](QSystemTrayIcon::ActivationReason reason) {
|
|
// Left click
|
|
if (reason == QSystemTrayIcon::Trigger) {
|
|
showSettingsAfterTrayEvent();
|
|
}
|
|
});
|
|
connect(AccountManager::instance(), &AccountManager::accountAdded, this,
|
|
[this](AccountStatePtr accountState) { connect(accountState.data(), &AccountState::stateChanged, this, &Systray::slotComputeOverallSyncStatus); });
|
|
connect(FolderMan::instance(), &FolderMan::folderSyncStateChange, this, &Systray::slotComputeOverallSyncStatus);
|
|
|
|
// init systray
|
|
slotComputeOverallSyncStatus();
|
|
computeContextMenu();
|
|
show();
|
|
}
|
|
|
|
void Systray::setToolTip(const QString &tip)
|
|
{
|
|
#ifdef Q_OS_WIN
|
|
QSystemTrayIcon::setToolTip(tr("%1: %2").arg(Theme::instance()->appNameGUI(), tip));
|
|
#else
|
|
QSystemTrayIcon::setToolTip(u"%1\n%2"_s.arg(Theme::instance()->appNameGUI(), tip));
|
|
#endif
|
|
}
|
|
|
|
void Systray::slotComputeOverallSyncStatus()
|
|
{
|
|
auto getIcon = [](const SyncResult &result) { return Theme::instance()->themeTrayIcon(result); };
|
|
auto getIconFromStatus = [getIcon](const SyncResult::Status &status) { return getIcon(SyncResult{status}); };
|
|
bool allSignedOut = true;
|
|
bool allPaused = true;
|
|
QVector<AccountStatePtr> problemAccounts;
|
|
|
|
for (const auto &a : AccountManager::instance()->accounts()) {
|
|
if (!a->isSignedOut()) {
|
|
allSignedOut = false;
|
|
}
|
|
if (!a->isConnected()) {
|
|
problemAccounts.append(a);
|
|
}
|
|
}
|
|
|
|
const auto &map = FolderMan::instance()->folders();
|
|
for (auto *f : map) {
|
|
if (!f->isSyncPaused()) {
|
|
allPaused = false;
|
|
}
|
|
}
|
|
|
|
if (!problemAccounts.empty()) {
|
|
setIcon(getIconFromStatus(SyncResult::Status::Offline));
|
|
#ifdef Q_OS_WIN
|
|
// Windows has a 128-char tray tooltip length limit.
|
|
QStringList accountNames;
|
|
for (const auto &a : std::as_const(problemAccounts)) {
|
|
accountNames.append(a->account()->displayNameWithHost());
|
|
}
|
|
setToolTip(tr("Disconnected from %1").arg(accountNames.join(QLatin1String(", "))));
|
|
#else
|
|
QStringList messages;
|
|
messages.append(tr("Disconnected from accounts:"));
|
|
for (const auto &a : std::as_const(problemAccounts)) {
|
|
QString message = tr("Account %1").arg(a->account()->displayNameWithHost());
|
|
if (!a->connectionErrors().empty()) {
|
|
message += QLatin1String("\n") + a->connectionErrors().join(QLatin1String("\n"));
|
|
}
|
|
messages.append(message);
|
|
}
|
|
setToolTip(messages.join(QLatin1String("\n\n")));
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
if (allSignedOut) {
|
|
setIcon(getIconFromStatus(SyncResult::Status::Offline));
|
|
setToolTip(tr("Please sign in"));
|
|
return;
|
|
} else if (allPaused) {
|
|
setIcon(getIconFromStatus(SyncResult::Paused));
|
|
setToolTip(tr("Account synchronization is disabled"));
|
|
return;
|
|
}
|
|
|
|
// display the info of the least successful sync (eg. do not just display the result of the latest sync)
|
|
QString trayMessage;
|
|
|
|
auto trayOverallStatusResult = FolderMan::trayOverallStatus(map);
|
|
const QIcon statusIcon = getIcon(trayOverallStatusResult.overallStatus());
|
|
setIcon(statusIcon);
|
|
|
|
// create the tray blob message, check if we have an defined state
|
|
#ifdef Q_OS_WIN
|
|
// Windows has a 128-char tray tooltip length limit.
|
|
trayMessage = FolderMan::instance()->trayTooltipStatusString(trayOverallStatusResult.overallStatus(), false);
|
|
#else
|
|
QStringList allStatusStrings;
|
|
for (auto *folder : map) {
|
|
QString folderMessage = FolderMan::trayTooltipStatusString(folder->syncResult(), folder->isSyncPaused());
|
|
allStatusStrings += tr("Space »%1«: %2").arg(folder->shortGuiLocalPath(), folderMessage);
|
|
}
|
|
trayMessage = allStatusStrings.join(QLatin1String("\n"));
|
|
#endif
|
|
setToolTip(trayMessage);
|
|
}
|
|
|
|
void Systray::computeContextMenu()
|
|
{
|
|
Q_ASSERT(!contextMenu());
|
|
auto *menu = new QMenu(Theme::instance()->appNameGUI());
|
|
|
|
auto *showAction = menu->addAction(Theme::instance()->applicationIcon(), tr("Show %1").arg(Theme::instance()->appNameGUI()));
|
|
connect(showAction, &QAction::triggered, this, [] { showSettingsAfterTrayEvent(); });
|
|
auto *pauseResume = new QAction(menu);
|
|
auto updatePauseResumeAction = [pauseResume] {
|
|
pauseResume->setText(FolderMan::instance()->scheduler()->isRunning() ? tr("Pause synchronizations") : tr("Resume synchronizations"));
|
|
};
|
|
connect(pauseResume, &QAction::triggered, FolderMan::instance()->scheduler(), [] {
|
|
if (FolderMan::instance()->scheduler()->isRunning()) {
|
|
FolderMan::instance()->scheduler()->stop();
|
|
FolderMan::instance()->scheduler()->terminateCurrentSync(tr("Synchronization paused"));
|
|
} else {
|
|
FolderMan::instance()->scheduler()->start();
|
|
}
|
|
});
|
|
connect(FolderMan::instance()->scheduler(), &SyncScheduler::isRunningChanged, pauseResume, updatePauseResumeAction);
|
|
menu->addAction(pauseResume);
|
|
updatePauseResumeAction();
|
|
|
|
if (ocApp()->debugMode()) {
|
|
menu->addSeparator();
|
|
auto *debugMenu = menu->addMenu(QStringLiteral("Debug actions"));
|
|
debugMenu->addAction(QStringLiteral("Crash if asserts enabled - OC_ENSURE"), ocApp(), [] {
|
|
if (OC_ENSURE(false)) {
|
|
Q_UNREACHABLE();
|
|
}
|
|
});
|
|
debugMenu->addAction(QStringLiteral("Crash if asserts enabled - Q_ASSERT"), ocApp(), [] { Q_ASSERT(false); });
|
|
debugMenu->addAction(QStringLiteral("Crash now - Utility::crash()"), ocApp(), [] { Utility::crash(); });
|
|
debugMenu->addAction(QStringLiteral("Crash now - OC_ENFORCE()"), ocApp(), [] { OC_ENFORCE(false); });
|
|
debugMenu->addAction(QStringLiteral("Crash now - qFatal"), ocApp(), [] { qFatal("la Qt fatale"); });
|
|
debugMenu->addAction(QStringLiteral("Restart now"), ocApp(), [] { RestartManager::requestRestart(); });
|
|
debugMenu->addSeparator();
|
|
auto captivePortalCheckbox = debugMenu->addAction(QStringLiteral("Behind Captive Portal"));
|
|
captivePortalCheckbox->setCheckable(true);
|
|
captivePortalCheckbox->setChecked(NetworkInformation::instance()->isForcedCaptivePortal());
|
|
connect(captivePortalCheckbox, &QAction::triggered, this, [](bool checked) { NetworkInformation::instance()->setForcedCaptivePortal(checked); });
|
|
connect(NetworkInformation::instance(), &NetworkInformation::isBehindCaptivePortalChanged, captivePortalCheckbox,
|
|
[captivePortalCheckbox] { captivePortalCheckbox->setChecked(NetworkInformation::instance()->isForcedCaptivePortal()); });
|
|
}
|
|
|
|
menu->addSeparator();
|
|
|
|
if (!Theme::instance()->helpUrl().isEmpty()) {
|
|
menu->addAction(tr("Help"), this, [] { QDesktopServices::openUrl(Theme::instance()->helpUrl()); });
|
|
}
|
|
|
|
menu->addAction(tr("About"), ocApp(), &Application::showAbout);
|
|
|
|
// this action will be hidden on mac and be part of the application menu
|
|
menu->addAction(tr("About Qt"), qApp, &QApplication::aboutQt)->setMenuRole(QAction::AboutQtRole);
|
|
|
|
menu->addAction(tr("Quit"), ocApp(), &QApplication::quit);
|
|
|
|
setContextMenu(menu);
|
|
}
|
|
|
|
} // namespace OCC
|