Add controls for moving outputs between partitions

This commit is contained in:
David Hoyes
2021-04-12 21:43:45 +01:00
parent aebc4af1e3
commit 111d790968
7 changed files with 90 additions and 11 deletions

View File

@@ -792,6 +792,7 @@ MainWindow::MainWindow(QWidget *parent)
connect(this, SIGNAL(newPartition(QString)), MPDConnection::self(), SLOT(newPartition(QString)));
connect(this, SIGNAL(delPartition(QString)), MPDConnection::self(), SLOT(delPartition(QString)));
connect(this, SIGNAL(enableOutput(quint32, bool)), MPDConnection::self(), SLOT(enableOutput(quint32, bool)));
connect(this, SIGNAL(moveOutput(QString)), MPDConnection::self(), SLOT(moveOutput(QString)));
connect(this, SIGNAL(outputs()), MPDConnection::self(), SLOT(outputs()));
connect(this, SIGNAL(pause(bool)), MPDConnection::self(), SLOT(setPause(bool)));
connect(this, SIGNAL(play()), MPDConnection::self(), SLOT(play()));
@@ -1389,43 +1390,70 @@ void MainWindow::partitionsUpdated(const QList<Partition> &partitions)
void MainWindow::outputsUpdated(const QList<Output> &outputs)
{
const char *constMpdConName="mpd-name";
const char *constMpdPartitionName="mpd-partition";
const char *constMpdEnabledOuptuts="mpd-outputs";
QString lastConn=property(constMpdConName).toString();
QString lastPart=property(constMpdPartitionName).toString();
QString newConn=MPDConnection::self()->getDetails().name;
QString newPart=MPDConnection::self()->getDetails().partition;
setProperty(constMpdConName, newConn);
setProperty(constMpdPartitionName, newPart);
outputsAction->setVisible(true);
QSet<QString> enabledMpd;
QSet<QString> inCurrentPartitionMpd;
QSet<QString> inOtherPartitionMpd;
QSet<QString> lastEnabledMpd=QSet<QString>::fromList(property(constMpdEnabledOuptuts).toStringList());
QSet<QString> mpd;
QSet<QString> menuItems;
QSet<QString> menuMoveableItems;
QMenu *menu=outputsAction->menu();
for (const Output &o: outputs) {
if (o.enabled) {
enabledMpd.insert(o.name);
if (o.in_current_partition) {
if (o.enabled) {
enabledMpd.insert(o.name);
}
inCurrentPartitionMpd.insert(o.name);
} else {
inOtherPartitionMpd.insert(o.name);
}
mpd.insert(o.name);
}
for (QAction *act: menu->actions()) {
menuItems.insert(act->data().toString());
if (act->isCheckable()) {
menuItems.insert(act->data().toString());
} else if (act->menu() && act->data().toString()=="moveoutput") {
for (QAction *sub_act: act->menu()->actions()) {
menuMoveableItems.insert(sub_act->data().toString());
}
}
}
if (menuItems!=mpd) {
if (menuItems!=inCurrentPartitionMpd || menuMoveableItems!=inOtherPartitionMpd) {
menu->clear();
QList<Output> out=outputs;
std::sort(out.begin(), out.end());
int i=Qt::Key_1;
for (const Output &o: out) {
if (!o.in_current_partition) continue;
QAction *act=menu->addAction(o.name, this, SLOT(toggleOutput()));
act->setData(o.id);
act->setCheckable(true);
act->setChecked(o.enabled);
act->setShortcut(Qt::ControlModifier+Qt::AltModifier+nextKey(i));
}
menu->addSeparator();
QMenu* move_menu = menu->addMenu(tr("Move output to this partition"));
move_menu->menuAction()->setData("moveoutput");
move_menu->menuAction()->setVisible(inOtherPartitionMpd.count()>0);
for (const Output &o: out) {
if (o.in_current_partition) continue;
QAction *act=move_menu->addAction(o.name, this, SLOT(moveOutputToThisPartition()));
act->setData(o.name);
}
} else {
for (const Output &o: outputs) {
if (!o.in_current_partition) continue;
for (QAction *act: menu->actions()) {
if (Utils::strippedText(act->text())==o.name) {
if (act->isCheckable() && Utils::strippedText(act->text())==o.name) {
act->setChecked(o.enabled);
break;
}
@@ -1433,7 +1461,7 @@ void MainWindow::outputsUpdated(const QList<Output> &outputs)
}
}
if (newConn==lastConn && enabledMpd!=lastEnabledMpd && !menuItems.isEmpty()) {
if (newConn==lastConn && newPart==lastPart && enabledMpd!=lastEnabledMpd && !menuItems.isEmpty()) {
QSet<QString> switchedOn=enabledMpd-lastEnabledMpd;
QSet<QString> switchedOff=lastEnabledMpd-enabledMpd;
@@ -1456,7 +1484,7 @@ void MainWindow::outputsUpdated(const QList<Output> &outputs)
}
}
setProperty(constMpdEnabledOuptuts, QStringList() << enabledMpd.toList());
outputsAction->setVisible(outputs.count()>1);
outputsAction->setVisible(outputs.count()>0);
trayItem->updateOutputs();
}
@@ -1654,6 +1682,14 @@ void MainWindow::toggleOutput()
}
}
void MainWindow::moveOutputToThisPartition()
{
QAction *act=qobject_cast<QAction *>(sender());
if (act) {
emit moveOutput(act->data().toString());
}
}
void MainWindow::selectPartition()
{
QAction *act=qobject_cast<QAction *>(sender());

View File

@@ -147,6 +147,7 @@ Q_SIGNALS:
void delPartition(QString name);
void outputs();
void enableOutput(quint32 id, bool);
void moveOutput(QString name);
void setPriority(const QList<qint32> &ids, quint8 priority, bool decreasePriority);
void addSongsToPlaylist(const QString &name, const QStringList &files);
void showPreferencesPage(const QString &page);
@@ -169,6 +170,7 @@ public Q_SLOTS:
void commitDataRequest(QSessionManager &mgr);
void updateSettings();
void toggleOutput();
void moveOutputToThisPartition();
void selectPartition();
void createNewPartition();
void deleteAPartition();

View File

@@ -147,6 +147,7 @@ void PlaybackSettings::updateOutputs(const QList<Output> &outputs)
outputsView->clear();
enabledOutputs.clear();
for (const Output &output: outputs) {
if (!output.in_current_partition) continue;
QListWidgetItem *item=new QListWidgetItem(output.name, outputsView);
item->setCheckState(output.enabled ? Qt::Checked : Qt::Unchecked);
item->setData(Qt::UserRole, output.id);

View File

@@ -1767,7 +1767,31 @@ void MPDConnection::outputs()
{
Response response=sendCommand("outputs");
if (response.ok) {
emit outputsUpdated(MPDParseUtils::parseOuputs(response.data));
QList<Output> outputs = MPDParseUtils::parseOuputs(response.data);
// We need to temporarily switch to the default partition in order
// to collect the details of all available outputs.
if (!details.partition.isEmpty() && details.partition != "default") {
QByteArray return_cmd = "partition " + encodeName(details.partition);
Response default_response=sendCommand("command_list_begin\npartition default\noutputs\n" + return_cmd + "\ncommand_list_end");
if (default_response.ok) {
QSet<QString> existing_names;
for (const Output &o: outputs) {
existing_names << o.name;
}
QList<Output> default_outputs = MPDParseUtils::parseOuputs(default_response.data);
for (Output &o: default_outputs) {
if (!existing_names.contains(o.name)) {
o.in_current_partition = false;
outputs << o;
}
}
} else {
sendCommand(return_cmd);
}
}
emit outputsUpdated(outputs);
}
}
@@ -1778,6 +1802,13 @@ void MPDConnection::enableOutput(quint32 id, bool enable)
}
}
void MPDConnection::moveOutput(QString name)
{
if (sendCommand("moveoutput " + encodeName(name)).ok) {
outputs();
}
}
/*
* Admin commands
*/

View File

@@ -345,6 +345,7 @@ public Q_SLOTS:
// Output
void outputs();
void enableOutput(quint32 id, bool enable);
void moveOutput(QString name);
// Miscellaneous
void getStats();

View File

@@ -81,6 +81,7 @@ static const QByteArray constPartitionKey("partition: ");
static const QByteArray constOutputIdKey("outputid: ");
static const QByteArray constOutputNameKey("outputname: ");
static const QByteArray constOutputEnabledKey("outputenabled: ");
static const QByteArray constOutputPluginKey("plugin: ");
static const QByteArray constChangePosKey("cpos");
static const QByteArray constChangeIdKey("Id");
static const QByteArray constLastModifiedKey("Last-Modified: ");
@@ -808,13 +809,18 @@ QList<Output> MPDParseUtils::parseOuputs(const QByteArray &data)
if (line.startsWith(constOutputIdKey)) {
if (!output.name.isEmpty()) {
outputs << output;
output.name=QString();
output=Output();
}
output.id=line.mid(constOutputIdKey.length()).toUInt();
} else if (line.startsWith(constOutputNameKey)) {
output.name=line.mid(constOutputNameKey.length());
} else if (line.startsWith(constOutputEnabledKey)) {
output.enabled=toBool(line.mid(constOutputEnabledKey.length()));
} else if (line.startsWith(constOutputPluginKey)) {
const QString plugin=line.mid(constOutputPluginKey.length());
if (plugin == "dummy") {
output.in_current_partition=false;
}
}
}

View File

@@ -39,6 +39,7 @@ struct Output
Output & operator=(const Output &o) {
id=o.id;
enabled=o.enabled;
in_current_partition=o.in_current_partition;
name=o.name;
return *this;
}
@@ -51,6 +52,7 @@ struct Output
quint32 id;
bool enabled;
bool in_current_partition{true};
QString name;
};