#include "XMMSHandler.h" #include "PlaylistList.h" #include "Playlist.h" #include #include #include PlaylistItem::PlaylistItem (PlaylistList *pl, uint id) { m_pl = pl; m_id = id; m_req = false; m_duration = QString ("00:00"); pl->addItem (this); } QString PlaylistItem::text (void) { XMMSHandler *xmmsh = XMMSHandler::getInstance (); if (m_text.count() < 1) { if (!m_req) { xmmsh->requestMediainfo (m_id); m_req = true; } QString q; q.setNum (m_id); return q; } else { m_req = false; return m_text; } } PlaylistList::PlaylistList (QWidget *parent) : QWidget (parent) { XMMSHandler *xmmsh = XMMSHandler::getInstance (); Skin *skin = Skin::getInstance (); setAttribute (Qt::WA_NoBackground); setFocusPolicy (Qt::StrongFocus); setAcceptDrops (true); connect (skin, SIGNAL (skinChanged (Skin *)), this, SLOT (setPixmaps(Skin *))); m_font = NULL; m_fontmetrics = NULL; m_items = new QList; m_selected = new QList; m_itemmap = new QHash; m_offset = 0; m_status = XMMS_PLAYBACK_STATUS_STOP; m_bar = -2; connect (xmmsh, SIGNAL(playlistList(QList)), this, SLOT(playlistList(QList))); connect (xmmsh, SIGNAL(currentID(uint)), this, SLOT(currentID(uint))); connect (xmmsh, SIGNAL(mediainfoChanged(uint, QHash)), this, SLOT(mediainfoChanged(uint, QHash))); connect (xmmsh, SIGNAL(playlistChanged(QHash)), this, SLOT(playlistChanged(QHash))); connect (xmmsh, SIGNAL(playbackStatusChanged(uint)), this, SLOT(setStatus(uint))); } void PlaylistList::setStatus (uint s) { m_status = s; } void PlaylistList::playlistChanged (QHash h) { int signal = h.value("type").toUInt(); XMMSHandler *xmmsh = XMMSHandler::getInstance (); switch (signal) { case XMMS_PLAYLIST_CHANGED_ADD: { uint id = h.value("id").toUInt(); if (m_itemmap->contains (id)) { addItem (m_itemmap->value (id)); } else { new PlaylistItem (this, id); } } break; case XMMS_PLAYLIST_CHANGED_INSERT: break; case XMMS_PLAYLIST_CHANGED_REMOVE: { int pos = h.value("position").toUInt(); PlaylistItem *i = m_items->value (pos); if (!i) { return; } m_items->removeAt (pos); if (!m_items->contains (i)) { m_itemmap->remove (i->getID ()); delete i; } if (m_active) { if (m_active > pos) { m_active --; } else if (m_active == pos) { m_active = 0; } } } break; case XMMS_PLAYLIST_CHANGED_MOVE: break; case XMMS_PLAYLIST_CHANGED_CLEAR: case XMMS_PLAYLIST_CHANGED_SHUFFLE: case XMMS_PLAYLIST_CHANGED_SORT: { m_itemmap->clear (); while (!m_items->isEmpty()) delete m_items->takeFirst(); if (signal != XMMS_PLAYLIST_CHANGED_CLEAR) { xmmsh->requestPlaylistList (); } } break; } update (); } void PlaylistList::currentID (uint id) { PlaylistItem *i = m_itemmap->value (id); if (!i) { m_active = -1; return; } m_active = m_items->indexOf (i); update (); } void PlaylistList::mediainfoChanged (uint id, QHash h) { PlaylistItem *i = m_itemmap->value (id); if (i) { QString n; if (h.contains ("artist") && h.contains ("album") && h.contains ("title")) { n = h.value("artist") + " - " + h.value("album") + " - " + h.value("title"); } else { QString t = h.value("url"); n = t.section ("/", -1); } i->setText (n); if (h.contains ("duration")) { int d = h.value("duration").toInt(); QString dur; dur.sprintf ("%02d:%02d", d/60000, (d/1000)%60); i->setDuration (dur); } } update (); } void PlaylistList::playlistList (QList l) { for (int i = 0; i < l.count(); i++) { if (m_itemmap->contains (l.value(i))) { addItem (m_itemmap->value (l.value (i))); } else { new PlaylistItem (this, l.value(i)); } } update (); } void PlaylistList::mouseDoubleClickEvent (QMouseEvent *event) { XMMSHandler *xmmsh = XMMSHandler::getInstance (); if (m_items->count() < 1 || m_selected->count() < 1) { return; } PlaylistItem *it = m_items->value (m_selected->first()); if (!it) { return; } xmmsh->requestTrackChange (m_items->indexOf(it)); if (m_status == XMMS_PLAYBACK_STATUS_STOP || m_status == XMMS_PLAYBACK_STATUS_PAUSE) { xmmsh->play (); } } QPixmap PlaylistList::generatePixmap (int i) { QStyleOptionHeader opt; QString t (m_items->value(i)->text()); QPixmap p (m_fontmetrics->width(t), getFontH()); QPainter paint; paint.begin (&p); paint.setFont (*m_font); paint.setPen (QPen (m_color_normal)); paint.fillRect (p.rect(), QBrush (m_color_normal_bg)); paint.drawText (p.rect(), Qt::TextSingleLine, t); paint.end (); return p; } void PlaylistList::mousePressEvent (QMouseEvent *event) { if (m_items->count() < 1) { return; } int i = ((event->pos().y()+m_offset) / getFontH()); if (i < 0) { i = 0; } if (i > m_items->count ()) { return; } if (event->button () == Qt::LeftButton) { if (event->modifiers() & Qt::ShiftModifier) { if (m_selected->count () > 0) { int o = m_selected->last (); if (o < i) { for (int y = o+1; y <= i; y++) { m_selected->append (y); } } else { for (int y = i; y < o; y++) { m_selected->append (y); } } } else { m_selected->append (i); } } else if (event->modifiers () & Qt::ControlModifier) { if (m_selected->contains (i)) { m_selected->removeAll (i); } else { m_selected->append (i); } } else { if (m_selected->contains (i)) { m_selected->clear(); } else { m_selected->clear(); m_selected->append(i); } m_dragstart = event->pos (); } } update (); } void PlaylistList::mouseMoveEvent (QMouseEvent *event) { if (!(event->buttons() & Qt::LeftButton)) return; if ((event->pos() - m_dragstart).manhattanLength() < QApplication::startDragDistance()) return; if (m_selected->count() > 0) { int i = m_selected->last (); m_drag = new QDrag (this); m_md = new QMimeData(); QByteArray encodedData; QDataStream stream (&encodedData, QIODevice::WriteOnly); stream << QString::number (m_selected->last ()); m_md->setData("application/playlist.move", encodedData); m_drag->setMimeData (m_md); m_drag_id = m_items->value (i)->getID (); m_pos = i; QPixmap p = generatePixmap (i); m_drag->setPixmap (p); m_items->removeAt (i); m_selected->clear (); Qt::DropAction drop = m_drag->start (); } } void PlaylistList::dragEnterEvent (QDragEnterEvent *event) { if (event->mimeData()->hasFormat("application/mlib.album") || event->mimeData()->hasFormat("application/playlist.move")) event->acceptProposedAction(); /* const QMimeData *md = event->mimeData (); QByteArray encodedData = md->data("application/mlib.album"); QDataStream stream(&encodedData, QIODevice::ReadOnly); QString artist; QString album; stream >> artist; stream >> album; qDebug ("korv %s - %s", qPrintable (artist), qPrintable (album)); event->accept (); */ } void PlaylistList::dragMoveEvent (QDragMoveEvent *event) { int i = ((event->pos().y()+m_offset) / getFontH()); if (event->pos().y() < getFontH() / 2) { m_bar = -1; } else if (i >= m_items->count ()) { m_bar = m_items->count ()-1; } else { m_bar = i; } update (); } void PlaylistList::dragLeaveEvent (QDragLeaveEvent *event) { m_bar = -2; update (); } void PlaylistList::dropEvent (QDropEvent *event) { XMMSHandler *xmmsh = XMMSHandler::getInstance (); if (event->mimeData()->hasFormat("application/playlist.move")) { if (m_bar == -2) { m_items->insert (m_pos, m_itemmap->value (m_drag_id)); } else { m_items->insert (m_bar + 1, m_itemmap->value (m_drag_id)); xmmsh->playlistMove (m_pos, m_bar + 1); } m_selected->append (m_drag_id); event->acceptProposedAction (); } else if (event->mimeData()->hasFormat("application/mlib.album")) { const QMimeData *md = event->mimeData (); QByteArray encodedData = md->data("application/mlib.album"); QDataStream stream(&encodedData, QIODevice::ReadOnly); QString artist; QString album; stream >> artist; stream >> album; QString query; query.sprintf ("select m1.id as id, ifnull(m3.value,-1) as tracknr from Media m1 join Media m2 on m1.id = m2.id and m2.key='album' left join Media m3 on m1.id = m3.id and m3.key='tracknr' where m1.key='artist' and m1.value='%s' and m2.value='%s' order by tracknr", artist.toUtf8 ().data (), album.toUtf8 ().data ()); xmmsh->medialibQueryAdd (query); event->acceptProposedAction (); } m_bar = -2; update (); } void PlaylistList::keyPressEvent (QKeyEvent *event) { XMMSHandler *xmmsh = XMMSHandler::getInstance (); switch (event->key ()) { case Qt::Key_Down: { int i = m_selected->last (); i ++; if (i > m_items->count ()) i = m_items->count (); m_selected->clear (); m_selected->append (i); update (); } break; case Qt::Key_Up: { int i = m_selected->last (); i --; if (i < 0) i = 0; m_selected->clear (); m_selected->append (i); update (); } break; case Qt::Key_Backspace: case Qt::Key_Delete: { /* Sort list and remove in reverse order */ qSort (*m_selected); for (int i = (m_selected->count () - 1); i >= 0; i --) { xmmsh->playlistRemove (m_selected->value (i)); } m_selected->clear (); } break; case Qt::Key_A: { if (event->modifiers() == Qt::ControlModifier) { m_selected->clear (); for (int i = 0; i < m_items->count (); i ++) { m_selected->append (i); } update (); } } break; } } void PlaylistList::paintEvent (QPaintEvent *event) { int i; QPainter paint; paint.begin (this); paint.setFont (*m_font); /* paint.setClipping (false); */ paint.setPen (QPen (m_color_normal)); int cy = event->rect().y () + m_offset; int ch = event->rect().height(); int sitem = cy / getFontH(); int eitem = (cy + ch) / getFontH(); int mod = m_offset - (getFontH() * sitem); if (eitem > m_items->count()) eitem = m_items->count(); QString q; QRect fullLine; QRect textLine; QRect numLine; for (i = sitem; i < eitem; i++) { PlaylistItem *item = m_items->value (i); int tw = m_fontmetrics->width(item->duration ())+2; fullLine.setRect(0, (getFontH()*(i-sitem)) - mod, size().width(), getFontH()); textLine.setRect(0, (getFontH()*(i-sitem)) - mod, size().width()-tw-4, getFontH()); numLine.setRect(size().width()-tw, (getFontH()*(i-sitem)) - mod, tw, getFontH()); q = QString::number (i + 1) + ". " + item->text (); if (m_selected->contains (i)) { paint.fillRect (fullLine, QBrush (m_color_selected)); } else { paint.eraseRect (fullLine); } if (m_active == i) { paint.setPen (QPen (m_color_active)); paint.drawText (textLine, Qt::TextSingleLine, q); paint.drawText (numLine, item->duration ()); paint.setPen (QPen (m_color_normal)); } else { paint.drawText (textLine, Qt::TextSingleLine, q); paint.drawText (numLine, item->duration ()); } if (m_bar == -1) { paint.save (); QPen pen (m_color_active); pen.setWidth (2); paint.setPen (pen); paint.drawLine (2, 0, size().width()-2, 0); paint.restore (); } else if (m_bar == i) { paint.save (); QPen pen (m_color_active); pen.setWidth (5); paint.setPen (pen); paint.drawLine (2, fullLine.y()+getFontH(), size().width()-2, fullLine.y()+getFontH()); paint.restore (); } } if ((getFontH()*(i-sitem) - mod) < size().height()) { paint.eraseRect (QRect (0, (getFontH()*(i-sitem) - mod), size().width(), size().height()-(getFontH()*(i-sitem) - mod))); } paint.end (); } void PlaylistList::addItem (PlaylistItem *i) { m_items->append (i); if (!m_itemmap->contains (i->getID())) { m_itemmap->insert (i->getID(), i); } if (m_items->count()*getFontH () > size().height()) { resize (size().width(), m_items->count ()*getFontH ()); } } int PlaylistList::getFontH (void) { if (!m_fontmetrics) { return 0; } return m_fontmetrics->height(); } void PlaylistList::setPixmaps (Skin *skin) { QPalette pal; QColor c; c.setNamedColor (skin->getPLeditValue ("normalbg")); QBrush b (c); pal.setBrush (QPalette::Window, b); setPalette (pal); if (m_font) { delete m_font; } m_font = new QFont (skin->getPLeditValue ("font")); m_font->setPixelSize (10); if (m_fontmetrics) { delete m_fontmetrics; } m_fontmetrics = new QFontMetrics (*m_font); m_color_active.setNamedColor (skin->getPLeditValue ("current")); m_color_selected.setNamedColor (skin->getPLeditValue ("selectedbg")); m_color_normal.setNamedColor (skin->getPLeditValue ("normal")); m_color_normal_bg.setNamedColor (skin->getPLeditValue ("normalbg")); update (); } void PlaylistList::setSize (int width, int height) { int nx, ny; nx = width; if (height > size().height()) { ny = height; } else { ny = size().height(); } resize (nx, ny); }