2018-02-27 18:06:05 +01:00
|
|
|
/*
|
|
|
|
* Strawberry Music Player
|
|
|
|
* This file was part of Clementine.
|
|
|
|
* Copyright 2010, David Sansome <me@davidsansome.com>
|
|
|
|
*
|
|
|
|
* Strawberry 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 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* Strawberry 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.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
2018-08-09 18:10:03 +02:00
|
|
|
*
|
2018-02-27 18:06:05 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
2018-05-01 00:41:33 +02:00
|
|
|
#include <QObject>
|
|
|
|
#include <QWidget>
|
|
|
|
#include <QApplication>
|
|
|
|
#include <QAbstractItemModel>
|
|
|
|
#include <QAbstractItemView>
|
2018-02-27 18:06:05 +01:00
|
|
|
#include <QDesktopWidget>
|
2018-05-01 00:41:33 +02:00
|
|
|
#include <QVariant>
|
|
|
|
#include <QString>
|
|
|
|
#include <QStringBuilder>
|
|
|
|
#include <QIcon>
|
2018-02-27 18:06:05 +01:00
|
|
|
#include <QPainter>
|
2018-05-01 00:41:33 +02:00
|
|
|
#include <QFlags>
|
|
|
|
#include <QFrame>
|
|
|
|
#include <QKeySequence>
|
|
|
|
#include <QLabel>
|
|
|
|
#include <QLayout>
|
|
|
|
#include <QRect>
|
|
|
|
#include <QDialogButtonBox>
|
2018-02-27 18:06:05 +01:00
|
|
|
#include <QPushButton>
|
|
|
|
#include <QScrollArea>
|
2018-05-01 00:41:33 +02:00
|
|
|
#include <QStackedWidget>
|
|
|
|
#include <QTreeWidget>
|
2018-02-27 18:06:05 +01:00
|
|
|
|
2018-05-01 00:41:33 +02:00
|
|
|
#include "core/application.h"
|
2018-06-28 01:15:32 +02:00
|
|
|
#include "core/player.h"
|
2018-07-01 01:29:52 +02:00
|
|
|
#include "core/logging.h"
|
2018-06-28 01:15:32 +02:00
|
|
|
#include "engine/enginebase.h"
|
2018-05-01 00:41:33 +02:00
|
|
|
#include "widgets/groupediconview.h"
|
|
|
|
#include "collection/collectionmodel.h"
|
2018-02-27 18:06:05 +01:00
|
|
|
|
2018-05-01 00:41:33 +02:00
|
|
|
#include "settingsdialog.h"
|
|
|
|
#include "settingspage.h"
|
|
|
|
#include "appearancesettingspage.h"
|
|
|
|
#include "backendsettingspage.h"
|
2018-02-27 18:06:05 +01:00
|
|
|
#include "behavioursettingspage.h"
|
|
|
|
#include "collectionsettingspage.h"
|
2018-05-01 00:41:33 +02:00
|
|
|
#include "networkproxysettingspage.h"
|
|
|
|
#include "notificationssettingspage.h"
|
2018-02-27 18:06:05 +01:00
|
|
|
#include "playbacksettingspage.h"
|
|
|
|
#include "playlistsettingspage.h"
|
|
|
|
#include "shortcutssettingspage.h"
|
|
|
|
#include "transcodersettingspage.h"
|
2018-08-09 18:10:03 +02:00
|
|
|
#include "tidalsettingspage.h"
|
|
|
|
|
2018-02-27 18:06:05 +01:00
|
|
|
#include "ui_settingsdialog.h"
|
|
|
|
|
2018-05-01 00:41:33 +02:00
|
|
|
class QShowEvent;
|
2018-02-27 18:06:05 +01:00
|
|
|
|
|
|
|
SettingsItemDelegate::SettingsItemDelegate(QObject *parent)
|
|
|
|
: QStyledItemDelegate(parent)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
QSize SettingsItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const {
|
|
|
|
|
|
|
|
const bool is_separator = index.data(SettingsDialog::Role_IsSeparator).toBool();
|
|
|
|
QSize ret = QStyledItemDelegate::sizeHint(option, index);
|
|
|
|
|
|
|
|
if (is_separator) {
|
|
|
|
ret.setHeight(ret.height() * 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void SettingsItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const {
|
|
|
|
|
|
|
|
const bool is_separator = index.data(SettingsDialog::Role_IsSeparator).toBool();
|
|
|
|
|
|
|
|
if (is_separator) {
|
|
|
|
GroupedIconView::DrawHeader(painter, option.rect, option.font, option.palette, index.data().toString());
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
QStyledItemDelegate::paint(painter, option, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
SettingsDialog::SettingsDialog(Application *app, QWidget *parent)
|
|
|
|
: QDialog(parent),
|
|
|
|
app_(app),
|
2018-06-28 01:15:32 +02:00
|
|
|
player_(app_->player()),
|
|
|
|
engine_(app_->player()->engine()),
|
2018-02-27 18:06:05 +01:00
|
|
|
model_(app_->collection_model()->directory_model()),
|
|
|
|
appearance_(app_->appearance()),
|
|
|
|
ui_(new Ui_SettingsDialog),
|
2018-07-01 01:29:52 +02:00
|
|
|
loading_settings_(false),
|
|
|
|
output_changed_(false) {
|
2018-02-27 18:06:05 +01:00
|
|
|
|
|
|
|
ui_->setupUi(this);
|
|
|
|
ui_->list->setItemDelegate(new SettingsItemDelegate(this));
|
|
|
|
|
|
|
|
QTreeWidgetItem *general = AddCategory(tr("General"));
|
|
|
|
|
|
|
|
AddPage(Page_Behaviour, new BehaviourSettingsPage(this), general);
|
|
|
|
AddPage(Page_Collection, new CollectionSettingsPage(this), general);
|
|
|
|
AddPage(Page_Backend, new BackendSettingsPage(this), general);
|
|
|
|
AddPage(Page_Playback, new PlaybackSettingsPage(this), general);
|
|
|
|
AddPage(Page_Playlist, new PlaylistSettingsPage(this), general);
|
|
|
|
AddPage(Page_Proxy, new NetworkProxySettingsPage(this), general);
|
|
|
|
#ifdef HAVE_GSTREAMER
|
|
|
|
AddPage(Page_Transcoding, new TranscoderSettingsPage(this), general);
|
|
|
|
#endif
|
2018-08-09 18:10:03 +02:00
|
|
|
AddPage(Page_Tidal, new TidalSettingsPage(this), general);
|
2018-02-27 18:06:05 +01:00
|
|
|
|
|
|
|
// User interface
|
|
|
|
QTreeWidgetItem *iface = AddCategory(tr("User interface"));
|
|
|
|
AddPage(Page_GlobalShortcuts, new GlobalShortcutsSettingsPage(this), iface);
|
|
|
|
AddPage(Page_Appearance, new AppearanceSettingsPage(this), iface);
|
|
|
|
AddPage(Page_Notifications, new NotificationsSettingsPage(this), iface);
|
|
|
|
|
|
|
|
// List box
|
|
|
|
connect(ui_->list, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), SLOT(CurrentItemChanged(QTreeWidgetItem*)));
|
|
|
|
ui_->list->setCurrentItem(pages_[Page_Behaviour].item_);
|
|
|
|
|
|
|
|
// Make sure the list is big enough to show all the items
|
|
|
|
ui_->list->setMinimumWidth(static_cast<QAbstractItemView*>(ui_->list)->sizeHintForColumn(0));
|
|
|
|
|
|
|
|
ui_->buttonBox->button(QDialogButtonBox::Cancel)->setShortcut(QKeySequence::Close);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
SettingsDialog::~SettingsDialog() {
|
|
|
|
delete ui_;
|
|
|
|
}
|
|
|
|
|
|
|
|
QTreeWidgetItem *SettingsDialog::AddCategory(const QString &name) {
|
|
|
|
|
|
|
|
QTreeWidgetItem *item = new QTreeWidgetItem;
|
|
|
|
item->setText(0, name);
|
|
|
|
item->setData(0, Role_IsSeparator, true);
|
|
|
|
item->setFlags(Qt::ItemIsEnabled);
|
|
|
|
|
|
|
|
ui_->list->invisibleRootItem()->addChild(item);
|
|
|
|
item->setExpanded(true);
|
|
|
|
|
|
|
|
return item;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void SettingsDialog::AddPage(Page id, SettingsPage *page, QTreeWidgetItem *parent) {
|
|
|
|
|
|
|
|
if (!parent) parent = ui_->list->invisibleRootItem();
|
|
|
|
|
|
|
|
// Connect page's signals to the settings dialog's signals
|
2018-05-01 00:41:33 +02:00
|
|
|
connect(page, SIGNAL(NotificationPreview(OSD::Behaviour, QString, QString)), SIGNAL(NotificationPreview(OSD::Behaviour, QString, QString)));
|
2018-02-27 18:06:05 +01:00
|
|
|
|
|
|
|
// Create the list item
|
|
|
|
QTreeWidgetItem *item = new QTreeWidgetItem;
|
|
|
|
item->setText(0, page->windowTitle());
|
|
|
|
item->setIcon(0, page->windowIcon());
|
|
|
|
item->setData(0, Role_IsSeparator, false);
|
|
|
|
|
|
|
|
if (!page->IsEnabled()) {
|
|
|
|
item->setFlags(Qt::NoItemFlags);
|
|
|
|
}
|
|
|
|
|
|
|
|
parent->addChild(item);
|
|
|
|
|
|
|
|
// Create a scroll area containing the page
|
|
|
|
QScrollArea *area = new QScrollArea;
|
|
|
|
area->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
|
|
area->setWidget(page);
|
|
|
|
area->setWidgetResizable(true);
|
|
|
|
area->setFrameShape(QFrame::NoFrame);
|
|
|
|
area->setMinimumWidth(page->layout()->minimumSize().width());
|
|
|
|
|
|
|
|
// Add the page to the stack
|
|
|
|
ui_->stacked_widget->addWidget(area);
|
|
|
|
|
|
|
|
// Remember where the page is
|
|
|
|
PageData data;
|
|
|
|
data.item_ = item;
|
|
|
|
data.scroll_area_ = area;
|
|
|
|
data.page_ = page;
|
|
|
|
pages_[id] = data;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void SettingsDialog::Save() {
|
|
|
|
for (const PageData &data : pages_.values()) {
|
|
|
|
data.page_->Save();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SettingsDialog::accept() {
|
|
|
|
Save();
|
2018-07-01 01:29:52 +02:00
|
|
|
// Only Xine needs to reinitialize to switch output and device.
|
|
|
|
if (output_changed_ && engine() && engine()->type() == Engine::Xine && engine()->state() == Engine::Empty) {
|
|
|
|
engine()->ReloadSettings();
|
|
|
|
engine()->Init();
|
|
|
|
}
|
2018-02-27 18:06:05 +01:00
|
|
|
QDialog::accept();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SettingsDialog::reject() {
|
|
|
|
|
|
|
|
// Notify each page that user clicks on Cancel
|
|
|
|
for (const PageData &data : pages_.values()) {
|
|
|
|
data.page_->Cancel();
|
|
|
|
}
|
|
|
|
|
|
|
|
QDialog::reject();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SettingsDialog::DialogButtonClicked(QAbstractButton *button) {
|
|
|
|
|
|
|
|
// While we only connect Apply at the moment, this might change in the future
|
|
|
|
if (ui_->buttonBox->button(QDialogButtonBox::Apply) == button) {
|
|
|
|
Save();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SettingsDialog::showEvent(QShowEvent *e) {
|
|
|
|
|
|
|
|
// Load settings
|
|
|
|
loading_settings_ = true;
|
|
|
|
for (const PageData &data : pages_.values()) {
|
|
|
|
data.page_->Load();
|
|
|
|
}
|
|
|
|
loading_settings_ = false;
|
|
|
|
|
|
|
|
// Resize the dialog if it's too big
|
|
|
|
const QSize available = QApplication::desktop()->availableGeometry(this).size();
|
|
|
|
if (available.height() < height()) {
|
|
|
|
resize(width(), sizeHint().height());
|
|
|
|
}
|
|
|
|
|
|
|
|
QDialog::showEvent(e);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void SettingsDialog::OpenAtPage(Page page) {
|
|
|
|
|
|
|
|
if (!pages_.contains(page)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ui_->list->setCurrentItem(pages_[page].item_);
|
|
|
|
show();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void SettingsDialog::CurrentItemChanged(QTreeWidgetItem *item) {
|
|
|
|
|
|
|
|
if (!(item->flags() & Qt::ItemIsSelectable)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the title
|
|
|
|
ui_->title->setText("<b>" + item->text(0) + "</b>");
|
|
|
|
|
|
|
|
// Display the right page
|
|
|
|
for (const PageData &data : pages_.values()) {
|
|
|
|
if (data.item_ == item) {
|
|
|
|
ui_->stacked_widget->setCurrentWidget(data.scroll_area_);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2018-09-21 18:53:27 +02:00
|
|
|
|
|
|
|
void SettingsDialog::ComboBoxLoadFromSettings(QSettings &s, QComboBox *combobox, QString setting, QString default_value) {
|
|
|
|
QString value = s.value(setting, default_value).toString();
|
|
|
|
int i = combobox->findData(value);
|
|
|
|
if (i == -1) i = combobox->findData(default_value);
|
|
|
|
combobox->setCurrentIndex(i);
|
|
|
|
}
|