MuseScore/mscore/palettebox.cpp
Dag Henning Liodden Sørbø 2b6cb8b432 Change to new preferences model
The old Preferences struct holding all preferences are removed in favor of a
new Preferences class which acts as a proxy for QSettings. The settings stored
in QSettings are accessed directly through access methods like getBool(key),
getInt(key), etc. and changed with setPreference(key, value).

Since we are using QSettings directly the preferences are stored automatically
without the need for a custom write() and read() method like before.

The preferences.cpp/.h and prefdialog.cpp/h are refactored to have fewer
responsibilities than before. The Preferences class are all about storing and
retrieving preferences - it should not contain any code to handle any other
aspect of MuseScore.

Testing:
The Preferences class can be used in tests. All preferences are initialized with
default values in mtest. If a test requires that a preference has a specific
value it can be changed using setPreference() for that single test. In the tests
the preferences are stored in memory only.

The Preference class is supposed to be used as a singleton. In preferences.h an
'extern Preferences preferences' is set and it is defined in preferences.cpp. All
files which includes preferences.h have access to the 'preferences' singleton
and should use this to get and set preferences.
2018-02-08 16:59:10 +01:00

562 lines
20 KiB
C++

//=============================================================================
// MuseScore
// Music Composition & Notation
// $Id: palettebox.cpp 5576 2012-04-24 19:15:22Z wschweer $
//
// Copyright (C) 2011-2016 Werner Schweer and others
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2
// as published by the Free Software Foundation and appearing in
// the file LICENSE.GPL
//=============================================================================
#include "palette.h"
#include "palettebox.h"
#include "musescore.h"
#include "preferences.h"
#include "libmscore/xml.h"
#include "workspace.h"
namespace Ms {
//---------------------------------------------------------
// PaletteBox
//---------------------------------------------------------
PaletteBox::PaletteBox(QWidget* parent)
: QDockWidget(tr("Palettes"), parent)
{
setContextMenuPolicy(Qt::ActionsContextMenu);
setObjectName("palette-box");
setAllowedAreas(Qt::DockWidgetAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea));
singlePaletteAction = new QAction(this);
singlePaletteAction->setCheckable(true);
singlePaletteAction->setChecked(preferences.getBool(PREF_APP_USESINGLEPALETTE));
addAction(singlePaletteAction);
connect(singlePaletteAction, SIGNAL(toggled(bool)), SLOT(setSinglePalette(bool)));
QWidget* w = new QWidget(this);
w->setContextMenuPolicy(Qt::NoContextMenu);
QVBoxLayout* vl = new QVBoxLayout(w);
vl->setMargin(0);
QHBoxLayout* hl = new QHBoxLayout;
hl->setContentsMargins(5,0,5,0);
workspaceList = new QComboBox;
hl->addWidget(workspaceList);
addWorkspaceButton = new QToolButton;
addWorkspaceButton->setMinimumHeight(24);
hl->addWidget(addWorkspaceButton);
setWidget(w);
_searchBox = new QLineEdit(this);
_searchBox->setFocusPolicy(Qt::StrongFocus);
_searchBox->installEventFilter(this);
_searchBox->setClearButtonEnabled(true);
_searchBox->setPlaceholderText(tr("Search"));
connect(_searchBox, SIGNAL(textChanged(const QString&)), this, SLOT(filterPalettes(const QString&)));
QHBoxLayout* hlSearch = new QHBoxLayout;
hlSearch->setContentsMargins(5,0,5,0);
hlSearch->addWidget(_searchBox);
PaletteBoxScrollArea* sa = new PaletteBoxScrollArea;
sa->setFocusPolicy(Qt::NoFocus);
sa->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
sa->setContextMenuPolicy(Qt::CustomContextMenu);
sa->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
sa->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
sa->setWidgetResizable(true);
sa->setFrameShape(QFrame::NoFrame);
vl->addWidget(sa);
vl->addLayout(hlSearch);
vl->addLayout(hl);
QWidget* paletteList = new QWidget;
sa->setWidget(paletteList);
vbox = new QVBoxLayout;
paletteList->setLayout(vbox);
vbox->setMargin(0);
vbox->setSpacing(1);
vbox->addStretch();
paletteList->show();
connect(addWorkspaceButton, SIGNAL(clicked()), SLOT(newWorkspaceClicked()));
connect(workspaceList, SIGNAL(activated(int)), SLOT(workspaceSelected(int)));
retranslate();
}
//---------------------------------------------------------
// retranslate
//---------------------------------------------------------
void PaletteBox::retranslate()
{
setWindowTitle(tr("Palettes"));
singlePaletteAction->setText(tr("Single Palette"));
workspaceList->setToolTip(tr("Select workspace"));
addWorkspaceButton->setText(tr("+"));
addWorkspaceButton->setToolTip(tr("Add new workspace"));
updateWorkspaces();
}
//---------------------------------------------------------
// filterPalettes
//---------------------------------------------------------
void PaletteBox::filterPalettes(const QString& text)
{
for (int i = 0; i < vbox->count(); i++) {
QWidgetItem* wi = static_cast<QWidgetItem*>(vbox->itemAt(i));
PaletteBoxButton* b = static_cast<PaletteBoxButton*>(wi->widget());
i++;
wi = static_cast<QWidgetItem*>(vbox->itemAt(i));
if (!wi) return;
Palette* p = static_cast<Palette*>(wi->widget());
bool f = p->filter(text);
b->setVisible(!f);
if (b->isVisible()) {
if (text.isEmpty())
b->showPalette(false);
else
b->showPalette(true);
}
else
b->showPalette(false);
}
}
//---------------------------------------------------------
// workspaceSelected
//---------------------------------------------------------
void PaletteBox::workspaceSelected(int idx)
{
Workspace* w = Workspace::workspaces().at(idx);
preferences.setPreference(PREF_APP_WORKSPACE, w->name());
mscore->changeWorkspace(w);
}
//---------------------------------------------------------
// newWorkspaceClicked
//---------------------------------------------------------
void PaletteBox::newWorkspaceClicked()
{
mscore->createNewWorkspace();
updateWorkspaces();
}
//---------------------------------------------------------
// updateWorkspaces
//---------------------------------------------------------
void PaletteBox::updateWorkspaces()
{
workspaceList->clear();
const QList<Workspace*> pl = Workspace::workspaces();
int idx = 0;
int curIdx = -1;
for (Workspace* p : pl) {
workspaceList->addItem(qApp->translate("Ms::Workspace", p->name().toUtf8()), p->path());
if (p->name() == preferences.getString(PREF_APP_WORKSPACE))
curIdx = idx;
++idx;
}
if (curIdx != -1)
workspaceList->setCurrentIndex(curIdx);
}
//---------------------------------------------------------
// clear
//---------------------------------------------------------
void PaletteBox::clear()
{
int n = vbox->count() - 1; // do not delete stretch item
while (n--) {
QLayoutItem* item = vbox->takeAt(0);
if (item->widget())
item->widget()->hide();
delete item;
}
vbox->invalidate();
}
//---------------------------------------------------------
// addPalette
//---------------------------------------------------------
void PaletteBox::addPalette(Palette* w)
{
PaletteBoxButton* b = new PaletteBoxButton(w);
int slotIdx = vbox->count() - 1; // insert before stretch
b->setId(slotIdx);
vbox->insertWidget(slotIdx, b);
vbox->insertWidget(slotIdx+1, w, paletteStretch);
connect(b, SIGNAL(paletteCmd(PaletteCommand,int)), SLOT(paletteCmd(PaletteCommand,int)));
connect(b, SIGNAL(closeAll()), SLOT(closeAll()));
connect(w, SIGNAL(changed()), SIGNAL(changed()));
}
//---------------------------------------------------------
// newPalette
//---------------------------------------------------------
Palette* PaletteBox::newPalette(const QString& name, int slot)
{
Palette* p = new Palette;
p->setReadOnly(false);
p->setName(name);
PaletteBoxButton* b = new PaletteBoxButton(p);
vbox->insertWidget(slot, b);
vbox->insertWidget(slot+1, p, paletteStretch);
connect(b, SIGNAL(paletteCmd(PaletteCommand, int)), SLOT(paletteCmd(PaletteCommand, int)));
connect(p, SIGNAL(changed()), Workspace::currentWorkspace, SLOT(setDirty()));
for (int i = 0; i < (vbox->count() - 1) / 2; ++i)
static_cast<PaletteBoxButton*>(vbox->itemAt(i * 2)->widget())->setId(i*2);
return p;
}
//---------------------------------------------------------
// paletteCmd
//---------------------------------------------------------
void PaletteBox::paletteCmd(PaletteCommand cmd, int slot)
{
QLayoutItem* item = vbox->itemAt(slot);
PaletteBoxButton* b = static_cast<PaletteBoxButton*>(item->widget());
Palette* palette = static_cast<Palette*>(vbox->itemAt(slot+1)->widget());
switch(cmd) {
case PaletteCommand::PDELETE:
{
QMessageBox::StandardButton reply;
reply = QMessageBox::question(0,
QWidget::tr("Are you sure?"),
QWidget::tr("Do you really want to delete the '%1' palette?").arg(palette->name()),
QMessageBox::Yes | QMessageBox::No,
QMessageBox::Yes
);
if (reply == QMessageBox::Yes) {
vbox->removeItem(item);
b->deleteLater(); // this is the button widget
delete item;
item = vbox->itemAt(slot);
vbox->removeItem(item);
delete item->widget();
delete item;
for (int i = 0; i < (vbox->count() - 1) / 2; ++i)
static_cast<PaletteBoxButton*>(vbox->itemAt(i * 2)->widget())->setId(i*2);
emit changed();
}
}
break;
case PaletteCommand::SAVE:
{
QString path = mscore->getPaletteFilename(false, palette->name());
if (!path.isEmpty())
palette->write(path);
}
break;
case PaletteCommand::LOAD:
{
QString path = mscore->getPaletteFilename(true);
if (!path.isEmpty()) {
QFileInfo fi(path);
Palette* palette = newPalette(fi.completeBaseName(), slot);
palette->read(path);
}
}
emit changed();
break;
case PaletteCommand::NEW:
palette = newPalette(tr("new Palette"), slot);
item = vbox->itemAt(slot);
b = static_cast<PaletteBoxButton*>(item->widget());
// fall through
case PaletteCommand::EDIT:
{
PaletteProperties pp(palette, 0);
int rv = pp.exec();
if (rv == 1) {
emit changed();
b->setText(palette->name());
palette->update();
}
}
emit changed();
break;
case PaletteCommand::UP:
if (slot) {
QLayoutItem* i1 = vbox->itemAt(slot);
QLayoutItem* i2 = vbox->itemAt(slot+1);
vbox->removeItem(i1);
vbox->removeItem(i2);
vbox->insertWidget(slot-2, i2->widget(), paletteStretch);
vbox->insertWidget(slot-2, i1->widget());
delete i1;
delete i2;
for (int i = 0; i < (vbox->count() - 1) / 2; ++i)
static_cast<PaletteBoxButton*>(vbox->itemAt(i * 2)->widget())->setId(i*2);
emit changed();
}
break;
case PaletteCommand::DOWN:
if (slot < (vbox->count() - 3)) {
QLayoutItem* i1 = vbox->itemAt(slot);
QLayoutItem* i2 = vbox->itemAt(slot+1);
vbox->removeItem(i1);
vbox->removeItem(i2);
vbox->insertWidget(slot+2, i2->widget(), paletteStretch);
vbox->insertWidget(slot+2, i1->widget());
delete i1;
delete i2;
for (int i = 0; i < (vbox->count() - 1) / 2; ++i)
static_cast<PaletteBoxButton*>(vbox->itemAt(i * 2)->widget())->setId(i*2);
emit changed();
}
break;
}
}
//---------------------------------------------------------
// closeAll
//---------------------------------------------------------
void PaletteBox::closeAll()
{
for (int i = 0; i < (vbox->count() - 1); i += 2) {
PaletteBoxButton* b = static_cast<PaletteBoxButton*> (vbox->itemAt(i)->widget() );
b->showPalette(false);
}
}
//---------------------------------------------------------
// write
//---------------------------------------------------------
void PaletteBox::write(XmlWriter& xml)
{
xml.stag("PaletteBox");
for (int i = 0; i < (vbox->count() - 1); i += 2) {
Palette* palette = static_cast<Palette*>(vbox->itemAt(i+1)->widget());
palette->write(xml);
}
xml.etag();
}
//---------------------------------------------------------
// palettes
//---------------------------------------------------------
QList<Palette*> PaletteBox::palettes()const
{
QList<Palette*> pl;
for (int i = 0; i < (vbox->count() - 1); i += 2)
pl.append(static_cast<Palette*>(vbox->itemAt(i+1)->widget()));
return pl;
}
//---------------------------------------------------------
// read
// return false on error
//---------------------------------------------------------
bool PaletteBox::read(XmlReader& e)
{
while (e.readNextStartElement()) {
const QStringRef& tag(e.name());
if (tag == "Palette") {
Palette* p = new Palette();
QString name = e.attribute("name");
p->setName(name);
p->read(e);
addPalette(p);
connect(p, SIGNAL(displayMore(const QString&)), mscore, SLOT(showMasterPalette(const QString&)));
}
else
e.unknown();
}
return true;
}
//---------------------------------------------------------
// sizeHint
//---------------------------------------------------------
QSize PaletteBoxScrollArea::sizeHint() const
{
return QSize(170 * guiScaling, 170 * guiScaling);
}
//---------------------------------------------------------
// setSinglePalette
//---------------------------------------------------------
void PaletteBox::setSinglePalette(bool val)
{
preferences.setPreference(PREF_APP_USESINGLEPALETTE, val);
}
//---------------------------------------------------------
// changeEvent
//---------------------------------------------------------
void PaletteBox::changeEvent(QEvent *event)
{
QDockWidget::changeEvent(event);
if (event->type() == QEvent::LanguageChange)
retranslate();
}
//---------------------------------------------------------
// noSelection
//---------------------------------------------------------
bool PaletteBox::noSelection()
{
for (Palette* p : palettes()) {
if (p->getCurrentIdx() != -1)
return false;
}
return true;
}
//---------------------------------------------------------
// mousePressEvent
//---------------------------------------------------------
void PaletteBox::mousePressEvent(QMouseEvent* ev, Palette* p1)
{
for (Palette* p : palettes()) {
QList<PaletteCell*> cells = p->getDragCells();
if (cells.isEmpty())
continue;
if (p->getCurrentIdx() != -1) {
p->setCurrentIdx(-1);
p->update();
}
}
p1->setCurrentIdx(p1->idx(ev->pos()));
p1->update();
_searchBox->setFocus();
}
//---------------------------------------------------------
// navigation
//---------------------------------------------------------
void PaletteBox::navigation(QKeyEvent *event)
{
if (!palettes().first()->isFilterActive())
return;
if (event->key() == Qt::Key_Down) {
for (Palette* p : palettes()) {
if (p->getCurrentIdx() == -1)
continue;
if (p->getCurrentIdx() != p->getDragCells().size() - 1) {
p->nextPaletteElement();
return;
}
else {
int index = palettes().indexOf(p);
p->setCurrentIdx(-1);
p->update();
for (int i = index + 1; i < palettes().size(); i++) {
Palette* next = palettes()[i];
if (!next->getDragCells().isEmpty()) {
next->setCurrentIdx(0);
next->update();
return;
}
}
}
}
for (Palette* p : palettes()) {
if (!p->getDragCells().isEmpty()) {
p->setCurrentIdx(0);
p->update();
keyboardNavigation = true;
return;
}
}
}
else if (event->key() == Qt::Key_Up) {
for (Palette* p : palettes()) {
if (p->getCurrentIdx() == -1)
continue;
if (p->getCurrentIdx() != 0) {
p->prevPaletteElement();
return;
}
else {
int index = palettes().indexOf(p);
p->setCurrentIdx(-1);
p->update();
for (int i = index - 1; i >= 0; i--) {
Palette* prev = palettes()[i];
if (!prev->getDragCells().isEmpty()) {
QList<PaletteCell*> cells = p->getDragCells();
int l = prev->getDragCells().size() - 1;
prev->setCurrentIdx(l);
prev->update();
return;
}
}
}
}
for (int j = palettes().size() - 1; j >= 0; j--) {
Palette* p = palettes()[j];
if (!p->getDragCells().isEmpty()) {
int l = p->getDragCells().size() - 1;
p->setCurrentIdx(l);
p->update();
keyboardNavigation = true;
return;
}
}
}
else if ((event->key() == Qt::Key_Enter) ||
(event->key() == Qt::Key_Return)) {
for (Palette* p : palettes()) {
if (p->getCurrentIdx() != -1) {
p->applyPaletteElement();
return;
}
}
}
}
bool PaletteBox::eventFilter(QObject* obj, QEvent *event)
{
if (obj == _searchBox) {
if (event->type() == QEvent::KeyPress) {
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent->key() == Qt::Key_Up || keyEvent->key() == Qt::Key_Down ||
keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return) {
navigation(keyEvent);
return true;
}
}
return false;
}
return QDockWidget::eventFilter(obj, event);
}
}