diff --git a/ChangeLog b/ChangeLog index 7431ca9c..8a3b2f38 100644 --- a/ChangeLog +++ b/ChangeLog @@ -24399,3 +24399,8 @@ 2023-09-27 Fred Gleason * Fixed a bug in 'RDSoundPanel' that threw a segfault when adding a new button to a User panel. +2023-09-28 Fred Gleason + * Added a 'RDJsonEscape(const QString &str)' function in + 'lib/rdweb.cpp' and 'lib/rdweb.h'. + * Added a '--dump-panel-updates' switch to rdpanel(1). + * Added a rdpanel(1) man page. diff --git a/docs/manpages/Makefile.am b/docs/manpages/Makefile.am index ad1d0657..277585e8 100644 --- a/docs/manpages/Makefile.am +++ b/docs/manpages/Makefile.am @@ -81,6 +81,9 @@ all-local: rdadmin.1\ rdmetadata.1\ rdmetadata.html\ rdmetadata.pdf\ + rdpanel.1\ + rdpanel.html\ + rdpanel.pdf\ rdrender.1\ rdrender.html\ rdrender.pdf\ @@ -112,6 +115,7 @@ man_MANS = rdadmin.1\ rdlogmanager.1\ rdmarkerset.8\ rdmetadata.1\ + rdpanel.1\ rdrender.1\ rmlsend.1\ rdservice.8\ @@ -168,6 +172,10 @@ EXTRA_DIST = exitcodes.xml\ rdmetadata.html\ rdmetadata.pdf\ rdmetadata.xml\ + rdpanel.1\ + rdpanel.html\ + rdpanel.pdf\ + rdpanel.xml\ rdrender.1\ rdrender.html\ rdrender.pdf\ diff --git a/docs/manpages/rdpanel.xml b/docs/manpages/rdpanel.xml new file mode 100644 index 00000000..ed982c84 --- /dev/null +++ b/docs/manpages/rdpanel.xml @@ -0,0 +1,70 @@ + + + + + rdpanel + 1 + September 2023 + Linux Audio Manual + + + rdpanel + + Module for stand-alone sound panel + + + + + + Fred + Gleason + fredg@paravelsystems.com + + Application Author + + + + + + + rdpanel + OPTIONS + + + + + + Description + + The rdpanel1 modules provides + a single, stand-alone "cart wall" application that allows + users to play carts by means of a single button press. + + + + + Options + + + + + + + + When this option is given, + rdpanel1 will print + a dump of the currently loaded sound panel configuration to + standard output each time the Rivendell user logged into the system + is changed. + + + + + + + + diff --git a/lib/rdbutton_panel.cpp b/lib/rdbutton_panel.cpp index cf6b3599..e22070b9 100644 --- a/lib/rdbutton_panel.cpp +++ b/lib/rdbutton_panel.cpp @@ -23,9 +23,12 @@ #include #include -RDButtonPanel::RDButtonPanel(RDAirPlayConf::PanelType type,QWidget *parent) +RDButtonPanel::RDButtonPanel(RDAirPlayConf::PanelType type,int number, + QWidget *parent) : RDWidget(parent) { + panel_number=number; + for(int i=0;iisEmpty()) { + count++; + } + } + } + + ret+=RDJsonPadding(padding)+"\"panel\": {\r\n"; + ret+=RDJsonField("number",panel_number,4+padding); + ret+=RDJsonField("title",panel_title,4+padding,count==0); + + for(int i=0;iisEmpty()) { + count--; + ret+=panel_button[i][j]->json(4+padding,count==0); + } + } + } + ret+=RDJsonPadding(padding)+"}"; + if(!final) { + ret+=","; + } + ret+="\r\n"; + + return ret; +} diff --git a/lib/rdbutton_panel.h b/lib/rdbutton_panel.h index 120c1fd3..ab811aec 100644 --- a/lib/rdbutton_panel.h +++ b/lib/rdbutton_panel.h @@ -29,6 +29,7 @@ #include #include #include +#include #include // @@ -43,10 +44,13 @@ class RDButtonPanel : public RDWidget { public: - RDButtonPanel(RDAirPlayConf::PanelType type,QWidget *parent); + RDButtonPanel(RDAirPlayConf::PanelType type,int number,QWidget *parent); ~RDButtonPanel(); QSize sizeHint() const; QSizePolicy sizePolicy() const; + int number() const; + QString title() const; + void setTitle(const QString &str); RDPanelButton *panelButton(int row,int col) const; void setActionMode(RDAirPlayConf::ActionMode mode); void setAllowDrags(bool state); @@ -54,8 +58,11 @@ class RDButtonPanel : public RDWidget void hide(); void show(); void clear(); + QString json(int padding=0,bool final=false) const; private: + int panel_number; + QString panel_title; RDPanelButton *panel_button[PANEL_MAX_BUTTON_ROWS][PANEL_MAX_BUTTON_COLUMNS]; }; diff --git a/lib/rdpanel_button.cpp b/lib/rdpanel_button.cpp index e173e396..ebe013e7 100644 --- a/lib/rdpanel_button.cpp +++ b/lib/rdpanel_button.cpp @@ -323,6 +323,45 @@ int RDPanelButton::duckVolume() const } +bool RDPanelButton::isEmpty() const +{ + return button_cart==0; +} + + +QString RDPanelButton::json(int padding,bool final) +{ + QString ret; + + ret+=RDJsonPadding(padding)+"\"button\": {\r\n"; + ret+=RDJsonField("column",button_col,4+padding); + ret+=RDJsonField("row",button_row,4+padding); + if(isEmpty()) { + ret+=RDJsonNullField("cart",4+padding); + ret+=RDJsonNullField("defaultColor",4+padding); + ret+=RDJsonNullField("length",4+padding); + ret+=RDJsonNullField("hookLength",4+padding); + ret+=RDJsonNullField("label",4+padding,true); + } + else { + ret+=RDJsonField("cart",button_cart,4+padding); + ret+=RDJsonField("defaultColor",button_default_color.name(),4+padding); + ret+=RDJsonField("length",RDGetTimeLength(button_length[0],true,false), + 4+padding); + ret+=RDJsonField("hookLength",RDGetTimeLength(button_length[1],true,false), + 4+padding); + ret+=RDJsonField("label",button_text,4+padding,true); + } + ret+=RDJsonPadding(padding)+"}"; + if(!final) { + ret+=","; + } + ret+="\r\n"; + + return ret; +} + + void RDPanelButton::tickClock() { int msecs; diff --git a/lib/rdpanel_button.h b/lib/rdpanel_button.h index 898ef472..b20062c6 100644 --- a/lib/rdpanel_button.h +++ b/lib/rdpanel_button.h @@ -21,8 +21,9 @@ #ifndef RDPANEL_BUTTON_H #define RDPANEL_BUTTON_H -#include #include +#include +#include #define RDPANEL_BUTTON_MARGIN 5 @@ -70,6 +71,8 @@ class RDPanelButton : public RDPushButton void setDuckVolume(int lvel); void setAllowDrags(bool state); void resetCounter(); + bool isEmpty() const; + QString json(int padding=0,bool final=false); signals: void cartDropped(int row,int col,unsigned cartnum,const QColor &color, diff --git a/lib/rdsound_panel.cpp b/lib/rdsound_panel.cpp index 9b0c6e56..b652fde1 100644 --- a/lib/rdsound_panel.cpp +++ b/lib/rdsound_panel.cpp @@ -28,6 +28,7 @@ #include "rdlog_line.h" #include "rdmacro.h" #include "rdsound_panel.h" +#include "rdweb.h" RDSoundPanel::RDSoundPanel(int station_panels,int user_panels,bool flash, const QString &caption,const QString &label_template, @@ -35,6 +36,7 @@ RDSoundPanel::RDSoundPanel(int station_panels,int user_panels,bool flash, RDCartDialog *cart_dialog,QWidget *parent) : RDWidget(parent) { + panel_dump_panel_updates=false; panel_playmode_box=NULL; panel_button_columns=PANEL_MAX_BUTTON_COLUMNS; panel_button_rows=PANEL_MAX_BUTTON_ROWS; @@ -235,6 +237,18 @@ QSizePolicy RDSoundPanel::sizePolicy() const } +bool RDSoundPanel::dumpPanelUpdates() const +{ + return panel_dump_panel_updates; +} + + +void RDSoundPanel::setDumpPanelUpdates(bool state) +{ + panel_dump_panel_updates=state; +} + + int RDSoundPanel::card(int outnum) const { return panel_card[outnum]; @@ -476,6 +490,45 @@ RDAirPlayConf::PanelType RDSoundPanel::currentType() const } +QString RDSoundPanel::json(const QString &owner,int padding,bool final) const +{ + QString ret; + QList panels=panel_panels.value(owner); + + ret+=RDJsonPadding(padding)+"\"array\": {\r\n"; + ret+=RDJsonField("owner",owner,4+padding); + + for(int i=0;i<(panels.size()-1);i++) { + ret+=panels.at(i)->json(4+padding); + } + if(panels.size()>0) { + ret+=panels.last()->json(4+padding,true); + } + + ret+=RDJsonPadding(padding)+"}"; + if(!final) { + ret+=","; + } + ret+="\r\n"; + + return ret; +} + + +QString RDSoundPanel::json(int padding) const +{ + QString ret; + + int count=0; + for(QMap >::const_iterator it=panel_panels. + begin();it!=panel_panels.end();it++) { + ret+=json(it.key(),4,++count==panel_panels.size()); + } + + return ret; +} + + void RDSoundPanel::setButton(RDAirPlayConf::PanelType type,int panel, int row,int col,unsigned cartnum, const QString &title) @@ -558,6 +611,9 @@ void RDSoundPanel::changeUser() { panel_config_panels=rda->user()->configPanels(); UpdatePanels(rda->user()->name()); + if(panel_dump_panel_updates) { + printf("{\r\n%s}\r\n",json(4).toUtf8().constData()); + } // // Remove Old Panel Names @@ -1421,7 +1477,7 @@ void RDSoundPanel::UpdatePanels(const QString &username) list=panel_panels.value(username); } for(int i=panel_panels.value(username).size();ipanelButton(k,j); diff --git a/lib/rdsound_panel.h b/lib/rdsound_panel.h index 200a529c..267446e7 100644 --- a/lib/rdsound_panel.h +++ b/lib/rdsound_panel.h @@ -55,6 +55,8 @@ class RDSoundPanel : public RDWidget ~RDSoundPanel(); QSize sizeHint() const; QSizePolicy sizePolicy() const; + bool dumpPanelUpdates() const; + void setDumpPanelUpdates(bool state); int card(int outnum) const; void setCard(int outnum,int card); int port(int outnum) const; @@ -84,6 +86,8 @@ class RDSoundPanel : public RDWidget void setPauseEnabled(bool state); int currentNumber() const; RDAirPlayConf::PanelType currentType() const; + QString json(const QString &owner,int padding=0,bool final=false) const; + QString json(int padding=0) const; public slots: void setButton(RDAirPlayConf::PanelType type,int panel,int row,int col, @@ -197,6 +201,7 @@ class RDSoundPanel : public RDWidget bool panel_onair_flag; QTimer *panel_scan_timer; QString panel_caption; + bool panel_dump_panel_updates; }; #endif // RDSOUND_PANEL_H diff --git a/lib/rdweb.cpp b/lib/rdweb.cpp index 0c31351c..a210eff5 100644 --- a/lib/rdweb.cpp +++ b/lib/rdweb.cpp @@ -206,6 +206,39 @@ QString RDJsonPadding(int padding) } +QString RDJsonEscape(const QString &str) +{ + QString ret; + + for(int i=0;icmdSwitch()->keys();i++) { + if(rda->cmdSwitch()->key(i)=="--dump-panel-updates") { + dump_panel_updates=true; + rda->cmdSwitch()->setProcessed(i,true); + } if(!rda->cmdSwitch()->processed(i)) { QMessageBox::critical(this,"RDPanel - "+tr("Error"), tr("Unknown command option")+": "+ rda->cmdSwitch()->key(i)); - exit(2); + exit(RDCoreApplication::ExitInvalidOption); } } @@ -129,6 +133,7 @@ MainWidget::MainWidget(RDConfig *c,QWidget *parent) "RDPanel", rda->panelConf()->buttonLabelTemplate(),true, panel_player,panel_cart_dialog,this); + panel_panel->setDumpPanelUpdates(dump_panel_updates); panel_panel->setPauseEnabled(rda->panelConf()->panelPauseEnabled()); panel_panel->setCard(0,rda->panelConf()->card(RDAirPlayConf::SoundPanel1Channel)); panel_panel->setPort(0,rda->panelConf()->port(RDAirPlayConf::SoundPanel1Channel)); diff --git a/rdpanel/rdpanel.h b/rdpanel/rdpanel.h index e2466a64..8b95034e 100644 --- a/rdpanel/rdpanel.h +++ b/rdpanel/rdpanel.h @@ -2,7 +2,7 @@ // // A Dedicated Cart Wall Utility for Rivendell. // -// (C) Copyright 2002-2021 Fred Gleason +// (C) Copyright 2002-2023 Fred Gleason // // 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 diff --git a/rivendell.spec.in b/rivendell.spec.in index 20449af3..faacf346 100644 --- a/rivendell.spec.in +++ b/rivendell.spec.in @@ -468,6 +468,7 @@ rm -rf $RPM_BUILD_ROOT %{_mandir}/man1/rdimport.1.gz %{_mandir}/man1/rdlogmanager.1.gz %{_mandir}/man1/rdmetadata.1.gz +%{_mandir}/man1/rdpanel.1.gz %{_mandir}/man1/rdrender.1.gz %{_mandir}/man1/rmlsend.1.gz %{_mandir}/man1/rdsinglestart.1.gz