2013-10-01 15:52:07 +04:00
|
|
|
/*
|
|
|
|
* Copyright (C) by Klaas Freitag <freitag@owncloud.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
|
2016-10-25 12:00:07 +03:00
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
2013-10-01 15:52:07 +04:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2014-07-11 02:31:24 +04:00
|
|
|
#include "application.h"
|
|
|
|
#include "owncloudgui.h"
|
2018-02-19 22:53:12 +03:00
|
|
|
#include "ocsnavigationappsjob.h"
|
2014-07-11 02:31:24 +04:00
|
|
|
#include "theme.h"
|
|
|
|
#include "folderman.h"
|
|
|
|
#include "progressdispatcher.h"
|
|
|
|
#include "owncloudsetupwizard.h"
|
2015-01-13 15:50:41 +03:00
|
|
|
#include "sharedialog.h"
|
2014-02-14 06:02:59 +04:00
|
|
|
#if defined(Q_OS_MAC)
|
2014-09-12 13:25:52 +04:00
|
|
|
#include "settingsdialogmac.h"
|
2014-08-12 16:58:34 +04:00
|
|
|
#include "macwindow.h" // qtmacgoodies
|
2014-02-14 06:02:59 +04:00
|
|
|
#else
|
2014-07-11 02:31:24 +04:00
|
|
|
#include "settingsdialog.h"
|
2014-02-14 06:02:59 +04:00
|
|
|
#endif
|
2014-07-11 02:31:24 +04:00
|
|
|
#include "logger.h"
|
|
|
|
#include "logbrowser.h"
|
|
|
|
#include "account.h"
|
2014-12-17 16:09:57 +03:00
|
|
|
#include "accountstate.h"
|
2014-07-07 17:49:48 +04:00
|
|
|
#include "openfilemanager.h"
|
2015-04-09 17:19:17 +03:00
|
|
|
#include "accountmanager.h"
|
2017-09-01 19:11:43 +03:00
|
|
|
#include "common/syncjournalfilerecord.h"
|
2013-11-23 03:14:02 +04:00
|
|
|
#include "creds/abstractcredentials.h"
|
2017-07-23 21:58:00 +03:00
|
|
|
#ifdef WITH_LIBCLOUDPROVIDERS
|
|
|
|
#include "cloudproviders/cloudprovidermanager.h"
|
|
|
|
#endif
|
2013-10-01 15:52:07 +04:00
|
|
|
|
|
|
|
#include <QDesktopServices>
|
2016-03-30 13:19:09 +03:00
|
|
|
#include <QDir>
|
2013-10-01 15:52:07 +04:00
|
|
|
#include <QMessageBox>
|
2017-07-23 21:58:00 +03:00
|
|
|
#include <QSignalMapper>
|
2017-12-15 11:45:28 +03:00
|
|
|
#ifdef WITH_LIBCLOUDPROVIDERS
|
2017-07-23 21:58:00 +03:00
|
|
|
#include <QtDBus/QDBusConnection>
|
|
|
|
#include <QtDBus/QDBusInterface>
|
2017-12-15 11:45:28 +03:00
|
|
|
#endif
|
2013-10-01 15:52:07 +04:00
|
|
|
|
2014-08-28 19:23:44 +04:00
|
|
|
#if defined(Q_OS_X11)
|
|
|
|
#include <QX11Info>
|
|
|
|
#endif
|
|
|
|
|
2018-01-19 22:53:45 +03:00
|
|
|
#include <QJsonDocument>
|
|
|
|
#include <QJsonObject>
|
2018-02-22 21:15:02 +03:00
|
|
|
#include <QJsonArray>
|
2018-01-19 22:53:45 +03:00
|
|
|
|
2014-11-10 00:34:07 +03:00
|
|
|
namespace OCC {
|
2013-10-01 15:52:07 +04:00
|
|
|
|
2015-05-13 13:54:31 +03:00
|
|
|
const char propertyAccountC[] = "oc_account";
|
|
|
|
|
2013-10-01 15:52:07 +04:00
|
|
|
ownCloudGui::ownCloudGui(Application *parent)
|
|
|
|
: QObject(parent)
|
2013-10-02 17:28:33 +04:00
|
|
|
, _tray(0)
|
2014-03-26 02:33:46 +04:00
|
|
|
#if defined(Q_OS_MAC)
|
2018-06-18 10:48:30 +03:00
|
|
|
, _settingsDialog(new SettingsDialogMac(this))
|
2014-03-26 02:33:46 +04:00
|
|
|
#else
|
2018-06-18 10:48:30 +03:00
|
|
|
, _settingsDialog(new SettingsDialog(this))
|
2014-03-26 02:33:46 +04:00
|
|
|
#endif
|
2018-06-18 10:48:30 +03:00
|
|
|
, _logBrowser(0)
|
2017-12-15 11:45:28 +03:00
|
|
|
#ifdef WITH_LIBCLOUDPROVIDERS
|
2017-07-23 21:58:00 +03:00
|
|
|
, _bus(QDBusConnection::sessionBus())
|
2017-12-15 11:45:28 +03:00
|
|
|
#endif
|
2013-10-01 15:52:07 +04:00
|
|
|
, _recentActionsMenu(0)
|
|
|
|
, _app(parent)
|
|
|
|
{
|
|
|
|
_tray = new Systray();
|
2013-10-31 13:52:19 +04:00
|
|
|
_tray->setParent(this);
|
2014-08-19 16:09:53 +04:00
|
|
|
|
|
|
|
// for the beginning, set the offline icon until the account was verified
|
2016-10-07 14:32:42 +03:00
|
|
|
_tray->setIcon(Theme::instance()->folderOfflineIcon(/*systray?*/ true, /*currently visible?*/ false));
|
2013-10-01 15:52:07 +04:00
|
|
|
|
2017-09-20 11:14:48 +03:00
|
|
|
connect(_tray.data(), &QSystemTrayIcon::activated,
|
|
|
|
this, &ownCloudGui::slotTrayClicked);
|
2013-10-01 15:52:07 +04:00
|
|
|
|
|
|
|
setupActions();
|
|
|
|
setupContextMenu();
|
|
|
|
|
|
|
|
_tray->show();
|
|
|
|
|
|
|
|
ProgressDispatcher *pd = ProgressDispatcher::instance();
|
2017-09-20 11:14:48 +03:00
|
|
|
connect(pd, &ProgressDispatcher::progressInfo, this,
|
|
|
|
&ownCloudGui::slotUpdateProgress);
|
2013-10-01 15:52:07 +04:00
|
|
|
|
|
|
|
FolderMan *folderMan = FolderMan::instance();
|
2017-09-20 11:14:48 +03:00
|
|
|
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,
|
|
|
|
this, &ownCloudGui::slotShowOptionalTrayMessage);
|
|
|
|
connect(Logger::instance(), &Logger::guiMessage,
|
|
|
|
this, &ownCloudGui::slotShowGuiMessage);
|
2013-10-01 15:52:07 +04:00
|
|
|
}
|
|
|
|
|
2017-07-23 21:58:00 +03:00
|
|
|
#ifdef WITH_LIBCLOUDPROVIDERS
|
|
|
|
void ownCloudGui::setupCloudProviders()
|
|
|
|
{
|
|
|
|
new CloudProviderManager(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ownCloudGui::cloudProviderApiAvailable()
|
|
|
|
{
|
|
|
|
if (!_bus.isConnected()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
QDBusInterface dbus_iface("org.freedesktop.CloudProviderManager", "/org/freedesktop/CloudProviderManager",
|
|
|
|
"org.freedesktop.CloudProvider.Manager1", _bus);
|
|
|
|
|
|
|
|
if (!dbus_iface.isValid()) {
|
|
|
|
qCInfo(lcApplication) << "DBus interface unavailable";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-11-10 00:30:29 +03:00
|
|
|
// This should rather be in application.... or rather in ConfigFile?
|
2015-09-02 12:10:01 +03:00
|
|
|
void ownCloudGui::slotOpenSettingsDialog()
|
2013-10-01 15:52:07 +04:00
|
|
|
{
|
2013-10-30 19:31:47 +04:00
|
|
|
// if account is set up, start the configuration wizard.
|
2015-04-17 18:56:17 +03:00
|
|
|
if (!AccountManager::instance()->accounts().isEmpty()) {
|
2015-11-10 14:33:36 +03:00
|
|
|
if (_settingsDialog.isNull() || QApplication::activeWindow() != _settingsDialog) {
|
2015-09-02 12:10:01 +03:00
|
|
|
slotShowSettings();
|
|
|
|
} else {
|
|
|
|
_settingsDialog->close();
|
2013-10-01 15:52:07 +04:00
|
|
|
}
|
|
|
|
} else {
|
2017-03-30 14:46:20 +03:00
|
|
|
qCInfo(lcApplication) << "No configured folders yet, starting setup wizard";
|
2016-11-18 14:17:05 +03:00
|
|
|
slotNewAccountWizard();
|
2013-10-01 15:52:07 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ownCloudGui::slotTrayClicked(QSystemTrayIcon::ActivationReason reason)
|
|
|
|
{
|
2018-06-14 15:35:06 +03:00
|
|
|
if (_workaroundFakeDoubleClick) {
|
2015-09-04 12:58:50 +03:00
|
|
|
static QElapsedTimer last_click;
|
|
|
|
if (last_click.isValid() && last_click.elapsed() < 200) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
last_click.start();
|
2015-09-02 12:10:01 +03:00
|
|
|
}
|
|
|
|
|
2017-04-20 09:55:44 +03:00
|
|
|
// Left click
|
2013-10-01 15:52:07 +04:00
|
|
|
if (reason == QSystemTrayIcon::Trigger) {
|
2017-04-20 09:55:44 +03:00
|
|
|
if (OwncloudSetupWizard::bringWizardToFrontIfVisible()) {
|
|
|
|
// brought wizard to front
|
|
|
|
} else if (_shareDialogs.size() > 0) {
|
|
|
|
// Share dialog(s) be hidden by other apps, bring them back
|
|
|
|
Q_FOREACH (const QPointer<ShareDialog> &shareDialog, _shareDialogs) {
|
|
|
|
Q_ASSERT(shareDialog.data());
|
|
|
|
raiseDialog(shareDialog);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
#ifdef Q_OS_MAC
|
|
|
|
// on macOS, a left click always opens menu.
|
|
|
|
// However if the settings dialog is already visible but hidden
|
|
|
|
// by other applications, this will bring it to the front.
|
|
|
|
if (!_settingsDialog.isNull() && _settingsDialog->isVisible()) {
|
|
|
|
raiseDialog(_settingsDialog.data());
|
|
|
|
}
|
2014-08-12 16:47:43 +04:00
|
|
|
#else
|
2017-04-20 09:55:44 +03:00
|
|
|
slotOpenSettingsDialog();
|
|
|
|
#endif
|
2014-08-12 16:47:43 +04:00
|
|
|
}
|
|
|
|
}
|
2017-04-20 09:55:44 +03:00
|
|
|
// FIXME: Also make sure that any auto updater dialogue https://github.com/owncloud/client/issues/5613
|
|
|
|
// or SSL error dialog also comes to front.
|
2013-10-01 15:52:07 +04:00
|
|
|
}
|
|
|
|
|
2015-04-28 16:13:39 +03:00
|
|
|
void ownCloudGui::slotSyncStateChange(Folder *folder)
|
2013-10-01 15:52:07 +04:00
|
|
|
{
|
2013-10-02 17:28:33 +04:00
|
|
|
slotComputeOverallSyncStatus();
|
2016-09-23 11:44:54 +03:00
|
|
|
updateContextMenuNeeded();
|
2013-10-01 15:52:07 +04:00
|
|
|
|
2015-04-28 16:13:39 +03:00
|
|
|
if (!folder) {
|
2014-08-19 16:08:31 +04:00
|
|
|
return; // Valid, just a general GUI redraw was needed.
|
|
|
|
}
|
|
|
|
|
2015-04-28 16:13:39 +03:00
|
|
|
auto result = folder->syncResult();
|
|
|
|
|
2017-03-30 14:46:20 +03:00
|
|
|
qCInfo(lcApplication) << "Sync state changed for folder " << folder->remoteUrl().toString() << ": " << result.statusString();
|
2013-10-01 15:52:07 +04:00
|
|
|
|
2018-04-10 13:20:12 +03:00
|
|
|
if (result.status() == SyncResult::Success
|
|
|
|
|| result.status() == SyncResult::Problem
|
|
|
|
|| result.status() == SyncResult::SyncAbortRequested
|
|
|
|
|| result.status() == SyncResult::Error) {
|
2013-10-02 17:28:33 +04:00
|
|
|
Logger::instance()->enterNextLogFile();
|
|
|
|
}
|
2015-11-04 18:40:22 +03:00
|
|
|
|
|
|
|
if (result.status() == SyncResult::NotYetStarted) {
|
|
|
|
_settingsDialog->slotRefreshActivity(folder->accountState());
|
|
|
|
}
|
2013-10-01 15:52:07 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void ownCloudGui::slotFoldersChanged()
|
|
|
|
{
|
2013-10-02 17:28:33 +04:00
|
|
|
slotComputeOverallSyncStatus();
|
2016-09-23 11:44:54 +03:00
|
|
|
updateContextMenuNeeded();
|
2013-10-01 15:52:07 +04:00
|
|
|
}
|
|
|
|
|
2013-10-02 20:16:24 +04:00
|
|
|
void ownCloudGui::slotOpenPath(const QString &path)
|
|
|
|
{
|
2014-07-07 17:49:48 +04:00
|
|
|
showInFileManager(path);
|
2013-10-02 20:16:24 +04:00
|
|
|
}
|
|
|
|
|
2013-11-25 18:33:35 +04:00
|
|
|
void ownCloudGui::slotAccountStateChanged()
|
2013-11-23 03:14:02 +04:00
|
|
|
{
|
2016-09-23 11:44:54 +03:00
|
|
|
updateContextMenuNeeded();
|
2014-04-14 19:51:57 +04:00
|
|
|
slotComputeOverallSyncStatus();
|
2013-11-23 03:14:02 +04:00
|
|
|
}
|
|
|
|
|
2016-03-02 13:59:36 +03:00
|
|
|
void ownCloudGui::slotTrayMessageIfServerUnsupported(Account *account)
|
|
|
|
{
|
|
|
|
if (account->serverVersionUnsupported()) {
|
|
|
|
slotShowTrayMessage(
|
|
|
|
tr("Unsupported Server Version"),
|
|
|
|
tr("The server on account %1 runs an old and unsupported version %2. "
|
|
|
|
"Using this client with unsupported server versions is untested and "
|
|
|
|
"potentially dangerous. Proceed at your own risk.")
|
|
|
|
.arg(account->displayName(), account->serverVersion()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-02 17:28:33 +04:00
|
|
|
void ownCloudGui::slotComputeOverallSyncStatus()
|
2013-10-01 15:52:07 +04:00
|
|
|
{
|
2015-05-13 14:10:14 +03:00
|
|
|
bool allSignedOut = true;
|
2016-03-01 18:07:11 +03:00
|
|
|
bool allPaused = true;
|
2017-10-06 12:54:16 +03:00
|
|
|
bool allDisconnected = true;
|
2015-07-01 13:30:18 +03:00
|
|
|
QVector<AccountStatePtr> problemAccounts;
|
2017-10-06 12:54:16 +03:00
|
|
|
auto setStatusText = [&](const QString &text) {
|
|
|
|
// Don't overwrite the status if we're currently syncing
|
|
|
|
if (FolderMan::instance()->currentSyncFolder())
|
|
|
|
return;
|
|
|
|
_actionStatus->setText(text);
|
|
|
|
};
|
|
|
|
|
2015-05-13 14:10:14 +03:00
|
|
|
foreach (auto a, AccountManager::instance()->accounts()) {
|
|
|
|
if (!a->isSignedOut()) {
|
|
|
|
allSignedOut = false;
|
2013-11-23 03:14:02 +04:00
|
|
|
}
|
2015-07-01 13:30:18 +03:00
|
|
|
if (!a->isConnected()) {
|
|
|
|
problemAccounts.append(a);
|
2017-10-06 12:54:16 +03:00
|
|
|
} else {
|
|
|
|
allDisconnected = false;
|
2015-07-01 13:30:18 +03:00
|
|
|
}
|
|
|
|
}
|
2016-03-01 18:07:11 +03:00
|
|
|
foreach (Folder *f, FolderMan::instance()->map()) {
|
|
|
|
if (!f->syncPaused()) {
|
|
|
|
allPaused = false;
|
|
|
|
}
|
|
|
|
}
|
2015-07-01 13:30:18 +03:00
|
|
|
|
|
|
|
if (!problemAccounts.empty()) {
|
2016-10-06 18:18:51 +03:00
|
|
|
_tray->setIcon(Theme::instance()->folderOfflineIcon(true, contextMenuVisible()));
|
2017-10-06 12:54:16 +03:00
|
|
|
if (allDisconnected) {
|
|
|
|
setStatusText(tr("Disconnected"));
|
|
|
|
} else {
|
|
|
|
setStatusText(tr("Disconnected from some accounts"));
|
|
|
|
}
|
2015-08-10 14:09:05 +03:00
|
|
|
#ifdef Q_OS_WIN
|
|
|
|
// Windows has a 128-char tray tooltip length limit.
|
|
|
|
QStringList accountNames;
|
|
|
|
foreach (AccountStatePtr a, problemAccounts) {
|
|
|
|
accountNames.append(a->account()->displayName());
|
|
|
|
}
|
|
|
|
_tray->setToolTip(tr("Disconnected from %1").arg(accountNames.join(QLatin1String(", "))));
|
|
|
|
#else
|
2015-07-01 13:30:18 +03:00
|
|
|
QStringList messages;
|
|
|
|
messages.append(tr("Disconnected from accounts:"));
|
|
|
|
foreach (AccountStatePtr a, problemAccounts) {
|
|
|
|
QString message = tr("Account %1: %2").arg(a->account()->displayName(), a->stateString(a->state()));
|
|
|
|
if (!a->connectionErrors().empty()) {
|
|
|
|
message += QLatin1String("\n");
|
|
|
|
message += a->connectionErrors().join(QLatin1String("\n"));
|
|
|
|
}
|
|
|
|
messages.append(message);
|
2014-04-14 19:51:57 +04:00
|
|
|
}
|
2015-07-01 13:30:18 +03:00
|
|
|
_tray->setToolTip(messages.join(QLatin1String("\n\n")));
|
2015-08-10 14:09:05 +03:00
|
|
|
#endif
|
2015-07-01 13:30:18 +03:00
|
|
|
return;
|
2013-11-23 03:14:02 +04:00
|
|
|
}
|
2015-05-13 14:10:14 +03:00
|
|
|
|
|
|
|
if (allSignedOut) {
|
2016-10-06 18:18:51 +03:00
|
|
|
_tray->setIcon(Theme::instance()->folderOfflineIcon(true, contextMenuVisible()));
|
2015-05-13 14:10:14 +03:00
|
|
|
_tray->setToolTip(tr("Please sign in"));
|
2017-10-06 12:54:16 +03:00
|
|
|
setStatusText(tr("Signed out"));
|
2015-05-13 14:10:14 +03:00
|
|
|
return;
|
2016-03-01 18:07:11 +03:00
|
|
|
} else if (allPaused) {
|
2016-10-06 18:18:51 +03:00
|
|
|
_tray->setIcon(Theme::instance()->syncStateIcon(SyncResult::Paused, true, contextMenuVisible()));
|
2016-03-01 18:07:11 +03:00
|
|
|
_tray->setToolTip(tr("Account synchronization is disabled"));
|
2017-10-06 12:54:16 +03:00
|
|
|
setStatusText(tr("Synchronization is paused"));
|
2016-03-01 18:07:11 +03:00
|
|
|
return;
|
2015-05-13 14:10:14 +03:00
|
|
|
}
|
|
|
|
|
2015-10-05 07:21:19 +03:00
|
|
|
// display the info of the least successful sync (eg. do not just display the result of the latest sync)
|
2013-10-01 15:52:07 +04:00
|
|
|
QString trayMessage;
|
|
|
|
FolderMan *folderMan = FolderMan::instance();
|
|
|
|
Folder::Map map = folderMan->map();
|
2018-01-23 16:11:20 +03:00
|
|
|
|
|
|
|
SyncResult::Status overallStatus = SyncResult::Undefined;
|
|
|
|
bool hasUnresolvedConflicts = false;
|
|
|
|
FolderMan::trayOverallStatus(map.values(), &overallStatus, &hasUnresolvedConflicts);
|
|
|
|
|
|
|
|
// If the sync succeeded but there are unresolved conflicts,
|
|
|
|
// show the problem icon!
|
|
|
|
auto iconStatus = overallStatus;
|
|
|
|
if (iconStatus == SyncResult::Success && hasUnresolvedConflicts) {
|
|
|
|
iconStatus = SyncResult::Problem;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we don't get a status for whatever reason, that's a Problem
|
|
|
|
if (iconStatus == SyncResult::Undefined) {
|
|
|
|
iconStatus = SyncResult::Problem;
|
|
|
|
}
|
|
|
|
|
|
|
|
QIcon statusIcon = Theme::instance()->syncStateIcon(iconStatus, true, contextMenuVisible());
|
|
|
|
_tray->setIcon(statusIcon);
|
2013-10-01 15:52:07 +04:00
|
|
|
|
2015-07-01 13:30:18 +03:00
|
|
|
// create the tray blob message, check if we have an defined state
|
2018-01-23 16:11:20 +03:00
|
|
|
if (map.count() > 0) {
|
2015-08-10 14:09:05 +03:00
|
|
|
#ifdef Q_OS_WIN
|
2017-10-06 12:54:16 +03:00
|
|
|
// Windows has a 128-char tray tooltip length limit.
|
2018-01-23 16:11:20 +03:00
|
|
|
trayMessage = folderMan->trayTooltipStatusString(overallStatus, hasUnresolvedConflicts, false);
|
2015-08-10 14:09:05 +03:00
|
|
|
#else
|
2017-10-06 12:54:16 +03:00
|
|
|
QStringList allStatusStrings;
|
|
|
|
foreach (Folder *folder, map.values()) {
|
2018-01-23 16:11:20 +03:00
|
|
|
QString folderMessage = FolderMan::trayTooltipStatusString(
|
|
|
|
folder->syncResult().status(),
|
|
|
|
folder->syncResult().hasUnresolvedConflicts(),
|
|
|
|
folder->syncPaused());
|
2017-10-06 12:54:16 +03:00
|
|
|
allStatusStrings += tr("Folder %1: %2").arg(folder->shortGuiLocalPath(), folderMessage);
|
2013-10-15 19:00:53 +04:00
|
|
|
}
|
2017-10-06 12:54:16 +03:00
|
|
|
trayMessage = allStatusStrings.join(QLatin1String("\n"));
|
|
|
|
#endif
|
2013-10-01 15:52:07 +04:00
|
|
|
_tray->setToolTip(trayMessage);
|
2017-10-06 12:54:16 +03:00
|
|
|
|
2018-01-23 16:11:20 +03:00
|
|
|
if (overallStatus == SyncResult::Success || overallStatus == SyncResult::Problem) {
|
|
|
|
if (hasUnresolvedConflicts) {
|
|
|
|
setStatusText(tr("Unresolved conflicts"));
|
|
|
|
} else {
|
|
|
|
setStatusText(tr("Up to date"));
|
|
|
|
}
|
|
|
|
} else if (overallStatus == SyncResult::Paused) {
|
2017-10-06 12:54:16 +03:00
|
|
|
setStatusText(tr("Synchronization is paused"));
|
|
|
|
} else {
|
|
|
|
setStatusText(tr("Error during synchronization"));
|
|
|
|
}
|
2013-10-01 15:52:07 +04:00
|
|
|
} else {
|
2015-07-01 13:30:18 +03:00
|
|
|
_tray->setToolTip(tr("There are no sync folders configured."));
|
2017-10-06 12:54:16 +03:00
|
|
|
setStatusText(tr("No sync folders configured"));
|
2013-10-01 15:52:07 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-03 11:59:44 +03:00
|
|
|
void ownCloudGui::addAccountContextMenu(AccountStatePtr accountState, QMenu *menu, bool separateMenu)
|
2013-10-01 15:52:07 +04:00
|
|
|
{
|
2015-07-03 11:59:44 +03:00
|
|
|
// 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()));
|
2017-09-20 11:14:48 +03:00
|
|
|
QObject::connect(actionOpenoC, &QAction::triggered, this, &ownCloudGui::slotOpenOwnCloud);
|
2015-07-03 11:59:44 +03:00
|
|
|
|
2013-10-01 15:52:07 +04:00
|
|
|
FolderMan *folderMan = FolderMan::instance();
|
2015-07-03 11:59:44 +03:00
|
|
|
bool firstFolder = true;
|
|
|
|
bool singleSyncFolder = folderMan->map().size() == 1 && Theme::instance()->singleSyncFolder();
|
2016-03-01 18:07:11 +03:00
|
|
|
bool onePaused = false;
|
|
|
|
bool allPaused = true;
|
2015-07-03 11:59:44 +03:00
|
|
|
foreach (Folder *folder, folderMan->map()) {
|
2016-03-16 21:07:40 +03:00
|
|
|
if (folder->accountState() != accountState.data()) {
|
2015-07-03 11:59:44 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-03-01 18:07:11 +03:00
|
|
|
if (folder->syncPaused()) {
|
|
|
|
onePaused = true;
|
|
|
|
} else {
|
|
|
|
allPaused = false;
|
|
|
|
}
|
|
|
|
|
2015-07-03 11:59:44 +03:00
|
|
|
if (firstFolder && !singleSyncFolder) {
|
|
|
|
firstFolder = false;
|
|
|
|
menu->addSeparator();
|
|
|
|
menu->addAction(tr("Managed Folders:"))->setDisabled(true);
|
|
|
|
}
|
2013-10-01 15:52:07 +04:00
|
|
|
|
2017-11-20 13:47:48 +03:00
|
|
|
QAction *action = menu->addAction(tr("Open folder '%1'").arg(folder->shortGuiLocalPath()));
|
2017-09-20 17:49:41 +03:00
|
|
|
auto alias = folder->alias();
|
|
|
|
connect(action, &QAction::triggered, this, [this, alias] { this->slotFolderOpenAction(alias); });
|
2015-07-03 11:59:44 +03:00
|
|
|
}
|
2015-09-26 01:24:51 +03:00
|
|
|
|
|
|
|
menu->addSeparator();
|
|
|
|
if (separateMenu) {
|
2016-03-01 18:07:11 +03:00
|
|
|
if (onePaused) {
|
2018-08-29 17:49:50 +03:00
|
|
|
QAction *enable = menu->addAction(tr("Resume all folders"));
|
2016-03-01 18:07:11 +03:00
|
|
|
enable->setProperty(propertyAccountC, QVariant::fromValue(accountState));
|
2017-09-20 11:14:48 +03:00
|
|
|
connect(enable, &QAction::triggered, this, &ownCloudGui::slotUnpauseAllFolders);
|
2016-03-01 18:07:11 +03:00
|
|
|
}
|
|
|
|
if (!allPaused) {
|
|
|
|
QAction *enable = menu->addAction(tr("Pause all folders"));
|
|
|
|
enable->setProperty(propertyAccountC, QVariant::fromValue(accountState));
|
2017-09-20 11:14:48 +03:00
|
|
|
connect(enable, &QAction::triggered, this, &ownCloudGui::slotPauseAllFolders);
|
2015-09-26 01:24:51 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (accountState->isSignedOut()) {
|
|
|
|
QAction *signin = menu->addAction(tr("Log in..."));
|
|
|
|
signin->setProperty(propertyAccountC, QVariant::fromValue(accountState));
|
2017-09-20 11:14:48 +03:00
|
|
|
connect(signin, &QAction::triggered, this, &ownCloudGui::slotLogin);
|
2017-05-17 11:55:42 +03:00
|
|
|
} else {
|
2015-09-26 01:24:51 +03:00
|
|
|
QAction *signout = menu->addAction(tr("Log out"));
|
|
|
|
signout->setProperty(propertyAccountC, QVariant::fromValue(accountState));
|
2017-09-20 11:14:48 +03:00
|
|
|
connect(signout, &QAction::triggered, this, &ownCloudGui::slotLogout);
|
2017-05-17 11:55:42 +03:00
|
|
|
}
|
|
|
|
}
|
2015-07-03 11:59:44 +03:00
|
|
|
}
|
|
|
|
|
2016-09-13 15:34:22 +03:00
|
|
|
void ownCloudGui::slotContextMenuAboutToShow()
|
|
|
|
{
|
2018-06-14 15:35:06 +03:00
|
|
|
_contextMenuVisibleManual = true;
|
2016-10-06 18:18:51 +03:00
|
|
|
|
|
|
|
// Update icon in sys tray, as it might change depending on the context menu state
|
|
|
|
slotComputeOverallSyncStatus();
|
2018-06-14 15:35:06 +03:00
|
|
|
|
|
|
|
if (!_workaroundNoAboutToShowUpdate) {
|
|
|
|
updateContextMenu();
|
|
|
|
}
|
2016-09-13 15:34:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void ownCloudGui::slotContextMenuAboutToHide()
|
|
|
|
{
|
2018-06-14 15:35:06 +03:00
|
|
|
_contextMenuVisibleManual = false;
|
2016-10-06 18:18:51 +03:00
|
|
|
|
|
|
|
// Update icon in sys tray, as it might change depending on the context menu state
|
|
|
|
slotComputeOverallSyncStatus();
|
2016-09-23 11:44:54 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ownCloudGui::contextMenuVisible() const
|
|
|
|
{
|
2018-06-14 15:35:06 +03:00
|
|
|
// On some platforms isVisible doesn't work and always returns false,
|
|
|
|
// elsewhere aboutToHide is unreliable.
|
|
|
|
if (_workaroundManualVisibility)
|
|
|
|
return _contextMenuVisibleManual;
|
2016-09-23 11:44:54 +03:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-14 15:35:06 +03:00
|
|
|
static QByteArray envForceQDBusTrayWorkaround()
|
2016-09-23 11:44:54 +03:00
|
|
|
{
|
|
|
|
static QByteArray var = qgetenv("OWNCLOUD_FORCE_QDBUS_TRAY_WORKAROUND");
|
|
|
|
return var;
|
2016-09-13 15:34:22 +03:00
|
|
|
}
|
|
|
|
|
2018-06-14 15:35:06 +03:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-07-03 11:59:44 +03:00
|
|
|
void ownCloudGui::setupContextMenu()
|
|
|
|
{
|
2016-09-23 11:44:54 +03:00
|
|
|
if (_contextMenu) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
_contextMenu.reset(new QMenu());
|
|
|
|
_contextMenu->setTitle(Theme::instance()->appNameGUI());
|
|
|
|
|
|
|
|
_recentActionsMenu = new QMenu(tr("Recent Changes"), _contextMenu.data());
|
|
|
|
|
|
|
|
// this must be called only once after creating the context menu, or
|
|
|
|
// it will trigger a bug in Ubuntu's SNI bridge patch (11.10, 12.04).
|
|
|
|
_tray->setContextMenu(_contextMenu.data());
|
|
|
|
|
2016-06-23 11:22:43 +03:00
|
|
|
// 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()) {
|
2016-09-23 11:44:54 +03:00
|
|
|
_contextMenu->addAction(_actionQuit);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-06-14 15:35:06 +03:00
|
|
|
bool qdbusmenuWorkarounds = false;
|
|
|
|
|
2016-09-23 11:44:54 +03:00
|
|
|
// Enables workarounds for bugs introduced in Qt 5.5.0
|
|
|
|
// In particular QTBUG-47863 #3672 (tray menu fails to update and
|
|
|
|
// becomes unresponsive) and QTBUG-48068 #3722 (click signal is
|
|
|
|
// emitted several times)
|
|
|
|
// The Qt version check intentionally uses 5.0.0 (where platformMenu()
|
|
|
|
// was introduced) instead of 5.5.0 to avoid issues where the Qt
|
|
|
|
// version used to build is different from the one used at runtime.
|
|
|
|
// If we build with 5.6.1 or newer, we can skip this because the
|
|
|
|
// bugs should be fixed there.
|
|
|
|
#ifdef Q_OS_LINUX
|
|
|
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) && (QT_VERSION < QT_VERSION_CHECK(5, 6, 0))
|
|
|
|
if (qVersion() == QByteArray("5.5.0")) {
|
|
|
|
QObject *platformMenu = reinterpret_cast<QObject *>(_tray->contextMenu()->platformMenu());
|
|
|
|
if (platformMenu
|
|
|
|
&& platformMenu->metaObject()->className() == QLatin1String("QDBusPlatformMenu")) {
|
2018-06-14 15:35:06 +03:00
|
|
|
qdbusmenuWorkarounds = true;
|
2017-03-30 14:46:20 +03:00
|
|
|
qCWarning(lcApplication) << "Enabled QDBusPlatformMenu workaround";
|
2016-06-23 11:22:43 +03:00
|
|
|
}
|
2016-09-23 11:44:54 +03:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
2018-06-14 15:35:06 +03:00
|
|
|
auto applyEnvVariable = [](bool *sw, const QByteArray &value) {
|
|
|
|
if (value == "1")
|
|
|
|
*sw = true;
|
|
|
|
if (value == "0")
|
|
|
|
*sw = false;
|
|
|
|
};
|
|
|
|
|
|
|
|
applyEnvVariable(&qdbusmenuWorkarounds, envForceQDBusTrayWorkaround());
|
|
|
|
if (qdbusmenuWorkarounds) {
|
|
|
|
_workaroundFakeDoubleClick = true;
|
|
|
|
_workaroundNoAboutToShowUpdate = true;
|
|
|
|
_workaroundShowAndHideTray = true;
|
2016-09-23 11:44:54 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef Q_OS_MAC
|
2018-06-14 15:35:06 +03:00
|
|
|
// https://bugreports.qt.io/browse/QTBUG-54633
|
|
|
|
_workaroundNoAboutToShowUpdate = true;
|
|
|
|
_workaroundManualVisibility = true;
|
2016-09-23 11:44:54 +03:00
|
|
|
#endif
|
2018-06-14 15:35:06 +03:00
|
|
|
|
|
|
|
#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;
|
2016-09-23 11:44:54 +03:00
|
|
|
}
|
2018-06-14 15:35:06 +03:00
|
|
|
#endif
|
|
|
|
|
|
|
|
applyEnvVariable(&_workaroundNoAboutToShowUpdate, envForceWorkaroundNoAboutToShowUpdate());
|
|
|
|
applyEnvVariable(&_workaroundFakeDoubleClick, envForceWorkaroundFakeDoubleClick());
|
|
|
|
applyEnvVariable(&_workaroundShowAndHideTray, envForceWorkaroundShowAndHideTray());
|
|
|
|
applyEnvVariable(&_workaroundManualVisibility, envForceWorkaroundManualVisibility());
|
|
|
|
|
2018-06-18 10:41:24 +03:00
|
|
|
qCInfo(lcApplication) << "Tray menu workarounds:"
|
|
|
|
<< "noabouttoshow:" << _workaroundNoAboutToShowUpdate
|
|
|
|
<< "fakedoubleclick:" << _workaroundFakeDoubleClick
|
|
|
|
<< "showhide:" << _workaroundShowAndHideTray
|
|
|
|
<< "manualvisibility:" << _workaroundManualVisibility;
|
2018-06-14 15:35:06 +03:00
|
|
|
|
|
|
|
|
|
|
|
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()));
|
2016-09-23 11:44:54 +03:00
|
|
|
|
|
|
|
// Populate the context menu now.
|
|
|
|
updateContextMenu();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ownCloudGui::updateContextMenu()
|
|
|
|
{
|
|
|
|
if (minimalTrayMenu()) {
|
2016-06-23 11:22:43 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-06-14 15:35:06 +03:00
|
|
|
// 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) {
|
2016-09-23 11:44:54 +03:00
|
|
|
// 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()) {
|
2018-06-14 15:35:06 +03:00
|
|
|
if (!_delayedTrayUpdateTimer.isActive()) {
|
|
|
|
_delayedTrayUpdateTimer.start();
|
2016-09-23 11:44:54 +03:00
|
|
|
}
|
|
|
|
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();
|
|
|
|
|
2015-05-13 13:54:31 +03:00
|
|
|
auto accountList = AccountManager::instance()->accounts();
|
2013-11-23 03:14:02 +04:00
|
|
|
|
2015-05-13 13:54:31 +03:00
|
|
|
bool isConfigured = (!accountList.isEmpty());
|
2015-07-03 11:59:44 +03:00
|
|
|
bool atLeastOneConnected = false;
|
2016-03-01 18:07:11 +03:00
|
|
|
bool atLeastOnePaused = false;
|
|
|
|
bool atLeastOneNotPaused = false;
|
2015-05-13 13:54:31 +03:00
|
|
|
foreach (auto a, accountList) {
|
|
|
|
if (a->isConnected()) {
|
2015-07-03 11:59:44 +03:00
|
|
|
atLeastOneConnected = true;
|
2015-07-15 16:05:30 +03:00
|
|
|
}
|
2013-11-23 03:14:02 +04:00
|
|
|
}
|
2016-03-01 18:07:11 +03:00
|
|
|
foreach (auto f, FolderMan::instance()->map()) {
|
|
|
|
if (f->syncPaused()) {
|
|
|
|
atLeastOnePaused = true;
|
|
|
|
} else {
|
|
|
|
atLeastOneNotPaused = true;
|
|
|
|
}
|
|
|
|
}
|
2013-10-01 15:52:07 +04:00
|
|
|
|
2015-07-03 11:59:44 +03:00
|
|
|
if (accountList.count() > 1) {
|
|
|
|
foreach (AccountStatePtr account, accountList) {
|
|
|
|
QMenu *accountMenu = new QMenu(account->account()->displayName(), _contextMenu.data());
|
|
|
|
_accountMenus.append(accountMenu);
|
|
|
|
_contextMenu->addMenu(accountMenu);
|
2015-05-13 13:54:31 +03:00
|
|
|
|
2015-07-03 11:59:44 +03:00
|
|
|
addAccountContextMenu(account, accountMenu, true);
|
2018-08-21 15:54:10 +03:00
|
|
|
fetchNavigationApps(account);
|
2013-10-01 15:52:07 +04:00
|
|
|
}
|
2015-07-03 11:59:44 +03:00
|
|
|
} else if (accountList.count() == 1) {
|
|
|
|
addAccountContextMenu(accountList.first(), _contextMenu.data(), false);
|
2018-08-21 15:54:10 +03:00
|
|
|
fetchNavigationApps(accountList.first());
|
2013-10-01 15:52:07 +04:00
|
|
|
}
|
2015-07-03 11:59:44 +03:00
|
|
|
|
2013-10-01 15:52:07 +04:00
|
|
|
_contextMenu->addSeparator();
|
2013-11-23 03:14:02 +04:00
|
|
|
|
2017-10-06 12:54:16 +03:00
|
|
|
_contextMenu->addAction(_actionStatus);
|
2015-07-03 11:59:44 +03:00
|
|
|
if (isConfigured && atLeastOneConnected) {
|
2013-11-23 03:14:02 +04:00
|
|
|
_contextMenu->addMenu(_recentActionsMenu);
|
|
|
|
}
|
2017-10-06 12:54:16 +03:00
|
|
|
|
|
|
|
_contextMenu->addSeparator();
|
|
|
|
|
2016-11-18 14:17:05 +03:00
|
|
|
if (accountList.isEmpty()) {
|
|
|
|
_contextMenu->addAction(_actionNewAccountWizard);
|
|
|
|
}
|
2013-10-01 15:52:07 +04:00
|
|
|
_contextMenu->addAction(_actionSettings);
|
|
|
|
if (!Theme::instance()->helpUrl().isEmpty()) {
|
|
|
|
_contextMenu->addAction(_actionHelp);
|
|
|
|
}
|
2014-08-26 17:46:24 +04:00
|
|
|
|
|
|
|
if (_actionCrash) {
|
|
|
|
_contextMenu->addAction(_actionCrash);
|
|
|
|
}
|
|
|
|
|
2013-10-01 15:52:07 +04:00
|
|
|
_contextMenu->addSeparator();
|
2016-03-01 18:07:11 +03:00
|
|
|
if (atLeastOnePaused) {
|
|
|
|
QString text;
|
|
|
|
if (accountList.count() > 1) {
|
2018-08-29 17:49:50 +03:00
|
|
|
text = tr("Resume all synchronization");
|
2016-03-01 18:07:11 +03:00
|
|
|
} else {
|
2018-08-29 17:49:50 +03:00
|
|
|
text = tr("Resume synchronization");
|
2016-03-01 18:07:11 +03:00
|
|
|
}
|
|
|
|
QAction *action = _contextMenu->addAction(text);
|
2017-09-20 11:14:48 +03:00
|
|
|
connect(action, &QAction::triggered, this, &ownCloudGui::slotUnpauseAllFolders);
|
2016-03-01 18:07:11 +03:00
|
|
|
}
|
|
|
|
if (atLeastOneNotPaused) {
|
|
|
|
QString text;
|
|
|
|
if (accountList.count() > 1) {
|
|
|
|
text = tr("Pause all synchronization");
|
|
|
|
} else {
|
|
|
|
text = tr("Pause synchronization");
|
|
|
|
}
|
|
|
|
QAction *action = _contextMenu->addAction(text);
|
2017-09-20 11:14:48 +03:00
|
|
|
connect(action, &QAction::triggered, this, &ownCloudGui::slotPauseAllFolders);
|
2016-03-01 18:07:11 +03:00
|
|
|
}
|
2013-10-01 15:52:07 +04:00
|
|
|
_contextMenu->addAction(_actionQuit);
|
2015-08-21 10:41:24 +03:00
|
|
|
|
2018-06-14 15:35:06 +03:00
|
|
|
if (_workaroundShowAndHideTray) {
|
2015-09-04 12:58:50 +03:00
|
|
|
_tray->show();
|
|
|
|
}
|
2013-10-01 15:52:07 +04:00
|
|
|
}
|
|
|
|
|
2016-09-23 11:44:54 +03:00
|
|
|
void ownCloudGui::updateContextMenuNeeded()
|
2016-08-15 14:42:56 +03:00
|
|
|
{
|
2018-06-14 15:35:06 +03:00
|
|
|
// 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();
|
2016-09-23 11:44:54 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-06-14 15:35:06 +03:00
|
|
|
// 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;
|
2016-09-13 15:34:22 +03:00
|
|
|
}
|
2016-08-15 14:42:56 +03:00
|
|
|
}
|
2013-10-01 15:52:07 +04:00
|
|
|
|
|
|
|
void ownCloudGui::slotShowTrayMessage(const QString &title, const QString &msg)
|
|
|
|
{
|
|
|
|
if (_tray)
|
|
|
|
_tray->showMessage(title, msg);
|
|
|
|
else
|
2017-03-30 14:46:20 +03:00
|
|
|
qCWarning(lcApplication) << "Tray not ready: " << msg;
|
2013-10-01 15:52:07 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void ownCloudGui::slotShowOptionalTrayMessage(const QString &title, const QString &msg)
|
|
|
|
{
|
2018-02-15 22:21:08 +03:00
|
|
|
slotShowTrayMessage(title, msg);
|
2013-10-01 15:52:07 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2015-10-05 07:21:19 +03:00
|
|
|
* open the folder with the given Alias
|
2013-10-01 15:52:07 +04:00
|
|
|
*/
|
|
|
|
void ownCloudGui::slotFolderOpenAction(const QString &alias)
|
|
|
|
{
|
|
|
|
Folder *f = FolderMan::instance()->folder(alias);
|
|
|
|
if (f) {
|
2017-03-30 14:46:20 +03:00
|
|
|
qCInfo(lcApplication) << "opening local url " << f->path();
|
2014-06-20 13:26:41 +04:00
|
|
|
QUrl url = QUrl::fromLocalFile(f->path());
|
2013-10-01 15:52:07 +04:00
|
|
|
|
2013-12-03 19:23:49 +04:00
|
|
|
#ifdef Q_OS_WIN
|
2013-10-01 15:52:07 +04:00
|
|
|
// work around a bug in QDesktopServices on Win32, see i-net
|
|
|
|
QString filePath = f->path();
|
|
|
|
|
|
|
|
if (filePath.startsWith(QLatin1String("\\\\")) || filePath.startsWith(QLatin1String("//")))
|
2015-01-14 19:39:14 +03:00
|
|
|
url = QUrl::fromLocalFile(QDir::toNativeSeparators(filePath));
|
2013-10-01 15:52:07 +04:00
|
|
|
else
|
|
|
|
url = QUrl::fromLocalFile(filePath);
|
|
|
|
#endif
|
|
|
|
QDesktopServices::openUrl(url);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ownCloudGui::setupActions()
|
|
|
|
{
|
|
|
|
_actionStatus = new QAction(tr("Unknown status"), this);
|
|
|
|
_actionStatus->setEnabled(false);
|
|
|
|
_actionSettings = new QAction(tr("Settings..."), this);
|
2016-11-18 14:17:05 +03:00
|
|
|
_actionNewAccountWizard = new QAction(tr("New account..."), this);
|
2013-10-01 15:52:07 +04:00
|
|
|
_actionRecent = new QAction(tr("Details..."), this);
|
|
|
|
_actionRecent->setEnabled(true);
|
|
|
|
|
2017-09-20 11:14:48 +03:00
|
|
|
QObject::connect(_actionRecent, &QAction::triggered, this, &ownCloudGui::slotShowSyncProtocol);
|
|
|
|
QObject::connect(_actionSettings, &QAction::triggered, this, &ownCloudGui::slotShowSettings);
|
|
|
|
QObject::connect(_actionNewAccountWizard, &QAction::triggered, this, &ownCloudGui::slotNewAccountWizard);
|
2013-10-01 15:52:07 +04:00
|
|
|
_actionHelp = new QAction(tr("Help"), this);
|
2017-09-20 11:14:48 +03:00
|
|
|
QObject::connect(_actionHelp, &QAction::triggered, this, &ownCloudGui::slotHelp);
|
2013-10-01 15:52:07 +04:00
|
|
|
_actionQuit = new QAction(tr("Quit %1").arg(Theme::instance()->appNameGUI()), this);
|
|
|
|
QObject::connect(_actionQuit, SIGNAL(triggered(bool)), _app, SLOT(quit()));
|
|
|
|
|
2014-08-26 17:46:24 +04:00
|
|
|
if (_app->debugMode()) {
|
2015-02-17 16:02:42 +03:00
|
|
|
_actionCrash = new QAction(tr("Crash now", "Only shows in debug mode to allow testing the crash handler"), this);
|
2017-09-20 12:48:13 +03:00
|
|
|
connect(_actionCrash, &QAction::triggered, _app, &Application::slotCrash);
|
2014-08-26 17:46:24 +04:00
|
|
|
} else {
|
|
|
|
_actionCrash = 0;
|
|
|
|
}
|
2013-10-01 15:52:07 +04:00
|
|
|
}
|
|
|
|
|
2018-04-10 23:51:47 +03:00
|
|
|
void ownCloudGui::slotEtagResponseHeaderReceived(const QByteArray &value, int statusCode){
|
|
|
|
if(statusCode == 200){
|
2018-05-07 19:19:29 +03:00
|
|
|
qCDebug(lcApplication) << "New navigation apps ETag Response Header received " << value;
|
2018-04-10 23:51:47 +03:00
|
|
|
auto account = qvariant_cast<AccountStatePtr>(sender()->property(propertyAccountC));
|
|
|
|
account->setNavigationAppsEtagResponseHeader(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-21 15:54:10 +03:00
|
|
|
void ownCloudGui::fetchNavigationApps(AccountStatePtr account){
|
2018-02-21 20:49:12 +03:00
|
|
|
OcsNavigationAppsJob *job = new OcsNavigationAppsJob(account->account());
|
2018-04-10 23:51:47 +03:00
|
|
|
job->setProperty(propertyAccountC, QVariant::fromValue(account));
|
|
|
|
job->addRawHeader("If-None-Match", account->navigationAppsEtagResponseHeader());
|
2018-02-21 20:49:12 +03:00
|
|
|
connect(job, &OcsNavigationAppsJob::appsJobFinished, this, &ownCloudGui::slotNavigationAppsFetched);
|
2018-04-10 23:51:47 +03:00
|
|
|
connect(job, &OcsNavigationAppsJob::etagResponseHeaderReceived, this, &ownCloudGui::slotEtagResponseHeaderReceived);
|
2018-02-21 20:49:12 +03:00
|
|
|
connect(job, &OcsNavigationAppsJob::ocsError, this, &ownCloudGui::slotOcsError);
|
|
|
|
job->getNavigationApps();
|
2018-01-26 15:50:47 +03:00
|
|
|
}
|
|
|
|
|
2018-04-11 16:20:41 +03:00
|
|
|
void ownCloudGui::buildNavigationAppsMenu(AccountStatePtr account, QMenu *accountMenu){
|
|
|
|
auto navLinks = _navApps.value(account);
|
|
|
|
if(navLinks.size() > 0){
|
|
|
|
|
|
|
|
// when there is only one account add the nav links above the settings
|
|
|
|
QAction *actionBefore = _actionSettings;
|
|
|
|
|
|
|
|
// when there is more than one account add the nav links above pause/unpause folder or logout action
|
|
|
|
if(AccountManager::instance()->accounts().size() > 1){
|
|
|
|
foreach(QAction *action, accountMenu->actions()){
|
|
|
|
|
|
|
|
// pause/unpause folder and logout actions have propertyAccountC
|
|
|
|
if(auto actionAccount = qvariant_cast<AccountStatePtr>(action->property(propertyAccountC))){
|
|
|
|
if(actionAccount == account){
|
|
|
|
actionBefore = action;
|
|
|
|
break;
|
2018-02-21 20:49:12 +03:00
|
|
|
}
|
2018-02-20 21:41:08 +03:00
|
|
|
}
|
2018-01-26 15:50:47 +03:00
|
|
|
}
|
|
|
|
}
|
2018-04-10 23:51:47 +03:00
|
|
|
|
2018-04-11 16:20:41 +03:00
|
|
|
// Create submenu with links
|
|
|
|
QMenu *navLinksMenu = new QMenu(tr("Apps"));
|
|
|
|
accountMenu->insertSeparator(actionBefore);
|
|
|
|
accountMenu->insertMenu(actionBefore, navLinksMenu);
|
|
|
|
foreach (const QJsonValue &value, navLinks) {
|
|
|
|
auto navLink = value.toObject();
|
|
|
|
QAction *action = new QAction(navLink.value("name").toString(), this);
|
|
|
|
QUrl href(navLink.value("href").toString());
|
|
|
|
connect(action, &QAction::triggered, this, [href] { QDesktopServices::openUrl(href); });
|
|
|
|
navLinksMenu->addAction(action);
|
|
|
|
}
|
|
|
|
accountMenu->insertSeparator(actionBefore);
|
2018-01-26 15:50:47 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-10 23:51:47 +03:00
|
|
|
void ownCloudGui::slotNavigationAppsFetched(const QJsonDocument &reply, int statusCode)
|
|
|
|
{
|
2018-08-01 01:06:17 +03:00
|
|
|
if(auto account = qvariant_cast<AccountStatePtr>(sender()->property(propertyAccountC))){
|
|
|
|
if (statusCode == 304) {
|
|
|
|
qCWarning(lcApplication) << "Status code " << statusCode << " Not Modified - No new navigation apps.";
|
|
|
|
} else {
|
|
|
|
if(!reply.isEmpty()){
|
|
|
|
auto element = reply.object().value("ocs").toObject().value("data");
|
|
|
|
auto navLinks = element.toArray();
|
2018-04-10 23:51:47 +03:00
|
|
|
_navApps.insert(account, navLinks);
|
|
|
|
}
|
2018-08-01 01:06:17 +03:00
|
|
|
}
|
2018-04-10 23:51:47 +03:00
|
|
|
|
2018-08-21 15:54:10 +03:00
|
|
|
// TODO see pull #523
|
|
|
|
auto accountList = AccountManager::instance()->accounts();
|
|
|
|
if(accountList.size() > 1){
|
|
|
|
// the list of apps will be displayed under the account that it belongs to
|
|
|
|
foreach (QMenu *accountMenu, _accountMenus) {
|
|
|
|
if(accountMenu->title() == account->account()->displayName()){
|
|
|
|
buildNavigationAppsMenu(account, accountMenu);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if(accountList.size() == 1){
|
|
|
|
buildNavigationAppsMenu(account, _contextMenu.data());
|
2018-08-01 01:06:17 +03:00
|
|
|
}
|
|
|
|
}
|
2018-04-10 23:51:47 +03:00
|
|
|
}
|
|
|
|
|
2018-01-19 22:53:45 +03:00
|
|
|
void ownCloudGui::slotOcsError(int statusCode, const QString &message)
|
|
|
|
{
|
|
|
|
emit serverError(statusCode, message);
|
|
|
|
}
|
|
|
|
|
2013-10-02 17:28:33 +04:00
|
|
|
void ownCloudGui::slotRebuildRecentMenus()
|
2013-10-01 15:52:07 +04:00
|
|
|
{
|
|
|
|
_recentActionsMenu->clear();
|
2014-03-20 17:43:10 +04:00
|
|
|
if (!_recentItemsActions.isEmpty()) {
|
|
|
|
foreach (QAction *a, _recentItemsActions) {
|
|
|
|
_recentActionsMenu->addAction(a);
|
2013-10-01 15:52:07 +04:00
|
|
|
}
|
2014-03-20 17:43:10 +04:00
|
|
|
_recentActionsMenu->addSeparator();
|
|
|
|
} else {
|
|
|
|
_recentActionsMenu->addAction(tr("No items synced recently"))->setEnabled(false);
|
|
|
|
}
|
2013-10-01 15:52:07 +04:00
|
|
|
// add a more... entry.
|
|
|
|
_recentActionsMenu->addAction(_actionRecent);
|
|
|
|
}
|
|
|
|
|
2015-11-11 13:19:04 +03:00
|
|
|
/// 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;
|
|
|
|
}
|
|
|
|
|
2013-10-01 15:52:07 +04:00
|
|
|
|
2015-01-30 15:36:20 +03:00
|
|
|
void ownCloudGui::slotUpdateProgress(const QString &folder, const ProgressInfo &progress)
|
2013-10-01 15:52:07 +04:00
|
|
|
{
|
|
|
|
Q_UNUSED(folder);
|
|
|
|
|
2017-07-11 13:52:40 +03:00
|
|
|
if (progress.status() == ProgressInfo::Discovery) {
|
2018-02-21 11:39:55 +03:00
|
|
|
if (!progress._currentDiscoveredRemoteFolder.isEmpty()) {
|
|
|
|
_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));
|
2017-07-11 13:52:40 +03:00
|
|
|
}
|
|
|
|
} else if (progress.status() == ProgressInfo::Done) {
|
2017-10-06 12:54:16 +03:00
|
|
|
QTimer::singleShot(2000, this, &ownCloudGui::slotComputeOverallSyncStatus);
|
2017-07-11 13:52:40 +03:00
|
|
|
}
|
|
|
|
if (progress.status() != ProgressInfo::Propagation) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (progress.totalSize() == 0) {
|
2015-01-30 15:36:20 +03:00
|
|
|
quint64 currentFile = progress.currentFile();
|
|
|
|
quint64 totalFileCount = qMax(progress.totalFiles(), currentFile);
|
2016-08-15 14:36:53 +03:00
|
|
|
QString msg;
|
|
|
|
if (progress.trustEta()) {
|
|
|
|
msg = tr("Syncing %1 of %2 (%3 left)")
|
|
|
|
.arg(currentFile)
|
|
|
|
.arg(totalFileCount)
|
|
|
|
.arg(Utility::durationToDescriptiveString2(progress.totalProgress().estimatedEta));
|
|
|
|
} else {
|
|
|
|
msg = tr("Syncing %1 of %2")
|
|
|
|
.arg(currentFile)
|
|
|
|
.arg(totalFileCount);
|
|
|
|
}
|
|
|
|
_actionStatus->setText(msg);
|
2014-12-11 13:32:05 +03:00
|
|
|
} else {
|
2015-01-30 15:36:20 +03:00
|
|
|
QString totalSizeStr = Utility::octetsToString(progress.totalSize());
|
2016-08-15 14:36:53 +03:00
|
|
|
QString msg;
|
|
|
|
if (progress.trustEta()) {
|
|
|
|
msg = tr("Syncing %1 (%2 left)")
|
|
|
|
.arg(totalSizeStr, Utility::durationToDescriptiveString2(progress.totalProgress().estimatedEta));
|
|
|
|
} else {
|
|
|
|
msg = tr("Syncing %1")
|
|
|
|
.arg(totalSizeStr);
|
|
|
|
}
|
|
|
|
_actionStatus->setText(msg);
|
2014-12-11 13:32:05 +03:00
|
|
|
}
|
2014-05-12 18:36:27 +04:00
|
|
|
|
2014-03-20 17:43:10 +04:00
|
|
|
_actionRecent->setIcon(QIcon()); // Fixme: Set a "in-progress"-item eventually.
|
2014-03-14 16:03:16 +04:00
|
|
|
|
2015-11-11 13:19:04 +03:00
|
|
|
if (!progress._lastCompletedItem.isEmpty()
|
|
|
|
&& shouldShowInRecentsMenu(progress._lastCompletedItem)) {
|
2014-03-14 20:18:26 +04:00
|
|
|
if (Progress::isWarningKind(progress._lastCompletedItem._status)) {
|
2015-10-05 07:21:19 +03:00
|
|
|
// display a warn icon if warnings happened.
|
2015-02-12 21:44:30 +03:00
|
|
|
QIcon warnIcon(":/client/resources/warning");
|
2014-03-14 20:18:26 +04:00
|
|
|
_actionRecent->setIcon(warnIcon);
|
|
|
|
}
|
|
|
|
|
2014-03-20 17:43:10 +04:00
|
|
|
QString kindStr = Progress::asResultString(progress._lastCompletedItem);
|
|
|
|
QString timeStr = QTime::currentTime().toString("hh:mm");
|
|
|
|
QString actionText = tr("%1 (%2, %3)").arg(progress._lastCompletedItem._file, kindStr, timeStr);
|
|
|
|
QAction *action = new QAction(actionText, this);
|
|
|
|
Folder *f = FolderMan::instance()->folder(folder);
|
|
|
|
if (f) {
|
|
|
|
QString fullPath = f->path() + '/' + progress._lastCompletedItem._file;
|
|
|
|
if (QFile(fullPath).exists()) {
|
2017-09-20 17:49:41 +03:00
|
|
|
connect(action, &QAction::triggered, this, [this, fullPath] { this->slotOpenPath(fullPath); });
|
2014-03-20 17:43:10 +04:00
|
|
|
} else {
|
|
|
|
action->setEnabled(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (_recentItemsActions.length() > 5) {
|
|
|
|
_recentItemsActions.takeFirst()->deleteLater();
|
|
|
|
}
|
|
|
|
_recentItemsActions.append(action);
|
|
|
|
|
2016-08-15 14:42:56 +03:00
|
|
|
// Update the "Recent" menu if the context menu is being shown,
|
|
|
|
// otherwise it'll be updated later, when the context menu is opened.
|
2016-09-23 11:44:54 +03:00
|
|
|
if (updateWhileVisible() && contextMenuVisible()) {
|
2016-08-15 14:42:56 +03:00
|
|
|
slotRebuildRecentMenus();
|
|
|
|
}
|
2014-03-20 17:43:10 +04:00
|
|
|
}
|
2013-10-01 15:52:07 +04:00
|
|
|
}
|
|
|
|
|
2015-07-03 11:59:44 +03:00
|
|
|
void ownCloudGui::slotLogin()
|
|
|
|
{
|
|
|
|
if (auto account = qvariant_cast<AccountStatePtr>(sender()->property(propertyAccountC))) {
|
2017-06-13 14:49:26 +03:00
|
|
|
account->account()->resetRejectedCertificates();
|
2015-12-09 13:06:28 +03:00
|
|
|
account->signIn();
|
2015-07-03 11:59:44 +03:00
|
|
|
} else {
|
2016-03-01 18:07:11 +03:00
|
|
|
auto list = AccountManager::instance()->accounts();
|
2015-07-03 11:59:44 +03:00
|
|
|
foreach (const auto &a, list) {
|
2015-12-09 13:06:28 +03:00
|
|
|
a->signIn();
|
2015-07-03 11:59:44 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ownCloudGui::slotLogout()
|
|
|
|
{
|
|
|
|
auto list = AccountManager::instance()->accounts();
|
|
|
|
if (auto account = qvariant_cast<AccountStatePtr>(sender()->property(propertyAccountC))) {
|
|
|
|
list.clear();
|
|
|
|
list.append(account);
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach (const auto &ai, list) {
|
2015-12-09 13:06:28 +03:00
|
|
|
ai->signOutByUi();
|
2015-07-03 11:59:44 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-01 18:07:11 +03:00
|
|
|
void ownCloudGui::slotUnpauseAllFolders()
|
|
|
|
{
|
|
|
|
setPauseOnAllFoldersHelper(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ownCloudGui::slotPauseAllFolders()
|
|
|
|
{
|
|
|
|
setPauseOnAllFoldersHelper(true);
|
|
|
|
}
|
|
|
|
|
2016-11-18 14:17:05 +03:00
|
|
|
void ownCloudGui::slotNewAccountWizard()
|
|
|
|
{
|
|
|
|
OwncloudSetupWizard::runWizard(qApp, SLOT(slotownCloudWizardDone(int)));
|
|
|
|
}
|
|
|
|
|
2016-03-01 18:07:11 +03:00
|
|
|
void ownCloudGui::setPauseOnAllFoldersHelper(bool pause)
|
|
|
|
{
|
|
|
|
QList<AccountState *> accounts;
|
|
|
|
if (auto account = qvariant_cast<AccountStatePtr>(sender()->property(propertyAccountC))) {
|
|
|
|
accounts.append(account.data());
|
|
|
|
} else {
|
|
|
|
foreach (auto a, AccountManager::instance()->accounts()) {
|
|
|
|
accounts.append(a.data());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
foreach (Folder *f, FolderMan::instance()->map()) {
|
|
|
|
if (accounts.contains(f->accountState())) {
|
|
|
|
f->setSyncPaused(pause);
|
2016-11-07 14:49:29 +03:00
|
|
|
if (pause) {
|
|
|
|
f->slotTerminateSync();
|
|
|
|
}
|
2016-03-01 18:07:11 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-01 15:52:07 +04:00
|
|
|
void ownCloudGui::slotShowGuiMessage(const QString &title, const QString &message)
|
|
|
|
{
|
|
|
|
QMessageBox *msgBox = new QMessageBox;
|
2017-02-20 15:58:35 +03:00
|
|
|
msgBox->setWindowFlags(msgBox->windowFlags() | Qt::WindowStaysOnTopHint);
|
2013-10-01 15:52:07 +04:00
|
|
|
msgBox->setAttribute(Qt::WA_DeleteOnClose);
|
|
|
|
msgBox->setText(message);
|
|
|
|
msgBox->setWindowTitle(title);
|
|
|
|
msgBox->setIcon(QMessageBox::Information);
|
|
|
|
msgBox->open();
|
|
|
|
}
|
|
|
|
|
2013-11-26 06:15:03 +04:00
|
|
|
void ownCloudGui::slotShowSettings()
|
2013-10-01 15:52:07 +04:00
|
|
|
{
|
|
|
|
if (_settingsDialog.isNull()) {
|
2014-02-14 06:02:59 +04:00
|
|
|
_settingsDialog =
|
|
|
|
#if defined(Q_OS_MAC)
|
|
|
|
new SettingsDialogMac(this);
|
|
|
|
#else
|
|
|
|
new SettingsDialog(this);
|
|
|
|
#endif
|
2013-10-01 15:52:07 +04:00
|
|
|
_settingsDialog->setAttribute(Qt::WA_DeleteOnClose, true);
|
|
|
|
_settingsDialog->show();
|
|
|
|
}
|
2014-07-07 17:20:37 +04:00
|
|
|
raiseDialog(_settingsDialog.data());
|
2013-10-01 15:52:07 +04:00
|
|
|
}
|
|
|
|
|
2013-11-29 14:18:59 +04:00
|
|
|
void ownCloudGui::slotShowSyncProtocol()
|
|
|
|
{
|
|
|
|
slotShowSettings();
|
2018-03-26 22:02:03 +03:00
|
|
|
//_settingsDialog->showActivityPage();
|
2013-11-29 14:18:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-10-02 17:28:33 +04:00
|
|
|
void ownCloudGui::slotShutdown()
|
2013-10-01 15:52:07 +04:00
|
|
|
{
|
2015-04-27 18:14:25 +03:00
|
|
|
// explicitly close windows. This is somewhat of a hack to ensure
|
|
|
|
// that saving the geometries happens ASAP during a OS shutdown
|
|
|
|
|
2013-10-01 15:52:07 +04:00
|
|
|
// those do delete on close
|
|
|
|
if (!_settingsDialog.isNull())
|
|
|
|
_settingsDialog->close();
|
2013-10-02 17:28:33 +04:00
|
|
|
if (!_logBrowser.isNull())
|
|
|
|
_logBrowser->deleteLater();
|
2013-10-01 15:52:07 +04:00
|
|
|
}
|
|
|
|
|
2013-10-02 17:28:33 +04:00
|
|
|
void ownCloudGui::slotToggleLogBrowser()
|
|
|
|
{
|
|
|
|
if (_logBrowser.isNull()) {
|
|
|
|
// init the log browser.
|
|
|
|
_logBrowser = new LogBrowser;
|
|
|
|
// ## TODO: allow new log name maybe?
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_logBrowser->isVisible()) {
|
|
|
|
_logBrowser->hide();
|
|
|
|
} else {
|
2014-07-07 17:20:37 +04:00
|
|
|
raiseDialog(_logBrowser);
|
2013-10-02 17:28:33 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ownCloudGui::slotOpenOwnCloud()
|
|
|
|
{
|
2015-05-13 13:54:31 +03:00
|
|
|
if (auto account = qvariant_cast<AccountPtr>(sender()->property(propertyAccountC))) {
|
|
|
|
QDesktopServices::openUrl(account->url());
|
2013-10-30 19:31:47 +04:00
|
|
|
}
|
2013-10-02 17:28:33 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void ownCloudGui::slotHelp()
|
|
|
|
{
|
|
|
|
QDesktopServices::openUrl(QUrl(Theme::instance()->helpUrl()));
|
|
|
|
}
|
|
|
|
|
2014-07-07 17:20:37 +04:00
|
|
|
void ownCloudGui::raiseDialog(QWidget *raiseWidget)
|
|
|
|
{
|
|
|
|
if (raiseWidget && raiseWidget->parentWidget() == 0) {
|
|
|
|
// Qt has a bug which causes parent-less dialogs to pop-under.
|
|
|
|
raiseWidget->showNormal();
|
|
|
|
raiseWidget->raise();
|
|
|
|
raiseWidget->activateWindow();
|
2014-08-12 16:47:43 +04:00
|
|
|
|
|
|
|
#if defined(Q_OS_MAC)
|
|
|
|
// viel hilft viel ;-)
|
|
|
|
MacWindow::bringToFront(raiseWidget);
|
2014-08-28 19:23:44 +04:00
|
|
|
#endif
|
|
|
|
#if defined(Q_OS_X11)
|
|
|
|
WId wid = widget->winId();
|
|
|
|
NETWM::init();
|
|
|
|
|
|
|
|
XEvent e;
|
|
|
|
e.xclient.type = ClientMessage;
|
|
|
|
e.xclient.message_type = NETWM::NET_ACTIVE_WINDOW;
|
|
|
|
e.xclient.display = QX11Info::display();
|
|
|
|
e.xclient.window = wid;
|
|
|
|
e.xclient.format = 32;
|
|
|
|
e.xclient.data.l[0] = 2;
|
|
|
|
e.xclient.data.l[1] = QX11Info::appTime();
|
|
|
|
e.xclient.data.l[2] = 0;
|
|
|
|
e.xclient.data.l[3] = 0l;
|
|
|
|
e.xclient.data.l[4] = 0l;
|
2014-09-06 00:07:54 +04:00
|
|
|
Display *display = QX11Info::display();
|
|
|
|
XSendEvent(display,
|
|
|
|
RootWindow(display, DefaultScreen(display)),
|
|
|
|
False, // propagate
|
|
|
|
SubstructureRedirectMask | SubstructureNotifyMask,
|
|
|
|
&e);
|
2014-08-12 16:47:43 +04:00
|
|
|
#endif
|
2014-07-07 17:20:37 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-02 17:28:33 +04:00
|
|
|
|
2018-04-06 18:13:29 +03:00
|
|
|
void ownCloudGui::slotShowShareDialog(const QString &sharePath, const QString &localPath, ShareDialogStartPage startPage)
|
2015-01-13 15:50:41 +03:00
|
|
|
{
|
2015-04-23 15:14:28 +03:00
|
|
|
const auto folder = FolderMan::instance()->folderForPath(localPath);
|
|
|
|
if (!folder) {
|
2017-03-30 14:46:20 +03:00
|
|
|
qCWarning(lcApplication) << "Could not open share dialog for" << localPath << "no responsible folder found";
|
2015-01-28 12:52:55 +03:00
|
|
|
return;
|
|
|
|
}
|
2015-09-16 18:17:00 +03:00
|
|
|
|
|
|
|
// For https://github.com/owncloud/client/issues/3783
|
|
|
|
_settingsDialog->hide();
|
|
|
|
|
2015-04-23 15:14:28 +03:00
|
|
|
const auto accountState = folder->accountState();
|
2015-01-28 12:52:55 +03:00
|
|
|
|
2017-05-10 10:37:10 +03:00
|
|
|
const QString file = localPath.mid(folder->cleanPath().length() + 1);
|
2017-09-13 20:02:38 +03:00
|
|
|
SyncJournalFileRecord fileRecord;
|
2017-05-10 10:37:10 +03:00
|
|
|
|
|
|
|
bool resharingAllowed = true; // lets assume the good
|
2017-09-13 20:02:38 +03:00
|
|
|
if (folder->journalDb()->getFileRecord(file, &fileRecord) && fileRecord.isValid()) {
|
2017-05-10 10:37:10 +03:00
|
|
|
// check the permission: Is resharing allowed?
|
2017-09-19 11:53:51 +03:00
|
|
|
if (!fileRecord._remotePerm.isNull() && !fileRecord._remotePerm.hasPermission(RemotePermissions::CanReshare)) {
|
2017-05-10 10:37:10 +03:00
|
|
|
resharingAllowed = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-30 12:33:34 +03:00
|
|
|
// As a first approximation, set the set of permissions that can be granted
|
|
|
|
// either to everything (resharing allowed) or nothing (no resharing).
|
|
|
|
//
|
|
|
|
// The correct value will be found with a propfind from ShareDialog.
|
|
|
|
// (we want to show the dialog directly, not wait for the propfind first)
|
|
|
|
SharePermissions maxSharingPermissions =
|
|
|
|
SharePermissionRead
|
|
|
|
| SharePermissionUpdate | SharePermissionCreate | SharePermissionDelete
|
|
|
|
| SharePermissionShare;
|
|
|
|
if (!resharingAllowed) {
|
|
|
|
maxSharingPermissions = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-01-20 15:17:54 +03:00
|
|
|
ShareDialog *w = 0;
|
|
|
|
if (_shareDialogs.contains(localPath) && _shareDialogs[localPath]) {
|
2017-03-30 14:46:20 +03:00
|
|
|
qCInfo(lcApplication) << "Raising share dialog" << sharePath << localPath;
|
2016-01-20 15:17:54 +03:00
|
|
|
w = _shareDialogs[localPath];
|
|
|
|
} else {
|
2017-03-30 14:46:20 +03:00
|
|
|
qCInfo(lcApplication) << "Opening share dialog" << sharePath << localPath << maxSharingPermissions;
|
2018-04-06 18:13:29 +03:00
|
|
|
w = new ShareDialog(accountState, sharePath, localPath, maxSharingPermissions, fileRecord.numericFileId(), startPage);
|
2016-01-20 15:17:54 +03:00
|
|
|
w->setAttribute(Qt::WA_DeleteOnClose, true);
|
|
|
|
|
|
|
|
_shareDialogs[localPath] = w;
|
2017-09-20 11:14:48 +03:00
|
|
|
connect(w, &QObject::destroyed, this, &ownCloudGui::slotRemoveDestroyedShareDialogs);
|
2016-01-20 15:17:54 +03:00
|
|
|
}
|
2015-02-16 18:46:05 +03:00
|
|
|
raiseDialog(w);
|
2015-01-13 15:50:41 +03:00
|
|
|
}
|
|
|
|
|
2016-01-20 15:17:54 +03:00
|
|
|
void ownCloudGui::slotRemoveDestroyedShareDialogs()
|
|
|
|
{
|
|
|
|
QMutableMapIterator<QString, QPointer<ShareDialog>> it(_shareDialogs);
|
|
|
|
while (it.hasNext()) {
|
|
|
|
it.next();
|
|
|
|
if (!it.value() || it.value() == sender()) {
|
|
|
|
it.remove();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-13 15:50:41 +03:00
|
|
|
|
2013-10-01 15:52:07 +04:00
|
|
|
} // end namespace
|