зеркало из https://github.com/nextcloud/desktop.git
Code cleanup regarding context menu. Pause/resume logic implemented. Halfway through remodeling account menu.
Signed-off-by: Dominique Fuchs <32204802+DominiqueFuchs@users.noreply.github.com>
This commit is contained in:
Родитель
a90995cf15
Коммит
330ff96ee2
|
@ -72,19 +72,24 @@ ownCloudGui::ownCloudGui(Application *parent)
|
|||
, _app(parent)
|
||||
{
|
||||
_tray = new Systray();
|
||||
//qmlRegisterType<Systray>("nc.desktop.systray.backend", 1, 0, "Systray");
|
||||
_tray->setParent(this);
|
||||
// for the beginning, set the offline icon until the account was verified
|
||||
_tray->setIcon(Theme::instance()->folderOfflineIcon(/*systray?*/ true, /*currently visible?*/ false));
|
||||
|
||||
setupActions();
|
||||
setupContextMenu();
|
||||
_tray->setIcon(Theme::instance()->folderOfflineIcon(/*systray?*/ true));
|
||||
|
||||
_tray->show();
|
||||
|
||||
connect(_tray.data(), &QSystemTrayIcon::activated,
|
||||
this, &ownCloudGui::slotTrayClicked);
|
||||
|
||||
connect(_tray.data(), &Systray::pauseSync,
|
||||
this, &ownCloudGui::slotPauseAllFolders);
|
||||
|
||||
connect(_tray.data(), &Systray::pauseSync,
|
||||
this, &ownCloudGui::slotUnpauseAllFolders);
|
||||
|
||||
connect(_tray.data(), &Systray::openHelp,
|
||||
this, &ownCloudGui::slotHelp);
|
||||
|
||||
connect(_tray.data(), &Systray::openSettings,
|
||||
this, &ownCloudGui::slotShowSettings);
|
||||
|
||||
|
@ -99,11 +104,6 @@ ownCloudGui::ownCloudGui(Application *parent)
|
|||
connect(folderMan, &FolderMan::folderSyncStateChange,
|
||||
this, &ownCloudGui::slotSyncStateChange);
|
||||
|
||||
connect(AccountManager::instance(), &AccountManager::accountAdded,
|
||||
this, &ownCloudGui::updateContextMenuNeeded);
|
||||
connect(AccountManager::instance(), &AccountManager::accountRemoved,
|
||||
this, &ownCloudGui::updateContextMenuNeeded);
|
||||
|
||||
connect(Logger::instance(), &Logger::guiLog,
|
||||
this, &ownCloudGui::slotShowTrayMessage);
|
||||
connect(Logger::instance(), &Logger::optionalGuiLog,
|
||||
|
@ -158,13 +158,6 @@ void ownCloudGui::slotOpenSettingsDialog()
|
|||
|
||||
void ownCloudGui::slotTrayClicked(QSystemTrayIcon::ActivationReason reason)
|
||||
{
|
||||
if (_workaroundFakeDoubleClick) {
|
||||
static QElapsedTimer last_click;
|
||||
if (last_click.isValid() && last_click.elapsed() < 200) {
|
||||
return;
|
||||
}
|
||||
last_click.start();
|
||||
}
|
||||
|
||||
// Left click
|
||||
if (reason == QSystemTrayIcon::Trigger) {
|
||||
|
@ -189,7 +182,6 @@ void ownCloudGui::slotTrayClicked(QSystemTrayIcon::ActivationReason reason)
|
|||
void ownCloudGui::slotSyncStateChange(Folder *folder)
|
||||
{
|
||||
slotComputeOverallSyncStatus();
|
||||
updateContextMenuNeeded();
|
||||
|
||||
if (!folder) {
|
||||
return; // Valid, just a general GUI redraw was needed.
|
||||
|
@ -210,7 +202,6 @@ void ownCloudGui::slotSyncStateChange(Folder *folder)
|
|||
void ownCloudGui::slotFoldersChanged()
|
||||
{
|
||||
slotComputeOverallSyncStatus();
|
||||
updateContextMenuNeeded();
|
||||
}
|
||||
|
||||
void ownCloudGui::slotOpenPath(const QString &path)
|
||||
|
@ -220,7 +211,6 @@ void ownCloudGui::slotOpenPath(const QString &path)
|
|||
|
||||
void ownCloudGui::slotAccountStateChanged()
|
||||
{
|
||||
updateContextMenuNeeded();
|
||||
slotComputeOverallSyncStatus();
|
||||
}
|
||||
|
||||
|
@ -246,7 +236,7 @@ void ownCloudGui::slotComputeOverallSyncStatus()
|
|||
// Don't overwrite the status if we're currently syncing
|
||||
if (FolderMan::instance()->currentSyncFolder())
|
||||
return;
|
||||
_actionStatus->setText(text);
|
||||
//_actionStatus->setText(text);
|
||||
};
|
||||
|
||||
foreach (auto a, AccountManager::instance()->accounts()) {
|
||||
|
@ -266,7 +256,7 @@ void ownCloudGui::slotComputeOverallSyncStatus()
|
|||
}
|
||||
|
||||
if (!problemAccounts.empty()) {
|
||||
_tray->setIcon(Theme::instance()->folderOfflineIcon(true, contextMenuVisible()));
|
||||
_tray->setIcon(Theme::instance()->folderOfflineIcon(true));
|
||||
if (allDisconnected) {
|
||||
setStatusText(tr("Disconnected"));
|
||||
} else {
|
||||
|
@ -296,12 +286,12 @@ void ownCloudGui::slotComputeOverallSyncStatus()
|
|||
}
|
||||
|
||||
if (allSignedOut) {
|
||||
_tray->setIcon(Theme::instance()->folderOfflineIcon(true, contextMenuVisible()));
|
||||
_tray->setIcon(Theme::instance()->folderOfflineIcon(true));
|
||||
_tray->setToolTip(tr("Please sign in"));
|
||||
setStatusText(tr("Signed out"));
|
||||
return;
|
||||
} else if (allPaused) {
|
||||
_tray->setIcon(Theme::instance()->syncStateIcon(SyncResult::Paused, true, contextMenuVisible()));
|
||||
_tray->setIcon(Theme::instance()->syncStateIcon(SyncResult::Paused, true));
|
||||
_tray->setToolTip(tr("Account synchronization is disabled"));
|
||||
setStatusText(tr("Synchronization is paused"));
|
||||
return;
|
||||
|
@ -328,7 +318,7 @@ void ownCloudGui::slotComputeOverallSyncStatus()
|
|||
iconStatus = SyncResult::Problem;
|
||||
}
|
||||
|
||||
QIcon statusIcon = Theme::instance()->syncStateIcon(iconStatus, true, contextMenuVisible());
|
||||
QIcon statusIcon = Theme::instance()->syncStateIcon(iconStatus, true);
|
||||
_tray->setIcon(statusIcon);
|
||||
|
||||
// create the tray blob message, check if we have an defined state
|
||||
|
@ -366,377 +356,6 @@ void ownCloudGui::slotComputeOverallSyncStatus()
|
|||
}
|
||||
}
|
||||
|
||||
void ownCloudGui::addAccountContextMenu(AccountStatePtr accountState, QMenu *menu, bool separateMenu)
|
||||
{
|
||||
// Only show the name in the action if it's not part of an
|
||||
// account sub menu.
|
||||
QString browserOpen = tr("Open in browser");
|
||||
if (!separateMenu) {
|
||||
browserOpen = tr("Open %1 in browser").arg(Theme::instance()->appNameGUI());
|
||||
}
|
||||
auto actionOpenoC = menu->addAction(browserOpen);
|
||||
actionOpenoC->setProperty(propertyAccountC, QVariant::fromValue(accountState->account()));
|
||||
QObject::connect(actionOpenoC, &QAction::triggered, this, &ownCloudGui::slotOpenOwnCloud);
|
||||
|
||||
FolderMan *folderMan = FolderMan::instance();
|
||||
bool firstFolder = true;
|
||||
bool singleSyncFolder = folderMan->map().size() == 1 && Theme::instance()->singleSyncFolder();
|
||||
bool onePaused = false;
|
||||
bool allPaused = true;
|
||||
foreach (Folder *folder, folderMan->map()) {
|
||||
if (folder->accountState() != accountState.data()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (folder->syncPaused()) {
|
||||
onePaused = true;
|
||||
} else {
|
||||
allPaused = false;
|
||||
}
|
||||
|
||||
if (firstFolder && !singleSyncFolder) {
|
||||
firstFolder = false;
|
||||
menu->addSeparator();
|
||||
menu->addAction(tr("Managed Folders:"))->setDisabled(true);
|
||||
}
|
||||
|
||||
QAction *action = menu->addAction(tr("Open folder '%1'").arg(folder->shortGuiLocalPath()));
|
||||
auto alias = folder->alias();
|
||||
connect(action, &QAction::triggered, this, [this, alias] { this->slotFolderOpenAction(alias); });
|
||||
}
|
||||
|
||||
menu->addSeparator();
|
||||
if (separateMenu) {
|
||||
if (onePaused) {
|
||||
QAction *enable = menu->addAction(tr("Resume all folders"));
|
||||
enable->setProperty(propertyAccountC, QVariant::fromValue(accountState));
|
||||
connect(enable, &QAction::triggered, this, &ownCloudGui::slotUnpauseAllFolders);
|
||||
}
|
||||
if (!allPaused) {
|
||||
QAction *enable = menu->addAction(tr("Pause all folders"));
|
||||
enable->setProperty(propertyAccountC, QVariant::fromValue(accountState));
|
||||
connect(enable, &QAction::triggered, this, &ownCloudGui::slotPauseAllFolders);
|
||||
}
|
||||
|
||||
if (accountState->isSignedOut()) {
|
||||
QAction *signin = menu->addAction(tr("Log in …"));
|
||||
signin->setProperty(propertyAccountC, QVariant::fromValue(accountState));
|
||||
connect(signin, &QAction::triggered, this, &ownCloudGui::slotLogin);
|
||||
} else {
|
||||
QAction *signout = menu->addAction(tr("Log out"));
|
||||
signout->setProperty(propertyAccountC, QVariant::fromValue(accountState));
|
||||
connect(signout, &QAction::triggered, this, &ownCloudGui::slotLogout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ownCloudGui::slotContextMenuAboutToShow()
|
||||
{
|
||||
_contextMenuVisibleManual = true;
|
||||
|
||||
// Update icon in sys tray, as it might change depending on the context menu state
|
||||
slotComputeOverallSyncStatus();
|
||||
|
||||
if (!_workaroundNoAboutToShowUpdate) {
|
||||
updateContextMenu();
|
||||
}
|
||||
}
|
||||
|
||||
void ownCloudGui::slotContextMenuAboutToHide()
|
||||
{
|
||||
_contextMenuVisibleManual = false;
|
||||
|
||||
// Update icon in sys tray, as it might change depending on the context menu state
|
||||
slotComputeOverallSyncStatus();
|
||||
}
|
||||
|
||||
bool ownCloudGui::contextMenuVisible() const
|
||||
{
|
||||
// On some platforms isVisible doesn't work and always returns false,
|
||||
// elsewhere aboutToHide is unreliable.
|
||||
if (_workaroundManualVisibility)
|
||||
return _contextMenuVisibleManual;
|
||||
return _contextMenu->isVisible();
|
||||
}
|
||||
|
||||
static bool minimalTrayMenu()
|
||||
{
|
||||
static QByteArray var = qgetenv("OWNCLOUD_MINIMAL_TRAY_MENU");
|
||||
return !var.isEmpty();
|
||||
}
|
||||
|
||||
static bool updateWhileVisible()
|
||||
{
|
||||
static QByteArray var = qgetenv("OWNCLOUD_TRAY_UPDATE_WHILE_VISIBLE");
|
||||
if (var == "1") {
|
||||
return true;
|
||||
} else if (var == "0") {
|
||||
return false;
|
||||
} else {
|
||||
// triggers bug on OS X: https://bugreports.qt.io/browse/QTBUG-54845
|
||||
// or flickering on Xubuntu
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static QByteArray envForceQDBusTrayWorkaround()
|
||||
{
|
||||
static QByteArray var = qgetenv("OWNCLOUD_FORCE_QDBUS_TRAY_WORKAROUND");
|
||||
return var;
|
||||
}
|
||||
|
||||
static QByteArray envForceWorkaroundShowAndHideTray()
|
||||
{
|
||||
static QByteArray var = qgetenv("OWNCLOUD_FORCE_TRAY_SHOW_HIDE");
|
||||
return var;
|
||||
}
|
||||
|
||||
static QByteArray envForceWorkaroundNoAboutToShowUpdate()
|
||||
{
|
||||
static QByteArray var = qgetenv("OWNCLOUD_FORCE_TRAY_NO_ABOUT_TO_SHOW");
|
||||
return var;
|
||||
}
|
||||
|
||||
static QByteArray envForceWorkaroundFakeDoubleClick()
|
||||
{
|
||||
static QByteArray var = qgetenv("OWNCLOUD_FORCE_TRAY_FAKE_DOUBLE_CLICK");
|
||||
return var;
|
||||
}
|
||||
|
||||
static QByteArray envForceWorkaroundManualVisibility()
|
||||
{
|
||||
static QByteArray var = qgetenv("OWNCLOUD_FORCE_TRAY_MANUAL_VISIBILITY");
|
||||
return var;
|
||||
}
|
||||
|
||||
void ownCloudGui::setupContextMenu()
|
||||
{
|
||||
if (_contextMenu) {
|
||||
return;
|
||||
}
|
||||
|
||||
_contextMenu.reset(new QMenu());
|
||||
_contextMenu->setTitle(Theme::instance()->appNameGUI());
|
||||
|
||||
_recentActionsMenu = new QMenu(tr("Recent Changes"), _contextMenu.data());
|
||||
|
||||
// The tray menu is surprisingly problematic. Being able to switch to
|
||||
// a minimal version of it is a useful workaround and testing tool.
|
||||
if (minimalTrayMenu()) {
|
||||
_contextMenu->addAction(_actionQuit);
|
||||
return;
|
||||
}
|
||||
|
||||
auto applyEnvVariable = [](bool *sw, const QByteArray &value) {
|
||||
if (value == "1")
|
||||
*sw = true;
|
||||
if (value == "0")
|
||||
*sw = false;
|
||||
};
|
||||
|
||||
// This is an old compound flag that people might still depend on
|
||||
bool qdbusmenuWorkarounds = false;
|
||||
applyEnvVariable(&qdbusmenuWorkarounds, envForceQDBusTrayWorkaround());
|
||||
if (qdbusmenuWorkarounds) {
|
||||
_workaroundFakeDoubleClick = true;
|
||||
_workaroundNoAboutToShowUpdate = true;
|
||||
_workaroundShowAndHideTray = true;
|
||||
}
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
// https://bugreports.qt.io/browse/QTBUG-54633
|
||||
_workaroundNoAboutToShowUpdate = true;
|
||||
_workaroundManualVisibility = true;
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
// For KDE sessions if the platform plugin is missing,
|
||||
// neither aboutToShow() updates nor the isVisible() call
|
||||
// work. At least aboutToHide is reliable.
|
||||
// https://github.com/owncloud/client/issues/6545
|
||||
static QByteArray xdgCurrentDesktop = qgetenv("XDG_CURRENT_DESKTOP");
|
||||
static QByteArray desktopSession = qgetenv("DESKTOP_SESSION");
|
||||
bool isKde =
|
||||
xdgCurrentDesktop.contains("KDE")
|
||||
|| desktopSession.contains("plasma")
|
||||
|| desktopSession.contains("kde");
|
||||
QObject *platformMenu = reinterpret_cast<QObject *>(_tray->contextMenu()->platformMenu());
|
||||
if (isKde && platformMenu && platformMenu->metaObject()->className() == QLatin1String("QDBusPlatformMenu")) {
|
||||
_workaroundManualVisibility = true;
|
||||
_workaroundNoAboutToShowUpdate = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
applyEnvVariable(&_workaroundNoAboutToShowUpdate, envForceWorkaroundNoAboutToShowUpdate());
|
||||
applyEnvVariable(&_workaroundFakeDoubleClick, envForceWorkaroundFakeDoubleClick());
|
||||
applyEnvVariable(&_workaroundShowAndHideTray, envForceWorkaroundShowAndHideTray());
|
||||
applyEnvVariable(&_workaroundManualVisibility, envForceWorkaroundManualVisibility());
|
||||
|
||||
qCInfo(lcApplication) << "Tray menu workarounds:"
|
||||
<< "noabouttoshow:" << _workaroundNoAboutToShowUpdate
|
||||
<< "fakedoubleclick:" << _workaroundFakeDoubleClick
|
||||
<< "showhide:" << _workaroundShowAndHideTray
|
||||
<< "manualvisibility:" << _workaroundManualVisibility;
|
||||
|
||||
|
||||
connect(&_delayedTrayUpdateTimer, &QTimer::timeout, this, &ownCloudGui::updateContextMenu);
|
||||
_delayedTrayUpdateTimer.setInterval(2 * 1000);
|
||||
_delayedTrayUpdateTimer.setSingleShot(true);
|
||||
|
||||
connect(_contextMenu.data(), SIGNAL(aboutToShow()), SLOT(slotContextMenuAboutToShow()));
|
||||
// unfortunately aboutToHide is unreliable, it seems to work on OSX though
|
||||
connect(_contextMenu.data(), SIGNAL(aboutToHide()), SLOT(slotContextMenuAboutToHide()));
|
||||
|
||||
// Populate the context menu now.
|
||||
updateContextMenu();
|
||||
}
|
||||
|
||||
void ownCloudGui::updateContextMenu()
|
||||
{
|
||||
if (minimalTrayMenu()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If it's visible, we can't update live, and it won't be updated lazily: reschedule
|
||||
if (contextMenuVisible() && !updateWhileVisible() && _workaroundNoAboutToShowUpdate) {
|
||||
if (!_delayedTrayUpdateTimer.isActive()) {
|
||||
_delayedTrayUpdateTimer.start();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (_workaroundShowAndHideTray) {
|
||||
// To make tray menu updates work with these bugs (see setupContextMenu)
|
||||
// we need to hide and show the tray icon. We don't want to do that
|
||||
// while it's visible!
|
||||
if (contextMenuVisible()) {
|
||||
if (!_delayedTrayUpdateTimer.isActive()) {
|
||||
_delayedTrayUpdateTimer.start();
|
||||
}
|
||||
return;
|
||||
}
|
||||
_tray->hide();
|
||||
}
|
||||
|
||||
_contextMenu->clear();
|
||||
slotRebuildRecentMenus();
|
||||
|
||||
// We must call deleteLater because we might be called from the press in one of the actions.
|
||||
foreach (auto menu, _accountMenus) {
|
||||
menu->deleteLater();
|
||||
}
|
||||
_accountMenus.clear();
|
||||
|
||||
auto accountList = AccountManager::instance()->accounts();
|
||||
|
||||
bool isConfigured = (!accountList.isEmpty());
|
||||
bool atLeastOneConnected = false;
|
||||
bool atLeastOnePaused = false;
|
||||
bool atLeastOneNotPaused = false;
|
||||
foreach (auto a, accountList) {
|
||||
if (a->isConnected()) {
|
||||
atLeastOneConnected = true;
|
||||
}
|
||||
}
|
||||
foreach (auto f, FolderMan::instance()->map()) {
|
||||
if (f->syncPaused()) {
|
||||
atLeastOnePaused = true;
|
||||
} else {
|
||||
atLeastOneNotPaused = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (accountList.count() > 1) {
|
||||
foreach (AccountStatePtr account, accountList) {
|
||||
QMenu *accountMenu = new QMenu(account->account()->displayName(), _contextMenu.data());
|
||||
_accountMenus.append(accountMenu);
|
||||
_contextMenu->addMenu(accountMenu);
|
||||
|
||||
addAccountContextMenu(account, accountMenu, true);
|
||||
fetchNavigationApps(account);
|
||||
}
|
||||
} else if (accountList.count() == 1) {
|
||||
addAccountContextMenu(accountList.first(), _contextMenu.data(), false);
|
||||
fetchNavigationApps(accountList.first());
|
||||
}
|
||||
|
||||
_contextMenu->addSeparator();
|
||||
|
||||
_contextMenu->addAction(_actionStatus);
|
||||
if (isConfigured && atLeastOneConnected) {
|
||||
_contextMenu->addMenu(_recentActionsMenu);
|
||||
}
|
||||
|
||||
_contextMenu->addSeparator();
|
||||
|
||||
if (_navLinksMenu) {
|
||||
_contextMenu->addMenu(_navLinksMenu);
|
||||
}
|
||||
|
||||
_contextMenu->addSeparator();
|
||||
|
||||
if (accountList.isEmpty()) {
|
||||
_contextMenu->addAction(_actionNewAccountWizard);
|
||||
}
|
||||
_contextMenu->addAction(_actionSettings);
|
||||
if (!Theme::instance()->helpUrl().isEmpty()) {
|
||||
_contextMenu->addAction(_actionHelp);
|
||||
}
|
||||
|
||||
if (_actionCrash) {
|
||||
_contextMenu->addAction(_actionCrash);
|
||||
}
|
||||
|
||||
_contextMenu->addSeparator();
|
||||
|
||||
if (atLeastOnePaused) {
|
||||
QString text;
|
||||
if (accountList.count() > 1) {
|
||||
text = tr("Resume all synchronization");
|
||||
} else {
|
||||
text = tr("Resume synchronization");
|
||||
}
|
||||
QAction *action = _contextMenu->addAction(text);
|
||||
connect(action, &QAction::triggered, this, &ownCloudGui::slotUnpauseAllFolders);
|
||||
}
|
||||
if (atLeastOneNotPaused) {
|
||||
QString text;
|
||||
if (accountList.count() > 1) {
|
||||
text = tr("Pause all synchronization");
|
||||
} else {
|
||||
text = tr("Pause synchronization");
|
||||
}
|
||||
QAction *action = _contextMenu->addAction(text);
|
||||
connect(action, &QAction::triggered, this, &ownCloudGui::slotPauseAllFolders);
|
||||
}
|
||||
_contextMenu->addAction(_actionQuit);
|
||||
|
||||
if (_workaroundShowAndHideTray) {
|
||||
_tray->show();
|
||||
}
|
||||
}
|
||||
|
||||
void ownCloudGui::updateContextMenuNeeded()
|
||||
{
|
||||
// if it's visible and we can update live: update now
|
||||
if (contextMenuVisible() && updateWhileVisible()) {
|
||||
// Note: don't update while visible on OSX
|
||||
// https://bugreports.qt.io/browse/QTBUG-54845
|
||||
updateContextMenu();
|
||||
return;
|
||||
}
|
||||
|
||||
// if we can't lazily update: update later
|
||||
if (_workaroundNoAboutToShowUpdate) {
|
||||
// Note: don't update immediately even in the invisible case
|
||||
// as that can lead to extremely frequent menu updates
|
||||
if (!_delayedTrayUpdateTimer.isActive()) {
|
||||
_delayedTrayUpdateTimer.start();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void ownCloudGui::slotShowTrayMessage(const QString &title, const QString &msg)
|
||||
{
|
||||
if (_tray)
|
||||
|
@ -774,30 +393,6 @@ void ownCloudGui::slotFolderOpenAction(const QString &alias)
|
|||
}
|
||||
}
|
||||
|
||||
void ownCloudGui::setupActions()
|
||||
{
|
||||
_actionStatus = new QAction(tr("Unknown status"), this);
|
||||
_actionStatus->setEnabled(false);
|
||||
_navLinksMenu = new QMenu(tr("Apps"));
|
||||
_navLinksMenu->setEnabled(false);
|
||||
_actionSettings = new QAction(tr("Settings …"), this);
|
||||
_actionNewAccountWizard = new QAction(tr("New account …"), this);
|
||||
|
||||
QObject::connect(_actionSettings, &QAction::triggered, this, &ownCloudGui::slotShowSettings);
|
||||
QObject::connect(_actionNewAccountWizard, &QAction::triggered, this, &ownCloudGui::slotNewAccountWizard);
|
||||
_actionHelp = new QAction(tr("Help"), this);
|
||||
QObject::connect(_actionHelp, &QAction::triggered, this, &ownCloudGui::slotHelp);
|
||||
_actionQuit = new QAction(tr("Quit %1").arg(Theme::instance()->appNameGUI()), this);
|
||||
QObject::connect(_actionQuit, SIGNAL(triggered(bool)), _app, SLOT(quit()));
|
||||
|
||||
if (_app->debugMode()) {
|
||||
_actionCrash = new QAction(tr("Crash now", "Only shows in debug mode to allow testing the crash handler"), this);
|
||||
connect(_actionCrash, &QAction::triggered, _app, &Application::slotCrash);
|
||||
} else {
|
||||
_actionCrash = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void ownCloudGui::slotEtagResponseHeaderReceived(const QByteArray &value, int statusCode){
|
||||
if(statusCode == 200){
|
||||
qCDebug(lcApplication) << "New navigation apps ETag Response Header received " << value;
|
||||
|
@ -875,7 +470,7 @@ void ownCloudGui::slotNavigationAppsFetched(const QJsonDocument &reply, int stat
|
|||
}
|
||||
}
|
||||
} else if(accountList.size() == 1){
|
||||
buildNavigationAppsMenu(account, _contextMenu.data());
|
||||
//buildNavigationAppsMenu(account, _contextMenu.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -885,40 +480,17 @@ void ownCloudGui::slotOcsError(int statusCode, const QString &message)
|
|||
emit serverError(statusCode, message);
|
||||
}
|
||||
|
||||
void ownCloudGui::slotRebuildRecentMenus()
|
||||
{
|
||||
_recentActionsMenu->clear();
|
||||
if (!_recentItemsActions.isEmpty()) {
|
||||
foreach (QAction *a, _recentItemsActions) {
|
||||
_recentActionsMenu->addAction(a);
|
||||
}
|
||||
_recentActionsMenu->addSeparator();
|
||||
} else {
|
||||
_recentActionsMenu->addAction(tr("No items synced recently"))->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if the completion of a given item should show up in the
|
||||
/// 'Recent Activity' menu
|
||||
static bool shouldShowInRecentsMenu(const SyncFileItem &item)
|
||||
{
|
||||
return !Progress::isIgnoredKind(item._status)
|
||||
&& item._instruction != CSYNC_INSTRUCTION_EVAL
|
||||
&& item._instruction != CSYNC_INSTRUCTION_NONE;
|
||||
}
|
||||
|
||||
|
||||
void ownCloudGui::slotUpdateProgress(const QString &folder, const ProgressInfo &progress)
|
||||
{
|
||||
Q_UNUSED(folder);
|
||||
|
||||
if (progress.status() == ProgressInfo::Discovery) {
|
||||
if (!progress._currentDiscoveredRemoteFolder.isEmpty()) {
|
||||
_actionStatus->setText(tr("Checking for changes in remote '%1'")
|
||||
.arg(progress._currentDiscoveredRemoteFolder));
|
||||
//_actionStatus->setText(tr("Checking for changes in remote '%1'")
|
||||
//.arg(progress._currentDiscoveredRemoteFolder));
|
||||
} else if (!progress._currentDiscoveredLocalFolder.isEmpty()) {
|
||||
_actionStatus->setText(tr("Checking for changes in local '%1'")
|
||||
.arg(progress._currentDiscoveredLocalFolder));
|
||||
//_actionStatus->setText(tr("Checking for changes in local '%1'")
|
||||
//.arg(progress._currentDiscoveredLocalFolder));
|
||||
}
|
||||
} else if (progress.status() == ProgressInfo::Done) {
|
||||
QTimer::singleShot(2000, this, &ownCloudGui::slotComputeOverallSyncStatus);
|
||||
|
@ -941,7 +513,7 @@ void ownCloudGui::slotUpdateProgress(const QString &folder, const ProgressInfo &
|
|||
.arg(currentFile)
|
||||
.arg(totalFileCount);
|
||||
}
|
||||
_actionStatus->setText(msg);
|
||||
//_actionStatus->setText(msg);
|
||||
} else {
|
||||
QString totalSizeStr = Utility::octetsToString(progress.totalSize());
|
||||
QString msg;
|
||||
|
@ -952,16 +524,10 @@ void ownCloudGui::slotUpdateProgress(const QString &folder, const ProgressInfo &
|
|||
msg = tr("Syncing %1")
|
||||
.arg(totalSizeStr);
|
||||
}
|
||||
_actionStatus->setText(msg);
|
||||
//_actionStatus->setText(msg);
|
||||
}
|
||||
|
||||
if (!progress._lastCompletedItem.isEmpty()
|
||||
&& shouldShowInRecentsMenu(progress._lastCompletedItem)) {
|
||||
if (Progress::isWarningKind(progress._lastCompletedItem._status)) {
|
||||
// display a warn icon if warnings happened.
|
||||
QIcon warnIcon(":/client/resources/warning");
|
||||
_actionRecent->setIcon(warnIcon);
|
||||
}
|
||||
if (!progress._lastCompletedItem.isEmpty()) {
|
||||
|
||||
QString kindStr = Progress::asResultString(progress._lastCompletedItem);
|
||||
QString timeStr = QTime::currentTime().toString("hh:mm");
|
||||
|
@ -980,12 +546,6 @@ void ownCloudGui::slotUpdateProgress(const QString &folder, const ProgressInfo &
|
|||
_recentItemsActions.takeFirst()->deleteLater();
|
||||
}
|
||||
_recentItemsActions.append(action);
|
||||
|
||||
// Update the "Recent" menu if the context menu is being shown,
|
||||
// otherwise it'll be updated later, when the context menu is opened.
|
||||
if (updateWhileVisible() && contextMenuVisible()) {
|
||||
slotRebuildRecentMenus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -64,25 +64,16 @@ public:
|
|||
bool cloudProviderApiAvailable();
|
||||
#endif
|
||||
|
||||
/// Whether the tray menu is visible
|
||||
bool contextMenuVisible() const;
|
||||
|
||||
signals:
|
||||
void setupProxy();
|
||||
void serverError(int code, const QString &message);
|
||||
void isShowingSettingsDialog();
|
||||
|
||||
public slots:
|
||||
void setupContextMenu();
|
||||
void updateContextMenu();
|
||||
void updateContextMenuNeeded();
|
||||
void slotContextMenuAboutToShow();
|
||||
void slotContextMenuAboutToHide();
|
||||
void slotComputeOverallSyncStatus();
|
||||
void slotShowTrayMessage(const QString &title, const QString &msg);
|
||||
void slotShowOptionalTrayMessage(const QString &title, const QString &msg);
|
||||
void slotFolderOpenAction(const QString &alias);
|
||||
void slotRebuildRecentMenus();
|
||||
void slotUpdateProgress(const QString &folder, const ProgressInfo &progress);
|
||||
void slotShowGuiMessage(const QString &title, const QString &message);
|
||||
void slotFoldersChanged();
|
||||
|
@ -126,22 +117,12 @@ private slots:
|
|||
|
||||
private:
|
||||
void setPauseOnAllFoldersHelper(bool pause);
|
||||
void setupActions();
|
||||
void addAccountContextMenu(AccountStatePtr accountState, QMenu *menu, bool separateMenu);
|
||||
void fetchNavigationApps(AccountStatePtr account);
|
||||
void buildNavigationAppsMenu(AccountStatePtr account, QMenu *accountMenu);
|
||||
|
||||
QPointer<Systray> _tray;
|
||||
QPointer<SettingsDialog> _settingsDialog;
|
||||
QPointer<LogBrowser> _logBrowser;
|
||||
// tray's menu
|
||||
QScopedPointer<QMenu> _contextMenu;
|
||||
|
||||
// Manually tracking whether the context menu is visible via aboutToShow
|
||||
// and aboutToHide. Unfortunately aboutToHide isn't reliable everywhere
|
||||
// so this only gets used with _workaroundManualVisibility (when the tray's
|
||||
// isVisible() is unreliable)
|
||||
bool _contextMenuVisibleManual = false;
|
||||
|
||||
#ifdef WITH_LIBCLOUDPROVIDERS
|
||||
QDBusConnection _bus;
|
||||
|
@ -149,21 +130,12 @@ private:
|
|||
|
||||
QMenu *_recentActionsMenu;
|
||||
QVector<QMenu *> _accountMenus;
|
||||
bool _workaroundShowAndHideTray = false;
|
||||
bool _workaroundNoAboutToShowUpdate = false;
|
||||
bool _workaroundFakeDoubleClick = false;
|
||||
bool _workaroundManualVisibility = false;
|
||||
QTimer _delayedTrayUpdateTimer;
|
||||
QMap<QString, QPointer<ShareDialog>> _shareDialogs;
|
||||
|
||||
QAction *_actionNewAccountWizard;
|
||||
QAction *_actionSettings;
|
||||
QAction *_actionStatus;
|
||||
QAction *_actionEstimate;
|
||||
QAction *_actionRecent;
|
||||
QAction *_actionHelp;
|
||||
QAction *_actionQuit;
|
||||
QAction *_actionCrash;
|
||||
|
||||
|
||||
QMenu *_navLinksMenu;
|
||||
QMap<AccountStatePtr, QJsonArray> _navApps;
|
||||
|
|
|
@ -38,6 +38,7 @@ namespace OCC {
|
|||
|
||||
Systray::Systray() // TODO: make singleton, provide ::instance()
|
||||
: _isOpen(false)
|
||||
, _syncIsPaused(false)
|
||||
, _trayComponent(nullptr)
|
||||
, _trayContext(nullptr)
|
||||
{
|
||||
|
@ -182,4 +183,21 @@ int Systray::calcTrayWindowY()
|
|||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Systray::syncIsPaused()
|
||||
{
|
||||
return _syncIsPaused;
|
||||
}
|
||||
|
||||
void Systray::pauseResumeSync()
|
||||
{
|
||||
if (_syncIsPaused) {
|
||||
_syncIsPaused = false;
|
||||
emit resumeSync();
|
||||
} else {
|
||||
_syncIsPaused = true;
|
||||
emit pauseSync();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace OCC
|
||||
|
|
|
@ -49,15 +49,20 @@ public:
|
|||
void setToolTip(const QString &tip);
|
||||
bool isOpen();
|
||||
|
||||
Q_INVOKABLE void pauseResumeSync();
|
||||
Q_INVOKABLE int calcTrayWindowX();
|
||||
Q_INVOKABLE int calcTrayWindowY();
|
||||
Q_INVOKABLE bool syncIsPaused();
|
||||
Q_INVOKABLE void setOpened();
|
||||
Q_INVOKABLE void setClosed();
|
||||
|
||||
signals:
|
||||
void currentUserChanged();
|
||||
void openSettings();
|
||||
void openHelp();
|
||||
void shutdown();
|
||||
void pauseSync();
|
||||
void resumeSync();
|
||||
|
||||
Q_INVOKABLE void hideWindow();
|
||||
Q_INVOKABLE void showWindow();
|
||||
|
@ -67,6 +72,7 @@ private slots:
|
|||
|
||||
private:
|
||||
bool _isOpen;
|
||||
bool _syncIsPaused;
|
||||
QQmlEngine *_trayEngine;
|
||||
QQmlComponent *_trayComponent;
|
||||
QQmlContext *_trayContext;
|
||||
|
|
|
@ -8,15 +8,12 @@ MenuItem {
|
|||
Connections {
|
||||
target: userModelBackend
|
||||
onRefreshUserMenu: {
|
||||
userLine.visible = isCurrentUser ? false : true
|
||||
userLine.height = isCurrentUser ? 0 : 60
|
||||
}
|
||||
}
|
||||
|
||||
id: userLine
|
||||
visible: isCurrentUser ? false : true
|
||||
width: 216
|
||||
height: isCurrentUser ? 0 : 60
|
||||
height: 60
|
||||
|
||||
Rectangle {
|
||||
id: userLineBackground
|
||||
|
@ -52,7 +49,7 @@ MenuItem {
|
|||
spacing: 0
|
||||
Image {
|
||||
id: accountAvatar
|
||||
Layout.leftMargin: 4
|
||||
Layout.leftMargin: 2
|
||||
verticalAlignment: Qt.AlignCenter
|
||||
source: ("image://avatars/" + index)
|
||||
Layout.preferredHeight: (userLineBackground.height -16)
|
||||
|
@ -66,14 +63,18 @@ MenuItem {
|
|||
Layout.leftMargin: 12
|
||||
Label {
|
||||
id: accountUser
|
||||
width: 120
|
||||
text: name
|
||||
elide: Text.ElideRight
|
||||
color: "black"
|
||||
font.pixelSize: 12
|
||||
font.bold: true
|
||||
}
|
||||
Label {
|
||||
id: accountServer
|
||||
width: 120
|
||||
text: server
|
||||
elide: Text.ElideRight
|
||||
color: "black"
|
||||
font.pixelSize: 10
|
||||
}
|
||||
|
|
|
@ -50,10 +50,6 @@ QString User::name() const
|
|||
if (name == "") {
|
||||
name = _account->account()->credentials()->user();
|
||||
}
|
||||
if (name.size() > 19) {
|
||||
name.truncate(17);
|
||||
name.append("...");
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
|
@ -63,10 +59,6 @@ QString User::server(bool shortened) const
|
|||
if (shortened) {
|
||||
serverUrl.replace(QLatin1String("https://"), QLatin1String(""));
|
||||
serverUrl.replace(QLatin1String("http://"), QLatin1String(""));
|
||||
if (serverUrl.size() > 21) {
|
||||
serverUrl.truncate(19);
|
||||
serverUrl.append("...");
|
||||
}
|
||||
}
|
||||
return serverUrl;
|
||||
}
|
||||
|
@ -278,4 +270,4 @@ QImage ImageProvider::requestImage(const QString &id, QSize *size, const QSize &
|
|||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -100,7 +100,7 @@ Window {
|
|||
hoverEnabled: true
|
||||
onClicked:
|
||||
{
|
||||
accMenuLoginButton.text = (userModelBackend.isCurrentUserConnected() ? "Log out" : "Log in")
|
||||
syncPauseButton.text = systrayBackend.syncIsPaused() ? "Resume sync for all" : "Pause sync for all"
|
||||
accountMenu.open()
|
||||
}
|
||||
|
||||
|
@ -109,6 +109,7 @@ Window {
|
|||
x: (currentAccountButton.x + 2)
|
||||
y: (currentAccountButton.y + currentAccountButton.height + 2)
|
||||
width: (currentAccountButton.width - 4)
|
||||
closePolicy: "CloseOnPressOutside"
|
||||
|
||||
background: Rectangle {
|
||||
border.color: "#0082c9"
|
||||
|
@ -118,33 +119,19 @@ Window {
|
|||
Instantiator {
|
||||
model: userModelBackend
|
||||
delegate: UserLine {}
|
||||
onObjectAdded: accountMenu.insertItem(3, object)
|
||||
onObjectAdded: accountMenu.insertItem(index, object)
|
||||
onObjectRemoved: accountMenu.removeItem(object)
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
id: accMenuLoginButton
|
||||
onClicked: (userModelBackend.isCurrentUserConnected()
|
||||
? userModelBackend.logout()
|
||||
: userModelBackend.login() )
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
text: "Remove account"
|
||||
onClicked: userModelBackend.removeAccount()
|
||||
}
|
||||
|
||||
MenuSeparator { id: accountMenuSeparator }
|
||||
|
||||
MenuItem {
|
||||
text: "Add account"
|
||||
onClicked: userModelBackend.addAccount()
|
||||
}
|
||||
|
||||
MenuSeparator { id: otherMenuSeparator }
|
||||
MenuSeparator { id: accountMenuSeparator }
|
||||
|
||||
MenuItem {
|
||||
text: systrayBackend.syncIsPaused() ? "Resume syncing" : "Pause syncing"
|
||||
id: syncPauseButton
|
||||
onClicked: systrayBackend.pauseResumeSync()
|
||||
}
|
||||
|
||||
|
@ -153,6 +140,11 @@ Window {
|
|||
onClicked: systrayBackend.openSettings()
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
text: "Help"
|
||||
onClicked: systrayBackend.openHelp()
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
text: "Quit Nextcloud"
|
||||
onClicked: systrayBackend.shutdown()
|
||||
|
@ -236,23 +228,27 @@ Window {
|
|||
Layout.leftMargin: 6
|
||||
Label {
|
||||
id: currentAccountUser
|
||||
width: 128
|
||||
text: userModelBackend.currentUserName()
|
||||
elide: Text.ElideRight
|
||||
color: "white"
|
||||
font.pixelSize: 12
|
||||
font.bold: true
|
||||
}
|
||||
Label {
|
||||
id: currentAccountServer
|
||||
width: 128
|
||||
text: userModelBackend.currentUserServer()
|
||||
elide: Text.ElideRight
|
||||
color: "white"
|
||||
font.pixelSize: 10
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
Layout.alignment: Qt.AlignRight
|
||||
verticalAlignment: Qt.AlignCenter
|
||||
Layout.margins: 12
|
||||
Layout.margins: 8
|
||||
source: "qrc:///client/theme/white/caret-down.svg"
|
||||
sourceSize.width: 20
|
||||
sourceSize.height: 20
|
||||
|
|
|
@ -123,11 +123,11 @@ QIcon Theme::applicationIcon() const
|
|||
* helper to load a icon from either the icon theme the desktop provides or from
|
||||
* the apps Qt resources.
|
||||
*/
|
||||
QIcon Theme::themeIcon(const QString &name, bool sysTray, bool sysTrayMenuVisible) const
|
||||
QIcon Theme::themeIcon(const QString &name, bool sysTray) const
|
||||
{
|
||||
QString flavor;
|
||||
if (sysTray) {
|
||||
flavor = systrayIconFlavor(_mono, sysTrayMenuVisible);
|
||||
flavor = systrayIconFlavor(_mono);
|
||||
} else {
|
||||
flavor = QLatin1String("colored");
|
||||
}
|
||||
|
@ -170,7 +170,7 @@ QIcon Theme::themeIcon(const QString &name, bool sysTray, bool sysTrayMenuVisibl
|
|||
#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
|
||||
// This defines the icon as a template and enables automatic macOS color handling
|
||||
// See https://bugreports.qt.io/browse/QTBUG-42109
|
||||
cached.setIsMask(_mono && sysTray && !sysTrayMenuVisible);
|
||||
cached.setIsMask(_mono && sysTray);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -270,18 +270,11 @@ QString Theme::defaultClientFolder() const
|
|||
return appName();
|
||||
}
|
||||
|
||||
QString Theme::systrayIconFlavor(bool mono, bool sysTrayMenuVisible) const
|
||||
QString Theme::systrayIconFlavor(bool mono) const
|
||||
{
|
||||
Q_UNUSED(sysTrayMenuVisible)
|
||||
QString flavor;
|
||||
if (mono) {
|
||||
flavor = Utility::hasDarkSystray() ? QLatin1String("white") : QLatin1String("black");
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
if (sysTrayMenuVisible) {
|
||||
flavor = QLatin1String("white");
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
flavor = QLatin1String("colored");
|
||||
}
|
||||
|
@ -395,7 +388,7 @@ QVariant Theme::customMedia(CustomMediaType type)
|
|||
return re;
|
||||
}
|
||||
|
||||
QIcon Theme::syncStateIcon(SyncResult::Status status, bool sysTray, bool sysTrayMenuVisible) const
|
||||
QIcon Theme::syncStateIcon(SyncResult::Status status, bool sysTray) const
|
||||
{
|
||||
// FIXME: Mind the size!
|
||||
QString statusIcon;
|
||||
|
@ -427,7 +420,7 @@ QIcon Theme::syncStateIcon(SyncResult::Status status, bool sysTray, bool sysTray
|
|||
statusIcon = QLatin1String("state-error");
|
||||
}
|
||||
|
||||
return themeIcon(statusIcon, sysTray, sysTrayMenuVisible);
|
||||
return themeIcon(statusIcon, sysTray);
|
||||
}
|
||||
|
||||
QIcon Theme::folderDisabledIcon() const
|
||||
|
@ -435,9 +428,9 @@ QIcon Theme::folderDisabledIcon() const
|
|||
return themeIcon(QLatin1String("state-pause"));
|
||||
}
|
||||
|
||||
QIcon Theme::folderOfflineIcon(bool sysTray, bool sysTrayMenuVisible) const
|
||||
QIcon Theme::folderOfflineIcon(bool sysTray) const
|
||||
{
|
||||
return themeIcon(QLatin1String("state-offline"), sysTray, sysTrayMenuVisible);
|
||||
return themeIcon(QLatin1String("state-offline"), sysTray);
|
||||
}
|
||||
|
||||
QColor Theme::wizardHeaderTitleColor() const
|
||||
|
|
|
@ -93,10 +93,10 @@ public:
|
|||
/**
|
||||
* get an sync state icon
|
||||
*/
|
||||
virtual QIcon syncStateIcon(SyncResult::Status, bool sysTray = false, bool sysTrayMenuVisible = false) const;
|
||||
virtual QIcon syncStateIcon(SyncResult::Status, bool sysTray = false) const;
|
||||
|
||||
virtual QIcon folderDisabledIcon() const;
|
||||
virtual QIcon folderOfflineIcon(bool sysTray = false, bool sysTrayMenuVisible = false) const;
|
||||
virtual QIcon folderOfflineIcon(bool sysTray = false) const;
|
||||
virtual QIcon applicationIcon() const;
|
||||
#endif
|
||||
|
||||
|
@ -166,7 +166,7 @@ public:
|
|||
virtual QString enforcedLocale() const { return QString(); }
|
||||
|
||||
/** colored, white or black */
|
||||
QString systrayIconFlavor(bool mono, bool sysTrayMenuVisible = false) const;
|
||||
QString systrayIconFlavor(bool mono) const;
|
||||
|
||||
#ifndef TOKEN_AUTH_ONLY
|
||||
/**
|
||||
|
@ -449,7 +449,7 @@ public:
|
|||
|
||||
protected:
|
||||
#ifndef TOKEN_AUTH_ONLY
|
||||
QIcon themeIcon(const QString &name, bool sysTray = false, bool sysTrayMenuVisible = false) const;
|
||||
QIcon themeIcon(const QString &name, bool sysTray = false) const;
|
||||
#endif
|
||||
Theme();
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче