1 /* VLC-REMOTE for MAEMO 5
2 * Copyright (C) 2010 Schutz Sacha <istdasklar@gmail.com>, Dru Moore <usr@dru-id.co.uk>, Yann Nave <yannux@onbebop.net>
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2,
5 * or (at your option) any later version, as published by the Free
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details
13 * You should have received a copy of the GNU General Public
14 * License along with this program; if not, write to the
15 * Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include "playermainwindow.h"
22 #include "ui_playermainwindow.h"
23 #include "configdialog.h"
24 #include "aboutdialog.h"
25 #include "accountdialog.h"
26 //#include "vlcstatus.h"
28 PlayerMainWindow::PlayerMainWindow(QWidget *parent) :
30 ui(new Ui::PlayerMainWindow)
33 setWindowTitle("Vlc remote");
37 mTimer = new QTimer(this);
38 mNetManager = new QNetworkAccessManager(this);
39 mPlayListMainWindow = new PlayListMainWindow;
40 mBrowserMainWindow = new BrowseMainWindow;
47 ui->playlistButton->setIcon(QIcon::fromTheme("notes_bullets"));
48 ui->browseButton->setIcon(QIcon::fromTheme("filemanager_media_folder"));
50 ui->previousButton->setIcon(QIcon::fromTheme("pdf_viewer_first_page"));
51 ui->nextButton->setIcon(QIcon::fromTheme("pdf_viewer_last_page"));
52 ui->playpauseButton->setIcon(QIcon::fromTheme("camera_playback"));
53 ui->stopButton->setIcon(QIcon::fromTheme("camera_video_stop"));
54 //ui->pauseButton->setIcon(QIcon::fromTheme("camera_video_pause"));
55 ui->fullscreenButton->setIcon(QIcon::fromTheme("general_fullsize"));
56 ui->volDown->setIcon(QIcon::fromTheme("statusarea_volumelevel1"));
57 ui->volUp->setIcon(QIcon::fromTheme("statusarea_volumelevel4"));
58 ui->volMute->setIcon(QIcon::fromTheme("statusarea_volume_mute"));
60 ui->labelArtPortrait->setVisible(false);
61 ui->labelArtLandscape->setVisible(false);
63 ui->labelTitle->setTextFormat(Qt::RichText);
64 ui->labelArtist->setTextFormat(Qt::RichText);
65 ui->labelAlbum->setTextFormat(Qt::RichText);
68 #if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5)
70 mPlayListMainWindow->setParent(this);
71 mPlayListMainWindow->setAttribute(Qt::WA_Maemo5StackedWindow);
72 setAttribute(Qt::WA_Maemo5StackedWindow);
73 mPlayListMainWindow->setWindowFlags(mPlayListMainWindow->windowFlags() | Qt::Window);
75 mBrowserMainWindow->setParent(this);
76 mBrowserMainWindow->setAttribute(Qt::WA_Maemo5StackedWindow);
77 setAttribute(Qt::WA_Maemo5StackedWindow);
78 mBrowserMainWindow->setWindowFlags(mBrowserMainWindow->windowFlags() | Qt::Window);
80 connect(QApplication::desktop(), SIGNAL(resized(int)), this, SLOT(orientationChanged()));
84 connect(mTimer,SIGNAL(timeout()),this,SLOT(askStatus()));
85 connect(ui->actionConfiguration,SIGNAL(triggered()),this,SLOT(showConfig()));
86 connect(ui->actionAbout,SIGNAL(triggered()),this,SLOT(showAbout()));
87 connect(ui->actionPortrait,SIGNAL(triggered()),this,SLOT(setPortrait()));
88 connect(ui->actionLandscape,SIGNAL(triggered()),this,SLOT(setLandscape()));
89 connect(ui->playlistButton,SIGNAL(clicked()),mPlayListMainWindow,SLOT(show()));
90 connect(ui->playlistButton,SIGNAL(clicked()),mPlayListMainWindow,SLOT(showPlayList()));
91 connect(ui->browseButton,SIGNAL(clicked()),mBrowserMainWindow,SLOT(show()));
92 connect(ui->browseButton,SIGNAL(clicked()),mBrowserMainWindow,SLOT(showCurrentDirectory()));
94 connect(ui->playpauseButton,SIGNAL(clicked()),this,SLOT(playpause()));
95 connect(ui->stopButton,SIGNAL(clicked()),this,SLOT(stop()));
96 //connect(ui->pauseButton,SIGNAL(clicked()),this,SLOT(playpause()));
97 connect(ui->previousButton,SIGNAL(clicked()),this,SLOT(previous()));
98 connect(ui->nextButton,SIGNAL(clicked()),this,SLOT(next()));
99 connect(ui->fullscreenButton,SIGNAL(clicked()),this,SLOT(fullscreen()));
100 connect(ui->volUp,SIGNAL(clicked()),this,SLOT(volUp()));
101 connect(ui->volDown,SIGNAL(clicked()),this,SLOT(volDown()));
102 connect(ui->volMute,SIGNAL(clicked()),this,SLOT(volMute()));
103 connect(ui->slider,SIGNAL(sliderMoved(int)),this,SLOT(slide(int)));
105 connect(mPlayListMainWindow, SIGNAL(idUpdated(int,bool,QString)), this, SLOT(playlistIdUpdated(int, bool, QString)));
108 // check if last used connection is still valid or showConfig
110 QString last_ip = AccountDialog::currentIp();
111 if (!last_ip.isNull() && !last_ip.isEmpty()) {
112 QTcpSocket * socket = new QTcpSocket;
113 if(last_ip.contains(":"))
115 QStringList hostSplit = last_ip.split(":");
116 QString ip = hostSplit.at(0);
117 QString port = hostSplit.at(1);
118 socket->connectToHost(ip,port.toInt());
121 socket->connectToHost(last_ip,8080);
123 if (!socket->waitForConnected(1000)) {
129 mPlayListMainWindow->init();
130 mBrowserMainWindow->init();
144 PlayerMainWindow::~PlayerMainWindow()
149 void PlayerMainWindow::changeEvent(QEvent *e)
151 QMainWindow::changeEvent(e);
153 case QEvent::LanguageChange:
154 ui->retranslateUi(this);
161 void PlayerMainWindow::setPortrait()
163 #if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5)
164 this->setAttribute(Qt::WA_Maemo5PortraitOrientation, true);
170 void PlayerMainWindow::setLandscape()
172 #if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5)
173 this->setAttribute(Qt::WA_Maemo5LandscapeOrientation, true);
177 void PlayerMainWindow::setAutoRotate()
179 #if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5)
180 this->setAttribute(Qt::WA_Maemo5AutoOrientation, true);
184 void PlayerMainWindow::orientationChanged() {
185 QRect screenGeometry = QApplication::desktop()->screenGeometry();
186 mIsLandscape = (screenGeometry.width() > screenGeometry.height());
189 ui->labelArtPortrait->setVisible(false);
190 ui->labelArtLandscape->setVisible(true);
193 ui->labelArtLandscape->setVisible(false);
194 ui->labelArtPortrait->setVisible(true);
198 ui->labelArtLandscape->setVisible(false);
199 ui->labelArtPortrait->setVisible(false);
203 void PlayerMainWindow::playpause()
205 // NB. There is no guarentee that our current state is the real current state.
206 // This is due to the polling frequency and possibility of user interaction directly on the server.
207 // Still this is probably better than nothing and our next real poll will set us straight again.
208 if (PAUSED == mCurrentStatus.state) {
209 mCurrentStatus.state = PLAYING;
211 updateUiWithCurrentStatus();
213 else if (PLAYING == mCurrentStatus.state) {
214 mCurrentStatus.state = PAUSED;
216 updateUiWithCurrentStatus();
219 // could be STOP or UNKNOWN, either way there is no guarentee we will enter a playing state next.
220 // So don't update the current state or UI
221 // Ideally we would try to find a way to check the current state again but this could lead to an infinite loop!
225 void PlayerMainWindow::play()
227 mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=pl_play")));
229 void PlayerMainWindow::stop()
231 mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=pl_stop")));
233 void PlayerMainWindow::pause()
235 mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=pl_pause")));
237 void PlayerMainWindow::previous()
239 mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=pl_previous")));
241 void PlayerMainWindow::next()
243 mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=pl_next")));
245 void PlayerMainWindow::fullscreen()
247 mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=fullscreen")));
249 void PlayerMainWindow::volUp()
251 QUrl url = QUrl("http://"+mIp+"/requests/status.xml?command=volume");
252 url.addEncodedQueryItem(QByteArray("val"), QByteArray("%2B20"));
253 mNetManager->get(QNetworkRequest(url));
255 void PlayerMainWindow::volDown()
257 mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=volume&val=-20")));
259 void PlayerMainWindow::volMute()
261 this->mMuted = !this->mMuted;
263 mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=volume&val=0")));
266 mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=volume&val="+QString::number(this->mVolume))));
269 void PlayerMainWindow::slide(int value)
271 mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=seek&val="+QString::number(value)+"%25")));
274 void PlayerMainWindow::showConfig()
277 AccountDialog * dialog = new AccountDialog;
280 mIp= AccountDialog::currentIp();
282 mPlayListMainWindow->init();
283 mBrowserMainWindow->init();
287 void PlayerMainWindow::showAbout()
290 AboutDialog * dialog = new AboutDialog;
295 void PlayerMainWindow::askStatus()
298 QNetworkReply * reply = mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml")));
299 connect(reply,SIGNAL(readyRead()),this,SLOT(parseXmlStatus()));
302 void PlayerMainWindow::parseXmlStatus()
304 QNetworkReply * reply = qobject_cast<QNetworkReply*>(sender());
306 doc.setContent(reply->readAll());
308 QDomElement docElem = doc.documentElement();
309 // Get the raw values
310 int volume = docElem.namedItem("volume").toElement().text().toInt();
311 int length = docElem.namedItem("length").toElement().text().toInt();
312 int time = docElem.namedItem("time").toElement().text().toInt();
313 int position = docElem.namedItem("position").toElement().text().toInt();
314 int random = docElem.namedItem("random").toElement().text().toInt();
315 int loop = docElem.namedItem("loop").toElement().text().toInt();
316 int repeat = docElem.namedItem("repeat").toElement().text().toInt();
317 QString state = docElem.namedItem("state").toElement().text();
318 QDomNode infoNode = docElem.namedItem("information");
319 QDomNode metaInfoNode = infoNode.namedItem("meta-information");
320 QString title = metaInfoNode.namedItem("title").toElement().text().replace("\\\\", "\\");
321 // if it's a file style title fix it up
322 if (40 < title.length()) {
323 if (0 < title.lastIndexOf("\\")) {
324 title = title.right(title.length() - (title.lastIndexOf("\\") + 1));
326 else if (0 < title.lastIndexOf("/")) {
327 title = title.right(title.length() - (title.lastIndexOf("/") + 1));
330 QString artist = metaInfoNode.namedItem("artist").toElement().text();
331 QString album = metaInfoNode.namedItem("album").toElement().text();
332 QString now_playing = metaInfoNode.namedItem("now_playing").toElement().text();
333 QString art_url = metaInfoNode.namedItem("art_url").toElement().text();
334 // Populate the current status structure
335 // now would be a good time to work out if we are a new track / file or not.
336 // key if we are going to look for album art later
337 // for now we check length and title this will require further examination later
338 mCurrentStatus.newtrack = true;
339 if (mCurrentStatus.length == length && !mCurrentStatus.title.isNull() && 0 == QString::compare(mCurrentStatus.title, title)) {
340 mCurrentStatus.newtrack = false;
342 mCurrentStatus.volume = volume;
343 mCurrentStatus.length = length;
344 mCurrentStatus.time = time;
345 mCurrentStatus.position = position;
346 mCurrentStatus.random = (1 == random);
347 mCurrentStatus.loop = (1 == loop);
348 mCurrentStatus.repeat = (1 == repeat);
349 mCurrentStatus.title = title;
350 mCurrentStatus.artist = artist;
351 mCurrentStatus.album = album;
352 mCurrentStatus.nowplaying = now_playing;
353 mCurrentStatus.hasart = (!art_url.isNull() && !art_url.isEmpty());
354 if (!state.isNull() && !state.isEmpty()) {
355 if (0 == QString::compare("playing", state, Qt::CaseInsensitive)) {
356 mCurrentStatus.state = PLAYING;
358 else if (0 == QString::compare("paused", state, Qt::CaseInsensitive)) {
359 mCurrentStatus.state = PAUSED;
361 else if (0 == QString::compare("stop", state, Qt::CaseInsensitive)) {
362 mCurrentStatus.state = STOP;
365 mCurrentStatus.state = UNKNOWN;
369 mCurrentStatus.state = UNKNOWN;
371 // What's our mute status?
372 if (0 < mCurrentStatus.volume) {
373 this->mVolume = mCurrentStatus.volume;
374 this->mMuted = false;
380 updateUiWithCurrentStatus();
384 void PlayerMainWindow::updateUiWithCurrentStatus() {
386 QTime timePosition(0,0,0) ;
387 timePosition = timePosition.addSecs(mCurrentStatus.time);
389 ui->timeLabel->setText(timePosition.toString("h:mm:ss"));
392 if (0 < mCurrentStatus.length) {
393 QTime timeDuration(0,0,0) ;
394 timeDuration = timeDuration.addSecs(mCurrentStatus.length);
396 ui->durationLabel->setText(timeDuration.toString("h:mm:ss"));
399 ui->durationLabel->setText("0:00:00");
403 if (mCurrentStatus.position >= 0 && mCurrentStatus.position <= 100)
404 ui->slider->setValue(mCurrentStatus.position);
406 ui->labelTitle->setText(mCurrentStatus.title);
407 ui->labelArtist->setText(mCurrentStatus.artist);
408 ui->labelAlbum->setText(mCurrentStatus.album);
410 if (PLAYING == mCurrentStatus.state) {
411 ui->playpauseButton->setIcon(QIcon::fromTheme("camera_video_pause"));
414 ui->playpauseButton->setIcon(QIcon::fromTheme("camera_playback"));
417 if (mCurrentStatus.newtrack) {
418 // potential actions:
419 // rebuild display layout
420 // retrieve album art
422 mPlayListMainWindow->requestPlayList();
424 // Update the buttons on the playlist window
425 if (NULL != this->mPlayListMainWindow) {
426 this->mPlayListMainWindow->updateUiWithCurrentStatus(& mCurrentStatus);
430 void PlayerMainWindow::playlistIdUpdated(int id, bool hasart, QString extension) {
435 ui->labelArtLandscape->setVisible(false);
436 ui->labelArtPortrait->setVisible(false);
437 // could use a default graphic here!
438 // setCoverArtFromPixmap();
441 void PlayerMainWindow::readReady() {
442 QNetworkReply * reply = qobject_cast<QNetworkReply*>(sender());
444 mResponse += reply->readAll();
446 void PlayerMainWindow::finished(QNetworkReply * reply) {
447 // now we can call setCoverArt to process the full buffers
448 this->setCoverArt(mResponse);
449 // only interested in finished signals
450 disconnect(mNetManager,SIGNAL(finished(QNetworkReply *)),this,SLOT(finished(QNetworkReply *)));
452 void PlayerMainWindow::getCoverArt(int id) {
454 QNetworkReply * reply = mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/art?id=" + QString::number(id))));
455 connect(reply,SIGNAL(readyRead()),this,SLOT(readReady()));
456 connect(mNetManager,SIGNAL(finished(QNetworkReply *)),this,SLOT(finished(QNetworkReply *)));
459 void PlayerMainWindow::setCoverArt(const QByteArray data) {
460 QPixmap* image = new QPixmap();
461 if (image->loadFromData(data)) {
463 ui->labelArtLandscape->setPixmap(image->scaledToHeight(120, Qt::SmoothTransformation));
464 ui->labelArtPortrait->setPixmap(image->scaledToHeight(310, Qt::SmoothTransformation));
466 ui->labelArtPortrait->setVisible(false);
467 ui->labelArtLandscape->setVisible(true);
470 ui->labelArtLandscape->setVisible(false);
471 ui->labelArtPortrait->setVisible(true);
475 ui->labelArtPortrait->setVisible(false);
476 ui->labelArtLandscape->setVisible(false);
479 void PlayerMainWindow::setCoverArtFromPixmap(QPixmap image) {
481 ui->labelArtLandscape->setPixmap(image.scaledToHeight(120, Qt::SmoothTransformation));
482 ui->labelArtPortrait->setPixmap(image.scaledToHeight(310, Qt::SmoothTransformation));
484 ui->labelArtPortrait->setVisible(false);
485 ui->labelArtLandscape->setVisible(true);
488 ui->labelArtLandscape->setVisible(false);
489 ui->labelArtPortrait->setVisible(true);