From 333d2a3d675fa376951156ea60a70e39f4b3d0a0 Mon Sep 17 00:00:00 2001 From: schutz Date: Fri, 30 Jul 2010 17:20:30 +0200 Subject: [PATCH 1/1] Add first commit - Alpha Version --- aboutdialog.cpp | 26 +++++++ aboutdialog.h | 23 +++++++ configdialog.cpp | 48 +++++++++++++ configdialog.h | 25 +++++++ main.cpp | 20 ++++++ mainwindow.cpp | 26 +++++++ mainwindow.h | 23 +++++++ playermainwindow.cpp | 178 ++++++++++++++++++++++++++++++++++++++++++++++++ playermainwindow.h | 48 +++++++++++++ playlistmainwindow.cpp | 33 +++++++++ playlistmainwindow.h | 25 +++++++ vlc-remote.png | Bin 0 -> 5908 bytes vlcRemote.pro | 32 +++++++++ 13 files changed, 507 insertions(+) create mode 100644 aboutdialog.cpp create mode 100644 aboutdialog.h create mode 100644 configdialog.cpp create mode 100644 configdialog.h create mode 100644 main.cpp create mode 100644 mainwindow.cpp create mode 100644 mainwindow.h create mode 100644 playermainwindow.cpp create mode 100644 playermainwindow.h create mode 100644 playlistmainwindow.cpp create mode 100644 playlistmainwindow.h create mode 100644 vlc-remote.png create mode 100644 vlcRemote.pro diff --git a/aboutdialog.cpp b/aboutdialog.cpp new file mode 100644 index 0000000..e524b8b --- /dev/null +++ b/aboutdialog.cpp @@ -0,0 +1,26 @@ +#include "aboutdialog.h" +#include "ui_aboutdialog.h" + +AboutDialog::AboutDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::AboutDialog) +{ + ui->setupUi(this); +} + +AboutDialog::~AboutDialog() +{ + delete ui; +} + +void AboutDialog::changeEvent(QEvent *e) +{ + QDialog::changeEvent(e); + switch (e->type()) { + case QEvent::LanguageChange: + ui->retranslateUi(this); + break; + default: + break; + } +} diff --git a/aboutdialog.h b/aboutdialog.h new file mode 100644 index 0000000..f587fcd --- /dev/null +++ b/aboutdialog.h @@ -0,0 +1,23 @@ +#ifndef ABOUTDIALOG_H +#define ABOUTDIALOG_H + +#include + +namespace Ui { + class AboutDialog; +} + +class AboutDialog : public QDialog { + Q_OBJECT +public: + explicit AboutDialog(QWidget *parent = 0); + ~AboutDialog(); + +protected: + void changeEvent(QEvent *e); + +private: + Ui::AboutDialog *ui; +}; + +#endif // ABOUTDIALOG_H diff --git a/configdialog.cpp b/configdialog.cpp new file mode 100644 index 0000000..f397e10 --- /dev/null +++ b/configdialog.cpp @@ -0,0 +1,48 @@ +#include "configdialog.h" +#include "ui_configdialog.h" +#include +ConfigDialog::ConfigDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::ConfigDialog) +{ + ui->setupUi(this); + load(); + connect(ui->buttonBox,SIGNAL(accepted()),this,SLOT(save())); +} + +ConfigDialog::~ConfigDialog() +{ + delete ui; +} + +void ConfigDialog::changeEvent(QEvent *e) +{ + QDialog::changeEvent(e); + switch (e->type()) { + case QEvent::LanguageChange: + ui->retranslateUi(this); + break; + default: + break; + } +} +void ConfigDialog::load() +{ + + + QSettings settings; + ui->lineEdit->setText(settings.value("ip").toString()); + +} + +void ConfigDialog::save() +{ + + QSettings settings; + settings.setValue("ip",ui->lineEdit->text()); + + emit accept(); + + + +} diff --git a/configdialog.h b/configdialog.h new file mode 100644 index 0000000..7cf3fa8 --- /dev/null +++ b/configdialog.h @@ -0,0 +1,25 @@ +#ifndef CONFIGDIALOG_H +#define CONFIGDIALOG_H + +#include + +namespace Ui { + class ConfigDialog; +} + +class ConfigDialog : public QDialog { + Q_OBJECT +public: + explicit ConfigDialog(QWidget *parent = 0); + ~ConfigDialog(); +public slots: +void load(); +void save(); +protected: + void changeEvent(QEvent *e); + +private: + Ui::ConfigDialog *ui; +}; + +#endif // CONFIGDIALOG_H diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..1703289 --- /dev/null +++ b/main.cpp @@ -0,0 +1,20 @@ +#include +#include +#include "playlistmainwindow.h" +#include "playermainwindow.h" + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + + QCoreApplication::setOrganizationName("Omed"); + QCoreApplication::setOrganizationDomain("medsoft.blogspot.com/"); + QCoreApplication::setApplicationName("Maemo VLC remote"); + + PlayerMainWindow * mainwindow = new PlayerMainWindow; + + + mainwindow->showMaximized(); + + return a.exec(); +} diff --git a/mainwindow.cpp b/mainwindow.cpp new file mode 100644 index 0000000..f73bd48 --- /dev/null +++ b/mainwindow.cpp @@ -0,0 +1,26 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" + +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow) +{ + ui->setupUi(this); +} + +MainWindow::~MainWindow() +{ + delete ui; +} + +void MainWindow::changeEvent(QEvent *e) +{ + QMainWindow::changeEvent(e); + switch (e->type()) { + case QEvent::LanguageChange: + ui->retranslateUi(this); + break; + default: + break; + } +} diff --git a/mainwindow.h b/mainwindow.h new file mode 100644 index 0000000..8a43e6c --- /dev/null +++ b/mainwindow.h @@ -0,0 +1,23 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include + +namespace Ui { + class MainWindow; +} + +class MainWindow : public QMainWindow { + Q_OBJECT +public: + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + +protected: + void changeEvent(QEvent *e); + +private: + Ui::MainWindow *ui; +}; + +#endif // MAINWINDOW_H diff --git a/playermainwindow.cpp b/playermainwindow.cpp new file mode 100644 index 0000000..1b7ddbd --- /dev/null +++ b/playermainwindow.cpp @@ -0,0 +1,178 @@ +#include +#include +#include "playermainwindow.h" +#include "ui_playermainwindow.h" +#include "configdialog.h" +#include "aboutdialog.h" + +PlayerMainWindow::PlayerMainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::PlayerMainWindow) +{ + ui->setupUi(this); + + QSettings settings; + mIp = settings.value("ip").toString(); + + if ( mIp.isEmpty()) + showConfig(); + + + mTimer = new QTimer(this); + mNetManager = new QNetworkAccessManager(this); + mPlayListMainWindow = new PlayListMainWindow; + + + ui->playlistButton->setIcon(QIcon::fromTheme("notes_bullets")); + ui->previousButton->setIcon(QIcon::fromTheme("pdf_viewer_first_page")); + ui->nextButton->setIcon(QIcon::fromTheme("pdf_viewer_last_page")); + ui->playButton->setIcon(QIcon::fromTheme("camera_playback")); + ui->stopButton->setIcon(QIcon::fromTheme("camera_video_stop")); + ui->pauseButton->setIcon(QIcon::fromTheme("camera_video_pause")); + ui->fullscreenButton->setIcon(QIcon::fromTheme("general_fullsize")); + ui->volDown->setIcon(QIcon::fromTheme("statusarea_volumelevel1")); + ui->volUp->setIcon(QIcon::fromTheme("statusarea_volumelevel4")); + +#if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) + mPlayListMainWindow->setParent(this); + mPlayListMainWindow->setAttribute(Qt::WA_Maemo5StackedWindow); + mPlayListMainWindow->setAttribute(Qt::WA_Maemo5LandscapeOrientation,true); + mPlayListMainWindow->setAttribute(Qt::WA_Maemo5LandscapeOrientation,true); + setAttribute(Qt::WA_Maemo5StackedWindow); + mPlayListMainWindow->setWindowFlags(mPlayListMainWindow->windowFlags() | Qt::Window); +#endif + + connect(mTimer,SIGNAL(timeout()),this,SLOT(askStatus())); + connect(ui->actionConfiguration,SIGNAL(triggered()),this,SLOT(showConfig())); + connect(ui->actionAbout,SIGNAL(triggered()),this,SLOT(showAbout())); + connect(ui->playlistButton,SIGNAL(clicked()),mPlayListMainWindow,SLOT(show())); + connect(ui->playButton,SIGNAL(clicked()),this,SLOT(play())); + connect(ui->stopButton,SIGNAL(clicked()),this,SLOT(stop())); + connect(ui->pauseButton,SIGNAL(clicked()),this,SLOT(pause())); + connect(ui->previousButton,SIGNAL(clicked()),this,SLOT(previous())); + connect(ui->nextButton,SIGNAL(clicked()),this,SLOT(next())); + connect(ui->fullscreenButton,SIGNAL(clicked()),this,SLOT(fullscreen())); + connect(ui->volUp,SIGNAL(clicked()),this,SLOT(volUp())); + connect(ui->volDown,SIGNAL(clicked()),this,SLOT(volDown())); + connect(ui->slider,SIGNAL(sliderMoved(int)),this,SLOT(slide(int))); + + mTimer->start(5000); + +} + +PlayerMainWindow::~PlayerMainWindow() +{ + delete ui; +} + +void PlayerMainWindow::changeEvent(QEvent *e) +{ + QMainWindow::changeEvent(e); + switch (e->type()) { + case QEvent::LanguageChange: + ui->retranslateUi(this); + break; + default: + break; + } +} + +void PlayerMainWindow::play() +{ + + mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=pl_play"))); + +} +void PlayerMainWindow::stop() +{ + mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=pl_stop"))); + +} +void PlayerMainWindow::pause() +{ + mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=pl_pause"))); + +} +void PlayerMainWindow::previous() +{ + mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=pl_previous"))); + +} +void PlayerMainWindow::next() +{ + mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=pl_next"))); + +} +void PlayerMainWindow::fullscreen() +{ + mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=fullscreen"))); + +} +void PlayerMainWindow::volUp() +{ + mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=volume&val=500"))); + +} +void PlayerMainWindow::volDown() +{ + + mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=volume&val=-20"))); + +} +void PlayerMainWindow::slide(int value) +{ + mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=seek&val="+QString::number(value)+"%25"))); + +} + +void PlayerMainWindow::showConfig() +{ + ConfigDialog * dialog = new ConfigDialog; + dialog->exec(); +} +void PlayerMainWindow::showAbout() +{ + + AboutDialog * dialog = new AboutDialog; + dialog->exec(); + +} + + +void PlayerMainWindow::askStatus() +{ + + QNetworkReply * reply = mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml"))); + connect(reply,SIGNAL(readyRead()),this,SLOT(parseXmlStatus())); +} +void PlayerMainWindow::parseXmlStatus() +{ + QNetworkReply * reply = qobject_cast(sender()); + QDomDocument doc; + doc.setContent(reply->readAll()); + QDomElement docElem = doc.documentElement(); + + int volume = docElem.namedItem("volume").toElement().text().toInt(); + int length = docElem.namedItem("length").toElement().text().toInt(); + int time = docElem.namedItem("time").toElement().text().toInt(); + int position = docElem.namedItem("position").toElement().text().toInt(); + QString state =docElem.namedItem("state").toElement().text(); + + QTime timeLength(0,0,0) ; + timeLength = timeLength.addSecs(time); + +ui->timeLabel->setText(timeLength.toString("mm:ss")); + + + QDomNode infoNode = docElem.namedItem("information"); + QDomNode metaInfoNode = infoNode.namedItem("meta-information"); + QString title = metaInfoNode.namedItem("title").toElement().text(); + + if ( position >= 0 && position <=100) + ui->slider->setValue(position); + + ui->label->setText(title); + delete reply; + +} + diff --git a/playermainwindow.h b/playermainwindow.h new file mode 100644 index 0000000..7315e61 --- /dev/null +++ b/playermainwindow.h @@ -0,0 +1,48 @@ +#ifndef PLAYERMAINWINDOW_H +#define PLAYERMAINWINDOW_H + +#include +#include +#include +#include +#include "playlistmainwindow.h" +namespace Ui { + class PlayerMainWindow; +} + +class PlayerMainWindow : public QMainWindow { + Q_OBJECT +public: + explicit PlayerMainWindow(QWidget *parent = 0); + ~PlayerMainWindow(); + +public slots: + void askStatus(); + void showConfig(); + void showAbout(); + void play(); + void stop(); + void pause(); + void previous(); + void next(); + void fullscreen(); + void volUp(); + void volDown(); + void slide(int value); + + +protected slots: + void parseXmlStatus(); +protected: + void changeEvent(QEvent *e); + +private: + Ui::PlayerMainWindow *ui; + PlayListMainWindow * mPlayListMainWindow; + QNetworkAccessManager * mNetManager; + QString mIp; + QTimer * mTimer; + +}; + +#endif // PLAYERMAINWINDOW_H diff --git a/playlistmainwindow.cpp b/playlistmainwindow.cpp new file mode 100644 index 0000000..c3d3c3b --- /dev/null +++ b/playlistmainwindow.cpp @@ -0,0 +1,33 @@ +#include "playlistmainwindow.h" +#include "ui_playlistmainwindow.h" +#include +#include "configdialog.h" + + +PlayListMainWindow::PlayListMainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::PlayListMainWindow) +{ + + ui->setupUi(this); + mTimer = new QTimer(this); + +} + +PlayListMainWindow::~PlayListMainWindow() +{ + delete ui; +} + +void PlayListMainWindow::changeEvent(QEvent *e) +{ + QMainWindow::changeEvent(e); + switch (e->type()) { + case QEvent::LanguageChange: + ui->retranslateUi(this); + break; + default: + break; + } +} + diff --git a/playlistmainwindow.h b/playlistmainwindow.h new file mode 100644 index 0000000..f6e83df --- /dev/null +++ b/playlistmainwindow.h @@ -0,0 +1,25 @@ +#ifndef PLAYLISTMAINWINDOW_H +#define PLAYLISTMAINWINDOW_H + +#include +#include + +namespace Ui { + class PlayListMainWindow; +} + +class PlayListMainWindow : public QMainWindow { + Q_OBJECT +public: + explicit PlayListMainWindow(QWidget *parent = 0); + ~PlayListMainWindow(); + +protected: + void changeEvent(QEvent *e); + +private: + Ui::PlayListMainWindow *ui; + QTimer * mTimer; +}; + +#endif // PLAYLISTMAINWINDOW_H diff --git a/vlc-remote.png b/vlc-remote.png new file mode 100644 index 0000000000000000000000000000000000000000..4ff8b11b1fc8ab4fb580e8a57eb45f2729acce49 GIT binary patch literal 5908 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