From f1d16ccd1936a711541e26f935477cd9764bdcb6 Mon Sep 17 00:00:00 2001 From: A/V User Date: Sun, 25 Jul 2021 01:11:40 -0500 Subject: [PATCH] Add viewer of slides in current song and combobox for song selection --- SlideController.pro | 2 +- SlideController.pro.user | 10 ++-- mainwindow.cpp | 22 +++---- obsclient.hpp | 2 - openlpclient.cpp | 120 ++++++++++++++++++++++++++++++++++++++- openlpclient.hpp | 38 +++++++++++++ slideview.cpp | 62 +++++++++++++++++++- slideview.hpp | 23 +++++++- 8 files changed, 254 insertions(+), 25 deletions(-) diff --git a/SlideController.pro b/SlideController.pro index 494fbd8..daba2c1 100644 --- a/SlideController.pro +++ b/SlideController.pro @@ -1,6 +1,6 @@ QT += core gui -greaterThan(QT_MAJOR_VERSION, 4): QT += webenginewidgets widgets +greaterThan(QT_MAJOR_VERSION, 4): QT += network widgets CONFIG += c++17 diff --git a/SlideController.pro.user b/SlideController.pro.user index e01bf2e..98d8b4b 100644 --- a/SlideController.pro.user +++ b/SlideController.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId @@ -91,7 +91,7 @@ Desktop Qt 5.15.2 MSVC2019 64bit Desktop Qt 5.15.2 MSVC2019 64bit qt.qt5.5152.win64_msvc2019_64_kit - 0 + 1 0 0 @@ -294,12 +294,14 @@ 2 - ProjectExplorer.CustomExecutableRunConfiguration - + Qt4ProjectManager.Qt4RunConfiguration:C:/Users/avuser/Documents/SlideController/SlideController.pro + C:/Users/avuser/Documents/SlideController/SlideController.pro false true + true false true + C:/Users/avuser/Documents/build-SlideController-Desktop_Qt_5_15_2_MSVC2019_64bit-Release 1 diff --git a/mainwindow.cpp b/mainwindow.cpp index b59e423..0928b87 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -4,8 +4,8 @@ #include #include #include -#include +#include "slideview.hpp" #include "mainwindow.hpp" MainWindow::MainWindow(QWidget *parent): QMainWindow(parent) { @@ -14,16 +14,13 @@ MainWindow::MainWindow(QWidget *parent): QMainWindow(parent) { setWindowTitle(tr("Slide Controller 9000")); const auto mainWidget = new QWidget(this); const auto rootLyt = new QVBoxLayout; - const auto viewsLayout = new QHBoxLayout; + //const auto viewsLayout = new QHBoxLayout; const auto controlsLayout = new QGridLayout; - const auto slideView = new QWebEngineView(mainWidget); + const auto slideView = new SlideView(this); setCentralWidget(mainWidget); mainWidget->setLayout(rootLyt); - viewsLayout->addWidget(slideView, 1); - viewsLayout->setSizeConstraint(QLayout::SetFixedSize); - rootLyt->addLayout(viewsLayout); + rootLyt->addWidget(slideView); rootLyt->addLayout(controlsLayout); - slideView->setUrl(QUrl("http://127.0.0.1:4316/main")); // setup slide controls const auto btnPrevSong = new QPushButton(tr("Previous Song (Left)"), this); const auto btnPrevSlide = new QPushButton(tr("Previous Slide (Up)"), this); @@ -32,9 +29,9 @@ MainWindow::MainWindow(QWidget *parent): QMainWindow(parent) { const auto btnBlankSlides = new QPushButton(tr("Blank Slides (,)"), this); const auto btnShowSlides = new QPushButton(tr("Show Slides (.)"), this); rootLyt->addLayout(controlsLayout); - controlsLayout->addWidget(btnPrevSong, 0, 0); - controlsLayout->addWidget(btnPrevSlide, 0, 1); - controlsLayout->addWidget(btnNextSlide, 1, 0); + controlsLayout->addWidget(btnPrevSlide, 0, 0); + controlsLayout->addWidget(btnNextSlide, 0, 1); + controlsLayout->addWidget(btnPrevSong, 1, 0); controlsLayout->addWidget(btnNextSong, 1, 1); controlsLayout->addWidget(btnBlankSlides, 2, 0); controlsLayout->addWidget(btnShowSlides, 2, 1); @@ -52,6 +49,11 @@ MainWindow::MainWindow(QWidget *parent): QMainWindow(parent) { connect(btnBlankSlides, &QPushButton::clicked, &m_openlpClient, &OpenLPClient::blankScreen); connect(btnBlankSlides, &QPushButton::clicked, &m_obsClient, &OBSClient::hideSlides); connect(btnShowSlides, &QPushButton::clicked, &m_openlpClient, &OpenLPClient::showSlides); + connect(&m_openlpClient, &OpenLPClient::pollUpdate, slideView, &SlideView::pollUpdate); + connect(&m_openlpClient, &OpenLPClient::songListUpdate, slideView, &SlideView::songListUpdate); + connect(&m_openlpClient, &OpenLPClient::slideListUpdate, slideView, &SlideView::slideListUpdate); + connect(slideView, &SlideView::songChanged, &m_openlpClient, &OpenLPClient::changeSong); + connect(slideView, &SlideView::slideChanged, &m_openlpClient, &OpenLPClient::changeSlide); // setup scene selector const auto btnObsHideSlides = new QPushButton(tr("Hide Slides in OBS (;)"), mainWidget); const auto btnObsShowSlides = new QPushButton(tr("Show Slides in OBS (')"), mainWidget); diff --git a/obsclient.hpp b/obsclient.hpp index 667cc10..3d6d17d 100644 --- a/obsclient.hpp +++ b/obsclient.hpp @@ -25,7 +25,5 @@ class OBSClient : public QObject private: void get(QString url); - signals: - }; diff --git a/openlpclient.cpp b/openlpclient.cpp index 59faf6c..ed96922 100644 --- a/openlpclient.cpp +++ b/openlpclient.cpp @@ -1,9 +1,19 @@ - +#include +#include +#include +#include +#include #include "openlpclient.hpp" OpenLPClient::OpenLPClient(QObject *parent): QObject(parent) { - + poll(); + m_pollTimer.start(500); + connect(&m_pollTimer, &QTimer::timeout, this, &OpenLPClient::poll); + connect(m_nam, &QNetworkAccessManager::finished, this, &OpenLPClient::handleGeneralResponse); + connect(m_songListNam, &QNetworkAccessManager::finished, this, &OpenLPClient::handleSongListResponse); + connect(m_slideListNam, &QNetworkAccessManager::finished, this, &OpenLPClient::handleSlideListResponse); + connect(m_pollingNam, &QNetworkAccessManager::finished, this, &OpenLPClient::handlePollResponse); } void OpenLPClient::nextSlide() { @@ -30,8 +40,114 @@ void OpenLPClient::showSlides() { get("/api/display/show"); } +void OpenLPClient::changeSong(int it) { + auto n = QString::number(it); + auto url = "/api/service/set?data=%7B%22request%22%3A+%7B%22id%22%3A+" + n + "%7D%7D&_=1627181837297"; + get(url); +} + +void OpenLPClient::changeSlide(int slide) { + auto n = QString::number(slide); + auto url = R"(/api/controller/live/set?data={"request"%3A+{"id"%3A)" + n + "}}&_=1626628079579)"; + get(url); +} + void OpenLPClient::get(QString urlExt) { QUrl url(QString(BaseUrl) + urlExt); QNetworkRequest rqst(url); m_nam->get(rqst); } + +void OpenLPClient::requestSongList() { + QUrl url(QString(BaseUrl) + "/api/service/list?_=1626628079579"); + QNetworkRequest rqst(url); + m_songListNam->get(rqst); +} + +void OpenLPClient::requestSlideList() { + QUrl url(QString(BaseUrl) + "/api/controller/live/text?_=1626628079579"); + QNetworkRequest rqst(url); + m_slideListNam->get(rqst); +} + +void OpenLPClient::poll() { + QUrl url(QString(BaseUrl) + "/api/poll?_=1626628079579"); + QNetworkRequest rqst(url); + m_pollingNam->get(rqst); +} + +void OpenLPClient::handleGeneralResponse(QNetworkReply *reply) { + if (reply->error()) { + qDebug() << reply->request().url() << ":" << reply->errorString(); + } +} + +void OpenLPClient::handlePollResponse(QNetworkReply *reply) { + if (reply->error()) { + qDebug() << reply->errorString(); + } + auto data = reply->readAll(); + if (data.isEmpty()) { + return; + } + auto doc = QJsonDocument::fromJson(data); + auto obj = doc.object()["results"].toObject(); + auto songId = obj["item"].toString(); + auto slide = obj["slide"].toInt(); + auto service = obj["service"].toInt(); + if (service != m_currentServiceId) { + requestSongList(); + m_currentServiceId = service; + } + if (m_currentSongId != songId) { + requestSlideList(); + m_currentSongId = songId; + } + emit pollUpdate(m_songNameMap[songId], slide); +} + +void OpenLPClient::handleSongListResponse(QNetworkReply *reply) { + if (reply->error()) { + qDebug() << reply->errorString(); + } + auto data = reply->readAll(); + if (data.isEmpty()) { + return; + } + QStringList songList; + auto doc = QJsonDocument::fromJson(data); + auto items = doc.object()["results"].toObject()["items"].toArray(); + m_songIdMap.clear(); + m_songNameMap.clear(); + for (const auto &item : items) { + auto song = item.toObject(); + auto name = song["title"].toString(); + auto id = song["id"].toString(); + m_songIdMap[name] = id; + m_songNameMap[id] = name; + songList.push_back(name); + } + emit songListUpdate(songList); +} + +void OpenLPClient::handleSlideListResponse(QNetworkReply *reply) { + if (reply->error()) { + qDebug() << reply->errorString(); + } + auto data = reply->readAll(); + if (data.isEmpty()) { + return; + } + QStringList slideList; + QStringList tagList; + auto doc = QJsonDocument::fromJson(data); + auto items = doc.object()["results"].toObject()["slides"].toArray(); + for (const auto &item : items) { + auto slide = item.toObject(); + auto text = slide["text"].toString(); + auto tag = slide["tag"].toString(); + slideList.push_back(text); + tagList.push_back(tag); + } + emit slideListUpdate(tagList, slideList); +} diff --git a/openlpclient.hpp b/openlpclient.hpp index ac75955..56cd16d 100644 --- a/openlpclient.hpp +++ b/openlpclient.hpp @@ -1,13 +1,27 @@ #pragma once +#include #include #include +#include class OpenLPClient: public QObject { Q_OBJECT private: + struct Song { + QString name; + QString id; + }; static constexpr auto BaseUrl = "http://127.0.0.1:4316"; QNetworkAccessManager *m_nam = new QNetworkAccessManager(this); + QNetworkAccessManager *m_pollingNam = new QNetworkAccessManager(this); + QNetworkAccessManager *m_songListNam = new QNetworkAccessManager(this); + QNetworkAccessManager *m_slideListNam = new QNetworkAccessManager(this); + QTimer m_pollTimer; + QHash m_songIdMap; + QHash m_songNameMap; + int m_currentServiceId = -1; + QString m_currentSongId; public: explicit OpenLPClient(QObject *parent = nullptr); @@ -25,10 +39,34 @@ class OpenLPClient: public QObject { void showSlides(); + void changeSong(int it); + + void changeSlide(int slide); + private: void get(QString url); + void requestSongList(); + + void requestSlideList(); + + private slots: + void poll(); + + void handleGeneralResponse(QNetworkReply *reply); + + void handlePollResponse(QNetworkReply *reply); + + void handleSongListResponse(QNetworkReply *reply); + + void handleSlideListResponse(QNetworkReply *reply); + signals: + void pollUpdate(QString songId, int slideNum); + + void songListUpdate(QStringList); + + void slideListUpdate(QStringList, QStringList); }; diff --git a/slideview.cpp b/slideview.cpp index 77b7c6b..a70fcc4 100644 --- a/slideview.cpp +++ b/slideview.cpp @@ -1,6 +1,62 @@ +#include +#include +#include +#include +#include + #include "slideview.hpp" -SlideView::SlideView(QWidget *parent) : QWidget(parent) -{ - +SlideView::SlideView(QWidget *parent): QWidget(parent) { + auto lyt = new QVBoxLayout(this); + m_songSelector = new QComboBox(this); + m_slideTable = new QTableWidget(this); + auto header = m_slideTable->horizontalHeader(); + header->setVisible(false); + header->setStretchLastSection(true); + m_slideTable->setSelectionBehavior(QTableWidget::SelectionBehavior::SelectRows); + m_slideTable->setSelectionMode(QTableWidget::SelectionMode::SingleSelection); + m_slideTable->setColumnCount(1); + connect(header, &QHeaderView::sectionResized, m_slideTable, &QTableWidget::resizeRowsToContents); + m_slideTable->resizeRowsToContents(); + m_slideTable->verticalHeader()->setDefaultSectionSize(300); + lyt->addWidget(m_songSelector); + lyt->addWidget(m_slideTable); + connect(m_slideTable, &QTableWidget::currentCellChanged, this, &SlideView::slideChanged); +} + +void SlideView::pollUpdate(QString songName, int slide) { + if (songName != m_currentSong) { + m_currentSong = songName; + m_songSelector->setCurrentText(songName); + } + if (slide != m_currentSlide) { + m_currentSlide = slide; + m_slideTable->setCurrentCell(slide, 0); + } +} + +void SlideView::changeSong(int song) { + if (m_songSelector->currentText() != m_currentSong) { + emit songChanged(song); + } +} + +void SlideView::slideListUpdate(QStringList tagList, QStringList slideList) { + m_currentSlide = -1; + m_slideTable->setRowCount(slideList.size()); + for (int i = 0; i < slideList.size(); ++i) { + auto txt = slideList[i]; + auto item = new QTableWidgetItem(txt); + item->setFlags(item->flags() & ~Qt::ItemIsEditable); + m_slideTable->setItem(i, 0, item); + } + m_slideTable->setVerticalHeaderLabels(tagList); +} + +void SlideView::songListUpdate(QStringList songList) { + disconnect(m_songSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(changeSong(int))); + m_songSelector->clear(); + m_songSelector->addItems(songList); + changeSong(0); + connect(m_songSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(changeSong(int))); } diff --git a/slideview.hpp b/slideview.hpp index 34a917a..b61bfe5 100644 --- a/slideview.hpp +++ b/slideview.hpp @@ -5,10 +5,27 @@ class SlideView : public QWidget { Q_OBJECT -public: - explicit SlideView(QWidget *parent = nullptr); + private: + class QTableWidget *m_slideTable = nullptr; + class QComboBox *m_songSelector = nullptr; + QString m_currentSong; + int m_currentSlide = -1; + public: + explicit SlideView(QWidget *parent = nullptr); -signals: + public slots: + void pollUpdate(QString songId, int slideNum); + void songListUpdate(QStringList songList); + + void slideListUpdate(QStringList tagList, QStringList songList); + + private slots: + void changeSong(int song); + + signals: + void songChanged(int); + + void slideChanged(int); };