diff --git a/libs/mediacenter/playlistmodel.cpp b/libs/mediacenter/playlistmodel.cpp index 698be210..5444b44c 100644 --- a/libs/mediacenter/playlistmodel.cpp +++ b/libs/mediacenter/playlistmodel.cpp @@ -1,205 +1,208 @@ /*********************************************************************************** * Copyright 2012 by Sinny Kumari * * * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2.1 of the License, or (at your option) any later version. * * * * This library 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 * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library. If not, see . * ***********************************************************************************/ #include "playlistmodel.h" #include "playlistitem.h" #include #include #include #include #include #include #include #include class PlaylistModel::Private { public: QList musicList; int currentIndex; QFile file; QString filePath; bool random; }; PlaylistModel::PlaylistModel(QObject* parent): QAbstractListModel(parent), d(new Private) { KConfigGroup cfgGroup = KGlobal::config()->group("General"); QString dirPath = KGlobal::dirs()->saveLocation("data") + KCmdLineArgs::appName(); QDir().mkdir(dirPath); d->filePath = dirPath + "/playlist"; if (QFile::exists(d->filePath)) { QFile file(d->filePath); if (file.open(QIODevice::ReadOnly)) { QTextStream in(&file); while (!in.atEnd()) { QString line = in.readLine(); PlaylistItem *item = new PlaylistItem(line, this); connect(item, SIGNAL(updated()), SLOT(playlistItemUpdated())); d->musicList.append(item); } } file.close(); } d->currentIndex = -1; setRoleNames(MediaCenter::appendAdditionalMediaRoles(roleNames())); QHash newRoles(roleNames()); newRoles[MediaLengthRole] = "mediaLength"; newRoles[MediaArtistRole] = "mediaArtist"; + newRoles[OriginalIndexRole] = "originalIndex"; setRoleNames(newRoles); qsrand(QDateTime::currentMSecsSinceEpoch()); } PlaylistModel::~PlaylistModel() { KConfigGroup cfgGroup = KGlobal::config()->group("General"); cfgGroup.sync(); QFile file(d->filePath); if (file.open(QIODevice::WriteOnly)) { QTextStream out(&file); Q_FOREACH (const PlaylistItem *item, d->musicList) { out << item->mediaUrl() << "\n"; } } file.close(); } QVariant PlaylistModel::data(const QModelIndex& index, int role) const { switch(role) { case Qt::DisplayRole: return d->musicList.at(index.row())->mediaName(); case MediaCenter::MediaUrlRole: return d->musicList.at(index.row())->mediaUrl(); case PlaylistModel::MediaArtistRole: return d->musicList.at(index.row())->mediaArtist(); case PlaylistModel::MediaLengthRole: return d->musicList.at(index.row())->mediaLength(); + case PlaylistModel::OriginalIndexRole: + return index.row(); } return QVariant(); } int PlaylistModel::rowCount(const QModelIndex& parent) const { return d->musicList.count(); } void PlaylistModel::addToPlaylist(const QString& url) { const int n = rowCount(); beginInsertRows(QModelIndex(), n, n); PlaylistItem *item = new PlaylistItem(url, this); connect(item, SIGNAL(updated()), SLOT(playlistItemUpdated())); d->musicList.append(item); endInsertRows(); } void PlaylistModel::removeFromPlaylist(const int& index) { beginResetModel(); d->musicList.takeAt(index)->deleteLater(); if (index <= d->currentIndex) { d->currentIndex -= 1; } endResetModel(); } void PlaylistModel::moveItem(int firstIndex, int secondIndex) { d->musicList.move(firstIndex,secondIndex); emit dataChanged(createIndex(firstIndex, 0), createIndex(secondIndex, 0)); } QString PlaylistModel::getNextUrl() { if (d->currentIndex == d->musicList.count() - 1) { setCurrentIndex(0); } else { setCurrentIndex(d->currentIndex + 1); } return d->musicList.at(d->currentIndex)->mediaUrl(); } QString PlaylistModel::getPreviousUrl() { if (d->currentIndex == 0) { setCurrentIndex(d->musicList.count() - 1); } else { setCurrentIndex(d->currentIndex - 1); } return d->musicList.at(d->currentIndex)->mediaUrl(); } QString PlaylistModel::getUrlofFirstIndex() { return d->musicList.isEmpty() ? QString() : d->musicList.at(0)->mediaUrl(); } void PlaylistModel::clearPlaylist() { beginResetModel(); Q_FOREACH(PlaylistItem *item, d->musicList) { item->deleteLater(); } d->musicList.clear(); d->currentIndex = -1; endResetModel(); } int PlaylistModel::currentIndex() const { return d->currentIndex; } void PlaylistModel::setCurrentIndex(int index) { d->currentIndex = index; emit currentIndexChanged(); } void PlaylistModel::shuffle() { QList musicListShuffle; while( !d->musicList.isEmpty() ) { musicListShuffle.append(d->musicList.takeAt(qrand() % d->musicList.size())); } beginResetModel(); d->musicList = musicListShuffle; endResetModel(); } void PlaylistModel::playlistItemUpdated() { PlaylistItem *item = qobject_cast(sender()); int i = d->musicList.indexOf(item); - emit dataChanged(createIndex(i, 0), createIndex(i, 0)); + emit dataChanged(createIndex(i, 0), createIndex(i, 0)); } diff --git a/libs/mediacenter/playlistmodel.h b/libs/mediacenter/playlistmodel.h index e4efd65a..3202e14f 100644 --- a/libs/mediacenter/playlistmodel.h +++ b/libs/mediacenter/playlistmodel.h @@ -1,71 +1,72 @@ /*********************************************************************************** * Copyright 2012 by Sinny Kumari * * * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2.1 of the License, or (at your option) any later version. * * * * This library 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 * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library. If not, see . * ***********************************************************************************/ #ifndef PLAYLISTMODEL_H #define PLAYLISTMODEL_H #include #include #include #include #include "mediacenter_export.h" #include "mediacenter.h" class MEDIACENTER_EXPORT PlaylistModel : public QAbstractListModel { Q_OBJECT Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged) public: enum Roles { MediaArtistRole = MediaCenter::AdditionalRoles + 1, - MediaLengthRole + MediaLengthRole, + OriginalIndexRole }; explicit PlaylistModel(QObject* parent = 0); ~PlaylistModel(); virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; virtual int rowCount(const QModelIndex& parent = QModelIndex()) const; Q_INVOKABLE void addToPlaylist(const QString &url); Q_INVOKABLE QString getNextUrl(); Q_INVOKABLE QString getPreviousUrl(); Q_INVOKABLE void clearPlaylist(); Q_INVOKABLE void removeFromPlaylist(const int &index); Q_INVOKABLE QString getUrlofFirstIndex(); Q_INVOKABLE void moveItem(int firstIndex,int secondIndex); int currentIndex() const; void setCurrentIndex(int index); bool random() const; Q_INVOKABLE void shuffle(); Q_SIGNALS: void currentIndexChanged(); void randomChanged(); private Q_SLOTS: void playlistItemUpdated(); private: class Private; Private * const d; }; #endif // PLAYLISTMODEL_H diff --git a/mediaelements/playlist/Playlist.qml b/mediaelements/playlist/Playlist.qml index 04a44d00..adb9452d 100644 --- a/mediaelements/playlist/Playlist.qml +++ b/mediaelements/playlist/Playlist.qml @@ -1,128 +1,142 @@ /*************************************************************************** * Copyright 2012 Sinny Kumari * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * 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 . * ***************************************************************************/ import QtQuick 1.1 import org.kde.plasma.core 0.1 as PlasmaCore import org.kde.plasma.components 0.1 as PlasmaComponents import org.kde.plasma.mediacenter.elements 0.1 as MediaCenterElements FocusScope { id: playlistItem property QtObject backend property bool active: false signal playRequested(string url) PlasmaCore.FrameSvgItem { imagePath: "widgets/background" enabledBorders: "LeftBorder|TopBorder|BottomBorder" anchors.fill: parent Item { anchors { fill: parent; leftMargin: 10; topMargin: 10; bottomMargin: 10 } clip: true Row { id: topRow anchors { top: parent.top; left: parent.left; right: parent.right } height: 64 Item { height: parent.height width: parent.width - clearPlaylist.width - randomButton.width Text { id: mediaCount anchors.centerIn: parent text: i18np("%1 item", "%1 items", playlistList.count) font.pixelSize: 18 color: theme.textColor } } PlasmaComponents.ToolButton { id: randomButton width: height height: parent.height iconSource: "media-playlist-shuffle" onClicked: { playlistModel.shuffle(); } } PlasmaComponents.ToolButton { id: clearPlaylist width: height height: parent.height iconSource: "edit-clear-list" onClicked: { if(playlistItem.backend.stopAddingSongsToPlaylist) playlistItem.backend.stopAddingSongsToPlaylist playlistModel.clearPlaylist(); } } } PlasmaComponents.TextField { anchors { top: topRow.bottom; left: parent.left; right: parent.right } id: filterText width: parent.width height: 30 clearButtonShown: true placeholderText: i18n("Search Playlist") } ListView { id: playlistList - currentIndex: playlistModel.currentIndex - onCurrentIndexChanged: { - positionViewAtIndex(currentIndex, ListView.Contain); - } anchors { top: filterText.bottom; left: parent.left; right: parent.right } anchors.bottom: parent.bottom anchors.margins: 5 + model: MediaCenterElements.FilterPlaylistModel { - sourcePlaylistModel : playlistModel - filterString: filterText.text + sourcePlaylistModel : playlistModel + filterString: filterText.text } spacing: 3 clip: true focus: true + delegate: PlaylistDelegate { + width: playlistList.width - playlistScrollbar.width ; height: 32 + onPlayRequested: { + playlistItem.active = true; + playlistList.currentIndex = index; + playlistModel.currentIndex = originalIndex; + playlistItem.playRequested(url); + } + } PlasmaComponents.ScrollBar { id: playlistScrollbar orientation: Qt.Vertical flickableItem: playlistList } - delegate: PlaylistDelegate { - width: playlistList.width - playlistScrollbar.width ; height: 32 - onPlayRequested: { playlistItem.active = true; playlistItem.playRequested(url) } + + Timer { + id: positionViewAtIndexTimer + interval: 10 + onTriggered: playlistList.positionViewAtIndex(playlistList.currentIndex, ListView.Center); + } + + onCurrentIndexChanged: { + if (currentIndex < count) { + positionViewAtIndexTimer.restart(); + } } } } } function playNext() { playlistList.currentIndex = playlistList.currentIndex == playlistList.count-1 ? 0 : playlistList.currentIndex+1; playlistList.currentItem.requestPlayback(); } function playPrevious() { playlistList.currentIndex = playlistList.currentIndex == 0 ? playlistList.count-1 : playlistList.currentIndex-1; playlistList.currentItem.requestPlayback(); } } diff --git a/mediaelements/playlist/PlaylistDelegate.qml b/mediaelements/playlist/PlaylistDelegate.qml index ad35c907..a0205982 100644 --- a/mediaelements/playlist/PlaylistDelegate.qml +++ b/mediaelements/playlist/PlaylistDelegate.qml @@ -1,153 +1,153 @@ /*************************************************************************** * Copyright 2012 Sinny Kumari * * Copyright 2012 Shantanu Tushar * * Copyright 2013 Saurabh Jain * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * 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 . * ***************************************************************************/ import QtQuick 1.1 import org.kde.plasma.components 0.1 as PlasmaComponents Item { id: listViewItem signal playRequested(string url) Row { anchors.fill: parent Rectangle { width: parent.width - removeFromPlaylistButton.width; height: parent.height color: listViewItem.ListView.isCurrentItem ? "#002378" : theme.backgroundColor Text { anchors { left: parent.left; verticalCenter: parent.verticalCenter right: artistText.left; margins: 5 } text: display - color: (index == playlistModel.currentIndex) ? "red" : theme.textColor + color: index == playlistModel.currentIndex && listViewItem.ListView.view.model.filterString == "" ? "red" : theme.textColor elide: Text.ElideRight font.pixelSize: 18 style: Text.Sunken } Text { id: artistText anchors { right: lengthText.left; verticalCenter: parent.verticalCenter } width: parent.width*0.4 text: mediaArtist - color: (index == playlistModel.currentIndex) ? "red" : theme.textColor + color: index == playlistModel.currentIndex && listViewItem.ListView.view.model.filterString == "" ? "red" : theme.textColor elide: Text.ElideRight font.pixelSize: 18 style: Text.Sunken } Text { id: lengthText property int seconds: mediaLength%60 anchors { right: parent.right; verticalCenter: parent.verticalCenter margins: 5 } text: mediaLength ? Math.floor(mediaLength/60) + ":" + (seconds.toString().length < 2 ? "0" + seconds : seconds) : "" - color: index == playlistModel.currentIndex ? "red" : theme.textColor + color: index == playlistModel.currentIndex && listViewItem.ListView.view.model.filterString == "" ? "red" : theme.textColor font.pixelSize: 18 style: Text.Sunken } MouseArea { id: dragItemArea hoverEnabled: true anchors.fill: parent property int posStartX: 0 property int posStartY: 0 property int posEndX: 0 property int posEndY: 0 property int movedX: Math.floor(posEndX - posStartX) property int movedY: Math.floor((posEndY - posStartY)/parent.height) property bool delegateHeld: false property int newPositionY: index + movedY drag.axis: Drag.XandYAxis onPressAndHold: { listViewItem.z = 1 posStartX = listViewItem.x posStartY = listViewItem.y delegateHeld = true dragItemArea.drag.target = listViewItem listViewItem.opacity = 0.5 listViewItem.ListView.interactive = false drag.maximumX = parent.width drag.minimumX = 0 drag.maximumY = parent.height*listViewItem.ListView.count drag.minimumY = 0 } onPositionChanged: { posEndX = listViewItem.x posEndY = listViewItem.y } onReleased: { if(!delegateHeld) return if(Math.abs(movedX) >= parent.width/3) playlistModel.removeFromPlaylist(index) else listViewItem.x = posStartX if (Math.abs(movedY) == 0 && delegateHeld == true){ listViewItem.y = posStartY } else { listViewItem.z = 0 listViewItem.opacity = 1 if(newPositionY < 1) newPositionY = 0 else if(newPositionY > playlistList.count-1) newPositionY = playlistList.count - 1 playlistModel.moveItem(index, newPositionY) listViewItem.x = posStartX listViewItem.y = posStartY } listViewItem.opacity =1 dragItemArea.drag.target = null listViewItem.ListView.interactive = true delegateHeld = false } onClicked: requestPlayback() } } PlasmaComponents.ToolButton { id: removeFromPlaylistButton width: height height: parent.height iconSource: "list-remove" onClicked: { playlistModel.removeFromPlaylist (index); } } } Keys.onReturnPressed: requestPlayback() function requestPlayback() { listViewItem.ListView.view.model.currentIndex = index; listViewItem.playRequested(mediaUrl); } }