diff --git a/src/gui/owncloudgui.cpp b/src/gui/owncloudgui.cpp index 24eb9aea9..54dd1faac 100644 --- a/src/gui/owncloudgui.cpp +++ b/src/gui/owncloudgui.cpp @@ -72,19 +72,24 @@ ownCloudGui::ownCloudGui(Application *parent) , _app(parent) { _tray = new Systray(); - //qmlRegisterType("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(_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(); - } } } diff --git a/src/gui/owncloudgui.h b/src/gui/owncloudgui.h index 98af71bb7..518be8b16 100644 --- a/src/gui/owncloudgui.h +++ b/src/gui/owncloudgui.h @@ -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 _tray; QPointer _settingsDialog; QPointer _logBrowser; - // tray's menu - QScopedPointer _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 _accountMenus; - bool _workaroundShowAndHideTray = false; - bool _workaroundNoAboutToShowUpdate = false; - bool _workaroundFakeDoubleClick = false; - bool _workaroundManualVisibility = false; - QTimer _delayedTrayUpdateTimer; QMap> _shareDialogs; QAction *_actionNewAccountWizard; QAction *_actionSettings; - QAction *_actionStatus; QAction *_actionEstimate; - QAction *_actionRecent; - QAction *_actionHelp; - QAction *_actionQuit; - QAction *_actionCrash; + QMenu *_navLinksMenu; QMap _navApps; diff --git a/src/gui/systray.cpp b/src/gui/systray.cpp index db61cfa82..93240c133 100644 --- a/src/gui/systray.cpp +++ b/src/gui/systray.cpp @@ -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 diff --git a/src/gui/systray.h b/src/gui/systray.h index 6fe451c00..3460940a3 100644 --- a/src/gui/systray.h +++ b/src/gui/systray.h @@ -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; diff --git a/src/gui/tray/UserLine.qml b/src/gui/tray/UserLine.qml index 4ade26f23..0d4fb0f08 100644 --- a/src/gui/tray/UserLine.qml +++ b/src/gui/tray/UserLine.qml @@ -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 } diff --git a/src/gui/tray/UserModel.cpp b/src/gui/tray/UserModel.cpp index e7103a65a..22b49396b 100644 --- a/src/gui/tray/UserModel.cpp +++ b/src/gui/tray/UserModel.cpp @@ -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 & } } -} \ No newline at end of file +} diff --git a/src/gui/tray/Window.qml b/src/gui/tray/Window.qml index a761885b7..d7bbe4a94 100644 --- a/src/gui/tray/Window.qml +++ b/src/gui/tray/Window.qml @@ -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 diff --git a/src/libsync/theme.cpp b/src/libsync/theme.cpp index 8b2b15e5c..08bf11521 100644 --- a/src/libsync/theme.cpp +++ b/src/libsync/theme.cpp @@ -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 diff --git a/src/libsync/theme.h b/src/libsync/theme.h index 966c9b5c9..12a643d00 100644 --- a/src/libsync/theme.h +++ b/src/libsync/theme.h @@ -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();