Logo Search packages:      
Sourcecode: qmpdclient version File versions  Download package

playlistview.cpp

/*
 * QMPDClient - An MPD client written in Qt 4.
 * Copyright (C) 2005-2008 HÃ¥vard Tautra Knutsen <havtknut@tihlde.org>
 *
 * 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.
 */

#include "config.h"
#include "mpd.h"
#include "mpdcache.h"
#include "mpdconnection.h"
#include "playlistitemdelegate.h"
#include "playlistmodel.h"
#include "playlistview.h"

#include <QDragMoveEvent>
#include <QInputDialog>
#include <QMenu>
#include <QPainter>
#include <QShortcut>
#include <QMessageBox>

PlaylistView::PlaylistView(QWidget *parent) : AbstractList(parent) {
      Q_ASSERT(m_menu);
      setItemDelegate(new PlaylistDelegate(this));
      setModel(m_model = new PlaylistModel(this));
      m_model->setPattern(Config::instance()->playlistPattern());

      // playlist menu
      m_queueAction = addMenuAction("queue", this, SLOT(queueSelectedSong()));
      addAction(m_queueAction); // Needed for shortcut key to work

      m_menu->addSeparator();
      m_removeAction = addMenuAction("remove", this, SLOT(removeItems()));
      m_removeAction->setShortcut(Qt::Key_Delete);
      m_removeAction->setShortcutContext(Qt::WidgetShortcut);
      addAction(m_removeAction); // Needed for shortcut key to work
      m_cropAction = addMenuAction("crop", this, SLOT(cropItems()));
      m_clearAction = addMenuAction("clear", MPD::instance(), SLOT(clearPlaylist()), false);

      m_menu->addSeparator();
      m_randomAction = addMenuAction("random", false);
      m_repeatAction = addMenuAction("repeat", false);
      m_shuffleAction = addMenuAction("shuffle", MPD::instance(), SLOT(shufflePlaylist()), false);

      m_menu->addSeparator();
      m_saveAction = addMenuAction("saveAs", this, SLOT(savePlaylist()), false);
      m_informationAction = addMenuAction("information", this, SLOT(information()));
      m_randomAction->setCheckable(true);
      m_repeatAction->setCheckable(true);

      // signals and slots connections
      connect(Config::instance(), SIGNAL(playlistPatternChanged(const QString &)), this, SLOT(playlistPatternChanged(const QString &)));
      connect(MPD::instance(), SIGNAL(playingSongUpdated(const MPDSong &)), this, SLOT(setSong(const MPDSong &)));
      connect(MPD::instance(), SIGNAL(playlistUpdated(const MPDSongList &)), this, SLOT(setPlaylist(const MPDSongList &)));
      connect(MPD::instance(), SIGNAL(randomUpdated(bool)), m_randomAction, SLOT(setChecked(bool)));
      connect(MPD::instance(), SIGNAL(repeatUpdated(bool)), m_repeatAction, SLOT(setChecked(bool)));
      connect(m_randomAction, SIGNAL(toggled(bool)), MPD::instance(), SLOT(setRandom(bool)));
      connect(m_repeatAction, SIGNAL(toggled(bool)), MPD::instance(), SLOT(setRepeat(bool)));
      // Disconnect the default action in AbstractList
      disconnect(this, SIGNAL(activated(const QModelIndex &)), this, SLOT(activated(const QModelIndex &)));
      connect(this, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(indexActivated(const QModelIndex &)));

      m_focusKey = new QShortcut(Qt::ALT | Qt::SHIFT | Qt::Key_P, this, SLOT(setFocus()));
      m_focusKey->setObjectName("focusPlaylistKey");
}

void PlaylistView::updateTranslation() {
      Q_ASSERT(m_cropAction);
      Q_ASSERT(m_informationAction);
      Q_ASSERT(m_randomAction);
      Q_ASSERT(m_removeAction);
      Q_ASSERT(m_clearAction);
      Q_ASSERT(m_repeatAction);
      Q_ASSERT(m_saveAction);
      Q_ASSERT(m_shuffleAction);
      Q_ASSERT(m_queueAction);
      Q_ASSERT(m_focusKey);
      m_cropAction->setText(tr("&Crop playlist"));
      m_informationAction->setText(tr("&Information..."));
      m_randomAction->setText(tr("Ra&ndom play"));
      m_removeAction->setText(tr("&Remove"));
      m_clearAction->setText(tr("Remove &all"));
      m_repeatAction->setText(tr("Re&peat play"));
      m_saveAction->setText(tr("&Save playlist..."));
      m_shuffleAction->setText(tr("S&huffle playlist"));
      m_queueAction->setText(tr("Add to queue"));
      m_queueAction->setShortcut(tr("Q", "This is the shortcut for 'Add to queue'"));
      m_focusKey->setWhatsThis(tr("Focus playlist"));
}

void PlaylistView::selectionChanged(const QItemSelection &s, const QItemSelection &u) {
      AbstractList::selectionChanged(s, u);
      emit toggleActions(!selectedIndexes().isEmpty());
}

void PlaylistView::playlistPatternChanged(const QString &p) {
      Q_ASSERT(m_model);
      m_model->setPattern(p);
}

