From 43ee25ac78884c3c579a555fee589f3677ea7f21 Mon Sep 17 00:00:00 2001 From: trialuser02 Date: Sat, 13 Dec 2008 18:14:00 +0000 Subject: moved playlist model to libqmmpui git-svn-id: http://svn.code.sf.net/p/qmmp-dev/code/trunk/qmmp@679 90c681e8-e032-0410-971d-27865f9a5e38 --- src/qmmpui/CMakeLists.txt | 14 +- src/qmmpui/abstractplaylist.cpp | 32 -- src/qmmpui/abstractplaylist.h | 38 -- src/qmmpui/fileloader.cpp | 116 +++++ src/qmmpui/fileloader.h | 72 ++++ src/qmmpui/playlistitem.cpp | 179 ++++++++ src/qmmpui/playlistitem.h | 74 ++++ src/qmmpui/playlistmodel.cpp | 910 ++++++++++++++++++++++++++++++++++++++++ src/qmmpui/playlistmodel.h | 353 ++++++++++++++++ src/qmmpui/playstate.cpp | 138 ++++++ src/qmmpui/playstate.h | 109 +++++ src/qmmpui/qmmpui.pro | 14 +- src/ui/CMakeLists.txt | 8 - src/ui/addurldialog.cpp | 2 +- src/ui/fileloader.cpp | 116 ----- src/ui/fileloader.h | 72 ---- src/ui/jumptotrackdialog.cpp | 2 +- src/ui/keyboardmanager.cpp | 3 +- src/ui/listwidget.cpp | 5 +- src/ui/mainwindow.cpp | 6 +- src/ui/mainwindow.h | 2 +- src/ui/playlist.cpp | 7 +- src/ui/playlistitem.cpp | 179 -------- src/ui/playlistitem.h | 74 ---- src/ui/playlistmodel.cpp | 910 ---------------------------------------- src/ui/playlistmodel.h | 353 ---------------- src/ui/playlisttitlebar.cpp | 3 +- src/ui/playstate.cpp | 138 ------ src/ui/playstate.h | 109 ----- src/ui/ui.pro | 7 - 30 files changed, 1989 insertions(+), 2056 deletions(-) delete mode 100644 src/qmmpui/abstractplaylist.cpp delete mode 100644 src/qmmpui/abstractplaylist.h create mode 100644 src/qmmpui/fileloader.cpp create mode 100644 src/qmmpui/fileloader.h create mode 100644 src/qmmpui/playlistitem.cpp create mode 100644 src/qmmpui/playlistitem.h create mode 100644 src/qmmpui/playlistmodel.cpp create mode 100644 src/qmmpui/playlistmodel.h create mode 100644 src/qmmpui/playstate.cpp create mode 100644 src/qmmpui/playstate.h delete mode 100644 src/ui/fileloader.cpp delete mode 100644 src/ui/fileloader.h delete mode 100644 src/ui/playlistitem.cpp delete mode 100644 src/ui/playlistitem.h delete mode 100644 src/ui/playlistmodel.cpp delete mode 100644 src/ui/playlistmodel.h delete mode 100644 src/ui/playstate.cpp delete mode 100644 src/ui/playstate.h (limited to 'src') diff --git a/src/qmmpui/CMakeLists.txt b/src/qmmpui/CMakeLists.txt index 96517cf0f..08b7a5c94 100644 --- a/src/qmmpui/CMakeLists.txt +++ b/src/qmmpui/CMakeLists.txt @@ -35,8 +35,11 @@ SET(libqmmpui_SRCS commandlinemanager.cpp filedialog.cpp qtfiledialog.cpp - abstractplaylist.cpp abstractplaylistitem.cpp + fileloader.cpp + playstate.cpp + playlistmodel.cpp + playlistitem.cpp ) SET(libqmmpui_MOC_HDRS @@ -50,8 +53,11 @@ SET(libqmmpui_MOC_HDRS filedialog.h filedialogfactory.h qtfiledialog.h - abstractplaylist.h abstractplaylistitem.h + fileloader.h + playstate.h + playlistmodel.h + playlistitem.h ) SET(libqmmpui_DEVEL_HDRS @@ -64,8 +70,10 @@ SET(libqmmpui_DEVEL_HDRS commandlineoption.h filedialog.h filedialogfactory.h - abstractplaylist.h + qtfiledialog.h abstractplaylistitem.h + playlistmodel.h + playlistitem.h ) diff --git a/src/qmmpui/abstractplaylist.cpp b/src/qmmpui/abstractplaylist.cpp deleted file mode 100644 index 607165426..000000000 --- a/src/qmmpui/abstractplaylist.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2008 by Ilya Kotov * - * forkotov02@hotmail.ru * - * * - * 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 "abstractplaylist.h" - -AbstractPlaylist::AbstractPlaylist(QObject *parent) - : QObject(parent) -{ -} - - -AbstractPlaylist::~AbstractPlaylist() -{ -} - - diff --git a/src/qmmpui/abstractplaylist.h b/src/qmmpui/abstractplaylist.h deleted file mode 100644 index 6190cd8b4..000000000 --- a/src/qmmpui/abstractplaylist.h +++ /dev/null @@ -1,38 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2008 by Ilya Kotov * - * forkotov02@hotmail.ru * - * * - * 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. * - ***************************************************************************/ -#ifndef ABSTRACTPLAYLIST_H -#define ABSTRACTPLAYLIST_H - -#include - -/** - @author Ilya Kotov -*/ -class AbstractPlaylist : public QObject -{ -Q_OBJECT -public: - AbstractPlaylist(QObject *parent = 0); - - ~AbstractPlaylist(); - -}; - -#endif diff --git a/src/qmmpui/fileloader.cpp b/src/qmmpui/fileloader.cpp new file mode 100644 index 000000000..ce5ccb56c --- /dev/null +++ b/src/qmmpui/fileloader.cpp @@ -0,0 +1,116 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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 + +#include "fileloader.h" +#include "playlistitem.h" + +FileLoader::FileLoader(QObject *parent) + : QThread(parent),m_files_to_load(),m_directory() +{ + m_filters = Decoder::nameFilters(); + m_finished = false; +} + + +FileLoader::~FileLoader() +{ + qWarning("FileLoader::~FileLoader()"); +} + + +void FileLoader::addFiles(const QStringList &files) +{ + if (files.isEmpty ()) + return; + + foreach(QString s, files) + { + /*if (s.startsWith("http://") || Decoder::supports(s)) + {*/ + //emit newPlayListItem(new PlayListItem(s)); + QList playList = Decoder::createPlayList(s); + foreach(FileInfo *info, playList) + emit newPlayListItem(new PlayListItem(info)); + //} + if (m_finished) return; + } +} + + +void FileLoader::addDirectory(const QString& s) +{ + QList playList; + QDir dir(s); + dir.setFilter(QDir::Files | QDir::Hidden | QDir::NoSymLinks); + dir.setSorting(QDir::Name); + QFileInfoList l = dir.entryInfoList(m_filters); + for (int i = 0; i < l.size(); ++i) + { + QFileInfo fileInfo = l.at(i); + QString suff = fileInfo.completeSuffix(); + list << fileInfo; + + /*if (Decoder::supports(fileInfo.absoluteFilePath ())) + {*/ + playList = Decoder::createPlayList(fileInfo.absoluteFilePath ()); + foreach(FileInfo *info, playList) + emit newPlayListItem(new PlayListItem(info)); + //emit newPlayListItem(new PlayListItem(fileInfo.absoluteFilePath ())); + //} + if (m_finished) return; + } + dir.setFilter(QDir::Dirs | QDir::NoDotAndDotDot); + dir.setSorting(QDir::Name); + l.clear(); + l = dir.entryInfoList(); + if (l.size() > 0) + for (int i = 0; i < l.size(); ++i) + { + QFileInfo fileInfo = l.at(i); + addDirectory(fileInfo.absoluteFilePath ()); + if (m_finished) return; + } +} + +void FileLoader::run() +{ + if (!m_files_to_load.isEmpty()) + addFiles(m_files_to_load); + else if (!m_directory.isEmpty()) + addDirectory(m_directory); +} + +void FileLoader::setFilesToLoad(const QStringList & l) +{ + m_files_to_load = l; + m_directory = QString(); +} + +void FileLoader::setDirectoryToLoad(const QString & d) +{ + m_directory = d; + m_files_to_load.clear(); +} + +void FileLoader::finish() +{ + m_finished = true; +} diff --git a/src/qmmpui/fileloader.h b/src/qmmpui/fileloader.h new file mode 100644 index 000000000..d2dcc0748 --- /dev/null +++ b/src/qmmpui/fileloader.h @@ -0,0 +1,72 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + ***************************************************************************/ +#ifndef FILELOADER_H +#define FILELOADER_H + +#include +#include +#include + +class PlayListItem; + +/*! + * This class represents fileloader object that + * processes file list in separate thread and emits + * \b newPlayListItem(PlayListItem*) signal for every newly + * created media file. + @author Ilya Kotov +*/ +class FileLoader : public QThread +{ + Q_OBJECT +public: + FileLoader(QObject *parent = 0); + + ~FileLoader(); + virtual void run(); + + /*! + * Call this method when you want to notify the thread about finishing + */ + void finish(); + + /*! + * Sets filelist to load( directory to load will be cleaned ) + */ + void setFilesToLoad(const QStringList&); + + /*! + * Sets directory to load( filelist to load will be cleaned ) + */ + void setDirectoryToLoad(const QString&); +signals: + void newPlayListItem(PlayListItem*); +protected: + void addFiles(const QStringList &files); + void addDirectory(const QString& s); +private: + QFileInfoList list; + QStringList m_filters; + QStringList m_files_to_load; + QString m_directory; + bool m_finished; +}; + +#endif diff --git a/src/qmmpui/playlistitem.cpp b/src/qmmpui/playlistitem.cpp new file mode 100644 index 000000000..bfbaa354c --- /dev/null +++ b/src/qmmpui/playlistitem.cpp @@ -0,0 +1,179 @@ +/*************************************************************************** + * Copyright (C) 2008 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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 +#include + +#include + +#include "playlistitem.h" + +PlayListItem::PlayListItem() : AbstractPlaylistItem(), m_flag(FREE) +{ + m_info = 0; +} + +PlayListItem::PlayListItem(FileInfo *info, QSettings *settings) : AbstractPlaylistItem(), m_flag(FREE) +{ + m_selected = FALSE; + m_current = FALSE; + m_info = info; + + //use external settings or create new + QSettings *s = settings; + if (!s) + s = new QSettings (QDir::homePath() +"/.qmmp/qmmprc", QSettings::IniFormat); + + m_use_meta = s->value ("PlayList/load_metadata", TRUE).toBool(); //TODO move to libqmmp + //format + m_format = s->value("PlayList/title_format", "%p - %t").toString(); + //other properties + m_convertUnderscore = s->value ("PlayList/convert_underscore", TRUE).toBool(); + m_convertTwenty = s->value ("PlayList/convert_twenty", TRUE).toBool(); + m_fullStreamPath = s->value ("PlayList/full_stream_path", FALSE).toBool(); + if (!settings) //delete created settings only + delete s; + + setMetaData(info->metaData()); + setMetaData(Qmmp::URL, m_info->path()); + setLength(m_info->length()); + readMetadata(); +} + +PlayListItem::~PlayListItem() +{ + if (m_info) + delete m_info; +} + +void PlayListItem::setSelected(bool yes) +{ + m_selected = yes; +} + +bool PlayListItem::isSelected() const +{ + return m_selected; +} + +void PlayListItem::setCurrent(bool yes) +{ + m_current = yes; +} + +bool PlayListItem::isCurrent() const +{ + return m_current; +} + +void PlayListItem::setFlag(FLAGS f) +{ + m_flag = f; +} + +PlayListItem::FLAGS PlayListItem::flag() const +{ + return m_flag; +} + +void PlayListItem::updateMetaData(const QMap &metaData) +{ + setMetaData(metaData); + readMetadata(); +} + +void PlayListItem::updateTags() +{ + if (url().startsWith("http://")) + return; + if (m_info) + { + delete m_info; + m_info = 0; + } + m_info = Decoder::createPlayList(url()).at(0); + setMetaData(m_info->metaData()); + setMetaData(Qmmp::URL, m_info->path()); + readMetadata(); +} + +const QString PlayListItem::text() const +{ + return m_title; +} + +void PlayListItem::setText(const QString &title) +{ + m_title = title; +} + +void PlayListItem::readMetadata() +{ + m_title = m_format; + m_title = printTag(m_title, "%p", artist()); + m_title = printTag(m_title, "%a", album()); + m_title = printTag(m_title, "%t", title()); + m_title = printTag(m_title, "%n", QString("%1").arg(track())); + m_title = printTag(m_title, "%g", genre()); + m_title = printTag(m_title, "%f", url().section('/',-1)); + m_title = printTag(m_title, "%F", url()); + m_title = printTag(m_title, "%y", QString("%1").arg(year ())); + + if (m_title.isEmpty()) + { + if (url().startsWith("http://") && m_fullStreamPath) + m_title = url(); + else + m_title = url().split('/',QString::SkipEmptyParts).takeLast (); + } + if (m_info) + delete m_info; + m_info = 0; + if (m_convertUnderscore) + m_title.replace("_", " "); + if (m_convertTwenty) + m_title.replace("%20", " "); +} + +QString PlayListItem::printTag(QString str, QString regExp, QString tagStr) +{ + if (!tagStr.isEmpty()) + str.replace(regExp, tagStr); + else + { + //remove unused separators + int regExpPos = str.indexOf(regExp); + if (regExpPos < 0) + return str; + int nextPos = str.indexOf("%", regExpPos + 1); + if (nextPos < 0) + { + //last separator + regExpPos = m_format.lastIndexOf(regExp); + nextPos = m_format.lastIndexOf("%", regExpPos - 1); + QString lastSep = m_format.right (m_format.size() - nextPos - 2); + str.remove(lastSep); + str.remove(regExp); + } + else + str.remove ( regExpPos, nextPos - regExpPos); + } + return str; +} + diff --git a/src/qmmpui/playlistitem.h b/src/qmmpui/playlistitem.h new file mode 100644 index 000000000..ce26ca2f5 --- /dev/null +++ b/src/qmmpui/playlistitem.h @@ -0,0 +1,74 @@ +/*************************************************************************** + * Copyright (C) 2008 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + ***************************************************************************/ +#ifndef PLAYLISTITEM_H +#define PLAYLISTITEM_H + +#include +#include + +class FileInfo; +class QSettings; +/** + @author Ilya Kotov +*/ +class PlayListItem : public AbstractPlaylistItem +{ +public: + /*! + * Current state of media file. + * FREE - instance is free and may be deleted + * EDITING - instance is currently busy in some kind of operation(tags editing etc.) + * and can't be deleted at the moment. Set flag SCHEDULED_FOR_DELETION for it + * instead of delete operator call. + */ + enum FLAGS{FREE = 0,EDITING,SCHEDULED_FOR_DELETION}; + PlayListItem(); + //PlayListItem(const QString& path); + PlayListItem(FileInfo *info, QSettings *settings = 0); + + ~PlayListItem(); + + //playlist support + void setSelected(bool yes); + bool isSelected() const; + void setCurrent(bool yes); + bool isCurrent() const; + FLAGS flag()const; + void setFlag(FLAGS); + const QString text() const; + void setText(const QString &title); + //modify functions + void updateMetaData(const QMap &metaData); + void updateTags(); + +private: + void readMetadata(); + QString printTag(QString str, QString regExp, QString tagStr); + QString m_title; + FileInfo *m_info; + bool m_selected; + bool m_current; + bool m_use_meta; + bool m_convertUnderscore, m_convertTwenty, m_fullStreamPath; + QString m_format; + FLAGS m_flag; +}; + +#endif diff --git a/src/qmmpui/playlistmodel.cpp b/src/qmmpui/playlistmodel.cpp new file mode 100644 index 000000000..ffde91ac8 --- /dev/null +++ b/src/qmmpui/playlistmodel.cpp @@ -0,0 +1,910 @@ +/*************************************************************************** + * Copyright(C) 2006-2008 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "fileloader.h" +#include "playlistmodel.h" +#include "playlistitem.h" +#include "playstate.h" + +#include + +#define INVALID_ROW -1 + +TagUpdater::TagUpdater(QObject* o,PlayListItem* item):m_observable(o),m_item(item) +{ + m_item->setFlag(PlayListItem::EDITING); + connect(m_observable, SIGNAL(destroyed(QObject *)),SLOT(updateTag())); + connect(m_observable, SIGNAL(destroyed(QObject *)),SLOT(deleteLater())); +} + +void TagUpdater::updateTag() +{ + if (m_item->flag() == PlayListItem::SCHEDULED_FOR_DELETION) + { + delete m_item; + m_item = NULL; + } + else + { + m_item->updateTags(); + m_item->setFlag(PlayListItem::FREE); + } +} + + +PlayListModel::PlayListModel(QObject *parent) + : QObject(parent) , m_selection() +{ + qsrand(time(0)); + m_total_length = 0; + m_current = 0; + m_block_update_signals = false; + is_repeatable_list = false; + m_play_state = new NormalPlayState(this); + //readSettings(); +} + +PlayListModel::~PlayListModel() +{ + writeSettings(); + clear(); + delete m_play_state; + //qDeleteAll(m_registered_pl_formats); + + foreach(GuardedFileLoader l,m_running_loaders) + { + if (!l.isNull()) + { + l->finish(); + l->wait(); + } + } +} + +void PlayListModel::load(PlayListItem *item) +{ + if (m_items.isEmpty()) + m_currentItem = item; + + m_total_length += item->length(); + m_items << item; + + if (m_items.size() == 1) + emit firstAdded(); + + if (!m_block_update_signals) + emit listChanged(); +} + +int PlayListModel::count() +{ + return m_items.size(); +} + +PlayListItem* PlayListModel::currentItem() +{ + if (m_items.isEmpty()) + return 0; + else + return m_items.at(qMin(m_items.size() - 1, m_current)); +} + +int PlayListModel::currentRow() +{ + return m_current; +} + +bool PlayListModel::setCurrent(int c) +{ + if (c > count()-1 || c < 0) + return FALSE; + m_current = c; + m_currentItem = m_items.at(c); + emit currentChanged(); + emit listChanged(); + return TRUE; +} + + +bool PlayListModel::next() +{ + if (isFileLoaderRunning()) + m_play_state->prepare(); + + return m_play_state->next(); +} + +bool PlayListModel::previous() +{ + if (isFileLoaderRunning()) + m_play_state->prepare(); + + return m_play_state->previous();//) +} + +void PlayListModel::clear() +{ + foreach(GuardedFileLoader l,m_running_loaders) + { + if (!l.isNull()) + { + l->finish(); + l->wait(); + } + } + + m_running_loaders.clear(); + + m_current = 0; + while (!m_items.isEmpty()) + { + PlayListItem* mf = m_items.takeFirst(); + + if (mf->flag() == PlayListItem::FREE) + { + delete mf; + } + else if (mf->flag() == PlayListItem::EDITING) + { + mf->setFlag(PlayListItem::SCHEDULED_FOR_DELETION); + } + } + + m_total_length = 0; + m_play_state->resetState(); + emit listChanged(); +} + +void PlayListModel::clearSelection() +{ + for (int i = 0; isetSelected(FALSE); + emit listChanged(); +} + +QList PlayListModel::getTitles(int b,int l) +{ + QList m_titles; + for (int i = b;(i < b + l) &&(i < m_items.size()); ++i) + m_titles << m_items.at(i)->text(); + return m_titles; +} + +QList PlayListModel::getTimes(int b,int l) +{ + QList m_times; + for (int i = b;(i < b + l) &&(i < m_items.size()); ++i) + m_times << QString("%1").arg(m_items.at(i)->length() /60) +":" + +QString("%1").arg(m_items.at(i)->length() %60/10) + + QString("%1").arg(m_items.at(i)->length() %60%10); + return m_times; +} + +bool PlayListModel::isSelected(int row) +{ + if (m_items.count() > row && row >= 0) + return m_items.at(row)->isSelected(); + + return false; +} + +void PlayListModel::setSelected(int row, bool yes) +{ + if (m_items.count() > row && row >= 0) + m_items.at(row)->setSelected(yes); +} + +void PlayListModel::removeSelected() +{ + removeSelection(false); +} + +void PlayListModel::removeUnselected() +{ + removeSelection(true); +} + +void PlayListModel::removeSelection(bool inverted) +{ + int i = 0; + + int select_after_delete = -1; + + while (!m_items.isEmpty() && iisSelected() ^ inverted) + { + PlayListItem* f = m_items.takeAt(i); + m_total_length -= f->length(); + if (m_total_length < 0) + m_total_length = 0; + + if (f->flag() == PlayListItem::FREE) + { + delete f; + f = NULL; + } + else if (f->flag() == PlayListItem::EDITING) + f->setFlag(PlayListItem::SCHEDULED_FOR_DELETION); + + select_after_delete = i; + + if (m_current >= i && m_current!=0) + m_current--; + } + else + i++; + } + + if (!m_items.isEmpty()) + m_currentItem = m_items.at(m_current); + + if (select_after_delete >= m_items.count()) + select_after_delete = m_items.count() - 1; + + setSelected(select_after_delete,true); + + m_play_state->prepare(); + + emit listChanged(); +} + +void PlayListModel::invertSelection() +{ + for (int i = 0; isetSelected(!m_items.at(i)->isSelected()); + emit listChanged(); +} + +void PlayListModel::selectAll() +{ + for (int i = 0; isetSelected(TRUE); + emit listChanged(); +} + +void PlayListModel::showDetails() +{ + for (int i = 0; iisSelected()) + { + if (!QFile::exists(m_items.at(i)->url())) + { + PlayListItem *item = m_items.at(i); + QString str; + str.append(tr("Url:") + " %1\n"); + str.append(tr("Title:") + " %2\n"); + str.append(tr("Artist:") + " %3\n"); + str.append(tr("Album:") + " %4\n"); + str.append(tr("Comment:") + " %5"); + str = str.arg(item->url()) + .arg(item->title().isEmpty() ? item->text() : item->title()) + .arg(item->artist()) + .arg(item->album()) + .arg(item->comment()); + QMessageBox::information(0, m_items.at(i)->url(), str); + return; + } + + DecoderFactory *fact = Decoder::findByPath(m_items.at(i)->url()); + if (fact) + { + QObject* o = fact->showDetails(0, m_items.at(i)->url()); + if (o) + { + TagUpdater *updater = new TagUpdater(o,m_items.at(i)); + m_editing_items.append(m_items.at(i)); + connect(updater, SIGNAL(destroyed(QObject *)),SIGNAL(listChanged())); + } + } + return; + } + } +} + +void PlayListModel::readSettings() +{ + QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat); + m_current = settings.value("Playlist/current",0).toInt(); + + QString line, param, value; + int s; + QList infoList; + QFile file(QDir::homePath() +"/.qmmp/playlist.txt"); + file.open(QIODevice::ReadOnly); + QByteArray array = file.readAll(); + file.close(); + QBuffer buffer(&array); + buffer.open(QIODevice::ReadOnly); + while (!buffer.atEnd()) + { + line = QString::fromUtf8(buffer.readLine()).trimmed(); + if ((s = line.indexOf("=")) < 0) + continue; + + param = line.left(s); + value = line.right(line.size() - s - 1); + + if (param == "file") + infoList << new FileInfo(value); + else if (infoList.isEmpty()) + continue; + else if (param == "title") + infoList.last()->setMetaData(Qmmp::TITLE, value); + else if (param == "artist") + infoList.last()->setMetaData(Qmmp::ARTIST, value); + else if (param == "album") + infoList.last()->setMetaData(Qmmp::ALBUM, value); + else if (param == "comment") + infoList.last()->setMetaData(Qmmp::COMMENT, value); + else if (param == "genre") + infoList.last()->setMetaData(Qmmp::GENRE, value); + else if (param == "year") + infoList.last()->setMetaData(Qmmp::YEAR, value); + else if (param == "track") + infoList.last()->setMetaData(Qmmp::TRACK, value); + else if (param == "length") + infoList.last()->setLength(value.toInt()); + } + buffer.close(); + if (m_current > infoList.count() - 1) + m_current = 0; + m_block_update_signals = TRUE; + foreach(FileInfo *info, infoList) + load(new PlayListItem(info, &settings)); //using one and the same settings object for all playlist items + m_block_update_signals = FALSE; + doCurrentVisibleRequest(); +} + +void PlayListModel::writeSettings() +{ + QFile file(QDir::homePath() +"/.qmmp/playlist.txt"); + file.open(QIODevice::WriteOnly); + foreach(PlayListItem* m, m_items) + { + file.write(QString("file=%1").arg(m->url()).toUtf8() +"\n"); + file.write(QString("title=%1").arg(m->title()).toUtf8() +"\n"); + file.write(QString("artist=%1").arg(m->artist()).toUtf8() +"\n"); + file.write(QString("album=%1").arg(m->album()).toUtf8() +"\n"); + file.write(QString("comment=%1").arg(m->comment()).toUtf8() +"\n"); + file.write(QString("genre=%1").arg(m->genre()).toUtf8() +"\n"); + file.write(QString("year=%1").arg(m->year()).toUtf8() +"\n"); + file.write(QString("track=%1").arg(m->track()).toUtf8() +"\n"); + file.write(QString("length=%1").arg(m->length()).toUtf8() +"\n"); + } + file.close(); + QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat); + settings.setValue("Playlist/current", m_current); +} + +void PlayListModel::addFile(const QString& path) +{ + if (path.isEmpty()) + return; + /*if(path.startsWith("http://")) + load(new PlayListItem(path)); + else if(Decoder::supports(path)) + load(new PlayListItem(path));*/ + QList playList = Decoder::createPlayList(path); + foreach(FileInfo *info, playList) + emit load(new PlayListItem(info)); + + m_play_state->prepare(); +} + +FileLoader * PlayListModel::createFileLoader() +{ + FileLoader* f_loader = new FileLoader(this); +// f_loader->setStackSize(20 * 1024 * 1024); + m_running_loaders << f_loader; + connect(f_loader,SIGNAL(newPlayListItem(PlayListItem*)),this,SLOT(load(PlayListItem*)),Qt::QueuedConnection); + connect(f_loader,SIGNAL(finished()),this,SLOT(preparePlayState())); + connect(f_loader,SIGNAL(finished()),f_loader,SLOT(deleteLater())); + return f_loader; +} + +void PlayListModel::addFiles(const QStringList &files) +{ + FileLoader* f_loader = createFileLoader(); + f_loader->setFilesToLoad(files); + f_loader->start(QThread::IdlePriority); +} + +void PlayListModel::addDirectory(const QString& s) +{ + FileLoader* f_loader = createFileLoader(); + f_loader->setDirectoryToLoad(s); + f_loader->start(QThread::IdlePriority); +} + +void PlayListModel::addFileList(const QStringList &l) +{ +// qWarning("void// PlayListModel::addFileList(const QStringList &l)"); + foreach(QString str,l) + { + QFileInfo f_info(str); + if (f_info.exists()) + { + if (f_info.isDir()) + addDirectory(str); + else + { + addFile(str); + loadPlaylist(str); + } + } + // Do processing the rest of events to avoid GUI freezing + QApplication::processEvents(QEventLoop::AllEvents,10); + } +} + +bool PlayListModel::setFileList(const QStringList & l) +{ + bool model_cleared = FALSE; + foreach(QString str,l) + { + QFileInfo f_info(str); + if (f_info.exists()) + { + if (!model_cleared) + { + clear(); + model_cleared = TRUE; + } + if (f_info.isDir()) + addDirectory(str); + else + { + addFile(str); + loadPlaylist(str); + } + } + // Do processing the rest of events to avoid GUI freezing + QApplication::processEvents(QEventLoop::AllEvents,10); + } + + return model_cleared; +} + +int PlayListModel::firstSelectedUpper(int row) +{ + for (int i = row - 1;i >= 0;i--) + { + if (isSelected(i)) + return i; + } + return -1; +} + +int PlayListModel::firstSelectedLower(int row) +{ + for (int i = row + 1;i < count() ;i++) + { + if (isSelected(i)) + return i; + } + return -1; +} + +void PlayListModel::moveItems(int from, int to) +{ + // Get rid of useless work + if (from == to) + return; + + QList selected_rows = getSelectedRows(); + + if (!(bottommostInSelection(from) == INVALID_ROW || + from == INVALID_ROW || + topmostInSelection(from) == INVALID_ROW) + ) + { + if (from > to) + foreach(int i, selected_rows) + if (i + to - from < 0) + break; + else + m_items.move(i,i + to - from); + else + for (int i = selected_rows.count() - 1; i >= 0; i--) + if (selected_rows[i] + to -from >= m_items.count()) + break; + else + m_items.move(selected_rows[i],selected_rows[i] + to - from); + + m_current = m_items.indexOf(m_currentItem); + + emit listChanged(); + } +} + + + +int PlayListModel::topmostInSelection(int row) +{ + if (row == 0) + return 0; + + for (int i = row - 1;i >= 0;i--) + { + if (isSelected(i)) + continue; + else + return i + 1; + } + return 0; +} + +int PlayListModel::bottommostInSelection(int row) +{ + if (row >= m_items.count() - 1) + return row; + + for (int i = row + 1;i < count() ;i++) + { + if (isSelected(i)) + continue; + else + return i - 1; + } + return count() - 1; +} + +const SimpleSelection& PlayListModel::getSelection(int row) +{ + m_selection.m_top = topmostInSelection(row); + m_selection.m_anchor = row; + m_selection.m_bottom = bottommostInSelection(row); + m_selection.m_selected_rows = getSelectedRows(); + return m_selection; +} + +QList PlayListModel::getSelectedRows() const +{ + QListselected_rows; + for (int i = 0;iisSelected()) + { + selected_rows.append(i); + } + } + return selected_rows; +} + +QList< PlayListItem * > PlayListModel::getSelectedItems() const +{ + QListselected_items; + for (int i = 0;iisSelected()) + { + selected_items.append(m_items[i]); + } + } + return selected_items; +} + +void PlayListModel::addToQueue() +{ + QList selected_items = getSelectedItems(); + foreach(PlayListItem* file,selected_items) + {/* + if(isQueued(file)) + m_queued_songs.removeAt(m_queued_songs.indexOf(file)); + else + m_queued_songs.append(file); + */ + setQueued(file); + } + emit listChanged(); +} + +void PlayListModel::setQueued(PlayListItem* file) +{ + if (isQueued(file)) + m_queued_songs.removeAt(m_queued_songs.indexOf(file)); + else + m_queued_songs.append(file); + + emit listChanged(); +} + +bool PlayListModel::isQueued(PlayListItem* f) const +{ + return m_queued_songs.contains(f); +} + +void PlayListModel::setCurrentToQueued() +{ + setCurrent(row(m_queued_songs.at(0))); + m_queued_songs.pop_front(); +} + +bool PlayListModel::isEmptyQueue() const +{ + return m_queued_songs.isEmpty(); +} + +void PlayListModel::randomizeList() +{ + for (int i = 0;i < m_items.size();i++) + m_items.swap(qrand()%m_items.size(),qrand()%m_items.size()); + + m_current = m_items.indexOf(m_currentItem); + emit listChanged(); +} + +void PlayListModel::reverseList() +{ + for (int i = 0;i < m_items.size()/2;i++) + m_items.swap(i,m_items.size() - i - 1); + + m_current = m_items.indexOf(m_currentItem); + emit listChanged(); +} + +////===============THE BEGINNING OF SORT IMPLEMENTATION =======================//// + +// First we'll implement bundle of static compare procedures +// to sort items in different ways +static bool _titleLessComparator(PlayListItem* s1,PlayListItem* s2) +{ + return s1->title() < s2->title(); +} + +static bool _titleGreaterComparator(PlayListItem* s1,PlayListItem* s2) +{ + return s1->title() > s2->title(); +} + +static bool _pathAndFilenameLessComparator(PlayListItem* s1,PlayListItem* s2) +{ + return s1->url() < s2->url(); +} + +static bool _pathAndFilenameGreaterComparator(PlayListItem* s1,PlayListItem* s2) +{ + return s1->url() > s2->url(); +} + +static bool _filenameLessComparator(PlayListItem* s1,PlayListItem* s2) +{ + QFileInfo i_s1(s1->url()); + QFileInfo i_s2(s2->url()); + return i_s1.baseName() < i_s2.baseName(); +} + +static bool _filenameGreaterComparator(PlayListItem* s1,PlayListItem* s2) +{ + QFileInfo i_s1(s1->url()); + QFileInfo i_s2(s2->url()); + return i_s1.baseName() > i_s2.baseName(); +} + +static bool _dateLessComparator(PlayListItem* s1,PlayListItem* s2) +{ + return s1->year() < s2->year(); +} + +static bool _dateGreaterComparator(PlayListItem* s1,PlayListItem* s2) +{ + return s1->year() > s2->year(); +} + +static bool _trackLessComparator(PlayListItem* s1,PlayListItem* s2) +{ + return s1->track() < s2->track(); +} + +static bool _trackGreaterComparator(PlayListItem* s1,PlayListItem* s2) +{ + return s1->track() > s2->track(); +} + +// This is main sort method +void PlayListModel::doSort(int sort_mode,QList& list_to_sort) +{ + QList::iterator begin; + QList::iterator end; + + begin = list_to_sort.begin(); + end = list_to_sort.end(); + + bool(*compareLessFunc)(PlayListItem*,PlayListItem*) = 0; + bool(*compareGreaterFunc)(PlayListItem*,PlayListItem*) = 0; + + switch (sort_mode) + { + case TITLE: + compareLessFunc = _titleLessComparator; + compareGreaterFunc = _titleGreaterComparator; + break; + case FILENAME: + compareLessFunc = _filenameLessComparator; + compareGreaterFunc = _filenameGreaterComparator; + break; + case PATH_AND_FILENAME: + compareLessFunc = _pathAndFilenameLessComparator; + compareGreaterFunc = _pathAndFilenameGreaterComparator; + break; + case DATE: + compareLessFunc = _dateLessComparator; + compareGreaterFunc = _dateGreaterComparator; + break; + //qWarning("TODO Sort by Date: %s\t%d",__FILE__,__LINE__); + case TRACK: + compareLessFunc = _trackLessComparator; + compareGreaterFunc = _trackGreaterComparator; + break; + default: + compareLessFunc = _titleLessComparator; + compareGreaterFunc = _titleGreaterComparator; + } + + static bool sorted_asc = false; + if (!sorted_asc) + { + qSort(begin,end,compareLessFunc); + sorted_asc = true; + } + else + { + qSort(begin,end,compareGreaterFunc); + sorted_asc = false; + } + + m_current = m_items.indexOf(m_currentItem); +} + +void PlayListModel::sortSelection(int mode) +{ + QListselected_items = getSelectedItems(); + QListselected_rows = getSelectedRows(); + + doSort(mode,selected_items); + + for (int i = 0;i < selected_rows.count();i++) + m_items.replace(selected_rows[i],selected_items[i]); + + m_current = m_items.indexOf(m_currentItem); + emit listChanged(); +} + +void PlayListModel::sort(int mode) +{ + doSort(mode,m_items); + emit listChanged(); +} + +////=============== THE END OF SORT IMPLEMENTATION =======================//// + +void PlayListModel::prepareForShufflePlaying(bool val) +{ + if (m_play_state) + delete m_play_state; + + if (val) + m_play_state = new ShufflePlayState(this); + else + m_play_state = new NormalPlayState(this); + +} + +void PlayListModel::prepareForRepeatablePlaying(bool val) +{ + is_repeatable_list = val; +} + +void PlayListModel::doCurrentVisibleRequest() +{ + emit currentChanged(); + emit listChanged(); +} + +void PlayListModel::setUpdatesEnabled(bool yes) +{ + if (yes) + { + m_block_update_signals = false; + emit listChanged(); + } + else + { + m_block_update_signals = true; + } +} + +void PlayListModel::loadPlaylist(const QString &f_name) +{ + PlaylistFormat* prs = PlaylistParser::instance()->findByPath(f_name); + if (prs) + { + QFile file(f_name); + if (file.open(QIODevice::ReadOnly)) + { + //clear(); + QStringList list = prs->decode(QTextStream(&file).readAll()); + for (int i = 0; i < list.size(); ++i) + { + if (QFileInfo(list.at(i)).isRelative() && !list.at(i).contains("://")) + QString path = list[i].prepend(QFileInfo(f_name).canonicalPath () + QDir::separator ()); + } + addFiles(list); + file.close(); + } + else + qWarning("Error opening %s",f_name.toLocal8Bit().data()); + } +} + +void PlayListModel::savePlaylist(const QString & f_name) +{ + PlaylistFormat* prs = PlaylistParser::instance()->findByPath(f_name); + if (prs) + { + QFile file(f_name); + if (file.open(QIODevice::WriteOnly)) + { + QTextStream ts(&file); + QList songs; + foreach(PlayListItem* item, m_items) + songs << item; + ts << prs->encode(songs); + file.close(); + } + else + qWarning("Error opening %s",f_name.toLocal8Bit().data()); + } +} + +bool PlayListModel::isFileLoaderRunning() const +{ + foreach(FileLoader* l,m_running_loaders) + if (l && l->isRunning()) + return TRUE; + + return FALSE; +} + +void PlayListModel::preparePlayState() +{ + m_play_state->prepare(); +} diff --git a/src/qmmpui/playlistmodel.h b/src/qmmpui/playlistmodel.h new file mode 100644 index 000000000..a5231b44f --- /dev/null +++ b/src/qmmpui/playlistmodel.h @@ -0,0 +1,353 @@ +/*************************************************************************** + * Copyright (C) 2006-2008 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + ***************************************************************************/ +#ifndef PLAYLISTMODEL_H +#define PLAYLISTMODEL_H + +#include +#include +#include +#include +#include +#include + +//#include "fileloader.h" +class FileLoader; + +/** + @author Ilya Kotov +*/ + +class PlayListItem; +class PlayState; +class PlaylistFormat; +class PlayListModel; + +struct SimpleSelection +{ + SimpleSelection() + { + ; + } + inline bool isValid()const + { + return (m_bottom != -1) && (m_anchor != -1) && (m_top != -1); + } + inline void dump()const + { + qWarning("top: %d\tbotom: %d\tanchor: %d",m_top,m_bottom,m_anchor); + } + inline int count()const + { + return m_bottom - m_top + 1; + } + int m_bottom; + int m_top; + int m_anchor; + QListm_selected_rows; +}; + +/*! + * Helper class used for tags update after details dialog closing. + * @author Vladimir Kuznetsov + */ +class TagUpdater : public QObject +{ + Q_OBJECT + QObject* m_observable; + PlayListItem* m_item; +public: + TagUpdater(QObject* o, PlayListItem* item); +protected slots: + void updateTag(); +}; + + +class PlayListModel : public QObject +{ + Q_OBJECT +public: + PlayListModel(QObject *parent = 0); + + ~PlayListModel(); + + int count(); + PlayListItem* currentItem(); + int row(PlayListItem* item)const + { + return m_items.indexOf(item); + } + PlayListItem* item(int row)const + { + return m_items.at(row); + } + int currentRow(); + bool setCurrent (int); + bool isSelected(int); + void setSelected(int, bool); + + bool next(); + bool previous(); + + QList getTitles(int,int); + QList getTimes(int,int); + + void moveItems(int from,int to); + + /*! + * Returns \b true if \b f file is in play queue, else return \b false + */ + bool isQueued(PlayListItem* item) const; + + bool isRepeatableList()const + { + return is_repeatable_list; + } + + /*! + * Sets current song to the file that is nex in queue, if queue is empty - does nothing + */ + void setCurrentToQueued(); + + /*! + * Returns \b true if play queue is empty,otherwise - \b false. + */ + bool isEmptyQueue()const; + + /*! + * Returns index of \b f file in queue.e + */ + int queuedIndex(PlayListItem* item)const + { + return m_queued_songs.indexOf(item); + } + + /*! + * Returns current selection(playlist can contain a lot of selections, + * this method returns selection which \b row belongs to) + */ + const SimpleSelection& getSelection(int row); + + /*! + * Returns vector with selected rows indexes. + */ + QList getSelectedRows()const; + /*! + * Returns vector of \b PlayListItem pointers that are selected. + */ + QList getSelectedItems()const; + + QList items()const + { + return m_items; + } + + /*! + * Returns number of first item that selected upper the \b row item. + */ + int firstSelectedUpper(int row); + + /*! + * Returns number of first item that selected lower the \b row item. + */ + int firstSelectedLower(int row); + + /*! + * Returns total lenght in seconds of all songs. + */ + int totalLength()const + { + return m_total_length; + } + + /*! + * Loads playlist with \b f_name name. + */ + void loadPlaylist(const QString& f_name); + + /*! + * Saves current songs to the playlist with \b f_name name. + */ + void savePlaylist(const QString& f_name); + + /*! + * Enum of available sort modes + */ + enum SortMode + { + TITLE,FILENAME,PATH_AND_FILENAME,DATE,TRACK + }; + +signals: + void listChanged(); + void currentChanged(); + void firstAdded(); + +public slots: + void load(PlayListItem *); + void clear(); + void clearSelection(); + void removeSelected(); + void removeUnselected(); + void invertSelection(); + void selectAll(); + void showDetails(); + void doCurrentVisibleRequest(); + + void addFile(const QString&); + + /*! + * Adds the list \b l of files to the model. + */ + void addFiles(const QStringList& l); + + /*! + * Adds \b dir to the model. + */ + void addDirectory(const QString& dir); + + /*! + * Loads list of files (regular files or directories), + * returns \b TRUE if at least one file has been successfully loaded, + * otherwise \b FALSE + */ + bool setFileList(const QStringList&); + + void addFileList(const QStringList &l); + + void randomizeList(); + void reverseList(); + + /*! + * Prepares model for shuffle playing. \b yes parameter is true - model iterates in shuffle mode. + */ + void prepareForShufflePlaying(bool yes); + + /*! + * Prepares model for shuffle playing. \b yes parameter is true - model iterates in repeat mode. + */ + void prepareForRepeatablePlaying(bool); + + /*! + * Sorts selected items in \b mode sort mode. + */ + void sortSelection(int mode); + + /*! + * Sorts items in \b mode sort mode. + */ + void sort(int mode); + + /*! + * Adds selected items to play queue. + */ + void addToQueue(); + + /*! + * Sets \b f media file to queue. + */ + void setQueued(PlayListItem* f); + + void preparePlayState(); + +private: + + /*! + * This internal method performs sorting of \b list_to_sort list of items. + */ + void doSort(int mode,QList& list_to_sort); + /*! + * Returns topmost row in current selection + */ + int topmostInSelection(int); + + /*! + * Returns bottommost row in current selection + */ + int bottommostInSelection(int); + + /*! + * Creates and initializes file loader object. + */ + FileLoader* createFileLoader(); + + + /*! + * Is someone of file loaders is running? + */ + bool isFileLoaderRunning()const; + + /*! + * Removes items from model. If \b inverted is \b false - + * selected items will be removed, else - unselected. + */ + void removeSelection(bool inverted = false); + +private: + + QList m_items; + QList m_editing_items; + PlayListItem* m_currentItem; + + int m_current; + void readSettings(); + void writeSettings(); + + void setUpdatesEnabled(bool); + + bool updatesEnabled()const + { + return !m_block_update_signals; + } + + /*! + * This flyweight object represents current selection. + */ + SimpleSelection m_selection; + + /*! + * Songs in play queue. + */ + QListm_queued_songs; + + /*! + * Is playlist repeatable? + */ + bool is_repeatable_list; + + /// Current playing state (Normal or Shuffle) + PlayState* m_play_state; + + bool m_block_update_signals; + + int m_total_length; + + typedef QPointer GuardedFileLoader; + + /*! Vector of currently running file loaders. + * All loaders are automatically sheduled for deletion + * when finished. + */ + QVector m_running_loaders; + + friend class MainWindow; +}; + + +#endif diff --git a/src/qmmpui/playstate.cpp b/src/qmmpui/playstate.cpp new file mode 100644 index 000000000..373619574 --- /dev/null +++ b/src/qmmpui/playstate.cpp @@ -0,0 +1,138 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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 + +ShufflePlayState::ShufflePlayState(PlayListModel * model) : PlayState(model) +{ + prepare(); +} + +bool ShufflePlayState::next() +{ + int itm_count = m_model->items().count(); + + if (itm_count > 0) + { + if (m_shuffled_current >= m_shuffled_indexes.count() -1 ) + { + if (!m_model->isRepeatableList()) + return FALSE; + else + prepare(); + } + + if (m_shuffled_current < m_shuffled_indexes.count() - 1)m_shuffled_current++; + + return m_model->setCurrent(m_shuffled_indexes.at(m_shuffled_current)); + } + return FALSE; +} + +bool ShufflePlayState::previous() +{ + int itm_count = m_model->items().count(); + + if (itm_count > 0) + { + if (m_shuffled_current <= 0) + { + if (!m_model->isRepeatableList()) + return FALSE; + else + { + prepare(); + m_shuffled_current = m_shuffled_indexes.count() - 1; + } + } + + if (itm_count > 1) m_shuffled_current --; + + m_model->setCurrent(m_shuffled_indexes.at(m_shuffled_current)); + return TRUE; + } + return FALSE; +} + +void ShufflePlayState::prepare() +{ + resetState(); + for (int i = 0;i < m_model->items().count();i++) + { + if (i != m_model->currentRow()) + m_shuffled_indexes << i; + } + + for (int i = 0;i < m_shuffled_indexes.count();i++) + m_shuffled_indexes.swap(qrand()%m_shuffled_indexes.size(),qrand()%m_shuffled_indexes.size()); + + m_shuffled_indexes.prepend(m_model->currentRow()); +} + +void ShufflePlayState::resetState() +{ + m_shuffled_indexes.clear(); + m_shuffled_current = 0; +} + + + + + +NormalPlayState::NormalPlayState(PlayListModel * model) : PlayState(model) +{} + + +bool NormalPlayState::next() +{ + int itm_count = m_model->items().count(); + + if (itm_count > 0) + { + if ( m_model->currentRow() == itm_count - 1) + { + if (m_model->isRepeatableList()) + return m_model->setCurrent(0); + else + return FALSE; + } + return m_model->setCurrent(m_model->currentRow() + 1); + } + else + return FALSE; +} + +bool NormalPlayState::previous() +{ + int itm_count = m_model->items().count(); + + if (itm_count > 0) + { + if ( m_model->currentRow() < 1 && !m_model->isRepeatableList()) + return FALSE; + else if (m_model->setCurrent(m_model->currentRow() - 1)) + return TRUE; + else if (m_model->isRepeatableList()) + return m_model->setCurrent(m_model->items().count() - 1); + } + + return FALSE; +} + diff --git a/src/qmmpui/playstate.h b/src/qmmpui/playstate.h new file mode 100644 index 000000000..e4af7fa6f --- /dev/null +++ b/src/qmmpui/playstate.h @@ -0,0 +1,109 @@ +/*************************************************************************** + * Copyright (C) 2006 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + ***************************************************************************/ + +#ifndef _PLAYSTATE_H +#define _PLAYSTATE_H + +/** + @author Vladimir Kuznetsov + */ + +#include + +/*! + * Abstract class that represents data model playing states + */ +class PlayState +{ +public: + /*! Makes single step forward through songs list. + * If the step has done returns \b true, otherwise \b false + */ + virtual bool next() = 0; + + /*! Makes single step back through songs list. + * If the step has done returns \b true, otherwise \b false + */ + virtual bool previous() = 0; + + /*! + * Service method, resets state to it's defaults. + */ + virtual void resetState() + { + ; + }; + + /*! + * Service method, can be used for state initializing. + */ + virtual void prepare() + { + ; + } + virtual ~PlayState() + { + ; + } + PlayState(PlayListModel* model) : m_model(model) + { + ; + } +protected: + + /// Data model + PlayListModel* m_model; +}; + +/*! + * Represents normal playing state. + * @author Vladimir Kuznetsov + */ +class NormalPlayState : public PlayState +{ +public: + virtual bool next(); + virtual bool previous(); + NormalPlayState(PlayListModel* model); +}; + +/*! + * Represents shuffle playing state. + * @author Vladimir Kuznetsov + */ +class ShufflePlayState : public PlayState +{ +public: + virtual bool next(); + virtual bool previous(); + virtual void prepare(); + ShufflePlayState(PlayListModel* model); + virtual void resetState(); +private: + + /// Current shuffled index. + int m_shuffled_current; + + /// List of indexes used for shuffled playing. + QList m_shuffled_indexes; +}; + + +#endif diff --git a/src/qmmpui/qmmpui.pro b/src/qmmpui/qmmpui.pro index 3d60de0c8..08182560f 100644 --- a/src/qmmpui/qmmpui.pro +++ b/src/qmmpui/qmmpui.pro @@ -40,16 +40,22 @@ HEADERS += general.h \ filedialog.h \ filedialogfactory.h \ qtfiledialog.h \ - abstractplaylist.h \ - abstractplaylistitem.h + abstractplaylistitem.h \ + playlistitem.h \ + playlistmodel.h \ + playstate.h \ + fileloader.h SOURCES += general.cpp \ generalhandler.cpp \ playlistparser.cpp \ commandlinemanager.cpp \ filedialog.cpp \ qtfiledialog.cpp \ - abstractplaylist.cpp \ - abstractplaylistitem.cpp + abstractplaylistitem.cpp \ + playlistmodel.cpp \ + playstate.cpp \ + playlistitem.cpp \ + fileloader.cpp DESTDIR = . diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index 292237903..45b7b1c83 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -49,24 +49,20 @@ SET(ui_SRCS eqslider.cpp eqtitlebar.cpp eqwidget.cpp - fileloader.cpp jumptotrackdialog.cpp keyboardmanager.cpp listwidget.cpp logscale.cpp mainvisual.cpp mainwindow.cpp - playlistitem.cpp monostereo.cpp mp3player.cpp number.cpp pixmapwidget.cpp playlistcontrol.cpp playlist.cpp - playlistmodel.cpp playlistslider.cpp playlisttitlebar.cpp - playstate.cpp playstatus.cpp pluginitem.cpp positionbar.cpp @@ -102,7 +98,6 @@ SET(ui_MOC_HDRS eqtitlebar.h eqwidget.h fft.h - fileloader.h inlines.h jumptotrackdialog.h keyboardmanager.h @@ -110,16 +105,13 @@ SET(ui_MOC_HDRS logscale.h mainvisual.h mainwindow.h - playlistitem.h monostereo.h number.h pixmapwidget.h playlistcontrol.h playlist.h - playlistmodel.h playlistslider.h playlisttitlebar.h - playstate.h playstatus.h pluginitem.h positionbar.h diff --git a/src/ui/addurldialog.cpp b/src/ui/addurldialog.cpp index 78a9a6969..581aa9cac 100644 --- a/src/ui/addurldialog.cpp +++ b/src/ui/addurldialog.cpp @@ -26,7 +26,7 @@ #include "addurldialog.h" #include #include -#include "playlistmodel.h" +#include #define HISTORY_SIZE 10 diff --git a/src/ui/fileloader.cpp b/src/ui/fileloader.cpp deleted file mode 100644 index ce5ccb56c..000000000 --- a/src/ui/fileloader.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2006 by Ilya Kotov * - * forkotov02@hotmail.ru * - * * - * 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 - -#include "fileloader.h" -#include "playlistitem.h" - -FileLoader::FileLoader(QObject *parent) - : QThread(parent),m_files_to_load(),m_directory() -{ - m_filters = Decoder::nameFilters(); - m_finished = false; -} - - -FileLoader::~FileLoader() -{ - qWarning("FileLoader::~FileLoader()"); -} - - -void FileLoader::addFiles(const QStringList &files) -{ - if (files.isEmpty ()) - return; - - foreach(QString s, files) - { - /*if (s.startsWith("http://") || Decoder::supports(s)) - {*/ - //emit newPlayListItem(new PlayListItem(s)); - QList playList = Decoder::createPlayList(s); - foreach(FileInfo *info, playList) - emit newPlayListItem(new PlayListItem(info)); - //} - if (m_finished) return; - } -} - - -void FileLoader::addDirectory(const QString& s) -{ - QList playList; - QDir dir(s); - dir.setFilter(QDir::Files | QDir::Hidden | QDir::NoSymLinks); - dir.setSorting(QDir::Name); - QFileInfoList l = dir.entryInfoList(m_filters); - for (int i = 0; i < l.size(); ++i) - { - QFileInfo fileInfo = l.at(i); - QString suff = fileInfo.completeSuffix(); - list << fileInfo; - - /*if (Decoder::supports(fileInfo.absoluteFilePath ())) - {*/ - playList = Decoder::createPlayList(fileInfo.absoluteFilePath ()); - foreach(FileInfo *info, playList) - emit newPlayListItem(new PlayListItem(info)); - //emit newPlayListItem(new PlayListItem(fileInfo.absoluteFilePath ())); - //} - if (m_finished) return; - } - dir.setFilter(QDir::Dirs | QDir::NoDotAndDotDot); - dir.setSorting(QDir::Name); - l.clear(); - l = dir.entryInfoList(); - if (l.size() > 0) - for (int i = 0; i < l.size(); ++i) - { - QFileInfo fileInfo = l.at(i); - addDirectory(fileInfo.absoluteFilePath ()); - if (m_finished) return; - } -} - -void FileLoader::run() -{ - if (!m_files_to_load.isEmpty()) - addFiles(m_files_to_load); - else if (!m_directory.isEmpty()) - addDirectory(m_directory); -} - -void FileLoader::setFilesToLoad(const QStringList & l) -{ - m_files_to_load = l; - m_directory = QString(); -} - -void FileLoader::setDirectoryToLoad(const QString & d) -{ - m_directory = d; - m_files_to_load.clear(); -} - -void FileLoader::finish() -{ - m_finished = true; -} diff --git a/src/ui/fileloader.h b/src/ui/fileloader.h deleted file mode 100644 index d2dcc0748..000000000 --- a/src/ui/fileloader.h +++ /dev/null @@ -1,72 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2006 by Ilya Kotov * - * forkotov02@hotmail.ru * - * * - * 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. * - ***************************************************************************/ -#ifndef FILELOADER_H -#define FILELOADER_H - -#include -#include -#include - -class PlayListItem; - -/*! - * This class represents fileloader object that - * processes file list in separate thread and emits - * \b newPlayListItem(PlayListItem*) signal for every newly - * created media file. - @author Ilya Kotov -*/ -class FileLoader : public QThread -{ - Q_OBJECT -public: - FileLoader(QObject *parent = 0); - - ~FileLoader(); - virtual void run(); - - /*! - * Call this method when you want to notify the thread about finishing - */ - void finish(); - - /*! - * Sets filelist to load( directory to load will be cleaned ) - */ - void setFilesToLoad(const QStringList&); - - /*! - * Sets directory to load( filelist to load will be cleaned ) - */ - void setDirectoryToLoad(const QString&); -signals: - void newPlayListItem(PlayListItem*); -protected: - void addFiles(const QStringList &files); - void addDirectory(const QString& s); -private: - QFileInfoList list; - QStringList m_filters; - QStringList m_files_to_load; - QString m_directory; - bool m_finished; -}; - -#endif diff --git a/src/ui/jumptotrackdialog.cpp b/src/ui/jumptotrackdialog.cpp index 37848e34f..6c9343170 100644 --- a/src/ui/jumptotrackdialog.cpp +++ b/src/ui/jumptotrackdialog.cpp @@ -19,7 +19,7 @@ ***************************************************************************/ #include "jumptotrackdialog.h" -#include "playlistmodel.h" +#include #include #include diff --git a/src/ui/keyboardmanager.cpp b/src/ui/keyboardmanager.cpp index 5ad32fee7..7e76625cd 100644 --- a/src/ui/keyboardmanager.cpp +++ b/src/ui/keyboardmanager.cpp @@ -21,8 +21,9 @@ #include +#include + #include "playlist.h" -#include "playlistmodel.h" #include "listwidget.h" #include "keyboardmanager.h" #include "mainwindow.h" diff --git a/src/ui/listwidget.cpp b/src/ui/listwidget.cpp index a81a6098c..3219611f1 100644 --- a/src/ui/listwidget.cpp +++ b/src/ui/listwidget.cpp @@ -27,11 +27,12 @@ #include #include -#include "playlistitem.h" +#include +#include + #include "textscroller.h" #include "listwidget.h" #include "skin.h" -#include "playlistmodel.h" #include "playlist.h" #define INVALID_ROW -1 diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 89761a7f0..4f38ec160 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -33,13 +33,13 @@ #include #include #include +#include +#include #include "textscroller.h" #include "mainwindow.h" -#include "fileloader.h" #include "skin.h" #include "playlist.h" -#include "playlistmodel.h" #include "configdialog.h" #include "dock.h" #include "eqwidget.h" @@ -350,7 +350,7 @@ void MainWindow::showMetaData() } } -void MainWindow::closeEvent ( QCloseEvent *) +void MainWindow::closeEvent (QCloseEvent *) { writeSettings(); m_playlist->close(); diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index 674b8ad06..4add7ccb3 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -25,9 +25,9 @@ #include #include #include +#include #include "display.h" -#include "playlistitem.h" #include "titlebar.h" /** diff --git a/src/ui/playlist.cpp b/src/ui/playlist.cpp index 42d560b2d..a6718ab74 100644 --- a/src/ui/playlist.cpp +++ b/src/ui/playlist.cpp @@ -27,13 +27,11 @@ #include #include "dock.h" -#include "fileloader.h" #include "playlist.h" #include "skin.h" #include "listwidget.h" #include "button.h" -#include "playlistitem.h" -#include "playlistmodel.h" + #include "playlisttitlebar.h" #include "playlistslider.h" #include "pixmapwidget.h" @@ -41,6 +39,9 @@ #include "playlistcontrol.h" #include "keyboardmanager.h" +#include +#include +#include #include PlayList::PlayList (QWidget *parent) diff --git a/src/ui/playlistitem.cpp b/src/ui/playlistitem.cpp deleted file mode 100644 index bfbaa354c..000000000 --- a/src/ui/playlistitem.cpp +++ /dev/null @@ -1,179 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2008 by Ilya Kotov * - * forkotov02@hotmail.ru * - * * - * 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 -#include - -#include - -#include "playlistitem.h" - -PlayListItem::PlayListItem() : AbstractPlaylistItem(), m_flag(FREE) -{ - m_info = 0; -} - -PlayListItem::PlayListItem(FileInfo *info, QSettings *settings) : AbstractPlaylistItem(), m_flag(FREE) -{ - m_selected = FALSE; - m_current = FALSE; - m_info = info; - - //use external settings or create new - QSettings *s = settings; - if (!s) - s = new QSettings (QDir::homePath() +"/.qmmp/qmmprc", QSettings::IniFormat); - - m_use_meta = s->value ("PlayList/load_metadata", TRUE).toBool(); //TODO move to libqmmp - //format - m_format = s->value("PlayList/title_format", "%p - %t").toString(); - //other properties - m_convertUnderscore = s->value ("PlayList/convert_underscore", TRUE).toBool(); - m_convertTwenty = s->value ("PlayList/convert_twenty", TRUE).toBool(); - m_fullStreamPath = s->value ("PlayList/full_stream_path", FALSE).toBool(); - if (!settings) //delete created settings only - delete s; - - setMetaData(info->metaData()); - setMetaData(Qmmp::URL, m_info->path()); - setLength(m_info->length()); - readMetadata(); -} - -PlayListItem::~PlayListItem() -{ - if (m_info) - delete m_info; -} - -void PlayListItem::setSelected(bool yes) -{ - m_selected = yes; -} - -bool PlayListItem::isSelected() const -{ - return m_selected; -} - -void PlayListItem::setCurrent(bool yes) -{ - m_current = yes; -} - -bool PlayListItem::isCurrent() const -{ - return m_current; -} - -void PlayListItem::setFlag(FLAGS f) -{ - m_flag = f; -} - -PlayListItem::FLAGS PlayListItem::flag() const -{ - return m_flag; -} - -void PlayListItem::updateMetaData(const QMap &metaData) -{ - setMetaData(metaData); - readMetadata(); -} - -void PlayListItem::updateTags() -{ - if (url().startsWith("http://")) - return; - if (m_info) - { - delete m_info; - m_info = 0; - } - m_info = Decoder::createPlayList(url()).at(0); - setMetaData(m_info->metaData()); - setMetaData(Qmmp::URL, m_info->path()); - readMetadata(); -} - -const QString PlayListItem::text() const -{ - return m_title; -} - -void PlayListItem::setText(const QString &title) -{ - m_title = title; -} - -void PlayListItem::readMetadata() -{ - m_title = m_format; - m_title = printTag(m_title, "%p", artist()); - m_title = printTag(m_title, "%a", album()); - m_title = printTag(m_title, "%t", title()); - m_title = printTag(m_title, "%n", QString("%1").arg(track())); - m_title = printTag(m_title, "%g", genre()); - m_title = printTag(m_title, "%f", url().section('/',-1)); - m_title = printTag(m_title, "%F", url()); - m_title = printTag(m_title, "%y", QString("%1").arg(year ())); - - if (m_title.isEmpty()) - { - if (url().startsWith("http://") && m_fullStreamPath) - m_title = url(); - else - m_title = url().split('/',QString::SkipEmptyParts).takeLast (); - } - if (m_info) - delete m_info; - m_info = 0; - if (m_convertUnderscore) - m_title.replace("_", " "); - if (m_convertTwenty) - m_title.replace("%20", " "); -} - -QString PlayListItem::printTag(QString str, QString regExp, QString tagStr) -{ - if (!tagStr.isEmpty()) - str.replace(regExp, tagStr); - else - { - //remove unused separators - int regExpPos = str.indexOf(regExp); - if (regExpPos < 0) - return str; - int nextPos = str.indexOf("%", regExpPos + 1); - if (nextPos < 0) - { - //last separator - regExpPos = m_format.lastIndexOf(regExp); - nextPos = m_format.lastIndexOf("%", regExpPos - 1); - QString lastSep = m_format.right (m_format.size() - nextPos - 2); - str.remove(lastSep); - str.remove(regExp); - } - else - str.remove ( regExpPos, nextPos - regExpPos); - } - return str; -} - diff --git a/src/ui/playlistitem.h b/src/ui/playlistitem.h deleted file mode 100644 index ce26ca2f5..000000000 --- a/src/ui/playlistitem.h +++ /dev/null @@ -1,74 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2008 by Ilya Kotov * - * forkotov02@hotmail.ru * - * * - * 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. * - ***************************************************************************/ -#ifndef PLAYLISTITEM_H -#define PLAYLISTITEM_H - -#include -#include - -class FileInfo; -class QSettings; -/** - @author Ilya Kotov -*/ -class PlayListItem : public AbstractPlaylistItem -{ -public: - /*! - * Current state of media file. - * FREE - instance is free and may be deleted - * EDITING - instance is currently busy in some kind of operation(tags editing etc.) - * and can't be deleted at the moment. Set flag SCHEDULED_FOR_DELETION for it - * instead of delete operator call. - */ - enum FLAGS{FREE = 0,EDITING,SCHEDULED_FOR_DELETION}; - PlayListItem(); - //PlayListItem(const QString& path); - PlayListItem(FileInfo *info, QSettings *settings = 0); - - ~PlayListItem(); - - //playlist support - void setSelected(bool yes); - bool isSelected() const; - void setCurrent(bool yes); - bool isCurrent() const; - FLAGS flag()const; - void setFlag(FLAGS); - const QString text() const; - void setText(const QString &title); - //modify functions - void updateMetaData(const QMap &metaData); - void updateTags(); - -private: - void readMetadata(); - QString printTag(QString str, QString regExp, QString tagStr); - QString m_title; - FileInfo *m_info; - bool m_selected; - bool m_current; - bool m_use_meta; - bool m_convertUnderscore, m_convertTwenty, m_fullStreamPath; - QString m_format; - FLAGS m_flag; -}; - -#endif diff --git a/src/ui/playlistmodel.cpp b/src/ui/playlistmodel.cpp deleted file mode 100644 index ffde91ac8..000000000 --- a/src/ui/playlistmodel.cpp +++ /dev/null @@ -1,910 +0,0 @@ -/*************************************************************************** - * Copyright(C) 2006-2008 by Ilya Kotov * - * forkotov02@hotmail.ru * - * * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include "fileloader.h" -#include "playlistmodel.h" -#include "playlistitem.h" -#include "playstate.h" - -#include - -#define INVALID_ROW -1 - -TagUpdater::TagUpdater(QObject* o,PlayListItem* item):m_observable(o),m_item(item) -{ - m_item->setFlag(PlayListItem::EDITING); - connect(m_observable, SIGNAL(destroyed(QObject *)),SLOT(updateTag())); - connect(m_observable, SIGNAL(destroyed(QObject *)),SLOT(deleteLater())); -} - -void TagUpdater::updateTag() -{ - if (m_item->flag() == PlayListItem::SCHEDULED_FOR_DELETION) - { - delete m_item; - m_item = NULL; - } - else - { - m_item->updateTags(); - m_item->setFlag(PlayListItem::FREE); - } -} - - -PlayListModel::PlayListModel(QObject *parent) - : QObject(parent) , m_selection() -{ - qsrand(time(0)); - m_total_length = 0; - m_current = 0; - m_block_update_signals = false; - is_repeatable_list = false; - m_play_state = new NormalPlayState(this); - //readSettings(); -} - -PlayListModel::~PlayListModel() -{ - writeSettings(); - clear(); - delete m_play_state; - //qDeleteAll(m_registered_pl_formats); - - foreach(GuardedFileLoader l,m_running_loaders) - { - if (!l.isNull()) - { - l->finish(); - l->wait(); - } - } -} - -void PlayListModel::load(PlayListItem *item) -{ - if (m_items.isEmpty()) - m_currentItem = item; - - m_total_length += item->length(); - m_items << item; - - if (m_items.size() == 1) - emit firstAdded(); - - if (!m_block_update_signals) - emit listChanged(); -} - -int PlayListModel::count() -{ - return m_items.size(); -} - -PlayListItem* PlayListModel::currentItem() -{ - if (m_items.isEmpty()) - return 0; - else - return m_items.at(qMin(m_items.size() - 1, m_current)); -} - -int PlayListModel::currentRow() -{ - return m_current; -} - -bool PlayListModel::setCurrent(int c) -{ - if (c > count()-1 || c < 0) - return FALSE; - m_current = c; - m_currentItem = m_items.at(c); - emit currentChanged(); - emit listChanged(); - return TRUE; -} - - -bool PlayListModel::next() -{ - if (isFileLoaderRunning()) - m_play_state->prepare(); - - return m_play_state->next(); -} - -bool PlayListModel::previous() -{ - if (isFileLoaderRunning()) - m_play_state->prepare(); - - return m_play_state->previous();//) -} - -void PlayListModel::clear() -{ - foreach(GuardedFileLoader l,m_running_loaders) - { - if (!l.isNull()) - { - l->finish(); - l->wait(); - } - } - - m_running_loaders.clear(); - - m_current = 0; - while (!m_items.isEmpty()) - { - PlayListItem* mf = m_items.takeFirst(); - - if (mf->flag() == PlayListItem::FREE) - { - delete mf; - } - else if (mf->flag() == PlayListItem::EDITING) - { - mf->setFlag(PlayListItem::SCHEDULED_FOR_DELETION); - } - } - - m_total_length = 0; - m_play_state->resetState(); - emit listChanged(); -} - -void PlayListModel::clearSelection() -{ - for (int i = 0; isetSelected(FALSE); - emit listChanged(); -} - -QList PlayListModel::getTitles(int b,int l) -{ - QList m_titles; - for (int i = b;(i < b + l) &&(i < m_items.size()); ++i) - m_titles << m_items.at(i)->text(); - return m_titles; -} - -QList PlayListModel::getTimes(int b,int l) -{ - QList m_times; - for (int i = b;(i < b + l) &&(i < m_items.size()); ++i) - m_times << QString("%1").arg(m_items.at(i)->length() /60) +":" - +QString("%1").arg(m_items.at(i)->length() %60/10) + - QString("%1").arg(m_items.at(i)->length() %60%10); - return m_times; -} - -bool PlayListModel::isSelected(int row) -{ - if (m_items.count() > row && row >= 0) - return m_items.at(row)->isSelected(); - - return false; -} - -void PlayListModel::setSelected(int row, bool yes) -{ - if (m_items.count() > row && row >= 0) - m_items.at(row)->setSelected(yes); -} - -void PlayListModel::removeSelected() -{ - removeSelection(false); -} - -void PlayListModel::removeUnselected() -{ - removeSelection(true); -} - -void PlayListModel::removeSelection(bool inverted) -{ - int i = 0; - - int select_after_delete = -1; - - while (!m_items.isEmpty() && iisSelected() ^ inverted) - { - PlayListItem* f = m_items.takeAt(i); - m_total_length -= f->length(); - if (m_total_length < 0) - m_total_length = 0; - - if (f->flag() == PlayListItem::FREE) - { - delete f; - f = NULL; - } - else if (f->flag() == PlayListItem::EDITING) - f->setFlag(PlayListItem::SCHEDULED_FOR_DELETION); - - select_after_delete = i; - - if (m_current >= i && m_current!=0) - m_current--; - } - else - i++; - } - - if (!m_items.isEmpty()) - m_currentItem = m_items.at(m_current); - - if (select_after_delete >= m_items.count()) - select_after_delete = m_items.count() - 1; - - setSelected(select_after_delete,true); - - m_play_state->prepare(); - - emit listChanged(); -} - -void PlayListModel::invertSelection() -{ - for (int i = 0; isetSelected(!m_items.at(i)->isSelected()); - emit listChanged(); -} - -void PlayListModel::selectAll() -{ - for (int i = 0; isetSelected(TRUE); - emit listChanged(); -} - -void PlayListModel::showDetails() -{ - for (int i = 0; iisSelected()) - { - if (!QFile::exists(m_items.at(i)->url())) - { - PlayListItem *item = m_items.at(i); - QString str; - str.append(tr("Url:") + " %1\n"); - str.append(tr("Title:") + " %2\n"); - str.append(tr("Artist:") + " %3\n"); - str.append(tr("Album:") + " %4\n"); - str.append(tr("Comment:") + " %5"); - str = str.arg(item->url()) - .arg(item->title().isEmpty() ? item->text() : item->title()) - .arg(item->artist()) - .arg(item->album()) - .arg(item->comment()); - QMessageBox::information(0, m_items.at(i)->url(), str); - return; - } - - DecoderFactory *fact = Decoder::findByPath(m_items.at(i)->url()); - if (fact) - { - QObject* o = fact->showDetails(0, m_items.at(i)->url()); - if (o) - { - TagUpdater *updater = new TagUpdater(o,m_items.at(i)); - m_editing_items.append(m_items.at(i)); - connect(updater, SIGNAL(destroyed(QObject *)),SIGNAL(listChanged())); - } - } - return; - } - } -} - -void PlayListModel::readSettings() -{ - QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat); - m_current = settings.value("Playlist/current",0).toInt(); - - QString line, param, value; - int s; - QList infoList; - QFile file(QDir::homePath() +"/.qmmp/playlist.txt"); - file.open(QIODevice::ReadOnly); - QByteArray array = file.readAll(); - file.close(); - QBuffer buffer(&array); - buffer.open(QIODevice::ReadOnly); - while (!buffer.atEnd()) - { - line = QString::fromUtf8(buffer.readLine()).trimmed(); - if ((s = line.indexOf("=")) < 0) - continue; - - param = line.left(s); - value = line.right(line.size() - s - 1); - - if (param == "file") - infoList << new FileInfo(value); - else if (infoList.isEmpty()) - continue; - else if (param == "title") - infoList.last()->setMetaData(Qmmp::TITLE, value); - else if (param == "artist") - infoList.last()->setMetaData(Qmmp::ARTIST, value); - else if (param == "album") - infoList.last()->setMetaData(Qmmp::ALBUM, value); - else if (param == "comment") - infoList.last()->setMetaData(Qmmp::COMMENT, value); - else if (param == "genre") - infoList.last()->setMetaData(Qmmp::GENRE, value); - else if (param == "year") - infoList.last()->setMetaData(Qmmp::YEAR, value); - else if (param == "track") - infoList.last()->setMetaData(Qmmp::TRACK, value); - else if (param == "length") - infoList.last()->setLength(value.toInt()); - } - buffer.close(); - if (m_current > infoList.count() - 1) - m_current = 0; - m_block_update_signals = TRUE; - foreach(FileInfo *info, infoList) - load(new PlayListItem(info, &settings)); //using one and the same settings object for all playlist items - m_block_update_signals = FALSE; - doCurrentVisibleRequest(); -} - -void PlayListModel::writeSettings() -{ - QFile file(QDir::homePath() +"/.qmmp/playlist.txt"); - file.open(QIODevice::WriteOnly); - foreach(PlayListItem* m, m_items) - { - file.write(QString("file=%1").arg(m->url()).toUtf8() +"\n"); - file.write(QString("title=%1").arg(m->title()).toUtf8() +"\n"); - file.write(QString("artist=%1").arg(m->artist()).toUtf8() +"\n"); - file.write(QString("album=%1").arg(m->album()).toUtf8() +"\n"); - file.write(QString("comment=%1").arg(m->comment()).toUtf8() +"\n"); - file.write(QString("genre=%1").arg(m->genre()).toUtf8() +"\n"); - file.write(QString("year=%1").arg(m->year()).toUtf8() +"\n"); - file.write(QString("track=%1").arg(m->track()).toUtf8() +"\n"); - file.write(QString("length=%1").arg(m->length()).toUtf8() +"\n"); - } - file.close(); - QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat); - settings.setValue("Playlist/current", m_current); -} - -void PlayListModel::addFile(const QString& path) -{ - if (path.isEmpty()) - return; - /*if(path.startsWith("http://")) - load(new PlayListItem(path)); - else if(Decoder::supports(path)) - load(new PlayListItem(path));*/ - QList playList = Decoder::createPlayList(path); - foreach(FileInfo *info, playList) - emit load(new PlayListItem(info)); - - m_play_state->prepare(); -} - -FileLoader * PlayListModel::createFileLoader() -{ - FileLoader* f_loader = new FileLoader(this); -// f_loader->setStackSize(20 * 1024 * 1024); - m_running_loaders << f_loader; - connect(f_loader,SIGNAL(newPlayListItem(PlayListItem*)),this,SLOT(load(PlayListItem*)),Qt::QueuedConnection); - connect(f_loader,SIGNAL(finished()),this,SLOT(preparePlayState())); - connect(f_loader,SIGNAL(finished()),f_loader,SLOT(deleteLater())); - return f_loader; -} - -void PlayListModel::addFiles(const QStringList &files) -{ - FileLoader* f_loader = createFileLoader(); - f_loader->setFilesToLoad(files); - f_loader->start(QThread::IdlePriority); -} - -void PlayListModel::addDirectory(const QString& s) -{ - FileLoader* f_loader = createFileLoader(); - f_loader->setDirectoryToLoad(s); - f_loader->start(QThread::IdlePriority); -} - -void PlayListModel::addFileList(const QStringList &l) -{ -// qWarning("void// PlayListModel::addFileList(const QStringList &l)"); - foreach(QString str,l) - { - QFileInfo f_info(str); - if (f_info.exists()) - { - if (f_info.isDir()) - addDirectory(str); - else - { - addFile(str); - loadPlaylist(str); - } - } - // Do processing the rest of events to avoid GUI freezing - QApplication::processEvents(QEventLoop::AllEvents,10); - } -} - -bool PlayListModel::setFileList(const QStringList & l) -{ - bool model_cleared = FALSE; - foreach(QString str,l) - { - QFileInfo f_info(str); - if (f_info.exists()) - { - if (!model_cleared) - { - clear(); - model_cleared = TRUE; - } - if (f_info.isDir()) - addDirectory(str); - else - { - addFile(str); - loadPlaylist(str); - } - } - // Do processing the rest of events to avoid GUI freezing - QApplication::processEvents(QEventLoop::AllEvents,10); - } - - return model_cleared; -} - -int PlayListModel::firstSelectedUpper(int row) -{ - for (int i = row - 1;i >= 0;i--) - { - if (isSelected(i)) - return i; - } - return -1; -} - -int PlayListModel::firstSelectedLower(int row) -{ - for (int i = row + 1;i < count() ;i++) - { - if (isSelected(i)) - return i; - } - return -1; -} - -void PlayListModel::moveItems(int from, int to) -{ - // Get rid of useless work - if (from == to) - return; - - QList selected_rows = getSelectedRows(); - - if (!(bottommostInSelection(from) == INVALID_ROW || - from == INVALID_ROW || - topmostInSelection(from) == INVALID_ROW) - ) - { - if (from > to) - foreach(int i, selected_rows) - if (i + to - from < 0) - break; - else - m_items.move(i,i + to - from); - else - for (int i = selected_rows.count() - 1; i >= 0; i--) - if (selected_rows[i] + to -from >= m_items.count()) - break; - else - m_items.move(selected_rows[i],selected_rows[i] + to - from); - - m_current = m_items.indexOf(m_currentItem); - - emit listChanged(); - } -} - - - -int PlayListModel::topmostInSelection(int row) -{ - if (row == 0) - return 0; - - for (int i = row - 1;i >= 0;i--) - { - if (isSelected(i)) - continue; - else - return i + 1; - } - return 0; -} - -int PlayListModel::bottommostInSelection(int row) -{ - if (row >= m_items.count() - 1) - return row; - - for (int i = row + 1;i < count() ;i++) - { - if (isSelected(i)) - continue; - else - return i - 1; - } - return count() - 1; -} - -const SimpleSelection& PlayListModel::getSelection(int row) -{ - m_selection.m_top = topmostInSelection(row); - m_selection.m_anchor = row; - m_selection.m_bottom = bottommostInSelection(row); - m_selection.m_selected_rows = getSelectedRows(); - return m_selection; -} - -QList PlayListModel::getSelectedRows() const -{ - QListselected_rows; - for (int i = 0;iisSelected()) - { - selected_rows.append(i); - } - } - return selected_rows; -} - -QList< PlayListItem * > PlayListModel::getSelectedItems() const -{ - QListselected_items; - for (int i = 0;iisSelected()) - { - selected_items.append(m_items[i]); - } - } - return selected_items; -} - -void PlayListModel::addToQueue() -{ - QList selected_items = getSelectedItems(); - foreach(PlayListItem* file,selected_items) - {/* - if(isQueued(file)) - m_queued_songs.removeAt(m_queued_songs.indexOf(file)); - else - m_queued_songs.append(file); - */ - setQueued(file); - } - emit listChanged(); -} - -void PlayListModel::setQueued(PlayListItem* file) -{ - if (isQueued(file)) - m_queued_songs.removeAt(m_queued_songs.indexOf(file)); - else - m_queued_songs.append(file); - - emit listChanged(); -} - -bool PlayListModel::isQueued(PlayListItem* f) const -{ - return m_queued_songs.contains(f); -} - -void PlayListModel::setCurrentToQueued() -{ - setCurrent(row(m_queued_songs.at(0))); - m_queued_songs.pop_front(); -} - -bool PlayListModel::isEmptyQueue() const -{ - return m_queued_songs.isEmpty(); -} - -void PlayListModel::randomizeList() -{ - for (int i = 0;i < m_items.size();i++) - m_items.swap(qrand()%m_items.size(),qrand()%m_items.size()); - - m_current = m_items.indexOf(m_currentItem); - emit listChanged(); -} - -void PlayListModel::reverseList() -{ - for (int i = 0;i < m_items.size()/2;i++) - m_items.swap(i,m_items.size() - i - 1); - - m_current = m_items.indexOf(m_currentItem); - emit listChanged(); -} - -////===============THE BEGINNING OF SORT IMPLEMENTATION =======================//// - -// First we'll implement bundle of static compare procedures -// to sort items in different ways -static bool _titleLessComparator(PlayListItem* s1,PlayListItem* s2) -{ - return s1->title() < s2->title(); -} - -static bool _titleGreaterComparator(PlayListItem* s1,PlayListItem* s2) -{ - return s1->title() > s2->title(); -} - -static bool _pathAndFilenameLessComparator(PlayListItem* s1,PlayListItem* s2) -{ - return s1->url() < s2->url(); -} - -static bool _pathAndFilenameGreaterComparator(PlayListItem* s1,PlayListItem* s2) -{ - return s1->url() > s2->url(); -} - -static bool _filenameLessComparator(PlayListItem* s1,PlayListItem* s2) -{ - QFileInfo i_s1(s1->url()); - QFileInfo i_s2(s2->url()); - return i_s1.baseName() < i_s2.baseName(); -} - -static bool _filenameGreaterComparator(PlayListItem* s1,PlayListItem* s2) -{ - QFileInfo i_s1(s1->url()); - QFileInfo i_s2(s2->url()); - return i_s1.baseName() > i_s2.baseName(); -} - -static bool _dateLessComparator(PlayListItem* s1,PlayListItem* s2) -{ - return s1->year() < s2->year(); -} - -static bool _dateGreaterComparator(PlayListItem* s1,PlayListItem* s2) -{ - return s1->year() > s2->year(); -} - -static bool _trackLessComparator(PlayListItem* s1,PlayListItem* s2) -{ - return s1->track() < s2->track(); -} - -static bool _trackGreaterComparator(PlayListItem* s1,PlayListItem* s2) -{ - return s1->track() > s2->track(); -} - -// This is main sort method -void PlayListModel::doSort(int sort_mode,QList& list_to_sort) -{ - QList::iterator begin; - QList::iterator end; - - begin = list_to_sort.begin(); - end = list_to_sort.end(); - - bool(*compareLessFunc)(PlayListItem*,PlayListItem*) = 0; - bool(*compareGreaterFunc)(PlayListItem*,PlayListItem*) = 0; - - switch (sort_mode) - { - case TITLE: - compareLessFunc = _titleLessComparator; - compareGreaterFunc = _titleGreaterComparator; - break; - case FILENAME: - compareLessFunc = _filenameLessComparator; - compareGreaterFunc = _filenameGreaterComparator; - break; - case PATH_AND_FILENAME: - compareLessFunc = _pathAndFilenameLessComparator; - compareGreaterFunc = _pathAndFilenameGreaterComparator; - break; - case DATE: - compareLessFunc = _dateLessComparator; - compareGreaterFunc = _dateGreaterComparator; - break; - //qWarning("TODO Sort by Date: %s\t%d",__FILE__,__LINE__); - case TRACK: - compareLessFunc = _trackLessComparator; - compareGreaterFunc = _trackGreaterComparator; - break; - default: - compareLessFunc = _titleLessComparator; - compareGreaterFunc = _titleGreaterComparator; - } - - static bool sorted_asc = false; - if (!sorted_asc) - { - qSort(begin,end,compareLessFunc); - sorted_asc = true; - } - else - { - qSort(begin,end,compareGreaterFunc); - sorted_asc = false; - } - - m_current = m_items.indexOf(m_currentItem); -} - -void PlayListModel::sortSelection(int mode) -{ - QListselected_items = getSelectedItems(); - QListselected_rows = getSelectedRows(); - - doSort(mode,selected_items); - - for (int i = 0;i < selected_rows.count();i++) - m_items.replace(selected_rows[i],selected_items[i]); - - m_current = m_items.indexOf(m_currentItem); - emit listChanged(); -} - -void PlayListModel::sort(int mode) -{ - doSort(mode,m_items); - emit listChanged(); -} - -////=============== THE END OF SORT IMPLEMENTATION =======================//// - -void PlayListModel::prepareForShufflePlaying(bool val) -{ - if (m_play_state) - delete m_play_state; - - if (val) - m_play_state = new ShufflePlayState(this); - else - m_play_state = new NormalPlayState(this); - -} - -void PlayListModel::prepareForRepeatablePlaying(bool val) -{ - is_repeatable_list = val; -} - -void PlayListModel::doCurrentVisibleRequest() -{ - emit currentChanged(); - emit listChanged(); -} - -void PlayListModel::setUpdatesEnabled(bool yes) -{ - if (yes) - { - m_block_update_signals = false; - emit listChanged(); - } - else - { - m_block_update_signals = true; - } -} - -void PlayListModel::loadPlaylist(const QString &f_name) -{ - PlaylistFormat* prs = PlaylistParser::instance()->findByPath(f_name); - if (prs) - { - QFile file(f_name); - if (file.open(QIODevice::ReadOnly)) - { - //clear(); - QStringList list = prs->decode(QTextStream(&file).readAll()); - for (int i = 0; i < list.size(); ++i) - { - if (QFileInfo(list.at(i)).isRelative() && !list.at(i).contains("://")) - QString path = list[i].prepend(QFileInfo(f_name).canonicalPath () + QDir::separator ()); - } - addFiles(list); - file.close(); - } - else - qWarning("Error opening %s",f_name.toLocal8Bit().data()); - } -} - -void PlayListModel::savePlaylist(const QString & f_name) -{ - PlaylistFormat* prs = PlaylistParser::instance()->findByPath(f_name); - if (prs) - { - QFile file(f_name); - if (file.open(QIODevice::WriteOnly)) - { - QTextStream ts(&file); - QList songs; - foreach(PlayListItem* item, m_items) - songs << item; - ts << prs->encode(songs); - file.close(); - } - else - qWarning("Error opening %s",f_name.toLocal8Bit().data()); - } -} - -bool PlayListModel::isFileLoaderRunning() const -{ - foreach(FileLoader* l,m_running_loaders) - if (l && l->isRunning()) - return TRUE; - - return FALSE; -} - -void PlayListModel::preparePlayState() -{ - m_play_state->prepare(); -} diff --git a/src/ui/playlistmodel.h b/src/ui/playlistmodel.h deleted file mode 100644 index a5231b44f..000000000 --- a/src/ui/playlistmodel.h +++ /dev/null @@ -1,353 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2006-2008 by Ilya Kotov * - * forkotov02@hotmail.ru * - * * - * 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. * - ***************************************************************************/ -#ifndef PLAYLISTMODEL_H -#define PLAYLISTMODEL_H - -#include -#include -#include -#include -#include -#include - -//#include "fileloader.h" -class FileLoader; - -/** - @author Ilya Kotov -*/ - -class PlayListItem; -class PlayState; -class PlaylistFormat; -class PlayListModel; - -struct SimpleSelection -{ - SimpleSelection() - { - ; - } - inline bool isValid()const - { - return (m_bottom != -1) && (m_anchor != -1) && (m_top != -1); - } - inline void dump()const - { - qWarning("top: %d\tbotom: %d\tanchor: %d",m_top,m_bottom,m_anchor); - } - inline int count()const - { - return m_bottom - m_top + 1; - } - int m_bottom; - int m_top; - int m_anchor; - QListm_selected_rows; -}; - -/*! - * Helper class used for tags update after details dialog closing. - * @author Vladimir Kuznetsov - */ -class TagUpdater : public QObject -{ - Q_OBJECT - QObject* m_observable; - PlayListItem* m_item; -public: - TagUpdater(QObject* o, PlayListItem* item); -protected slots: - void updateTag(); -}; - - -class PlayListModel : public QObject -{ - Q_OBJECT -public: - PlayListModel(QObject *parent = 0); - - ~PlayListModel(); - - int count(); - PlayListItem* currentItem(); - int row(PlayListItem* item)const - { - return m_items.indexOf(item); - } - PlayListItem* item(int row)const - { - return m_items.at(row); - } - int currentRow(); - bool setCurrent (int); - bool isSelected(int); - void setSelected(int, bool); - - bool next(); - bool previous(); - - QList getTitles(int,int); - QList getTimes(int,int); - - void moveItems(int from,int to); - - /*! - * Returns \b true if \b f file is in play queue, else return \b false - */ - bool isQueued(PlayListItem* item) const; - - bool isRepeatableList()const - { - return is_repeatable_list; - } - - /*! - * Sets current song to the file that is nex in queue, if queue is empty - does nothing - */ - void setCurrentToQueued(); - - /*! - * Returns \b true if play queue is empty,otherwise - \b false. - */ - bool isEmptyQueue()const; - - /*! - * Returns index of \b f file in queue.e - */ - int queuedIndex(PlayListItem* item)const - { - return m_queued_songs.indexOf(item); - } - - /*! - * Returns current selection(playlist can contain a lot of selections, - * this method returns selection which \b row belongs to) - */ - const SimpleSelection& getSelection(int row); - - /*! - * Returns vector with selected rows indexes. - */ - QList getSelectedRows()const; - /*! - * Returns vector of \b PlayListItem pointers that are selected. - */ - QList getSelectedItems()const; - - QList items()const - { - return m_items; - } - - /*! - * Returns number of first item that selected upper the \b row item. - */ - int firstSelectedUpper(int row); - - /*! - * Returns number of first item that selected lower the \b row item. - */ - int firstSelectedLower(int row); - - /*! - * Returns total lenght in seconds of all songs. - */ - int totalLength()const - { - return m_total_length; - } - - /*! - * Loads playlist with \b f_name name. - */ - void loadPlaylist(const QString& f_name); - - /*! - * Saves current songs to the playlist with \b f_name name. - */ - void savePlaylist(const QString& f_name); - - /*! - * Enum of available sort modes - */ - enum SortMode - { - TITLE,FILENAME,PATH_AND_FILENAME,DATE,TRACK - }; - -signals: - void listChanged(); - void currentChanged(); - void firstAdded(); - -public slots: - void load(PlayListItem *); - void clear(); - void clearSelection(); - void removeSelected(); - void removeUnselected(); - void invertSelection(); - void selectAll(); - void showDetails(); - void doCurrentVisibleRequest(); - - void addFile(const QString&); - - /*! - * Adds the list \b l of files to the model. - */ - void addFiles(const QStringList& l); - - /*! - * Adds \b dir to the model. - */ - void addDirectory(const QString& dir); - - /*! - * Loads list of files (regular files or directories), - * returns \b TRUE if at least one file has been successfully loaded, - * otherwise \b FALSE - */ - bool setFileList(const QStringList&); - - void addFileList(const QStringList &l); - - void randomizeList(); - void reverseList(); - - /*! - * Prepares model for shuffle playing. \b yes parameter is true - model iterates in shuffle mode. - */ - void prepareForShufflePlaying(bool yes); - - /*! - * Prepares model for shuffle playing. \b yes parameter is true - model iterates in repeat mode. - */ - void prepareForRepeatablePlaying(bool); - - /*! - * Sorts selected items in \b mode sort mode. - */ - void sortSelection(int mode); - - /*! - * Sorts items in \b mode sort mode. - */ - void sort(int mode); - - /*! - * Adds selected items to play queue. - */ - void addToQueue(); - - /*! - * Sets \b f media file to queue. - */ - void setQueued(PlayListItem* f); - - void preparePlayState(); - -private: - - /*! - * This internal method performs sorting of \b list_to_sort list of items. - */ - void doSort(int mode,QList& list_to_sort); - /*! - * Returns topmost row in current selection - */ - int topmostInSelection(int); - - /*! - * Returns bottommost row in current selection - */ - int bottommostInSelection(int); - - /*! - * Creates and initializes file loader object. - */ - FileLoader* createFileLoader(); - - - /*! - * Is someone of file loaders is running? - */ - bool isFileLoaderRunning()const; - - /*! - * Removes items from model. If \b inverted is \b false - - * selected items will be removed, else - unselected. - */ - void removeSelection(bool inverted = false); - -private: - - QList m_items; - QList m_editing_items; - PlayListItem* m_currentItem; - - int m_current; - void readSettings(); - void writeSettings(); - - void setUpdatesEnabled(bool); - - bool updatesEnabled()const - { - return !m_block_update_signals; - } - - /*! - * This flyweight object represents current selection. - */ - SimpleSelection m_selection; - - /*! - * Songs in play queue. - */ - QListm_queued_songs; - - /*! - * Is playlist repeatable? - */ - bool is_repeatable_list; - - /// Current playing state (Normal or Shuffle) - PlayState* m_play_state; - - bool m_block_update_signals; - - int m_total_length; - - typedef QPointer GuardedFileLoader; - - /*! Vector of currently running file loaders. - * All loaders are automatically sheduled for deletion - * when finished. - */ - QVector m_running_loaders; - - friend class MainWindow; -}; - - -#endif diff --git a/src/ui/playlisttitlebar.cpp b/src/ui/playlisttitlebar.cpp index f218504d5..73e66f881 100644 --- a/src/ui/playlisttitlebar.cpp +++ b/src/ui/playlisttitlebar.cpp @@ -22,9 +22,10 @@ #include #include +#include + #include "dock.h" #include "button.h" -#include "playlistmodel.h" #include "playlisttitlebar.h" #include "skin.h" diff --git a/src/ui/playstate.cpp b/src/ui/playstate.cpp deleted file mode 100644 index 373619574..000000000 --- a/src/ui/playstate.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2006 by Ilya Kotov * - * forkotov02@hotmail.ru * - * * - * 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 - -ShufflePlayState::ShufflePlayState(PlayListModel * model) : PlayState(model) -{ - prepare(); -} - -bool ShufflePlayState::next() -{ - int itm_count = m_model->items().count(); - - if (itm_count > 0) - { - if (m_shuffled_current >= m_shuffled_indexes.count() -1 ) - { - if (!m_model->isRepeatableList()) - return FALSE; - else - prepare(); - } - - if (m_shuffled_current < m_shuffled_indexes.count() - 1)m_shuffled_current++; - - return m_model->setCurrent(m_shuffled_indexes.at(m_shuffled_current)); - } - return FALSE; -} - -bool ShufflePlayState::previous() -{ - int itm_count = m_model->items().count(); - - if (itm_count > 0) - { - if (m_shuffled_current <= 0) - { - if (!m_model->isRepeatableList()) - return FALSE; - else - { - prepare(); - m_shuffled_current = m_shuffled_indexes.count() - 1; - } - } - - if (itm_count > 1) m_shuffled_current --; - - m_model->setCurrent(m_shuffled_indexes.at(m_shuffled_current)); - return TRUE; - } - return FALSE; -} - -void ShufflePlayState::prepare() -{ - resetState(); - for (int i = 0;i < m_model->items().count();i++) - { - if (i != m_model->currentRow()) - m_shuffled_indexes << i; - } - - for (int i = 0;i < m_shuffled_indexes.count();i++) - m_shuffled_indexes.swap(qrand()%m_shuffled_indexes.size(),qrand()%m_shuffled_indexes.size()); - - m_shuffled_indexes.prepend(m_model->currentRow()); -} - -void ShufflePlayState::resetState() -{ - m_shuffled_indexes.clear(); - m_shuffled_current = 0; -} - - - - - -NormalPlayState::NormalPlayState(PlayListModel * model) : PlayState(model) -{} - - -bool NormalPlayState::next() -{ - int itm_count = m_model->items().count(); - - if (itm_count > 0) - { - if ( m_model->currentRow() == itm_count - 1) - { - if (m_model->isRepeatableList()) - return m_model->setCurrent(0); - else - return FALSE; - } - return m_model->setCurrent(m_model->currentRow() + 1); - } - else - return FALSE; -} - -bool NormalPlayState::previous() -{ - int itm_count = m_model->items().count(); - - if (itm_count > 0) - { - if ( m_model->currentRow() < 1 && !m_model->isRepeatableList()) - return FALSE; - else if (m_model->setCurrent(m_model->currentRow() - 1)) - return TRUE; - else if (m_model->isRepeatableList()) - return m_model->setCurrent(m_model->items().count() - 1); - } - - return FALSE; -} - diff --git a/src/ui/playstate.h b/src/ui/playstate.h deleted file mode 100644 index e4af7fa6f..000000000 --- a/src/ui/playstate.h +++ /dev/null @@ -1,109 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2006 by Ilya Kotov * - * forkotov02@hotmail.ru * - * * - * 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. * - ***************************************************************************/ - -#ifndef _PLAYSTATE_H -#define _PLAYSTATE_H - -/** - @author Vladimir Kuznetsov - */ - -#include - -/*! - * Abstract class that represents data model playing states - */ -class PlayState -{ -public: - /*! Makes single step forward through songs list. - * If the step has done returns \b true, otherwise \b false - */ - virtual bool next() = 0; - - /*! Makes single step back through songs list. - * If the step has done returns \b true, otherwise \b false - */ - virtual bool previous() = 0; - - /*! - * Service method, resets state to it's defaults. - */ - virtual void resetState() - { - ; - }; - - /*! - * Service method, can be used for state initializing. - */ - virtual void prepare() - { - ; - } - virtual ~PlayState() - { - ; - } - PlayState(PlayListModel* model) : m_model(model) - { - ; - } -protected: - - /// Data model - PlayListModel* m_model; -}; - -/*! - * Represents normal playing state. - * @author Vladimir Kuznetsov - */ -class NormalPlayState : public PlayState -{ -public: - virtual bool next(); - virtual bool previous(); - NormalPlayState(PlayListModel* model); -}; - -/*! - * Represents shuffle playing state. - * @author Vladimir Kuznetsov - */ -class ShufflePlayState : public PlayState -{ -public: - virtual bool next(); - virtual bool previous(); - virtual void prepare(); - ShufflePlayState(PlayListModel* model); - virtual void resetState(); -private: - - /// Current shuffled index. - int m_shuffled_current; - - /// List of indexes used for shuffled playing. - QList m_shuffled_indexes; -}; - - -#endif diff --git a/src/ui/ui.pro b/src/ui/ui.pro index 5bda93a6f..a9391b9a1 100644 --- a/src/ui/ui.pro +++ b/src/ui/ui.pro @@ -12,7 +12,6 @@ FORMS += ./forms/configdialog.ui \ ./forms/addurldialog.ui HEADERS += mainwindow.h \ - fileloader.h \ button.h \ display.h \ skin.h \ @@ -21,7 +20,6 @@ HEADERS += mainwindow.h \ number.h \ playlist.h \ listwidget.h \ - playlistmodel.h \ pixmapwidget.h \ playlisttitlebar.h \ configdialog.h \ @@ -60,12 +58,10 @@ HEADERS += mainwindow.h \ titlebarcontrol.h \ shadedvisual.h \ shadedbar.h \ - playlistitem.h \ builtincommandlineoption.h SOURCES += mainwindow.cpp \ mp3player.cpp \ - fileloader.cpp \ button.cpp \ display.cpp \ skin.cpp \ @@ -74,7 +70,6 @@ SOURCES += mainwindow.cpp \ number.cpp \ playlist.cpp \ listwidget.cpp \ - playlistmodel.cpp \ pixmapwidget.cpp \ playlisttitlebar.cpp \ configdialog.cpp \ @@ -94,7 +89,6 @@ SOURCES += mainwindow.cpp \ pluginitem.cpp \ volumebar.cpp \ balancebar.cpp \ - playstate.cpp \ symboldisplay.cpp \ playlistcontrol.cpp \ qmmpstarter.cpp \ @@ -111,7 +105,6 @@ SOURCES += mainwindow.cpp \ titlebarcontrol.cpp \ shadedvisual.cpp \ shadedbar.cpp \ - playlistitem.cpp \ builtincommandlineoption.cpp #Some conf to redirect intermediate stuff in separate dirs -- cgit v1.2.3-13-gbd6f