diff --git a/aboutdialog.ui b/aboutdialog.ui index 2211abb..abd5cb9 100644 --- a/aboutdialog.ui +++ b/aboutdialog.ui @@ -264,7 +264,8 @@ Vladislav Kobzar ------------------- Ilya Spivakov -Matvey Adzhigirey +Matvey Adzhigirey +Stefan Slonevskiy diff --git a/bible.cpp b/bible.cpp index 1ed9890..1a8830e 100644 --- a/bible.cpp +++ b/bible.cpp @@ -178,20 +178,20 @@ Verse Bible::getCurrentVerseAndCaption(QList currentRows, BibleSettings& s Verse v; // get primary verse - getVerseAndCaption(v.primary_text,v.primary_caption,verse_id,bv.primaryBible,sets.useAbbriviation); + getVerseAndCaption(v.primary_text,v.primary_caption,v.primary_abbr,verse_id,bv.primaryBible,sets.useAbbriviation); // get secondary verse if(bv.primaryBible!=bv.secondaryBible && bv.secondaryBible!="none") - getVerseAndCaption(v.secondary_text,v.secondary_caption,verse_id,bv.secondaryBible,sets.useAbbriviation); + getVerseAndCaption(v.secondary_text,v.secondary_caption,v.secondary_abbr,verse_id,bv.secondaryBible,sets.useAbbriviation); // get trinary versse if(bv.trinaryBible!=bv.primaryBible && bv.trinaryBible!=bv.secondaryBible && bv.trinaryBible!="none") - getVerseAndCaption(v.trinary_text,v.trinary_caption,verse_id,bv.trinaryBible,sets.useAbbriviation); + getVerseAndCaption(v.trinary_text,v.trinary_caption,v.trinary_abbr,verse_id,bv.trinaryBible,sets.useAbbriviation); return v; } -void Bible::getVerseAndCaption(QString& verse, QString& caption, QString verId, QString& bibId, bool useAbbr) +void Bible::getVerseAndCaption(QString& verse, QString& caption, QString& abbr, QString verId, QString& bibId, bool useAbbr) { QString verse_old, verse_show, verse_n, verse_nold, verse_nfirst, chapter; QString book; @@ -280,18 +280,19 @@ void Bible::getVerseAndCaption(QString& verse, QString& caption, QString verId, caption = sq.value(0).toString() + caption; sq.clear(); - // Add bible abbreveation if to to use it - if(useAbbr) - { - sq.exec("SELECT abbreviation FROM BibleVersions WHERE id = " + bibId); - sq.first(); - QString abr = sq.value(0).toString().trimmed(); - if (!abr.isEmpty()) + // Add bible abbreviation if to to use it + sq.exec("SELECT abbreviation FROM BibleVersions WHERE id = " + bibId); + sq.first(); + QString abr = sq.value(0).toString().trimmed(); + if (!abr.isEmpty()) { + abbr = QString("%1").arg(abr); + if (useAbbr) caption = QString("%1 (%2)").arg(caption).arg(abr); } verse = verse.simplified(); caption = caption.simplified(); + abbr = abbr.simplified(); } QList Bible::searchBible(bool allWords, QRegExp searchExp) diff --git a/bible.hpp b/bible.hpp index 134dc42..a2a76eb 100644 --- a/bible.hpp +++ b/bible.hpp @@ -41,11 +41,14 @@ class Verse // For now both primary and secondary information is stored in // primary_text and primary_caption QString primary_text; - QString secondary_text; QString primary_caption; + QString primary_abbr; + QString secondary_text; QString secondary_caption; + QString secondary_abbr; QString trinary_text; QString trinary_caption; + QString trinary_abbr; }; class BibleSearch @@ -96,7 +99,7 @@ public slots: void getVerseRef(QString vId, QString &book, int &chapter, int &verse); int getVerseNumberLast(QString vId); QStringList getChapter(int book, int chapter); - void getVerseAndCaption(QString &verse, QString &caption, QString verId, QString &bibId, bool useAbbr); + void getVerseAndCaption(QString& verse, QString& caption, QString& abbr, QString verId, QString& bibId, bool useAbbr); int getCurrentBookRow(QString book); Verse getCurrentVerseAndCaption(QList currentRows, BibleSettings& sets, BibleVersionSettings& bv); void setBiblesId(QString& id); diff --git a/biblewidget.cpp b/biblewidget.cpp index 85e89e3..8619da4 100644 --- a/biblewidget.cpp +++ b/biblewidget.cpp @@ -376,7 +376,7 @@ void BibleWidget::on_search_button_clicked() if (!search_results.isEmpty()) // If have results, then show them { - if( not ui->result_label->isVisible() ) + if( !ui->result_label->isVisible() ) { ui->lineEditBook->clear(); hidden_splitter_state = ui->results_splitter->saveState(); diff --git a/generalsettingwidget.cpp b/generalsettingwidget.cpp index e582cb6..b8fb17b 100644 --- a/generalsettingwidget.cpp +++ b/generalsettingwidget.cpp @@ -59,7 +59,7 @@ void GeneralSettingWidget::loadSettings() loadThemes(); ui->comboBoxTheme->setCurrentIndex(themeIdList.indexOf(mySettings.currentThemeId)); - // Get display screen infomration + // Get display screen information monitors.clear(); QDesktopWidget d; int screen_count = d.screenCount(); @@ -101,6 +101,10 @@ void GeneralSettingWidget::loadSettings() ui->comboBoxControlsAlignV->setCurrentIndex(mySettings.displayControls.alignmentV); ui->comboBoxControlsAlignH->setCurrentIndex(mySettings.displayControls.alignmentH); ui->horizontalSliderOpacity->setValue(mySettings.displayControls.opacity*100); + + // Set HTTP Controls + ui->checkBoxEnableHttpServer->setChecked(mySettings.httpServerEnabled); + ui->lineEditHttpPort->setText(QString::number(mySettings.httpServerPort)); } void GeneralSettingWidget::loadThemes() @@ -139,6 +143,9 @@ GeneralSettings GeneralSettingWidget::getSettings() r = r/100; mySettings.displayControls.opacity = r; + mySettings.httpServerEnabled = ui->checkBoxEnableHttpServer->isChecked(); + mySettings.httpServerPort = ui->lineEditHttpPort->text().toInt(); + return mySettings; } diff --git a/generalsettingwidget.ui b/generalsettingwidget.ui index f2d843a..fa77a06 100644 --- a/generalsettingwidget.ui +++ b/generalsettingwidget.ui @@ -298,6 +298,58 @@ + + + + HTTP XML Feed Controls + + + + + + + 0 + 0 + + + + 5 + + + + + + + HTTP Server Port: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Enable HTTP XML feed + + + + + + diff --git a/httpserver.cpp b/httpserver.cpp new file mode 100644 index 0000000..2c642e1 --- /dev/null +++ b/httpserver.cpp @@ -0,0 +1,140 @@ +/*************************************************************************** +// +// softProjector - an open source media projection software +// Copyright (C) 2021 Vladislav Kobzar +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation version 3 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +***************************************************************************/ + +#include "httpserver.hpp" + +HttpServer::HttpServer(QObject *parent) : QObject(parent) +{ + isRunning = false; +} + +HttpServer::~HttpServer() +{ + stopServer(); +} + +void HttpServer::startServer(quint16 port) +{ + server = new QTcpServer(this); + + // waiting for the web brower to make contact, this will emit signal + connect(server, SIGNAL(newConnection()), this, SLOT(startConnection())); + + if(!server->listen(QHostAddress::Any, port)) + isRunning = false; + else + isRunning = true; +} + +void HttpServer::startConnection() +{ + QTcpSocket *socket = server->nextPendingConnection(); + connect(socket, SIGNAL(readyRead()), this, SLOT(sendData())); + connect(socket, SIGNAL(disconnected()), this, SLOT(closingClient())); +} + +void HttpServer::closingClient() +{ + QTcpSocket* socket = (QTcpSocket*)sender(); + socket->deleteLater(); +} + +void HttpServer::sendData() +{ + QTcpSocket* socket = (QTcpSocket*)sender(); + + socket->write("HTTP/1.1 200 OK\r\n"); // \r needs to be before \n + socket->write("Content-Type: text/xml\r\n"); + socket->write("Connection: close\r\n"); // Require two \r\n. + socket->write("\r\n"); + + socket->write("\r\n"); + socket->write("\r\n"); + socket->write(xmlData.toUtf8()); + socket->write("\r\n"); + + socket->disconnectFromHost(); +} + + +void HttpServer::stopServer() +{ + server->close(); + delete server; + isRunning = false; +} + +void HttpServer::setBibleText(Verse bVerse, BibleSettings &bSets) +{ + // Translation flags + bool havePrimary = ("none" != bSets.versions.primaryBible); + bool haveSecondary = ("none" != bSets.versions.secondaryBible); + bool haveTrinary = ("none" != bSets.versions.trinaryBible); + + xmlData = ""; + + xmlData += "\r\n"; + xmlData += "" + bVerse.primary_text + "\r\n"; + xmlData += "" + bVerse.primary_caption + "\r\n"; + xmlData += "" + bVerse.primary_abbr + "\r\n"; + xmlData += "\r\n"; + + if (haveSecondary) { + xmlData += "\r\n"; + xmlData += "" + bVerse.secondary_text + "\r\n"; + xmlData += "" + bVerse.secondary_caption + "\r\n"; + xmlData += "" + bVerse.secondary_abbr + "\r\n"; + xmlData += "\r\n"; + } + + if (haveTrinary) { + xmlData += "\r\n"; + xmlData += "" + bVerse.trinary_text + "\r\n"; + xmlData += "" + bVerse.trinary_caption + "\r\n"; + xmlData += "" + bVerse.trinary_abbr + "\r\n"; + xmlData += "\r\n"; + } +} + +void HttpServer::setSongText(Stanza stanza, SongSettings &sSets) +{ + xmlData = "\r\n"; + + xmlData += "" + stanza.stanza + "\r\n"; + xmlData += "" + stanza.stanzaTitle + "\r\n"; + xmlData += "" + stanza.tune + "\r\n"; + xmlData += "" + stanza.wordsBy + "\r\n"; + xmlData += "" + stanza.musicBy + "\r\n"; + xmlData += "" + QString::number(stanza.number) + "\r\n"; + xmlData += "" + QString::number(stanza.isLast) + "\r\n"; + + xmlData += "\r\n"; +} + +void HttpServer::setAnnounceText(AnnounceSlide announce, TextSettings &aSets) +{ + xmlData = "\r\n"; + xmlData += "" + announce.text + "\r\n"; + xmlData += "\r\n"; +} + +void HttpServer::setBlank() +{ + xmlData = ""; +} diff --git a/httpserver.hpp b/httpserver.hpp new file mode 100644 index 0000000..d083895 --- /dev/null +++ b/httpserver.hpp @@ -0,0 +1,68 @@ +/*************************************************************************** +// +// softProjector - an open source media projection software +// Copyright (C) 2021 Vladislav Kobzar +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation version 3 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +***************************************************************************/ + +// Simple HTTP server implementation in Qt taken from https://stackoverflow.com/a/32931195 + +#ifndef HTTPSERVER_HPP +#define HTTPSERVER_HPP + +#include +#include +#include +#include +#include +#include +#include + +#include "bible.hpp" +#include "song.hpp" +#include "announcement.hpp" + +class HttpServer : public QObject +{ + Q_OBJECT + +public: + explicit HttpServer(QObject *parent = 0); + ~HttpServer(); + void startServer(quint16 port); + void stopServer(); + void setBibleText(Verse bVerse, BibleSettings &bSets); + void setSongText(Stanza stanza, SongSettings &sSets); + void setAnnounceText(AnnounceSlide announce, TextSettings &aSets); + void setBlank(); + bool isRunning; + //QTcpSocket *socket; + +public slots: + void startConnection(); + void sendData(); + void closingClient(); + +private: + QTcpServer *server; + qint64 bytesAvailable() const; + QString xmlData; + void establishConnection(); + bool servingConnection; + +signals: +}; + +#endif diff --git a/mediawidget.cpp b/mediawidget.cpp index a353faf..8505251 100644 --- a/mediawidget.cpp +++ b/mediawidget.cpp @@ -23,8 +23,17 @@ #include "ui_mediawidget.h" #ifdef Q_OS_WIN -#include // this need for Sleep function +#include // for Sleep #endif +void qSleep(int ms) +{ +#ifdef Q_OS_WIN + Sleep(uint(ms)); +#else + struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 }; + nanosleep(&ts, NULL); +#endif +} MediaWidget::MediaWidget(QWidget *parent) : QWidget(parent), @@ -407,13 +416,7 @@ void MediaWidget::goLiveFromSchedule() { while (!isReadyToPlay) { - int ms = 1000; -#ifdef Q_OS_WIN - Sleep(uint(ms)); -#else - struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 }; - nanosleep(&ts, nullptr); -#endif + qSleep(100); } qDebug()<isVisible()<pushButtonGoLive->isEnabled(); if(ui->pushButtonGoLive->isEnabled()) diff --git a/settings.cpp b/settings.cpp index fe711a2..c329761 100644 --- a/settings.cpp +++ b/settings.cpp @@ -800,6 +800,10 @@ void Settings::loadSettings() } else if (n == "dcOpacity") general.displayControls.opacity = v.toDouble(); + else if (n == "httpEnabled") + general.httpServerEnabled = (v=="true"); + else if (n == "httpPort") + general.httpServerPort = v.toInt(); } } else if(t == "spMain") @@ -914,6 +918,11 @@ void Settings::saveSettings() gset += "\ndcIconSize = " + QString::number(general.displayControls.buttonSize); gset += QString("\ndcAlignment = %1,%2").arg(general.displayControls.alignmentV).arg(general.displayControls.alignmentH); gset += "\ndcOpacity = " + QString::number(general.displayControls.opacity); + if(general.httpServerEnabled) + gset += "\nhttpEnabled = true"; + else + gset += "\nhttpEnabled = false"; + gset += "\nhttpPort = " + QString::number(general.httpServerPort); // **** prepare softProjector main settings spset += "spSplitter = " + spMain.spSplitter.toHex(); diff --git a/settings.hpp b/settings.hpp index b3d2572..dc4e931 100644 --- a/settings.hpp +++ b/settings.hpp @@ -286,6 +286,8 @@ class GeneralSettings bool settingsChangedAll; bool settingsChangedMulti; bool settingsChangedSingle; + bool httpServerEnabled; + int httpServerPort; }; class DisplaySettings diff --git a/settingsdialog.cpp b/settingsdialog.cpp index e9cb1c0..c70d0d6 100644 --- a/settingsdialog.cpp +++ b/settingsdialog.cpp @@ -72,6 +72,8 @@ void SettingsDialog::loadSettings(GeneralSettings &sets, Theme &thm, SlideShowSe is_always_on_top = gsettings.displayIsOnTop; current_display_screen = gsettings.displayScreen; currentDisplayScreen2 = gsettings.displayScreen2; + current_http_enabled = gsettings.httpServerEnabled; + current_http_port = gsettings.httpServerPort; // Set individual items generalSettingswidget->setSettings(gsettings); @@ -154,6 +156,13 @@ void SettingsDialog::applySettings() // Redraw the screen: emit updateScreen(); + // Update HTTP server state + if(current_http_port!=gsettings.httpServerPort + || current_http_enabled!=gsettings.httpServerEnabled) + { + emit httpServerState(gsettings.httpServerEnabled,gsettings.httpServerPort); + } + // Save Settings theme.saveThemeUpdate(); @@ -161,6 +170,8 @@ void SettingsDialog::applySettings() is_always_on_top = gsettings.displayIsOnTop; current_display_screen = gsettings.displayScreen; currentDisplayScreen2 = gsettings.displayScreen2; + current_http_enabled = gsettings.httpServerEnabled; + current_http_port = gsettings.httpServerPort; } void SettingsDialog::getThemes() diff --git a/settingsdialog.hpp b/settingsdialog.hpp index 82f58b0..be074e4 100644 --- a/settingsdialog.hpp +++ b/settingsdialog.hpp @@ -52,6 +52,7 @@ public slots: BibleVersionSettings& bsets, BibleVersionSettings& bsets2); void positionsDisplayWindow(); void updateScreen(); + void httpServerState(bool& state, int& port); private: Ui::SettingsDialog *ui; @@ -59,6 +60,8 @@ public slots: int current_display_screen; int currentDisplayScreen2; bool is_always_on_top; + bool current_http_enabled; + int current_http_port; GeneralSettings gsettings; Theme theme; diff --git a/softProjector.pro b/softProjector.pro index 3d2129f..b105d27 100644 --- a/softProjector.pro +++ b/softProjector.pro @@ -88,7 +88,8 @@ SOURCES += main.cpp \ projectordisplayscreen.cpp \ imagegenerator.cpp \ spimageprovider.cpp \ - mediacontrol.cpp + mediacontrol.cpp \ + httpserver.cpp HEADERS += softprojector.hpp \ songwidget.hpp \ biblewidget.hpp \ @@ -131,7 +132,8 @@ HEADERS += softprojector.hpp \ projectordisplayscreen.hpp \ imagegenerator.hpp \ spimageprovider.hpp \ - mediacontrol.hpp + mediacontrol.hpp \ + httpserver.hpp FORMS += softprojector.ui \ songwidget.ui \ biblewidget.ui \ diff --git a/softprojector.cpp b/softprojector.cpp index be4ef7b..6632169 100644 --- a/softprojector.cpp +++ b/softprojector.cpp @@ -55,6 +55,10 @@ SoftProjector::SoftProjector(QWidget *parent) pictureWidget = new PictureWidget; mediaPlayer = new MediaWidget; mediaControls = new MediaControl(this); + httpServer = new HttpServer(); + + if (mySettings.general.httpServerEnabled) + httpServer->startServer(mySettings.general.httpServerPort); ui->setupUi(this); @@ -110,6 +114,7 @@ SoftProjector::SoftProjector(QWidget *parent) BibleVersionSettings&,BibleVersionSettings&))); connect(settingsDialog,SIGNAL(positionsDisplayWindow()),this,SLOT(positionDisplayWindow())); connect(settingsDialog,SIGNAL(updateScreen()),this,SLOT(updateScreen())); + connect(settingsDialog,SIGNAL(httpServerState(bool&,int&)),this,SLOT(httpServerState(bool&,int&))); connect(songWidget,SIGNAL(addToSchedule(Song&)),this,SLOT(addToShcedule(Song&))); connect(announceWidget,SIGNAL(addToSchedule(Announcement&)),this,SLOT(addToShcedule(Announcement&))); @@ -207,6 +212,7 @@ SoftProjector::~SoftProjector() delete shSart2; delete helpDialog; delete ui; + delete httpServer; } void SoftProjector::positionDisplayWindow() @@ -390,6 +396,15 @@ void SoftProjector::applySetting(GeneralSettings &g, Theme &t, SlideShowSettings retranslateUis(); } +void SoftProjector::httpServerState(bool &state, int &port) +{ + if (httpServer->isRunning) + httpServer->stopServer(); + + if (state) + httpServer->startServer(port); +} + void SoftProjector::closeEvent(QCloseEvent *event) { if(is_schedule_saved || schedule_file_path.isEmpty()) @@ -695,6 +710,11 @@ void SoftProjector::updateScreen() ui->actionShow->setEnabled(true); ui->actionHide->setEnabled(false); ui->actionClear->setEnabled(false); + + if (mySettings.general.httpServerEnabled) + { + httpServer->setBlank(); + } } else if ((currentRow >=0 || pType == VIDEO) && !new_list) { @@ -776,6 +796,13 @@ void SoftProjector::showBible() mySettings.bibleSets),theme.bible); } } + + if(mySettings.general.httpServerEnabled) + { + httpServer->setBibleText(bibleWidget->bible. + getCurrentVerseAndCaption(currentRows,theme.bible, + mySettings.bibleSets),theme.bible); + } } void SoftProjector::showSong(int currentRow) @@ -803,6 +830,11 @@ void SoftProjector::showSong(int currentRow) pds2->renderSongText(current_song.getStanza(currentRow),s1); } } + + if(mySettings.general.httpServerEnabled) + { + httpServer->setSongText(current_song.getStanza(currentRow),s2); + } } void SoftProjector::showAnnounce(int currentRow) @@ -819,6 +851,11 @@ void SoftProjector::showAnnounce(int currentRow) pds2->renderAnnounceText(currentAnnounce.getAnnounceSlide(currentRow),theme.announce); } } + + if(mySettings.general.httpServerEnabled) + { + httpServer->setAnnounceText(currentAnnounce.getAnnounceSlide(currentRow),theme.announce); + } } void SoftProjector::showPicture(int currentRow) diff --git a/softprojector.hpp b/softprojector.hpp index 3bcd1ee..7a04894 100644 --- a/softprojector.hpp +++ b/softprojector.hpp @@ -40,6 +40,7 @@ #include "videoinfo.hpp" #include "slideshoweditor.hpp" #include "schedule.hpp" +#include "httpserver.hpp" class QActionGroup; @@ -76,6 +77,8 @@ class SoftProjector : public QMainWindow MediaWidget *mediaPlayer; MediaControl *mediaControls; + HttpServer *httpServer; + bool showing; // whether we are currently showing to the projector Song current_song; int current_song_verse; @@ -93,6 +96,7 @@ public slots: void saveSettings(); void positionDisplayWindow(); void updateScreen(); + void httpServerState(bool &state, int &port); void setWaitCursor(); void setArrowCursor();