Add controls for moving outputs between partitions
This commit is contained in:
@@ -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());
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -345,6 +345,7 @@ public Q_SLOTS:
|
||||
// Output
|
||||
void outputs();
|
||||
void enableOutput(quint32 id, bool enable);
|
||||
void moveOutput(QString name);
|
||||
|
||||
// Miscellaneous
|
||||
void getStats();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user