From 92131c9881aed5a71cd7922f62b05051f7451bcb Mon Sep 17 00:00:00 2001 From: yannux Date: Fri, 27 Aug 2010 17:55:02 +0200 Subject: [PATCH] New structure for project. Delete unused files todo --- AboutDialog.ui | 64 ----- Maemo_VLC_remote.svg | 453 --------------------------------- TODO.txt | 1 - aboutdialog.cpp | 43 ---- aboutdialog.h | 40 --- aboutdialog.ui | 81 ------ accountdialog.cpp | 210 ---------------- accountdialog.h | 53 ---- accountdialog.ui | 87 ------- accountnewdialog.ui | 67 ----- appsettings.cpp | 90 ------- appsettings.h | 49 ---- browsemainwindow.cpp | 427 ------------------------------- browsemainwindow.h | 76 ------ browsemainwindow.ui | 97 -------- config-vlc.jpg | Bin 77930 -> 0 bytes configdialog.cpp | 61 ----- configdialog.h | 42 ---- configdialog.ui | 69 ----- favouritesmainwindow.cpp | 170 ------------- favouritesmainwindow.h | 67 ----- favouritesmainwindow.ui | 88 ------- main.cpp | 70 ------ newaccountdialog.cpp | 98 -------- newaccountdialog.h | 50 ---- playermainwindow.cpp | 511 -------------------------------------- playermainwindow.h | 90 ------- playermainwindow.ui | 320 ------------------------ playlistmainwindow.cpp | 411 ------------------------------ playlistmainwindow.h | 82 ------ playlistmainwindow.ui | 140 ----------- resource.qrc | 5 - ressources.qrc | 5 - scanipdialog.cpp | 26 -- scanipdialog.h | 23 -- scanipdialog.ui | 83 ------- src/AboutDialog.ui | 64 +++++ src/Maemo_VLC_remote.svg | 453 +++++++++++++++++++++++++++++++++ src/aboutdialog.cpp | 43 ++++ src/aboutdialog.h | 40 +++ src/aboutdialog.ui | 81 ++++++ src/accountdialog.cpp | 210 ++++++++++++++++ src/accountdialog.h | 53 ++++ src/accountdialog.ui | 87 +++++++ src/accountnewdialog.ui | 67 +++++ src/appsettings.cpp | 90 +++++++ src/appsettings.h | 49 ++++ src/browsemainwindow.cpp | 427 +++++++++++++++++++++++++++++++ src/browsemainwindow.h | 76 ++++++ src/browsemainwindow.ui | 97 ++++++++ src/config-vlc.jpg | Bin 0 -> 77930 bytes src/configdialog.cpp | 61 +++++ src/configdialog.h | 42 ++++ src/configdialog.ui | 69 +++++ src/data/26x26/vlc-remote.png | Bin 0 -> 1310 bytes src/data/48x48/vlc-remote.png | Bin 0 -> 2948 bytes src/data/64x64/vlc-remote.png | Bin 0 -> 4286 bytes src/favouritesmainwindow.cpp | 170 +++++++++++++ src/favouritesmainwindow.h | 67 +++++ src/favouritesmainwindow.ui | 88 +++++++ src/main.cpp | 70 ++++++ src/newaccountdialog.cpp | 98 ++++++++ src/newaccountdialog.h | 50 ++++ src/playermainwindow.cpp | 511 ++++++++++++++++++++++++++++++++++++++ src/playermainwindow.h | 90 +++++++ src/playermainwindow.ui | 320 ++++++++++++++++++++++++ src/playlistmainwindow.cpp | 411 ++++++++++++++++++++++++++++++ src/playlistmainwindow.h | 82 ++++++ src/playlistmainwindow.ui | 140 +++++++++++ src/resource.qrc | 5 + src/ressources.qrc | 5 + src/scanipdialog.cpp | 26 ++ src/scanipdialog.h | 23 ++ src/scanipdialog.ui | 83 +++++++ src/src.pro | 45 ++++ src/vlc-remote.desktop | 12 + src/vlc-remote.png | Bin 0 -> 4444 bytes src/vlcbrowseelement.cpp | 19 ++ src/vlcbrowseelement.h | 33 +++ src/vlcplaylistelementsimple.cpp | 18 ++ src/vlcplaylistelementsimple.h | 33 +++ src/vlcremote_fr_FR.qm | Bin 0 -> 12582 bytes src/vlcremote_fr_FR.ts | 433 ++++++++++++++++++++++++++++++++ src/vlcstatus.cpp | 18 ++ src/vlcstatus.h | 46 ++++ todo.txt | 1 - vlc-remote.desktop | 12 - vlc-remote.png | Bin 4444 -> 0 bytes vlc-remote.pro | 8 + vlcRemote.pro | 45 ---- vlcbrowseelement.cpp | 19 -- vlcbrowseelement.h | 33 --- vlcplaylistelementsimple.cpp | 18 -- vlcplaylistelementsimple.h | 33 --- vlcremote_fr_FR.qm | Bin 12582 -> 0 bytes vlcremote_fr_FR.ts | 433 -------------------------------- vlcstatus.cpp | 18 -- vlcstatus.h | 46 ---- www/index.html | 27 +- www/styles.css | 6 +- 100 files changed, 4937 insertions(+), 4916 deletions(-) delete mode 100644 AboutDialog.ui delete mode 100644 Maemo_VLC_remote.svg delete mode 100644 TODO.txt delete mode 100644 aboutdialog.cpp delete mode 100644 aboutdialog.h delete mode 100644 aboutdialog.ui delete mode 100644 accountdialog.cpp delete mode 100644 accountdialog.h delete mode 100644 accountdialog.ui delete mode 100644 accountnewdialog.ui delete mode 100644 appsettings.cpp delete mode 100644 appsettings.h delete mode 100644 browsemainwindow.cpp delete mode 100644 browsemainwindow.h delete mode 100644 browsemainwindow.ui delete mode 100644 config-vlc.jpg delete mode 100644 configdialog.cpp delete mode 100644 configdialog.h delete mode 100644 configdialog.ui delete mode 100644 favouritesmainwindow.cpp delete mode 100644 favouritesmainwindow.h delete mode 100644 favouritesmainwindow.ui delete mode 100644 main.cpp delete mode 100644 newaccountdialog.cpp delete mode 100644 newaccountdialog.h delete mode 100644 playermainwindow.cpp delete mode 100644 playermainwindow.h delete mode 100644 playermainwindow.ui delete mode 100644 playlistmainwindow.cpp delete mode 100644 playlistmainwindow.h delete mode 100644 playlistmainwindow.ui delete mode 100644 resource.qrc delete mode 100644 ressources.qrc delete mode 100644 scanipdialog.cpp delete mode 100644 scanipdialog.h delete mode 100644 scanipdialog.ui create mode 100644 src/AboutDialog.ui create mode 100644 src/Maemo_VLC_remote.svg create mode 100644 src/aboutdialog.cpp create mode 100644 src/aboutdialog.h create mode 100644 src/aboutdialog.ui create mode 100644 src/accountdialog.cpp create mode 100644 src/accountdialog.h create mode 100644 src/accountdialog.ui create mode 100644 src/accountnewdialog.ui create mode 100644 src/appsettings.cpp create mode 100644 src/appsettings.h create mode 100644 src/browsemainwindow.cpp create mode 100644 src/browsemainwindow.h create mode 100644 src/browsemainwindow.ui create mode 100644 src/config-vlc.jpg create mode 100644 src/configdialog.cpp create mode 100644 src/configdialog.h create mode 100644 src/configdialog.ui create mode 100644 src/data/26x26/vlc-remote.png create mode 100644 src/data/48x48/vlc-remote.png create mode 100644 src/data/64x64/vlc-remote.png create mode 100644 src/favouritesmainwindow.cpp create mode 100644 src/favouritesmainwindow.h create mode 100644 src/favouritesmainwindow.ui create mode 100644 src/main.cpp create mode 100644 src/newaccountdialog.cpp create mode 100644 src/newaccountdialog.h create mode 100644 src/playermainwindow.cpp create mode 100644 src/playermainwindow.h create mode 100644 src/playermainwindow.ui create mode 100644 src/playlistmainwindow.cpp create mode 100644 src/playlistmainwindow.h create mode 100644 src/playlistmainwindow.ui create mode 100644 src/resource.qrc create mode 100644 src/ressources.qrc create mode 100644 src/scanipdialog.cpp create mode 100644 src/scanipdialog.h create mode 100644 src/scanipdialog.ui create mode 100644 src/src.pro create mode 100644 src/vlc-remote.desktop create mode 100644 src/vlc-remote.png create mode 100644 src/vlcbrowseelement.cpp create mode 100644 src/vlcbrowseelement.h create mode 100644 src/vlcplaylistelementsimple.cpp create mode 100644 src/vlcplaylistelementsimple.h create mode 100644 src/vlcremote_fr_FR.qm create mode 100644 src/vlcremote_fr_FR.ts create mode 100644 src/vlcstatus.cpp create mode 100644 src/vlcstatus.h create mode 100644 src/welcome delete mode 100644 todo.txt delete mode 100644 vlc-remote.desktop delete mode 100644 vlc-remote.png create mode 100644 vlc-remote.pro delete mode 100644 vlcRemote.pro delete mode 100644 vlcbrowseelement.cpp delete mode 100644 vlcbrowseelement.h delete mode 100644 vlcplaylistelementsimple.cpp delete mode 100644 vlcplaylistelementsimple.h delete mode 100644 vlcremote_fr_FR.qm delete mode 100644 vlcremote_fr_FR.ts delete mode 100644 vlcstatus.cpp delete mode 100644 vlcstatus.h delete mode 100644 welcome diff --git a/AboutDialog.ui b/AboutDialog.ui deleted file mode 100644 index 2cf6ba0..0000000 --- a/AboutDialog.ui +++ /dev/null @@ -1,64 +0,0 @@ - - - Dialog - - - - 0 - 0 - 400 - 300 - - - - Dialog - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - buttonBox - accepted() - Dialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - Dialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - - diff --git a/Maemo_VLC_remote.svg b/Maemo_VLC_remote.svg deleted file mode 100644 index 83ad807..0000000 --- a/Maemo_VLC_remote.svg +++ /dev/null @@ -1,453 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/TODO.txt b/TODO.txt deleted file mode 100644 index 3bdf506..0000000 --- a/TODO.txt +++ /dev/null @@ -1 +0,0 @@ -TODO diff --git a/aboutdialog.cpp b/aboutdialog.cpp deleted file mode 100644 index e1606ea..0000000 --- a/aboutdialog.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* VLC-REMOTE for MAEMO 5 -* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2, -* or (at your option) any later version, as published by the Free -* Software Foundation -* -* 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, write to the -* Free Software Foundation, Inc., -* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -#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 deleted file mode 100644 index c92ce70..0000000 --- a/aboutdialog.h +++ /dev/null @@ -1,40 +0,0 @@ -/* VLC-REMOTE for MAEMO 5 -* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2, -* or (at your option) any later version, as published by the Free -* Software Foundation -* -* 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, write to the -* Free Software Foundation, Inc., -* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -#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/aboutdialog.ui b/aboutdialog.ui deleted file mode 100644 index ad5fdd1..0000000 --- a/aboutdialog.ui +++ /dev/null @@ -1,81 +0,0 @@ - - - AboutDialog - - - - 0 - 0 - 400 - 300 - - - - Dialog - - - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'DejaVu Sans'; font-size:14pt; font-weight:400; font-style:normal;"> -<table style="-qt-table-type: root; margin-top:4px; margin-bottom:4px; margin-left:4px; margin-right:4px;"> -<tr> -<td style="border: none;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">OMed </p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Application by Sacha schutz </p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">istdasklar@gmail.com</p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://omedsoft.blogspot.com/"><span style=" text-decoration: underline; color:#0000ff;">http://omedsoft.blogspot.com/</span></a></p></td></tr></table></body></html> - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - buttonBox - accepted() - AboutDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - AboutDialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - - diff --git a/accountdialog.cpp b/accountdialog.cpp deleted file mode 100644 index ecdb02f..0000000 --- a/accountdialog.cpp +++ /dev/null @@ -1,210 +0,0 @@ -/* VLC-REMOTE for MAEMO 5 -* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2, -* or (at your option) any later version, as published by the Free -* Software Foundation -* -* 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, write to the -* Free Software Foundation, Inc., -* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -#include "accountdialog.h" -#include "ui_accountdialog.h" -#include "newaccountdialog.h" -#include -#include -#include -#include -#include -#include - - - -QListWidgetItem asyncTestItem(const QListWidgetItem &item) -{ - - QListWidgetItem item2= item; - item2.setText("boby"); - - return item; - -} - - - - -AccountDialog::AccountDialog(QWidget *parent) : - QDialog(parent), - ui(new Ui::AccountDialog) -{ - ui->setupUi(this); - - mFuturWatcher = new QFutureWatcher(this); - connect(mFuturWatcher,SIGNAL(resultReadyAt(int)),this,SLOT(setAsyncItem(int))); - - connect(ui->addButton,SIGNAL(clicked()),this,SLOT(add())); - connect(ui->editButton,SIGNAL(clicked()),this,SLOT(edit())); - connect(ui->remButton,SIGNAL(clicked()),this,SLOT(rem())); - connect(ui->useButton,SIGNAL(clicked()),this,SLOT(use())); - connect(ui->listWidget, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(enableUi())); - - load(); - -} - -AccountDialog::~AccountDialog() -{ - delete ui; -} - -void AccountDialog::add() -{ - - NewAccountDialog *dialog = new NewAccountDialog(this); - dialog->exec(); - load(); -} -QString AccountDialog::currentIp() -{ - - QSettings settings; - QString useKey = settings.value("config/currentKey").toString(); - QString useIp ; - if ( !useKey.isEmpty()) - useIp = settings.value("account/"+useKey).toString(); - - else return QString(); - - return useIp; -} - -void AccountDialog::load() -{ - ui->editButton->setEnabled(false); - ui->remButton->setEnabled(false); - ui->useButton->setEnabled(false); - ui->listWidget->clear(); // tjr effacer , sinon on rajoute - - QSettings settings; - - QString useKey = settings.value("config/currentKey").toString(); - - QList asycItems; - - settings.beginGroup("account"); - foreach ( QString key, settings.allKeys()) - { - QListWidgetItem * item = new QListWidgetItem; - - item->setText(key); - item->setData(Qt::UserRole, settings.value(key)); - if (useKey == key) { - QFont font = item->font(); - font.setBold(true); - item->setFont(font); - } - ui->listWidget->addItem(item); - asycItems.append(*item); - } - settings.endGroup(); - - - // ... create and add in the list widget - - // QFuture itemFutur = QtConcurrent::mapped(asycItems, asyncTestItem); - - - mFuturWatcher->setFuture(QtConcurrent::mapped(asycItems, asyncTestItem)); -} - -QListWidgetItem AccountDialog::asyncTestItem(const QListWidgetItem& item) -{ - //==========> NEED TO USE POINTER TO AVOID setAsyncItem! But I don't know how;.. - QListWidgetItem newItem = item; - - QTcpSocket * socket = new QTcpSocket; - QSettings settings; - QString host = settings.value("account/"+item.text()).toString(); - - if(host.contains(":")) - { - QStringList hostSplit = host.split(":"); - QString ip = hostSplit.at(0); - QString port = hostSplit.at(1); - socket->connectToHost(ip,port.toInt()); - } - - else - socket->connectToHost(host,8080); - - if (socket->waitForConnected(1000)) - newItem.setIcon(QIcon::fromTheme("widgets_tickmark_list")); - else - newItem.setIcon(QIcon::fromTheme("statusarea_presence_busy_error")); - - return newItem; - - -} - - - -void AccountDialog::setAsyncItem(int row) // EDIT THE ROW AFTER ASYNC FUNCTION FINISHED -{ - QListWidgetItem newItem = mFuturWatcher->resultAt(row); - QListWidgetItem * item = ui->listWidget->item(row); - - item->setIcon(newItem.icon()); - - - -} - - - -void AccountDialog::edit() -{ - QString currentIp = ui->listWidget->currentItem()->data(Qt::UserRole).toString(); - QString currentKey = ui->listWidget->currentItem()->text(); - - NewAccountDialog *dialog = new NewAccountDialog(this); - dialog->edit(currentKey, currentIp); - dialog->exec(); - - load(); -} - -void AccountDialog::rem() -{ - QString key = ui->listWidget->currentItem()->text(); - - QSettings settings; - settings.beginGroup("account"); - settings.remove(key); - settings.endGroup(); - - load(); // On recharge les compte -} - -void AccountDialog::use() -{ - QString currentKey = ui->listWidget->currentItem()->text(); - QSettings settings; - settings.setValue("config/currentKey", currentKey); - load(); - emit accept(); -} - -void AccountDialog::enableUi() -{ - ui->editButton->setEnabled(true); - ui->remButton->setEnabled(true); - ui->useButton->setEnabled(true); -} diff --git a/accountdialog.h b/accountdialog.h deleted file mode 100644 index e9468dd..0000000 --- a/accountdialog.h +++ /dev/null @@ -1,53 +0,0 @@ -/* VLC-REMOTE for MAEMO 5 -* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2, -* or (at your option) any later version, as published by the Free -* Software Foundation -* -* 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, write to the -* Free Software Foundation, Inc., -* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -#ifndef ACCOUNTDIALOG_H -#define ACCOUNTDIALOG_H - -#include -#include -#include -namespace Ui { - class AccountDialog; -} - -class AccountDialog : public QDialog -{ - Q_OBJECT - -public: - explicit AccountDialog(QWidget *parent = 0); - ~AccountDialog(); - static QListWidgetItem asyncTestItem(const QListWidgetItem& item); - - -static QString currentIp(); - -public slots: - void add(); - void edit(); - void rem(); - void use(); - void load(); - void enableUi(); - void setAsyncItem(int row); -private: - Ui::AccountDialog *ui; - QFutureWatcher * mFuturWatcher; -}; - -#endif // ACCOUNTDIALOG_H diff --git a/accountdialog.ui b/accountdialog.ui deleted file mode 100644 index 8b0dd97..0000000 --- a/accountdialog.ui +++ /dev/null @@ -1,87 +0,0 @@ - - - AccountDialog - - - - 0 - 0 - 400 - 300 - - - - Accounts - - - - - - - test - - - - - - - - - - Add - - - - - - - false - - - Edit - - - - - - - false - - - Remove - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - false - - - Use - - - - - - - - - - diff --git a/accountnewdialog.ui b/accountnewdialog.ui deleted file mode 100644 index 0ac856e..0000000 --- a/accountnewdialog.ui +++ /dev/null @@ -1,67 +0,0 @@ - - Dialog - - - - 0 - 0 - 320 - 240 - - - - Dialog - - - - - 10 - 200 - 301 - 32 - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - buttonBox - accepted() - Dialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - Dialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - - diff --git a/appsettings.cpp b/appsettings.cpp deleted file mode 100644 index babef8c..0000000 --- a/appsettings.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* VLC-REMOTE for MAEMO 5 -* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2, -* or (at your option) any later version, as published by the Free -* Software Foundation -* -* 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, write to the -* Free Software Foundation, Inc., -* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -#include -#include "appsettings.h" - -AppSettings::AppSettings() { -} - -AppSettings::~AppSettings() { - ; -} - -QString AppSettings::getCurrentKey() { - QSettings sets; - return sets.value("config/currentKey", "").toString(); -} -QString AppSettings::getCurrentIp() { - QSettings sets; - return sets.value("account/" + getCurrentKey(), "").toString(); -} -VlcDirectory AppSettings::getHomeDirectory() { - QSettings sets; - VlcDirectory home; - home.name = sets.value("config/accounts/" + getCurrentKey() + "/homeDirName", "Default").toString(); - home.path = sets.value("config/accounts/" + getCurrentKey() + "/homeDirPath", "~/").toString(); - return home; -} -bool AppSettings::setHomeDirectory(VlcDirectory dir) { - QSettings sets; - sets.setValue("config/accounts/" + getCurrentKey() + "/homeDirName", dir.name); - sets.setValue("config/accounts/" + getCurrentKey() + "/homeDirPath", dir.path); - return true; -} -QList* AppSettings::getFavourites() { - QSettings sets; - QList * favourites = new QList(); - - sets.beginGroup("config/accounts/" + getCurrentKey() + "/favourites"); - foreach ( QString key, sets.allKeys()) - { - VlcDirectory dir; - // key is name - dir.name = key; - // value is path - dir.path = sets.value(key, "~/").toString(); - favourites->append(dir); - } - sets.endGroup(); - return favourites; -} -bool AppSettings::addFavourite(VlcDirectory dir) { - QSettings sets; - // should check for existing first otherwise it overwrites - if (0 < sets.value("config/accounts/" + getCurrentKey() + "/favourites/" + dir.name, "").toString().length()) { - dir.name = "_" + dir.name; - return addFavourite(dir); - } - sets.setValue("config/accounts/" + getCurrentKey() + "/favourites/" + dir.name, dir.path); - return true; -} -bool AppSettings::deleteFavourite(VlcDirectory dir) { - QSettings sets; - sets.remove("config/accounts/" + getCurrentKey() + "/favourites/" + dir.name); - return true; -} -Orientation AppSettings::setOrientation(Orientation orientation) { - QSettings sets; - sets.setValue("config/orientation", (int)orientation); - return orientation; -} -Orientation AppSettings::getOrientation() { - QSettings sets; - return (Orientation)(sets.value("config/orientation", AUTO_ROTATE).toInt()); -} - diff --git a/appsettings.h b/appsettings.h deleted file mode 100644 index 407b5a2..0000000 --- a/appsettings.h +++ /dev/null @@ -1,49 +0,0 @@ -/* VLC-REMOTE for MAEMO 5 -* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2, -* or (at your option) any later version, as published by the Free -* Software Foundation -* -* 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, write to the -* Free Software Foundation, Inc., -* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -#ifndef APPSETTINGS_H -#define APPSETTINGS_H -#include - -struct VlcDirectory { - QString name; - QString path; -}; -enum Orientation { - AUTO_ROTATE = 0, - LANDSCAPE, - PORTRAIT -}; - -class AppSettings { -public: - explicit AppSettings(); - ~AppSettings(); - static QString getCurrentKey(); - static QString getCurrentIp(); - static VlcDirectory getHomeDirectory(); - static QList* getFavourites(); - static bool addFavourite(VlcDirectory dir); - static bool deleteFavourite(VlcDirectory dir); - static bool setHomeDirectory(VlcDirectory dir); - static Orientation setOrientation(Orientation orientation); - static Orientation getOrientation(); -//private: - //static QSettings settings; -}; - -#endif // APPSETTINGS_H diff --git a/browsemainwindow.cpp b/browsemainwindow.cpp deleted file mode 100644 index a07b131..0000000 --- a/browsemainwindow.cpp +++ /dev/null @@ -1,427 +0,0 @@ -/* VLC-REMOTE for MAEMO 5 -* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2, -* or (at your option) any later version, as published by the Free -* Software Foundation -* -* 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, write to the -* Free Software Foundation, Inc., -* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -#include "browsemainwindow.h" -#include "ui_browsemainwindow.h" -#include -#if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) -#include -#endif -#include "configdialog.h" -#include "aboutdialog.h" -#include "vlcbrowseelement.h" -#include "appsettings.h" -#include "favouritesmainwindow.h" - -BrowseMainWindow::BrowseMainWindow(QWidget *parent) : - QMainWindow(parent), - ui(new Ui::BrowseMainWindow) -{ - - ui->setupUi(this); - mFavouritesMainWindow = new FavouritesMainWindow; - mCurrentDir = "~/"; //AppSettings::getHomeDirectory().path; // This works on win as well as linux, would guess mac too. - setWindowTitle("Vlc remote"); - - - mNetManager = new QNetworkAccessManager(this); - - mContents = new QList(); - - ui->listWidget->setTextElideMode(Qt::ElideMiddle); - ui->listWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - - ui->playButton->setIcon(QIcon::fromTheme("camera_playback")); - ui->addButton->setIcon(QIcon::fromTheme("general_add")); - ui->browseButton->setIcon(QIcon::fromTheme("filemanager_media_folder")); - ui->browseButton->setDisabled(true); - ui->playButton->setDisabled(true); - ui->addButton->setDisabled(true); - - -#if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) - - mFavouritesMainWindow->setParent(this); - mFavouritesMainWindow->setAttribute(Qt::WA_Maemo5StackedWindow, true); - setAttribute(Qt::WA_Maemo5StackedWindow, true); - mFavouritesMainWindow->setWindowFlags(mFavouritesMainWindow->windowFlags() | Qt::Window); - -#endif - - connect(ui->browseButton,SIGNAL(clicked()),this,SLOT(onBrowse())); - connect(ui->addButton,SIGNAL(clicked()),this,SLOT(onAddToPlaylist())); - connect(ui->playButton,SIGNAL(clicked()),this,SLOT(onPlay())); - connect(ui->listWidget, SIGNAL(itemSelectionChanged()), this, SLOT(onListSelectionChanged())); - - connect(ui->actionGoUserHome, SIGNAL(triggered()), this, SLOT(showUserHomeFolder())); - connect(ui->actionGoHome, SIGNAL(triggered()), this, SLOT(showHomeFolder())); - connect(ui->actionSetHome, SIGNAL(triggered()), this, SLOT(setHomeFolder())); - connect(ui->actionViewFavourites, SIGNAL(triggered()), this, SLOT(showFavourites())); - connect(ui->actionSetFavourite, SIGNAL(triggered()), this, SLOT(setFavourite())); - - connect(this->mFavouritesMainWindow, SIGNAL(browseDirectory(QString)), this, SLOT(browseDirectory(QString))); - - init(); - - -} -void BrowseMainWindow::init() // THIS METHOD IS CALLED WHEN CONFIG CHANGED... -{ - mIp = AppSettings::getCurrentIp(); // AccountDialog::currentIp(); - setHomeDirectory(); -} -void BrowseMainWindow::setHomeDirectory() -{ - mCurrentDir = AppSettings::getHomeDirectory().path; -} -void BrowseMainWindow::showCurrentDirectory() // THIS METHOD IS CALLED WHEN WINDOW IS OPENED... -{ - browseDirectory(mCurrentDir); -} - -BrowseMainWindow::~BrowseMainWindow() -{ - delete ui; -} - -void BrowseMainWindow::changeEvent(QEvent *e) -{ - QMainWindow::changeEvent(e); - switch (e->type()) { - case QEvent::LanguageChange: - ui->retranslateUi(this); - break; - default: - break; - } -} - -void BrowseMainWindow::showHomeFolder() { - browseDirectory(AppSettings::getHomeDirectory().path); -} -void BrowseMainWindow::showUserHomeFolder() { - browseDirectory("~/"); -} -void BrowseMainWindow::setHomeFolder() { - if (0 < mCurrentElement.name.length() && (0 == QString::compare("directory", mCurrentElement.type) || 0 == QString::compare("dir", mCurrentElement.type))) { - VlcDirectory dir; - dir.name = mCurrentElement.name; - dir.path = mCurrentElement.path; - AppSettings::setHomeDirectory(dir); - } - else if (0 < mCurrentDir.length()) { - VlcDirectory dir; - QString name = mCurrentDir; - int idx = mCurrentDir.lastIndexOf('/'); - if (0 > idx) idx = mCurrentDir.lastIndexOf('\\'); - if (0 < idx) { - name = mCurrentDir.right(mCurrentDir.length() - (idx + 1)); - } - dir.name = name; - dir.path = mCurrentDir; - AppSettings::setHomeDirectory(dir); - } -} -void BrowseMainWindow::showFavourites() { - mFavouritesMainWindow->show(); - mFavouritesMainWindow->init(); -} -void BrowseMainWindow::setFavourite() { - if (0 < mCurrentElement.name.length() && (0 == QString::compare("directory", mCurrentElement.type) || 0 == QString::compare("dir", mCurrentElement.type))) { - VlcDirectory dir; - dir.name = mCurrentElement.name; - dir.path = mCurrentElement.path; - AppSettings::addFavourite(dir); - } - else if (0 < mCurrentDir.length()) { - VlcDirectory dir; - QString name = mCurrentDir; - int idx = mCurrentDir.lastIndexOf('/'); - if (0 > idx) idx = mCurrentDir.lastIndexOf('\\'); - if (0 < idx) { - name = mCurrentDir.right(mCurrentDir.length() - (idx + 1)); - } - dir.name = name; - dir.path = mCurrentDir; - AppSettings::addFavourite(dir); - } -} - -void BrowseMainWindow::onListSelectionChanged() { - QList items = ui->listWidget->selectedItems(); - if (0 < items.count()) { - mCurrentElement = getElementFromText(items.at(0)->text()); - // are we up dir? - if (0 == QString::compare("..", mCurrentElement.name)) { - ui->browseButton->setDisabled(true); - ui->playButton->setDisabled(true); - ui->addButton->setDisabled(true); - mCurrentDir = mCurrentElement.path; - browseDirectory(mCurrentDir); - } - else { - // can we browse? - if (0 == QString::compare("directory", mCurrentElement.type) || 0 == QString::compare("dir", mCurrentElement.type)) { - ui->browseButton->setDisabled(false); - } - else { - ui->browseButton->setDisabled(true); - } - // can we play? - ui->playButton->setDisabled(false); - // can we playlist? - ui->addButton->setDisabled(false); - } - } -} - -VlcBrowseElement BrowseMainWindow::getElementFromText(QString text) { - for (int idx = 0; idx < mContents->count(); ++idx) { - if (0 == QString::compare(text, mContents->at(idx).name)) { - return mContents->at(idx); - } - } - return *(new VlcBrowseElement()); -} - -void BrowseMainWindow::onBrowse() { - // check for directory - if (0 == QString::compare("directory", mCurrentElement.type) || 0 == QString::compare("dir", mCurrentElement.type)) { - // call browseDirectory - mCurrentDir = mCurrentElement.path; - browseDirectory(mCurrentDir); - } - else { - ui->browseButton->setDisabled(true); - } -} - -void BrowseMainWindow::onAddToPlaylist() { - QUrl url = QUrl("http://"+mIp+"/requests/status.xml?command=in_enqueue"); - url.addEncodedQueryItem(QByteArray("input"), QUrl::toPercentEncoding(mCurrentElement.path.replace("\\", "\\\\").replace("'", "\\'"))); - mNetManager->get(QNetworkRequest(url)); - //mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=in_enqueue&input=" + mCurrentElement.path.replace("\\", "\\\\")))); -} - -void BrowseMainWindow::onPlay() { - QUrl url = QUrl("http://"+mIp+"/requests/status.xml?command=in_play"); - url.addEncodedQueryItem(QByteArray("input"), QUrl::toPercentEncoding(mCurrentElement.path.replace("\\", "\\\\").replace("'", "\\'"))); - mNetManager->get(QNetworkRequest(url)); - //mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=in_play&input=" + mCurrentElement.path.replace("\\", "\\\\")))); -} - -void BrowseMainWindow::browseDirectory(QString dir) { - if (mFavouritesMainWindow) { - setParent(this->parentWidget()); -#if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) - setAttribute(Qt::WA_Maemo5StackedWindow, true); -#endif - mFavouritesMainWindow->hide(); - } - mResponse.clear(); - QUrl url = QUrl("http://"+mIp+"/requests/browse.xml"); - url.addEncodedQueryItem(QByteArray("dir"), QUrl::toPercentEncoding(dir)); - QNetworkReply * reply = mNetManager->get(QNetworkRequest(url)); - //QNetworkReply * reply = mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/browse.xml?dir=" + dir.replace("&", "%26").replace("\\", "\\\\")))); -#if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) - this->setAttribute(Qt::WA_Maemo5ShowProgressIndicator, true); -#endif - connect(reply,SIGNAL(readyRead()),this,SLOT(readReady())); - connect(reply,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(error(QNetworkReply::NetworkError))); - connect(mNetManager,SIGNAL(finished(QNetworkReply *)),this,SLOT(finished(QNetworkReply *))); -} -void BrowseMainWindow::error(QNetworkReply::NetworkError code) { -#if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) - this->setAttribute(Qt::WA_Maemo5ShowProgressIndicator, false); -#endif - qDebug() << code; -} -void BrowseMainWindow::readReady() { - QNetworkReply * reply = qobject_cast(sender()); - // append to buffer - mResponse += reply->readAll(); -} -void BrowseMainWindow::finished(QNetworkReply * reply) { - // now we can call parseXmlDirectory to process the full buffers - this->parseXmlDirectory(); - // only interested in finished signals - disconnect(mNetManager,SIGNAL(finished(QNetworkReply *)),this,SLOT(finished(QNetworkReply *))); -#if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) - this->setAttribute(Qt::WA_Maemo5ShowProgressIndicator, false); -#endif - delete reply; -} -void BrowseMainWindow::parseXmlDirectory() { - QDomDocument doc; - doc.setContent(this->mResponse); - QDomElement docElem = doc.documentElement(); - QDomNodeList elements = docElem.elementsByTagName("element"); - // we can sort by folders then files alphabetically by running to lists and appending them at the end - // vlc alpha sorts everything in the incoming stream, we just need to seperate files from folders. - if (0 < elements.count()) { - QList* files = new QList(); - int idx = 0; - mContents->clear(); - do { - QDomNode node = elements.at(idx); - VlcBrowseElement* dir = new VlcBrowseElement(); - dir->type = node.attributes().namedItem("type").nodeValue(); - dir->size = node.attributes().namedItem("size").nodeValue().toInt(); - dir->date = QDate::fromString(node.attributes().namedItem("date").nodeValue()); - dir->path = node.attributes().namedItem("path").nodeValue(); - dir->name = node.attributes().namedItem("name").nodeValue(); - dir->extension = getExtension(dir->path, node.attributes().namedItem("extension").nodeValue()); - ++idx; - if (0 != QString::compare("directory", dir->type) && 0 != QString::compare("dir", dir->type)) { - files->append(*dir); - } - else if (0 == QString::compare("..", dir->name)) { - this->mContents->prepend(*dir); - } - else { - this->mContents->append(*dir); - } - delete dir; - } while (idx < elements.count()); - if (0 < files->count()) { - mContents->append(*files); - } - delete files; - // Update UI - this->updateList(); - } - else { - // alert user of error / empty directory - qDebug() << "can't browse dir: " << mCurrentDir; -#if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) - QMaemo5InformationBox::information(this, tr("Directory could not be browsed!"), QMaemo5InformationBox::DefaultTimeout); -#endif - } - mResponse.clear(); - -} - -QString BrowseMainWindow::getExtension(QString path, QString extension) { - // return extension if exists - if (!extension.isNull() && !extension.isEmpty()) return extension; - // return blank if no path - if (path.isNull() || path.isEmpty()) return ""; - // otherwise extract the extension - int dot_pos = path.lastIndexOf('.'); - if (0 < dot_pos) { - return path.right(path.length() - (dot_pos + 1)); - } - else { // no dot - return ""; - } -} - -void BrowseMainWindow::updateList() { - ui->listWidget->clear(); - int ct = this->mContents->count(); - if (0 < ct) { - QIcon icon_up = QIcon::fromTheme("filemanager_folder_up"); - QIcon icon_folder = QIcon::fromTheme("general_folder"); - QIcon icon_audio = QIcon::fromTheme("general_audio_file"); - QIcon icon_video = QIcon::fromTheme("general_video_file"); - QIcon icon_image = QIcon::fromTheme("general_image"); - QIcon icon_flash = QIcon::fromTheme("filemanager_flash_file"); - QIcon icon_real = QIcon::fromTheme("filemanager_real_music"); - QIcon icon_playl = QIcon::fromTheme("filemanager_playlist"); - QIcon icon_unknown= QIcon::fromTheme("filemanager_unknown_file"); - for (int idx = 0; idx < ct; ++idx) { - VlcBrowseElement dir = mContents->at(idx); - QListWidgetItem* item; - bool item_good = false; - if (0 == QString::compare("directory", dir.type) || 0 == QString::compare("dir", dir.type)) { - if (0 == QString::compare("..", dir.name)) { - item = new QListWidgetItem(icon_up, dir.name, ui->listWidget, 0); - item_good = true; - } - else { - item = new QListWidgetItem(icon_folder, dir.name, ui->listWidget, 0); - item_good = true; - } - } - else if (0 == QString::compare("file", dir.type)) { - if ( 0 == QString::compare(dir.extension, "jpg") || - 0 == QString::compare(dir.extension, "jpeg") || - 0 == QString::compare(dir.extension, "gif") || - 0 == QString::compare(dir.extension, "png") || - 0 == QString::compare(dir.extension, "bmp") ) { - item_good = true; - item = new QListWidgetItem(icon_image, dir.name, ui->listWidget, 0); // .jpg, .jpeg, .gif, .png, .bmp - } - else if ( 0 == QString::compare(dir.extension, "mp3") || - 0 == QString::compare(dir.extension, "m4a") || - 0 == QString::compare(dir.extension, "ogg") || - 0 == QString::compare(dir.extension, "oga") || - 0 == QString::compare(dir.extension, "wav") || - 0 == QString::compare(dir.extension, "flac") ) { - item_good = true; - item = new QListWidgetItem(icon_audio, dir.name, ui->listWidget, 0); // .mp3, .m4a, .ogg, .oga, .wav, .flac - } - else if ( 0 == QString::compare(dir.extension, "m3u") || - 0 == QString::compare(dir.extension, "wpl") || - 0 == QString::compare(dir.extension, "pls") || - 0 == QString::compare(dir.extension, "asx") || - 0 == QString::compare(dir.extension, "xspf") || - 0 == QString::compare(dir.extension, "cmml") ) { - item_good = true; - item = new QListWidgetItem(icon_playl, dir.name, ui->listWidget, 0); // .m3u, .wpl, .pls, .asx, .xspf, .cmml - } - else if ( 0 == QString::compare(dir.extension, "avi") || - 0 == QString::compare(dir.extension, "mpeg") || - 0 == QString::compare(dir.extension, "mpg") || - 0 == QString::compare(dir.extension, "mov") || - 0 == QString::compare(dir.extension, "mp4") || - 0 == QString::compare(dir.extension, "m4v") || - 0 == QString::compare(dir.extension, "wmv") || - 0 == QString::compare(dir.extension, "mkv") || - 0 == QString::compare(dir.extension, "ogv") ) { - item_good = true; - item = new QListWidgetItem(icon_video, dir.name, ui->listWidget, 0); // .avi, .mpg, .mpeg, .mov, .mp4, .m4v, .wmv, .mkv, .ogv - } - else if ( 0 == QString::compare(dir.extension, "rm") || - 0 == QString::compare(dir.extension, "ra") || - 0 == QString::compare(dir.extension, "ram") ) { - item = new QListWidgetItem(icon_real, dir.name, ui->listWidget, 0); // .ram, 'rm, 'ra - } - else if ( 0 == QString::compare(dir.extension, "flv") ) { - item_good = true; - item = new QListWidgetItem(icon_flash, dir.name, ui->listWidget, 0); // .flv - } - else { - if (dir.name.startsWith("Flash")) { - item_good = true; - item = new QListWidgetItem(icon_flash, dir.name, ui->listWidget, 0); - } - else { - item_good = false; - //item = new QListWidgetItem(icon_unknown, dir.name, ui->listWidget, 0); - } - } - } - if (item_good) { - ui->listWidget->addItem(item); - } - // other types ignored - } - } -} - - diff --git a/browsemainwindow.h b/browsemainwindow.h deleted file mode 100644 index 052421a..0000000 --- a/browsemainwindow.h +++ /dev/null @@ -1,76 +0,0 @@ -/* VLC-REMOTE for MAEMO 5 -* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2, -* or (at your option) any later version, as published by the Free -* Software Foundation -* -* 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, write to the -* Free Software Foundation, Inc., -* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -#ifndef BROWSEMAINWINDOW_H -#define BROWSEMAINWINDOW_H - -#include -#include -#include -#include -#include "vlcbrowseelement.h" -#include "favouritesmainwindow.h" - -namespace Ui { - class BrowseMainWindow; -} - -class BrowseMainWindow : public QMainWindow { - Q_OBJECT -public: - explicit BrowseMainWindow(QWidget *parent = 0); - ~BrowseMainWindow(); - -public slots: - void init(); - void browseDirectory(QString); - void onBrowse(); - void onPlay(); - void onAddToPlaylist(); - void onListSelectionChanged(); - void finished(QNetworkReply * reply); - void readReady(); - void error(QNetworkReply::NetworkError code); - void showCurrentDirectory(); - void setHomeFolder(); - void showHomeFolder(); - void showUserHomeFolder(); - void setFavourite(); - void showFavourites(); - void setHomeDirectory(); - -protected slots: - void parseXmlDirectory(); - void updateList(); - -protected: - void changeEvent(QEvent *e); - VlcBrowseElement getElementFromText(QString text); - QString getExtension(QString path, QString extension); - -private: - Ui::BrowseMainWindow *ui; - FavouritesMainWindow *mFavouritesMainWindow; - QNetworkAccessManager * mNetManager; - QString mCurrentDir; - QString mIp; - QList* mContents; - VlcBrowseElement mCurrentElement; - QByteArray mResponse; -}; - -#endif // BROWSEMAINWINDOW_H diff --git a/browsemainwindow.ui b/browsemainwindow.ui deleted file mode 100644 index 6ae1aee..0000000 --- a/browsemainwindow.ui +++ /dev/null @@ -1,97 +0,0 @@ - - - BrowseMainWindow - - - - 0 - 0 - 800 - 600 - - - - MainWindow - - - - - - - - - - - - - Play - - - - - - - Enqueue - - - - - - - Browse - - - - - - - - - - - 0 - 0 - 800 - 27 - - - - - menu - - - - - - - - - - - User Folder - - - - - Home - - - - - Set as Home - - - - - Favourites - - - - - Add to Favourite - - - - - - diff --git a/config-vlc.jpg b/config-vlc.jpg deleted file mode 100644 index b4610f057bfd3992d73e402eb33e40e28951c2f7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 77930 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

