[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [plasma-mediacenter] /: Make playlist model aware of currently playing media
From:       Shantanu Tushar <shantanu () kde ! org>
Date:       2014-03-01 7:07:06
Message-ID: E1WJe0o-0008Di-KK () scm ! kde ! org
[Download RAW message or body]

Git commit 93a7fd6b58371b81c3a3b30c7829c8bcfbc6d498 by Shantanu Tushar.
Committed on 17/02/2014 at 15:03.
Pushed by shantanu into branch 'master'.

Make playlist model aware of currently playing media

REVIEW: 115764

M  +5    -10   libs/mediacenter/multipleplaylistmodel.cpp
M  +5    -3    libs/mediacenter/multipleplaylistmodel.h
M  +63   -26   libs/mediacenter/playlistmodel.cpp
M  +9    -4    libs/mediacenter/playlistmodel.h
M  +2    -32   mediaelements/playlist/MultiplePlaylists.qml
M  +23   -10   mediaelements/playlist/Playlist.qml
M  +5    -3    mediaelements/playlist/PlaylistDelegate.qml
M  +1    -3    shells/newshell/application.cpp
M  +5    -43   shells/newshell/mainwindow.cpp
M  +0    -1    shells/newshell/mainwindow.h
M  +0    -2    shells/newshell/package/contents/ui/mediacenter.qml

http://commits.kde.org/plasma-mediacenter/93a7fd6b58371b81c3a3b30c7829c8bcfbc6d498

diff --git a/libs/mediacenter/multipleplaylistmodel.cpp \
b/libs/mediacenter/multipleplaylistmodel.cpp index f2c9246..be3ac70 100644
--- a/libs/mediacenter/multipleplaylistmodel.cpp
+++ b/libs/mediacenter/multipleplaylistmodel.cpp
@@ -77,7 +77,7 @@ void MultiplePlaylistModel::setPlaylistModelAddress(QObject* model)
     }
 }
 
-QObject* MultiplePlaylistModel::playlistModelAddress()
+QObject* MultiplePlaylistModel::playlistModelAddress() const
 {
     return m_playlistModel;
 }
@@ -86,6 +86,7 @@ void MultiplePlaylistModel::switchToPlaylist(const QString &name)
 {
     if (!name.isEmpty()) {
         m_playlistModel->setPlaylistName(name);
+        emit currentIndexChanged();
     }
 }
 
@@ -117,14 +118,8 @@ void MultiplePlaylistModel::removeCurrentPlaylist()
     endResetModel();
 }
 
-bool MultiplePlaylistModel::checkCmdLineStat()
+int MultiplePlaylistModel::currentIndex() const
 {
-    PlaylistModel *p = dynamic_cast<PlaylistModel*> (playlistModelAddress());
-    return p->getCmdLineURL();
-}
-
-void MultiplePlaylistModel::setCmdLineStat(bool val)
-{
-    PlaylistModel *p = dynamic_cast<PlaylistModel*> (playlistModelAddress());
-    p->setCmdLineURL(val);
+    PlaylistModel *p = qobject_cast<PlaylistModel*> (playlistModelAddress());
+    return m_multiplePlaylistList.indexOf(p->playlistName());
 }
diff --git a/libs/mediacenter/multipleplaylistmodel.h \
b/libs/mediacenter/multipleplaylistmodel.h index 06b64df..1c7731b 100644
--- a/libs/mediacenter/multipleplaylistmodel.h
+++ b/libs/mediacenter/multipleplaylistmodel.h
@@ -30,6 +30,7 @@ class MEDIACENTER_EXPORT MultiplePlaylistModel : public \
QAbstractListModel  {
     Q_OBJECT
     Q_PROPERTY(QObject* playlistModelAddress READ playlistModelAddress WRITE \
setPlaylistModelAddress NOTIFY playlistModelAddressChanged) +    Q_PROPERTY(int \
currentIndex READ currentIndex NOTIFY currentIndexChanged)  
 public:
     explicit MultiplePlaylistModel(QObject* parent = 0);
@@ -38,16 +39,17 @@ public:
     virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) \
                const;
     virtual int rowCount(const QModelIndex& parent = QModelIndex()) const;
 