void PlaylistView::indexActivated(const QModelIndex &index) {
      Q_ASSERT(m_model);
      foreach(MPDSong s, m_model->songs(index)) {
            MPD::instance()->jumpPlaylistSong(s);
            break;
      }
}

void PlaylistView::cropItems() {
      Q_ASSERT(m_model);
      MPD::instance()->removeSongs(m_model->unSelectedSongs(selectedIndexes()));
}

void PlaylistView::removeItems() {
      QModelIndexList selected = selectedIndexes();
      if (selected.isEmpty())
            return;
      Q_ASSERT(m_model);
      MPD::instance()->removeSongs(m_model->songs(selected));
}

void PlaylistView::setPlaylist(const MPDSongList &songs) {
      Q_ASSERT(m_model);
      QModelIndexList selected = selectedIndexes();
      QModelIndex last = selected.isEmpty() ? QModelIndex() : selected.last();
      m_model->setSongs(songs);
      setCurrentIndex(last);
}


void PlaylistView::setSong(const MPDSong &s) {
      Q_ASSERT(m_model);
      MPDSong playing = s;
      if (m_model->queue().isEmpty()) {
            m_model->setPlaying(s);
      } else {
            playing = m_model->playingSong();
            if (s != playing) {
                  m_model->advanceQueue();
                  playing = m_model->playingSong();
                  if (s != playing) {
                        indexActivated(m_model->indexOfSong(playing));
                  }
            }
      }
      if (!playing.isNull() && Config::instance()->scrollToPlaying()) {
            scrollTo(m_model->indexOfSong(playing), QAbstractItemView::PositionAtCenter);
            m_hidden = true;
      }
}

void PlaylistView::hideEvent(QHideEvent *e) {
      AbstractList::hideEvent(e);
      m_hidden = true;
}

void PlaylistView::paintEvent(QPaintEvent *e) {
      Q_ASSERT(m_model);
      AbstractList::paintEvent(e);
      if (MPDConnection::instance()->isConnected() && isEnabled()) {
            if (!m_dropLine.isNull()) {
                  QPainter painter(viewport());
                  painter.drawLine(m_dropLine);
            }
            if (m_hidden && Config::instance()->scrollToPlaying()) {
                  scrollTo(m_model->indexOfSong(m_model->playingSong()), QAbstractItemView::PositionAtCenter);
                  m_hidden = false;
            }
            return;
      }
}

void PlaylistView::savePlaylist() {
      bool ok;
      int button;

      QString plName = QInputDialog::getText(this, tr("Save playlist as..."),
                                                               tr("Playlist name:"), QLineEdit::Normal, "", &ok);
      while (ok && !plName.isEmpty()) {
            if (!MPDCache::instance()->playlistExists(plName)) {
                  MPDCache::instance()->savePlaylist(plName);
                  break;
            }

            button = QMessageBox::question(this, tr("Attention!"),
                                            tr("A playlist with that name already exists.\nOverwrite?"),
                                            QMessageBox::Yes, QMessageBox::No);

            if (button != QMessageBox::Yes) {
                  QString msg = tr("A playlist with that name already exists.\nPlease use another name:");
                  plName = QInputDialog::getText(this, tr("Save playlist as..."),
                                                               msg, QLineEdit::Normal, "", &ok);
            }
            else MPDCache::instance()->deletePlaylist(plName);
      }
}

MPDSongList PlaylistView::selectedSongs() const {
      Q_ASSERT(m_model);
      return m_model->songs(selectedIndexes());
}

// Set up custom drop indicator, since the default one does not behave as I wish.
void PlaylistView::dragMoveEvent(QDragMoveEvent *e) {
      Q_ASSERT(m_model);
      AbstractList::dragMoveEvent(e);
      if (m_model->rowCount() < 1) // The list is empty, draw nothing
            return;

      startAutoScroll();

      QModelIndex mouseIndex = indexAt(e->pos());
      if (!mouseIndex.isValid())
            mouseIndex = m_model->index(m_model->rowCount() - 1, 0);

      QRect itemRect = visualRect(mouseIndex);

      int y = itemRect.bottom();
      const int halfy = itemRect.y() + itemRect.height() / 2;

      if (mouseIndex.row() == 0 && e->pos().y() < halfy) {
            // We are at first song, and halfway above item, draw line on top
            y = itemRect.top();
            m_model->setTopDrop(true);
      } else
            m_model->setTopDrop(false);

      m_dropLine = QLine(0, y, viewport()->width(), y);
      setDirtyRegion(visibleRegion());
      repaint();
}

// Remove drop indicator
void PlaylistView::dropEvent(QDropEvent *e) {
      AbstractList::dropEvent(e);
      m_dropLine = QLine();
      setDirtyRegion(visibleRegion());
      repaint();
}

// Remove drop indicator
void PlaylistView::dragLeaveEvent(QDragLeaveEvent *e) {
      AbstractList::dragLeaveEvent(e);
      m_dropLine = QLine();
      setDirtyRegion(visibleRegion());
      repaint();
}

// Queue
void PlaylistView::queueSelectedSong() {
      m_model->toggleQueue(selectedIndexes());
}

void PlaylistView::setFilter(const QString &needle) {
      m_model->setFilter(needle);
}

Generated by  Doxygen 1.6.0   Back to index