nextcloud-desktop/src/gui/settingsdialog.cpp

383 lines
12 KiB
C++
Raw Normal View History

/*
* Copyright (C) by Daniel Molkentin <danimo@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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "settingsdialog.h"
#include "ui_settingsdialog.h"
#include "folderman.h"
#include "theme.h"
#include "generalsettings.h"
#include "networksettings.h"
#include "accountsettings.h"
2014-11-10 01:25:57 +03:00
#include "configfile.h"
#include "progressdispatcher.h"
#include "owncloudgui.h"
#include "activitywidget.h"
2015-04-17 18:56:17 +03:00
#include "accountmanager.h"
#include "protocolwidget.h"
#include <QLabel>
#include <QStandardItemModel>
#include <QStackedWidget>
#include <QPushButton>
#include <QSettings>
#include <QToolBar>
2015-08-10 11:50:57 +03:00
#include <QToolButton>
#include <QLayout>
2015-08-10 11:50:57 +03:00
#include <QVBoxLayout>
#include <QPixmap>
#include <QImage>
#include <QWidgetAction>
#include <QPainter>
#include <QPainterPath>
namespace {
2017-05-17 11:55:42 +03:00
const char TOOLBAR_CSS[] =
2015-08-11 09:43:36 +03:00
"QToolBar { background: %1; margin: 0; padding: 0; border: none; border-bottom: 1px solid %2; spacing: 0; } "
"QToolBar QToolButton { background: %1; border: none; border-bottom: 1px solid %2; margin: 0; padding: 5px; } "
"QToolBar QToolBarExtension { padding:0; } "
"QToolBar QToolButton:checked { background: %3; color: %4; }";
2017-05-17 11:55:42 +03:00
static const float buttonSizeRatio = 1.618; // golden ratio
}
2014-11-10 00:34:07 +03:00
namespace OCC {
2017-05-17 11:55:42 +03:00
static QIcon circleMask(const QImage &avatar)
{
int dim = avatar.width();
QPixmap fixedImage(dim, dim);
fixedImage.fill(Qt::transparent);
QPainter imgPainter(&fixedImage);
QPainterPath clip;
clip.addEllipse(0, 0, dim, dim);
imgPainter.setClipPath(clip);
imgPainter.drawImage(0, 0, avatar);
imgPainter.end();
return QIcon(fixedImage);
}
//
// Whenever you change something here check both settingsdialog.cpp and settingsdialogmac.cpp !
//
2017-05-17 11:55:42 +03:00
SettingsDialog::SettingsDialog(ownCloudGui *gui, QWidget *parent)
: QDialog(parent)
, _ui(new Ui::SettingsDialog)
, _gui(gui)
{
ConfigFile cfg;
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
_ui->setupUi(this);
_toolBar = new QToolBar;
_toolBar->setIconSize(QSize(32, 32));
_toolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
layout()->setMenuBar(_toolBar);
// People perceive this as a Window, so also make Ctrl+W work
QAction *closeWindowAction = new QAction(this);
closeWindowAction->setShortcut(QKeySequence("Ctrl+W"));
connect(closeWindowAction, SIGNAL(triggered()), SLOT(accept()));
addAction(closeWindowAction);
setObjectName("Settings"); // required as group for saveGeometry call
setWindowTitle(Theme::instance()->appNameGUI());
_actionGroup = new QActionGroup(this);
_actionGroup->setExclusive(true);
// Note: all the actions have a '\n' because the account name is in two lines and
// all buttons must have the same size in order to keep a good layout
_activityAction = createColorAwareAction(QLatin1String(":/client/resources/activity.png"), tr("Activity"));
_actionGroup->addAction(_activityAction);
_toolBar->addAction(_activityAction);
_activitySettings = new ActivitySettings;
_ui->stack->addWidget(_activitySettings);
2017-05-17 11:55:42 +03:00
connect(_activitySettings, SIGNAL(guiLog(QString, QString)), _gui,
SLOT(slotShowOptionalTrayMessage(QString, QString)));
_activitySettings->setNotificationRefreshInterval(cfg.notificationRefreshInterval());
QAction *generalAction = createColorAwareAction(QLatin1String(":/client/resources/settings.png"), tr("General"));
_actionGroup->addAction(generalAction);
_toolBar->addAction(generalAction);
GeneralSettings *generalSettings = new GeneralSettings;
_ui->stack->addWidget(generalSettings);
QAction *networkAction = createColorAwareAction(QLatin1String(":/client/resources/network.png"), tr("Network"));
_actionGroup->addAction(networkAction);
_toolBar->addAction(networkAction);
NetworkSettings *networkSettings = new NetworkSettings;
_ui->stack->addWidget(networkSettings);
_actionGroupWidgets.insert(_activityAction, _activitySettings);
_actionGroupWidgets.insert(generalAction, generalSettings);
_actionGroupWidgets.insert(networkAction, networkSettings);
2017-05-17 11:55:42 +03:00
connect(_actionGroup, SIGNAL(triggered(QAction *)), SLOT(slotSwitchPage(QAction *)));
2017-05-17 11:55:42 +03:00
connect(AccountManager::instance(), SIGNAL(accountAdded(AccountState *)),
this, SLOT(accountAdded(AccountState *)));
connect(AccountManager::instance(), SIGNAL(accountRemoved(AccountState *)),
this, SLOT(accountRemoved(AccountState *)));
foreach (auto ai, AccountManager::instance()->accounts()) {
2015-04-17 18:56:17 +03:00
accountAdded(ai.data());
}
QTimer::singleShot(1, this, SLOT(showFirstPage()));
QPushButton *closeButton = _ui->buttonBox->button(QDialogButtonBox::Close);
connect(closeButton, SIGNAL(clicked()), SLOT(accept()));
QAction *showLogWindow = new QAction(this);
showLogWindow->setShortcut(QKeySequence("F12"));
connect(showLogWindow, SIGNAL(triggered()), gui, SLOT(slotToggleLogBrowser()));
addAction(showLogWindow);
customizeStyle();
cfg.restoreGeometry(this);
}
SettingsDialog::~SettingsDialog()
{
delete _ui;
}
// close event is not being called here
2017-05-17 11:55:42 +03:00
void SettingsDialog::reject()
{
2014-11-10 00:30:29 +03:00
ConfigFile cfg;
cfg.saveGeometry(this);
QDialog::reject();
}
2017-05-17 11:55:42 +03:00
void SettingsDialog::accept()
{
2014-11-10 00:30:29 +03:00
ConfigFile cfg;
cfg.saveGeometry(this);
QDialog::accept();
}
void SettingsDialog::changeEvent(QEvent *e)
{
switch (e->type()) {
case QEvent::StyleChange:
case QEvent::PaletteChange:
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
case QEvent::ThemeChange:
#endif
customizeStyle();
break;
default:
break;
}
QDialog::changeEvent(e);
}
void SettingsDialog::slotSwitchPage(QAction *action)
{
_ui->stack->setCurrentWidget(_actionGroupWidgets.value(action));
}
void SettingsDialog::showFirstPage()
{
2017-05-17 11:55:42 +03:00
QList<QAction *> actions = _toolBar->actions();
if (!actions.empty()) {
actions.first()->trigger();
}
}
void SettingsDialog::showActivityPage()
{
if (_activityAction) {
2015-12-22 12:26:13 +03:00
_activityAction->trigger();
}
}
2015-04-17 18:56:17 +03:00
void SettingsDialog::accountAdded(AccountState *s)
{
auto height = _toolBar->sizeHint().height();
bool brandingSingleAccount = !Theme::instance()->multiAccount();
QAction *accountAction;
QImage avatar = s->account()->avatar();
const QString actionText = brandingSingleAccount ? tr("Account") : s->account()->displayName();
2017-05-17 11:55:42 +03:00
if (avatar.isNull()) {
accountAction = createColorAwareAction(QLatin1String(":/client/resources/account.png"),
2017-05-17 11:55:42 +03:00
actionText);
} else {
QIcon icon = circleMask(avatar);
accountAction = createActionWithIcon(icon, actionText);
}
if (!brandingSingleAccount) {
accountAction->setToolTip(s->account()->displayName());
accountAction->setIconText(s->shortDisplayNameForSettings(height * buttonSizeRatio));
}
_toolBar->insertAction(_toolBar->actions().at(0), accountAction);
2015-04-17 18:56:17 +03:00
auto accountSettings = new AccountSettings(s, this);
2017-05-17 11:55:42 +03:00
_ui->stack->insertWidget(0, accountSettings);
_actionGroup->addAction(accountAction);
_actionGroupWidgets.insert(accountAction, accountSettings);
_actionForAccount.insert(s->account().data(), accountAction);
2015-04-17 18:56:17 +03:00
2017-05-17 11:55:42 +03:00
connect(accountSettings, SIGNAL(folderChanged()), _gui, SLOT(slotFoldersChanged()));
connect(accountSettings, SIGNAL(openFolderAlias(const QString &)),
_gui, SLOT(slotFolderOpenAction(QString)));
connect(s->account().data(), SIGNAL(accountChangedAvatar()), SLOT(slotAccountAvatarChanged()));
slotRefreshActivity(s);
2015-04-17 18:56:17 +03:00
}
void SettingsDialog::slotAccountAvatarChanged()
{
2017-05-17 11:55:42 +03:00
Account *account = static_cast<Account *>(sender());
if (account && _actionForAccount.contains(account)) {
QAction *action = _actionForAccount[account];
2017-05-17 11:55:42 +03:00
if (action) {
QImage pix = account->avatar();
2017-05-17 11:55:42 +03:00
if (!pix.isNull()) {
action->setIcon(circleMask(pix));
}
}
}
}
2015-04-17 18:56:17 +03:00
void SettingsDialog::accountRemoved(AccountState *s)
{
for (auto it = _actionGroupWidgets.begin(); it != _actionGroupWidgets.end(); ++it) {
2015-04-17 18:56:17 +03:00
auto as = qobject_cast<AccountSettings *>(*it);
if (!as) {
continue;
}
if (as->accountsState() == s) {
_toolBar->removeAction(it.key());
if (_ui->stack->currentWidget() == it.value()) {
showFirstPage();
}
2016-03-31 09:56:26 +03:00
it.key()->deleteLater();
it.value()->deleteLater();
_actionGroupWidgets.erase(it);
2015-04-17 18:56:17 +03:00
break;
}
}
2017-05-17 11:55:42 +03:00
if (_actionForAccount.contains(s->account().data())) {
_actionForAccount.remove(s->account().data());
}
_activitySettings->slotRemoveAccount(s);
// Hide when the last account is deleted. We want to enter the same
// state we'd be in the client was started up without an account
// configured.
if (AccountManager::instance()->accounts().isEmpty()) {
hide();
}
2015-04-17 18:56:17 +03:00
}
void SettingsDialog::customizeStyle()
{
2017-05-17 11:55:42 +03:00
QString highlightColor(palette().highlight().color().name());
QString altBase(palette().alternateBase().color().name());
QString dark(palette().dark().color().name());
QString background(palette().base().color().name());
2017-05-17 11:55:42 +03:00
_toolBar->setStyleSheet(QString::fromAscii(TOOLBAR_CSS).arg(background, dark, highlightColor, altBase));
2017-05-17 11:55:42 +03:00
Q_FOREACH (QAction *a, _actionGroup->actions()) {
QIcon icon = createColorAwareIcon(a->property("iconPath").toString());
a->setIcon(icon);
2017-05-17 11:55:42 +03:00
QToolButton *btn = qobject_cast<QToolButton *>(_toolBar->widgetForAction(a));
if (btn) {
btn->setIcon(icon);
}
}
}
QIcon SettingsDialog::createColorAwareIcon(const QString &name)
{
2017-05-17 11:55:42 +03:00
QColor bg(palette().base().color());
QImage img(name);
// account for different sensitivity of the human eye to certain colors
2017-05-17 11:55:42 +03:00
double treshold = 1.0 - (0.299 * bg.red() + 0.587 * bg.green() + 0.114 * bg.blue()) / 255.0;
if (treshold > 0.5) {
img.invertPixels(QImage::InvertRgb);
}
return QIcon(QPixmap::fromImage(img));
}
class ToolButtonAction : public QWidgetAction
{
public:
2017-05-17 11:55:42 +03:00
explicit ToolButtonAction(const QIcon &icon, const QString &text, QObject *parent)
: QWidgetAction(parent)
{
setText(text);
setIcon(icon);
}
2017-05-17 11:55:42 +03:00
QWidget *createWidget(QWidget *parent) Q_DECL_OVERRIDE
{
auto toolbar = qobject_cast<QToolBar *>(parent);
if (!toolbar) {
// this means we are in the extention menu, no special action here
return 0;
}
2017-05-17 11:55:42 +03:00
QToolButton *btn = new QToolButton(parent);
btn->setDefaultAction(this);
btn->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
btn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
2017-05-17 11:55:42 +03:00
// btn->setMinimumWidth(qMax<int>(parent->sizeHint().height() * buttonSizeRatio,
// btn->sizeHint().width()));
return btn;
}
};
2017-05-17 11:55:42 +03:00
QAction *SettingsDialog::createActionWithIcon(const QIcon &icon, const QString &text, const QString &iconPath)
{
QAction *action = new ToolButtonAction(icon, text, this);
action->setCheckable(true);
2017-05-17 11:55:42 +03:00
if (!iconPath.isEmpty()) {
action->setProperty("iconPath", iconPath);
}
return action;
}
QAction *SettingsDialog::createColorAwareAction(const QString &iconPath, const QString &text)
{
// all buttons must have the same size in order to keep a good layout
QIcon coloredIcon = createColorAwareIcon(iconPath);
return createActionWithIcon(coloredIcon, text, iconPath);
}
2015-04-17 18:56:17 +03:00
2017-05-17 11:55:42 +03:00
void SettingsDialog::slotRefreshActivity(AccountState *accountState)
{
if (accountState) {
_activitySettings->slotRefresh(accountState);
}
}
2014-11-10 00:34:07 +03:00
} // namespace OCC