diff --git a/backend_xmmsclient++/playlistmodel.cpp b/backend_xmmsclient++/playlistmodel.cpp index 6bbfea0..9faeac2 100644 --- a/backend_xmmsclient++/playlistmodel.cpp +++ b/backend_xmmsclient++/playlistmodel.cpp @@ -29,23 +29,24 @@ #include "playlistmodel.h" #include "xclient.h" #include "xclientcache.h" +#include "xplayback.h" // Used to check for Protocolversion at compiletime #include PlaylistModel::PlaylistModel (QObject *parent, XClient *client, const QString &name) : QAbstractItemModel (parent), m_current_pos (0) { -// m_columns.append ("#"); m_columns.append ("Artist"); m_columns.append ("Album"); m_columns.append ("Title"); + m_columns.append ("#queue"); m_columns.append ("Duration"); -// m_colfallback.append (""); m_colfallback.append (""); m_colfallback.append (""); m_colfallback.append ("url"); m_colfallback.append (""); + m_colfallback.append (""); m_cached_size.append (QSize ()); m_cached_size.append (QSize ()); @@ -127,9 +128,11 @@ PlaylistModel::handle_update_pos (const Xmms::Dict &posdict) #else uint32_t pos = posdict.get ("position"); #endif - m_current_pos = pos; - emit currentPosChanged (index (pos, 0)); - emit dataChanged(index (pos, 0), index (pos, m_columns.size ())); + if (queue_next(pos)) { + m_current_pos = pos; + emit currentPosChanged (index (pos, 0)); + emit dataChanged(index (pos, 0), index (pos, m_columns.size ())); + } } return true; } @@ -137,9 +140,11 @@ PlaylistModel::handle_update_pos (const Xmms::Dict &posdict) bool PlaylistModel::handle_update_pos (const uint32_t &pos) { - m_current_pos = pos; - emit currentPosChanged (index (pos, 0)); - emit dataChanged(index (pos, 0), index (pos, m_columns.size ())); + if (queue_next()) { + m_current_pos = pos; + emit currentPosChanged (index (pos, 0)); + emit dataChanged(index (pos, 0), index (pos, m_columns.size ())); + } return true; } #endif @@ -223,14 +228,16 @@ PlaylistModel::handle_change (const Xmms::Dict &chg) break; case XMMS_PLAYLIST_CHANGED_REMOVE: + m_queue.removeAt(m_queue_index.take(m_plist[pos])); m_client->cache ()->invalidate (m_plist[pos]); beginRemoveRows (idx, pos, pos); m_plist.removeAt (pos); endRemoveRows (); break; + case XMMS_PLAYLIST_CHANGED_CLEAR: + queueClear(); case XMMS_PLAYLIST_CHANGED_SHUFFLE: case XMMS_PLAYLIST_CHANGED_SORT: - case XMMS_PLAYLIST_CHANGED_CLEAR: m_client->cache ()->invalidate_all (); m_client->playlist ()->listEntries () (Xmms::bind (&PlaylistModel::handle_list, this)); break; @@ -387,6 +394,12 @@ PlaylistModel::data (const QModelIndex &index, int role) const if (key == "#") { return QVariant (index.row ()); + } else if (key == "#queue") { + unsigned int id = m_plist[index.row ()]; + if (m_queue_index.contains (id)) { + return QVariant (QString ("(%1)").arg (m_queue_index.value(id) + 1)); + } + return QVariant (); } else { unsigned int id = m_plist[index.row ()]; PlaylistModel *fake = const_cast (this); @@ -631,4 +644,74 @@ PlaylistModel::removeRows (QModelIndexList index_list) } } +void +PlaylistModel::queueToggle(unsigned int pos) +{ + uint32_t id = m_plist.at(pos); + if (m_queue_index.contains(id)) { + unsigned int queue_idx = m_queue_index.take(id); + m_queue.removeAt(queue_idx); + } else { + m_queue.append(id); + m_queue_index[id] = m_queue.length() - 1; + } + emit dataChanged(index(pos, 3), index(pos, 3)); +} + +void +PlaylistModel::queueClear() +{ + m_queue.clear(); + m_queue_index.clear(); +} + +int +PlaylistModel::queue_peek () +{ + if (m_queue.isEmpty()) + return -1; + + uint32_t next_id = m_queue.first(); + QList next_pos_list = getPosById(next_id); + if (next_pos_list.isEmpty()) + return -1; + else + return next_pos_list.first(); +} + +void +PlaylistModel::queue_pop () +{ + uint32_t next_id = m_queue.takeFirst(); + m_queue_index.remove(next_id); + QHash::iterator it; + for (it = m_queue_index.begin(); it != m_queue_index.end(); ++it) { + it.value()--; + } +} + +bool +PlaylistModel::queue_next (int pos) +{ + while (!m_queue.isEmpty()) { + int next_pos = queue_peek(); + if (next_pos == -1) { + // Queue item no longer exists in playlist + queue_pop(); + } else if (next_pos == pos) { + // Now on the next queue item; we're done + queue_pop(); + return true; + } else if (pos - m_current_pos != 1) { + // User manually jumped in playlist, bail out + return true; + } else { + // Jump to queue position + m_client->xplayback ()->setPos(next_pos); + return false; + } + } + return true; +} + #include "playlistmodel.moc" diff --git a/backend_xmmsclient++/playlistmodel.h b/backend_xmmsclient++/playlistmodel.h index fbc45ac..5c08126 100644 --- a/backend_xmmsclient++/playlistmodel.h +++ b/backend_xmmsclient++/playlistmodel.h @@ -26,6 +26,7 @@ class XClient; #include #include #include +#include #include /** @@ -118,6 +119,17 @@ class PlaylistModel : public QAbstractItemModel uint32_t getPlaytimeForSelection(const QModelIndexList &index_list); + /** + * Add a playlist item to the queue + * @param pos Position of the item to be added + */ + void queueToggle(uint32_t pos); + + /** + * Clears the playlist queue + */ + void queueClear(); + protected: XClient *m_client; QList < unsigned int > m_plist; @@ -153,6 +165,10 @@ class PlaylistModel : public QAbstractItemModel void emitTotalPlaytime (); + bool queue_next(int pos); + void queue_pop(); + int queue_peek(); + uint32_t m_current_pos; bool m_isactive; @@ -160,6 +176,9 @@ class PlaylistModel : public QAbstractItemModel QString m_name; + QList m_queue; // list of ids, in queue order + QHash m_queue_index; // map of ids to queue position + }; #endif diff --git a/src/playlist/playlistview.cpp b/src/playlist/playlistview.cpp index ab8b3ee..2f50258 100644 --- a/src/playlist/playlistview.cpp +++ b/src/playlist/playlistview.cpp @@ -70,7 +70,7 @@ PlaylistDelegate::paint( QPainter *painter, const QStyleOptionViewItem& option, QRect r = option.rect; QString s; // Get playtime and if it exists, draw it - m = index.sibling (index.row (), 3); + m = index.sibling (index.row (), 4); tmp = m.data (); if (tmp.isValid ()) { int seconds = tmp.toInt () / 1000; @@ -81,11 +81,12 @@ PlaylistDelegate::paint( QPainter *painter, const QStyleOptionViewItem& option, r.setWidth (r.width () - option.fontMetrics.width (s)); } - // now build String for Artis Title and Position + // now build String for Artist, Title and Position s = QString ("%1. ").arg (index.row () + 1); tmp = index.data (); if (tmp.isValid ()) s.append (tmp.toString ()).append (" - "); + m = index.sibling (index.row (), 1); tmp = m.data (); if (tmp.isValid ()) @@ -93,8 +94,14 @@ PlaylistDelegate::paint( QPainter *painter, const QStyleOptionViewItem& option, m = index.sibling (index.row (), 2); tmp = m.data (); + if (tmp.isValid ()) + s.append (tmp.toString ().append (" ")); + + m = index.sibling (index.row (), 3); + tmp = m.data (); if (tmp.isValid ()) s.append (tmp.toString ()); + s = option.fontMetrics.elidedText(s, Qt::ElideRight, r.width()); painter->drawText (r, Qt::AlignVCenter, s); @@ -371,6 +378,26 @@ PlaylistView::mouseMoveEvent (QMouseEvent *event) } } +void +PlaylistView::keyPressEvent (QKeyEvent *event) +{ + if (event->key() == Qt::Key_Q) { + PlaylistModel *plmodel = qobject_cast (model ()); + + if (event->modifiers () && Qt::ShiftModifier) { + plmodel->queueClear (); + } else { + QModelIndexList sel = selectedIndexes (); + for (int i = 0; i < sel.size (); i++) { + plmodel->queueToggle (sel[i].row()); + } + } + + } else { + QListView::keyPressEvent(event); + } +} + void PlaylistView::entryMoved(QModelIndex a, QModelIndex b) { diff --git a/src/playlist/playlistview.h b/src/playlist/playlistview.h index 9412569..ebc636b 100644 --- a/src/playlist/playlistview.h +++ b/src/playlist/playlistview.h @@ -75,6 +75,7 @@ class PlaylistView : public QListView { protected: void mouseDoubleClickEvent (QMouseEvent *event); void mouseMoveEvent (QMouseEvent *event); + void keyPressEvent (QKeyEvent *event); protected slots: void selectionChanged (const QItemSelection &, const QItemSelection &);