-    QObject *playlistModelAddress();
+    QObject *playlistModelAddress() const;
     Q_INVOKABLE void createNewPlaylist(const QString &name);
     void setPlaylistModelAddress (QObject *model);
     Q_INVOKABLE void switchToPlaylist (const QString& name);
     Q_INVOKABLE void removeCurrentPlaylist ();
-    Q_INVOKABLE bool checkCmdLineStat();
-    Q_INVOKABLE void setCmdLineStat(bool val);
+
+    int currentIndex() const;
 
 signals:
     void playlistModelAddressChanged();
+    void currentIndexChanged();
 
 private:
     QStringList m_multiplePlaylistList;
diff --git a/libs/mediacenter/playlistmodel.cpp b/libs/mediacenter/playlistmodel.cpp
index 9c1dea9..5d62a71 100644
--- a/libs/mediacenter/playlistmodel.cpp
+++ b/libs/mediacenter/playlistmodel.cpp
@@ -21,12 +21,18 @@
 #include <KDebug>
 #include <KDE/KStandardDirs>
 #include <KDE/KCmdLineArgs>
+#include <KUrl>
 
 #include <QtCore/QDir>
 #include <QtCore/QStringList>
 #include <QtCore/QDateTime>
 #include <QtCore/QCoreApplication>
 #include <QtXml/QDomDocument>
+#include <QApplication>
+
+namespace {
+    static const char DEFAULT_PLAYLIST_NAME[] = "Default";
+}
 
 class PlaylistModel::Private
 {
@@ -44,7 +50,7 @@ PlaylistModel::PlaylistModel(QObject* parent):
     QAbstractListModel(parent),
     d(new Private)
 {
-    d->playlistName = "Default";
+    d->playlistName = DEFAULT_PLAYLIST_NAME;
     loadFromFile(playlistFilePath());
 
     d->currentIndex = -1;
@@ -59,6 +65,8 @@ PlaylistModel::PlaylistModel(QObject* parent):
     qsrand(QDateTime::currentMSecsSinceEpoch());
 
     connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), \
SLOT(savePlaylist())); +
+    connect(this, SIGNAL(currentIndexChanged()), SIGNAL(currentUrlChanged()));
 }
 
 PlaylistModel::~PlaylistModel()