ctnJ7tnQUR$KDKUFR(x>F73A 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 Nai^!, Dru Moore , Yann Nave -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2, -* or (at your option) any later version, as published by the Free -* Software Foundation -* -* 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, write to the -* Free Software Foundation, Inc., -* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -#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 deleted file mode 100644 index e6c4f67..0000000 --- a/configdialog.h +++ /dev/null @@ -1,42 +0,0 @@ -/* VLC-REMOTE for MAEMO 5 -* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2, -* or (at your option) any later version, as published by the Free -* Software Foundation -* -* 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, write to the -* Free Software Foundation, Inc., -* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -#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/configdialog.ui b/configdialog.ui deleted file mode 100644 index c3dd6f0..0000000 --- a/configdialog.ui +++ /dev/null @@ -1,69 +0,0 @@ - - - ConfigDialog - - - - 0 - 0 - 442 - 304 - - - - Dialog - - - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'DejaVu Sans'; font-size:14pt; font-weight:400; font-style:normal;"> -<table border="0" style="-qt-table-type: root; margin-top:4px; margin-bottom:4px; margin-left:4px; margin-right:4px;"> -<tr> -<td style="border: none;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Enter IP of VLC server. </p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Example : <span style=" font-weight:600;">192.168.0.8:8080</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Be sure you have properly configured Vlc</p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> and allows connection by adding this IP in /vlc/http/.hosts</p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">More information on my blog : <a href="http://omedsoft.blogspot.com/"><span style=" text-decoration: underline; color:#0000ff;">omed.blogspot.com</span></a><br /></p></td></tr></table></body></html> - - - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - buttonBox - rejected() - ConfigDialog - reject() - - - 295 - 284 - - - 286 - 274 - - - - - diff --git a/favouritesmainwindow.cpp b/favouritesmainwindow.cpp deleted file mode 100644 index a578deb..0000000 --- a/favouritesmainwindow.cpp +++ /dev/null @@ -1,170 +0,0 @@ -/* VLC-REMOTE for MAEMO 5 -* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2, -* or (at your option) any later version, as published by the Free -* Software Foundation -* -* 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, write to the -* Free Software Foundation, Inc., -* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -#include "favouritesmainwindow.h" -#include "ui_favouritesmainwindow.h" -#include -#if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) -#include -#endif -#include "appsettings.h" -//#include "browsemainwindow.h" - -FavouritesMainWindow::FavouritesMainWindow(QWidget *parent) : - QMainWindow(parent), - ui(new Ui::FavouritesMainWindow) -{ - - ui->setupUi(this); - - setWindowTitle("Vlc remote"); - mCurrentItemIndex = -1; - - ui->listWidget->setTextElideMode(Qt::ElideMiddle); - ui->listWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - - ui->deleteButton->setIcon(QIcon::fromTheme("general_delete")); - ui->editButton->setIcon(QIcon::fromTheme("general_sketch")); - ui->browseButton->setIcon(QIcon::fromTheme("filemanager_media_folder")); - ui->saveButton->setIcon(QIcon::fromTheme("notes_save")); - ui->browseButton->setDisabled(true); - ui->editButton->setDisabled(true); - ui->deleteButton->setDisabled(true); - ui->actionSetHome->setDisabled(true); - ui->label->setVisible(false); - ui->lineEdit->setVisible(false); - ui->saveButton->setVisible(false); - ui->saveButton->setDisabled(true); - - connect(ui->browseButton,SIGNAL(clicked()),this,SLOT(onBrowse())); - connect(ui->deleteButton,SIGNAL(clicked()),this,SLOT(onDelete())); - connect(ui->editButton,SIGNAL(clicked()),this,SLOT(onEdit())); - connect(ui->listWidget, SIGNAL(itemSelectionChanged()), this, SLOT(onListSelectionChanged())); - connect(ui->actionSetHome, SIGNAL(triggered()), this, SLOT(setHomeFolder())); - connect(ui->saveButton, SIGNAL(clicked()), this, SLOT(onEditSave())); - connect(ui->lineEdit, SIGNAL(textChanged(QString)), this, SLOT(onLineEditTextChanged(QString))); - - init(); - - -} -void FavouritesMainWindow::init() // THIS METHOD IS CALLED WHEN CONFIG CHANGED AND WINDOW SHOWN... -{ - mFavourites = AppSettings::getFavourites(); - updateList(); -} - -FavouritesMainWindow::~FavouritesMainWindow() -{ - delete mFavourites; - delete ui; -} - -void FavouritesMainWindow::changeEvent(QEvent *e) -{ - QMainWindow::changeEvent(e); - switch (e->type()) { - case QEvent::LanguageChange: - ui->retranslateUi(this); - break; - default: - break; - } -} -void FavouritesMainWindow::updateList() { - ui->listWidget->clear(); - if (NULL != mFavourites && 0 < mFavourites->count()) { - for (int idx = 0; idx < mFavourites->count(); ++idx) { - QListWidgetItem* item = new QListWidgetItem(QIcon::fromTheme("imageviewer_favourite"), mFavourites->at(idx).name, ui->listWidget, LIST_ITEM_TYPE_OFFSET + idx); - ui->listWidget->addItem(item); - } - } -} -void FavouritesMainWindow::setHomeFolder() { - if (-1 < mCurrentItemIndex) { - AppSettings::setHomeDirectory(mCurrentFavourite); - } -} -void FavouritesMainWindow::onListSelectionChanged() { - ui->label->setVisible(false); - ui->lineEdit->setVisible(false); - ui->saveButton->setVisible(false); - ui->saveButton->setDisabled(true); - QList items = ui->listWidget->selectedItems(); - if (0 < items.count()) { - mCurrentItemIndex = ui->listWidget->currentIndex().row(); - mCurrentFavourite = mFavourites->at(items.at(0)->type() - LIST_ITEM_TYPE_OFFSET); // Qt reserves types up to 1000, we use an offset beyond that for index tracking. May prove to be too hacky! - ui->browseButton->setDisabled(false); - ui->editButton->setDisabled(false); - ui->deleteButton->setDisabled(false); - ui->actionSetHome->setDisabled(false); - } - else { - mCurrentItemIndex = -1; - ui->browseButton->setDisabled(true); - ui->editButton->setDisabled(true); - ui->deleteButton->setDisabled(true); - ui->actionSetHome->setDisabled(true); - } -} -void FavouritesMainWindow::onLineEditTextChanged(QString text) { - if (0 < text.length()) { - ui->saveButton->setDisabled(false); - } - else { - ui->saveButton->setDisabled(true); - } -} -void FavouritesMainWindow::onEditSave() { - if (-1 < mCurrentItemIndex && 0 < ui->lineEdit->text().length()) { - ui->label->setVisible(false); - ui->lineEdit->setVisible(false); - ui->saveButton->setVisible(false); - ui->saveButton->setDisabled(true); - AppSettings::deleteFavourite(mCurrentFavourite); - mCurrentFavourite.name = ui->lineEdit->text(); - AppSettings::addFavourite(mCurrentFavourite); - ui->lineEdit->setText(""); - ui->listWidget->itemAt(mCurrentItemIndex, 0)->setText(mCurrentFavourite.name); - init(); - } -} -void FavouritesMainWindow::onEdit() { - if (-1 < mCurrentItemIndex) { - ui->label->setVisible(true); - ui->lineEdit->setVisible(true); - ui->saveButton->setVisible(true); - ui->saveButton->setDisabled(false); - ui->lineEdit->setText(mCurrentFavourite.name); - ui->browseButton->setDisabled(true); - ui->editButton->setDisabled(true); - ui->deleteButton->setDisabled(true); - } -} -void FavouritesMainWindow::onBrowse() { - if (-1 < mCurrentItemIndex) { - emit browseDirectory(mCurrentFavourite.path); - //this->close(); - //((BrowseMainWindow *)this->parent())->browseDirectory(mCurrentFavourite.path); - } -} -void FavouritesMainWindow::onDelete() { - if (-1 < mCurrentItemIndex) { - AppSettings::deleteFavourite(mCurrentFavourite); - init(); - } -} diff --git a/favouritesmainwindow.h b/favouritesmainwindow.h deleted file mode 100644 index 76964b0..0000000 --- a/favouritesmainwindow.h +++ /dev/null @@ -1,67 +0,0 @@ -/* VLC-REMOTE for MAEMO 5 -* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2, -* or (at your option) any later version, as published by the Free -* Software Foundation -* -* 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, write to the -* Free Software Foundation, Inc., -* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -#ifndef FAVOURITESMAINWINDOW_H -#define FAVOURITESMAINWINDOW_H - -#include -#include -#include -#include -#include "appsettings.h" - -#ifndef LIST_ITEM_TYPE_OFFSET -#define LIST_ITEM_TYPE_OFFSET 1000 -#endif - -namespace Ui { - class FavouritesMainWindow; -} - -class FavouritesMainWindow : public QMainWindow { - Q_OBJECT -public: - explicit FavouritesMainWindow(QWidget *parent = 0); - ~FavouritesMainWindow(); - -public slots: - void init(); - void onListSelectionChanged(); - void onLineEditTextChanged(QString text); - void onBrowse(); - void onEdit(); - void onDelete(); - void setHomeFolder(); - void onEditSave(); - -protected slots: - -signals: - void browseDirectory(QString path); - -protected: - void changeEvent(QEvent *e); - void updateList(); - -private: - Ui::FavouritesMainWindow *ui; - int mCurrentItemIndex; - QList* mFavourites; - VlcDirectory mCurrentFavourite; -}; - -#endif // FAVOURITESMAINWINDOW_H diff --git a/favouritesmainwindow.ui b/favouritesmainwindow.ui deleted file mode 100644 index b379237..0000000 --- a/favouritesmainwindow.ui +++ /dev/null @@ -1,88 +0,0 @@ - - - FavouritesMainWindow - - - - 0 - 0 - 798 - 598 - - - - MainWindow - - - - - - - - - - - - Name - - - - - - - - - - Save - - - - - - - - - - - Delete - - - - - - - Edit - - - - - - - Browse - - - - - - - - - - - 0 - 0 - 798 - 20 - - - - - - - Set as Home - - - - - - diff --git a/main.cpp b/main.cpp deleted file mode 100644 index 8e21758..0000000 --- a/main.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* VLC-REMOTE for MAEMO 5 -* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2, -* or (at your option) any later version, as published by the Free -* Software Foundation -* -* 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, write to the -* Free Software Foundation, Inc., -* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -#include -#include -#include -#include -#include -#include -#include "playermainwindow.h" -#include "appsettings.h" -int main(int argc, char *argv[]) -{ - QApplication a(argc, argv); - - QCoreApplication::setOrganizationName("Omed"); - QCoreApplication::setOrganizationDomain("medsoft.blogspot.com/"); - QCoreApplication::setApplicationName("Maemo VLC remote"); - - QString locale = QLocale::system().name(); - QTranslator translator; - translator.load(QString(":/languages/vlcremote_") + locale); - a.installTranslator(&translator); - - QTextCodec::setCodecForTr(QTextCodec::codecForName("utf8")); - - - qDebug() << AppSettings::getCurrentIp(); - - - PlayerMainWindow * mainwindow = new PlayerMainWindow; - - //mainwindow->setAttribute(Qt::WA_Maemo5LandscapeOrientation, true); - //mainwindow->setAttribute(Qt::WA_Maemo5PortraitOrientation, true); - //mainwindow->setAttribute(Qt::WA_Maemo5AutoOrientation, true); - - mainwindow->showMaximized(); - #if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) - Orientation o = AppSettings::getOrientation(); - switch (o) { - case AUTO_ROTATE: - mainwindow->setAttribute(Qt::WA_Maemo5AutoOrientation, true); - break; - case LANDSCAPE: - mainwindow->setAttribute(Qt::WA_Maemo5LandscapeOrientation, true); - break; - case PORTRAIT: - mainwindow->setAttribute(Qt::WA_Maemo5PortraitOrientation, true); - break; - default: - mainwindow->setAttribute(Qt::WA_Maemo5AutoOrientation, true); - break; - } -#endif - return a.exec(); -} diff --git a/newaccountdialog.cpp b/newaccountdialog.cpp deleted file mode 100644 index 3a3acd3..0000000 --- a/newaccountdialog.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* VLC-REMOTE for MAEMO 5 -* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2, -* or (at your option) any later version, as published by the Free -* Software Foundation -* -* 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, write to the -* Free Software Foundation, Inc., -* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -#include "newaccountdialog.h" -#include -#include -#include -//#include - -NewAccountDialog::NewAccountDialog(QWidget *parent) -{ - Q_UNUSED(parent); - this->setWindowTitle(tr("Add account")); - - mKeyLineEdit = new QLineEdit; - mIpLineEdit = new QLineEdit; - mPortLineEdit = new QLineEdit; - mPortLineEdit->setText("8080"); - mPortLineEdit->setReadOnly(false); - - mButtonBox = new QDialogButtonBox; - mButtonBox->addButton(QDialogButtonBox::Save); - mButtonBox->addButton(QDialogButtonBox::Cancel); - - connect(mButtonBox, SIGNAL(accepted()), this, SLOT(save())); - connect(mButtonBox, SIGNAL(rejected()), this, SLOT(reject())); - - QFormLayout *layout = new QFormLayout; - layout->expandingDirections(); - layout->addRow(tr("Name:"), mKeyLineEdit); - layout->addRow(tr("Ip:"), mIpLineEdit); - layout->addRow(tr("Port:"), mPortLineEdit); - layout->addWidget(mButtonBox); - - setLayout(layout); -} - -void NewAccountDialog::save() -{ - QString myKey = mKeyLineEdit->text(); - QString myIp = mIpLineEdit->text(); - QString myPort = mPortLineEdit->text(); - - QSettings settings; - settings.beginGroup("account"); - if (!mEditKey.isEmpty()) { - settings.remove(mEditKey); - } - - if (!myIp.isEmpty() && !myKey.isEmpty()) { - if (myPort.isEmpty()) { - myPort = "8080"; - } - settings.setValue(myKey, myIp+":"+myPort); - // Rajouter des tests pour vérifier qu'on est sur Maemo - //QMaemo5InformationBox::information(this, tr("Account saved"), QMaemo5InformationBox::DefaultTimeout); - } - settings.endGroup(); - - emit accept(); -} - -void NewAccountDialog::edit(QString &key, QString &ip) -{ - Q_UNUSED(ip); - this->setWindowTitle(tr("Edit account")); - - QSettings settings; - settings.beginGroup("account"); - QString value = settings.value(key).toString(); - settings.endGroup(); - - QStringList values = value.split(":"); - - mEditKey = key; - mEditIp = values.first(); - mEditPort = values.last(); - - mKeyLineEdit->setText(mEditKey); - mKeyLineEdit->setDisabled(true); - mIpLineEdit->setText(mEditIp); - mPortLineEdit->setText(mEditPort); -} - diff --git a/newaccountdialog.h b/newaccountdialog.h deleted file mode 100644 index 70794ab..0000000 --- a/newaccountdialog.h +++ /dev/null @@ -1,50 +0,0 @@ -/* VLC-REMOTE for MAEMO 5 -* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2, -* or (at your option) any later version, as published by the Free -* Software Foundation -* -* 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, write to the -* Free Software Foundation, Inc., -* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -#ifndef NEWACCOUNTDIALOG_H -#define NEWACCOUNTDIALOG_H - -#include -#include -#include -#include - -class NewAccountDialog : public QDialog -{ - Q_OBJECT - -public: - explicit NewAccountDialog(QWidget *parent = 0); - void edit(QString &key, QString &ip); - -public slots: - void save(); - -private: - QLineEdit *mKeyLineEdit; - QLineEdit *mIpLineEdit; - QLineEdit *mPortLineEdit; - QPushButton *mSavePushButton; - QPushButton *mCancelPushButton; - QDialogButtonBox *mButtonBox; - - QString mEditKey; - QString mEditIp; - QString mEditPort; -}; - -#endif // NEWACCOUNTDIALOG_H diff --git a/playermainwindow.cpp b/playermainwindow.cpp deleted file mode 100644 index 33d001c..0000000 --- a/playermainwindow.cpp +++ /dev/null @@ -1,511 +0,0 @@ - /* VLC-REMOTE for MAEMO 5 - * Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, - * or (at your option) any later version, as published by the Free - * Software Foundation - * - * 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, write to the - * Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - #include - #include - #include - #include "playermainwindow.h" - #include "ui_playermainwindow.h" - #include "configdialog.h" - #include "aboutdialog.h" - #include "accountdialog.h" - #include "appsettings.h" - //#include "vlcstatus.h" - - PlayerMainWindow::PlayerMainWindow(QWidget *parent) : - QMainWindow(parent), - ui(new Ui::PlayerMainWindow) - { - ui->setupUi(this); - setWindowTitle("Vlc remote"); - - - - mTimer = new QTimer(this); - mNetManager = new QNetworkAccessManager(this); - mPlayListMainWindow = new PlayListMainWindow; - mBrowserMainWindow = new BrowseMainWindow; - - mVolume = 100; - mMuted = false; - - mIsLandscape = true; - - ui->playlistButton->setIcon(QIcon::fromTheme("notes_bullets")); - ui->browseButton->setIcon(QIcon::fromTheme("filemanager_media_folder")); - - ui->previousButton->setIcon(QIcon::fromTheme("pdf_viewer_first_page")); - ui->nextButton->setIcon(QIcon::fromTheme("pdf_viewer_last_page")); - ui->playpauseButton->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")); - ui->volMute->setIcon(QIcon::fromTheme("statusarea_volume_mute")); - - ui->labelArtPortrait->setVisible(false); - ui->labelArtLandscape->setVisible(false); - - ui->labelTitle->setTextFormat(Qt::RichText); - ui->labelArtist->setTextFormat(Qt::RichText); - ui->labelAlbum->setTextFormat(Qt::RichText); - - - #if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) - - mPlayListMainWindow->setParent(this); - mPlayListMainWindow->setAttribute(Qt::WA_Maemo5StackedWindow, true); - setAttribute(Qt::WA_Maemo5StackedWindow, true); - mPlayListMainWindow->setWindowFlags(mPlayListMainWindow->windowFlags() | Qt::Window); - - mBrowserMainWindow->setParent(this); - mBrowserMainWindow->setAttribute(Qt::WA_Maemo5StackedWindow, true); - setAttribute(Qt::WA_Maemo5StackedWindow, true); - mBrowserMainWindow->setWindowFlags(mBrowserMainWindow->windowFlags() | Qt::Window); - - connect(QApplication::desktop(), SIGNAL(resized(int)), this, SLOT(orientationChanged())); - - #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->actionPortrait,SIGNAL(triggered()),this,SLOT(setPortrait())); - connect(ui->actionLandscape,SIGNAL(triggered()),this,SLOT(setLandscape())); - connect(ui->actionAutoRotate,SIGNAL(triggered()),this,SLOT(setAutoRotate())); - connect(ui->playlistButton,SIGNAL(clicked()),mPlayListMainWindow,SLOT(show())); - connect(ui->playlistButton,SIGNAL(clicked()),mPlayListMainWindow,SLOT(showPlayList())); - connect(ui->browseButton,SIGNAL(clicked()),mBrowserMainWindow,SLOT(show())); - connect(ui->browseButton,SIGNAL(clicked()),mBrowserMainWindow,SLOT(showCurrentDirectory())); - - connect(ui->playpauseButton,SIGNAL(clicked()),this,SLOT(playpause())); - connect(ui->stopButton,SIGNAL(clicked()),this,SLOT(stop())); - 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->volMute,SIGNAL(clicked()),this,SLOT(volMute())); - connect(ui->slider,SIGNAL(sliderMoved(int)),this,SLOT(slide(int))); - - connect(mPlayListMainWindow, SIGNAL(idUpdated(int,bool,QString)), this, SLOT(playlistIdUpdated(int, bool, QString))); - - - // check if last used connection is still valid or showConfig - QSettings settings; - QString last_ip = AccountDialog::currentIp(); - if (!last_ip.isNull() && !last_ip.isEmpty()) { - QTcpSocket * socket = new QTcpSocket; - if(last_ip.contains(":")) - { - QStringList hostSplit = last_ip.split(":"); - QString ip = hostSplit.at(0); - QString port = hostSplit.at(1); - socket->connectToHost(ip,port.toInt()); - } - else { - socket->connectToHost(last_ip,8080); - } - if (!socket->waitForConnected(1000)) { - showConfig(); - } - else { - mIp= last_ip; - - mPlayListMainWindow->init(); - mBrowserMainWindow->init(); - mTimer->start(5000); - askStatus(); - } - delete socket; - } - else { - showConfig(); - } - - - } - - - 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::setPortrait() - { - #if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) - AppSettings::setOrientation(PORTRAIT); - this->setAttribute(Qt::WA_Maemo5PortraitOrientation, true); - #endif - } - - void PlayerMainWindow::setLandscape() - { - #if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) - AppSettings::setOrientation(LANDSCAPE); - this->setAttribute(Qt::WA_Maemo5LandscapeOrientation, true); - #endif - } - - void PlayerMainWindow::setAutoRotate() - { - #if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) - AppSettings::setOrientation(AUTO_ROTATE); - this->setAttribute(Qt::WA_Maemo5AutoOrientation, true); - #endif - } - - void PlayerMainWindow::orientationChanged() { - QRect screenGeometry = QApplication::desktop()->screenGeometry(); - mIsLandscape = (screenGeometry.width() > screenGeometry.height()); - if (mHasImage) { - if (mIsLandscape) { - ui->labelArtPortrait->setVisible(false); - ui->labelArtLandscape->setVisible(true); - } - else { - ui->labelArtLandscape->setVisible(false); - ui->labelArtPortrait->setVisible(true); - } - } - else { - ui->labelArtLandscape->setVisible(false); - ui->labelArtPortrait->setVisible(false); - } - } - - void PlayerMainWindow::playpause() - { - // NB. There is no guarentee that our current state is the real current state. - // This is due to the polling frequency and possibility of user interaction directly on the server. - // Still this is probably better than nothing and our next real poll will set us straight again. - if (PAUSED == mCurrentStatus.state) { - mCurrentStatus.state = PLAYING; - pause(); - updateUiWithCurrentStatus(); - } - else if (PLAYING == mCurrentStatus.state) { - mCurrentStatus.state = PAUSED; - pause(); - updateUiWithCurrentStatus(); - } - else { - // could be STOP or UNKNOWN, either way there is no guarentee we will enter a playing state next. - // So don't update the current state or UI - // Ideally we would try to find a way to check the current state again but this could lead to an infinite loop! - play(); - } - } - 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() - { - QUrl url = QUrl("http://"+mIp+"/requests/status.xml?command=volume"); - url.addEncodedQueryItem(QByteArray("val"), QByteArray("%2B10")); - mNetManager->get(QNetworkRequest(url)); - } - void PlayerMainWindow::volDown() - { - mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=volume&val=-10"))); - } - void PlayerMainWindow::volMute() - { - this->mMuted = !this->mMuted; - if (this->mMuted) { - mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=volume&val=0"))); - } - else { - mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=volume&val="+QString::number(this->mVolume)))); - } - } - void PlayerMainWindow::slide(int value) - { - mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=seek&val="+QString::number(value)+"%25"))); - } - - void PlayerMainWindow::showConfig() - { - mTimer->stop(); - AccountDialog * dialog = new AccountDialog; - dialog->exec(); - - mIp= AccountDialog::currentIp(); - - mPlayListMainWindow->init(); - mBrowserMainWindow->init(); - mTimer->start(5000); - askStatus(); - } - void PlayerMainWindow::showAbout() - { - - AboutDialog * dialog = new AboutDialog; - dialog->exec(); - - } - - void PlayerMainWindow::askStatus() - { - //qDebug() << "Status requested. at:" << QTime::currentTime().toString("hh::mm:ss"); - 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()); - delete reply; - QDomElement docElem = doc.documentElement(); - // Get the raw values - 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(); - int random = docElem.namedItem("random").toElement().text().toInt(); - int loop = docElem.namedItem("loop").toElement().text().toInt(); - int repeat = docElem.namedItem("repeat").toElement().text().toInt(); - QString state = docElem.namedItem("state").toElement().text(); - QDomNode infoNode = docElem.namedItem("information"); - QDomNode metaInfoNode = infoNode.namedItem("meta-information"); - QString title = metaInfoNode.namedItem("title").toElement().text().replace("\\\\", "\\"); - // if it's a file style title fix it up - if (40 < title.length()) { - if (0 < title.lastIndexOf("\\")) { - title = title.right(title.length() - (title.lastIndexOf("\\") + 1)); - } - else if (0 < title.lastIndexOf("/")) { - title = title.right(title.length() - (title.lastIndexOf("/") + 1)); - } - } - QString artist = metaInfoNode.namedItem("artist").toElement().text(); - QString album = metaInfoNode.namedItem("album").toElement().text(); - QString now_playing = metaInfoNode.namedItem("now_playing").toElement().text(); - QString art_url = metaInfoNode.namedItem("art_url").toElement().text(); - //metaInfoNode.clear(); - //infoNode.clear(); - //docElem.clear(); - //doc.clear(); - // Populate the current status structure - // now would be a good time to work out if we are a new track / file or not. - // key if we are going to look for album art later - // for now we check length and title this will require further examination later - mCurrentStatus.newtrack = true; - if (mCurrentStatus.length == length && !mCurrentStatus.title.isNull() && 0 == QString::compare(mCurrentStatus.title, title)) { - mCurrentStatus.newtrack = false; - } - mCurrentStatus.volume = volume; - mCurrentStatus.length = length; - mCurrentStatus.time = time; - mCurrentStatus.position = position; - mCurrentStatus.random = (1 == random); - mCurrentStatus.loop = (1 == loop); - mCurrentStatus.repeat = (1 == repeat); - mCurrentStatus.title = title; - mCurrentStatus.artist = artist; - mCurrentStatus.album = album; - mCurrentStatus.nowplaying = now_playing; - mCurrentStatus.hasart = (!art_url.isNull() && !art_url.isEmpty()); - if (!state.isNull() && !state.isEmpty()) { - if (0 == QString::compare("playing", state, Qt::CaseInsensitive)) { - mCurrentStatus.state = PLAYING; - } - else if (0 == QString::compare("paused", state, Qt::CaseInsensitive)) { - mCurrentStatus.state = PAUSED; - } - else if (0 == QString::compare("stop", state, Qt::CaseInsensitive)) { - mCurrentStatus.state = STOP; - } - else { - mCurrentStatus.state = UNKNOWN; - } - } - else { - mCurrentStatus.state = UNKNOWN; - } - // What's our mute status? - if (0 < mCurrentStatus.volume) { - this->mVolume = mCurrentStatus.volume; - this->mMuted = false; - } - else { - this->mMuted = true; - } - // Update the UI - updateUiWithCurrentStatus(); - - } - - void PlayerMainWindow::updateUiWithCurrentStatus() { - // position - QTime timePosition(0,0,0) ; - timePosition = timePosition.addSecs(mCurrentStatus.time); - - ui->timeLabel->setText(timePosition.toString("h:mm:ss")); - - // duration - if (0 < mCurrentStatus.length) { - QTime timeDuration(0,0,0) ; - timeDuration = timeDuration.addSecs(mCurrentStatus.length); - - ui->durationLabel->setText(timeDuration.toString("h:mm:ss")); - } - else { - ui->durationLabel->setText("0:00:00"); - } - - - if (mCurrentStatus.position >= 0 && mCurrentStatus.position <= 100) { - ui->slider->blockSignals(true); - ui->slider->setValue(mCurrentStatus.position); - ui->slider->blockSignals(false); - } - - ui->labelTitle->setText(mCurrentStatus.title); - ui->labelArtist->setText(mCurrentStatus.artist); - ui->labelAlbum->setText(mCurrentStatus.album); - - if (PLAYING == mCurrentStatus.state) { - ui->playpauseButton->setIcon(QIcon::fromTheme("camera_video_pause")); - } - else { - ui->playpauseButton->setIcon(QIcon::fromTheme("camera_playback")); - } - - if (mCurrentStatus.newtrack) { - // potential actions: - // rebuild display layout - // retrieve album art - mHasImage = false; - QTimer::singleShot(500, mPlayListMainWindow, SLOT(requestPlayList())); - } - // Update the buttons on the playlist window - if (NULL != this->mPlayListMainWindow) { - this->mPlayListMainWindow->updateUiWithCurrentStatus(& mCurrentStatus); - } - - } - void PlayerMainWindow::playlistIdUpdated(int id, bool hasart, QString extension) { - Q_UNUSED(extension); - if (hasart) { - getCoverArt(id); - } - else { - ui->labelArtLandscape->setVisible(false); - ui->labelArtPortrait->setVisible(false); - // could use a default graphic from extension here! - // setCoverArtFromPixmap(); - } - } - void PlayerMainWindow::error(QNetworkReply::NetworkError code) { - qDebug() << "Error Code: " << code; - } - void PlayerMainWindow::readReady() { - QNetworkReply * reply = qobject_cast(sender()); - // append to buffer - mResponse += reply->readAll(); - } - void PlayerMainWindow::finished(QNetworkReply * reply) { - // now we can call setCoverArt to process the full buffers - this->setCoverArt(mResponse); - // only interested in finished signals - disconnect(mNetManager,SIGNAL(finished(QNetworkReply *)),this,SLOT(finished(QNetworkReply *))); - delete reply; - } - void PlayerMainWindow::getCoverArt(int id) { - qDebug() << "getCoverArt id=!" << id; - mResponse.clear(); - QNetworkReply * reply = mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/art?id=" + QString::number(id)))); - connect(reply,SIGNAL(readyRead()),this,SLOT(readReady())); - connect(reply,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(error(QNetworkReply::NetworkError))); - connect(mNetManager,SIGNAL(finished(QNetworkReply *)),this,SLOT(finished(QNetworkReply *))); - - } - void PlayerMainWindow::setCoverArt(const QByteArray data) { - QPixmap* image = new QPixmap(); - if (image->loadFromData(data)) { - mHasImage = true; - ui->labelArtLandscape->setPixmap(image->scaledToHeight(120, Qt::SmoothTransformation)); - ui->labelArtPortrait->setPixmap(image->scaledToHeight(310, Qt::SmoothTransformation)); - if (mIsLandscape) { - ui->labelArtPortrait->setVisible(false); - ui->labelArtLandscape->setVisible(true); - } - else { - ui->labelArtLandscape->setVisible(false); - ui->labelArtPortrait->setVisible(true); - } - } - else { - qDebug() << "image load failed!"; - qDebug() << "data.length" << data.length(); - ui->labelArtPortrait->setVisible(false); - ui->labelArtLandscape->setVisible(false); - } - delete image; - } - void PlayerMainWindow::setCoverArtFromPixmap(QPixmap image) { - mHasImage = true; - ui->labelArtLandscape->setPixmap(image.scaledToHeight(120, Qt::SmoothTransformation)); - ui->labelArtPortrait->setPixmap(image.scaledToHeight(320, Qt::SmoothTransformation)); - if (mIsLandscape) { - ui->labelArtPortrait->setVisible(false); - ui->labelArtLandscape->setVisible(true); - } - else { - ui->labelArtLandscape->setVisible(false); - ui->labelArtPortrait->setVisible(true); - } - } - diff --git a/playermainwindow.h b/playermainwindow.h deleted file mode 100644 index 73c22b2..0000000 --- a/playermainwindow.h +++ /dev/null @@ -1,90 +0,0 @@ -/* VLC-REMOTE for MAEMO 5 -* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2, -* or (at your option) any later version, as published by the Free -* Software Foundation -* -* 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, write to the -* Free Software Foundation, Inc., -* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -#ifndef PLAYERMAINWINDOW_H -#define PLAYERMAINWINDOW_H - -#include -#include -#include -#include -#include "playlistmainwindow.h" -#include "browsemainwindow.h" -#include "vlcstatus.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 playpause(); - void stop(); - void pause(); - void previous(); - void next(); - void fullscreen(); - void volUp(); - void volDown(); - void volMute(); - void slide(int value); - void updateUiWithCurrentStatus(); - void setCoverArt(const QByteArray data); - void setCoverArtFromPixmap(QPixmap image); - void getCoverArt(int id); - void finished(QNetworkReply * reply); - void error(QNetworkReply::NetworkError code); - void readReady(); - void orientationChanged(); - void setPortrait(); - void setLandscape(); - void setAutoRotate(); - void playlistIdUpdated(int id, bool hasart, QString extension); - - -protected slots: - void parseXmlStatus(); -protected: - void changeEvent(QEvent *e); - - -private: - Ui::PlayerMainWindow *ui; - PlayListMainWindow * mPlayListMainWindow; - BrowseMainWindow * mBrowserMainWindow; - QNetworkAccessManager * mNetManager; - QString mIp; - QTimer * mTimer; - int mVolume; - int mMuted; - VlcStatus mCurrentStatus; - QByteArray mResponse; - bool mIsLandscape; - bool mHasImage; - -}; - -#endif // PLAYERMAINWINDOW_H diff --git a/playermainwindow.ui b/playermainwindow.ui deleted file mode 100644 index a9d9065..0000000 --- a/playermainwindow.ui +++ /dev/null @@ -1,320 +0,0 @@ - - - PlayerMainWindow - - - - 0 - 0 - 796 - 631 - - - - Vlc-Remote - - - - - - - - 380 - 350 - - - - - 380 - 350 - - - - Qt::AlignCenter|Qt::AlignHCenter|Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - - - 0 - 30 - - - - Information - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 30 - - - - Information - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 30 - - - - Information - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - 140 - 140 - - - - - 140 - 140 - - - - Qt::AlignCenter|Qt::AlignHCenter|Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - Qt::Vertical - - - - 20 - 100 - - - - - - - - - - color: rgb(201, 201, 201); - - - - - - - - - - color: rgb(201, 201, 201); - - - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - true - - - 100 - - - Qt::Horizontal - - - - - - - - - < - - - - - - - Play/Pause - - - - - - - > - - - - - - - Stop - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - FS - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - V+ - - - - - - - V- - - - - - - - Mute - - - - - - - - - - - PlayList - - - - - - - Browse - - - - - - - - - - - 0 - 0 - 796 - 20 - - - - - menu - - - - - - - - - - - - Configuration - - - - - About - - - - - Portrait Mode - - - - - Landscape Mode - - - - - Auto Rotate - - - - - - diff --git a/playlistmainwindow.cpp b/playlistmainwindow.cpp deleted file mode 100644 index a6c8a5c..0000000 --- a/playlistmainwindow.cpp +++ /dev/null @@ -1,411 +0,0 @@ -/* VLC-REMOTE for MAEMO 5 - * Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, - * or (at your option) any later version, as published by the Free - * Software Foundation - * - * 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, write to the - * Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#include "playlistmainwindow.h" -#include "ui_playlistmainwindow.h" -#include -#include -#if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) -#include -#endif -#include "configdialog.h" -#include "aboutdialog.h" -#include "appsettings.h" -//#include "vlcstatus.h" - -PlayListMainWindow::PlayListMainWindow(QWidget *parent) : - QMainWindow(parent), - ui(new Ui::PlayListMainWindow) -{ - - ui->setupUi(this); - mTimer = new QTimer(this); - setWindowTitle("Vlc remote"); - - mCurrentDepth = 0; - mCurrentVlcIndex = 0; - - - mNetManager = new QNetworkAccessManager(this); - - mContents = new QList(); - - ui->listWidget->setTextElideMode(Qt::ElideLeft); - ui->listWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - - ui->playButton->setIcon(QIcon::fromTheme("camera_playback")); - ui->clearButton->setIcon(QIcon::fromTheme("general_delete")); - ui->shuffleButton->setIcon(QIcon::fromTheme("mediaplayer_default_shuffle")); - ui->loopButton->setIcon(QIcon::fromTheme("general_refresh")); - ui->repeatButton->setIcon(QIcon::fromTheme("general_redo")); - ui->removeButton->setIcon(QIcon::fromTheme("general_close")); - - ui->clearButton->setDisabled(false); - ui->shuffleButton->setDisabled(false); - ui->loopButton->setDisabled(false); - ui->repeatButton->setDisabled(false); - ui->removeButton->setDisabled(true); - ui->playButton->setDisabled(true); - - connect(ui->playButton,SIGNAL(clicked()),this,SLOT(onPlay())); - connect(ui->removeButton,SIGNAL(clicked()),this,SLOT(onRemove())); - connect(ui->repeatButton,SIGNAL(clicked()),this,SLOT(onRepeat())); - connect(ui->loopButton,SIGNAL(clicked()),this,SLOT(onLoop())); - connect(ui->shuffleButton,SIGNAL(clicked()),this,SLOT(onShuffle())); - connect(ui->clearButton,SIGNAL(clicked()),this,SLOT(onClear())); - connect(ui->listWidget, SIGNAL(itemSelectionChanged()), this, SLOT(onListSelectionChanged())); - - init(); - -} -void PlayListMainWindow::init() // CALL WHEN CONFIG CHANGES -{ - mIp = AppSettings::getCurrentIp(); // AccountDialog::currentIp(); -} -void PlayListMainWindow::showPlayList() // CALL WHEN SHOWN -{ - requestPlayList(); -} - -PlayListMainWindow::~PlayListMainWindow() -{ - delete ui; -} - -void PlayListMainWindow::changeEvent(QEvent *e) -{ - QMainWindow::changeEvent(e); - switch (e->type()) { - case QEvent::LanguageChange: - ui->retranslateUi(this); - break; - default: - break; - } -} - -void PlayListMainWindow::onListSelectionChanged() { - QList items = ui->listWidget->selectedItems(); - if (0 < items.count()) { - // TODO VLC doesn't seem to support removing nodes! - // Playing nodes works fine, however. - // should check to see if it is a leaf or not and disable the remove button - mCurrentVlcIndex = items.at(0)->type() - LIST_ITEM_TYPE_OFFSET; // Qt reserves types up to 1000, we use an offset beyond that for index tracking. May prove to be too hacky! - mCurrentElement = getElementFromId(mCurrentVlcIndex); - if (0 == QString::compare("node", mCurrentElement.type)) { - ui->removeButton->setDisabled(true); - ui->playButton->setDisabled(false); - } - else { - ui->removeButton->setDisabled(false); - ui->playButton->setDisabled(false); - } - } - else { - mCurrentVlcIndex = 0; - ui->removeButton->setDisabled(true); - ui->playButton->setDisabled(true); - } -} - -void PlayListMainWindow::onRemove() { - if (0 < this->mCurrentVlcIndex) { - mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=pl_delete&id=" + QString::number(this->mCurrentVlcIndex)))); - //connect(mNetManager,SIGNAL(finished(QNetworkReply *)),this,SLOT(requestPlayList())); - // don't refresh just clear the item! - delete ui->listWidget->takeItem(ui->listWidget->currentRow()); - } -} -void PlayListMainWindow::onPlay() { - if (0 < this->mCurrentVlcIndex) { - mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=pl_play&id=" + QString::number(this->mCurrentVlcIndex)))); - } -} -void PlayListMainWindow::onRepeat() { - mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=pl_repeat"))); -} -void PlayListMainWindow::onLoop() { - mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=pl_loop"))); -} -void PlayListMainWindow::onShuffle() { - mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=pl_random"))); -} -void PlayListMainWindow::onClear() { - mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=pl_empty"))); - mContents->clear(); - ui->listWidget->clear(); - //connect(mNetManager,SIGNAL(finished(QNetworkReply *)),this,SLOT(requestPlayList())); -} -void PlayListMainWindow::requestPlayList() { - mResponse.clear(); - ui->removeButton->setDisabled(true); - ui->playButton->setDisabled(true); -#if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) - this->setAttribute(Qt::WA_Maemo5ShowProgressIndicator, true); -#endif - QNetworkReply * reply = mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/playlist.xml"))); - disconnect(mNetManager,SIGNAL(finished(QNetworkReply *)),this,SLOT(requestPlayList())); - connect(reply,SIGNAL(readyRead()),this,SLOT(readReady())); - connect(reply,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(error(QNetworkReply::NetworkError))); - connect(mNetManager,SIGNAL(finished(QNetworkReply *)),this,SLOT(finished(QNetworkReply *))); -} -void PlayListMainWindow::error(QNetworkReply::NetworkError code) { -#if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) - this->setAttribute(Qt::WA_Maemo5ShowProgressIndicator, false); -#endif - qDebug() << code; -#if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) - QMaemo5InformationBox::information(this, tr("Playlist could not be retrieved."), QMaemo5InformationBox::DefaultTimeout); -#endif -} -void PlayListMainWindow::readReady() { - QNetworkReply * reply = qobject_cast(sender()); - // append to buffer - mResponse += reply->readAll(); -} -void PlayListMainWindow::finished(QNetworkReply * reply) { - // now we can call parseXmlList to process the full buffers - this->parseXmlPlayList(); - // only interested in finished signals - disconnect(mNetManager,SIGNAL(finished(QNetworkReply *)),this,SLOT(finished(QNetworkReply *))); -#if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) - this->setAttribute(Qt::WA_Maemo5ShowProgressIndicator, false); -#endif - delete reply; -} - -void PlayListMainWindow::parseXmlPlayList() { - mContents->clear(); - QDomDocument doc; - doc.setContent(this->mResponse); - QDomElement docElem = doc.documentElement(); - QDomNodeList nodes = docElem.elementsByTagName("node"); - int depth = 0; - - int currentLeafId = 0; - bool hasArt = false; - QString extension = ""; - - int ct = nodes.count(); - for (int idx = 0; idx < ct; ++idx) { - QDomNode node = nodes.at(idx); - QString current = ""; - //QString name = node.attributes().namedItem("name").nodeValue().replace("\\\\", "\\"); - int id = node.attributes().namedItem("id").nodeValue().toInt(); - if (4 > id && 0 == QString::compare(node.attributes().namedItem("ro").nodeValue(), "ro")) { - // got the main playlist, let's build it up - if (node.hasChildNodes()) { - QDomNodeList leafs = node.childNodes(); - int leafct = leafs.count(); - if (0 < leafct) { - depth = 1; - for (int jdx = 0; jdx < leafct; ++jdx) { - QDomNode leaf = leafs.at(jdx); - parsePlayListItem(&leaf, &extension, &hasArt, ¤tLeafId, 1); - } - } - } - - } - } - - mResponse.clear(); - - emit this->idUpdated(currentLeafId, hasArt, extension); - this->updateList(); - - -} - - -int PlayListMainWindow::parsePlayListItem(QDomNode *node, QString *extension, bool *hasArt, int *currentLeafId, int depth) { - int leafCt = 0; - if (NULL != node) { - QString current; - VlcPlayListElementSimple* el = new VlcPlayListElementSimple(); - el->id = node->attributes().namedItem("id").nodeValue().toInt(); - el->path = node->attributes().namedItem("uri").nodeValue(); - el->name = node->attributes().namedItem("name").nodeValue().replace("\\\\", "\\"); - current = node->attributes().namedItem("current").nodeValue(); - el->playing = (0 < current.length()); - el->depth = depth; - if (0 != QString::compare(node->nodeName(), "node")) { - el->type = "leaf"; - el->extension = getExtension(el->path, NULL); - if (el->playing) { - *currentLeafId = el->id; - QString art = node->toElement().namedItem("art_url").toElement().text(); - *hasArt = (!art.isNull() && !art.isEmpty()); - *extension = getExtension(el->path, NULL); - } - QString title = node->toElement().namedItem("title").toElement().text(); - QString artist = node->toElement().namedItem("artist").toElement().text(); - QString album = node->toElement().namedItem("album").toElement().text(); - if (0 < artist.length() || 0 < album.length()) { - el->name = "" + title + "\n" + artist + " - " + album; - } - this->mContents->append(*el); - ++leafCt; - delete el; - } - else { - el->type = "node"; - el->extension = getExtension(el->path, NULL); - // empty nodes appear in the playlist when they can't be played! - if (node->hasChildNodes()) { - this->mContents->append(*el); - ++leafCt; - } - delete el; - // now parse the child nodes as leaf. - if (node->hasChildNodes()) { - QDomNodeList items = node->childNodes(); - int itemct = items.count(); - int added = 0; - if (0 < itemct) { - ++depth; - for (int kdx = 0; kdx < itemct; ++kdx) { - QDomNode item = items.at(kdx); - added += parsePlayListItem(&item, extension, hasArt, currentLeafId, depth); - } - if (1 > added) { - // should remove the last PlayListElement - this->mContents->removeLast(); - --leafCt; - } - else { - leafCt += added; - } - } - } - } - } - return leafCt; -} - -QString PlayListMainWindow::getExtension(QString path, QString extension) { - // return extension if exists - if (!extension.isNull() && !extension.isEmpty()) return extension; - // return blank if no path - if (path.isNull() || path.isEmpty()) return ""; - // otherwise extract the extension - int dot_pos = path.lastIndexOf('.'); - if (0 < dot_pos) { - return path.right(path.length() - (dot_pos + 1)); - } - else { // no dot - return ""; - } -} - -VlcPlayListElementSimple PlayListMainWindow::getElementFromId(int id) { - //if (0 != QString::compare("", text)) { - for (int idx = 0; idx < mContents->count(); ++idx) { - if (0 < id && (id == mContents->at(idx).id)) { - return mContents->at(idx); - } - } - //} - return *(new VlcPlayListElementSimple()); -} - -void PlayListMainWindow::updateList() { - ui->listWidget->clear(); - int ct = this->mContents->count(); - if (0 < ct) { - QIcon icon_audio = QIcon::fromTheme("general_audio_file"); - QIcon icon_video = QIcon::fromTheme("general_video_file"); - QIcon icon_image = QIcon::fromTheme("general_image"); - QIcon icon_flash = QIcon::fromTheme("filemanager_flash_file"); - QIcon icon_media = QIcon::fromTheme("filemanager_media_folder"); - QIcon icon_real = QIcon::fromTheme("filemanager_real_music"); - QIcon icon_playl = QIcon::fromTheme("filemanager_playlist"); - QIcon icon_unknown= QIcon::fromTheme("filemanager_unknown_file"); - for (int idx = 0; idx < ct; ++idx) { - VlcPlayListElementSimple el = mContents->at(idx); - QListWidgetItem* item; - if (0 == QString::compare("node", el.type)) { - item = new QListWidgetItem(icon_media, el.name, ui->listWidget, LIST_ITEM_TYPE_OFFSET + el.id); - } - else { - if ( 0 == QString::compare(el.extension, "jpg") || - 0 == QString::compare(el.extension, "jpeg") || - 0 == QString::compare(el.extension, "gif") || - 0 == QString::compare(el.extension, "png") || - 0 == QString::compare(el.extension, "bmp") ) { - item = new QListWidgetItem(icon_image, el.name, ui->listWidget, LIST_ITEM_TYPE_OFFSET + el.id); // .jpg, .jpeg, .gif, .png, .bmp - } - else if ( 0 == QString::compare(el.extension, "mp3") || - 0 == QString::compare(el.extension, "m4a") || - 0 == QString::compare(el.extension, "ogg") || - 0 == QString::compare(el.extension, "oga") || - 0 == QString::compare(el.extension, "wav") || - 0 == QString::compare(el.extension, "flac") ) { - item = new QListWidgetItem(icon_audio, el.name, ui->listWidget, LIST_ITEM_TYPE_OFFSET + el.id); // .mp3, .m4a, .ogg, .oga, .wav, .flac - } - else if ( 0 == QString::compare(el.extension, "m3u") || - 0 == QString::compare(el.extension, "wpl") || - 0 == QString::compare(el.extension, "pls") || - 0 == QString::compare(el.extension, "asx") || - 0 == QString::compare(el.extension, "xspf") || - 0 == QString::compare(el.extension, "cmml") ) { - item = new QListWidgetItem(icon_playl, el.name, ui->listWidget, LIST_ITEM_TYPE_OFFSET + el.id); // .m3u, .wpl, .pls, .asx, .xspf, .cmml - } - else if ( 0 == QString::compare(el.extension, "avi") || - 0 == QString::compare(el.extension, "mpeg") || - 0 == QString::compare(el.extension, "mpg") || - 0 == QString::compare(el.extension, "mov") || - 0 == QString::compare(el.extension, "mp4") || - 0 == QString::compare(el.extension, "m4v") || - 0 == QString::compare(el.extension, "wmv") || - 0 == QString::compare(el.extension, "mkv") || - 0 == QString::compare(el.extension, "ogv") ) { - item = new QListWidgetItem(icon_video, el.name, ui->listWidget, LIST_ITEM_TYPE_OFFSET + el.id); // .avi, .mpg, .mpeg, .mov, .m4v, .mp4, .wmv, .mkv, .ogv - } - else if ( 0 == QString::compare(el.extension, "rm") || - 0 == QString::compare(el.extension, "ra") || - 0 == QString::compare(el.extension, "ram") ) { - item = new QListWidgetItem(icon_real, el.name, ui->listWidget, LIST_ITEM_TYPE_OFFSET + el.id); // .ram, 'rm, 'ra - } - else if ( 0 == QString::compare(el.extension, "flv") ) { - item = new QListWidgetItem(icon_flash, el.name, ui->listWidget, LIST_ITEM_TYPE_OFFSET + el.id); // .flv - } - //else if ( 0 == QString::compare(el.extension, "") ) { - // item = new QListWidgetItem(icon_unknown, el.name, ui->listWidget, LIST_ITEM_TYPE_OFFSET + el.id); // .flv - //} - else { - if (el.name.contains("Flash")) { - item = new QListWidgetItem(icon_flash, el.name, ui->listWidget, LIST_ITEM_TYPE_OFFSET + el.id); - } - else { - item = new QListWidgetItem(icon_media, el.name, ui->listWidget, LIST_ITEM_TYPE_OFFSET + el.id); - } - } - } - item->setSelected(el.playing); - ui->listWidget->addItem(item); - if (el.playing) { - ui->listWidget->scrollToItem(item, QAbstractItemView::PositionAtCenter); - } - } - } -} -void PlayListMainWindow::updateUiWithCurrentStatus(VlcStatus * status) { - ui->loopButton->setChecked(status->loop); - ui->repeatButton->setChecked(status->repeat); - ui->shuffleButton->setChecked(status->random); -} diff --git a/playlistmainwindow.h b/playlistmainwindow.h deleted file mode 100644 index a6a444f..0000000 --- a/playlistmainwindow.h +++ /dev/null @@ -1,82 +0,0 @@ -/* VLC-REMOTE for MAEMO 5 -* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2, -* or (at your option) any later version, as published by the Free -* Software Foundation -* -* 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, write to the -* Free Software Foundation, Inc., -* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -#ifndef PLAYLISTMAINWINDOW_H -#define PLAYLISTMAINWINDOW_H - -#include -#include -#include -#include -#include "vlcplaylistelementsimple.h" -#include "vlcstatus.h" - -#ifndef LIST_ITEM_TYPE_OFFSET -#define LIST_ITEM_TYPE_OFFSET 1000 -#endif - -namespace Ui { - class PlayListMainWindow; -} - -class PlayListMainWindow : public QMainWindow { - Q_OBJECT -public: - explicit PlayListMainWindow(QWidget *parent = 0); - ~PlayListMainWindow(); - void init(); -public slots: - void onClear(); - void onShuffle(); - void onLoop(); - void onPlay(); - void onRepeat(); - void onRemove(); - void requestPlayList(); - void onListSelectionChanged(); - void finished(QNetworkReply * reply); - void readReady(); - void error(QNetworkReply::NetworkError code); - void showPlayList(); - void updateUiWithCurrentStatus(VlcStatus * status); - -protected slots: - void parseXmlPlayList(); - void updateList(); - int parsePlayListItem(QDomNode *node, QString *extension, bool *hasArt, int *currentLeafId, int depth); - -signals: - void idUpdated(int id, bool hasArt, QString extension); - -protected: - void changeEvent(QEvent *e); - VlcPlayListElementSimple getElementFromId(int id); - QString getExtension(QString path, QString extension); - -private: - Ui::PlayListMainWindow *ui; - QTimer * mTimer; - QString mIp; - QNetworkAccessManager * mNetManager; - QList* mContents; - VlcPlayListElementSimple mCurrentElement; - int mCurrentVlcIndex; - int mCurrentDepth; - QByteArray mResponse; -}; - -#endif // PLAYLISTMAINWINDOW_H diff --git a/playlistmainwindow.ui b/playlistmainwindow.ui deleted file mode 100644 index c98d800..0000000 --- a/playlistmainwindow.ui +++ /dev/null @@ -1,140 +0,0 @@ - - - PlayListMainWindow - - - - 0 - 0 - 800 - 600 - - - - Playlist - - - - - - - - not yet done - - - - - not yet done - - - - - not yet done - - - - - - - - - - Play - - - - - - - Shuffle - - - true - - - - - - - Loop - - - true - - - - - - - Repeat - - - true - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - Clear all - - - - - - - Remove - - - - - - - - - - - 0 - 0 - 800 - 25 - - - - - menu - - - - - - - Portrait Mode - - - - - Landscape Mode - - - - - - diff --git a/resource.qrc b/resource.qrc deleted file mode 100644 index aeea2b6..0000000 --- a/resource.qrc +++ /dev/null @@ -1,5 +0,0 @@ - - - config-vlc.jpg - - diff --git a/ressources.qrc b/ressources.qrc deleted file mode 100644 index 0821e0c..0000000 --- a/ressources.qrc +++ /dev/null @@ -1,5 +0,0 @@ - - - vlcremote_fr_FR.qm - - diff --git a/scanipdialog.cpp b/scanipdialog.cpp deleted file mode 100644 index 4de0efe..0000000 --- a/scanipdialog.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "scanipdialog.h" -#include "ui_scanipdialog.h" - -ScanIPDialog::ScanIPDialog(QWidget *parent) : - QDialog(parent), - ui(new Ui::ScanIPDialog) -{ - ui->setupUi(this); -} - -ScanIPDialog::~ScanIPDialog() -{ - delete ui; -} - -void ScanIPDialog::changeEvent(QEvent *e) -{ - QDialog::changeEvent(e); - switch (e->type()) { - case QEvent::LanguageChange: - ui->retranslateUi(this); - break; - default: - break; - } -} diff --git a/scanipdialog.h b/scanipdialog.h deleted file mode 100644 index 0e3cdf4..0000000 --- a/scanipdialog.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef SCANIPDIALOG_H -#define SCANIPDIALOG_H - -#include - -namespace Ui { - class ScanIPDialog; -} - -class ScanIPDialog : public QDialog { - Q_OBJECT -public: - explicit ScanIPDialog(QWidget *parent = 0); - ~ScanIPDialog(); - -protected: - void changeEvent(QEvent *e); - -private: - Ui::ScanIPDialog *ui; -}; - -#endif // SCANIPDIALOG_H diff --git a/scanipdialog.ui b/scanipdialog.ui deleted file mode 100644 index e5aa69a..0000000 --- a/scanipdialog.ui +++ /dev/null @@ -1,83 +0,0 @@ - - - ScanIPDialog - - - - 0 - 0 - 422 - 360 - - - - Dialog - - - - - - - - - - name - - - - - - - - - - IP - - - - - - - - - - - - - - - - - - - Scan - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Done - - - - - - - - - - diff --git a/src/AboutDialog.ui b/src/AboutDialog.ui new file mode 100644 index 0000000..2cf6ba0 --- /dev/null +++ b/src/AboutDialog.ui @@ -0,0 +1,64 @@ + + + Dialog + + + + 0 + 0 + 400 + 300 + + + + Dialog + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + Dialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + Dialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/Maemo_VLC_remote.svg b/src/Maemo_VLC_remote.svg new file mode 100644 index 0000000..83ad807 --- /dev/null +++ b/src/Maemo_VLC_remote.svg @@ -0,0 +1,453 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/aboutdialog.cpp b/src/aboutdialog.cpp new file mode 100644 index 0000000..e1606ea --- /dev/null +++ b/src/aboutdialog.cpp @@ -0,0 +1,43 @@ +/* VLC-REMOTE for MAEMO 5 +* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2, +* or (at your option) any later version, as published by the Free +* Software Foundation +* +* 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, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#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/src/aboutdialog.h b/src/aboutdialog.h new file mode 100644 index 0000000..c92ce70 --- /dev/null +++ b/src/aboutdialog.h @@ -0,0 +1,40 @@ +/* VLC-REMOTE for MAEMO 5 +* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2, +* or (at your option) any later version, as published by the Free +* Software Foundation +* +* 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, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#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/src/aboutdialog.ui b/src/aboutdialog.ui new file mode 100644 index 0000000..ad5fdd1 --- /dev/null +++ b/src/aboutdialog.ui @@ -0,0 +1,81 @@ + + + AboutDialog + + + + 0 + 0 + 400 + 300 + + + + Dialog + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'DejaVu Sans'; font-size:14pt; font-weight:400; font-style:normal;"> +<table style="-qt-table-type: root; margin-top:4px; margin-bottom:4px; margin-left:4px; margin-right:4px;"> +<tr> +<td style="border: none;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">OMed </p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Application by Sacha schutz </p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">istdasklar@gmail.com</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://omedsoft.blogspot.com/"><span style=" text-decoration: underline; color:#0000ff;">http://omedsoft.blogspot.com/</span></a></p></td></tr></table></body></html> + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + AboutDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + AboutDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/accountdialog.cpp b/src/accountdialog.cpp new file mode 100644 index 0000000..ecdb02f --- /dev/null +++ b/src/accountdialog.cpp @@ -0,0 +1,210 @@ +/* VLC-REMOTE for MAEMO 5 +* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2, +* or (at your option) any later version, as published by the Free +* Software Foundation +* +* 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, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#include "accountdialog.h" +#include "ui_accountdialog.h" +#include "newaccountdialog.h" +#include +#include +#include +#include +#include +#include + + + +QListWidgetItem asyncTestItem(const QListWidgetItem &item) +{ + + QListWidgetItem item2= item; + item2.setText("boby"); + + return item; + +} + + + + +AccountDialog::AccountDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::AccountDialog) +{ + ui->setupUi(this); + + mFuturWatcher = new QFutureWatcher(this); + connect(mFuturWatcher,SIGNAL(resultReadyAt(int)),this,SLOT(setAsyncItem(int))); + + connect(ui->addButton,SIGNAL(clicked()),this,SLOT(add())); + connect(ui->editButton,SIGNAL(clicked()),this,SLOT(edit())); + connect(ui->remButton,SIGNAL(clicked()),this,SLOT(rem())); + connect(ui->useButton,SIGNAL(clicked()),this,SLOT(use())); + connect(ui->listWidget, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(enableUi())); + + load(); + +} + +AccountDialog::~AccountDialog() +{ + delete ui; +} + +void AccountDialog::add() +{ + + NewAccountDialog *dialog = new NewAccountDialog(this); + dialog->exec(); + load(); +} +QString AccountDialog::currentIp() +{ + + QSettings settings; + QString useKey = settings.value("config/currentKey").toString(); + QString useIp ; + if ( !useKey.isEmpty()) + useIp = settings.value("account/"+useKey).toString(); + + else return QString(); + + return useIp; +} + +void AccountDialog::load() +{ + ui->editButton->setEnabled(false); + ui->remButton->setEnabled(false); + ui->useButton->setEnabled(false); + ui->listWidget->clear(); // tjr effacer , sinon on rajoute + + QSettings settings; + + QString useKey = settings.value("config/currentKey").toString(); + + QList asycItems; + + settings.beginGroup("account"); + foreach ( QString key, settings.allKeys()) + { + QListWidgetItem * item = new QListWidgetItem; + + item->setText(key); + item->setData(Qt::UserRole, settings.value(key)); + if (useKey == key) { + QFont font = item->font(); + font.setBold(true); + item->setFont(font); + } + ui->listWidget->addItem(item); + asycItems.append(*item); + } + settings.endGroup(); + + + // ... create and add in the list widget + + // QFuture itemFutur = QtConcurrent::mapped(asycItems, asyncTestItem); + + + mFuturWatcher->setFuture(QtConcurrent::mapped(asycItems, asyncTestItem)); +} + +QListWidgetItem AccountDialog::asyncTestItem(const QListWidgetItem& item) +{ + //==========> NEED TO USE POINTER TO AVOID setAsyncItem! But I don't know how;.. + QListWidgetItem newItem = item; + + QTcpSocket * socket = new QTcpSocket; + QSettings settings; + QString host = settings.value("account/"+item.text()).toString(); + + if(host.contains(":")) + { + QStringList hostSplit = host.split(":"); + QString ip = hostSplit.at(0); + QString port = hostSplit.at(1); + socket->connectToHost(ip,port.toInt()); + } + + else + socket->connectToHost(host,8080); + + if (socket->waitForConnected(1000)) + newItem.setIcon(QIcon::fromTheme("widgets_tickmark_list")); + else + newItem.setIcon(QIcon::fromTheme("statusarea_presence_busy_error")); + + return newItem; + + +} + + + +void AccountDialog::setAsyncItem(int row) // EDIT THE ROW AFTER ASYNC FUNCTION FINISHED +{ + QListWidgetItem newItem = mFuturWatcher->resultAt(row); + QListWidgetItem * item = ui->listWidget->item(row); + + item->setIcon(newItem.icon()); + + + +} + + + +void AccountDialog::edit() +{ + QString currentIp = ui->listWidget->currentItem()->data(Qt::UserRole).toString(); + QString currentKey = ui->listWidget->currentItem()->text(); + + NewAccountDialog *dialog = new NewAccountDialog(this); + dialog->edit(currentKey, currentIp); + dialog->exec(); + + load(); +} + +void AccountDialog::rem() +{ + QString key = ui->listWidget->currentItem()->text(); + + QSettings settings; + settings.beginGroup("account"); + settings.remove(key); + settings.endGroup(); + + load(); // On recharge les compte +} + +void AccountDialog::use() +{ + QString currentKey = ui->listWidget->currentItem()->text(); + QSettings settings; + settings.setValue("config/currentKey", currentKey); + load(); + emit accept(); +} + +void AccountDialog::enableUi() +{ + ui->editButton->setEnabled(true); + ui->remButton->setEnabled(true); + ui->useButton->setEnabled(true); +} diff --git a/src/accountdialog.h b/src/accountdialog.h new file mode 100644 index 0000000..e9468dd --- /dev/null +++ b/src/accountdialog.h @@ -0,0 +1,53 @@ +/* VLC-REMOTE for MAEMO 5 +* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2, +* or (at your option) any later version, as published by the Free +* Software Foundation +* +* 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, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#ifndef ACCOUNTDIALOG_H +#define ACCOUNTDIALOG_H + +#include +#include +#include +namespace Ui { + class AccountDialog; +} + +class AccountDialog : public QDialog +{ + Q_OBJECT + +public: + explicit AccountDialog(QWidget *parent = 0); + ~AccountDialog(); + static QListWidgetItem asyncTestItem(const QListWidgetItem& item); + + +static QString currentIp(); + +public slots: + void add(); + void edit(); + void rem(); + void use(); + void load(); + void enableUi(); + void setAsyncItem(int row); +private: + Ui::AccountDialog *ui; + QFutureWatcher * mFuturWatcher; +}; + +#endif // ACCOUNTDIALOG_H diff --git a/src/accountdialog.ui b/src/accountdialog.ui new file mode 100644 index 0000000..8b0dd97 --- /dev/null +++ b/src/accountdialog.ui @@ -0,0 +1,87 @@ + + + AccountDialog + + + + 0 + 0 + 400 + 300 + + + + Accounts + + + + + + + test + + + + + + + + + + Add + + + + + + + false + + + Edit + + + + + + + false + + + Remove + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + false + + + Use + + + + + + + + + + diff --git a/src/accountnewdialog.ui b/src/accountnewdialog.ui new file mode 100644 index 0000000..0ac856e --- /dev/null +++ b/src/accountnewdialog.ui @@ -0,0 +1,67 @@ + + Dialog + + + + 0 + 0 + 320 + 240 + + + + Dialog + + + + + 10 + 200 + 301 + 32 + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + buttonBox + accepted() + Dialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + Dialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/appsettings.cpp b/src/appsettings.cpp new file mode 100644 index 0000000..babef8c --- /dev/null +++ b/src/appsettings.cpp @@ -0,0 +1,90 @@ +/* VLC-REMOTE for MAEMO 5 +* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2, +* or (at your option) any later version, as published by the Free +* Software Foundation +* +* 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, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#include +#include "appsettings.h" + +AppSettings::AppSettings() { +} + +AppSettings::~AppSettings() { + ; +} + +QString AppSettings::getCurrentKey() { + QSettings sets; + return sets.value("config/currentKey", "").toString(); +} +QString AppSettings::getCurrentIp() { + QSettings sets; + return sets.value("account/" + getCurrentKey(), "").toString(); +} +VlcDirectory AppSettings::getHomeDirectory() { + QSettings sets; + VlcDirectory home; + home.name = sets.value("config/accounts/" + getCurrentKey() + "/homeDirName", "Default").toString(); + home.path = sets.value("config/accounts/" + getCurrentKey() + "/homeDirPath", "~/").toString(); + return home; +} +bool AppSettings::setHomeDirectory(VlcDirectory dir) { + QSettings sets; + sets.setValue("config/accounts/" + getCurrentKey() + "/homeDirName", dir.name); + sets.setValue("config/accounts/" + getCurrentKey() + "/homeDirPath", dir.path); + return true; +} +QList* AppSettings::getFavourites() { + QSettings sets; + QList * favourites = new QList(); + + sets.beginGroup("config/accounts/" + getCurrentKey() + "/favourites"); + foreach ( QString key, sets.allKeys()) + { + VlcDirectory dir; + // key is name + dir.name = key; + // value is path + dir.path = sets.value(key, "~/").toString(); + favourites->append(dir); + } + sets.endGroup(); + return favourites; +} +bool AppSettings::addFavourite(VlcDirectory dir) { + QSettings sets; + // should check for existing first otherwise it overwrites + if (0 < sets.value("config/accounts/" + getCurrentKey() + "/favourites/" + dir.name, "").toString().length()) { + dir.name = "_" + dir.name; + return addFavourite(dir); + } + sets.setValue("config/accounts/" + getCurrentKey() + "/favourites/" + dir.name, dir.path); + return true; +} +bool AppSettings::deleteFavourite(VlcDirectory dir) { + QSettings sets; + sets.remove("config/accounts/" + getCurrentKey() + "/favourites/" + dir.name); + return true; +} +Orientation AppSettings::setOrientation(Orientation orientation) { + QSettings sets; + sets.setValue("config/orientation", (int)orientation); + return orientation; +} +Orientation AppSettings::getOrientation() { + QSettings sets; + return (Orientation)(sets.value("config/orientation", AUTO_ROTATE).toInt()); +} + diff --git a/src/appsettings.h b/src/appsettings.h new file mode 100644 index 0000000..407b5a2 --- /dev/null +++ b/src/appsettings.h @@ -0,0 +1,49 @@ +/* VLC-REMOTE for MAEMO 5 +* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2, +* or (at your option) any later version, as published by the Free +* Software Foundation +* +* 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, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#ifndef APPSETTINGS_H +#define APPSETTINGS_H +#include + +struct VlcDirectory { + QString name; + QString path; +}; +enum Orientation { + AUTO_ROTATE = 0, + LANDSCAPE, + PORTRAIT +}; + +class AppSettings { +public: + explicit AppSettings(); + ~AppSettings(); + static QString getCurrentKey(); + static QString getCurrentIp(); + static VlcDirectory getHomeDirectory(); + static QList* getFavourites(); + static bool addFavourite(VlcDirectory dir); + static bool deleteFavourite(VlcDirectory dir); + static bool setHomeDirectory(VlcDirectory dir); + static Orientation setOrientation(Orientation orientation); + static Orientation getOrientation(); +//private: + //static QSettings settings; +}; + +#endif // APPSETTINGS_H diff --git a/src/browsemainwindow.cpp b/src/browsemainwindow.cpp new file mode 100644 index 0000000..a07b131 --- /dev/null +++ b/src/browsemainwindow.cpp @@ -0,0 +1,427 @@ +/* VLC-REMOTE for MAEMO 5 +* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2, +* or (at your option) any later version, as published by the Free +* Software Foundation +* +* 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, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#include "browsemainwindow.h" +#include "ui_browsemainwindow.h" +#include +#if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) +#include +#endif +#include "configdialog.h" +#include "aboutdialog.h" +#include "vlcbrowseelement.h" +#include "appsettings.h" +#include "favouritesmainwindow.h" + +BrowseMainWindow::BrowseMainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::BrowseMainWindow) +{ + + ui->setupUi(this); + mFavouritesMainWindow = new FavouritesMainWindow; + mCurrentDir = "~/"; //AppSettings::getHomeDirectory().path; // This works on win as well as linux, would guess mac too. + setWindowTitle("Vlc remote"); + + + mNetManager = new QNetworkAccessManager(this); + + mContents = new QList(); + + ui->listWidget->setTextElideMode(Qt::ElideMiddle); + ui->listWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + ui->playButton->setIcon(QIcon::fromTheme("camera_playback")); + ui->addButton->setIcon(QIcon::fromTheme("general_add")); + ui->browseButton->setIcon(QIcon::fromTheme("filemanager_media_folder")); + ui->browseButton->setDisabled(true); + ui->playButton->setDisabled(true); + ui->addButton->setDisabled(true); + + +#if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) + + mFavouritesMainWindow->setParent(this); + mFavouritesMainWindow->setAttribute(Qt::WA_Maemo5StackedWindow, true); + setAttribute(Qt::WA_Maemo5StackedWindow, true); + mFavouritesMainWindow->setWindowFlags(mFavouritesMainWindow->windowFlags() | Qt::Window); + +#endif + + connect(ui->browseButton,SIGNAL(clicked()),this,SLOT(onBrowse())); + connect(ui->addButton,SIGNAL(clicked()),this,SLOT(onAddToPlaylist())); + connect(ui->playButton,SIGNAL(clicked()),this,SLOT(onPlay())); + connect(ui->listWidget, SIGNAL(itemSelectionChanged()), this, SLOT(onListSelectionChanged())); + + connect(ui->actionGoUserHome, SIGNAL(triggered()), this, SLOT(showUserHomeFolder())); + connect(ui->actionGoHome, SIGNAL(triggered()), this, SLOT(showHomeFolder())); + connect(ui->actionSetHome, SIGNAL(triggered()), this, SLOT(setHomeFolder())); + connect(ui->actionViewFavourites, SIGNAL(triggered()), this, SLOT(showFavourites())); + connect(ui->actionSetFavourite, SIGNAL(triggered()), this, SLOT(setFavourite())); + + connect(this->mFavouritesMainWindow, SIGNAL(browseDirectory(QString)), this, SLOT(browseDirectory(QString))); + + init(); + + +} +void BrowseMainWindow::init() // THIS METHOD IS CALLED WHEN CONFIG CHANGED... +{ + mIp = AppSettings::getCurrentIp(); // AccountDialog::currentIp(); + setHomeDirectory(); +} +void BrowseMainWindow::setHomeDirectory() +{ + mCurrentDir = AppSettings::getHomeDirectory().path; +} +void BrowseMainWindow::showCurrentDirectory() // THIS METHOD IS CALLED WHEN WINDOW IS OPENED... +{ + browseDirectory(mCurrentDir); +} + +BrowseMainWindow::~BrowseMainWindow() +{ + delete ui; +} + +void BrowseMainWindow::changeEvent(QEvent *e) +{ + QMainWindow::changeEvent(e); + switch (e->type()) { + case QEvent::LanguageChange: + ui->retranslateUi(this); + break; + default: + break; + } +} + +void BrowseMainWindow::showHomeFolder() { + browseDirectory(AppSettings::getHomeDirectory().path); +} +void BrowseMainWindow::showUserHomeFolder() { + browseDirectory("~/"); +} +void BrowseMainWindow::setHomeFolder() { + if (0 < mCurrentElement.name.length() && (0 == QString::compare("directory", mCurrentElement.type) || 0 == QString::compare("dir", mCurrentElement.type))) { + VlcDirectory dir; + dir.name = mCurrentElement.name; + dir.path = mCurrentElement.path; + AppSettings::setHomeDirectory(dir); + } + else if (0 < mCurrentDir.length()) { + VlcDirectory dir; + QString name = mCurrentDir; + int idx = mCurrentDir.lastIndexOf('/'); + if (0 > idx) idx = mCurrentDir.lastIndexOf('\\'); + if (0 < idx) { + name = mCurrentDir.right(mCurrentDir.length() - (idx + 1)); + } + dir.name = name; + dir.path = mCurrentDir; + AppSettings::setHomeDirectory(dir); + } +} +void BrowseMainWindow::showFavourites() { + mFavouritesMainWindow->show(); + mFavouritesMainWindow->init(); +} +void BrowseMainWindow::setFavourite() { + if (0 < mCurrentElement.name.length() && (0 == QString::compare("directory", mCurrentElement.type) || 0 == QString::compare("dir", mCurrentElement.type))) { + VlcDirectory dir; + dir.name = mCurrentElement.name; + dir.path = mCurrentElement.path; + AppSettings::addFavourite(dir); + } + else if (0 < mCurrentDir.length()) { + VlcDirectory dir; + QString name = mCurrentDir; + int idx = mCurrentDir.lastIndexOf('/'); + if (0 > idx) idx = mCurrentDir.lastIndexOf('\\'); + if (0 < idx) { + name = mCurrentDir.right(mCurrentDir.length() - (idx + 1)); + } + dir.name = name; + dir.path = mCurrentDir; + AppSettings::addFavourite(dir); + } +} + +void BrowseMainWindow::onListSelectionChanged() { + QList items = ui->listWidget->selectedItems(); + if (0 < items.count()) { + mCurrentElement = getElementFromText(items.at(0)->text()); + // are we up dir? + if (0 == QString::compare("..", mCurrentElement.name)) { + ui->browseButton->setDisabled(true); + ui->playButton->setDisabled(true); + ui->addButton->setDisabled(true); + mCurrentDir = mCurrentElement.path; + browseDirectory(mCurrentDir); + } + else { + // can we browse? + if (0 == QString::compare("directory", mCurrentElement.type) || 0 == QString::compare("dir", mCurrentElement.type)) { + ui->browseButton->setDisabled(false); + } + else { + ui->browseButton->setDisabled(true); + } + // can we play? + ui->playButton->setDisabled(false); + // can we playlist? + ui->addButton->setDisabled(false); + } + } +} + +VlcBrowseElement BrowseMainWindow::getElementFromText(QString text) { + for (int idx = 0; idx < mContents->count(); ++idx) { + if (0 == QString::compare(text, mContents->at(idx).name)) { + return mContents->at(idx); + } + } + return *(new VlcBrowseElement()); +} + +void BrowseMainWindow::onBrowse() { + // check for directory + if (0 == QString::compare("directory", mCurrentElement.type) || 0 == QString::compare("dir", mCurrentElement.type)) { + // call browseDirectory + mCurrentDir = mCurrentElement.path; + browseDirectory(mCurrentDir); + } + else { + ui->browseButton->setDisabled(true); + } +} + +void BrowseMainWindow::onAddToPlaylist() { + QUrl url = QUrl("http://"+mIp+"/requests/status.xml?command=in_enqueue"); + url.addEncodedQueryItem(QByteArray("input"), QUrl::toPercentEncoding(mCurrentElement.path.replace("\\", "\\\\").replace("'", "\\'"))); + mNetManager->get(QNetworkRequest(url)); + //mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=in_enqueue&input=" + mCurrentElement.path.replace("\\", "\\\\")))); +} + +void BrowseMainWindow::onPlay() { + QUrl url = QUrl("http://"+mIp+"/requests/status.xml?command=in_play"); + url.addEncodedQueryItem(QByteArray("input"), QUrl::toPercentEncoding(mCurrentElement.path.replace("\\", "\\\\").replace("'", "\\'"))); + mNetManager->get(QNetworkRequest(url)); + //mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=in_play&input=" + mCurrentElement.path.replace("\\", "\\\\")))); +} + +void BrowseMainWindow::browseDirectory(QString dir) { + if (mFavouritesMainWindow) { + setParent(this->parentWidget()); +#if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) + setAttribute(Qt::WA_Maemo5StackedWindow, true); +#endif + mFavouritesMainWindow->hide(); + } + mResponse.clear(); + QUrl url = QUrl("http://"+mIp+"/requests/browse.xml"); + url.addEncodedQueryItem(QByteArray("dir"), QUrl::toPercentEncoding(dir)); + QNetworkReply * reply = mNetManager->get(QNetworkRequest(url)); + //QNetworkReply * reply = mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/browse.xml?dir=" + dir.replace("&", "%26").replace("\\", "\\\\")))); +#if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) + this->setAttribute(Qt::WA_Maemo5ShowProgressIndicator, true); +#endif + connect(reply,SIGNAL(readyRead()),this,SLOT(readReady())); + connect(reply,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(error(QNetworkReply::NetworkError))); + connect(mNetManager,SIGNAL(finished(QNetworkReply *)),this,SLOT(finished(QNetworkReply *))); +} +void BrowseMainWindow::error(QNetworkReply::NetworkError code) { +#if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) + this->setAttribute(Qt::WA_Maemo5ShowProgressIndicator, false); +#endif + qDebug() << code; +} +void BrowseMainWindow::readReady() { + QNetworkReply * reply = qobject_cast(sender()); + // append to buffer + mResponse += reply->readAll(); +} +void BrowseMainWindow::finished(QNetworkReply * reply) { + // now we can call parseXmlDirectory to process the full buffers + this->parseXmlDirectory(); + // only interested in finished signals + disconnect(mNetManager,SIGNAL(finished(QNetworkReply *)),this,SLOT(finished(QNetworkReply *))); +#if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) + this->setAttribute(Qt::WA_Maemo5ShowProgressIndicator, false); +#endif + delete reply; +} +void BrowseMainWindow::parseXmlDirectory() { + QDomDocument doc; + doc.setContent(this->mResponse); + QDomElement docElem = doc.documentElement(); + QDomNodeList elements = docElem.elementsByTagName("element"); + // we can sort by folders then files alphabetically by running to lists and appending them at the end + // vlc alpha sorts everything in the incoming stream, we just need to seperate files from folders. + if (0 < elements.count()) { + QList* files = new QList(); + int idx = 0; + mContents->clear(); + do { + QDomNode node = elements.at(idx); + VlcBrowseElement* dir = new VlcBrowseElement(); + dir->type = node.attributes().namedItem("type").nodeValue(); + dir->size = node.attributes().namedItem("size").nodeValue().toInt(); + dir->date = QDate::fromString(node.attributes().namedItem("date").nodeValue()); + dir->path = node.attributes().namedItem("path").nodeValue(); + dir->name = node.attributes().namedItem("name").nodeValue(); + dir->extension = getExtension(dir->path, node.attributes().namedItem("extension").nodeValue()); + ++idx; + if (0 != QString::compare("directory", dir->type) && 0 != QString::compare("dir", dir->type)) { + files->append(*dir); + } + else if (0 == QString::compare("..", dir->name)) { + this->mContents->prepend(*dir); + } + else { + this->mContents->append(*dir); + } + delete dir; + } while (idx < elements.count()); + if (0 < files->count()) { + mContents->append(*files); + } + delete files; + // Update UI + this->updateList(); + } + else { + // alert user of error / empty directory + qDebug() << "can't browse dir: " << mCurrentDir; +#if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) + QMaemo5InformationBox::information(this, tr("Directory could not be browsed!"), QMaemo5InformationBox::DefaultTimeout); +#endif + } + mResponse.clear(); + +} + +QString BrowseMainWindow::getExtension(QString path, QString extension) { + // return extension if exists + if (!extension.isNull() && !extension.isEmpty()) return extension; + // return blank if no path + if (path.isNull() || path.isEmpty()) return ""; + // otherwise extract the extension + int dot_pos = path.lastIndexOf('.'); + if (0 < dot_pos) { + return path.right(path.length() - (dot_pos + 1)); + } + else { // no dot + return ""; + } +} + +void BrowseMainWindow::updateList() { + ui->listWidget->clear(); + int ct = this->mContents->count(); + if (0 < ct) { + QIcon icon_up = QIcon::fromTheme("filemanager_folder_up"); + QIcon icon_folder = QIcon::fromTheme("general_folder"); + QIcon icon_audio = QIcon::fromTheme("general_audio_file"); + QIcon icon_video = QIcon::fromTheme("general_video_file"); + QIcon icon_image = QIcon::fromTheme("general_image"); + QIcon icon_flash = QIcon::fromTheme("filemanager_flash_file"); + QIcon icon_real = QIcon::fromTheme("filemanager_real_music"); + QIcon icon_playl = QIcon::fromTheme("filemanager_playlist"); + QIcon icon_unknown= QIcon::fromTheme("filemanager_unknown_file"); + for (int idx = 0; idx < ct; ++idx) { + VlcBrowseElement dir = mContents->at(idx); + QListWidgetItem* item; + bool item_good = false; + if (0 == QString::compare("directory", dir.type) || 0 == QString::compare("dir", dir.type)) { + if (0 == QString::compare("..", dir.name)) { + item = new QListWidgetItem(icon_up, dir.name, ui->listWidget, 0); + item_good = true; + } + else { + item = new QListWidgetItem(icon_folder, dir.name, ui->listWidget, 0); + item_good = true; + } + } + else if (0 == QString::compare("file", dir.type)) { + if ( 0 == QString::compare(dir.extension, "jpg") || + 0 == QString::compare(dir.extension, "jpeg") || + 0 == QString::compare(dir.extension, "gif") || + 0 == QString::compare(dir.extension, "png") || + 0 == QString::compare(dir.extension, "bmp") ) { + item_good = true; + item = new QListWidgetItem(icon_image, dir.name, ui->listWidget, 0); // .jpg, .jpeg, .gif, .png, .bmp + } + else if ( 0 == QString::compare(dir.extension, "mp3") || + 0 == QString::compare(dir.extension, "m4a") || + 0 == QString::compare(dir.extension, "ogg") || + 0 == QString::compare(dir.extension, "oga") || + 0 == QString::compare(dir.extension, "wav") || + 0 == QString::compare(dir.extension, "flac") ) { + item_good = true; + item = new QListWidgetItem(icon_audio, dir.name, ui->listWidget, 0); // .mp3, .m4a, .ogg, .oga, .wav, .flac + } + else if ( 0 == QString::compare(dir.extension, "m3u") || + 0 == QString::compare(dir.extension, "wpl") || + 0 == QString::compare(dir.extension, "pls") || + 0 == QString::compare(dir.extension, "asx") || + 0 == QString::compare(dir.extension, "xspf") || + 0 == QString::compare(dir.extension, "cmml") ) { + item_good = true; + item = new QListWidgetItem(icon_playl, dir.name, ui->listWidget, 0); // .m3u, .wpl, .pls, .asx, .xspf, .cmml + } + else if ( 0 == QString::compare(dir.extension, "avi") || + 0 == QString::compare(dir.extension, "mpeg") || + 0 == QString::compare(dir.extension, "mpg") || + 0 == QString::compare(dir.extension, "mov") || + 0 == QString::compare(dir.extension, "mp4") || + 0 == QString::compare(dir.extension, "m4v") || + 0 == QString::compare(dir.extension, "wmv") || + 0 == QString::compare(dir.extension, "mkv") || + 0 == QString::compare(dir.extension, "ogv") ) { + item_good = true; + item = new QListWidgetItem(icon_video, dir.name, ui->listWidget, 0); // .avi, .mpg, .mpeg, .mov, .mp4, .m4v, .wmv, .mkv, .ogv + } + else if ( 0 == QString::compare(dir.extension, "rm") || + 0 == QString::compare(dir.extension, "ra") || + 0 == QString::compare(dir.extension, "ram") ) { + item = new QListWidgetItem(icon_real, dir.name, ui->listWidget, 0); // .ram, 'rm, 'ra + } + else if ( 0 == QString::compare(dir.extension, "flv") ) { + item_good = true; + item = new QListWidgetItem(icon_flash, dir.name, ui->listWidget, 0); // .flv + } + else { + if (dir.name.startsWith("Flash")) { + item_good = true; + item = new QListWidgetItem(icon_flash, dir.name, ui->listWidget, 0); + } + else { + item_good = false; + //item = new QListWidgetItem(icon_unknown, dir.name, ui->listWidget, 0); + } + } + } + if (item_good) { + ui->listWidget->addItem(item); + } + // other types ignored + } + } +} + + diff --git a/src/browsemainwindow.h b/src/browsemainwindow.h new file mode 100644 index 0000000..052421a --- /dev/null +++ b/src/browsemainwindow.h @@ -0,0 +1,76 @@ +/* VLC-REMOTE for MAEMO 5 +* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2, +* or (at your option) any later version, as published by the Free +* Software Foundation +* +* 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, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#ifndef BROWSEMAINWINDOW_H +#define BROWSEMAINWINDOW_H + +#include +#include +#include +#include +#include "vlcbrowseelement.h" +#include "favouritesmainwindow.h" + +namespace Ui { + class BrowseMainWindow; +} + +class BrowseMainWindow : public QMainWindow { + Q_OBJECT +public: + explicit BrowseMainWindow(QWidget *parent = 0); + ~BrowseMainWindow(); + +public slots: + void init(); + void browseDirectory(QString); + void onBrowse(); + void onPlay(); + void onAddToPlaylist(); + void onListSelectionChanged(); + void finished(QNetworkReply * reply); + void readReady(); + void error(QNetworkReply::NetworkError code); + void showCurrentDirectory(); + void setHomeFolder(); + void showHomeFolder(); + void showUserHomeFolder(); + void setFavourite(); + void showFavourites(); + void setHomeDirectory(); + +protected slots: + void parseXmlDirectory(); + void updateList(); + +protected: + void changeEvent(QEvent *e); + VlcBrowseElement getElementFromText(QString text); + QString getExtension(QString path, QString extension); + +private: + Ui::BrowseMainWindow *ui; + FavouritesMainWindow *mFavouritesMainWindow; + QNetworkAccessManager * mNetManager; + QString mCurrentDir; + QString mIp; + QList* mContents; + VlcBrowseElement mCurrentElement; + QByteArray mResponse; +}; + +#endif // BROWSEMAINWINDOW_H diff --git a/src/browsemainwindow.ui b/src/browsemainwindow.ui new file mode 100644 index 0000000..6ae1aee --- /dev/null +++ b/src/browsemainwindow.ui @@ -0,0 +1,97 @@ + + + BrowseMainWindow + + + + 0 + 0 + 800 + 600 + + + + MainWindow + + + + + + + + + + + + + Play + + + + + + + Enqueue + + + + + + + Browse + + + + + + + + + + + 0 + 0 + 800 + 27 + + + + + menu + + + + + + + + + + + User Folder + + + + + Home + + + + + Set as Home + + + + + Favourites + + + + + Add to Favourite + + + + + + diff --git a/src/config-vlc.jpg b/src/config-vlc.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b4610f057bfd3992d73e402eb33e40e28951c2f7 GIT binary patch literal 77930 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

ctnJ7tnQUR$KDKUFR(x>F73A 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 Nai^!, Dru Moore , Yann Nave +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2, +* or (at your option) any later version, as published by the Free +* Software Foundation +* +* 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, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#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/src/configdialog.h b/src/configdialog.h new file mode 100644 index 0000000..e6c4f67 --- /dev/null +++ b/src/configdialog.h @@ -0,0 +1,42 @@ +/* VLC-REMOTE for MAEMO 5 +* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2, +* or (at your option) any later version, as published by the Free +* Software Foundation +* +* 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, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#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/src/configdialog.ui b/src/configdialog.ui new file mode 100644 index 0000000..c3dd6f0 --- /dev/null +++ b/src/configdialog.ui @@ -0,0 +1,69 @@ + + + ConfigDialog + + + + 0 + 0 + 442 + 304 + + + + Dialog + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'DejaVu Sans'; font-size:14pt; font-weight:400; font-style:normal;"> +<table border="0" style="-qt-table-type: root; margin-top:4px; margin-bottom:4px; margin-left:4px; margin-right:4px;"> +<tr> +<td style="border: none;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Enter IP of VLC server. </p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Example : <span style=" font-weight:600;">192.168.0.8:8080</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Be sure you have properly configured Vlc</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> and allows connection by adding this IP in /vlc/http/.hosts</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">More information on my blog : <a href="http://omedsoft.blogspot.com/"><span style=" text-decoration: underline; color:#0000ff;">omed.blogspot.com</span></a><br /></p></td></tr></table></body></html> + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + rejected() + ConfigDialog + reject() + + + 295 + 284 + + + 286 + 274 + + + + + diff --git a/src/data/26x26/vlc-remote.png b/src/data/26x26/vlc-remote.png new file mode 100644 index 0000000000000000000000000000000000000000..eb65d6fc0cd9aec6fc270f26f8c1a433ccaa169b GIT binary patch literal 1310 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, Dru Moore , Yann Nave +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2, +* or (at your option) any later version, as published by the Free +* Software Foundation +* +* 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, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#include "favouritesmainwindow.h" +#include "ui_favouritesmainwindow.h" +#include +#if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) +#include +#endif +#include "appsettings.h" +//#include "browsemainwindow.h" + +FavouritesMainWindow::FavouritesMainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::FavouritesMainWindow) +{ + + ui->setupUi(this); + + setWindowTitle("Vlc remote"); + mCurrentItemIndex = -1; + + ui->listWidget->setTextElideMode(Qt::ElideMiddle); + ui->listWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + ui->deleteButton->setIcon(QIcon::fromTheme("general_delete")); + ui->editButton->setIcon(QIcon::fromTheme("general_sketch")); + ui->browseButton->setIcon(QIcon::fromTheme("filemanager_media_folder")); + ui->saveButton->setIcon(QIcon::fromTheme("notes_save")); + ui->browseButton->setDisabled(true); + ui->editButton->setDisabled(true); + ui->deleteButton->setDisabled(true); + ui->actionSetHome->setDisabled(true); + ui->label->setVisible(false); + ui->lineEdit->setVisible(false); + ui->saveButton->setVisible(false); + ui->saveButton->setDisabled(true); + + connect(ui->browseButton,SIGNAL(clicked()),this,SLOT(onBrowse())); + connect(ui->deleteButton,SIGNAL(clicked()),this,SLOT(onDelete())); + connect(ui->editButton,SIGNAL(clicked()),this,SLOT(onEdit())); + connect(ui->listWidget, SIGNAL(itemSelectionChanged()), this, SLOT(onListSelectionChanged())); + connect(ui->actionSetHome, SIGNAL(triggered()), this, SLOT(setHomeFolder())); + connect(ui->saveButton, SIGNAL(clicked()), this, SLOT(onEditSave())); + connect(ui->lineEdit, SIGNAL(textChanged(QString)), this, SLOT(onLineEditTextChanged(QString))); + + init(); + + +} +void FavouritesMainWindow::init() // THIS METHOD IS CALLED WHEN CONFIG CHANGED AND WINDOW SHOWN... +{ + mFavourites = AppSettings::getFavourites(); + updateList(); +} + +FavouritesMainWindow::~FavouritesMainWindow() +{ + delete mFavourites; + delete ui; +} + +void FavouritesMainWindow::changeEvent(QEvent *e) +{ + QMainWindow::changeEvent(e); + switch (e->type()) { + case QEvent::LanguageChange: + ui->retranslateUi(this); + break; + default: + break; + } +} +void FavouritesMainWindow::updateList() { + ui->listWidget->clear(); + if (NULL != mFavourites && 0 < mFavourites->count()) { + for (int idx = 0; idx < mFavourites->count(); ++idx) { + QListWidgetItem* item = new QListWidgetItem(QIcon::fromTheme("imageviewer_favourite"), mFavourites->at(idx).name, ui->listWidget, LIST_ITEM_TYPE_OFFSET + idx); + ui->listWidget->addItem(item); + } + } +} +void FavouritesMainWindow::setHomeFolder() { + if (-1 < mCurrentItemIndex) { + AppSettings::setHomeDirectory(mCurrentFavourite); + } +} +void FavouritesMainWindow::onListSelectionChanged() { + ui->label->setVisible(false); + ui->lineEdit->setVisible(false); + ui->saveButton->setVisible(false); + ui->saveButton->setDisabled(true); + QList items = ui->listWidget->selectedItems(); + if (0 < items.count()) { + mCurrentItemIndex = ui->listWidget->currentIndex().row(); + mCurrentFavourite = mFavourites->at(items.at(0)->type() - LIST_ITEM_TYPE_OFFSET); // Qt reserves types up to 1000, we use an offset beyond that for index tracking. May prove to be too hacky! + ui->browseButton->setDisabled(false); + ui->editButton->setDisabled(false); + ui->deleteButton->setDisabled(false); + ui->actionSetHome->setDisabled(false); + } + else { + mCurrentItemIndex = -1; + ui->browseButton->setDisabled(true); + ui->editButton->setDisabled(true); + ui->deleteButton->setDisabled(true); + ui->actionSetHome->setDisabled(true); + } +} +void FavouritesMainWindow::onLineEditTextChanged(QString text) { + if (0 < text.length()) { + ui->saveButton->setDisabled(false); + } + else { + ui->saveButton->setDisabled(true); + } +} +void FavouritesMainWindow::onEditSave() { + if (-1 < mCurrentItemIndex && 0 < ui->lineEdit->text().length()) { + ui->label->setVisible(false); + ui->lineEdit->setVisible(false); + ui->saveButton->setVisible(false); + ui->saveButton->setDisabled(true); + AppSettings::deleteFavourite(mCurrentFavourite); + mCurrentFavourite.name = ui->lineEdit->text(); + AppSettings::addFavourite(mCurrentFavourite); + ui->lineEdit->setText(""); + ui->listWidget->itemAt(mCurrentItemIndex, 0)->setText(mCurrentFavourite.name); + init(); + } +} +void FavouritesMainWindow::onEdit() { + if (-1 < mCurrentItemIndex) { + ui->label->setVisible(true); + ui->lineEdit->setVisible(true); + ui->saveButton->setVisible(true); + ui->saveButton->setDisabled(false); + ui->lineEdit->setText(mCurrentFavourite.name); + ui->browseButton->setDisabled(true); + ui->editButton->setDisabled(true); + ui->deleteButton->setDisabled(true); + } +} +void FavouritesMainWindow::onBrowse() { + if (-1 < mCurrentItemIndex) { + emit browseDirectory(mCurrentFavourite.path); + //this->close(); + //((BrowseMainWindow *)this->parent())->browseDirectory(mCurrentFavourite.path); + } +} +void FavouritesMainWindow::onDelete() { + if (-1 < mCurrentItemIndex) { + AppSettings::deleteFavourite(mCurrentFavourite); + init(); + } +} diff --git a/src/favouritesmainwindow.h b/src/favouritesmainwindow.h new file mode 100644 index 0000000..76964b0 --- /dev/null +++ b/src/favouritesmainwindow.h @@ -0,0 +1,67 @@ +/* VLC-REMOTE for MAEMO 5 +* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2, +* or (at your option) any later version, as published by the Free +* Software Foundation +* +* 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, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#ifndef FAVOURITESMAINWINDOW_H +#define FAVOURITESMAINWINDOW_H + +#include +#include +#include +#include +#include "appsettings.h" + +#ifndef LIST_ITEM_TYPE_OFFSET +#define LIST_ITEM_TYPE_OFFSET 1000 +#endif + +namespace Ui { + class FavouritesMainWindow; +} + +class FavouritesMainWindow : public QMainWindow { + Q_OBJECT +public: + explicit FavouritesMainWindow(QWidget *parent = 0); + ~FavouritesMainWindow(); + +public slots: + void init(); + void onListSelectionChanged(); + void onLineEditTextChanged(QString text); + void onBrowse(); + void onEdit(); + void onDelete(); + void setHomeFolder(); + void onEditSave(); + +protected slots: + +signals: + void browseDirectory(QString path); + +protected: + void changeEvent(QEvent *e); + void updateList(); + +private: + Ui::FavouritesMainWindow *ui; + int mCurrentItemIndex; + QList* mFavourites; + VlcDirectory mCurrentFavourite; +}; + +#endif // FAVOURITESMAINWINDOW_H diff --git a/src/favouritesmainwindow.ui b/src/favouritesmainwindow.ui new file mode 100644 index 0000000..b379237 --- /dev/null +++ b/src/favouritesmainwindow.ui @@ -0,0 +1,88 @@ + + + FavouritesMainWindow + + + + 0 + 0 + 798 + 598 + + + + MainWindow + + + + + + + + + + + + Name + + + + + + + + + + Save + + + + + + + + + + + Delete + + + + + + + Edit + + + + + + + Browse + + + + + + + + + + + 0 + 0 + 798 + 20 + + + + + + + Set as Home + + + + + + diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..8e21758 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,70 @@ +/* VLC-REMOTE for MAEMO 5 +* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2, +* or (at your option) any later version, as published by the Free +* Software Foundation +* +* 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, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#include +#include +#include +#include +#include +#include +#include "playermainwindow.h" +#include "appsettings.h" +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + + QCoreApplication::setOrganizationName("Omed"); + QCoreApplication::setOrganizationDomain("medsoft.blogspot.com/"); + QCoreApplication::setApplicationName("Maemo VLC remote"); + + QString locale = QLocale::system().name(); + QTranslator translator; + translator.load(QString(":/languages/vlcremote_") + locale); + a.installTranslator(&translator); + + QTextCodec::setCodecForTr(QTextCodec::codecForName("utf8")); + + + qDebug() << AppSettings::getCurrentIp(); + + + PlayerMainWindow * mainwindow = new PlayerMainWindow; + + //mainwindow->setAttribute(Qt::WA_Maemo5LandscapeOrientation, true); + //mainwindow->setAttribute(Qt::WA_Maemo5PortraitOrientation, true); + //mainwindow->setAttribute(Qt::WA_Maemo5AutoOrientation, true); + + mainwindow->showMaximized(); + #if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) + Orientation o = AppSettings::getOrientation(); + switch (o) { + case AUTO_ROTATE: + mainwindow->setAttribute(Qt::WA_Maemo5AutoOrientation, true); + break; + case LANDSCAPE: + mainwindow->setAttribute(Qt::WA_Maemo5LandscapeOrientation, true); + break; + case PORTRAIT: + mainwindow->setAttribute(Qt::WA_Maemo5PortraitOrientation, true); + break; + default: + mainwindow->setAttribute(Qt::WA_Maemo5AutoOrientation, true); + break; + } +#endif + return a.exec(); +} diff --git a/src/newaccountdialog.cpp b/src/newaccountdialog.cpp new file mode 100644 index 0000000..3a3acd3 --- /dev/null +++ b/src/newaccountdialog.cpp @@ -0,0 +1,98 @@ +/* VLC-REMOTE for MAEMO 5 +* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2, +* or (at your option) any later version, as published by the Free +* Software Foundation +* +* 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, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#include "newaccountdialog.h" +#include +#include +#include +//#include + +NewAccountDialog::NewAccountDialog(QWidget *parent) +{ + Q_UNUSED(parent); + this->setWindowTitle(tr("Add account")); + + mKeyLineEdit = new QLineEdit; + mIpLineEdit = new QLineEdit; + mPortLineEdit = new QLineEdit; + mPortLineEdit->setText("8080"); + mPortLineEdit->setReadOnly(false); + + mButtonBox = new QDialogButtonBox; + mButtonBox->addButton(QDialogButtonBox::Save); + mButtonBox->addButton(QDialogButtonBox::Cancel); + + connect(mButtonBox, SIGNAL(accepted()), this, SLOT(save())); + connect(mButtonBox, SIGNAL(rejected()), this, SLOT(reject())); + + QFormLayout *layout = new QFormLayout; + layout->expandingDirections(); + layout->addRow(tr("Name:"), mKeyLineEdit); + layout->addRow(tr("Ip:"), mIpLineEdit); + layout->addRow(tr("Port:"), mPortLineEdit); + layout->addWidget(mButtonBox); + + setLayout(layout); +} + +void NewAccountDialog::save() +{ + QString myKey = mKeyLineEdit->text(); + QString myIp = mIpLineEdit->text(); + QString myPort = mPortLineEdit->text(); + + QSettings settings; + settings.beginGroup("account"); + if (!mEditKey.isEmpty()) { + settings.remove(mEditKey); + } + + if (!myIp.isEmpty() && !myKey.isEmpty()) { + if (myPort.isEmpty()) { + myPort = "8080"; + } + settings.setValue(myKey, myIp+":"+myPort); + // Rajouter des tests pour vérifier qu'on est sur Maemo + //QMaemo5InformationBox::information(this, tr("Account saved"), QMaemo5InformationBox::DefaultTimeout); + } + settings.endGroup(); + + emit accept(); +} + +void NewAccountDialog::edit(QString &key, QString &ip) +{ + Q_UNUSED(ip); + this->setWindowTitle(tr("Edit account")); + + QSettings settings; + settings.beginGroup("account"); + QString value = settings.value(key).toString(); + settings.endGroup(); + + QStringList values = value.split(":"); + + mEditKey = key; + mEditIp = values.first(); + mEditPort = values.last(); + + mKeyLineEdit->setText(mEditKey); + mKeyLineEdit->setDisabled(true); + mIpLineEdit->setText(mEditIp); + mPortLineEdit->setText(mEditPort); +} + diff --git a/src/newaccountdialog.h b/src/newaccountdialog.h new file mode 100644 index 0000000..70794ab --- /dev/null +++ b/src/newaccountdialog.h @@ -0,0 +1,50 @@ +/* VLC-REMOTE for MAEMO 5 +* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2, +* or (at your option) any later version, as published by the Free +* Software Foundation +* +* 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, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#ifndef NEWACCOUNTDIALOG_H +#define NEWACCOUNTDIALOG_H + +#include +#include +#include +#include + +class NewAccountDialog : public QDialog +{ + Q_OBJECT + +public: + explicit NewAccountDialog(QWidget *parent = 0); + void edit(QString &key, QString &ip); + +public slots: + void save(); + +private: + QLineEdit *mKeyLineEdit; + QLineEdit *mIpLineEdit; + QLineEdit *mPortLineEdit; + QPushButton *mSavePushButton; + QPushButton *mCancelPushButton; + QDialogButtonBox *mButtonBox; + + QString mEditKey; + QString mEditIp; + QString mEditPort; +}; + +#endif // NEWACCOUNTDIALOG_H diff --git a/src/playermainwindow.cpp b/src/playermainwindow.cpp new file mode 100644 index 0000000..33d001c --- /dev/null +++ b/src/playermainwindow.cpp @@ -0,0 +1,511 @@ + /* VLC-REMOTE for MAEMO 5 + * Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * or (at your option) any later version, as published by the Free + * Software Foundation + * + * 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, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + #include + #include + #include + #include "playermainwindow.h" + #include "ui_playermainwindow.h" + #include "configdialog.h" + #include "aboutdialog.h" + #include "accountdialog.h" + #include "appsettings.h" + //#include "vlcstatus.h" + + PlayerMainWindow::PlayerMainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::PlayerMainWindow) + { + ui->setupUi(this); + setWindowTitle("Vlc remote"); + + + + mTimer = new QTimer(this); + mNetManager = new QNetworkAccessManager(this); + mPlayListMainWindow = new PlayListMainWindow; + mBrowserMainWindow = new BrowseMainWindow; + + mVolume = 100; + mMuted = false; + + mIsLandscape = true; + + ui->playlistButton->setIcon(QIcon::fromTheme("notes_bullets")); + ui->browseButton->setIcon(QIcon::fromTheme("filemanager_media_folder")); + + ui->previousButton->setIcon(QIcon::fromTheme("pdf_viewer_first_page")); + ui->nextButton->setIcon(QIcon::fromTheme("pdf_viewer_last_page")); + ui->playpauseButton->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")); + ui->volMute->setIcon(QIcon::fromTheme("statusarea_volume_mute")); + + ui->labelArtPortrait->setVisible(false); + ui->labelArtLandscape->setVisible(false); + + ui->labelTitle->setTextFormat(Qt::RichText); + ui->labelArtist->setTextFormat(Qt::RichText); + ui->labelAlbum->setTextFormat(Qt::RichText); + + + #if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) + + mPlayListMainWindow->setParent(this); + mPlayListMainWindow->setAttribute(Qt::WA_Maemo5StackedWindow, true); + setAttribute(Qt::WA_Maemo5StackedWindow, true); + mPlayListMainWindow->setWindowFlags(mPlayListMainWindow->windowFlags() | Qt::Window); + + mBrowserMainWindow->setParent(this); + mBrowserMainWindow->setAttribute(Qt::WA_Maemo5StackedWindow, true); + setAttribute(Qt::WA_Maemo5StackedWindow, true); + mBrowserMainWindow->setWindowFlags(mBrowserMainWindow->windowFlags() | Qt::Window); + + connect(QApplication::desktop(), SIGNAL(resized(int)), this, SLOT(orientationChanged())); + + #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->actionPortrait,SIGNAL(triggered()),this,SLOT(setPortrait())); + connect(ui->actionLandscape,SIGNAL(triggered()),this,SLOT(setLandscape())); + connect(ui->actionAutoRotate,SIGNAL(triggered()),this,SLOT(setAutoRotate())); + connect(ui->playlistButton,SIGNAL(clicked()),mPlayListMainWindow,SLOT(show())); + connect(ui->playlistButton,SIGNAL(clicked()),mPlayListMainWindow,SLOT(showPlayList())); + connect(ui->browseButton,SIGNAL(clicked()),mBrowserMainWindow,SLOT(show())); + connect(ui->browseButton,SIGNAL(clicked()),mBrowserMainWindow,SLOT(showCurrentDirectory())); + + connect(ui->playpauseButton,SIGNAL(clicked()),this,SLOT(playpause())); + connect(ui->stopButton,SIGNAL(clicked()),this,SLOT(stop())); + 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->volMute,SIGNAL(clicked()),this,SLOT(volMute())); + connect(ui->slider,SIGNAL(sliderMoved(int)),this,SLOT(slide(int))); + + connect(mPlayListMainWindow, SIGNAL(idUpdated(int,bool,QString)), this, SLOT(playlistIdUpdated(int, bool, QString))); + + + // check if last used connection is still valid or showConfig + QSettings settings; + QString last_ip = AccountDialog::currentIp(); + if (!last_ip.isNull() && !last_ip.isEmpty()) { + QTcpSocket * socket = new QTcpSocket; + if(last_ip.contains(":")) + { + QStringList hostSplit = last_ip.split(":"); + QString ip = hostSplit.at(0); + QString port = hostSplit.at(1); + socket->connectToHost(ip,port.toInt()); + } + else { + socket->connectToHost(last_ip,8080); + } + if (!socket->waitForConnected(1000)) { + showConfig(); + } + else { + mIp= last_ip; + + mPlayListMainWindow->init(); + mBrowserMainWindow->init(); + mTimer->start(5000); + askStatus(); + } + delete socket; + } + else { + showConfig(); + } + + + } + + + 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::setPortrait() + { + #if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) + AppSettings::setOrientation(PORTRAIT); + this->setAttribute(Qt::WA_Maemo5PortraitOrientation, true); + #endif + } + + void PlayerMainWindow::setLandscape() + { + #if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) + AppSettings::setOrientation(LANDSCAPE); + this->setAttribute(Qt::WA_Maemo5LandscapeOrientation, true); + #endif + } + + void PlayerMainWindow::setAutoRotate() + { + #if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) + AppSettings::setOrientation(AUTO_ROTATE); + this->setAttribute(Qt::WA_Maemo5AutoOrientation, true); + #endif + } + + void PlayerMainWindow::orientationChanged() { + QRect screenGeometry = QApplication::desktop()->screenGeometry(); + mIsLandscape = (screenGeometry.width() > screenGeometry.height()); + if (mHasImage) { + if (mIsLandscape) { + ui->labelArtPortrait->setVisible(false); + ui->labelArtLandscape->setVisible(true); + } + else { + ui->labelArtLandscape->setVisible(false); + ui->labelArtPortrait->setVisible(true); + } + } + else { + ui->labelArtLandscape->setVisible(false); + ui->labelArtPortrait->setVisible(false); + } + } + + void PlayerMainWindow::playpause() + { + // NB. There is no guarentee that our current state is the real current state. + // This is due to the polling frequency and possibility of user interaction directly on the server. + // Still this is probably better than nothing and our next real poll will set us straight again. + if (PAUSED == mCurrentStatus.state) { + mCurrentStatus.state = PLAYING; + pause(); + updateUiWithCurrentStatus(); + } + else if (PLAYING == mCurrentStatus.state) { + mCurrentStatus.state = PAUSED; + pause(); + updateUiWithCurrentStatus(); + } + else { + // could be STOP or UNKNOWN, either way there is no guarentee we will enter a playing state next. + // So don't update the current state or UI + // Ideally we would try to find a way to check the current state again but this could lead to an infinite loop! + play(); + } + } + 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() + { + QUrl url = QUrl("http://"+mIp+"/requests/status.xml?command=volume"); + url.addEncodedQueryItem(QByteArray("val"), QByteArray("%2B10")); + mNetManager->get(QNetworkRequest(url)); + } + void PlayerMainWindow::volDown() + { + mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=volume&val=-10"))); + } + void PlayerMainWindow::volMute() + { + this->mMuted = !this->mMuted; + if (this->mMuted) { + mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=volume&val=0"))); + } + else { + mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=volume&val="+QString::number(this->mVolume)))); + } + } + void PlayerMainWindow::slide(int value) + { + mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=seek&val="+QString::number(value)+"%25"))); + } + + void PlayerMainWindow::showConfig() + { + mTimer->stop(); + AccountDialog * dialog = new AccountDialog; + dialog->exec(); + + mIp= AccountDialog::currentIp(); + + mPlayListMainWindow->init(); + mBrowserMainWindow->init(); + mTimer->start(5000); + askStatus(); + } + void PlayerMainWindow::showAbout() + { + + AboutDialog * dialog = new AboutDialog; + dialog->exec(); + + } + + void PlayerMainWindow::askStatus() + { + //qDebug() << "Status requested. at:" << QTime::currentTime().toString("hh::mm:ss"); + 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()); + delete reply; + QDomElement docElem = doc.documentElement(); + // Get the raw values + 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(); + int random = docElem.namedItem("random").toElement().text().toInt(); + int loop = docElem.namedItem("loop").toElement().text().toInt(); + int repeat = docElem.namedItem("repeat").toElement().text().toInt(); + QString state = docElem.namedItem("state").toElement().text(); + QDomNode infoNode = docElem.namedItem("information"); + QDomNode metaInfoNode = infoNode.namedItem("meta-information"); + QString title = metaInfoNode.namedItem("title").toElement().text().replace("\\\\", "\\"); + // if it's a file style title fix it up + if (40 < title.length()) { + if (0 < title.lastIndexOf("\\")) { + title = title.right(title.length() - (title.lastIndexOf("\\") + 1)); + } + else if (0 < title.lastIndexOf("/")) { + title = title.right(title.length() - (title.lastIndexOf("/") + 1)); + } + } + QString artist = metaInfoNode.namedItem("artist").toElement().text(); + QString album = metaInfoNode.namedItem("album").toElement().text(); + QString now_playing = metaInfoNode.namedItem("now_playing").toElement().text(); + QString art_url = metaInfoNode.namedItem("art_url").toElement().text(); + //metaInfoNode.clear(); + //infoNode.clear(); + //docElem.clear(); + //doc.clear(); + // Populate the current status structure + // now would be a good time to work out if we are a new track / file or not. + // key if we are going to look for album art later + // for now we check length and title this will require further examination later + mCurrentStatus.newtrack = true; + if (mCurrentStatus.length == length && !mCurrentStatus.title.isNull() && 0 == QString::compare(mCurrentStatus.title, title)) { + mCurrentStatus.newtrack = false; + } + mCurrentStatus.volume = volume; + mCurrentStatus.length = length; + mCurrentStatus.time = time; + mCurrentStatus.position = position; + mCurrentStatus.random = (1 == random); + mCurrentStatus.loop = (1 == loop); + mCurrentStatus.repeat = (1 == repeat); + mCurrentStatus.title = title; + mCurrentStatus.artist = artist; + mCurrentStatus.album = album; + mCurrentStatus.nowplaying = now_playing; + mCurrentStatus.hasart = (!art_url.isNull() && !art_url.isEmpty()); + if (!state.isNull() && !state.isEmpty()) { + if (0 == QString::compare("playing", state, Qt::CaseInsensitive)) { + mCurrentStatus.state = PLAYING; + } + else if (0 == QString::compare("paused", state, Qt::CaseInsensitive)) { + mCurrentStatus.state = PAUSED; + } + else if (0 == QString::compare("stop", state, Qt::CaseInsensitive)) { + mCurrentStatus.state = STOP; + } + else { + mCurrentStatus.state = UNKNOWN; + } + } + else { + mCurrentStatus.state = UNKNOWN; + } + // What's our mute status? + if (0 < mCurrentStatus.volume) { + this->mVolume = mCurrentStatus.volume; + this->mMuted = false; + } + else { + this->mMuted = true; + } + // Update the UI + updateUiWithCurrentStatus(); + + } + + void PlayerMainWindow::updateUiWithCurrentStatus() { + // position + QTime timePosition(0,0,0) ; + timePosition = timePosition.addSecs(mCurrentStatus.time); + + ui->timeLabel->setText(timePosition.toString("h:mm:ss")); + + // duration + if (0 < mCurrentStatus.length) { + QTime timeDuration(0,0,0) ; + timeDuration = timeDuration.addSecs(mCurrentStatus.length); + + ui->durationLabel->setText(timeDuration.toString("h:mm:ss")); + } + else { + ui->durationLabel->setText("0:00:00"); + } + + + if (mCurrentStatus.position >= 0 && mCurrentStatus.position <= 100) { + ui->slider->blockSignals(true); + ui->slider->setValue(mCurrentStatus.position); + ui->slider->blockSignals(false); + } + + ui->labelTitle->setText(mCurrentStatus.title); + ui->labelArtist->setText(mCurrentStatus.artist); + ui->labelAlbum->setText(mCurrentStatus.album); + + if (PLAYING == mCurrentStatus.state) { + ui->playpauseButton->setIcon(QIcon::fromTheme("camera_video_pause")); + } + else { + ui->playpauseButton->setIcon(QIcon::fromTheme("camera_playback")); + } + + if (mCurrentStatus.newtrack) { + // potential actions: + // rebuild display layout + // retrieve album art + mHasImage = false; + QTimer::singleShot(500, mPlayListMainWindow, SLOT(requestPlayList())); + } + // Update the buttons on the playlist window + if (NULL != this->mPlayListMainWindow) { + this->mPlayListMainWindow->updateUiWithCurrentStatus(& mCurrentStatus); + } + + } + void PlayerMainWindow::playlistIdUpdated(int id, bool hasart, QString extension) { + Q_UNUSED(extension); + if (hasart) { + getCoverArt(id); + } + else { + ui->labelArtLandscape->setVisible(false); + ui->labelArtPortrait->setVisible(false); + // could use a default graphic from extension here! + // setCoverArtFromPixmap(); + } + } + void PlayerMainWindow::error(QNetworkReply::NetworkError code) { + qDebug() << "Error Code: " << code; + } + void PlayerMainWindow::readReady() { + QNetworkReply * reply = qobject_cast(sender()); + // append to buffer + mResponse += reply->readAll(); + } + void PlayerMainWindow::finished(QNetworkReply * reply) { + // now we can call setCoverArt to process the full buffers + this->setCoverArt(mResponse); + // only interested in finished signals + disconnect(mNetManager,SIGNAL(finished(QNetworkReply *)),this,SLOT(finished(QNetworkReply *))); + delete reply; + } + void PlayerMainWindow::getCoverArt(int id) { + qDebug() << "getCoverArt id=!" << id; + mResponse.clear(); + QNetworkReply * reply = mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/art?id=" + QString::number(id)))); + connect(reply,SIGNAL(readyRead()),this,SLOT(readReady())); + connect(reply,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(error(QNetworkReply::NetworkError))); + connect(mNetManager,SIGNAL(finished(QNetworkReply *)),this,SLOT(finished(QNetworkReply *))); + + } + void PlayerMainWindow::setCoverArt(const QByteArray data) { + QPixmap* image = new QPixmap(); + if (image->loadFromData(data)) { + mHasImage = true; + ui->labelArtLandscape->setPixmap(image->scaledToHeight(120, Qt::SmoothTransformation)); + ui->labelArtPortrait->setPixmap(image->scaledToHeight(310, Qt::SmoothTransformation)); + if (mIsLandscape) { + ui->labelArtPortrait->setVisible(false); + ui->labelArtLandscape->setVisible(true); + } + else { + ui->labelArtLandscape->setVisible(false); + ui->labelArtPortrait->setVisible(true); + } + } + else { + qDebug() << "image load failed!"; + qDebug() << "data.length" << data.length(); + ui->labelArtPortrait->setVisible(false); + ui->labelArtLandscape->setVisible(false); + } + delete image; + } + void PlayerMainWindow::setCoverArtFromPixmap(QPixmap image) { + mHasImage = true; + ui->labelArtLandscape->setPixmap(image.scaledToHeight(120, Qt::SmoothTransformation)); + ui->labelArtPortrait->setPixmap(image.scaledToHeight(320, Qt::SmoothTransformation)); + if (mIsLandscape) { + ui->labelArtPortrait->setVisible(false); + ui->labelArtLandscape->setVisible(true); + } + else { + ui->labelArtLandscape->setVisible(false); + ui->labelArtPortrait->setVisible(true); + } + } + diff --git a/src/playermainwindow.h b/src/playermainwindow.h new file mode 100644 index 0000000..73c22b2 --- /dev/null +++ b/src/playermainwindow.h @@ -0,0 +1,90 @@ +/* VLC-REMOTE for MAEMO 5 +* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2, +* or (at your option) any later version, as published by the Free +* Software Foundation +* +* 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, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#ifndef PLAYERMAINWINDOW_H +#define PLAYERMAINWINDOW_H + +#include +#include +#include +#include +#include "playlistmainwindow.h" +#include "browsemainwindow.h" +#include "vlcstatus.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 playpause(); + void stop(); + void pause(); + void previous(); + void next(); + void fullscreen(); + void volUp(); + void volDown(); + void volMute(); + void slide(int value); + void updateUiWithCurrentStatus(); + void setCoverArt(const QByteArray data); + void setCoverArtFromPixmap(QPixmap image); + void getCoverArt(int id); + void finished(QNetworkReply * reply); + void error(QNetworkReply::NetworkError code); + void readReady(); + void orientationChanged(); + void setPortrait(); + void setLandscape(); + void setAutoRotate(); + void playlistIdUpdated(int id, bool hasart, QString extension); + + +protected slots: + void parseXmlStatus(); +protected: + void changeEvent(QEvent *e); + + +private: + Ui::PlayerMainWindow *ui; + PlayListMainWindow * mPlayListMainWindow; + BrowseMainWindow * mBrowserMainWindow; + QNetworkAccessManager * mNetManager; + QString mIp; + QTimer * mTimer; + int mVolume; + int mMuted; + VlcStatus mCurrentStatus; + QByteArray mResponse; + bool mIsLandscape; + bool mHasImage; + +}; + +#endif // PLAYERMAINWINDOW_H diff --git a/src/playermainwindow.ui b/src/playermainwindow.ui new file mode 100644 index 0000000..a9d9065 --- /dev/null +++ b/src/playermainwindow.ui @@ -0,0 +1,320 @@ + + + PlayerMainWindow + + + + 0 + 0 + 796 + 631 + + + + Vlc-Remote + + + + + + + + 380 + 350 + + + + + 380 + 350 + + + + Qt::AlignCenter|Qt::AlignHCenter|Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + 0 + 30 + + + + Information + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 30 + + + + Information + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 30 + + + + Information + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + 140 + 140 + + + + + 140 + 140 + + + + Qt::AlignCenter|Qt::AlignHCenter|Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + Qt::Vertical + + + + 20 + 100 + + + + + + + + + + color: rgb(201, 201, 201); + + + + + + + + + + color: rgb(201, 201, 201); + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + true + + + 100 + + + Qt::Horizontal + + + + + + + + + < + + + + + + + Play/Pause + + + + + + + > + + + + + + + Stop + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + FS + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + V+ + + + + + + + V- + + + + + + + Mute + + + + + + + + + + + PlayList + + + + + + + Browse + + + + + + + + + + + 0 + 0 + 796 + 20 + + + + + menu + + + + + + + + + + + + Configuration + + + + + About + + + + + Portrait Mode + + + + + Landscape Mode + + + + + Auto Rotate + + + + + + diff --git a/src/playlistmainwindow.cpp b/src/playlistmainwindow.cpp new file mode 100644 index 0000000..a6c8a5c --- /dev/null +++ b/src/playlistmainwindow.cpp @@ -0,0 +1,411 @@ +/* VLC-REMOTE for MAEMO 5 + * Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * or (at your option) any later version, as published by the Free + * Software Foundation + * + * 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, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "playlistmainwindow.h" +#include "ui_playlistmainwindow.h" +#include +#include +#if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) +#include +#endif +#include "configdialog.h" +#include "aboutdialog.h" +#include "appsettings.h" +//#include "vlcstatus.h" + +PlayListMainWindow::PlayListMainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::PlayListMainWindow) +{ + + ui->setupUi(this); + mTimer = new QTimer(this); + setWindowTitle("Vlc remote"); + + mCurrentDepth = 0; + mCurrentVlcIndex = 0; + + + mNetManager = new QNetworkAccessManager(this); + + mContents = new QList(); + + ui->listWidget->setTextElideMode(Qt::ElideLeft); + ui->listWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + ui->playButton->setIcon(QIcon::fromTheme("camera_playback")); + ui->clearButton->setIcon(QIcon::fromTheme("general_delete")); + ui->shuffleButton->setIcon(QIcon::fromTheme("mediaplayer_default_shuffle")); + ui->loopButton->setIcon(QIcon::fromTheme("general_refresh")); + ui->repeatButton->setIcon(QIcon::fromTheme("general_redo")); + ui->removeButton->setIcon(QIcon::fromTheme("general_close")); + + ui->clearButton->setDisabled(false); + ui->shuffleButton->setDisabled(false); + ui->loopButton->setDisabled(false); + ui->repeatButton->setDisabled(false); + ui->removeButton->setDisabled(true); + ui->playButton->setDisabled(true); + + connect(ui->playButton,SIGNAL(clicked()),this,SLOT(onPlay())); + connect(ui->removeButton,SIGNAL(clicked()),this,SLOT(onRemove())); + connect(ui->repeatButton,SIGNAL(clicked()),this,SLOT(onRepeat())); + connect(ui->loopButton,SIGNAL(clicked()),this,SLOT(onLoop())); + connect(ui->shuffleButton,SIGNAL(clicked()),this,SLOT(onShuffle())); + connect(ui->clearButton,SIGNAL(clicked()),this,SLOT(onClear())); + connect(ui->listWidget, SIGNAL(itemSelectionChanged()), this, SLOT(onListSelectionChanged())); + + init(); + +} +void PlayListMainWindow::init() // CALL WHEN CONFIG CHANGES +{ + mIp = AppSettings::getCurrentIp(); // AccountDialog::currentIp(); +} +void PlayListMainWindow::showPlayList() // CALL WHEN SHOWN +{ + requestPlayList(); +} + +PlayListMainWindow::~PlayListMainWindow() +{ + delete ui; +} + +void PlayListMainWindow::changeEvent(QEvent *e) +{ + QMainWindow::changeEvent(e); + switch (e->type()) { + case QEvent::LanguageChange: + ui->retranslateUi(this); + break; + default: + break; + } +} + +void PlayListMainWindow::onListSelectionChanged() { + QList items = ui->listWidget->selectedItems(); + if (0 < items.count()) { + // TODO VLC doesn't seem to support removing nodes! + // Playing nodes works fine, however. + // should check to see if it is a leaf or not and disable the remove button + mCurrentVlcIndex = items.at(0)->type() - LIST_ITEM_TYPE_OFFSET; // Qt reserves types up to 1000, we use an offset beyond that for index tracking. May prove to be too hacky! + mCurrentElement = getElementFromId(mCurrentVlcIndex); + if (0 == QString::compare("node", mCurrentElement.type)) { + ui->removeButton->setDisabled(true); + ui->playButton->setDisabled(false); + } + else { + ui->removeButton->setDisabled(false); + ui->playButton->setDisabled(false); + } + } + else { + mCurrentVlcIndex = 0; + ui->removeButton->setDisabled(true); + ui->playButton->setDisabled(true); + } +} + +void PlayListMainWindow::onRemove() { + if (0 < this->mCurrentVlcIndex) { + mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=pl_delete&id=" + QString::number(this->mCurrentVlcIndex)))); + //connect(mNetManager,SIGNAL(finished(QNetworkReply *)),this,SLOT(requestPlayList())); + // don't refresh just clear the item! + delete ui->listWidget->takeItem(ui->listWidget->currentRow()); + } +} +void PlayListMainWindow::onPlay() { + if (0 < this->mCurrentVlcIndex) { + mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=pl_play&id=" + QString::number(this->mCurrentVlcIndex)))); + } +} +void PlayListMainWindow::onRepeat() { + mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=pl_repeat"))); +} +void PlayListMainWindow::onLoop() { + mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=pl_loop"))); +} +void PlayListMainWindow::onShuffle() { + mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=pl_random"))); +} +void PlayListMainWindow::onClear() { + mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/status.xml?command=pl_empty"))); + mContents->clear(); + ui->listWidget->clear(); + //connect(mNetManager,SIGNAL(finished(QNetworkReply *)),this,SLOT(requestPlayList())); +} +void PlayListMainWindow::requestPlayList() { + mResponse.clear(); + ui->removeButton->setDisabled(true); + ui->playButton->setDisabled(true); +#if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) + this->setAttribute(Qt::WA_Maemo5ShowProgressIndicator, true); +#endif + QNetworkReply * reply = mNetManager->get(QNetworkRequest(QUrl("http://"+mIp+"/requests/playlist.xml"))); + disconnect(mNetManager,SIGNAL(finished(QNetworkReply *)),this,SLOT(requestPlayList())); + connect(reply,SIGNAL(readyRead()),this,SLOT(readReady())); + connect(reply,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(error(QNetworkReply::NetworkError))); + connect(mNetManager,SIGNAL(finished(QNetworkReply *)),this,SLOT(finished(QNetworkReply *))); +} +void PlayListMainWindow::error(QNetworkReply::NetworkError code) { +#if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) + this->setAttribute(Qt::WA_Maemo5ShowProgressIndicator, false); +#endif + qDebug() << code; +#if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) + QMaemo5InformationBox::information(this, tr("Playlist could not be retrieved."), QMaemo5InformationBox::DefaultTimeout); +#endif +} +void PlayListMainWindow::readReady() { + QNetworkReply * reply = qobject_cast(sender()); + // append to buffer + mResponse += reply->readAll(); +} +void PlayListMainWindow::finished(QNetworkReply * reply) { + // now we can call parseXmlList to process the full buffers + this->parseXmlPlayList(); + // only interested in finished signals + disconnect(mNetManager,SIGNAL(finished(QNetworkReply *)),this,SLOT(finished(QNetworkReply *))); +#if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) + this->setAttribute(Qt::WA_Maemo5ShowProgressIndicator, false); +#endif + delete reply; +} + +void PlayListMainWindow::parseXmlPlayList() { + mContents->clear(); + QDomDocument doc; + doc.setContent(this->mResponse); + QDomElement docElem = doc.documentElement(); + QDomNodeList nodes = docElem.elementsByTagName("node"); + int depth = 0; + + int currentLeafId = 0; + bool hasArt = false; + QString extension = ""; + + int ct = nodes.count(); + for (int idx = 0; idx < ct; ++idx) { + QDomNode node = nodes.at(idx); + QString current = ""; + //QString name = node.attributes().namedItem("name").nodeValue().replace("\\\\", "\\"); + int id = node.attributes().namedItem("id").nodeValue().toInt(); + if (4 > id && 0 == QString::compare(node.attributes().namedItem("ro").nodeValue(), "ro")) { + // got the main playlist, let's build it up + if (node.hasChildNodes()) { + QDomNodeList leafs = node.childNodes(); + int leafct = leafs.count(); + if (0 < leafct) { + depth = 1; + for (int jdx = 0; jdx < leafct; ++jdx) { + QDomNode leaf = leafs.at(jdx); + parsePlayListItem(&leaf, &extension, &hasArt, ¤tLeafId, 1); + } + } + } + + } + } + + mResponse.clear(); + + emit this->idUpdated(currentLeafId, hasArt, extension); + this->updateList(); + + +} + + +int PlayListMainWindow::parsePlayListItem(QDomNode *node, QString *extension, bool *hasArt, int *currentLeafId, int depth) { + int leafCt = 0; + if (NULL != node) { + QString current; + VlcPlayListElementSimple* el = new VlcPlayListElementSimple(); + el->id = node->attributes().namedItem("id").nodeValue().toInt(); + el->path = node->attributes().namedItem("uri").nodeValue(); + el->name = node->attributes().namedItem("name").nodeValue().replace("\\\\", "\\"); + current = node->attributes().namedItem("current").nodeValue(); + el->playing = (0 < current.length()); + el->depth = depth; + if (0 != QString::compare(node->nodeName(), "node")) { + el->type = "leaf"; + el->extension = getExtension(el->path, NULL); + if (el->playing) { + *currentLeafId = el->id; + QString art = node->toElement().namedItem("art_url").toElement().text(); + *hasArt = (!art.isNull() && !art.isEmpty()); + *extension = getExtension(el->path, NULL); + } + QString title = node->toElement().namedItem("title").toElement().text(); + QString artist = node->toElement().namedItem("artist").toElement().text(); + QString album = node->toElement().namedItem("album").toElement().text(); + if (0 < artist.length() || 0 < album.length()) { + el->name = "" + title + "\n" + artist + " - " + album; + } + this->mContents->append(*el); + ++leafCt; + delete el; + } + else { + el->type = "node"; + el->extension = getExtension(el->path, NULL); + // empty nodes appear in the playlist when they can't be played! + if (node->hasChildNodes()) { + this->mContents->append(*el); + ++leafCt; + } + delete el; + // now parse the child nodes as leaf. + if (node->hasChildNodes()) { + QDomNodeList items = node->childNodes(); + int itemct = items.count(); + int added = 0; + if (0 < itemct) { + ++depth; + for (int kdx = 0; kdx < itemct; ++kdx) { + QDomNode item = items.at(kdx); + added += parsePlayListItem(&item, extension, hasArt, currentLeafId, depth); + } + if (1 > added) { + // should remove the last PlayListElement + this->mContents->removeLast(); + --leafCt; + } + else { + leafCt += added; + } + } + } + } + } + return leafCt; +} + +QString PlayListMainWindow::getExtension(QString path, QString extension) { + // return extension if exists + if (!extension.isNull() && !extension.isEmpty()) return extension; + // return blank if no path + if (path.isNull() || path.isEmpty()) return ""; + // otherwise extract the extension + int dot_pos = path.lastIndexOf('.'); + if (0 < dot_pos) { + return path.right(path.length() - (dot_pos + 1)); + } + else { // no dot + return ""; + } +} + +VlcPlayListElementSimple PlayListMainWindow::getElementFromId(int id) { + //if (0 != QString::compare("", text)) { + for (int idx = 0; idx < mContents->count(); ++idx) { + if (0 < id && (id == mContents->at(idx).id)) { + return mContents->at(idx); + } + } + //} + return *(new VlcPlayListElementSimple()); +} + +void PlayListMainWindow::updateList() { + ui->listWidget->clear(); + int ct = this->mContents->count(); + if (0 < ct) { + QIcon icon_audio = QIcon::fromTheme("general_audio_file"); + QIcon icon_video = QIcon::fromTheme("general_video_file"); + QIcon icon_image = QIcon::fromTheme("general_image"); + QIcon icon_flash = QIcon::fromTheme("filemanager_flash_file"); + QIcon icon_media = QIcon::fromTheme("filemanager_media_folder"); + QIcon icon_real = QIcon::fromTheme("filemanager_real_music"); + QIcon icon_playl = QIcon::fromTheme("filemanager_playlist"); + QIcon icon_unknown= QIcon::fromTheme("filemanager_unknown_file"); + for (int idx = 0; idx < ct; ++idx) { + VlcPlayListElementSimple el = mContents->at(idx); + QListWidgetItem* item; + if (0 == QString::compare("node", el.type)) { + item = new QListWidgetItem(icon_media, el.name, ui->listWidget, LIST_ITEM_TYPE_OFFSET + el.id); + } + else { + if ( 0 == QString::compare(el.extension, "jpg") || + 0 == QString::compare(el.extension, "jpeg") || + 0 == QString::compare(el.extension, "gif") || + 0 == QString::compare(el.extension, "png") || + 0 == QString::compare(el.extension, "bmp") ) { + item = new QListWidgetItem(icon_image, el.name, ui->listWidget, LIST_ITEM_TYPE_OFFSET + el.id); // .jpg, .jpeg, .gif, .png, .bmp + } + else if ( 0 == QString::compare(el.extension, "mp3") || + 0 == QString::compare(el.extension, "m4a") || + 0 == QString::compare(el.extension, "ogg") || + 0 == QString::compare(el.extension, "oga") || + 0 == QString::compare(el.extension, "wav") || + 0 == QString::compare(el.extension, "flac") ) { + item = new QListWidgetItem(icon_audio, el.name, ui->listWidget, LIST_ITEM_TYPE_OFFSET + el.id); // .mp3, .m4a, .ogg, .oga, .wav, .flac + } + else if ( 0 == QString::compare(el.extension, "m3u") || + 0 == QString::compare(el.extension, "wpl") || + 0 == QString::compare(el.extension, "pls") || + 0 == QString::compare(el.extension, "asx") || + 0 == QString::compare(el.extension, "xspf") || + 0 == QString::compare(el.extension, "cmml") ) { + item = new QListWidgetItem(icon_playl, el.name, ui->listWidget, LIST_ITEM_TYPE_OFFSET + el.id); // .m3u, .wpl, .pls, .asx, .xspf, .cmml + } + else if ( 0 == QString::compare(el.extension, "avi") || + 0 == QString::compare(el.extension, "mpeg") || + 0 == QString::compare(el.extension, "mpg") || + 0 == QString::compare(el.extension, "mov") || + 0 == QString::compare(el.extension, "mp4") || + 0 == QString::compare(el.extension, "m4v") || + 0 == QString::compare(el.extension, "wmv") || + 0 == QString::compare(el.extension, "mkv") || + 0 == QString::compare(el.extension, "ogv") ) { + item = new QListWidgetItem(icon_video, el.name, ui->listWidget, LIST_ITEM_TYPE_OFFSET + el.id); // .avi, .mpg, .mpeg, .mov, .m4v, .mp4, .wmv, .mkv, .ogv + } + else if ( 0 == QString::compare(el.extension, "rm") || + 0 == QString::compare(el.extension, "ra") || + 0 == QString::compare(el.extension, "ram") ) { + item = new QListWidgetItem(icon_real, el.name, ui->listWidget, LIST_ITEM_TYPE_OFFSET + el.id); // .ram, 'rm, 'ra + } + else if ( 0 == QString::compare(el.extension, "flv") ) { + item = new QListWidgetItem(icon_flash, el.name, ui->listWidget, LIST_ITEM_TYPE_OFFSET + el.id); // .flv + } + //else if ( 0 == QString::compare(el.extension, "") ) { + // item = new QListWidgetItem(icon_unknown, el.name, ui->listWidget, LIST_ITEM_TYPE_OFFSET + el.id); // .flv + //} + else { + if (el.name.contains("Flash")) { + item = new QListWidgetItem(icon_flash, el.name, ui->listWidget, LIST_ITEM_TYPE_OFFSET + el.id); + } + else { + item = new QListWidgetItem(icon_media, el.name, ui->listWidget, LIST_ITEM_TYPE_OFFSET + el.id); + } + } + } + item->setSelected(el.playing); + ui->listWidget->addItem(item); + if (el.playing) { + ui->listWidget->scrollToItem(item, QAbstractItemView::PositionAtCenter); + } + } + } +} +void PlayListMainWindow::updateUiWithCurrentStatus(VlcStatus * status) { + ui->loopButton->setChecked(status->loop); + ui->repeatButton->setChecked(status->repeat); + ui->shuffleButton->setChecked(status->random); +} diff --git a/src/playlistmainwindow.h b/src/playlistmainwindow.h new file mode 100644 index 0000000..a6a444f --- /dev/null +++ b/src/playlistmainwindow.h @@ -0,0 +1,82 @@ +/* VLC-REMOTE for MAEMO 5 +* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2, +* or (at your option) any later version, as published by the Free +* Software Foundation +* +* 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, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#ifndef PLAYLISTMAINWINDOW_H +#define PLAYLISTMAINWINDOW_H + +#include +#include +#include +#include +#include "vlcplaylistelementsimple.h" +#include "vlcstatus.h" + +#ifndef LIST_ITEM_TYPE_OFFSET +#define LIST_ITEM_TYPE_OFFSET 1000 +#endif + +namespace Ui { + class PlayListMainWindow; +} + +class PlayListMainWindow : public QMainWindow { + Q_OBJECT +public: + explicit PlayListMainWindow(QWidget *parent = 0); + ~PlayListMainWindow(); + void init(); +public slots: + void onClear(); + void onShuffle(); + void onLoop(); + void onPlay(); + void onRepeat(); + void onRemove(); + void requestPlayList(); + void onListSelectionChanged(); + void finished(QNetworkReply * reply); + void readReady(); + void error(QNetworkReply::NetworkError code); + void showPlayList(); + void updateUiWithCurrentStatus(VlcStatus * status); + +protected slots: + void parseXmlPlayList(); + void updateList(); + int parsePlayListItem(QDomNode *node, QString *extension, bool *hasArt, int *currentLeafId, int depth); + +signals: + void idUpdated(int id, bool hasArt, QString extension); + +protected: + void changeEvent(QEvent *e); + VlcPlayListElementSimple getElementFromId(int id); + QString getExtension(QString path, QString extension); + +private: + Ui::PlayListMainWindow *ui; + QTimer * mTimer; + QString mIp; + QNetworkAccessManager * mNetManager; + QList* mContents; + VlcPlayListElementSimple mCurrentElement; + int mCurrentVlcIndex; + int mCurrentDepth; + QByteArray mResponse; +}; + +#endif // PLAYLISTMAINWINDOW_H diff --git a/src/playlistmainwindow.ui b/src/playlistmainwindow.ui new file mode 100644 index 0000000..c98d800 --- /dev/null +++ b/src/playlistmainwindow.ui @@ -0,0 +1,140 @@ + + + PlayListMainWindow + + + + 0 + 0 + 800 + 600 + + + + Playlist + + + + + + + + not yet done + + + + + not yet done + + + + + not yet done + + + + + + + + + + Play + + + + + + + Shuffle + + + true + + + + + + + Loop + + + true + + + + + + + Repeat + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Clear all + + + + + + + Remove + + + + + + + + + + + 0 + 0 + 800 + 25 + + + + + menu + + + + + + + Portrait Mode + + + + + Landscape Mode + + + + + + diff --git a/src/resource.qrc b/src/resource.qrc new file mode 100644 index 0000000..aeea2b6 --- /dev/null +++ b/src/resource.qrc @@ -0,0 +1,5 @@ + + + config-vlc.jpg + + diff --git a/src/ressources.qrc b/src/ressources.qrc new file mode 100644 index 0000000..0821e0c --- /dev/null +++ b/src/ressources.qrc @@ -0,0 +1,5 @@ + + + vlcremote_fr_FR.qm + + diff --git a/src/scanipdialog.cpp b/src/scanipdialog.cpp new file mode 100644 index 0000000..4de0efe --- /dev/null +++ b/src/scanipdialog.cpp @@ -0,0 +1,26 @@ +#include "scanipdialog.h" +#include "ui_scanipdialog.h" + +ScanIPDialog::ScanIPDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::ScanIPDialog) +{ + ui->setupUi(this); +} + +ScanIPDialog::~ScanIPDialog() +{ + delete ui; +} + +void ScanIPDialog::changeEvent(QEvent *e) +{ + QDialog::changeEvent(e); + switch (e->type()) { + case QEvent::LanguageChange: + ui->retranslateUi(this); + break; + default: + break; + } +} diff --git a/src/scanipdialog.h b/src/scanipdialog.h new file mode 100644 index 0000000..0e3cdf4 --- /dev/null +++ b/src/scanipdialog.h @@ -0,0 +1,23 @@ +#ifndef SCANIPDIALOG_H +#define SCANIPDIALOG_H + +#include + +namespace Ui { + class ScanIPDialog; +} + +class ScanIPDialog : public QDialog { + Q_OBJECT +public: + explicit ScanIPDialog(QWidget *parent = 0); + ~ScanIPDialog(); + +protected: + void changeEvent(QEvent *e); + +private: + Ui::ScanIPDialog *ui; +}; + +#endif // SCANIPDIALOG_H diff --git a/src/scanipdialog.ui b/src/scanipdialog.ui new file mode 100644 index 0000000..e5aa69a --- /dev/null +++ b/src/scanipdialog.ui @@ -0,0 +1,83 @@ + + + ScanIPDialog + + + + 0 + 0 + 422 + 360 + + + + Dialog + + + + + + + + + + name + + + + + + + + + + IP + + + + + + + + + + + + + + + + + + + Scan + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Done + + + + + + + + + + diff --git a/src/src.pro b/src/src.pro new file mode 100644 index 0000000..35196ae --- /dev/null +++ b/src/src.pro @@ -0,0 +1,45 @@ +# ------------------------------------------------- +# Project created by QtCreator 2010-07-29T19:02:39 +# ------------------------------------------------- +QT += core \ + gui \ + network \ + xml \ + maemo5 +TARGET = vlc-remote +TEMPLATE = app +SOURCES += main.cpp \ + playlistmainwindow.cpp \ + playermainwindow.cpp \ + configdialog.cpp \ + aboutdialog.cpp \ + accountdialog.cpp \ + newaccountdialog.cpp \ + browsemainwindow.cpp \ + vlcbrowseelement.cpp \ + vlcplaylistelementsimple.cpp \ + vlcstatus.cpp \ + appsettings.cpp \ + favouritesmainwindow.cpp +HEADERS += playlistmainwindow.h \ + playermainwindow.h \ + configdialog.h \ + aboutdialog.h \ + accountdialog.h \ + newaccountdialog.h \ + browsemainwindow.h \ + vlcbrowseelement.h \ + vlcplaylistelementsimple.h \ + vlcstatus.h \ + appsettings.h \ + favouritesmainwindow.h +FORMS += playlistmainwindow.ui \ + playermainwindow.ui \ + configdialog.ui \ + aboutdialog.ui \ + accountdialog.ui \ + browsemainwindow.ui \ + favouritesmainwindow.ui +OTHER_FILES += vlc-remote.desktop +RESOURCES += ressources.qrc +TRANSLATIONS = vlcremote_fr_FR.ts diff --git a/src/vlc-remote.desktop b/src/vlc-remote.desktop new file mode 100644 index 0000000..82f4514 --- /dev/null +++ b/src/vlc-remote.desktop @@ -0,0 +1,12 @@ +[Desktop Entry] +Encoding=UTF-8 +Version=0.2 +Type=Application +Terminal=true +Name=vlc-remote +Exec=/usr/bin/vlc-remote +Icon= +#X-Window-Icon=timerwidget +X-Window-Icon= +X-HildonDesk-ShowInToolbar=true +X-Osso-Type=application/x-executable diff --git a/src/vlc-remote.png b/src/vlc-remote.png new file mode 100644 index 0000000000000000000000000000000000000000..7f58140f27ac2e337c06498d7d571cc4eaf51274 GIT binary patch literal 4444 zcmV-i5u@&jP)P>%3Jzjh@#t;7`+=%fk3 z9YaJwz&HRToj5do{NU)7P8B7%ql0iP=3M(-LlueC66fm9Wqe?F3=cBe*Vh+>eOhT4qa1x?3y zP9Hyb?V!2!LNxeGo)qt-WOt0-K78P22pPBrsDs8%MqEr*tCF66@qXau!Sh>=!3*>V zX72P~eQ5lapV?MA`1`%j(TwUtZ@X!*#Cl`EE+)d>S6Mq={Utm3;dM@nDPMOan*RLj z?i?Jq-WaSvCr`-KnMcR$w)jRfcH_FIMteR&v|UdOhS=H|tUzymv&h*;ZY^K)?pW;l zp^lmODA8-&!7CjT4OF1hoVL+K^B3&)4XnL(g7Vwn2t+6P%W8cLQXtve_=oNGRrZJ( z-`M(VcO4~~3_sszUh86jyVyyozjW@lC>b@?fB!8c8bRwbP`v<24T6Vk0;%soQ5tjL z>kTUPomWjCKX_=zsk1*E9M=v8CeR~~VBUhiolwEey@c49F#F$xnRAd-!Fwdxj?Cxh zrwhu$3(BrHmXXoQmw;Ob#kCs)bFsHR@#hB+bA-|`QX0;q=MX>xgrejku6=%~B6tUB zO~H+=6BG0ogAzzWx^RrRB2pef;xY)J9?_702Gn!}vau4Cg~kGq4p*j+zwX$8xGuwh z1Ue}pgijGwkjf}(OK4E=9#o-Kv+J@TK`0GDV^PrnxZz(N4A3jB%41#Yr`oBnvi2vfyo$;$yDeto1FxtXv+ZNV*Gz#M`qCCL+t_vc+4;=zaCA>W1m#X(|jM@{Uj z6?EzaOlblMDY%4i@fpI4KR{>C6S4-FIHL@`ntLCd2^R7ORR!h#5SqPj|>RTh+2M&e-wfuyPUMDljN|1nX21QNLu zF%XrZGJ=$c!Nz%oBY5yB_}qeIrH{#KffT5W6ek9#&*!R2_DaI@jbY1ov8faGu$1L7 zGgij_#0}V;hmdXiVQ5?K8%tB@?0=yPFQRERx1?_P^0Gy`g{%S9ivb0!HW;;M3DsdV zx^TyiQ_p;3O9#<~e(Yj*mac)yYfF^g{-)TOa%)$@g}U{%|MFC$G8}=$k-W z>S9wTtOaf_?G|M8JzFZyGT3p<`1^?uOd)RK+Ua}u4)^Cmn{=^Lr%sIk$AD#tl@trf zM3~;Y+dg|VezhPY@4^fpLSflfo?ma(<_>7PpI*pmcFxhpQ-tcj;$E0!!4E(AQf2R> zA%Mu*1KPw`=YR)~A3uI(!vdW;b!r%RK26gdwOS1jM1--iQ4SwI4A66cFTQx5^FRJE zh+taBMS6&~^0QKCl7B9QRSm^?o!^(WFKz%Rc`3JbtkZ7wwN`2nMG@t4nR>l`_h#0h z+ma;N@!dxsMG$OciKCdEyLNHp$dNT0HIsz7g++`p7!gDaB2om2`MVZ%>7W5r2_c|L z{!Tzc>$m*e5Pb0-I==@+HQ;?fHMEbb20|#>1SPbNc~4M9yZY_ME=E z+j#BKPXh4VpZz|r-uK+GZ%EUWGiT1Qu&}_5H{M8^rc|rdjc@Z}t*HzRQ>j$AaNz;~ z6Z;Nw)pb7wz{1Ym`07G`*be}WMjgn7nwgnle0-dlnVF3XWW`FkTp=!%NYe~}kS2s? z(Q)GNsb8;)|FwuBgZCZo^?IF3rNZ>|^d2 z&XJ~R&ptQhVsWWN6vu7SEkY|vNsGryek~*DBHD^#z4M4Ms0oOPz!=0B2zj)N=FxNh zERn7nXt&VIbzSbP!3WYTB}+4sq)C=#OifL3?%cUoCQv9yN!K-3F4B4AtX(rFNEbl` zM2ozrIIo>Ps3IsL5o#lL?S3^g^Yghl-l17mM7@Pj+CwDrNfR-+;K?$FbB-*_a#4~L z?;Wa|^C-sT-0C9TrUepI+d>qBZdp)HO7h7yg(!suv^`r}$z#Z$ZDDyHq(zD##voC| zTMixK(3{@KA3pRA$WqiMkO-=}_0Uc{ zgAa%S=L0STvcgJlI(!|83;f=L50N5d0WzOw=!nUy0xd5#1{0SsL&HSFBSb?ZNL)gU zpw8iw2Bu!eHEQjIHn`AxG2gU6LDhSg&qV9DV)lb7qKXj%QA}xUoX;FPhFHtvXMV)F zi&K2!{qIFX;Ge(!Z#?yb?~{fGSuLUAzW6_jqhS!@jm2{=&FNx&=-Oyq$#dZr`E_tX)Z0&oS&oCXaY)7uMv`F z9;}6~p0v|fKFg~~H?xf2{L=^d!BbBWk|bZKL+Cs{6FebFaJ3ps^+u7ncI9-cG;39S zvq5lKC!${m8yBdsAm`kwTPITN09piM3o}#Pa>w16xRm?62p|3QX9!uElS`U}EG4W= za*Ns2;8DLk{7*8+eP4Z;C!c(hth$JA)(cAvom)EIvddx3E!yasf+K5>(&rz!vYPtOWPZ4&j-~bQG}4k7D=-$7S>{lokBx#JWElR<;Pny zsGVT16|aOWYxkcz$BC~##N&@WPC9o9Ut7W_&GsN$$*YDyND~~O&Jh~*d_fk05b$Y| zTVC4CEvQIrx5ULp-SojFxhl7y9>+zsm~|y2O2{(Anj+vUGW-y70laTN{*t>uzR0#k zOcO$yw8gpaPrk}`AA5pqaSpe%h-=hxp+hc?cDa~3m*4O5F1My)8*g1(U2dJ~ebIh> zY)GJ~6E>=h-E|;XPw*>tDadC}1W_fpB03dM$e^A67go}`!IzgrI;D#|!w$JCG@FE^ zN#-11c;Jutk0-u|t1aQ{HC&^PrYY)tyIr>hgd%vvxppW4MdltlmewA`7Og=yi@J() z4(Hc+GE9pH>O>)cN>P?rdAE?l+E$X&+Gk`T(Ye2J% z0Q}>(zD03AmQd7#g3EF@UNhe5SYs=7Sjlyx!n6=gov>fB6WnVmx+*3Lncy$AzY(18 zz0LO??S@IT&essoq9B$zpH~7}@l~;gY$zCfIoDqU5%9Tqhni^T>JHsB_)D#V6C`Ou z@D3x=4&y=yG#ZUnZ8r*4kN1IkqfsnZrdYR4JAP?xtAlG{Wj#9T zN^+xTlhP1R0Z*;p$y8{tP@5+NWpZ+oix)4pJAd}sXE#l%CtA7D%H*-DJlb!F2-~-B zr&_H75Is?=WQodU@0Co226Oc}ym#!|w~zVxd6KS_VoRWFtZoAk26Az(zWQp)<#I=$ z-Ld-+!ab_2d*68K()@u-m&#YGD%-Yg)pWW~i zW*_|E2VY;UR?kFHB-YyY?Vf)9ug8@{mSsHm+;i0H_4_yVjN<(~8% ivYZ~62fhaU_WuB1e?=, Dru Moore , Yann Nave + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * or (at your option) any later version, as published by the Free + * Software Foundation + * + * 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, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "vlcbrowseelement.h" + diff --git a/src/vlcbrowseelement.h b/src/vlcbrowseelement.h new file mode 100644 index 0000000..b263b10 --- /dev/null +++ b/src/vlcbrowseelement.h @@ -0,0 +1,33 @@ +/* VLC-REMOTE for MAEMO 5 +* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2, +* or (at your option) any later version, as published by the Free +* Software Foundation +* +* 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, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#ifndef VLCBROWSEELEMENT_H +#define VLCBROWSEELEMENT_H +#include +#include + +struct VlcBrowseElement { + QString type; + int size; + QDate date; + QString path; + QString name; + QString extension; +} ; + + +#endif // VLCBROWSEELEMENT_H diff --git a/src/vlcplaylistelementsimple.cpp b/src/vlcplaylistelementsimple.cpp new file mode 100644 index 0000000..08eb506 --- /dev/null +++ b/src/vlcplaylistelementsimple.cpp @@ -0,0 +1,18 @@ +/* VLC-REMOTE for MAEMO 5 + * Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * or (at your option) any later version, as published by the Free + * Software Foundation + * + * 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, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "vlcplaylistelementsimple.h" diff --git a/src/vlcplaylistelementsimple.h b/src/vlcplaylistelementsimple.h new file mode 100644 index 0000000..a49dea8 --- /dev/null +++ b/src/vlcplaylistelementsimple.h @@ -0,0 +1,33 @@ +/* VLC-REMOTE for MAEMO 5 +* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2, +* or (at your option) any later version, as published by the Free +* Software Foundation +* +* 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, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#ifndef VLCPLAYLISTELEMENTSIMPLE_H +#define VLCPLAYLISTELEMENTSIMPLE_H + +#include + +struct VlcPlayListElementSimple { + int id; // vlc playlist item id + int depth; // how deep in the tree + bool playing; // currently playing item + QString type; // node or leaf + QString extension; // file extension + QString path; // Only used for leaf - repeat name otherwise + QString name; // name or metadata title if available +} ; + +#endif // VLCPLAYLISTELEMENTSIMPLE_H diff --git a/src/vlcremote_fr_FR.qm b/src/vlcremote_fr_FR.qm new file mode 100644 index 0000000000000000000000000000000000000000..7ce38cafa06fa940dc521b38e71a539d4795ff55 GIT binary patch literal 12582 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 literal 0 HcmV?d00001 diff --git a/src/vlcremote_fr_FR.ts b/src/vlcremote_fr_FR.ts new file mode 100644 index 0000000..5204e2a --- /dev/null +++ b/src/vlcremote_fr_FR.ts @@ -0,0 +1,433 @@ + + + + + AboutDialog + + + Dialog + À propos + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'DejaVu Sans'; font-size:14pt; font-weight:400; font-style:normal;"> +<table style="-qt-table-type: root; margin-top:4px; margin-bottom:4px; margin-left:4px; margin-right:4px;"> +<tr> +<td style="border: none;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">OMed </p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Application by Sacha schutz </p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">istdasklar@gmail.com</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://omedsoft.blogspot.com/"><span style=" text-decoration: underline; color:#0000ff;">http://omedsoft.blogspot.com/</span></a></p></td></tr></table></body></html> + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'DejaVu Sans'; font-size:14pt; font-weight:400; font-style:normal;"> +<table style="-qt-table-type: root; margin-top:4px; margin-bottom:4px; margin-left:4px; margin-right:4px;"> +<tr> +<td style="border: none;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">OMed </p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Application par Sacha schutz </p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">istdasklar@gmail.com</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://omedsoft.blogspot.com/"><span style=" text-decoration: underline; color:#0000ff;">http://omedsoft.blogspot.com/</span></a></p></td></tr></table></body></html> + + + + AccountDialog + + + Accounts + Comptes + + + + test + test + + + + Add + Ajouter + + + + Edit + Éditer + + + + Remove + Supprimer + + + + Use + Utiliser + + + + BrowseMainWindow + + + MainWindow + Vlc remote + + + + Play + Lire + + + + Enqueue + Ajouter + + + + Browse + Ouvrir + + + + menu + + + + + User Folder + Utiliser + + + + Home + Dossier d'accueil + + + + Set as Home + Marquer comme dossier d'accueil + + + + Favourites + Favoris + + + + Add to Favourite + Ajouter aux favoris + + + configuration + Configuration + + + About + À propos + + + + Directory could not be browsed! + Le dossier ne peux être listé ! + + + + ConfigDialog + + + Dialog + Configuration + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'DejaVu Sans'; font-size:14pt; font-weight:400; font-style:normal;"> +<table border="0" style="-qt-table-type: root; margin-top:4px; margin-bottom:4px; margin-left:4px; margin-right:4px;"> +<tr> +<td style="border: none;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Enter IP of VLC server. </p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Example : <span style=" font-weight:600;">192.168.0.8:8080</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Be sure you have properly configured Vlc</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> and allows connection by adding this IP in /vlc/http/.hosts</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">More information on my blog : <a href="http://omedsoft.blogspot.com/"><span style=" text-decoration: underline; color:#0000ff;">omed.blogspot.com</span></a><br /></p></td></tr></table></body></html> + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'DejaVu Sans'; font-size:14pt; font-weight:400; font-style:normal;"> +<table border="0" style="-qt-table-type: root; margin-top:4px; margin-bottom:4px; margin-left:4px; margin-right:4px;"> +<tr> +<td style="border: none;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Mettre l'ip du Serveur VLC.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Exemple : <span style=" font-weight:600;">192.168.0.8:8080</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Vous devez avoir configurer VLC correctement</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> et autoriser les connexions en ajoutant l'ip de votre N900 dans /vlc/http/.hosts</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Plus d'informations sur mon blog : <a href="http://omedsoft.blogspot.com/"><span style=" text-decoration: underline; color:#0000ff;">omed.blogspot.com</span></a><br /></p></td></tr></table></body></html> + + + + FavouritesMainWindow + + + MainWindow + Vlc remote + + + + Name + Nom + + + + Save + Sauvegarder + + + + Delete + Supprimer + + + + Edit + Éditer + + + + Browse + Ouvrir + + + + Set as Home + Dossier d'accueil + + + + NewAccountDialog + + + Add account + Ajouter un compte + + + + Name: + Nom : + + + + Ip: + Ip : + + + + Port: + Port : + + + + Edit account + Édition d'un compte + + + + PlayListMainWindow + + MainWindow + Vlc remote + + + + Playlist + Liste de lecture + + + + + + not yet done + fonctions pas encore développée + + + Clear + Vider + + + + Play + Lire + + + + Shuffle + Aléatoire + + + + Loop + Boucler + + + + Repeat + Répéter + + + + Clear all + Vider + + + + Remove + Supprimer + + + + menu + + + + + Portrait Mode + Mode Portrait + + + + Landscape Mode + Mode Paysage + + + configuration + Configuration + + + About + À propos + + + + Playlist could not be retrieved. + Impossible de récupérer la liste de lecture. + + + + PlayerMainWindow + + MainWindow + Vlc remote + + + + Vlc-Remote + Vlc-Remote + + + + + + Information + Information + + + + < + < + + + play + Lire + + + + > + > + + + Pause + Pause + + + play/pause + Lire/Pause + + + + Stop + Stop + + + + FS + FS + + + + V+ + V+ + + + + V- + V- + + + mute + Couper le son + + + + Play/Pause + Lecture/Pause + + + + Mute + Couper le son + + + + PlayList + Liste de lecture + + + + Browse + Ouvrir + + + + menu + + + + + Configuration + Configuration + + + + About + À propos + + + + Portrait Mode + Mode Portrait + + + + Landscape Mode + Mode Paysage + + + + Auto Rotate + À propos de l'orientation + + + diff --git a/src/vlcstatus.cpp b/src/vlcstatus.cpp new file mode 100644 index 0000000..0857f0b --- /dev/null +++ b/src/vlcstatus.cpp @@ -0,0 +1,18 @@ +/* VLC-REMOTE for MAEMO 5 +* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2, +* or (at your option) any later version, as published by the Free +* Software Foundation +* +* 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, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#include "vlcstatus.h" diff --git a/src/vlcstatus.h b/src/vlcstatus.h new file mode 100644 index 0000000..738780a --- /dev/null +++ b/src/vlcstatus.h @@ -0,0 +1,46 @@ +/* VLC-REMOTE for MAEMO 5 +* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2, +* or (at your option) any later version, as published by the Free +* Software Foundation +* +* 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, write to the +* Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#ifndef VLCSTATUS_H +#define VLCSTATUS_H +#include + +enum VlcStatusState { + UNKNOWN, + STOP, + PLAYING, + PAUSED +}; + +struct VlcStatus { + bool newtrack; + bool random; + bool loop; + bool repeat; + bool hasart; + int volume; + int length; + int time; + int position; + VlcStatusState state; + QString title; + QString artist; + QString album; + QString nowplaying; +}; + +#endif // VLCSTATUS_H diff --git a/src/welcome b/src/welcome new file mode 100644 index 0000000..e69de29 diff --git a/todo.txt b/todo.txt deleted file mode 100644 index 9daeafb..0000000 --- a/todo.txt +++ /dev/null @@ -1 +0,0 @@ -test diff --git a/vlc-remote.desktop b/vlc-remote.desktop deleted file mode 100644 index 82f4514..0000000 --- a/vlc-remote.desktop +++ /dev/null @@ -1,12 +0,0 @@ -[Desktop Entry] -Encoding=UTF-8 -Version=0.2 -Type=Application -Terminal=true -Name=vlc-remote -Exec=/usr/bin/vlc-remote -Icon= -#X-Window-Icon=timerwidget -X-Window-Icon= -X-HildonDesk-ShowInToolbar=true -X-Osso-Type=application/x-executable diff --git a/vlc-remote.png b/vlc-remote.png deleted file mode 100644 index 7f58140f27ac2e337c06498d7d571cc4eaf51274..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4444 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 ivYZ~62fhaU_WuB1e?=, Dru Moore , Yann Nave - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, - * or (at your option) any later version, as published by the Free - * Software Foundation - * - * 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, write to the - * Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#include "vlcbrowseelement.h" - diff --git a/vlcbrowseelement.h b/vlcbrowseelement.h deleted file mode 100644 index b263b10..0000000 --- a/vlcbrowseelement.h +++ /dev/null @@ -1,33 +0,0 @@ -/* VLC-REMOTE for MAEMO 5 -* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2, -* or (at your option) any later version, as published by the Free -* Software Foundation -* -* 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, write to the -* Free Software Foundation, Inc., -* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -#ifndef VLCBROWSEELEMENT_H -#define VLCBROWSEELEMENT_H -#include -#include - -struct VlcBrowseElement { - QString type; - int size; - QDate date; - QString path; - QString name; - QString extension; -} ; - - -#endif // VLCBROWSEELEMENT_H diff --git a/vlcplaylistelementsimple.cpp b/vlcplaylistelementsimple.cpp deleted file mode 100644 index 08eb506..0000000 --- a/vlcplaylistelementsimple.cpp +++ /dev/null @@ -1,18 +0,0 @@ -/* VLC-REMOTE for MAEMO 5 - * Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, - * or (at your option) any later version, as published by the Free - * Software Foundation - * - * 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, write to the - * Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#include "vlcplaylistelementsimple.h" diff --git a/vlcplaylistelementsimple.h b/vlcplaylistelementsimple.h deleted file mode 100644 index a49dea8..0000000 --- a/vlcplaylistelementsimple.h +++ /dev/null @@ -1,33 +0,0 @@ -/* VLC-REMOTE for MAEMO 5 -* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2, -* or (at your option) any later version, as published by the Free -* Software Foundation -* -* 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, write to the -* Free Software Foundation, Inc., -* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -#ifndef VLCPLAYLISTELEMENTSIMPLE_H -#define VLCPLAYLISTELEMENTSIMPLE_H - -#include - -struct VlcPlayListElementSimple { - int id; // vlc playlist item id - int depth; // how deep in the tree - bool playing; // currently playing item - QString type; // node or leaf - QString extension; // file extension - QString path; // Only used for leaf - repeat name otherwise - QString name; // name or metadata title if available -} ; - -#endif // VLCPLAYLISTELEMENTSIMPLE_H diff --git a/vlcremote_fr_FR.qm b/vlcremote_fr_FR.qm deleted file mode 100644 index 7ce38cafa06fa940dc521b38e71a539d4795ff55..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12582 zcmeHNdu$v>8UJkG*^XbNp_D2hF}b8k+xTwJjT^a_vsK4-nh4vmVkc=Ngu1@n^KG-Y zyV>2d<5UGfEAc86gn~c;d1gJs?kbr-Jct}7I5>WVkGq<En35B~R&T&Ba?|a)U(XH=l z|G=F;BFes_{n0<8|J-BkALQp-M>_U8!=Rh(c=queWTuXv220@Q4XWICCG|1qGRFC& zD)$Ym^58S6C!cvI+WjN-)F9;8=cYdU&{?AXAFFcjpVE&U!#D$0es!^_wN2-$bZA5s=Vci z9hF}}u0dnR6W@Fm{rB$p+w(Qh{l4ev!8Y*uVsHM3=>PU}y$|R5pogixiI-moxkvi$ z{pw2??_A$czB`3>Qv-K@DUJ7USLNW77LnH9L9}BZ?7xR5=_F0i0-d8dnj%5RaX&-T zxSONXbQE_d@Lo`cvZUevEFHo#-%XXJ`Os9&H{xSqoJ6Bvals$|o!>?^>NPZpI>=E%U+K(Axe1MZ`iWAff49q;(QN+#Or z7~jE_pGHA*q23QunRF3X=CA}V99hFxZZ{jAf%$WG}YKVqKeYYvw-->x8(*E%;vPoAu?RKNmI3 z6Zgt~V__6-<$_!0$b(HczGscG2fCn3Zp9WZqg8SX_Q6Cl-a{efcw`?Z>(CCoF9Ujf=wFmFT5O(CPf zcGQ?9qn!bb1n@mu>gjIGMvep==W@^z&+qN(QAO!16?hLvF^;DkrQ=nXb;ENmfR;GQ zfo;I(tiR#&U5BiC#V{HT?a=L)~&s2tsKq*is&TBM$%l~p}4H@pWK>*lRu zC-%l4D(;y)Ik9kVZb}?qn3)!Hr;kpbm=Kw)rky=Bp=px~lj_BAF0W}*vl)@8grQf^ zw3U^W+{&Sx>n~{wr?gX36WK~wwTJUs5c*ar%o(AP8S5!>c&{HYKFRS^r|_U zxqvp6(7YICM9FnR(+Nj2Lm8os6@zfqHbuDVp%pjKN5fAnhF)%2{ikcd1(KS|utQyUTGRDZ3^{QpB77k3B_v>eBVqSNG14q=W zz`A4>hK9Yc{=8yZOO>!NoXUN!g7WBBG|0=pS=)fWkr_xE(qUs(Nk6T zmnfCuBo!kG6rjE{+VlA}CdA;iWC*%L+n656;`VfA>;Vx9nWWt!|~Bin^%yW_dK4xo*`o0=FFI zVB@90b3h|VxxUnJLDb+2zHPzhFlBAmFYL|ZuUv);)gsdHxPn3z2I%JOF=|aAzu!Pk-Y}?ymD8~+ zxZl%|`c0FTZ%g2@uxh-BFY87H15T#mO$W`npVHdJyK-7o{} z)s+1oY5_|o;qt0(EGC7Q1WSxLgqAheg#y# z@ea0ajG2R0B2QYfLi`4f zKzg}s`Z=+s(Bsraz3Ks%E{L^Yp2WZFp!Q*a+L^JTyY9#h9UjT$b0dY3{7Alm(rq1{ zdlYzj%{PTub!(!cFPp&kT@RQeLp4s>TEa_1oUuz=38o6&F@$d0K(?4G2Ut=af7T7d za+X9`u>y7r%MseLT>_{XdRngH24S$3e9yShtmTyX1VeHR(7d`T7y@Q*`Hw@yj18{= zoEr`YSa{Lrlb=@z4);w+XK2D}cT1d?7ujgz*jQ#8cuo^eys?9;Vv;w;NL`GQNjS45 zj5}%Crouv#JGcsRoJ{zt(7fbsI`K^tR_TVKQnNUqW8f>9}P zOzyRh5&x@q+k?-~I7P=cufb5q39pdMNS`v(I+`>as|D2nK6m4dCvWbX$4bw+e%OMp z2QY!P&Z;{mY*Y6+_A!^c81|jUQP;Zpa5L~;{+Nr?hdKDhDmJ+~yd=h%2c{81gOcu< zV#YP3pColQfG_npXDrElCO$1lO}nnwii;L7b<$WuBHNs|C}5heoJDc2$;e48KsSqS zL-bZ0+zSgc$PhvI(FbBmGd@lw7{2#VGHjz#Hs0>5L!Cq>DA({85wWrMAj3Ct{%$TK z+O}eE_Zl-P7vV1+aDvqspr4(@*Wu4svs23;7@uV&seS+-NnVkCif;eeS^67M7+^T?&X?7Wh*^!Jc(inhcEsx%4sl_nyIz2z;1cK z+K6_*b~t=9iV;V?9=4q}r`Oam^X9y~%0S9%NV1NuElzFDSU0vU^1IqtCG+?=CwcG` xR>6af#_eYgwr-kjYMM=M8tvP%hz`y)#g!aqsZ?@z-aGi`xmo2@xlNA diff --git a/vlcremote_fr_FR.ts b/vlcremote_fr_FR.ts deleted file mode 100644 index 5204e2a..0000000 --- a/vlcremote_fr_FR.ts +++ /dev/null @@ -1,433 +0,0 @@ - - - - - AboutDialog - - - Dialog - À propos - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'DejaVu Sans'; font-size:14pt; font-weight:400; font-style:normal;"> -<table style="-qt-table-type: root; margin-top:4px; margin-bottom:4px; margin-left:4px; margin-right:4px;"> -<tr> -<td style="border: none;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">OMed </p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Application by Sacha schutz </p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">istdasklar@gmail.com</p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://omedsoft.blogspot.com/"><span style=" text-decoration: underline; color:#0000ff;">http://omedsoft.blogspot.com/</span></a></p></td></tr></table></body></html> - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'DejaVu Sans'; font-size:14pt; font-weight:400; font-style:normal;"> -<table style="-qt-table-type: root; margin-top:4px; margin-bottom:4px; margin-left:4px; margin-right:4px;"> -<tr> -<td style="border: none;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">OMed </p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Application par Sacha schutz </p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">istdasklar@gmail.com</p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://omedsoft.blogspot.com/"><span style=" text-decoration: underline; color:#0000ff;">http://omedsoft.blogspot.com/</span></a></p></td></tr></table></body></html> - - - - AccountDialog - - - Accounts - Comptes - - - - test - test - - - - Add - Ajouter - - - - Edit - Éditer - - - - Remove - Supprimer - - - - Use - Utiliser - - - - BrowseMainWindow - - - MainWindow - Vlc remote - - - - Play - Lire - - - - Enqueue - Ajouter - - - - Browse - Ouvrir - - - - menu - - - - - User Folder - Utiliser - - - - Home - Dossier d'accueil - - - - Set as Home - Marquer comme dossier d'accueil - - - - Favourites - Favoris - - - - Add to Favourite - Ajouter aux favoris - - - configuration - Configuration - - - About - À propos - - - - Directory could not be browsed! - Le dossier ne peux être listé ! - - - - ConfigDialog - - - Dialog - Configuration - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'DejaVu Sans'; font-size:14pt; font-weight:400; font-style:normal;"> -<table border="0" style="-qt-table-type: root; margin-top:4px; margin-bottom:4px; margin-left:4px; margin-right:4px;"> -<tr> -<td style="border: none;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Enter IP of VLC server. </p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Example : <span style=" font-weight:600;">192.168.0.8:8080</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Be sure you have properly configured Vlc</p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> and allows connection by adding this IP in /vlc/http/.hosts</p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">More information on my blog : <a href="http://omedsoft.blogspot.com/"><span style=" text-decoration: underline; color:#0000ff;">omed.blogspot.com</span></a><br /></p></td></tr></table></body></html> - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'DejaVu Sans'; font-size:14pt; font-weight:400; font-style:normal;"> -<table border="0" style="-qt-table-type: root; margin-top:4px; margin-bottom:4px; margin-left:4px; margin-right:4px;"> -<tr> -<td style="border: none;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Mettre l'ip du Serveur VLC.</p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Exemple : <span style=" font-weight:600;">192.168.0.8:8080</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Vous devez avoir configurer VLC correctement</p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> et autoriser les connexions en ajoutant l'ip de votre N900 dans /vlc/http/.hosts</p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Plus d'informations sur mon blog : <a href="http://omedsoft.blogspot.com/"><span style=" text-decoration: underline; color:#0000ff;">omed.blogspot.com</span></a><br /></p></td></tr></table></body></html> - - - - FavouritesMainWindow - - - MainWindow - Vlc remote - - - - Name - Nom - - - - Save - Sauvegarder - - - - Delete - Supprimer - - - - Edit - Éditer - - - - Browse - Ouvrir - - - - Set as Home - Dossier d'accueil - - - - NewAccountDialog - - - Add account - Ajouter un compte - - - - Name: - Nom : - - - - Ip: - Ip : - - - - Port: - Port : - - - - Edit account - Édition d'un compte - - - - PlayListMainWindow - - MainWindow - Vlc remote - - - - Playlist - Liste de lecture - - - - - - not yet done - fonctions pas encore développée - - - Clear - Vider - - - - Play - Lire - - - - Shuffle - Aléatoire - - - - Loop - Boucler - - - - Repeat - Répéter - - - - Clear all - Vider - - - - Remove - Supprimer - - - - menu - - - - - Portrait Mode - Mode Portrait - - - - Landscape Mode - Mode Paysage - - - configuration - Configuration - - - About - À propos - - - - Playlist could not be retrieved. - Impossible de récupérer la liste de lecture. - - - - PlayerMainWindow - - MainWindow - Vlc remote - - - - Vlc-Remote - Vlc-Remote - - - - - - Information - Information - - - - < - < - - - play - Lire - - - - > - > - - - Pause - Pause - - - play/pause - Lire/Pause - - - - Stop - Stop - - - - FS - FS - - - - V+ - V+ - - - - V- - V- - - - mute - Couper le son - - - - Play/Pause - Lecture/Pause - - - - Mute - Couper le son - - - - PlayList - Liste de lecture - - - - Browse - Ouvrir - - - - menu - - - - - Configuration - Configuration - - - - About - À propos - - - - Portrait Mode - Mode Portrait - - - - Landscape Mode - Mode Paysage - - - - Auto Rotate - À propos de l'orientation - - - diff --git a/vlcstatus.cpp b/vlcstatus.cpp deleted file mode 100644 index 0857f0b..0000000 --- a/vlcstatus.cpp +++ /dev/null @@ -1,18 +0,0 @@ -/* VLC-REMOTE for MAEMO 5 -* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2, -* or (at your option) any later version, as published by the Free -* Software Foundation -* -* 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, write to the -* Free Software Foundation, Inc., -* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -#include "vlcstatus.h" diff --git a/vlcstatus.h b/vlcstatus.h deleted file mode 100644 index 738780a..0000000 --- a/vlcstatus.h +++ /dev/null @@ -1,46 +0,0 @@ -/* VLC-REMOTE for MAEMO 5 -* Copyright (C) 2010 Schutz Sacha , Dru Moore , Yann Nave -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2, -* or (at your option) any later version, as published by the Free -* Software Foundation -* -* 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, write to the -* Free Software Foundation, Inc., -* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -#ifndef VLCSTATUS_H -#define VLCSTATUS_H -#include - -enum VlcStatusState { - UNKNOWN, - STOP, - PLAYING, - PAUSED -}; - -struct VlcStatus { - bool newtrack; - bool random; - bool loop; - bool repeat; - bool hasart; - int volume; - int length; - int time; - int position; - VlcStatusState state; - QString title; - QString artist; - QString album; - QString nowplaying; -}; - -#endif // VLCSTATUS_H diff --git a/welcome b/welcome deleted file mode 100644 index e69de29..0000000 diff --git a/www/index.html b/www/index.html index d1ce30c..8281167 100644 --- a/www/index.html +++ b/www/index.html @@ -57,20 +57,28 @@

Les procèdures sont similaires suivant votre système d'exploitation ( Windows/Linux/Mac OS)

Nous considèrons ici que vous avez déjà installé VLC sur votre ordinateur

Linux

-
    +
    1. Démarrez VLC
    2. Cliquez sur le menu Outils
    3. Cliquez sur Préférences, vous avez une fenêtre similaire à celle ci : - VLC - Outils -Préférences
    4. + VLC - Outils -Préférences
    5. Cliquez sur Tous en bas à gauche de la fenêtre, la colonne de gauche contient maintenant une arboressence de menu
    6. -
    7. Double cliquez sur Interface, puis sur Interfaces Principales - VLC - Outils -Préférences - Interfaces principales http
    8. - +
    9. Double cliquez sur Interface, puis sur Interfaces Principales.
      + Cocher la case Interface de commande à distance HTTP. + VLC - Outils -Préférences - Interfaces principales http
    10. +
    11. + Dans l'arborescence à gauche cliquez sur HTTP en dessous d'Interfaces principales.
      + Cochez la case Exporter la jaquette vers « /art »
      + Cliquez sur Enregistrer pour valider les paramètres et fermer la fenêtre, puis redémarez VLC. + VLC - Outils -Préférences - Interfaces principales http - art +

    Windows

    Mac OS

    + +

    Configurer Vlc-remote sur votre mobile

    Lorsque vous démarez l'application la fenêtre de gestion de compte apparait.
    Elle vous permet d'enregistrer plusieurs machines, ainsi vous pouvez facilement accèder @@ -78,10 +86,8 @@

    Gestionnaire de compte

    - Copite d'écran du gestionnaire de compte - -
      +
      1. Ajouter

        Un compte contient les éléments suivants :

          @@ -107,6 +113,11 @@
        +

        Utiliser

        +

        L'affichage principale permet de controler la vidéo en cours + de lecture, de consulter la playlist et de naviguer dans les + repertoires de l'ordinateur sur leque Vlc est en cours d'éxecution. +

        Retour menu

        4. Licence

        diff --git a/www/styles.css b/www/styles.css index 8886fd8..9c41fe6 100644 --- a/www/styles.css +++ b/www/styles.css @@ -117,4 +117,8 @@ a:hover { text-decoration: underline; } -p { margin-left: 1em; } \ No newline at end of file +p { margin-left: 1em; } + +.instructions img{ + width: 90%; +} \ No newline at end of file -- 1.7.9.5