summaryrefslogtreecommitdiff
path: root/src/playlist.cpp
diff options
context:
space:
mode:
authorMaia Kozheva <sikon@ubuntu.com>2009-11-20 18:22:19 +0600
committerMaia Kozheva <sikon@ubuntu.com>2009-11-20 18:22:19 +0600
commit263b32f108c15cd1c55a8f4eb4704fac6553f1ac (patch)
tree1c49e7848aa2d3d64a9d9b96b8852cb1884da2f7 /src/playlist.cpp
Imported Upstream version 0.6.8
Diffstat (limited to 'src/playlist.cpp')
-rw-r--r--src/playlist.cpp1356
1 files changed, 1356 insertions, 0 deletions
diff --git a/src/playlist.cpp b/src/playlist.cpp
new file mode 100644
index 0000000..cbb1148
--- /dev/null
+++ b/src/playlist.cpp
@@ -0,0 +1,1356 @@
+/* smplayer, GUI front-end for mplayer.
+ Copyright (C) 2006-2009 Ricardo Villalba <rvm@escomposlinux.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "playlist.h"
+
+#include <QToolBar>
+#include <QFile>
+#include <QTextStream>
+#include <QDir>
+#include <QFileInfo>
+#include <QMessageBox>
+#include <QPushButton>
+#include <QRegExp>
+#include <QMenu>
+#include <QDateTime>
+#include <QSettings>
+#include <QInputDialog>
+#include <QToolButton>
+#include <QTimer>
+#include <QVBoxLayout>
+#include <QUrl>
+#include <QDragEnterEvent>
+#include <QDropEvent>
+#include <QHeaderView>
+#include <QTextCodec>
+#include <QApplication>
+
+#include "mytablewidget.h"
+#include "myaction.h"
+#include "filedialog.h"
+#include "helper.h"
+#include "images.h"
+#include "preferences.h"
+#include "version.h"
+#include "global.h"
+#include "core.h"
+#include "extensions.h"
+#include "guiconfig.h"
+#include "playlistpreferences.h"
+
+#include <stdlib.h>
+
+#if USE_INFOPROVIDER
+#include "infoprovider.h"
+#endif
+
+#define DRAG_ITEMS 0
+
+#define COL_PLAY 0
+#define COL_NAME 1
+#define COL_TIME 2
+
+using namespace Global;
+
+
+Playlist::Playlist( Core *c, QWidget * parent, Qt::WindowFlags f)
+ : QWidget(parent,f)
+{
+ save_playlist_in_config = true;
+ recursive_add_directory = false;
+#ifdef Q_OS_WIN
+ automatically_get_info = false;
+#else
+ automatically_get_info = true;
+#endif
+ play_files_from_start = true;
+
+ automatically_play_next = true;
+
+ row_spacing = -1; // Default height
+
+ modified = false;
+
+ core = c;
+ playlist_path = "";
+ latest_dir = "";
+
+ createTable();
+ createActions();
+ createToolbar();
+
+ connect( core, SIGNAL(mediaFinished()), this, SLOT(playNext()), Qt::QueuedConnection );
+ connect( core, SIGNAL(mediaLoaded()), this, SLOT(getMediaInfo()) );
+
+ QVBoxLayout *layout = new QVBoxLayout;
+ layout->addWidget( listView );
+ layout->addWidget( toolbar );
+ setLayout(layout);
+
+ clear();
+
+ retranslateStrings();
+
+#if !DOCK_PLAYLIST
+ setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Expanding );
+ adjustSize();
+#else
+ //setSizePolicy( QSizePolicy::Maximum, QSizePolicy::Expanding );
+ //setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
+ setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred );
+#endif
+
+ setAcceptDrops(true);
+ setAttribute(Qt::WA_NoMousePropagation);
+
+ // Random seed
+ QTime t;
+ t.start();
+ srand( t.hour() * 3600 + t.minute() * 60 + t.second() );
+
+ loadSettings();
+
+ // Ugly hack to avoid to play next item automatically
+ if (!automatically_play_next) {
+ disconnect( core, SIGNAL(mediaFinished()), this, SLOT(playNext()) );
+ }
+
+ // Save config every 5 minutes.
+ save_timer = new QTimer(this);
+ connect( save_timer, SIGNAL(timeout()), this, SLOT(maybeSaveSettings()) );
+ save_timer->start( 5 * 60000 );
+}
+
+Playlist::~Playlist() {
+ saveSettings();
+}
+
+void Playlist::setModified(bool mod) {
+ qDebug("Playlist::setModified: %d", mod);
+
+ modified = mod;
+ emit modifiedChanged(modified);
+}
+
+void Playlist::createTable() {
+ listView = new MyTableWidget( 0, COL_TIME + 1, this);
+ listView->setObjectName("playlist_table");
+ listView->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
+ listView->setSelectionBehavior(QAbstractItemView::SelectRows);
+ listView->setSelectionMode(QAbstractItemView::ExtendedSelection);
+ listView->setContextMenuPolicy( Qt::CustomContextMenu );
+ listView->setShowGrid(false);
+ listView->setSortingEnabled(false);
+ //listView->setAlternatingRowColors(true);
+ listView->horizontalHeader()->setResizeMode(QHeaderView::Interactive);
+ listView->horizontalHeader()->setResizeMode(COL_NAME, QHeaderView::Stretch);
+ /*
+ listView->horizontalHeader()->setResizeMode(COL_TIME, QHeaderView::ResizeToContents);
+ listView->horizontalHeader()->setResizeMode(COL_PLAY, QHeaderView::ResizeToContents);
+ */
+ listView->setIconSize( Images::icon("ok").size() );
+
+#if DRAG_ITEMS
+ listView->setSelectionMode(QAbstractItemView::SingleSelection);
+ listView->setDragEnabled(true);
+ listView->setAcceptDrops(true);
+ listView->setDropIndicatorShown(true);
+ listView->setDragDropMode(QAbstractItemView::InternalMove);
+#endif
+
+ connect( listView, SIGNAL(cellActivated(int,int)),
+ this, SLOT(itemDoubleClicked(int)) );
+}
+
+void Playlist::createActions() {
+ openAct = new MyAction(this, "pl_open", false);
+ connect( openAct, SIGNAL(triggered()), this, SLOT(load()) );
+
+ saveAct = new MyAction(this, "pl_save", false);
+ connect( saveAct, SIGNAL(triggered()), this, SLOT(save()) );
+
+ playAct = new MyAction(this, "pl_play", false);
+ connect( playAct, SIGNAL(triggered()), this, SLOT(playCurrent()) );
+
+ nextAct = new MyAction(Qt::Key_N /*Qt::Key_Greater*/, this, "pl_next", false);
+ connect( nextAct, SIGNAL(triggered()), this, SLOT(playNext()) );
+
+ prevAct = new MyAction(Qt::Key_P /*Qt::Key_Less*/, this, "pl_prev", false);
+ connect( prevAct, SIGNAL(triggered()), this, SLOT(playPrev()) );
+
+ moveUpAct = new MyAction(this, "pl_move_up", false);
+ connect( moveUpAct, SIGNAL(triggered()), this, SLOT(upItem()) );
+
+ moveDownAct = new MyAction(this, "pl_move_down", false);
+ connect( moveDownAct, SIGNAL(triggered()), this, SLOT(downItem()) );
+
+ repeatAct = new MyAction(this, "pl_repeat", false);
+ repeatAct->setCheckable(true);
+
+ shuffleAct = new MyAction(this, "pl_shuffle", false);
+ shuffleAct->setCheckable(true);
+
+ preferencesAct = new MyAction(this, "pl_preferences", false);
+ connect( preferencesAct, SIGNAL(triggered()), this, SLOT(editPreferences()) );
+
+ // Add actions
+ addCurrentAct = new MyAction(this, "pl_add_current", false);
+ connect( addCurrentAct, SIGNAL(triggered()), this, SLOT(addCurrentFile()) );
+
+ addFilesAct = new MyAction(this, "pl_add_files", false);
+ connect( addFilesAct, SIGNAL(triggered()), this, SLOT(addFiles()) );
+
+ addDirectoryAct = new MyAction(this, "pl_add_directory", false);
+ connect( addDirectoryAct, SIGNAL(triggered()), this, SLOT(addDirectory()) );
+
+ // Remove actions
+ removeSelectedAct = new MyAction(this, "pl_remove_selected", false);
+ connect( removeSelectedAct, SIGNAL(triggered()), this, SLOT(removeSelected()) );
+
+ removeAllAct = new MyAction(this, "pl_remove_all", false);
+ connect( removeAllAct, SIGNAL(triggered()), this, SLOT(removeAll()) );
+
+ // Edit
+ editAct = new MyAction(this, "pl_edit", false);
+ connect( editAct, SIGNAL(triggered()), this, SLOT(editCurrentItem()) );
+}
+
+void Playlist::createToolbar() {
+ toolbar = new QToolBar(this);
+ toolbar->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum );
+
+ toolbar->addAction(openAct);
+ toolbar->addAction(saveAct);;
+ toolbar->addSeparator();
+
+ add_menu = new QMenu( this );
+ add_menu->addAction(addCurrentAct);
+ add_menu->addAction(addFilesAct );
+ add_menu->addAction(addDirectoryAct);
+
+ add_button = new QToolButton( this );
+ add_button->setMenu( add_menu );
+ add_button->setPopupMode(QToolButton::InstantPopup);
+
+ remove_menu = new QMenu( this );
+ remove_menu->addAction(removeSelectedAct);
+ remove_menu->addAction(removeAllAct);
+
+ remove_button = new QToolButton( this );
+ remove_button->setMenu( remove_menu );
+ remove_button->setPopupMode(QToolButton::InstantPopup);
+
+ toolbar->addWidget(add_button);
+ toolbar->addWidget(remove_button);
+
+ toolbar->addSeparator();
+ toolbar->addAction(playAct);
+ toolbar->addSeparator();
+ toolbar->addAction(prevAct);
+ toolbar->addAction(nextAct);
+ toolbar->addSeparator();
+ toolbar->addAction(repeatAct);
+ toolbar->addAction(shuffleAct);
+ toolbar->addSeparator();
+ toolbar->addAction(moveUpAct);
+ toolbar->addAction(moveDownAct);
+ toolbar->addSeparator();
+ toolbar->addAction(preferencesAct);
+
+ // Popup menu
+ popup = new QMenu(this);
+ popup->addAction(playAct);
+ popup->addAction(removeSelectedAct);
+ popup->addAction(editAct);
+
+ connect( listView, SIGNAL(customContextMenuRequested(const QPoint &)),
+ this, SLOT(showPopup(const QPoint &)) );
+}
+
+void Playlist::retranslateStrings() {
+ listView->setHorizontalHeaderLabels( QStringList() << " " <<
+ tr("Name") << tr("Length") );
+
+ openAct->change( Images::icon("open"), tr("&Load") );
+ saveAct->change( Images::icon("save"), tr("&Save") );
+
+ playAct->change( tr("&Play") );
+
+ nextAct->change( tr("&Next") );
+ prevAct->change( tr("Pre&vious") );
+
+ if (qApp->isLeftToRight()) {
+ playAct->setIcon( Images::icon("play") );
+ nextAct->setIcon( Images::icon("next") );
+ prevAct->setIcon( Images::icon("previous") );
+ } else {
+ playAct->setIcon( Images::flippedIcon("play") );
+ nextAct->setIcon( Images::flippedIcon("next") );
+ prevAct->setIcon( Images::flippedIcon("previous") );
+ }
+
+ moveUpAct->change( Images::icon("up"), tr("Move &up") );
+ moveDownAct->change( Images::icon("down"), tr("Move &down") );
+
+ repeatAct->change( Images::icon("repeat"), tr("&Repeat") );
+ shuffleAct->change( Images::icon("shuffle"), tr("S&huffle") );
+
+ preferencesAct->change( Images::icon("prefs"), tr("Preferences") );
+
+ // Add actions
+ addCurrentAct->change( tr("Add &current file") );
+ addFilesAct->change( tr("Add &file(s)") );
+ addDirectoryAct->change( tr("Add &directory") );
+
+ // Remove actions
+ removeSelectedAct->change( tr("Remove &selected") );
+ removeAllAct->change( tr("Remove &all") );
+
+ // Edit
+ editAct->change( tr("&Edit") );
+
+ // Tool buttons
+ add_button->setIcon( Images::icon("plus") );
+ add_button->setToolTip( tr("Add...") );
+ remove_button->setIcon( Images::icon("minus") );
+ remove_button->setToolTip( tr("Remove...") );
+
+ // Icon
+ setWindowIcon( Images::icon("logo", 64) );
+ setWindowTitle( tr( "SMPlayer - Playlist" ) );
+}
+
+void Playlist::list() {
+ qDebug("Playlist::list");
+
+ PlaylistItemList::iterator it;
+ for ( it = pl.begin(); it != pl.end(); ++it ) {
+ qDebug( "filename: '%s', name: '%s' duration: %f",
+ (*it).filename().toUtf8().data(), (*it).name().toUtf8().data(),
+ (*it).duration() );
+ }
+}
+
+void Playlist::updateView() {
+ qDebug("Playlist::updateView");
+
+ listView->setRowCount( pl.count() );
+
+ //QString number;
+ QString name;
+ QString time;
+
+ for (int n=0; n < pl.count(); n++) {
+ name = pl[n].name();
+ if (name.isEmpty()) name = pl[n].filename();
+ time = Helper::formatTime( (int) pl[n].duration() );
+
+ //listView->setText(n, COL_POS, number);
+ qDebug("Playlist::updateView: name: '%s'", name.toUtf8().data());
+ listView->setText(n, COL_NAME, name);
+ listView->setText(n, COL_TIME, time);
+
+ if (pl[n].played()) {
+ listView->setIcon(n, COL_PLAY, Images::icon("ok") );
+ } else {
+ listView->setIcon(n, COL_PLAY, QPixmap() );
+ }
+
+ if (row_spacing > -1) listView->setRowHeight(n, listView->font().pointSize() + row_spacing);
+ }
+ //listView->resizeColumnsToContents();
+ listView->resizeColumnToContents(COL_PLAY);
+ listView->resizeColumnToContents(COL_TIME);
+
+ setCurrentItem(current_item);
+
+ //adjustSize();
+}
+
+void Playlist::setCurrentItem(int current) {
+ QIcon play_icon;
+ if (qApp->isLeftToRight()) {
+ play_icon = Images::icon("play");
+ } else {
+ play_icon = Images::flippedIcon("play");
+ }
+
+ int old_current = current_item;
+ current_item = current;
+
+ if ((current_item > -1) && (current_item < pl.count())) {
+ pl[current_item].setPlayed(TRUE);
+ }
+
+ if ( (old_current >= 0) && (old_current < listView->rowCount()) ) {
+ listView->setIcon(old_current, COL_PLAY, QPixmap() );
+ }
+
+ if ( (current_item >= 0) && (current_item < listView->rowCount()) ) {
+ listView->setIcon(current_item, COL_PLAY, play_icon );
+ }
+ //if (current_item >= 0) listView->selectRow(current_item);
+ if (current_item >= 0) {
+ listView->clearSelection();
+ listView->setCurrentCell( current_item, 0);
+ }
+}
+
+void Playlist::clear() {
+ pl.clear();
+
+ listView->clearContents();
+ listView->setRowCount(0);
+
+ setCurrentItem(0);
+
+ setModified( false );
+}
+
+int Playlist::count() {
+ return pl.count();
+}
+
+bool Playlist::isEmpty() {
+ return pl.isEmpty();
+}
+
+void Playlist::addItem(QString filename, QString name, double duration) {
+ qDebug("Playlist::addItem: '%s'", filename.toUtf8().data());
+
+ #ifdef Q_OS_WIN
+ filename = Helper::changeSlashes(filename);
+ #endif
+
+ // Test if already is in the list
+ bool exists = false;
+ for ( int n = 0; n < pl.count(); n++) {
+ if ( pl[n].filename() == filename ) {
+ exists = true;
+ int last_item = pl.count()-1;
+ pl.move(n, last_item);
+ qDebug("Playlist::addItem: item already in list (%d), moved to %d", n, last_item);
+ if (current_item > -1) {
+ if (current_item > n) current_item--;
+ else
+ if (current_item == n) current_item = last_item;
+ }
+ break;
+ }
+ }
+
+ if (!exists) {
+ if (name.isEmpty()) {
+ QFileInfo fi(filename);
+ // Let's see if it looks like a file (no dvd://1 or something)
+ if (filename.indexOf(QRegExp("^.*://.*")) == -1) {
+ // Local file
+ name = fi.fileName(); //fi.baseName(TRUE);
+ } else {
+ // Stream
+ name = filename;
+ }
+ }
+ pl.append( PlaylistItem(filename, name, duration) );
+ //setModified( true ); // Better set the modified on a higher level
+ } else {
+ qDebug("Playlist::addItem: item not added, already in the list");
+ }
+}
+
+void Playlist::load_m3u(QString file) {
+ qDebug("Playlist::load_m3u");
+
+ bool utf8 = (QFileInfo(file).suffix().toLower() == "m3u8");
+
+ QRegExp m3u_id("^#EXTM3U|^#M3U");
+ QRegExp info("^#EXTINF:(.*),(.*)");
+
+ QFile f( file );
+ if ( f.open( QIODevice::ReadOnly ) ) {
+ playlist_path = QFileInfo(file).path();
+
+ clear();
+ QString filename="";
+ QString name="";
+ double duration=0;
+
+ QTextStream stream( &f );
+
+ if (utf8)
+ stream.setCodec("UTF-8");
+ else
+ stream.setCodec(QTextCodec::codecForLocale());
+
+ QString line;
+ while ( !stream.atEnd() ) {
+ line = stream.readLine(); // line of text excluding '\n'
+ qDebug( " * line: '%s'", line.toUtf8().data() );
+ if (m3u_id.indexIn(line)!=-1) {
+ //#EXTM3U
+ // Ignore line
+ }
+ else
+ if (info.indexIn(line)!=-1) {
+ duration = info.cap(1).toDouble();
+ name = info.cap(2);
+ qDebug(" * name: '%s', duration: %f", name.toUtf8().data(), duration );
+ }
+ else
+ if (line.startsWith("#")) {
+ // Comment
+ // Ignore
+ } else {
+ filename = line;
+ QFileInfo fi(filename);
+ if (fi.exists()) {
+ filename = fi.absoluteFilePath();
+ }
+ if (!fi.exists()) {
+ if (QFileInfo( playlist_path + "/" + filename).exists() ) {
+ filename = playlist_path + "/" + filename;
+ }
+ }
+ addItem( filename, name, duration );
+ name="";
+ duration = 0;
+ }
+ }
+ f.close();
+ list();
+ updateView();
+
+ setModified( false );
+
+ startPlay();
+ }
+}
+
+void Playlist::load_pls(QString file) {
+ qDebug("Playlist::load_pls");
+
+ if (!QFile::exists(file)) {
+ qDebug("Playlist::load_pls: '%s' doesn't exist, doing nothing", file.toUtf8().constData());
+ return;
+ }
+
+ playlist_path = QFileInfo(file).path();
+
+ QSettings set(file, QSettings::IniFormat);
+ set.beginGroup("playlist");
+
+ if (set.status() == QSettings::NoError) {
+ clear();
+ QString filename;
+ QString name;
+ double duration;
+
+ int num_items = set.value("NumberOfEntries", 0).toInt();
+
+ for (int n=0; n < num_items; n++) {
+ filename = set.value("File"+QString::number(n+1), "").toString();
+ name = set.value("Title"+QString::number(n+1), "").toString();
+ duration = (double) set.value("Length"+QString::number(n+1), 0).toInt();
+
+ QFileInfo fi(filename);
+ if (fi.exists()) {
+ filename = fi.absoluteFilePath();
+ }
+ if (!fi.exists()) {
+ if (QFileInfo( playlist_path + "/" + filename).exists() ) {
+ filename = playlist_path + "/" + filename;
+ }
+ }
+ addItem( filename, name, duration );
+ }
+ }
+
+ set.endGroup();
+
+ list();
+ updateView();
+
+ setModified( false );
+
+ if (set.status() == QSettings::NoError) startPlay();
+}
+
+bool Playlist::save_m3u(QString file) {
+ qDebug("Playlist::save_m3u: '%s'", file.toUtf8().data());
+
+ QString dir_path = QFileInfo(file).path();
+ if (!dir_path.endsWith("/")) dir_path += "/";
+
+ #ifdef Q_OS_WIN
+ dir_path = Helper::changeSlashes(dir_path);
+ #endif
+
+ qDebug(" * dirPath: '%s'", dir_path.toUtf8().data());
+
+ bool utf8 = (QFileInfo(file).suffix().toLower() == "m3u8");
+
+ QFile f( file );
+ if ( f.open( QIODevice::WriteOnly ) ) {
+ QTextStream stream( &f );
+
+ if (utf8)
+ stream.setCodec("UTF-8");
+ else
+ stream.setCodec(QTextCodec::codecForLocale());
+
+ QString filename;
+
+ stream << "#EXTM3U" << "\n";
+ stream << "# Playlist created by SMPlayer " << smplayerVersion() << " \n";
+
+ PlaylistItemList::iterator it;
+ for ( it = pl.begin(); it != pl.end(); ++it ) {
+ filename = (*it).filename();
+ #ifdef Q_OS_WIN
+ filename = Helper::changeSlashes(filename);
+ #endif
+ stream << "#EXTINF:";
+ stream << (*it).duration() << ",";
+ stream << (*it).name() << "\n";
+ // Try to save the filename as relative instead of absolute
+ if (filename.startsWith( dir_path )) {
+ filename = filename.mid( dir_path.length() );
+ }
+ stream << filename << "\n";
+ }
+ f.close();
+
+ setModified( false );
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+bool Playlist::save_pls(QString file) {
+ qDebug("Playlist::save_pls: '%s'", file.toUtf8().data());
+
+ QString dir_path = QFileInfo(file).path();
+ if (!dir_path.endsWith("/")) dir_path += "/";
+
+ #ifdef Q_OS_WIN
+ dir_path = Helper::changeSlashes(dir_path);
+ #endif
+
+ qDebug(" * dirPath: '%s'", dir_path.toUtf8().data());
+
+ QSettings set(file, QSettings::IniFormat);
+ set.beginGroup( "playlist");
+
+ QString filename;
+
+ PlaylistItemList::iterator it;
+ for ( int n=0; n < pl.count(); n++ ) {
+ filename = pl[n].filename();
+ #ifdef Q_OS_WIN
+ filename = Helper::changeSlashes(filename);
+ #endif
+
+ // Try to save the filename as relative instead of absolute
+ if (filename.startsWith( dir_path )) {
+ filename = filename.mid( dir_path.length() );
+ }
+
+ set.setValue("File"+QString::number(n+1), filename);
+ set.setValue("Title"+QString::number(n+1), pl[n].name());
+ set.setValue("Length"+QString::number(n+1), (int) pl[n].duration());
+ }
+
+ set.setValue("NumberOfEntries", pl.count());
+ set.setValue("Version", 2);
+
+ set.endGroup();
+
+ set.sync();
+
+ bool ok = (set.status() == QSettings::NoError);
+ if (ok) setModified( false );
+
+ return ok;
+}
+
+
+void Playlist::load() {
+ if (maybeSave()) {
+ Extensions e;
+ QString s = MyFileDialog::getOpenFileName(
+ this, tr("Choose a file"),
+ lastDir(),
+ tr("Playlists") + e.playlist().forFilter());
+
+ if (!s.isEmpty()) {
+ latest_dir = QFileInfo(s).absolutePath();
+
+ if (QFileInfo(s).suffix().toLower() == "pls")
+ load_pls(s);
+ else
+ load_m3u(s);
+ }
+ }
+}
+
+bool Playlist::save() {
+ Extensions e;
+ QString s = MyFileDialog::getSaveFileName(
+ this, tr("Choose a filename"),
+ lastDir(),
+ tr("Playlists") + e.playlist().forFilter());
+
+ if (!s.isEmpty()) {
+ // If filename has no extension, add it
+ if (QFileInfo(s).suffix().isEmpty()) {
+ s = s + ".m3u";
+ }
+ if (QFileInfo(s).exists()) {
+ int res = QMessageBox::question( this,
+ tr("Confirm overwrite?"),
+ tr("The file %1 already exists.\n"
+ "Do you want to overwrite?").arg(s),
+ QMessageBox::Yes,
+ QMessageBox::No,
+ QMessageBox::NoButton);
+ if (res == QMessageBox::No ) {
+ return false;
+ }
+ }
+ latest_dir = QFileInfo(s).absolutePath();
+
+ if (QFileInfo(s).suffix().toLower() == "pls")
+ return save_pls(s);
+ else
+ return save_m3u(s);
+
+ } else {
+ return false;
+ }
+}
+
+bool Playlist::maybeSave() {
+ if (!isModified()) return true;
+
+ int res = QMessageBox::question( this,
+ tr("Playlist modified"),
+ tr("There are unsaved changes, do you want to save the playlist?"),
+ QMessageBox::Yes,
+ QMessageBox::No,
+ QMessageBox::Cancel);
+
+ switch (res) {
+ case QMessageBox::No : return true; // Discard changes
+ case QMessageBox::Cancel : return false; // Cancel operation
+ default : return save();
+ }
+}
+
+void Playlist::playCurrent() {
+ int current = listView->currentRow();
+ if (current > -1) {
+ playItem(current);
+ }
+}
+
+void Playlist::itemDoubleClicked(int row) {
+ qDebug("Playlist::itemDoubleClicked: row: %d", row );
+ playItem(row);
+}
+
+void Playlist::showPopup(const QPoint & pos) {
+ qDebug("Playlist::showPopup: x: %d y: %d", pos.x(), pos.y() );
+
+ if (!popup->isVisible()) {
+ popup->move( listView->viewport()->mapToGlobal(pos) );
+ popup->show();
+ }
+}
+
+void Playlist::startPlay() {
+ // Start to play
+ if ( shuffleAct->isChecked() )
+ playItem( chooseRandomItem() );
+ else
+ playItem(0);
+}
+
+void Playlist::playItem( int n ) {
+ qDebug("Playlist::playItem: %d (count:%d)", n, pl.count());
+
+ if ( (n >= pl.count()) || (n < 0) ) {
+ qDebug("Playlist::playItem: out of range");
+ emit playlistEnded();
+ return;
+ }
+
+ qDebug(" playlist_path: '%s'", playlist_path.toUtf8().data() );
+
+ QString filename = pl[n].filename();
+ QString filename_with_path = playlist_path + "/" + filename;
+
+ if (!filename.isEmpty()) {
+ //pl[n].setPlayed(TRUE);
+ setCurrentItem(n);
+ if (play_files_from_start)
+ core->open(filename, 0);
+ else
+ core->open(filename);
+ }
+
+}
+
+void Playlist::playNext() {
+ qDebug("Playlist::playNext");
+
+ if (shuffleAct->isChecked()) {
+ // Shuffle
+ int chosen_item = chooseRandomItem();
+ if (chosen_item == -1) {
+ clearPlayedTag();
+ if (repeatAct->isChecked()) chosen_item = chooseRandomItem();
+ }
+ playItem( chosen_item );
+ } else {
+ bool finished_list = (current_item+1 >= pl.count());
+ if (finished_list) clearPlayedTag();
+
+ if ( (repeatAct->isChecked()) && (finished_list) ) {
+ playItem(0);
+ } else {
+ playItem( current_item+1 );
+ }
+ }
+}
+
+void Playlist::playPrev() {
+ qDebug("Playlist::playPrev");
+ if (current_item > 0) {
+ playItem( current_item-1 );
+ } else {
+ if (pl.count() > 1) playItem( pl.count() -1 );
+ }
+}
+
+void Playlist::getMediaInfo() {
+ qDebug("Playlist:: getMediaInfo");
+
+ QString filename = core->mdat.filename;
+ double duration = core->mdat.duration;
+ QString name = core->mdat.clip_name;
+ QString artist = core->mdat.clip_artist;
+
+ #ifdef Q_OS_WIN
+ filename = Helper::changeSlashes(filename);
+ #endif
+
+ if (name.isEmpty()) {
+ QFileInfo fi(filename);
+ if (fi.exists()) {
+ // Local file
+ name = fi.fileName();
+ } else {
+ // Stream
+ name = filename;
+ }
+ }
+ if (!artist.isEmpty()) name = artist + " - " + name;
+
+ int pos=0;
+ PlaylistItemList::iterator it;
+ for ( it = pl.begin(); it != pl.end(); ++it ) {
+ if ( (*it).filename() == filename ) {
+ if ((*it).duration()<1) {
+ if (!name.isEmpty()) {
+ (*it).setName(name);
+ }
+ (*it).setDuration(duration);
+ //setModified( true );
+ }
+ else
+ // Edited name (sets duration to 1)
+ if ((*it).duration()==1) {
+ (*it).setDuration(duration);
+ //setModified( true );
+ }
+ setCurrentItem(pos);
+ }
+ pos++;
+ }
+ updateView();
+}
+
+// Add current file to playlist
+void Playlist::addCurrentFile() {
+ qDebug("Playlist::addCurrentFile");
+ if (!core->mdat.filename.isEmpty()) {
+ addItem( core->mdat.filename, "", 0 );
+ getMediaInfo();
+ }
+}
+
+void Playlist::addFiles() {
+ QStringList files = MyFileDialog::getOpenFileNames(
+ this, tr("Select one or more files to open"),
+ lastDir(),
+ tr("All files") +" (*.*)" );
+
+ if (files.count()!=0) addFiles(files);
+}
+
+void Playlist::addFiles(QStringList files, AutoGetInfo auto_get_info) {
+ qDebug("Playlist::addFiles");
+
+#if USE_INFOPROVIDER
+ bool get_info = (auto_get_info == GetInfo);
+ if (auto_get_info == UserDefined) {
+ get_info = automatically_get_info;
+ }
+
+ MediaData data;
+ setCursor(Qt::WaitCursor);
+#endif
+
+ QStringList::Iterator it = files.begin();
+ while( it != files.end() ) {
+#if USE_INFOPROVIDER
+ if ( (get_info) && (QFile::exists((*it))) ) {
+ data = InfoProvider::getInfo( (*it) );
+ addItem( (*it), data.displayName(), data.duration );
+ //updateView();
+ //qApp->processEvents();
+ } else {
+ addItem( (*it), "", 0 );
+ }
+#else
+ addItem( (*it), "", 0 );
+#endif
+
+ if (QFile::exists(*it)) {
+ latest_dir = QFileInfo((*it)).absolutePath();
+ }
+
+ ++it;
+ }
+#if USE_INFOPROVIDER
+ unsetCursor();
+#endif
+ updateView();
+
+ qDebug( "Playlist::addFiles: latest_dir: '%s'", latest_dir.toUtf8().constData() );
+}
+
+void Playlist::addFile(QString file, AutoGetInfo auto_get_info) {
+ addFiles( QStringList() << file, auto_get_info );
+}
+
+void Playlist::addDirectory() {
+ QString s = MyFileDialog::getExistingDirectory(
+ this, tr("Choose a directory"),
+ lastDir() );
+
+ if (!s.isEmpty()) {
+ addDirectory(s);
+ latest_dir = s;
+ }
+}
+
+void Playlist::addOneDirectory(QString dir) {
+ QStringList filelist;
+
+ Extensions e;
+ QRegExp rx_ext(e.multimedia().forRegExp());
+ rx_ext.setCaseSensitivity(Qt::CaseInsensitive);
+
+ QStringList dir_list = QDir(dir).entryList();
+
+ QString filename;
+ QStringList::Iterator it = dir_list.begin();
+ while( it != dir_list.end() ) {
+ filename = dir;
+ if (filename.right(1)!="/") filename += "/";
+ filename += (*it);
+ QFileInfo fi(filename);
+ if (!fi.isDir()) {
+ if (rx_ext.indexIn(fi.suffix()) > -1) {
+ filelist << filename;
+ }
+ }
+ ++it;
+ }
+ addFiles(filelist);
+}
+
+void Playlist::addDirectory(QString dir) {
+ addOneDirectory(dir);
+
+ if (recursive_add_directory) {
+ QFileInfoList dir_list = QDir(dir).entryInfoList(QStringList() << "*", QDir::AllDirs | QDir::NoDotAndDotDot);
+ for (int n=0; n < dir_list.count(); n++) {
+ if (dir_list[n].isDir()) {
+ qDebug("Playlist::addDirectory: adding directory: %s", dir_list[n].filePath().toUtf8().data());
+ addDirectory(dir_list[n].filePath());
+ }
+ }
+ }
+}
+
+// Remove selected items
+void Playlist::removeSelected() {
+ qDebug("Playlist::removeSelected");
+
+ int first_selected = -1;
+ int number_previous_item = 0;
+
+ for (int n=0; n < listView->rowCount(); n++) {
+ if (listView->isSelected(n, 0)) {
+ qDebug(" row %d selected", n);
+ pl[n].setMarkForDeletion(TRUE);
+ number_previous_item++;
+ if (first_selected == -1) first_selected = n;
+ }
+ }
+
+ PlaylistItemList::iterator it;
+ for ( it = pl.begin(); it != pl.end(); ++it ) {
+ if ( (*it).markedForDeletion() ) {
+ qDebug("Remove '%s'", (*it).filename().toUtf8().data());
+ it = pl.erase(it);
+ it--;
+ setModified( true );
+ }
+ }
+
+
+ if (first_selected < current_item) {
+ current_item -= number_previous_item;
+ }
+
+ if (isEmpty()) setModified(false);
+ updateView();
+
+ if (first_selected >= listView->rowCount())
+ first_selected = listView->rowCount() - 1;
+
+ if ( ( first_selected > -1) && ( first_selected < listView->rowCount() ) ) {
+ listView->clearSelection();
+ listView->setCurrentCell( first_selected, 0);
+ //listView->selectRow( first_selected );
+ }
+}
+
+void Playlist::removeAll() {
+ /*
+ pl.clear();
+ updateView();
+ setModified( false );
+ */
+ clear();
+}
+
+void Playlist::clearPlayedTag() {
+ PlaylistItemList::iterator it;
+ for ( it = pl.begin(); it != pl.end(); ++it ) {
+ (*it).setPlayed(FALSE);
+ }
+ updateView();
+}
+
+int Playlist::chooseRandomItem() {
+ qDebug( "Playlist::chooseRandomItem");
+ QList <int> fi; //List of not played items (free items)
+
+ int n=0;
+ PlaylistItemList::iterator it;
+ for ( it = pl.begin(); it != pl.end(); ++it ) {
+ if (! (*it).played() ) fi.append(n);
+ n++;
+ }
+
+ qDebug(" * free items: %d", fi.count() );
+
+ if (fi.count()==0) return -1; // none free
+
+ qDebug(" * items: ");
+ for (int i=0; i < fi.count(); i++) {
+ qDebug(" * item: %d", fi[i]);
+ }
+
+ int selected = (int) ((double) fi.count() * rand()/(RAND_MAX+1.0));
+ qDebug(" * selected item: %d (%d)", selected, fi[selected]);
+ return fi[selected];
+}
+
+void Playlist::swapItems(int item1, int item2 ) {
+ PlaylistItem it1 = pl[item1];
+ pl[item1] = pl[item2];
+ pl[item2] = it1;
+ setModified( true );
+}
+
+
+void Playlist::upItem() {
+ qDebug("Playlist::upItem");
+
+ int current = listView->currentRow();
+ qDebug(" currentRow: %d", current );
+
+ if (current >= 1) {
+ swapItems( current, current-1 );
+ if (current_item == (current-1)) current_item = current;
+ else
+ if (current_item == current) current_item = current-1;
+ updateView();
+ listView->clearSelection();
+ listView->setCurrentCell( current-1, 0);
+ }
+}
+
+void Playlist::downItem() {
+ qDebug("Playlist::downItem");
+
+ int current = listView->currentRow();
+ qDebug(" currentRow: %d", current );
+
+ if ( (current > -1) && (current < (pl.count()-1)) ) {
+ swapItems( current, current+1 );
+ if (current_item == (current+1)) current_item = current;
+ else
+ if (current_item == current) current_item = current+1;
+ updateView();
+ listView->clearSelection();
+ listView->setCurrentCell( current+1, 0);
+ }
+}
+
+void Playlist::editCurrentItem() {
+ int current = listView->currentRow();
+ if (current > -1) editItem(current);
+}
+
+void Playlist::editItem(int item) {
+ QString current_name = pl[item].name();
+ if (current_name.isEmpty()) current_name = pl[item].filename();
+
+ bool ok;
+ QString text = QInputDialog::getText( this,
+ tr("Edit name"),
+ tr("Type the name that will be displayed in the playlist for this file:"),
+ QLineEdit::Normal,
+ current_name, &ok );
+ if ( ok && !text.isEmpty() ) {
+ // user entered something and pressed OK
+ pl[item].setName(text);
+
+ // If duration == 0 the name will be overwritten!
+ if (pl[item].duration()<1) pl[item].setDuration(1);
+ updateView();
+
+ setModified( true );
+ }
+}
+
+void Playlist::editPreferences() {
+ PlaylistPreferences d(this);
+
+ d.setDirectoryRecursion(recursive_add_directory);
+ d.setAutoGetInfo(automatically_get_info);
+ d.setSavePlaylistOnExit(save_playlist_in_config);
+ d.setPlayFilesFromStart(play_files_from_start);
+
+ if (d.exec() == QDialog::Accepted) {
+ recursive_add_directory = d.directoryRecursion();
+ automatically_get_info = d.autoGetInfo();
+ save_playlist_in_config = d.savePlaylistOnExit();
+ play_files_from_start = d.playFilesFromStart();
+ }
+}
+
+// Drag&drop
+void Playlist::dragEnterEvent( QDragEnterEvent *e ) {
+ qDebug("Playlist::dragEnterEvent");
+
+ if (e->mimeData()->hasUrls()) {
+ e->acceptProposedAction();
+ }
+}
+
+void Playlist::dropEvent( QDropEvent *e ) {
+ qDebug("Playlist::dropEvent");
+
+ QStringList files;
+
+ if (e->mimeData()->hasUrls()) {
+ QList <QUrl> l = e->mimeData()->urls();
+ QString s;
+ for (int n=0; n < l.count(); n++) {
+ if (l[n].isValid()) {
+ qDebug("Playlist::dropEvent: scheme: '%s'", l[n].scheme().toUtf8().data());
+ if (l[n].scheme() == "file")
+ s = l[n].toLocalFile();
+ else
+ s = l[n].toString();
+ /*
+ qDebug(" * '%s'", l[n].toString().toUtf8().data());
+ qDebug(" * '%s'", l[n].toLocalFile().toUtf8().data());
+ */
+ qDebug("Playlist::dropEvent: file: '%s'", s.toUtf8().data());
+ files.append(s);
+ }
+ }
+ }
+
+
+ QStringList only_files;
+ for (int n = 0; n < files.count(); n++) {
+ if ( QFileInfo( files[n] ).isDir() ) {
+ addDirectory( files[n] );
+ } else {
+ only_files.append( files[n] );
+ }
+ }
+ addFiles( only_files );
+}
+
+
+void Playlist::hideEvent( QHideEvent * ) {
+ emit visibilityChanged(false);
+}
+
+void Playlist::showEvent( QShowEvent * ) {
+ emit visibilityChanged(true);
+}
+
+void Playlist::closeEvent( QCloseEvent * e ) {
+ saveSettings();
+ e->accept();
+}
+
+
+void Playlist::maybeSaveSettings() {
+ qDebug("Playlist::maybeSaveSettings");
+ if (isModified()) saveSettings();
+}
+
+void Playlist::saveSettings() {
+ qDebug("Playlist::saveSettings");
+
+ QSettings * set = settings;
+
+ set->beginGroup( "playlist");
+
+ set->setValue( "repeat", repeatAct->isChecked() );
+ set->setValue( "shuffle", shuffleAct->isChecked() );
+
+ set->setValue( "auto_get_info", automatically_get_info );
+ set->setValue( "recursive_add_directory", recursive_add_directory );
+ set->setValue( "save_playlist_in_config", save_playlist_in_config );
+ set->setValue( "play_files_from_start", play_files_from_start );
+ set->setValue( "automatically_play_next", automatically_play_next );
+
+ set->setValue( "row_spacing", row_spacing );
+
+#if !DOCK_PLAYLIST
+ set->setValue( "size", size() );
+#endif
+ set->setValue( "latest_dir", latest_dir );
+
+ set->endGroup();
+
+ if (save_playlist_in_config) {
+ //Save current list
+ set->beginGroup( "playlist_contents");
+
+ set->setValue( "count", (int) pl.count() );
+ for ( int n=0; n < pl.count(); n++ ) {
+ set->setValue( QString("item_%1_filename").arg(n), pl[n].filename() );
+ set->setValue( QString("item_%1_duration").arg(n), pl[n].duration() );
+ set->setValue( QString("item_%1_name").arg(n), pl[n].name() );
+ }
+ set->setValue( "current_item", current_item );
+ set->setValue( "modified", modified );
+
+ set->endGroup();
+ }
+}
+
+void Playlist::loadSettings() {
+ qDebug("Playlist::loadSettings");
+
+ QSettings * set = settings;
+
+ set->beginGroup( "playlist");
+
+ repeatAct->setChecked( set->value( "repeat", repeatAct->isChecked() ).toBool() );
+ shuffleAct->setChecked( set->value( "shuffle", shuffleAct->isChecked() ).toBool() );
+
+ automatically_get_info = set->value( "auto_get_info", automatically_get_info ).toBool();
+ recursive_add_directory = set->value( "recursive_add_directory", recursive_add_directory ).toBool();
+ save_playlist_in_config = set->value( "save_playlist_in_config", save_playlist_in_config ).toBool();
+ play_files_from_start = set->value( "play_files_from_start", play_files_from_start ).toBool();
+ automatically_play_next = set->value( "automatically_play_next", automatically_play_next ).toBool();
+
+ row_spacing = set->value( "row_spacing", row_spacing ).toInt();
+
+#if !DOCK_PLAYLIST
+ resize( set->value("size", size()).toSize() );
+#endif
+
+ latest_dir = set->value( "latest_dir", latest_dir ).toString();
+
+ set->endGroup();
+
+ if (save_playlist_in_config) {
+ //Load latest list
+ set->beginGroup( "playlist_contents");
+
+ int count = set->value( "count", 0 ).toInt();
+ QString filename, name;
+ double duration;
+ for ( int n=0; n < count; n++ ) {
+ filename = set->value( QString("item_%1_filename").arg(n), "" ).toString();
+ duration = set->value( QString("item_%1_duration").arg(n), -1 ).toDouble();
+ name = set->value( QString("item_%1_name").arg(n), "" ).toString();
+ addItem( filename, name, duration );
+ }
+ setCurrentItem( set->value( "current_item", -1 ).toInt() );
+ setModified( set->value( "modified", false ).toBool() );
+ updateView();
+
+ set->endGroup();
+ }
+}
+
+QString Playlist::lastDir() {
+ QString last_dir = latest_dir;
+ if (last_dir.isEmpty()) last_dir = pref->latest_dir;
+ return last_dir;
+}
+
+// Language change stuff
+void Playlist::changeEvent(QEvent *e) {
+ if (e->type() == QEvent::LanguageChange) {
+ retranslateStrings();
+ } else {
+ QWidget::changeEvent(e);
+ }
+}
+
+#include "moc_playlist.cpp"