@@ -68,6 +76,10 @@ PlaylistModel::~PlaylistModel()
 
 QVariant PlaylistModel::data(const QModelIndex& index, int role) const
 {
+    if (index.row() < 0 || index.row() >= rowCount()) {
+        return QVariant();
+    }
+
     switch(role) {
     case Qt::DisplayRole:
         return d->musicList.at(index.row())->mediaName();
@@ -85,19 +97,30 @@ QVariant PlaylistModel::data(const QModelIndex& index, int role) \
const  
 int PlaylistModel::rowCount(const QModelIndex& parent) const
 {
-    return d->musicList.count();
+    return d->musicList.size();
 }
 
-void PlaylistModel::addToPlaylist(const QString& url)
+int PlaylistModel::addToPlaylist(const QStringList& urls)
 {
     const int n = rowCount();
-    beginInsertRows(QModelIndex(), n, n);
+    if (urls.isEmpty()) return n-1;
+
+    beginInsertRows(QModelIndex(), n, n+urls.size());
 
-    PlaylistItem *item = new PlaylistItem(url, this);
-    connect(item, SIGNAL(updated()), SLOT(playlistItemUpdated()));
-    d->musicList.append(item);
+    Q_FOREACH(const QString &url, urls) {
+        PlaylistItem *item = new PlaylistItem(url, this);
+        connect(item, SIGNAL(updated()), SLOT(playlistItemUpdated()));
+        d->musicList.append(item);
+    }
 
     endInsertRows();
+
+    return n;
+}
+
+void PlaylistModel::addToPlaylist(const QString& url)
+{
+    addToPlaylist(QStringList() << url);
 }
 
 void PlaylistModel::removeFromPlaylist(const int& index)
@@ -189,7 +212,6 @@ void PlaylistModel::shuffle()
     setCurrentIndex(0);
 }
 
-
 void PlaylistModel::playlistItemUpdated()
 {
     PlaylistItem *item = qobject_cast<PlaylistItem*>(sender());
@@ -214,7 +236,7 @@ void PlaylistModel::loadFromFile(const QString& path)
 
             QDomNodeList itemList = doc.elementsByTagName("item");
             d->musicList.clear();
-            d->currentIndex = -1;
+            setCurrentIndex(-1);
             for (int i=0; i<itemList.count(); i++) {
                 QDomNode node = itemList.at(i);
                 if (node.isNull()) continue;
@@ -258,14 +280,12 @@ void PlaylistModel::saveToFile(const QString& path) const
 
 void PlaylistModel::savePlaylist()
 {
-    beginResetModel();
     saveToFile(playlistFilePath());
-    endResetModel();
 }
 
 bool PlaylistModel::removeCurrentPlaylist(const QString \
&playlistToSwitchToAfterDeletion)  {
-    if (d->playlistName == "Default") {
+    if (d->playlistName == DEFAULT_PLAYLIST_NAME) {
         clearPlaylist();
         return false;
     } else {
@@ -288,6 +308,8 @@ QString PlaylistModel::playlistName() const
 
 void PlaylistModel::setPlaylistName(const QString& name)
 {
+    if (playlistName() == name) return;
+
     beginResetModel();
     saveToFile(playlistFilePath());
 
@@ -298,28 +320,43 @@ void PlaylistModel::setPlaylistName(const QString& name)
     endResetModel();
 }
 
-bool PlaylistModel::checkPlaylistPathExists(const QString& name)
+QString PlaylistModel::getPlaylistPath() const
 {
-    QString playlistAbsolutePath = getPlaylistPath() + name;
-    return QFile::exists(playlistAbsolutePath);
+    if (d->playlistsDirectoryPath.isEmpty()) {
+        d->playlistsDirectoryPath = MediaCenter::dataDirForComponent("playlists");
+        QDir().mkpath(d->playlistsDirectoryPath);
+    }
+    return d->playlistsDirectoryPath;
 }
 
-bool PlaylistModel::setCmdLineURL(bool value)
+bool PlaylistModel::processCommandLineArgs(const KCmdLineArgs* args)
 {
-    d->cmdLineURL = value;
-    return d->cmdLineURL;
+    QStringList urls;
+
+    for (int i=0; i<args->count(); ++i) {
+        const KUrl url = args->url(i);
+        if (url.isValid()) {
+            urls.append(url.toLocalFile(KUrl::RemoveTrailingSlash));
+        }
+    }
+
+    if (urls.size()) {
+        setPlaylistName(DEFAULT_PLAYLIST_NAME);
+        const int indexOfFirstMedia = addToPlaylist(urls);
+
+        setCurrentIndex(indexOfFirstMedia);
+        return true;
+    }
+
+    return false;
 }
 
-bool PlaylistModel::getCmdLineURL()
+void PlaylistModel::play(int index)
 {
-    return d->cmdLineURL;
+    setCurrentIndex(index);
 }
 
-QString PlaylistModel::getPlaylistPath() const
+QString PlaylistModel::currentUrl() const
 {
-    if (d->playlistsDirectoryPath.isEmpty()) {
-        d->playlistsDirectoryPath = MediaCenter::dataDirForComponent("playlists");
-        QDir().mkpath(d->playlistsDirectoryPath);
-    }
-    return d->playlistsDirectoryPath;
+    return data(index(currentIndex()), MediaCenter::MediaUrlRole).toString();
 }
diff --git a/libs/mediacenter/playlistmodel.h b/libs/mediacenter/playlistmodel.h
index f79f814..cb88c6c 100644
--- a/libs/mediacenter/playlistmodel.h
+++ b/libs/mediacenter/playlistmodel.h
@@ -26,10 +26,12 @@
 #include "mediacenter_export.h"
 #include "mediacenter.h"
 
+class KCmdLineArgs;
 class MEDIACENTER_EXPORT PlaylistModel : public QAbstractListModel
 {
     Q_OBJECT
-    Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY \
currentIndexChanged) +    Q_PROPERTY(int currentIndex READ currentIndex NOTIFY \
currentIndexChanged) +    Q_PROPERTY(QString currentUrl READ currentUrl NOTIFY \
currentUrlChanged)  
 public:
     enum Roles {
@@ -55,17 +57,19 @@ public:
     bool random() const;
     Q_INVOKABLE void shuffle();
     bool removeCurrentPlaylist (const QString& playlistToSwitchToAfterDeletion);
+    bool processCommandLineArgs(const KCmdLineArgs *args);
+    Q_INVOKABLE void play(int index);
 
     QString playlistName() const;
     void setPlaylistName(const QString &name);
-    bool checkPlaylistPathExists(const QString &name);
-    bool setCmdLineURL(bool value);
-    bool getCmdLineURL();
     QString getPlaylistPath() const;
 
+    QString currentUrl() const;
+
 Q_SIGNALS:
     void currentIndexChanged();
     void randomChanged();
+    void currentUrlChanged();
 
 public Q_SLOTS:
     void savePlaylist();
@@ -81,6 +85,7 @@ private:
     void saveToFile(const QString &path) const;
     QString playlistFilePath() const;
     void clearPlaylistWithoutModelReset();
+    int addToPlaylist(const QStringList &urls);
 };
 
 #endif // PLAYLISTMODEL_H
diff --git a/mediaelements/playlist/MultiplePlaylists.qml \
b/mediaelements/playlist/MultiplePlaylists.qml index d94fe6e..4b085fe 100644
--- a/mediaelements/playlist/MultiplePlaylists.qml
+++ b/mediaelements/playlist/MultiplePlaylists.qml
@@ -48,6 +48,7 @@ FocusScope {
             model: MediaCenterElements.MultiplePlaylistModel {
                 playlistModelAddress: playlistModel
             }
+            currentIndex: model.currentIndex
 
             delegate:
             Item {
@@ -69,38 +70,7 @@ FocusScope {
 
                 MouseArea {
                     anchors.fill: parent
-                    onClicked: playlistText.ListView.view.currentIndex = index
-                }
-
-                Component.onCompleted: {
-                    if( ( display == "Misc" ) && ( \
                multiplePlaylistList.model.checkCmdLineStat() )) {
-                         autoSelectPlaylistTimer.start();
-                    }
-                }
-
-                Timer {
-                    id: autoSelectPlaylistTimer
-                    interval: 10
-                    onTriggered: {
-                       multiplePlaylistList.currentIndex = index;
-                       if( multiplePlaylistList.model.checkCmdLineStat() )
-                           multiplePlaylistList.model.setCmdLineStat(false);
-                    }
-                }
-            }
-
-            onCurrentIndexChanged: {
-                if( multiplePlaylistList.model.checkCmdLineStat() ) {
-                    multiplePlaylistList.model.switchToPlaylist("Misc");
-                } else {
-                    multiplePlaylistList.model.switchToPlaylist(
-                    currentItem.currentPlaylist);
-                }
-            }
-
-            Component.onCompleted: {
-                if( multiplePlaylistList.model.checkCmdLineStat() ) {
-                    multiplePlaylistList.model.switchToPlaylist("Misc");
+                    onClicked: \
playlistText.ListView.view.model.switchToPlaylist(itemText.text)  }
             }
         }
diff --git a/mediaelements/playlist/Playlist.qml \
b/mediaelements/playlist/Playlist.qml index fd83c21..96f792e 100644
--- a/mediaelements/playlist/Playlist.qml
+++ b/mediaelements/playlist/Playlist.qml
@@ -24,7 +24,6 @@ import org.kde.plasma.mediacenter.elements 0.1 as \
MediaCenterElements  
 FocusScope {
     id: playlistItem
-    property QtObject backend
     property bool active: false
     signal playRequested(string url)
 
@@ -92,16 +91,14 @@ FocusScope {
                     width: height
                     height: parent.height
                     iconSource: "edit-clear-list"
-                    onClicked: {
-                        if(playlistItem.backend.stopAddingSongsToPlaylist)
-                            playlistItem.backend.stopAddingSongsToPlaylist
-                        playlistModel.clearPlaylist();
-                    }
+                    onClicked: playlistModel.clearPlaylist()
                 }
             }
 
             ListView {
                 id: playlistList
+                property int currentlyPlayingIndex: playlistModel.currentIndex
+
                 anchors { top: playlistActions.bottom; left: parent.left; right: \
parent.right }  anchors.bottom: parent.bottom
                 anchors.margins: 5
@@ -115,11 +112,9 @@ FocusScope {
                 delegate: PlaylistDelegate {
                     width: playlistList.width - playlistScrollbar.width ; height: 32
                     onPlayRequested: {
-                        playlistItem.active = true;
                         playlistList.currentIndex = index;
-                        playlistModel.currentIndex = originalIndex;
-                        playlistItem.playRequested(url);
-                        filterText.text = "";
+                        playlistModel.play(index);
+                        playCurrent();
                     }
                 }
 
@@ -141,6 +136,8 @@ FocusScope {
                     }
                 }
 
+                onCurrentlyPlayingIndexChanged: playCurrent()
+
                 Keys.onPressed: if (event.key == Qt.Key_Up && currentIndex == 0) {
                     filterText.focus = true;
                     event.accepted = true;
@@ -148,6 +145,13 @@ FocusScope {
                     filterText.focus = true;
                     filterText.text = event.text;
                 }
+
+                function playCurrent()
+                {
+                    playlistItem.active = true;
+                    playlistItem.playRequested(playlistModel.currentUrl);
+                    filterText.text = "";
+                }
             }
         }
     }
@@ -163,4 +167,13 @@ FocusScope {
         playlistList.currentIndex = playlistList.currentIndex == 0 ? \
playlistList.count-1 : playlistList.currentIndex-1;  \
playlistList.currentItem.requestPlayback();  }
+
+    function playCurrent()
+    {
+        if (playlistModel.currentIndex != -1) {
+            playlistList.playCurrent();
+        }
+    }
+
+    Component.onCompleted: playCurrent();
 }
diff --git a/mediaelements/playlist/PlaylistDelegate.qml \
b/mediaelements/playlist/PlaylistDelegate.qml index e1bd31d..a73ba2f 100644
--- a/mediaelements/playlist/PlaylistDelegate.qml
+++ b/mediaelements/playlist/PlaylistDelegate.qml
@@ -24,6 +24,9 @@ import org.kde.plasma.components 0.1 as PlasmaComponents
 
 Item {
     id: listViewItem
+    property bool isCurrentlyPlaying: index == playlistModel.currentIndex
+    property variant url: mediaUrl
+
     signal playRequested(string url)
 
     Row {
@@ -37,7 +40,7 @@ Item {
                     right: artistText.left; margins: 5
                 }
                 text: display
-                color: index == playlistModel.currentIndex && \
listViewItem.ListView.view.model.filterString == "" ? "red" : theme.textColor +       \
color: listViewItem.isCurrentlyPlaying && \
listViewItem.ListView.view.model.filterString == "" ? "red" : theme.textColor  elide: \
Text.ElideRight  font.pixelSize: 18
                 style: Text.Sunken
@@ -148,7 +151,6 @@ Item {
     Keys.onReturnPressed: requestPlayback()
 
     function requestPlayback() {
-        listViewItem.ListView.view.model.currentIndex = index;
-        listViewItem.playRequested(mediaUrl);
+        listViewItem.playRequested(mediaUrl)
     }
 }
diff --git a/shells/newshell/application.cpp b/shells/newshell/application.cpp
index adc95dc..f01bc1c 100644
--- a/shells/newshell/application.cpp
+++ b/shells/newshell/application.cpp
@@ -35,10 +35,8 @@ Application::~Application()
 
 int Application::newInstance()
 {
-    if (!m_mainWindow)
-    {
+    if (!m_mainWindow) {
         m_mainWindow = new MainWindow(this);
-
         m_mainWindow->show();
     } else {
         m_mainWindow->addNewInstanceArgsPlaylist();
diff --git a/shells/newshell/mainwindow.cpp b/shells/newshell/mainwindow.cpp
index 7f7f31d..f721d68 100644
--- a/shells/newshell/mainwindow.cpp
+++ b/shells/newshell/mainwindow.cpp
@@ -53,15 +53,6 @@ MainWindow::MainWindow(Application *parent)
 {
     KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
 
-    const int argsCount = args->count();
-
-    QList<KUrl> urls;
-    for (int i = 0; i < argsCount; ++i) {
-        const KUrl url = args->url(i);
-        if (url.isValid()) {
-            urls.append(url);
-        }
-    }
     if (args->isSet("fullscreen") || Settings().value("fullscreen", false).toBool()) \
{  toggleFullScreen();
     }
@@ -79,7 +70,6 @@ MainWindow::MainWindow(Application *parent)
         view->setViewport(widget);
 #endif
     }
-    args->clear();
 
     view->setAttribute(Qt::WA_OpaquePaintEvent);
     view->setAttribute(Qt::WA_NoSystemBackground);
@@ -104,7 +94,9 @@ MainWindow::MainWindow(Application *parent)
     view->rootContext()->setContextProperty("backendsModel", backendsModel);
 
     playlistModel = new PlaylistModel(this);
-    addToMiscPlaylist(urls,"true");
+    if (playlistModel->processCommandLineArgs(args)) {
+        QTimer::singleShot(500, this, SLOT(playPlaylist()));
+    }
     view->rootContext()->setContextProperty("playlistModel", playlistModel);
 
     view->rootContext()->setContextProperty("_pmc_mainwindow", this);
@@ -127,9 +119,6 @@ MainWindow::MainWindow(Application *parent)
 
     view->setSource(QUrl(package->filePath("mainscript")));
 
-    if (view->rootObject() && urls.count() > 0) {
-        QTimer::singleShot(500, this, SLOT(playPlaylist()));
-    }
     resize(1366, 768);
 
     installEventFilter(this);
@@ -216,34 +205,7 @@ void MainWindow::playPlaylist()
 void MainWindow::addNewInstanceArgsPlaylist()
 {
     KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
-
-    const int argsCount = args->count();
-
-    QList<KUrl> urls;
-    for (int i = 0; i < argsCount; ++i) {
-        const KUrl url = args->url(i);
-        if (url.isValid()) {
-            urls.append(url);
-        }
-    }
-    bool clearPlaylist = "false";
-    addToMiscPlaylist(urls,false);
-}
-
-void MainWindow::addToMiscPlaylist(QList< KUrl >& urls, bool clearPlaylist)
-{
-    if (urls.length() > 0) {
-        playlistModel->setCmdLineURL(true);
-        playlistModel->setPlaylistName("Misc");
-        if( playlistModel->checkPlaylistPathExists("Misc") && clearPlaylist) {
-            playlistModel->clearPlaylist();
-        }
-        foreach (const KUrl &url, urls) {
-            playlistModel->addToPlaylist(url.prettyUrl());
-        }
-        playlistModel->savePlaylist();
-    } else {
-        playlistModel->setCmdLineURL(false);
+    if (playlistModel->processCommandLineArgs(args)) {
+        QTimer::singleShot(500, this, SLOT(playPlaylist()));
     }
 }
-
diff --git a/shells/newshell/mainwindow.h b/shells/newshell/mainwindow.h
index d918e3d..f224060 100644
--- a/shells/newshell/mainwindow.h
+++ b/shells/newshell/mainwindow.h
@@ -49,7 +49,6 @@ public Q_SLOTS:
     void hideMousePointer();
     void showMousePointer();
     void playPlaylist();
-    void addToMiscPlaylist(QList<KUrl> &urls, bool clearPlaylist);
     void addNewInstanceArgsPlaylist();
 
 Q_SIGNALS:
diff --git a/shells/newshell/package/contents/ui/mediacenter.qml \
b/shells/newshell/package/contents/ui/mediacenter.qml index 3d87d7f..37718c5 100644
--- a/shells/newshell/package/contents/ui/mediacenter.qml
+++ b/shells/newshell/package/contents/ui/mediacenter.qml
@@ -247,7 +247,6 @@ Image {
         Component {
             id: pmcPlaylistComponent
             MediaCenterElements.Playlist {
-                backend: runtimeData.currentBrowsingBackend
                 onPlayRequested: {
                     if (!mediaPlayerInstance) {
                         pmcPageStack.pushAndFocus(getMediaPlayer());
@@ -358,7 +357,6 @@ Image {
     //FIXME: Hack to play params passed from the command line
     function play() {
         pmcPageStack.pushAndFocus(getPlaylist());
-        getPlaylist().playRequested(playlistModel.getNextUrl());
     }
 
     function showController(itemToFocus)


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic