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 "settingsdialog.h"
27 #include "appsettings.h"
28 #if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5)
29 #include <QMaemo5InformationBox>
30 #include <mce/dbus-names.h>
31 #include <mce/mode-names.h>
32 #include <QDBusConnection>
33 #include <QDBusMessage>
34 #include <QDBusInterface>
36 #include <QMessageBox>
38 #if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5)
39 QDBusConnection PlayerMainWindow::dBusConnection = QDBusConnection::systemBus();
40 QDBusInterface* PlayerMainWindow::dBusInterface = new QDBusInterface(MCE_SERVICE, MCE_REQUEST_PATH,
41 MCE_REQUEST_IF, dBusConnection);
44 PlayerMainWindow::PlayerMainWindow(QWidget *parent) :
46 ui(new Ui::PlayerMainWindow)
49 setWindowTitle("Vlc remote");
51 mIsFirstStatusCall = true;
53 mTimer = new QTimer(this);
54 mNetManager = new QNetworkAccessManager(this);
55 mPlayListMainWindow = new PlayListMainWindow;
56 mBrowserMainWindow = new BrowseMainWindow;
57 mFavouritesMainWindow = new FavouritesMainWindow;
64 ui->playlistButton->setIcon(QIcon::fromTheme("notes_bullets"));
65 ui->browseButton->setIcon(QIcon::fromTheme("filemanager_media_folder"));
67 ui->previousButton->setIcon(QIcon::fromTheme("pdf_viewer_first_page"));
68 ui->nextButton->setIcon(QIcon::fromTheme("pdf_viewer_last_page"));
69 ui->playpauseButton->setIcon(QIcon::fromTheme("camera_playback"));
70 ui->stopButton->setIcon(QIcon::fromTheme("camera_video_stop"));
71 ui->fullscreenButton->setIcon(QIcon::fromTheme("general_fullsize"));
72 ui->volDown->setIcon(QIcon::fromTheme("statusarea_volumelevel1"));
73 ui->volUp->setIcon(QIcon::fromTheme("statusarea_volumelevel4"));
74 ui->volMute->setIcon(QIcon::fromTheme("statusarea_volume_mute"));
76 ui->labelArtPortrait->setVisible(false);
77 ui->labelArtLandscape->setVisible(false);
79 ui->labelTitle->setTextFormat(Qt::RichText);
80 ui->labelArtist->setTextFormat(Qt::RichText);
81 ui->labelAlbum->setTextFormat(Qt::RichText);
84 #if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5)
85 // Handle screen state on / off
86 dBusConnection.connect(MCE_SERVICE, MCE_SIGNAL_PATH, MCE_SIGNAL_IF,
87 MCE_DISPLAY_SIG, this, SLOT(displayStateChanged(const QDBusMessage &)));
89 mPlayListMainWindow->setParent(this);
90 mPlayListMainWindow->setAttribute(Qt::WA_Maemo5StackedWindow, true);
91 setAttribute(Qt::WA_Maemo5StackedWindow, true);
92 mPlayListMainWindow->setWindowFlags(mPlayListMainWindow->windowFlags() | Qt::Window);
94 mBrowserMainWindow->setParent(this);
95 mBrowserMainWindow->setAttribute(Qt::WA_Maemo5StackedWindow, true);
96 setAttribute(Qt::WA_Maemo5StackedWindow, true);
97 mBrowserMainWindow->setWindowFlags(mBrowserMainWindow->windowFlags() | Qt::Window);
99 mFavouritesMainWindow->setParent(this);
100 mFavouritesMainWindow->setAttribute(Qt::WA_Maemo5StackedWindow, true);
101 setAttribute(Qt::WA_Maemo5StackedWindow, true);
102 mFavouritesMainWindow->setWindowFlags(mFavouritesMainWindow->windowFlags() | Qt::Window);
104 connect(QApplication::desktop(), SIGNAL(resized(int)), this, SLOT(orientationChanged()));
108 connect(mTimer,SIGNAL(timeout()),this,SLOT(askStatus()));
109 connect(ui->actionSettings,SIGNAL(triggered()),this,SLOT(showSettings()));
110 connect(ui->actionConfiguration,SIGNAL(triggered()),this,SLOT(showConfig()));
111 connect(ui->actionAbout,SIGNAL(triggered()),this,SLOT(showAbout()));
112 connect(ui->actionFavourites,SIGNAL(triggered()),this,SLOT(showFavourites()));
113 //connect(ui->actionPortrait,SIGNAL(triggered()),this,SLOT(setPortrait()));
114 //connect(ui->actionLandscape,SIGNAL(triggered()),this,SLOT(setLandscape()));
115 //connect(ui->actionAutoRotate,SIGNAL(triggered()),this,SLOT(setAutoRotate()));
116 connect(ui->playlistButton,SIGNAL(clicked()),mPlayListMainWindow,SLOT(show()));
117 connect(ui->playlistButton,SIGNAL(clicked()),mPlayListMainWindow,SLOT(showPlayList()));
118 connect(ui->browseButton,SIGNAL(clicked()),mBrowserMainWindow,SLOT(show()));
119 connect(ui->browseButton,SIGNAL(clicked()),mBrowserMainWindow,SLOT(showCurrentDirectory()));
121 connect(ui->playpauseButton,SIGNAL(clicked()),this,SLOT(playpause()));
122 connect(ui->stopButton,SIGNAL(clicked()),this,SLOT(stop()));
123 connect(ui->previousButton,SIGNAL(clicked()),this,SLOT(previous()));
124 connect(ui->nextButton,SIGNAL(clicked()),this,SLOT(next()));
125 connect(ui->fullscreenButton,SIGNAL(clicked()),this,SLOT(fullscreen()));
126 connect(ui->volUp,SIGNAL(clicked()),this,SLOT(volUp()));
127 connect(ui->volDown,SIGNAL(clicked()),this,SLOT(volDown()));
128 connect(ui->volMute,SIGNAL(clicked()),this,SLOT(volMute()));
129 connect(ui->slider,SIGNAL(sliderMoved(int)),this,SLOT(slide(int)));
131 connect(mPlayListMainWindow, SIGNAL(idUpdated(int,bool,QString)), this, SLOT(playlistIdUpdated(int, bool, QString)));
132 connect(mBrowserMainWindow, SIGNAL(showFavouritesWindow()), this, SLOT(showFavourites()));
134 connect(mFavouritesMainWindow, SIGNAL(browseDirectory(QString)), mFavouritesMainWindow, SLOT(close()));
135 connect(mFavouritesMainWindow, SIGNAL(browseDirectory(QString)), mBrowserMainWindow, SLOT(browseDirectory(QString)));
136 connect(mFavouritesMainWindow, SIGNAL(closeSignal()), mBrowserMainWindow, SLOT(show()));
139 // check if last used connection is still valid or showConfig
142 if (AppSettings::isConnected()) {
144 QString last_ip = AppSettings::getCurrentIp(); // AccountDialog::currentIp();
145 if (!last_ip.isNull() && !last_ip.isEmpty()) {
146 QTcpSocket * socket = new QTcpSocket;
147 if(last_ip.contains(":"))
149 QStringList hostSplit = last_ip.split(":");
150 QString ip = hostSplit.at(0);
151 QString port = hostSplit.at(1);
152 socket->connectToHost(ip,port.toInt());
155 socket->connectToHost(last_ip,8080);
157 if (!socket->waitForConnected(AppSettings::getConnectionTimeout())) {
163 mPlayListMainWindow->init();
164 mBrowserMainWindow->init();
165 mTimer->start(AppSettings::getStatusPollTimeout());
175 #if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5)
176 QMaemo5InformationBox::information(this, tr("Network unavailable!"), QMaemo5InformationBox::DefaultTimeout);
183 PlayerMainWindow::~PlayerMainWindow()
188 void PlayerMainWindow::changeEvent(QEvent *e)
190 QMainWindow::changeEvent(e);
192 case QEvent::LanguageChange:
193 ui->retranslateUi(this);
200 #if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5)
201 void PlayerMainWindow::displayStateChanged(const QDBusMessage &message)
203 QString state = message.arguments().at(0).toString();
204 if (!state.isEmpty()) {
205 if (state == MCE_DISPLAY_ON_STRING) {
206 mTimer->start(AppSettings::getStatusPollTimeout());
208 else if (state == MCE_DISPLAY_OFF_STRING) {
215 void PlayerMainWindow::showFavourites() {
216 mFavouritesMainWindow->show();
217 mFavouritesMainWindow->init();
220 void PlayerMainWindow::updateFromSettings()
222 #if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5)
223 switch (AppSettings::getOrientation()) {
225 this->setAttribute(Qt::WA_Maemo5LandscapeOrientation, true);
228 this->setAttribute(Qt::WA_Maemo5PortraitOrientation, true);
231 this->setAttribute(Qt::WA_Maemo5AutoOrientation, true);
235 if (AppSettings::getShowAlbumArt()) {
236 this->mIsFirstStatusCall = true;
238 mTimer->start(AppSettings::getStatusPollTimeout());
241 void PlayerMainWindow::setPortrait()
243 #if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5)
244 AppSettings::setOrientation(PORTRAIT);
245 this->setAttribute(Qt::WA_Maemo5PortraitOrientation, true);
249 void PlayerMainWindow::setLandscape()
251 #if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5)
252 AppSettings::setOrientation(LANDSCAPE);
253 this->setAttribute(Qt::WA_Maemo5LandscapeOrientation, true);
257 void PlayerMainWindow::setAutoRotate()
259 #if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5)
260 AppSettings::setOrientation(AUTO_ROTATE);
261 this->setAttribute(Qt::WA_Maemo5AutoOrientation, true);
265 void PlayerMainWindow::orientationChanged() {
266 QRect screenGeometry = QApplication::desktop()->screenGeometry();
267 mIsLandscape = (screenGeometry.width() > screenGeometry.height());
270 ui->labelArtPortrait->setVisible(false);
271 ui->labelArtLandscape->setVisible(true);
274 ui->labelArtLandscape->setVisible(false);
275 ui->labelArtPortrait->setVisible(true);
279 ui->labelArtLandscape->setVisible(false);
280 ui->labelArtPortrait->setVisible(false);
284 void PlayerMainWindow::playpause()
286 // NB. There is no guarentee that our current state is the real current state.
287 // This is due to the polling frequency and possibility of user interaction directly on the server.
288 // Still this is probably better than nothing and our next real poll will set us straight again.
289 if (PAUSED == mCurrentStatus.state) {
290 mCurrentStatus.state = PLAYING;
292 updateUiWithCurrentStatus();
294 else if (PLAYING == mCurrentStatus.state) {
295 mCurrentStatus.state = PAUSED;
297 updateUiWithCurrentStatus();
300 // could be STOP or UNKNOWN, either way there is no guarentee we will enter a playing state next.
301 // So don't update the current state or UI
302 // Ideally we would try to find a way to check the current state again but this could lead to an infinite loop!
306 void PlayerMainWindow::play()
308 mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=pl_play")));
310 void PlayerMainWindow::stop()
312 mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=pl_stop")));
314 void PlayerMainWindow::pause()
316 mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=pl_pause")));
318 void PlayerMainWindow::previous()
320 mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=pl_previous")));
322 void PlayerMainWindow::next()
324 mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=pl_next")));
326 void PlayerMainWindow::fullscreen()
328 mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=fullscreen")));
330 void PlayerMainWindow::volUp()
332 QUrl url = QUrl("http://"+mIp+"/requests/status.xml?command=volume");
333 url.addEncodedQueryItem(QByteArray("val"), QByteArray("%2B10"));
334 mNetManager->get(QNetworkRequest(url));
336 void PlayerMainWindow::volDown()
338 mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=volume&val=-10")));
340 void PlayerMainWindow::volMute()
342 this->mMuted = !this->mMuted;
344 mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=volume&val=0")));
347 mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=volume&val="+QString::number(this->mVolume))));
350 void PlayerMainWindow::slide(int value)
352 mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=seek&val="+QString::number(value)+"%25")));
355 void PlayerMainWindow::showSettings()
357 SettingsDialog * dialog = new SettingsDialog(this);
358 connect(dialog, SIGNAL(closeSignal()), this, SLOT(updateFromSettings()));
361 void PlayerMainWindow::showConfig()
365 if (AppSettings::isConnected()) {
366 AccountDialog * dialog = new AccountDialog(this);
369 mIp= AppSettings::getCurrentIp(); //AccountDialog::currentIp();
371 mPlayListMainWindow->init();
372 mBrowserMainWindow->init();
373 mTimer->start(AppSettings::getStatusPollTimeout());
377 #if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5)
378 QMaemo5InformationBox::information(this, tr("Network unavailable!"), QMaemo5InformationBox::DefaultTimeout);
380 QTimer::singleShot(AppSettings::getRetryNetworkTimeout(), this, SLOT(showConfig()));
383 void PlayerMainWindow::showAbout()
386 AboutDialog * dialog = new AboutDialog;
391 void PlayerMainWindow::askStatus()
393 if (AppSettings::isConnected()) {
394 QNetworkReply * reply = mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml")));
395 connect(reply,SIGNAL(readyRead()),this,SLOT(parseXmlStatus()));
396 connect(reply,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(error(QNetworkReply::NetworkError)));
399 showConfig(); // this will handle stopping and restarting the timer.
403 void PlayerMainWindow::parseXmlStatus()
405 QNetworkReply * reply = qobject_cast<QNetworkReply*>(sender());
407 doc.setContent(reply->readAll());
409 QDomElement docElem = doc.documentElement();
410 VlcStatusState oldState = mCurrentStatus.state;
411 // Get the raw values
412 int volume = docElem.namedItem("volume").toElement().text().toInt();
413 int length = docElem.namedItem("length").toElement().text().toInt();
414 int time = docElem.namedItem("time").toElement().text().toInt();
415 int position = docElem.namedItem("position").toElement().text().toInt();
416 int random = docElem.namedItem("random").toElement().text().toInt();
417 int loop = docElem.namedItem("loop").toElement().text().toInt();
418 int repeat = docElem.namedItem("repeat").toElement().text().toInt();
419 QString state = docElem.namedItem("state").toElement().text();
420 QDomNode infoNode = docElem.namedItem("information");
421 QDomNode metaInfoNode = infoNode.namedItem("meta-information");
422 QString title = metaInfoNode.namedItem("title").toElement().text().replace("\\\\", "\\");
423 // if it's a file style title fix it up
424 if (40 < title.length()) {
425 if (0 < title.lastIndexOf("\\")) {
426 title = title.right(title.length() - (title.lastIndexOf("\\") + 1));
428 else if (0 < title.lastIndexOf("/")) {
429 title = title.right(title.length() - (title.lastIndexOf("/") + 1));
432 QString artist = metaInfoNode.namedItem("artist").toElement().text();
433 QString album = metaInfoNode.namedItem("album").toElement().text();
434 QString now_playing = metaInfoNode.namedItem("now_playing").toElement().text();
435 QString art_url = metaInfoNode.namedItem("art_url").toElement().text();
436 // Populate the current status structure
437 // now would be a good time to work out if we are a new track / file or not.
438 // key if we are going to look for album art later
439 // for now we check length and title this will require further examination later
440 if (!state.isNull() && !state.isEmpty()) {
441 if (0 == QString::compare("playing", state, Qt::CaseInsensitive)) {
442 mCurrentStatus.state = PLAYING;
444 else if (0 == QString::compare("paused", state, Qt::CaseInsensitive)) {
445 mCurrentStatus.state = PAUSED;
447 else if (0 == QString::compare("stop", state, Qt::CaseInsensitive)) {
448 mCurrentStatus.state = STOP;
451 mCurrentStatus.state = UNKNOWN;
452 mIsFirstStatusCall = true;
456 mCurrentStatus.state = UNKNOWN;
457 mIsFirstStatusCall = true;
459 mCurrentStatus.newtrack = true;
460 if (mIsFirstStatusCall) {
461 mIsFirstStatusCall = false;
462 mCurrentStatus.newtrack = true; // unneeded but self-documenting
464 else if (STOP == oldState && STOP != mCurrentStatus.state) {
465 mCurrentStatus.newtrack = true; // unneeded but self-documenting
468 if ( (0 == mCurrentStatus.length || STOP == mCurrentStatus.state) // stopped or null
469 || // same track as current playing
470 (mCurrentStatus.length == length && !mCurrentStatus.title.isNull() && !title.isNull() && 0 == QString::compare(mCurrentStatus.title, title)) ){
471 mCurrentStatus.newtrack = false;
474 mCurrentStatus.volume = volume;
475 mCurrentStatus.length = length;
476 mCurrentStatus.time = time;
477 mCurrentStatus.position = position;
478 mCurrentStatus.random = (1 == random);
479 mCurrentStatus.loop = (1 == loop);
480 mCurrentStatus.repeat = (1 == repeat);
481 mCurrentStatus.title = title;
482 mCurrentStatus.artist = artist;
483 mCurrentStatus.album = album;
484 mCurrentStatus.nowplaying = now_playing;
485 mCurrentStatus.hasart = (!art_url.isNull() && !art_url.isEmpty());
486 // What's our mute status?
487 if (0 < mCurrentStatus.volume) {
488 this->mVolume = mCurrentStatus.volume;
489 this->mMuted = false;
495 updateUiWithCurrentStatus();
499 void PlayerMainWindow::updateUiWithCurrentStatus() {
501 QTime timePosition(0,0,0) ;
502 timePosition = timePosition.addSecs(mCurrentStatus.time);
504 ui->timeLabel->setText(timePosition.toString("h:mm:ss"));
507 if (0 < mCurrentStatus.length) {
508 QTime timeDuration(0,0,0) ;
509 timeDuration = timeDuration.addSecs(mCurrentStatus.length);
511 ui->durationLabel->setText(timeDuration.toString("h:mm:ss"));
514 ui->durationLabel->setText("0:00:00");
518 if (mCurrentStatus.position >= 0 && mCurrentStatus.position <= 100) {
519 ui->slider->blockSignals(true);
520 ui->slider->setValue(mCurrentStatus.position);
521 ui->slider->blockSignals(false);
524 ui->labelTitle->setText(mCurrentStatus.title);
525 ui->labelArtist->setText(mCurrentStatus.artist);
526 ui->labelAlbum->setText(mCurrentStatus.album);
528 if (PLAYING == mCurrentStatus.state) {
529 ui->playpauseButton->setIcon(QIcon::fromTheme("camera_video_pause"));
532 ui->playpauseButton->setIcon(QIcon::fromTheme("camera_playback"));
535 if (STOP == mCurrentStatus.state || !AppSettings::getShowAlbumArt()) {
536 ui->labelArtPortrait->setVisible(false);
537 ui->labelArtLandscape->setVisible(false);
540 if (mCurrentStatus.newtrack && STOP != mCurrentStatus.state) {
541 // potential actions:
542 // rebuild display layout
543 // retrieve album art
544 if (AppSettings::getShowAlbumArt()) {
546 QTimer::singleShot(AppSettings::getRetrieveArtTimeout(), mPlayListMainWindow, SLOT(requestPlayList()));
549 // Update the buttons on the playlist window
550 if (NULL != this->mPlayListMainWindow) {
551 this->mPlayListMainWindow->updateUiWithCurrentStatus(& mCurrentStatus);
555 void PlayerMainWindow::playlistIdUpdated(int id, bool hasart, QString extension) {
561 ui->labelArtLandscape->setVisible(false);
562 ui->labelArtPortrait->setVisible(false);
563 // could use a default graphic from extension here!
564 // setCoverArtFromPixmap();
567 void PlayerMainWindow::error(QNetworkReply::NetworkError code) {
569 //qDebug() << "Error Code: " << code;
571 void PlayerMainWindow::readReady() {
572 QNetworkReply * reply = qobject_cast<QNetworkReply*>(sender());
574 mResponse += reply->readAll();
576 void PlayerMainWindow::finished(QNetworkReply * reply) {
577 // now we can call setCoverArt to process the full buffers
578 this->setCoverArt(mResponse);
579 // only interested in finished signals
580 disconnect(mNetManager,SIGNAL(finished(QNetworkReply *)),this,SLOT(finished(QNetworkReply *)));
583 void PlayerMainWindow::getCoverArt(int id) {
585 QNetworkReply * reply = mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/art?id=" + QString::number(id))));
586 connect(reply,SIGNAL(readyRead()),this,SLOT(readReady()));
587 connect(reply,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(error(QNetworkReply::NetworkError)));
588 connect(mNetManager,SIGNAL(finished(QNetworkReply *)),this,SLOT(finished(QNetworkReply *)));
591 void PlayerMainWindow::setCoverArt(const QByteArray data) {
592 QPixmap* image = new QPixmap();
593 if (image->loadFromData(data)) {
595 ui->labelArtLandscape->setPixmap(image->scaledToHeight(160, Qt::SmoothTransformation));
596 ui->labelArtPortrait->setPixmap(image->scaledToHeight(310, Qt::SmoothTransformation));
598 ui->labelArtPortrait->setVisible(false);
599 ui->labelArtLandscape->setVisible(true);
602 ui->labelArtLandscape->setVisible(false);
603 ui->labelArtPortrait->setVisible(true);
607 ui->labelArtPortrait->setVisible(false);
608 ui->labelArtLandscape->setVisible(false);
612 void PlayerMainWindow::setCoverArtFromPixmap(QPixmap image) {
614 ui->labelArtLandscape->setPixmap(image.scaledToHeight(160, Qt::SmoothTransformation));
615 ui->labelArtPortrait->setPixmap(image.scaledToHeight(310, Qt::SmoothTransformation));
617 ui->labelArtPortrait->setVisible(false);
618 ui->labelArtLandscape->setVisible(true);
621 ui->labelArtLandscape->setVisible(false);
622 ui->labelArtPortrait->setVisible(true);
625 void PlayerMainWindow::closeEvent(QCloseEvent * event) {
626 if (!AppSettings::getAlertOnClose() || PLAYING != mCurrentStatus.state) {
629 else { // handle alert
630 if (QMessageBox::Yes == QMessageBox::question(this
632 , tr("You currently have media playing on your remote machine. Are you sure you wish to quit vlc-remote?")
633 , QMessageBox::Yes | QMessageBox::No
634 , QMessageBox::No)) {