diff options
author | Noam Rosenthal <nrosenth@nokia.com> | 2009-06-08 12:27:03 -0700 |
---|---|---|
committer | Noam Rosenthal <nrosenth@nokia.com> | 2009-06-08 12:27:03 -0700 |
commit | d0441f605434a89b53735427e4e81182c65debbd (patch) | |
tree | b96d25dc89cdb523c007a22bc0deed3a5aa5dd56 /examples/mediaplayer | |
parent | a6553f68f17c28adca049857686496a69b4c1e7a (diff) |
scxml for 4.6
Diffstat (limited to 'examples/mediaplayer')
-rw-r--r-- | examples/mediaplayer/main.cpp | 58 | ||||
-rw-r--r-- | examples/mediaplayer/mediaplayer.pro | 23 | ||||
-rw-r--r-- | examples/mediaplayer/mediaplayer.qrc | 5 | ||||
-rw-r--r-- | examples/mediaplayer/mediaplayer.scxml | 240 | ||||
-rw-r--r-- | examples/mediaplayer/mediaplayer.ui | 145 | ||||
-rw-r--r-- | examples/mediaplayer/songdata.h | 15 | ||||
-rw-r--r-- | examples/mediaplayer/spengine.cpp | 84 | ||||
-rw-r--r-- | examples/mediaplayer/spengine.h | 41 | ||||
-rw-r--r-- | examples/mediaplayer/spharvester.cpp | 68 | ||||
-rw-r--r-- | examples/mediaplayer/spharvester.h | 25 | ||||
-rw-r--r-- | examples/mediaplayer/spmodel.cpp | 274 | ||||
-rw-r--r-- | examples/mediaplayer/spmodel.h | 64 | ||||
-rw-r--r-- | examples/mediaplayer/spview.cpp | 97 | ||||
-rw-r--r-- | examples/mediaplayer/spview.h | 36 |
14 files changed, 1175 insertions, 0 deletions
diff --git a/examples/mediaplayer/main.cpp b/examples/mediaplayer/main.cpp new file mode 100644 index 0000000..1eb7b4b --- /dev/null +++ b/examples/mediaplayer/main.cpp @@ -0,0 +1,58 @@ +#include "qscriptedstatemachine.h" +#include "spview.h" +#include "spmodel.h" +#include "spengine.h" +#include "spharvester.h" +#include "math.h" +#include "time.h" +#include <QDebug> +#include <QApplication> +#include <QLabel> +#include <QPushButton> +#include <QScriptEngine> +#include <QVBoxLayout> +#include <QHBoxLayout> +#include <QFileInfo> +#include <QScriptContext> +#include <QScriptEngine> +#include <QMenu> +#include <QMainWindow> + + +int main( int argc, char **argv) +{ + QApplication app(argc, argv); + QString dir; + bool recurse; + if (argc > 1) { + dir = QString(argv[1]); + if (argc > 2) + { + recurse = !strcmp(argv[2],"-recurse"); + } + } else { + printf("Usage: stateplayer directory [-recurse]"); + return 0; + } + + app.setApplicationName("SCXML-mediaplayer"); + + SPView* view = new SPView(NULL); + QtScriptedStateMachine *sm = QtScriptedStateMachine::load(":/mediaplayer.scxml"); + QObject::connect (sm, SIGNAL(finished()), &app, SLOT(quit())); + SPModel* model= new SPModel(NULL); + view->setModel(model); + model->setObjectName("model"); + SPEngine* engine = new SPEngine(sm); + engine->setObjectName("engine"); + SPHarvester* harvester = new SPHarvester (view); + QObject::connect (harvester, SIGNAL(foundTrack(SongData)), model, SLOT(addSong(SongData))); + harvester->harvest(dir,recurse); + view->setObjectName("view"); + sm->registerObject(model); + sm->registerObject(engine); + sm->registerObject(view,"",true); + view->show (); + sm->start (); + return app.exec (); +} diff --git a/examples/mediaplayer/mediaplayer.pro b/examples/mediaplayer/mediaplayer.pro new file mode 100644 index 0000000..355da25 --- /dev/null +++ b/examples/mediaplayer/mediaplayer.pro @@ -0,0 +1,23 @@ +TEMPLATE = app +TARGET = scxmlplayer +QT += script \ + sql \ + phonon +include($$PWD/../../src/qtstatemachine.pri) + +HEADERS += spmodel.h \ + spengine.h \ + spview.h \ + spharvester.h \ + songdata.h +SOURCES += main.cpp \ + spmodel.cpp \ + spengine.cpp \ + spview.cpp \ + spharvester.cpp +FORMS += mediaplayer.ui +RESOURCES += mediaplayer.qrc +win32:CONFIG += console +mac:CONFIG -= app_bundle +INCLUDEPATH += . +DEPENDPATH += . diff --git a/examples/mediaplayer/mediaplayer.qrc b/examples/mediaplayer/mediaplayer.qrc new file mode 100644 index 0000000..ff8226f --- /dev/null +++ b/examples/mediaplayer/mediaplayer.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource> + <file>mediaplayer.scxml</file> + </qresource> +</RCC> diff --git a/examples/mediaplayer/mediaplayer.scxml b/examples/mediaplayer/mediaplayer.scxml new file mode 100644 index 0000000..323d9c9 --- /dev/null +++ b/examples/mediaplayer/mediaplayer.scxml @@ -0,0 +1,240 @@ +<scxml xmlns="http://www.w3.org/2005/07/scxml" initial="root"> + <parallel id="root"> + <state initial="gui"> + <invoke targettype="q-bindings"> + <content>[[listView,'styleSheet','QListView {font-size:20px}']]</content> + </invoke> + <state id="gui" initial="menu_tree"> + <transition event="q-signal:backButton.clicked()" anchor="lastmenupos" /> + <transition event="q-signal:homeButton.clicked()" target="mainmenu" /> + <state id="menu_tree" initial="mainmenu"> + <invoke type="q-binding"><content>[[stackedWidget,"currentIndex",0]]</content></invoke> + <state id="mainmenu"> + <anchor type="lastmenupos" /> + <onentry><script> + homeButton.enabled = false; + selectButton.enabled = false; + </script></onentry> + <onexit><script> + homeButton.enabled = true; + selectButton.enabled = true; + </script></onexit> + <invoke type="q-menu"> + <content> + { "parent" : listView, "windowTitle" : + "Music Player", "styleSheet" : "QMenu {font-size:24px; width: 505;height:1000;}" + + "QMenu::item:hover {background-color: blue;color: black;}", + "children": function() { var c = [ + {"type" : "action","id" : "artists", "text" : "Artists" }, + {"type" : "action", "id" : "albums", "text" : "Albums" }, + {"type" : "action", "id" : "genres", "text" : "Genres" }, + {"type" : "action", "id" : "allsongs", "text" : "All Songs" }]; + if (model.currentSongTitle != '') + c[c.length] = {type: "action", id: "curplaying", text: model.currentSongTitle}; + return c; }() + }</content> + </invoke> + <transition event="menu.action.artists" target="artists" /> + <transition event="menu.action.albums" target="albums"> + <script>model.clearAlbumFilter ();</script> + </transition> + <transition event="menu.action.genres" target="genres" /> + <transition event="menu.action.curplaying" target="playingwin" /> + <transition event="menu.action.allsongs" target="songs"> + <script>model.clearSongFilter ();</script> + </transition> + </state> + <state id="artists"> + <anchor type="lastmenupos" /> + <onentry> + <script>model.loadArtists (); view.showArtists();</script> + </onentry> + <transition event="q-signal:model.artistChanged(QString)"> + + <script>model.loadArtists();</script> + </transition> + <transition event="q-signal:selectButton.clicked()" target="albums" cond="view.currentIndex >=0"> + <script> + model.filterAlbumsByArtist(view.currentItem); + </script> + </transition> + </state> + <state id="albums"> + <onentry> + <script>model.loadAlbums ();</script> + </onentry> + <transition cond="model.albumCount==1" target="songs" /> + <transition cond="model.albumCount > 1" target="show_albums" /> + <transition cond="model.albumCount==0" target="songs" /> + </state> + <state id="show_albums"> + <anchor type="lastmenupos" /> + <transition event="q-signal:model.albumChanged(QString)"> + + <script>model.loadAlbums();</script> + </transition> + <transition event="q-signal:selectButton.clicked()" cond="view.currentIndex >=0" target="songs"> + <script> + model.filterSongsByAlbum(view.currentItem);</script> + </transition> + <onentry> + <script>view.showAlbums ();</script> + </onentry> + </state> + <state id="genres"> + <anchor type="lastmenupos" /> + <onentry> + <script>model.loadGenres (); view.showGenres + ();</script> + </onentry> + <transition event="q-signal:model.genreChanged(QString)"> + + <script>model.loadGenres();</script> + </transition> + <transition event="q-signal:selectButton.clicked()" cond="view.currentIndex >=0" target="songs"> + <script> + model.filterSongsByGenre(view.currentItem);</script> + </transition> + </state> + <state id="songs"> + <anchor type="lastmenupos" /> + <onentry> + <script>model.loadSongs (); view.showSongs + ();</script> + </onentry> + <transition event="q-signal:model.songListChanged()"> + <script>model.loadSongs();</script> + </transition> + <transition event="q-signal:selectButton.clicked()" cond="view.currentIndex >=0" target="playingwin"> + <script> + model.selectSong (view.currentItem); + engine.setTrack(model.currentSong); + </script> + <raise event="playIntent" /> + <raise event="songSelected" /> + </transition> + </state> + </state> + <state id="playingwin"> + <anchor type="lastmenupos" /> + <invoke type="q-bindings"> + <content>[ + [selectButton,"enabled",false], + [playingLabel,"text",model.currentSongTitle], + [midLabel,"text",model.currentSongArtist], + [posSlider,"minimum",0], + [posSlider,"maximum",engine.totalTime], + [stackedWidget,"currentIndex",1] + ]</content> + </invoke> + <onentry> + <script>view.showPlayer ();</script> + </onentry> + <transition event="q-signal:model.songChanged()"> + <script> + midLabel.text = model.currentSongArtist + ' / ' + model.currentSongAlbum; + playingLabel.text = model.currentSongTitle; + </script> + </transition> + </state> + </state> + </state> + <state id="engine" initial="idle"> + <onentry><script> + volumeSlider.value = engine.volume; + </script></onentry> + + <transition event="q-signal:model.songChanged()"> + <script>engine.setTrack(model.currentSong);</script> + <raise event="playIntent" /> + <raise event="songChanged" /> + </transition> + <state id="idle"> + <transition event="playIntent" target="playing" /> + <transition event="q-signal:playButton.clicked()"> + <raise event="playIntent" /> + </transition> + <invoke type="q-bindings"> + <content>[[stopButton,"enabled",false]]</content> + </invoke> + </state> + <state id="active" initial="playing"> + <invoke type="q-bindings"> + <content>[[stopButton,"enabled",true]]</content> + </invoke> + <transition event="q-signal:stopButton.clicked()" + target="idle"> + <script>engine.stop ();</script> + </transition> + <state id="playing"> + <invoke type="q-bindings"> + <content>[[playButton,"text","Pause"]]</content> + </invoke> + <onentry> + <script>engine.play ();</script> + </onentry> + <transition event="q-signal:playButton.clicked()" + target="paused" /> + <transition event="songChanged"> + <script>engine.play();</script> + </transition> + <transition event="q-signal:engine.tick(qint64)"> + <script>view.setCurrentTime(_event.data[0]);</script> + </transition> + <transition event="q-signal:engine.totalTimeChanged(qint64)"> + <script>view.setTotalTime(_event.data[0]);</script> + </transition> + </state> + <state id="paused"> + <onentry> + <script>engine.pause();</script> + </onentry> + <transition event="q-signal:playButton.clicked()" + target="playing" /> + </state> + <transition event="q-signal:model.endOfList()" + target="idle"> + <script>engine.stop (); model.reset ();</script> + </transition> + </state> + <transition event="q-signal:engine.aboutToFinish()"> + <raise event="nextSong" /> + </transition> + <transition event="nextSong"> + <script> + model.next(); + engine.enqueue(model.currentSong); + </script> + </transition> + <transition event="q-signal:nextButton.clicked()"> + <script>model.gotoNext();</script> + </transition> + <transition event="q-signal:prevButton.clicked()"> + <script>model.gotoPrev();</script> + </transition> + <transition event="q-signal:posSlider.sliderMoved(int)"> + <script>engine.seek(_event.data[0]);</script> + </transition> + <transition event="q-signal:volumeSlider.sliderMoved(int)"> + <script>engine.volume = _event.data[0];</script> + </transition> + <transition event="q-signal:engine.volumeChanged(int)"> + <script>volumeSlider.value = _event.data[0];</script> + </transition> + </state> + <state id="selection_state" initial="no_song_selected"> + <state id="no_song_selected"> + <transition event="songSelected" target="song_selected" /> + <invoke type="q-bindings"> + <content>[[stopButton,"enabled",false], + [playButton,"enabled",false], + [prevButton,"enabled",false], + [nextButton,"enabled",false]]</content> + </invoke> + </state> + <state id="song_selected"> + <transition event="endOfList" target="no_song_selected" /> + </state> + </state> + </parallel> +</scxml> diff --git a/examples/mediaplayer/mediaplayer.ui b/examples/mediaplayer/mediaplayer.ui new file mode 100644 index 0000000..dbbc6fd --- /dev/null +++ b/examples/mediaplayer/mediaplayer.ui @@ -0,0 +1,145 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>mediaPlayerWidget</class> + <widget class="QWidget" name="mediaPlayerWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>394</width> + <height>287</height> + </rect> + </property> + <property name="windowTitle"> + <string>SCXML Media Player</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QStackedWidget" name="stackedWidget"> + <property name="currentIndex"> + <number>0</number> + </property> + <widget class="QWidget" name="page"> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QListView" name="listView"/> + </item> + </layout> + </widget> + <widget class="QWidget" name="playerPage"> + <widget class="QLabel" name="playingLabel"> + <property name="geometry"> + <rect> + <x>0</x> + <y>50</y> + <width>291</width> + <height>61</height> + </rect> + </property> + <property name="styleSheet"> + <string>QLabel {font-size: 24px; color: #336699}</string> + </property> + <property name="text"> + <string>TextLabel</string> + </property> + </widget> + <widget class="QLabel" name="midLabel"> + <property name="geometry"> + <rect> + <x>0</x> + <y>120</y> + <width>291</width> + <height>21</height> + </rect> + </property> + <property name="text"> + <string>TextLabel</string> + </property> + </widget> + <widget class="QSlider" name="posSlider"> + <property name="geometry"> + <rect> + <x>0</x> + <y>180</y> + <width>301</width> + <height>16</height> + </rect> + </property> + <property name="maximum"> + <number>0</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </widget> + </widget> + </item> + <item> + <widget class="QWidget" name="widget1" native="true"> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QToolButton" name="homeButton"> + <property name="text"> + <string>Home</string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="playButton"> + <property name="text"> + <string>Play</string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="prevButton"> + <property name="text"> + <string>Prev</string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="nextButton"> + <property name="text"> + <string>Next</string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="stopButton"> + <property name="text"> + <string>Stop</string> + </property> + </widget> + </item> + <item> + <widget class="QSlider" name="volumeSlider"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="selectButton"> + <property name="text"> + <string>Select</string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="backButton"> + <property name="text"> + <string>Back</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <layoutdefault spacing="6" margin="11"/> + <resources/> + <connections/> +</ui> diff --git a/examples/mediaplayer/songdata.h b/examples/mediaplayer/songdata.h new file mode 100644 index 0000000..0c31f03 --- /dev/null +++ b/examples/mediaplayer/songdata.h @@ -0,0 +1,15 @@ +#ifndef SONGDATA_H +#define SONGDATA_H + +#include <QStringList> + +struct SongData +{ + QString url; + QString title; + QString album; + QString artist; + QStringList genres; + int trackNumber; +}; +#endif diff --git a/examples/mediaplayer/spengine.cpp b/examples/mediaplayer/spengine.cpp new file mode 100644 index 0000000..9d8132f --- /dev/null +++ b/examples/mediaplayer/spengine.cpp @@ -0,0 +1,84 @@ +#include "spengine.h" +#include <phonon> + +using namespace Phonon; + +class SPEnginePvt +{ + public: + MediaObject* mediaObject; + AudioOutput* audioOutput; +}; +void SPEngine::clearQueue() +{ + pvt->mediaObject->clearQueue(); +} + +int SPEngine::currentTime() const +{ + return pvt->mediaObject->currentTime (); +} +int SPEngine::totalTime() const +{ + return pvt->mediaObject->totalTime(); +} + +void SPEngine::enqueue (const QUrl & u) +{ + pvt->mediaObject->enqueue(MediaSource(u)); +} +void SPEngine::setTrack(const QUrl & u) +{ + pvt->mediaObject->setCurrentSource(MediaSource(u)); +} +void SPEngine::play() +{ + pvt->mediaObject->play (); +} + +void SPEngine::pause() +{ + pvt->mediaObject->pause (); +} + +void SPEngine::stop() +{ + pvt->mediaObject->stop(); +} + +void SPEngine::seek(qint64 pos) +{ + pvt->mediaObject->seek(pos); +} + +void SPEngine::setVolume(int v) +{ + pvt->audioOutput->setVolume((qreal)v/100); +} + +void SPEngine::onVolumeChanged(qreal r) +{ + emit volumeChanged(r*100); +} +int SPEngine::volume() const +{ + return pvt->audioOutput->volume()*100; +} + +SPEngine::SPEngine(QObject* p) : QObject(p) +{ + pvt = new SPEnginePvt; + pvt->mediaObject = new Phonon::MediaObject(this); + pvt->audioOutput = new Phonon::AudioOutput(Phonon::MusicCategory, this); + createPath (pvt->mediaObject, pvt->audioOutput); + pvt->mediaObject->setTickInterval(500); + connect (pvt->mediaObject, SIGNAL(aboutToFinish()), this, SIGNAL(aboutToFinish())); + connect (pvt->mediaObject, SIGNAL(tick(qint64)), this, SIGNAL(tick(qint64))); + connect (pvt->mediaObject, SIGNAL(totalTimeChanged(qint64)), this, SIGNAL(totalTimeChanged(qint64))); + connect (pvt->audioOutput, SIGNAL(volumeChanged(qreal)), this, SLOT(onVolumeChanged(qreal))); +} + +SPEngine::~SPEngine () +{ + delete pvt; +} diff --git a/examples/mediaplayer/spengine.h b/examples/mediaplayer/spengine.h new file mode 100644 index 0000000..3134b75 --- /dev/null +++ b/examples/mediaplayer/spengine.h @@ -0,0 +1,41 @@ +#ifndef SPENGINE_H +#define SPENGINE_H +#include <QObject> +#include <QUrl> +class SPEngine : public QObject +{ + Q_OBJECT + Q_PROPERTY(int totalTime READ totalTime) + Q_PROPERTY(int currentTime READ currentTime) + Q_PROPERTY(int volume READ volume WRITE setVolume) + + Q_SIGNALS: + void aboutToFinish(); + void tick(qint64); + void totalTimeChanged(qint64); + void volumeChanged(int); + + public Q_SLOTS: + void clearQueue(); + void enqueue (const QUrl &); + void setTrack(const QUrl &); + void play(); + void pause(); + void seek(qint64); + void stop (); + + protected Q_SLOTS: + void onVolumeChanged(qreal); + + public: + SPEngine(QObject*); + virtual ~SPEngine (); + int currentTime () const; + int totalTime () const; + void setVolume(int); + int volume () const; + + private: + class SPEnginePvt* pvt; +}; +#endif diff --git a/examples/mediaplayer/spharvester.cpp b/examples/mediaplayer/spharvester.cpp new file mode 100644 index 0000000..ee6294f --- /dev/null +++ b/examples/mediaplayer/spharvester.cpp @@ -0,0 +1,68 @@ +#include "spharvester.h" +#include <QDir> +#include <phonon> +#include <QQueue> +#include <QFile> +#include <QUrl> + +using namespace Phonon; + +struct SPHarvesterPvt +{ + MediaObject* mediaObject; + QQueue<QString> pathQueue; +}; + +SPHarvester::SPHarvester(QObject* o) : QObject(o) +{ + pvt = new SPHarvesterPvt; + pvt->mediaObject = new MediaObject(this); + connect (pvt->mediaObject, SIGNAL(metaDataChanged()), this, SLOT(readMetaData ())); +} + +SPHarvester::~SPHarvester() +{ + delete pvt; +} + +void SPHarvester::harvest (const QString & directory, bool recurse) +{ + QDir d (directory); + QFileInfoList l = d.entryInfoList(QStringList() << "*.mp3",recurse ? QDir::AllDirs | QDir::NoDotAndDotDot | QDir::Files : QDir::Files); + foreach (QFileInfo fi, l) { + if (fi.isDir()) { + harvest (fi.absoluteFilePath(), recurse); + } else { + pvt->pathQueue.enqueue(fi.absoluteFilePath()); + } + } + harvestNext (); +} + +void SPHarvester::harvestNext () +{ + if (pvt->pathQueue.empty()) + emit done(); + else { + QString s = pvt->pathQueue.dequeue(); + pvt->mediaObject->setCurrentSource(MediaSource(s)); + } +} + +void SPHarvester::readMetaData () +{ + QStringList albums = pvt->mediaObject->metaData("ALBUM"); + QStringList titles = pvt->mediaObject->metaData("TITLE"); + QStringList artists = pvt->mediaObject->metaData("ARTIST"); + QStringList trackNums = pvt->mediaObject->metaData("TRACKNUMBER"); + SongData sd; + sd.url = pvt->mediaObject->currentSource().url().toString(); + sd.album = albums.count() ? albums[0] : "Unknown Album"; + sd.artist = artists.count() ? artists[0] : "Unknown Artist"; + sd.trackNumber = trackNums.count() ? trackNums[0].toInt() : 0; + sd.genres = pvt->mediaObject->metaData("GENRE"); + sd.title = titles.count() ? titles[0] : QFileInfo(sd.url).baseName(); + + emit foundTrack(sd); + harvestNext (); +} diff --git a/examples/mediaplayer/spharvester.h b/examples/mediaplayer/spharvester.h new file mode 100644 index 0000000..8fbe583 --- /dev/null +++ b/examples/mediaplayer/spharvester.h @@ -0,0 +1,25 @@ +#ifndef SPHARVESTER_H +#define SPHARVESTER_H + +#include "songdata.h" +class SPHarvester : public QObject +{ + Q_OBJECT +public: + SPHarvester(QObject* o = NULL); + virtual ~SPHarvester (); +public slots: + void harvest (const QString & directory, bool recurse = true); + +private slots: + void harvestNext (); + void readMetaData(); +signals: + void foundTrack (const SongData & d); + void done (); + +private: + class SPHarvesterPvt* pvt; +}; + +#endif // _H diff --git a/examples/mediaplayer/spmodel.cpp b/examples/mediaplayer/spmodel.cpp new file mode 100644 index 0000000..46e614d --- /dev/null +++ b/examples/mediaplayer/spmodel.cpp @@ -0,0 +1,274 @@ +#include "spmodel.h" +#include <QSqlQueryModel> +#include <QtSql> +#include <QStandardItemModel> +#include <QMessageBox> +// an SQL query model that always as column (0) as uid and column (1) as display +class SPSqlQueryModel : public QSqlQueryModel +{ + Q_OBJECT + public: + SPSqlQueryModel (QObject* o = NULL): QSqlQueryModel (o) {} + virtual QVariant data(const QModelIndex & index, int role) const + { + QModelIndex idx(index); + if (role == Qt::DisplayRole && query().record().count() > 1) { + idx = idx.sibling(idx.row(),1); + } else if (role == Qt::UserRole) + role = Qt::DisplayRole; + return QSqlQueryModel::data(idx,role); + } +}; + + +class SPModelPvt +{ + public: + SPSqlQueryModel + artistModel, + albumModel, + songModel, + playlistModel, genreModel; + + QSqlQuery artistQuery, albumQuery, songQuery, playlistQuery, genreQuery, playingQuery; + +}; + +SPModel::SPModel(QObject* o) + :QObject(o) +{ + QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); + db.setDatabaseName("sqlite.db"); + if (!db.open()) { + QMessageBox::critical(0, qApp->tr("Cannot open database"), + qApp->tr("Unable to establish a database connection.\n" + "This example needs SQLite support. Please read " + "the Qt SQL driver documentation for information how " + "to build it.\n\n" + "Click Cancel to exit."), QMessageBox::Cancel); + } + + db.exec("CREATE TABLE IF NOT EXISTS songs (song_url VARCHAR(1024) PRIMARY KEY, song_title VARCHAR(1024), song_artist VARCHAR(1024), song_album VARCHAR(1024), song_track_index SMALLINT)"); + db.exec("DROP TABLE genres"); + db.exec("CREATE TABLE IF NOT EXISTS genres (genre_title VARCHAR(64), genre_song_url VARCHAR(1024))"); +// db.exec("CREATE TABLE IF NOT EXISTS playlists (playlist_id VARACHAR(256) PRIMARY KEY, playlist_title VARCHAR(1024))"); +// db.exec("CREATE TABLE IF NOT EXISTS playlist_songs (playlist_song_id BIGINT PRIMARY KEY, playlist_song_playlist + + pvt = new SPModelPvt; + pvt->artistQuery = QSqlQuery("SELECT DISTINCT song_artist FROM songs"); + pvt->albumQuery = QSqlQuery("SELECT DISTINCT song_album FROM songs"); + pvt->playlistQuery = QSqlQuery("SELECT playlist_url, playlist_title FROM playlists"); + pvt->songQuery = QSqlQuery("SELECT song_url, song_title from songs"); + pvt->genreQuery = QSqlQuery("SELECT DISTINCT genre_title from genres"); + QSqlQuery q; +// q.exec("SELECT DISTINCT song_url,song_title FROM songs, genres WHERE genre_song_url=song_url AND genre_title='All'"); + q.exec("SELECT * from genres"); + while (q.next()) { + qDebug () << q.value(0); + } +} + +void SPModel::addSong ( const SongData & data) +{ + + QSqlQuery q; + q.prepare("SELECT count(*) FROM songs WHERE song_url=:url"); + q.bindValue(":url",data.url); + bool inserting = true; + if (q.exec()) { + q.next(); + inserting = q.value(0).toInt() == 0; + } + if (inserting) { + q.prepare ("INSERT INTO songs (song_url, song_title, song_artist, song_album, song_track_index) VALUES (:url, :title, :artist, :album, :track)"); + } else { + q.prepare("UPDATE songs SET song_title=:title, song_album=:album, song_track_index=:track WHERE song_url=:url "); + } + q.bindValue(":url",data.url); + q.bindValue(":title",data.title); + q.bindValue(":artist",data.artist); + q.bindValue(":album",data.album); + q.bindValue(":track",data.trackNumber); + q.exec(); + + q.prepare ("DELETE FROM genres WHERE genre_song_url=:url"); + q.bindValue(":url",data.url); + q.exec(); + + q.prepare ("INSERT INTO genres (genre_song_url, genre_title) VALUES(:url, :genre)"); + q.bindValue(":url",data.url); + QStringList gn = data.genres; + gn << "All"; + foreach (QString g, gn) { + q.bindValue(":genre",g); + q.exec (); + } + + if (inserting) { + emit albumChanged(data.album); + emit songListChanged(); + emit artistChanged(data.artist); + foreach (QString g, data.genres) { + emit genreChanged(g); + } + } + + +} + + +SPModel::~SPModel() +{ + delete pvt; +} + +int SPModel::albumCount() const +{ + return pvt->albumModel.rowCount(); +} + +void SPModel::clearAlbumFilter () +{ + pvt->albumQuery = QSqlQuery ("SELECT DISTINCT song_album FROM songs "); +} +void SPModel::clearSongFilter () +{ + pvt->songQuery = QSqlQuery ("SELECT song_url, song_title FROM songs"); +} +void SPModel::loadArtists () +{ + pvt->artistQuery.exec (); + pvt->artistModel.setQuery(pvt->artistQuery); +} +void SPModel::filterAlbumsByArtist(const QString & artist) +{ + pvt->albumQuery.prepare("SELECT DISTINCT song_album FROM songs WHERE song_artist=:artist"); + pvt->albumQuery.bindValue(":artist",artist); +} +void SPModel::filterSongsByAlbum(const QString & album) +{ + pvt->albumQuery.prepare("SELECT song_url,song_title, song_track_index FROM songs WHERE song_album=:album ORDER BY song_track_index"); + pvt->albumQuery.bindValue(":album",album); +} +void SPModel::loadGenres () +{ + pvt->genreQuery.exec(); + pvt->genreModel.setQuery(pvt->genreQuery); +} + +void SPModel::filterSongsByGenre(const QString & genre) +{ + pvt->songQuery.prepare ("SELECT DISTINCT song_url,song_title FROM songs, genres WHERE genre_song_url=song_url AND genre_title=:genre"); + pvt->songQuery.bindValue(":genre",genre); +} +void SPModel::loadPlaylists() +{ + pvt->playlistQuery.exec (); + pvt->playlistModel.setQuery(pvt->playlistQuery); +} +void SPModel::loadAlbums() +{ + pvt->albumQuery.exec (); + pvt->albumModel.setQuery(pvt->albumQuery); +} +void SPModel::filterSongsByPlaylist(const QString & uid) +{ + pvt->songQuery.prepare("SELECT DISTINCT song_url, song_title, playlist_song_index FROM playlist_songs INNER JOIN songs ON playlist_song_url=song_url WHERE playlist_id=:playlist ORDER BY playlist_song_index"); + pvt->songQuery.bindValue(":playlist",uid); +} +void SPModel::loadSongs () +{ + pvt->songQuery.exec (); + pvt->songModel.setQuery(pvt->songQuery); +} +QUrl SPModel::currentSong() +{ + if (pvt->playingQuery.isValid()) + return QUrl(pvt->playingQuery.value(0).toString()); + else + return QUrl(); +} +QString SPModel::currentSongTitle() +{ + if (pvt->playingQuery.isValid()) + return pvt->playingQuery.value(1).toString(); + else + return QString(); +} +QString SPModel::currentSongArtist() +{ + QSqlQuery q; + q.prepare("SELECT song_artist FROM songs WHERE song_url=:url"); + q.bindValue(":url",currentSong().toString()); + q.exec(); + q.next(); + return q.value(0).toString(); +} +QString SPModel::currentSongAlbum() +{ + QSqlQuery q; + q.prepare("SELECT song_album FROM songs WHERE song_url=:url"); + q.bindValue(":url",currentSong().toString()); + q.exec(); + q.next(); + return q.value(0).toString(); +} + +void SPModel::selectSong (const QString & s) +{ + pvt->playingQuery = QSqlQuery(pvt->songQuery.executedQuery ()); + + while (pvt->playingQuery.next()) { + if (pvt->playingQuery.value(0).toString() == s) { + emit songChanged (); + return; + } + } + emit endOfList (); +} + +void SPModel::reset () +{ + pvt->playingQuery = QSqlQuery(pvt->songQuery.executedQuery ()); + pvt->playingQuery.exec(); +} + +void SPModel::gotoNext() +{ + if (pvt->playingQuery.next()) { + emit songChanged (); + }else + emit endOfList (); +} +void SPModel::gotoPrev() +{ + if (pvt->playingQuery.previous()) + emit songChanged (); + else + emit endOfList (); +} + + + +QAbstractItemModel* SPModel::albumsItemModel() const +{ + return &pvt->albumModel; +} +QAbstractItemModel* SPModel::genresItemModel() const +{ + return &pvt->genreModel; +} +QAbstractItemModel* SPModel::songsItemModel() const +{ + return &pvt->songModel; +} +QAbstractItemModel* SPModel::playlistsItemModel() const +{ + return &pvt->playlistModel; +} +QAbstractItemModel* SPModel::artistsItemModel() const +{ + return &pvt->artistModel; +} + +#include <spmodel.moc> diff --git a/examples/mediaplayer/spmodel.h b/examples/mediaplayer/spmodel.h new file mode 100644 index 0000000..af8254b --- /dev/null +++ b/examples/mediaplayer/spmodel.h @@ -0,0 +1,64 @@ +#ifndef SPMODEL_H +#define SPMODEL_H +#include <QObject> +#include <QUrl> +#include <QAbstractItemModel> +#include "songdata.h" + +class SPModel : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QUrl currentSong READ currentSong) + Q_PROPERTY(QString currentSongTitle READ currentSongTitle) + Q_PROPERTY(QString currentSongArtist READ currentSongArtist) + Q_PROPERTY(QString currentSongAlbum READ currentSongAlbum) + Q_PROPERTY(int albumCount READ albumCount) + + + public slots: + void clearAlbumFilter (); + void clearSongFilter (); + void loadArtists (); + void filterAlbumsByArtist(const QString & name); + void loadGenres (); + void filterSongsByGenre(const QString & genre); + void loadPlaylists(); + void loadAlbums(); + void filterSongsByPlaylist(const QString & uid); + void filterSongsByAlbum(const QString & name); + void loadSongs (); + void selectSong (const QString &); + void gotoNext(); + void gotoPrev(); + void addSong (const SongData &); + void reset (); + + signals: + void albumChanged(const QString &); + void artistChanged(const QString &); + void genreChanged(const QString &); + void songListChanged(); + void songChanged (); + void endOfList (); + + public: + SPModel(QObject*); + virtual ~SPModel (); + + QUrl currentSong(); + QString currentSongTitle (); + QString currentSongArtist(); + QString currentSongAlbum(); + QAbstractItemModel* albumsItemModel() const; + QAbstractItemModel* genresItemModel() const; + QAbstractItemModel* songsItemModel() const; + QAbstractItemModel* playlistsItemModel() const; + QAbstractItemModel* artistsItemModel() const; + int albumCount() const; + + private: + class SPModelPvt* pvt; +}; + +#endif diff --git a/examples/mediaplayer/spview.cpp b/examples/mediaplayer/spview.cpp new file mode 100644 index 0000000..1d52053 --- /dev/null +++ b/examples/mediaplayer/spview.cpp @@ -0,0 +1,97 @@ +#include "spview.h" +#include "spmodel.h" +#include <QDebug> +#include <QItemDelegate> + +class SPViewPvt +{ + public: + SPModel* model; +}; + + +class SPItemDelegate : public QItemDelegate +{ + Q_OBJECT + +public: + SPItemDelegate(QObject* o) : QItemDelegate(o) {} + + virtual void paint (QPainter* p, QStyleOptionViewItem & option, const QModelIndex & index) const + { + QString disp = index.data(Qt::DisplayRole).toString(); + drawBackground(p,option,index); + drawDisplay(p,option,option.rect,disp); + } +}; + +void SPView::setModel (SPModel* m) +{ + pvt->model = m; +} + +void SPView::showAlbums () +{ + listView->setModel (pvt->model->albumsItemModel()); +} + +void SPView::showArtists () +{ + listView->setModel (pvt->model->artistsItemModel()); +} + +void SPView::showGenres () +{ + QAbstractItemModel* model = pvt->model->genresItemModel(); + listView->setModel (model); +} + +void SPView::showSongs () +{ + listView->setModel (pvt->model->songsItemModel()); +} + +void SPView::showPlaylists() +{ + listView->setModel (pvt->model->playlistsItemModel()); +} + + +SPView::SPView(QWidget* w) : QWidget (w) +{ + pvt = new SPViewPvt; + setupUi(this); + listView->setItemDelegate(new SPItemDelegate(this)); +} + +QString SPView::currentItem() const +{ + QVariant v = listView->model()->data(listView->currentIndex(),Qt::UserRole); + if (v.isNull()) + v = listView->currentIndex().data(Qt::DisplayRole); + return v.toString (); +} + +int SPView::itemCount () const +{ + return listView->model()->rowCount (); +} +int SPView::currentIndex() const +{ + return listView->currentIndex().row(); +} + +void SPView::setTotalTime (int t) +{ + posSlider->setMaximum(t); +} +void SPView::setCurrentTime (int t) +{ + posSlider->setValue (t); +} + +SPView::~SPView () +{ + delete pvt; +} +#include "spview.moc" diff --git a/examples/mediaplayer/spview.h b/examples/mediaplayer/spview.h new file mode 100644 index 0000000..53b8c09 --- /dev/null +++ b/examples/mediaplayer/spview.h @@ -0,0 +1,36 @@ +#ifndef SPVIEW_H +#define SPVIEW_H +#include <QObject> +#include <QUrl> +#include "spmodel.h" +#include "ui_mediaplayer.h" + +class SPView : public QWidget, public virtual Ui::mediaPlayerWidget +{ + Q_OBJECT + Q_PROPERTY(QString currentItem READ currentItem) + Q_PROPERTY(int itemCount READ itemCount) + Q_PROPERTY(int currentIndex READ currentIndex) + public slots: + void setModel (SPModel*); + void showAlbums (); + void showArtists (); + void showGenres (); + void showSongs (); + void showPlaylists(); + void setTotalTime (int); + void setCurrentTime (int); + + + public: + SPView(QWidget*); + virtual ~SPView (); + QString currentItem () const; + int itemCount () const; + int currentIndex() const; + + private: + class SPViewPvt* pvt; +}; + +#endif |