mirror of
https://github.com/RetroShare/RetroShare.git
synced 2024-12-27 00:19:25 -05:00
87344de7d4
git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@1850 b45a01b8-16f6-495d-af2f-9b41ad6348cc
1327 lines
33 KiB
C++
1327 lines
33 KiB
C++
/* smplayer, GUI front-end for mplayer.
|
|
Copyright (C) 2006-2008 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;
|
|
|
|
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();
|
|
|
|
// 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_small").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 ¤t 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_small") );
|
|
} else {
|
|
listView->setIcon(n, COL_PLAY, QPixmap() );
|
|
}
|
|
}
|
|
//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;
|
|
PlaylistItemList::iterator it;
|
|
for ( it = pl.begin(); it != pl.end(); ++it ) {
|
|
if ( (*it).filename() == filename ) {
|
|
exists = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!exists) {
|
|
if (name.isEmpty()) {
|
|
QFileInfo fi(filename);
|
|
if (fi.exists()) {
|
|
// 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(" Not added. File 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");
|
|
|
|
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 );
|
|
|
|
#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();
|
|
|
|
#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"
|