diff options
| author | trialuser02 <trialuser02@90c681e8-e032-0410-971d-27865f9a5e38> | 2015-01-09 12:01:22 +0000 |
|---|---|---|
| committer | trialuser02 <trialuser02@90c681e8-e032-0410-971d-27865f9a5e38> | 2015-01-09 12:01:22 +0000 |
| commit | ebd7f9bc697973366de8a6bf7265051e825e0680 (patch) | |
| tree | 1feb9df1c5fe3493e9aa1dd8f5d6233a38ae9d3c /src/qmmpui | |
| parent | bc7ad688c646afd2a89e5c5ff58696f2df2c8605 (diff) | |
| download | qmmp-ebd7f9bc697973366de8a6bf7265051e825e0680.tar.gz qmmp-ebd7f9bc697973366de8a6bf7265051e825e0680.tar.bz2 qmmp-ebd7f9bc697973366de8a6bf7265051e825e0680.zip | |
renaming experimental branch
git-svn-id: http://svn.code.sf.net/p/qmmp-dev/code/trunk/qmmp@4675 90c681e8-e032-0410-971d-27865f9a5e38
Diffstat (limited to 'src/qmmpui')
| -rw-r--r-- | src/qmmpui/CMakeLists.txt | 28 | ||||
| -rw-r--r-- | src/qmmpui/aboutdialog.cpp | 6 | ||||
| -rw-r--r-- | src/qmmpui/groupedcontainer.cpp | 98 | ||||
| -rw-r--r-- | src/qmmpui/groupedcontainer_p.h | 5 | ||||
| -rw-r--r-- | src/qmmpui/normalcontainer.cpp | 48 | ||||
| -rw-r--r-- | src/qmmpui/normalcontainer_p.h | 5 | ||||
| -rw-r--r-- | src/qmmpui/playlistcontainer.cpp | 205 | ||||
| -rw-r--r-- | src/qmmpui/playlistcontainer_p.h | 10 | ||||
| -rw-r--r-- | src/qmmpui/playlistgroup.cpp | 10 | ||||
| -rw-r--r-- | src/qmmpui/playlistmanager.cpp | 10 | ||||
| -rw-r--r-- | src/qmmpui/playlistmanager.h | 4 | ||||
| -rw-r--r-- | src/qmmpui/playlistmodel.cpp | 351 | ||||
| -rw-r--r-- | src/qmmpui/playlistmodel.h | 34 | ||||
| -rw-r--r-- | src/qmmpui/playlisttask.cpp | 371 | ||||
| -rw-r--r-- | src/qmmpui/playlisttask_p.h | 52 | ||||
| -rw-r--r-- | src/qmmpui/playlisttrack.cpp | 54 | ||||
| -rw-r--r-- | src/qmmpui/playlisttrack.h | 33 | ||||
| -rw-r--r-- | src/qmmpui/qmmpuisettings.cpp | 4 | ||||
| -rw-r--r-- | src/qmmpui/qmmpuisettings.h | 2 | ||||
| -rw-r--r-- | src/qmmpui/tagupdater.cpp | 6 |
20 files changed, 755 insertions, 581 deletions
diff --git a/src/qmmpui/CMakeLists.txt b/src/qmmpui/CMakeLists.txt index 14525d47e..18aab75ce 100644 --- a/src/qmmpui/CMakeLists.txt +++ b/src/qmmpui/CMakeLists.txt @@ -1,6 +1,6 @@ project(libqmmpui) -cmake_minimum_required(VERSION 2.4.7) +cmake_minimum_required(VERSION 2.8.6) if(COMMAND cmake_policy) cmake_policy(SET CMP0003 OLD) @@ -59,6 +59,7 @@ SET(libqmmpui_SRCS addurldialog.cpp qmmpuiplugincache.cpp tagupdater.cpp + playlisttask.cpp ) SET(libqmmpui_HDRS @@ -83,27 +84,6 @@ SET(libqmmpui_HDRS qmmpuiplugincache_p.h ) -SET(libqmmpui_MOC_HDRS - uihelper.h - filedialog.h - qtfiledialog_p.h - fileloader_p.h - playlistmodel.h - mediaplayer.h - detailsdialog.h - tageditor_p.h - playlistmanager.h - templateeditor.h - jumptotrackdialog_p.h - configdialog.h - aboutdialog_p.h - qmmpuisettings.h - radioitemdelegate_p.h - playlistdownloader.h - addurldialog_p.h - tagupdater_p.h -) - SET(libqmmpui_DEVEL_HDRS commandlinemanager.h commandlineoption.h @@ -145,11 +125,9 @@ QT4_WRAP_UI(libqmmpui_UIS_H ${libqmmpui_UIS}) QT4_ADD_RESOURCES(libqmmpui_RCC_SRCS translations/libqmmpui_locales.qrc txt/txt.qrc images/qmmpui_images.qrc) -QT4_WRAP_CPP(libqmmpui_MOC_SRCS ${libqmmpui_MOC_HDRS}) - include_directories(${CMAKE_CURRENT_BINARY_DIR}) -ADD_LIBRARY(qmmpui SHARED ${libqmmpui_SRCS} ${libqmmpui_MOC_SRCS} ${libqmmpui_RCC_SRCS} ${libqmmpui_UIS_H} ${libqmmpui_HDRS}) +ADD_LIBRARY(qmmpui SHARED ${libqmmpui_SRCS} ${libqmmpui_RCC_SRCS} ${libqmmpui_UIS_H} ${libqmmpui_HDRS}) target_link_libraries(qmmpui ${QT_LIBRARIES} -lqmmp) add_dependencies(qmmpui libqmmp) SET_TARGET_PROPERTIES(qmmpui PROPERTIES VERSION ${QMMP_VERSION} SOVERSION ${QMMP_SOVERSION}) diff --git a/src/qmmpui/aboutdialog.cpp b/src/qmmpui/aboutdialog.cpp index 073a3187d..888f3ea68 100644 --- a/src/qmmpui/aboutdialog.cpp +++ b/src/qmmpui/aboutdialog.cpp @@ -1,5 +1,5 @@ -/*************************************************************************** -* Copyright (C) 2006-2013 by Ilya Kotov * +/************************************************************************** +* Copyright (C) 2006-2015 by Ilya Kotov * * forkotov02@hotmail.ru * * * * This program is free software; you can redistribute it and/or modify * @@ -68,7 +68,7 @@ QString AboutDialog::loadAbout() text.append(tr("Using Qt %1 (compiled with Qt %2)" ).arg(qVersion()).arg(QT_VERSION_STR) + "</p>"); text.append("<p>"); - text.append(tr("(c) %1-%2 Qmmp Development Team").arg(2006).arg(2014)+"<br>"); + text.append(tr("(c) %1-%2 Qmmp Development Team").arg(2006).arg(2015)+"<br>"); text.append("<a href=\"http://qmmp.ylsoftware.com/\">http://qmmp.ylsoftware.com/</a><br>"); text.append("<a href=\"http://code.google.com/p/qmmp/\">http://code.google.com/p/qmmp/</a>"); text.append("</p>"); diff --git a/src/qmmpui/groupedcontainer.cpp b/src/qmmpui/groupedcontainer.cpp index e98cf88f6..c6628a845 100644 --- a/src/qmmpui/groupedcontainer.cpp +++ b/src/qmmpui/groupedcontainer.cpp @@ -23,7 +23,6 @@ GroupedContainer::GroupedContainer() { - m_reverted = false; m_update = true; } @@ -65,31 +64,26 @@ void GroupedContainer::addTrack(PlayListTrack *track) void GroupedContainer::addTracks(QList<PlayListTrack *> tracks) { - PlayListGroup *group = m_groups.isEmpty() ? 0 : m_groups.last(); + bool found = false; - foreach (PlayListTrack *track, tracks) + for(int i = 0; i < tracks.count(); ++i) { - if(!group || track->groupName() != group->formattedTitle()) + found = false; + for(int j = m_groups.count() - 1; j >= 0; --j) { - group = 0; - foreach(PlayListGroup *g, m_groups) + if(m_groups.at(j)->formattedTitle() == tracks.at(i)->groupName()) { - if(track->groupName() == g->formattedTitle()) - { - group = g; - break; - } + found = true; + m_groups.at(j)->trackList.append(tracks[i]); + break; } } - if(!group) - { - group = new PlayListGroup(track->groupName()); - m_groups.append(group); - m_update = true; - } + if(found) + continue; - group->trackList.append(track); + m_groups << new PlayListGroup(tracks.at(i)->groupName()); + m_groups.last()->trackList.append(tracks.at(i)); } m_update = true; } @@ -123,11 +117,31 @@ void GroupedContainer::insertTrack(int index, PlayListTrack *track) addTrack(track); } +void GroupedContainer::replaceTracks(QList<PlayListTrack *> tracks) +{ + foreach (PlayListGroup *g, m_groups) + { + g->trackList.clear(); + } + clear(); + addTracks(tracks); +} + QList<PlayListGroup *> GroupedContainer::groups() const { return m_groups; } +QList<PlayListTrack *> GroupedContainer::tracks() const +{ + QList<PlayListTrack *> trackList; + for(int i = 0; i < m_groups.count(); ++i) + { + trackList.append(m_groups[i]->trackList); + } + return trackList; +} + QList<PlayListItem *> GroupedContainer::items() const { updateCache(); @@ -389,55 +403,21 @@ void GroupedContainer::reverseList() void GroupedContainer::randomizeList() { - QList<PlayListTrack *> tracks = takeAllTracks(); - - for (int i = 0; i < tracks.size(); i++) - tracks.swap(qrand()%tracks.size(),qrand()%tracks.size()); - - addTracks(tracks); -} - -void GroupedContainer::sort(int mode) -{ - if(mode == PlayListModel::ARTIST || mode == PlayListModel::ALBUM - || mode == PlayListModel::DATE || mode == PlayListModel::GROUP) - { - QList<PlayListTrack *> tracks = takeAllTracks(); - doSort(mode, tracks, m_reverted); - addTracks(tracks); - } - else + for(int i = 0; i < m_groups.count(); ++i) { - foreach (PlayListGroup *g, m_groups) + for (int j = 0; j < m_groups[i]->trackList.size(); j++) { - doSort(mode, g->trackList, m_reverted); + m_groups[i]->trackList.swap(qrand() % m_groups[i]->trackList.size(), + qrand() % m_groups[i]->trackList.size()); } - m_update = true; } - m_reverted = !m_reverted; -} -void GroupedContainer::sortSelection(int mode) -{ - QList<PlayListTrack *> tracks = takeAllTracks(); - QList<PlayListTrack *> selected_tracks; - QList<int> selected_indexes; - for(int i = 0; i < tracks.count(); ++i) + for(int i = 0; i < m_groups.count(); ++i) { - if(tracks[i]->isSelected()) - { - selected_tracks.append(tracks[i]); - selected_indexes.append(i); - } + m_groups.swap(qrand() % m_groups.size(), qrand() % m_groups.size()); } - doSort(mode, selected_tracks, m_reverted); - - for (int i = 0; i < selected_indexes.count(); i++) - tracks.replace(selected_indexes[i], selected_tracks[i]); - addTracks(tracks); - - m_reverted = !m_reverted; + m_update = true; } void GroupedContainer::updateCache() const diff --git a/src/qmmpui/groupedcontainer_p.h b/src/qmmpui/groupedcontainer_p.h index 241b07fc4..449493144 100644 --- a/src/qmmpui/groupedcontainer_p.h +++ b/src/qmmpui/groupedcontainer_p.h @@ -37,7 +37,9 @@ public: void addTrack(PlayListTrack *track); void addTracks(QList<PlayListTrack *> tracks); void insertTrack(int index, PlayListTrack *track); + void replaceTracks(QList<PlayListTrack *> tracks); QList<PlayListGroup *> groups() const; + QList<PlayListTrack *> tracks() const; QList<PlayListItem *> items() const; int count() const; int trackCount() const; @@ -61,13 +63,10 @@ public: void reverseList(); void randomizeList(); - void sort(int mode); - void sortSelection(int mode); private: void updateCache() const; QList<PlayListGroup *> m_groups; - bool m_reverted; mutable QList<PlayListItem *> m_items; mutable bool m_update; diff --git a/src/qmmpui/normalcontainer.cpp b/src/qmmpui/normalcontainer.cpp index 4e585b9d6..b26b33d06 100644 --- a/src/qmmpui/normalcontainer.cpp +++ b/src/qmmpui/normalcontainer.cpp @@ -21,9 +21,7 @@ #include "normalcontainer_p.h" NormalContainer::NormalContainer() -{ - m_reverted = false; -} +{} NormalContainer::~NormalContainer() { @@ -46,11 +44,25 @@ void NormalContainer::insertTrack(int index, PlayListTrack *track) m_items.append(track); } +void NormalContainer::replaceTracks(QList<PlayListTrack *> tracks) +{ + m_items.clear(); + addTracks(tracks); +} + QList<PlayListGroup *> NormalContainer::groups() const { return QList<PlayListGroup *>(); } +QList<PlayListTrack *> NormalContainer::tracks() const +{ + QList<PlayListTrack *> trackList; + for(int i = 0; i < m_items.count(); ++i) + trackList.append(dynamic_cast<PlayListTrack *>(m_items[i])); + return trackList; +} + QList<PlayListItem *> NormalContainer::items() const { return m_items; @@ -205,33 +217,3 @@ void NormalContainer::randomizeList() for (int i = 0; i < m_items.size(); i++) m_items.swap(qrand()%m_items.size(), qrand()%m_items.size()); } - -void NormalContainer::sort(int mode) -{ - QList<PlayListTrack *> tracks = takeAllTracks(); - doSort(mode, tracks, m_reverted); - addTracks(tracks); - m_reverted = !m_reverted; -} - -void NormalContainer::sortSelection(int mode) -{ - QList<PlayListTrack *> tracks = takeAllTracks(); - QList<PlayListTrack *> selected_tracks; - QList<int> selected_indexes; - for(int i = 0; i < tracks.count(); ++i) - { - if(tracks[i]->isSelected()) - { - selected_tracks.append(tracks[i]); - selected_indexes.append(i); - } - } - doSort(mode, selected_tracks, m_reverted); - - for (int i = 0; i < selected_indexes.count(); i++) - tracks.replace(selected_indexes[i], selected_tracks[i]); - - addTracks(tracks); - m_reverted = !m_reverted; -} diff --git a/src/qmmpui/normalcontainer_p.h b/src/qmmpui/normalcontainer_p.h index c2aab57f1..803b8ada0 100644 --- a/src/qmmpui/normalcontainer_p.h +++ b/src/qmmpui/normalcontainer_p.h @@ -36,7 +36,9 @@ public: void addTracks(QList<PlayListTrack *> tracks); void insertTrack(int index, PlayListTrack *track); + void replaceTracks(QList<PlayListTrack *> tracks); QList<PlayListGroup *> groups() const; + QList<PlayListTrack *> tracks() const; QList<PlayListItem *> items() const; int count() const; int trackCount() const; @@ -60,12 +62,9 @@ public: void reverseList(); void randomizeList(); - void sort(int mode); - void sortSelection(int mode); private: QList<PlayListItem *> m_items; - bool m_reverted; }; #endif // NORMALCONTAINER_P_H diff --git a/src/qmmpui/playlistcontainer.cpp b/src/qmmpui/playlistcontainer.cpp index 7772d1b3e..c7aaf3482 100644 --- a/src/qmmpui/playlistcontainer.cpp +++ b/src/qmmpui/playlistcontainer.cpp @@ -28,208 +28,3 @@ void PlayListContainer::addTrack(PlayListTrack *track) { addTracks(QList<PlayListTrack *> () << track); } - -////===============THE BEGINNING OF SORT IMPLEMENTATION =======================//// - -// First we'll implement bundle of static compare procedures -// to sort items in different ways - -//by title -static bool _titleLessComparator(PlayListTrack* s1,PlayListTrack* s2) -{ - return QString::localeAwareCompare (s1->value(Qmmp::TITLE), s2->value(Qmmp::TITLE)) < 0; -} - -static bool _titleGreaterComparator(PlayListTrack* s1,PlayListTrack* s2) -{ - return QString::localeAwareCompare (s1->value(Qmmp::TITLE), s2->value(Qmmp::TITLE)) > 0; -} -//by album+disc -static bool _discnumberLessComparator(PlayListTrack* s1,PlayListTrack* s2) -{ - return QString::localeAwareCompare (s1->value(Qmmp::DISCNUMBER), s2->value(Qmmp::DISCNUMBER)) < 0; -} - -static bool _discnumberGreaterComparator(PlayListTrack* s1,PlayListTrack* s2) -{ - return QString::localeAwareCompare (s1->value(Qmmp::DISCNUMBER), s2->value(Qmmp::DISCNUMBER)) > 0; -} -//by album -static bool _albumLessComparator(PlayListTrack* s1,PlayListTrack* s2) -{ - return QString::localeAwareCompare (s1->value(Qmmp::ALBUM), s2->value(Qmmp::ALBUM)) < 0; -} - -static bool _albumGreaterComparator(PlayListTrack* s1,PlayListTrack* s2) -{ - return QString::localeAwareCompare (s1->value(Qmmp::ALBUM), s2->value(Qmmp::ALBUM)) > 0; -} -//by artist -static bool _artistLessComparator(PlayListTrack* s1,PlayListTrack* s2) -{ - return QString::localeAwareCompare (s1->value(Qmmp::ARTIST), s2->value(Qmmp::ARTIST)) < 0; -} - -static bool _artistGreaterComparator(PlayListTrack* s1,PlayListTrack* s2) -{ - return QString::localeAwareCompare (s1->value(Qmmp::ARTIST), s2->value(Qmmp::ARTIST)) > 0; -} -//by album artist -static bool _albumArtistLessComparator(PlayListTrack* s1,PlayListTrack* s2) -{ - return QString::localeAwareCompare (s1->value(Qmmp::ALBUMARTIST), s2->value(Qmmp::ALBUMARTIST)) < 0; -} - -static bool _albumArtistGreaterComparator(PlayListTrack* s1,PlayListTrack* s2) -{ - return QString::localeAwareCompare (s1->value(Qmmp::ALBUMARTIST), s2->value(Qmmp::ALBUMARTIST)) > 0; -} -//by path -static bool _pathAndFilenameLessComparator(PlayListTrack* s1,PlayListTrack* s2) -{ - return QString::localeAwareCompare (s1->url(), s2->url()) < 0; -} - -static bool _pathAndFilenameGreaterComparator(PlayListTrack* s1,PlayListTrack* s2) -{ - return QString::localeAwareCompare (s1->url(), s2->url()) > 0; -} -//by file name -static bool _filenameLessComparator(PlayListTrack* s1,PlayListTrack* s2) -{ - QFileInfo i_s1(s1->url()); - QFileInfo i_s2(s2->url()); - return QString::localeAwareCompare (i_s1.baseName(), i_s2.baseName()) < 0; -} - -static bool _filenameGreaterComparator(PlayListTrack* s1,PlayListTrack* s2) -{ - QFileInfo i_s1(s1->url()); - QFileInfo i_s2(s2->url()); - return QString::localeAwareCompare (i_s1.baseName(), i_s2.baseName()) > 0; -} -//by date -static bool _dateLessComparator(PlayListTrack* s1,PlayListTrack* s2) -{ - return s1->value(Qmmp::YEAR).toInt() < s2->value(Qmmp::YEAR).toInt(); -} - -static bool _dateGreaterComparator(PlayListTrack* s1,PlayListTrack* s2) -{ - return s1->value(Qmmp::YEAR).toInt() > s2->value(Qmmp::YEAR).toInt(); -} -//by track -static bool _trackLessComparator(PlayListTrack* s1,PlayListTrack* s2) -{ - return s1->value(Qmmp::TRACK).toInt() < s2->value(Qmmp::TRACK).toInt(); -} - -static bool _trackGreaterComparator(PlayListTrack* s1,PlayListTrack* s2) -{ - return s1->value(Qmmp::TRACK).toInt() > s2->value(Qmmp::TRACK).toInt(); -} -//by file creation date -static bool _fileCreationDateLessComparator(PlayListTrack* s1,PlayListTrack* s2) -{ - return QFileInfo(s1->value(Qmmp::URL)).created() < QFileInfo(s2->value(Qmmp::URL)).created(); -} - -static bool _fileCreationDateGreaterComparator(PlayListTrack* s1,PlayListTrack* s2) -{ - return QFileInfo(s1->value(Qmmp::URL)).created() > QFileInfo(s2->value(Qmmp::URL)).created(); -} -//by file modification date -static bool _fileModificationDateLessComparator(PlayListTrack* s1,PlayListTrack* s2) -{ - return QFileInfo(s1->value(Qmmp::URL)).lastModified() < QFileInfo(s2->value(Qmmp::URL)).lastModified(); -} - -static bool _fileModificationDateGreaterComparator(PlayListTrack* s1,PlayListTrack* s2) -{ - return QFileInfo(s1->value(Qmmp::URL)).lastModified() > QFileInfo(s2->value(Qmmp::URL)).lastModified(); -} - -//by group -static bool _groupLessComparator(PlayListTrack* s1,PlayListTrack* s2) -{ - return QString::localeAwareCompare (s1->groupName(), s2->groupName()) < 0; -} - -static bool _groupGreaterComparator(PlayListTrack* s1,PlayListTrack* s2) -{ - return QString::localeAwareCompare (s1->groupName(), s2->groupName()) > 0; -} - -void PlayListContainer::doSort(int sort_mode, QList<PlayListTrack*>& list_to_sort, bool reverted) -{ - QList<PlayListTrack*>::iterator begin; - QList<PlayListTrack*>::iterator end; - - begin = list_to_sort.begin(); - end = list_to_sort.end(); - - bool(*compareLessFunc)(PlayListTrack*,PlayListTrack*) = 0; - bool(*compareGreaterFunc)(PlayListTrack*,PlayListTrack*) = 0; - - switch (sort_mode) - { - case PlayListModel::TITLE: - compareLessFunc = _titleLessComparator; - compareGreaterFunc = _titleGreaterComparator; - break; - case PlayListModel::DISCNUMBER: - compareLessFunc = _discnumberLessComparator; - compareGreaterFunc = _discnumberGreaterComparator; - break; - case PlayListModel::ALBUM: - compareLessFunc = _albumLessComparator; - compareGreaterFunc = _albumGreaterComparator; - break; - case PlayListModel::ARTIST: - compareLessFunc = _artistLessComparator; - compareGreaterFunc = _artistGreaterComparator; - break; - case PlayListModel::ALBUMARTIST: - compareLessFunc = _albumArtistLessComparator; - compareGreaterFunc = _albumArtistGreaterComparator; - break; - case PlayListModel::FILENAME: - compareLessFunc = _filenameLessComparator; - compareGreaterFunc = _filenameGreaterComparator; - break; - case PlayListModel::PATH_AND_FILENAME: - compareLessFunc = _pathAndFilenameLessComparator; - compareGreaterFunc = _pathAndFilenameGreaterComparator; - break; - case PlayListModel::DATE: - compareLessFunc = _dateLessComparator; - compareGreaterFunc = _dateGreaterComparator; - break; - case PlayListModel::TRACK: - compareLessFunc = _trackLessComparator; - compareGreaterFunc = _trackGreaterComparator; - break; - case PlayListModel::FILE_CREATION_DATE: - compareLessFunc = _fileCreationDateLessComparator; - compareGreaterFunc = _fileCreationDateGreaterComparator; - break; - case PlayListModel::FILE_MODIFICATION_DATE: - compareLessFunc = _fileModificationDateLessComparator; - compareGreaterFunc = _fileModificationDateGreaterComparator; - break; - case PlayListModel::GROUP: - compareLessFunc = _groupLessComparator; - compareGreaterFunc = _groupGreaterComparator; - break; - default: - compareLessFunc = _titleLessComparator; - compareGreaterFunc = _titleGreaterComparator; - } - - if(reverted) - qStableSort(begin,end,compareGreaterFunc); - else - qStableSort(begin,end,compareLessFunc); -} - -////=============== THE END OF SORT IMPLEMENTATION =======================//// diff --git a/src/qmmpui/playlistcontainer_p.h b/src/qmmpui/playlistcontainer_p.h index b72aa4519..351a3b30f 100644 --- a/src/qmmpui/playlistcontainer_p.h +++ b/src/qmmpui/playlistcontainer_p.h @@ -41,8 +41,10 @@ public: virtual void addTrack(PlayListTrack *track); virtual void addTracks(QList<PlayListTrack *> tracks) = 0; virtual void insertTrack(int index, PlayListTrack *track) = 0; + virtual void replaceTracks(QList<PlayListTrack *> tracks) = 0; virtual QList<PlayListGroup *> groups() const = 0; virtual QList<PlayListItem *> items() const = 0; + virtual QList<PlayListTrack *> tracks() const = 0; virtual int count() const = 0; virtual int trackCount() const = 0; virtual QList<PlayListItem *> mid(int pos, int count) const = 0; @@ -65,14 +67,6 @@ public: virtual void reverseList() = 0; virtual void randomizeList() = 0; - virtual void sort(int mode) = 0; - virtual void sortSelection(int mode) = 0; - -protected: - /*! - * This internal method performs sorting of \b list_to_sort list of items. - */ - void doSort(int sort_mode, QList<PlayListTrack*>& list_to_sort, bool reverted); }; #endif // PLAYLISTCONTAINER_P_H diff --git a/src/qmmpui/playlistgroup.cpp b/src/qmmpui/playlistgroup.cpp index d5d5ba42b..ad3a5bc16 100644 --- a/src/qmmpui/playlistgroup.cpp +++ b/src/qmmpui/playlistgroup.cpp @@ -31,14 +31,10 @@ PlayListGroup::~PlayListGroup() { PlayListTrack* mf = trackList.takeFirst(); - if (mf->flag() == PlayListTrack::FREE) - { + if (mf->isUsed()) + mf->deleteLater(); + else delete mf; - } - else if (mf->flag() == PlayListTrack::EDITING) - { - mf->setFlag(PlayListTrack::SCHEDULED_FOR_DELETION); - } } } diff --git a/src/qmmpui/playlistmanager.cpp b/src/qmmpui/playlistmanager.cpp index e99a49a81..17dbd67e8 100644 --- a/src/qmmpui/playlistmanager.cpp +++ b/src/qmmpui/playlistmanager.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2009-2014 by Ilya Kotov * + * Copyright (C) 2009-2015 by Ilya Kotov * * forkotov02@hotmail.ru * * * * This program is free software; you can redistribute it and/or modify * @@ -166,7 +166,7 @@ PlayListModel *PlayListManager::createPlayList(const QString &name) } m_models.append(model); connect(model, SIGNAL(nameChanged(QString)), SIGNAL(playListsChanged())); - connect(model, SIGNAL(countChanged()), SLOT(onCountChanged())); + connect(model, SIGNAL(listChanged(int)), SLOT(onListChanged(int))); emit playListAdded(m_models.indexOf(model)); selectPlayList(model); return model; @@ -314,7 +314,7 @@ void PlayListManager::readPlayLists() foreach(PlayListModel *model, m_models) { connect(model, SIGNAL(nameChanged(QString)), SIGNAL(playListsChanged())); - connect(model, SIGNAL(countChanged()), SLOT(onCountChanged())); + connect(model, SIGNAL(listChanged(int)), SLOT(onListChanged(int))); } } @@ -373,9 +373,9 @@ void PlayListManager::writePlayLists() } } -void PlayListManager::onCountChanged() +void PlayListManager::onListChanged(int flags) { - if(m_ui_settings->autoSavePlayList()) + if((flags & PlayListModel::STRUCTURE) && m_ui_settings->autoSavePlayList()) m_timer->start(); } diff --git a/src/qmmpui/playlistmanager.h b/src/qmmpui/playlistmanager.h index 6962fb2ba..4222273aa 100644 --- a/src/qmmpui/playlistmanager.h +++ b/src/qmmpui/playlistmanager.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2009-2014 by Ilya Kotov * + * Copyright (C) 2009-2015 by Ilya Kotov * * forkotov02@hotmail.ru * * * * This program is free software; you can redistribute it and/or modify * @@ -239,7 +239,7 @@ public slots: private slots: void writePlayLists(); - void onCountChanged(); + void onListChanged(int flags); private: void readPlayLists(); diff --git a/src/qmmpui/playlistmodel.cpp b/src/qmmpui/playlistmodel.cpp index c41bd11c1..52392ed64 100644 --- a/src/qmmpui/playlistmodel.cpp +++ b/src/qmmpui/playlistmodel.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright(C) 2006-2014 by Ilya Kotov * + * Copyright(C) 2006-2015 by Ilya Kotov * * forkotov02@hotmail.ru * * * * This program is free software; you can redistribute it and/or modify * @@ -27,6 +27,7 @@ #include "playlistcontainer_p.h" #include "groupedcontainer_p.h" #include "normalcontainer_p.h" +#include "playlisttask_p.h" #include "fileloader_p.h" #include "playstate_p.h" #include "detailsdialog.h" @@ -46,6 +47,7 @@ PlayListModel::PlayListModel(const QString &name, QObject *parent) m_stop_track = 0; m_name = name; m_loader = new FileLoader(this); + m_task = new PlayListTask(this); if(m_ui_settings->isGroupsEnabled()) m_container = new GroupedContainer; else @@ -62,6 +64,7 @@ PlayListModel::PlayListModel(const QString &name, QObject *parent) SLOT(insert(PlayListItem*, PlayListTrack*)), Qt::QueuedConnection); connect(m_loader, SIGNAL(finished()), SLOT(preparePlayState())); connect(m_loader, SIGNAL(finished()), SIGNAL(loaderFinished())); + connect(m_task, SIGNAL(finished()), SLOT(onTaskFinished())); } PlayListModel::~PlayListModel() @@ -91,21 +94,21 @@ void PlayListModel::add(PlayListTrack *track) { m_container->addTrack(track); m_total_length += track->length(); + int flags = 0; if(m_container->trackCount() == 1) { m_current_track = track; m_current = m_container->indexOf(track); - emit currentChanged(); + flags |= CURRENT; } else if(m_ui_settings->isGroupsEnabled()) { //update current index for grouped container only m_current = m_container->indexOf(m_current_track); } - emit trackAdded(track); - emit listChanged(); - emit countChanged(); + flags |= STRUCTURE; + emit listChanged(flags); } void PlayListModel::add(QList<PlayListTrack *> tracks) @@ -113,13 +116,15 @@ void PlayListModel::add(QList<PlayListTrack *> tracks) if(tracks.isEmpty()) return; + int flags = 0; + m_container->addTracks(tracks); if(m_container->trackCount() == tracks.count()) { m_current_track = tracks.first(); m_current = m_container->indexOf(m_current_track); - emit currentChanged(); + flags |= CURRENT; } else if(m_ui_settings->isGroupsEnabled()) { @@ -133,23 +138,32 @@ void PlayListModel::add(QList<PlayListTrack *> tracks) emit trackAdded(track); } preparePlayState(); - emit listChanged(); - emit countChanged(); + flags |= STRUCTURE; + emit listChanged(flags); } void PlayListModel::add(const QString &path) { - m_loader->add(path); - loadPlaylist(path); + QStringList paths = PlayListParser::loadPlaylist(path); + if(paths.isEmpty()) + m_loader->add(path); + else + m_loader->add(paths); } void PlayListModel::add(const QStringList &paths) { - m_loader->add(paths); - foreach(QString str, paths) + QStringList urls, pl_urls; + foreach(QString path, paths) { - loadPlaylist(str); + pl_urls = PlayListParser::loadPlaylist(path); //is it playlist? + if(pl_urls.isEmpty()) + urls.append(path); + else + urls.append(pl_urls); + } + m_loader->add(urls); } void PlayListModel::insert(int index, PlayListTrack *track) @@ -157,11 +171,13 @@ void PlayListModel::insert(int index, PlayListTrack *track) m_container->insertTrack(index, track); m_total_length += track->length(); + int flags = 0; + if(m_container->trackCount() == 1) { m_current_track = track; m_current = m_container->indexOf(track); - emit currentChanged(); + flags |= CURRENT; } else { @@ -169,8 +185,8 @@ void PlayListModel::insert(int index, PlayListTrack *track) m_current = m_container->indexOf(m_current_track); } emit trackAdded(track); - emit listChanged(); - emit countChanged(); + flags |= STRUCTURE; + emit listChanged(flags); } void PlayListModel::insert(PlayListItem *before, PlayListTrack *track) @@ -183,6 +199,8 @@ void PlayListModel::insert(int index, QList<PlayListTrack *> tracks) if(tracks.isEmpty()) return; + int flags = 0; + PlayListItem *prevItem = m_container->item(index); foreach(PlayListTrack *track, tracks) { @@ -194,15 +212,15 @@ void PlayListModel::insert(int index, QList<PlayListTrack *> tracks) { m_current_track = track; m_current = m_container->indexOf(track); - emit currentChanged(); + flags |= CURRENT; } emit trackAdded(track); } //update current index m_current = m_container->indexOf(m_current_track); preparePlayState(); - emit listChanged(); - emit countChanged(); + flags |= STRUCTURE; + emit listChanged(flags); } void PlayListModel::insert(int index, const QString &path) @@ -304,8 +322,7 @@ bool PlayListModel::setCurrent(int index) } m_current = index; m_current_track = dynamic_cast<PlayListTrack*> (item); - emit currentChanged(); - emit listChanged(); + emit listChanged(CURRENT); return true; } @@ -335,12 +352,14 @@ bool PlayListModel::next() if(m_stop_track == currentTrack()) { m_stop_track = 0; - emit listChanged(); + emit listChanged(STOP_AFTER); return false; } - if (!isEmptyQueue()) + if (!m_queued_songs.isEmpty()) { - setCurrentToQueued(); + m_current_track = m_queued_songs.dequeue(); + m_current = m_container->indexOf(m_current_track); + emit listChanged(CURRENT | QUEUE); return true; } @@ -365,14 +384,13 @@ void PlayListModel::clear() m_queued_songs.clear(); m_total_length = 0; m_play_state->resetState(); - emit listChanged(); - emit countChanged(); + emit listChanged(STRUCTURE | QUEUE | STOP_AFTER | CURRENT | SELECTION); } void PlayListModel::clearSelection() { m_container->clearSelection(); - emit listChanged(); + emit listChanged(SELECTION); } QList<PlayListItem *> PlayListModel::mid(int pos, int count) const @@ -411,21 +429,21 @@ PlayListTrack *PlayListModel::findTrack(int number) const void PlayListModel::setSelected(int index, bool selected) { m_container->setSelected(index, selected); - emit listChanged(); + emit listChanged(SELECTION); } void PlayListModel::setSelected(QList<PlayListTrack *> tracks, bool selected) { foreach(PlayListTrack *t, tracks) t->setSelected(selected); - emit listChanged(); + emit listChanged(SELECTION); } void PlayListModel::setSelected(QList<PlayListItem *> items, bool selected) { foreach(PlayListItem *i, items) i->setSelected(selected); - emit listChanged(); + emit listChanged(SELECTION); } void PlayListModel::setSelected(int first, int last, bool selected) @@ -442,7 +460,7 @@ void PlayListModel::setSelected(int first, int last, bool selected) continue; i->setSelected(selected); } - emit listChanged(); + emit listChanged(SELECTION); } void PlayListModel::removeSelected() @@ -457,55 +475,9 @@ void PlayListModel::removeUnselected() void PlayListModel::removeTrack (int i) { - bool current_changed = false; - if ((i < count()) && (i >= 0)) - { - PlayListTrack* track = m_container->track(i); - if(!track) - return; - m_queued_songs.removeAll(track); - m_container->removeTrack(track); - if(m_stop_track == track) - m_stop_track = 0; - m_total_length -= track->length(); - m_total_length = qMax(0, m_total_length); - - if(m_current_track == track) - { - if(m_container->isEmpty()) - m_current_track = 0; - else - { - current_changed = true; - int current = qMin(i - 1, m_container->count() - 1); - current = qMax(current, 0); - m_current_track = m_container->track(current); - if(!m_current_track) - { - m_current_track = current > 0 ? m_container->track(current-1) : - m_container->track(1); - } - } - } - - if (track->flag() == PlayListTrack::FREE) - { - delete track; - track = NULL; - } - else if (track->flag() == PlayListTrack::EDITING) - track->setFlag(PlayListTrack::SCHEDULED_FOR_DELETION); - - - m_current = m_current_track ? m_container->indexOf(m_current_track) : -1; - m_play_state->prepare(); - - if(current_changed) - emit currentChanged(); - - emit listChanged(); - emit countChanged(); - } + int flags = removeTrackInternal(i); + if(flags) + emit listChanged(flags); } void PlayListModel::removeTrack (PlayListItem *track) @@ -518,16 +490,14 @@ void PlayListModel::removeSelection(bool inverted) { int i = 0; int select_after_delete = -1; - PlayListTrack *prev_current_track = m_current_track; + int flags = 0; while (!m_container->isEmpty() && i < m_container->count()) { PlayListItem *item = m_container->item(i); if (!item->isGroup() && item->isSelected() ^ inverted) { - blockSignals(true); - removeTrack(i); - blockSignals(false); + flags |= removeTrackInternal(i); if(m_container->isEmpty()) continue; @@ -538,33 +508,83 @@ void PlayListModel::removeSelection(bool inverted) i++; } - if (select_after_delete >= m_container->count()) - select_after_delete = m_container->count() - 1; + select_after_delete = qMin(select_after_delete, m_container->count() - 1); - if(select_after_delete != -1) + if(select_after_delete >= 0) + { m_container->setSelected(select_after_delete, true); + flags |= SELECTION; + } m_play_state->prepare(); - if(prev_current_track != m_current_track) - emit currentChanged(); + if(flags) + emit listChanged(flags); +} - emit listChanged(); - emit countChanged(); +int PlayListModel::removeTrackInternal(int i) +{ + if((i < 0) || (i >= count())) + return 0; + + int flags = 0; + PlayListTrack* track = m_container->track(i); + if(!track) + return flags; + if(m_queued_songs.removeAll(track) > 0) + flags |= QUEUE; + m_container->removeTrack(track); + if(m_stop_track == track) + { + flags |= STOP_AFTER; + m_stop_track = 0; + } + if(track->isSelected()) + flags |= SELECTION; + + m_total_length -= track->length(); + m_total_length = qMax(0, m_total_length); + + if(m_current_track == track) + { + flags |= CURRENT; + if(m_container->isEmpty()) + m_current_track = 0; + else + { + m_current = i > 0 ? qMin(i - 1, m_container->count() - 1) : 0; + if(!(m_current_track = m_container->track(m_current))) + { + m_current_track = m_current > 0 ? m_container->track(m_current - 1) : + m_container->track(1); + } + } + } + + if (track->isUsed()) + track->deleteLater(); + else + delete track; + + m_current = m_current_track ? m_container->indexOf(m_current_track) : -1; + m_play_state->prepare(); + + flags |= STRUCTURE; + return flags; } void PlayListModel::invertSelection() { for (int i = 0; i < m_container->count(); ++i) m_container->setSelected(i, !m_container->isSelected(i)); - emit listChanged(); + emit listChanged(SELECTION); } void PlayListModel::selectAll() { for (int i = 0; i < m_container->count(); ++i) m_container->setSelected(i, true); - emit listChanged(); + emit listChanged(SELECTION); } void PlayListModel::showDetails(QWidget *parent) @@ -576,9 +596,8 @@ void PlayListModel::showDetails(QWidget *parent) if(!m_container->isSelected(i)) continue; PlayListTrack *track = m_container->track(i); - if(!track || track->flag() != PlayListTrack::FREE) - continue; - selected_tracks.append(track); + if(track) + selected_tracks.append(track); } if(!selected_tracks.isEmpty()) @@ -640,7 +659,7 @@ void PlayListModel::moveItems(int from, int to) if(m_container->move(selected_indexes, from, to)) { m_current = m_container->indexOf(m_current_track); - emit listChanged(); + emit listChanged(STRUCTURE); } } @@ -714,9 +733,11 @@ QList<PlayListItem *> PlayListModel::items() const void PlayListModel::addToQueue() { QList<PlayListTrack*> selected_tracks = selectedTracks(); + blockSignals(true); foreach(PlayListTrack* track, selected_tracks) setQueued(track); - emit listChanged(); + blockSignals(false); + emit listChanged(QUEUE); } void PlayListModel::setQueued(PlayListTrack *item) @@ -725,7 +746,7 @@ void PlayListModel::setQueued(PlayListTrack *item) m_queued_songs.removeAll(item); else m_queued_songs.enqueue(item); - emit listChanged(); + emit listChanged(QUEUE); } bool PlayListModel::isQueued(PlayListTrack *f) const @@ -733,11 +754,6 @@ bool PlayListModel::isQueued(PlayListTrack *f) const return m_queued_songs.contains(f); } -void PlayListModel::setCurrentToQueued() -{ - setCurrent(indexOf(m_queued_songs.dequeue())); -} - bool PlayListModel::isEmptyQueue() const { return m_queued_songs.isEmpty(); @@ -764,7 +780,7 @@ void PlayListModel::randomizeList() return; m_container->randomizeList(); m_current = m_container->indexOf(m_current_track); - emit listChanged(); + emit listChanged(STRUCTURE); } void PlayListModel::reverseList() @@ -773,25 +789,23 @@ void PlayListModel::reverseList() return; m_container->reverseList(); m_current = m_container->indexOf(m_current_track); - emit listChanged(); + emit listChanged(STRUCTURE); } void PlayListModel::sortSelection(int mode) { if(m_container->isEmpty()) return; - m_container->sortSelection(mode); - m_current = m_container->indexOf(m_current_track); - emit listChanged(); + + m_task->sortSelection(m_container->tracks(), (PlayListModel::SortMode) mode); } void PlayListModel::sort(int mode) { if(m_container->isEmpty()) return; - m_container->sort(mode); - m_current = m_container->indexOf(m_current_track); - emit listChanged(); + + m_task->sort(m_container->tracks(), (PlayListModel::SortMode) mode); } void PlayListModel::prepareForShufflePlaying(bool val) @@ -817,13 +831,60 @@ void PlayListModel::prepareGroups(bool enabled) m_container = container; if(!m_container->isEmpty()) m_current = m_container->indexOf(m_current_track); - emit listChanged(); + emit listChanged(STRUCTURE); +} + +void PlayListModel::onTaskFinished() +{ + if(m_task->isChanged(m_container)) //update unchanged container only + return; + + if(m_task->type() == PlayListTask::SORT || m_task->type() == PlayListTask::SORT_SELECTION) + { + m_container->replaceTracks(m_task->takeResults(&m_current_track)); + m_current = m_container->indexOf(m_current_track); + emit listChanged(STRUCTURE); + } + else if(m_task->type() == PlayListTask::REMOVE_INVALID + || m_task->type() == PlayListTask::REMOVE_DUPLICATES) + { + PlayListTrack *prev_current_track = m_current_track; + bool prev_count = m_container->count(); + + m_container->replaceTracks(m_task->takeResults(&m_current_track)); + + if(prev_count != m_container->count()) + { + int flags = STRUCTURE; + m_current = m_container->indexOf(m_current_track); + if(prev_current_track != m_current_track) + flags |= CURRENT; + + if(m_stop_track && !m_container->contains(m_stop_track)) + { + m_stop_track = 0; + flags |= STOP_AFTER; + } + + foreach (PlayListTrack *t, m_queued_songs) + { + if(!m_container->contains(t)) + { + flags |= QUEUE; + m_queued_songs.removeAll(t); + } + } + + emit listChanged(flags); + } + } } void PlayListModel::doCurrentVisibleRequest() { - emit currentChanged(); - emit listChanged(); + //TODO check these signals + //emit currentChanged(); + //emit listChanged(); } void PlayListModel::loadPlaylist(const QString &f_name) @@ -855,70 +916,25 @@ void PlayListModel::preparePlayState() void PlayListModel::removeInvalidTracks() { - bool ok = false; - - for(int i = m_container->count() - 1; i >= 0; i--) - { - if(i >= m_container->count() || !isTrack(i)) - continue; - - PlayListTrack *track = m_container->track(i); - - if(track->url().contains("://")) - ok = MetaDataManager::instance()->protocols().contains(track->url().section("://",0,0)); - else - ok = MetaDataManager::instance()->supports(track->url()); - if(!ok) - removeTrack(i); - - } + m_task->removeInvalidTracks(m_container->tracks(), m_current_track); } void PlayListModel::removeDuplicates() { - QStringList urls; - bool modified = false; - PlayListTrack *prev_current = m_current_track; - - for(int i = 0; i < m_container->count(); ++i) - { - if(!isTrack(i)) - continue; - - if(urls.contains(track(i)->url())) - { - blockSignals(true); - removeTrack(i); - blockSignals(false); - modified = true; - i--; - } - else - { - urls.append(track(i)->url()); - } - } - - if(modified) - { - if(m_current_track != prev_current) - emit currentChanged(); - - emit listChanged(); - emit countChanged(); - } + m_task->removeDuplicates(m_container->tracks(), m_current_track); } void PlayListModel::clearQueue() { m_queued_songs.clear(); m_stop_track = 0; - emit listChanged(); + emit listChanged(QUEUE); } void PlayListModel::stopAfterSelected() { QList<PlayListTrack*> selected_tracks = selectedTracks(); + int flags = STOP_AFTER; if(!m_queued_songs.isEmpty()) { m_stop_track = m_stop_track != m_queued_songs.last() ? m_queued_songs.last() : 0; @@ -929,15 +945,18 @@ void PlayListModel::stopAfterSelected() } else if(selected_tracks.count() > 1) { + blockSignals(true); addToQueue(); + blockSignals(false); + flags |= QUEUE; m_stop_track = m_queued_songs.last(); } else return; - emit listChanged(); + emit listChanged(flags); } -void PlayListModel::updateGroups() +void PlayListModel::rebuildGroups() { if(m_ui_settings->isGroupsEnabled()) prepareGroups(true); diff --git a/src/qmmpui/playlistmodel.h b/src/qmmpui/playlistmodel.h index 06333fb61..a4f411f34 100644 --- a/src/qmmpui/playlistmodel.h +++ b/src/qmmpui/playlistmodel.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2006-2014 by Ilya Kotov * + * Copyright (C) 2006-2015 by Ilya Kotov * * forkotov02@hotmail.ru * * * * This program is free software; you can redistribute it and/or modify * @@ -37,6 +37,7 @@ class PlayListFormat; class PlayListModel; class PlayListContainer; class QmmpUiSettings; +class PlayListTask; /*! @brief Helper class that keeps track of a view's selected items. * @@ -214,10 +215,6 @@ public: */ bool isQueued(PlayListTrack* item) const; /*! - * 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 returns - \b false. */ bool isEmptyQueue()const; @@ -304,15 +301,21 @@ public: PlayListTrack *findTrack(int number) const; + + enum UpdateFlags + { + STRUCTURE = 0x01, //added/removed/moved + SELECTION = 0x02, + QUEUE = 0x04, + CURRENT = 0x08, + STOP_AFTER = 0x10 + }; + signals: /*! * Emitted when the state of PlayListModel has changed. */ - void listChanged(); - /*! - * Emitted when current item has changed. - */ - void currentChanged(); + void listChanged(int flags); /*! * Emitted when new track has added. * @param track Pointer of the new playlist track. @@ -327,10 +330,6 @@ signals: * Emitted when playlist loader thread has finished. */ void loaderFinished(); - /*! - * Emitted when playlist items are added or removed. - */ - void countChanged(); public slots: /*! @@ -466,7 +465,7 @@ public slots: /*! * Rebuilds groups */ - void updateGroups(); + void rebuildGroups(); private: /*! @@ -483,6 +482,8 @@ private: */ void removeSelection(bool inverted = false); + int removeTrackInternal(int i); + private slots: /*! * Prepares play state object @@ -498,6 +499,8 @@ private slots: */ void prepareGroups(bool enabled); + void onTaskFinished(); + private: PlayListTrack* m_current_track; PlayListTrack* m_stop_track; @@ -510,6 +513,7 @@ private: QString m_name; PlayListContainer *m_container; QmmpUiSettings *m_ui_settings; + PlayListTask *m_task; }; #endif diff --git a/src/qmmpui/playlisttask.cpp b/src/qmmpui/playlisttask.cpp index fc23618e5..f1859135e 100644 --- a/src/qmmpui/playlisttask.cpp +++ b/src/qmmpui/playlisttask.cpp @@ -18,14 +18,381 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ +#include <QFileInfo> +#include <QDateTime> +#include <QTime> +#include <qmmp/metadatamanager.h> +#include "qmmpuisettings.h" +#include "playlisttrack.h" #include "playlisttask_p.h" -PlayListTask::PlayListTask(QObject *parent) : - QRunnable(parent) +struct TrackField { + PlayListTrack *track; + QString value; + QString groupName; +}; + +struct GroupdField +{ + QList <TrackField *> fields; + QString groupName; +}; + +////===============THE BEGINNING OF SORT IMPLEMENTATION =======================//// + +// First we'll implement bundle of static compare procedures +// to sort items in different ways + +//by string +static bool _stringLessComparator(TrackField* s1, TrackField* s2) +{ + return QString::localeAwareCompare (s1->value, s2->value) < 0; +} + +static bool _stringGreaterComparator(TrackField* s1, TrackField* s2) +{ + return QString::localeAwareCompare (s1->value, s2->value) > 0; +} +//by number +static bool _numberLessComparator(TrackField* s1, TrackField* s2) +{ + return s1->value.toInt() < s2->value.toInt(); +} + +static bool _numberGreaterComparator(TrackField* s1, TrackField* s2) +{ + return s1->value.toInt() > s2->value.toInt(); +} +//by file creation date +static bool _fileCreationDateLessComparator(TrackField* s1, TrackField* s2) +{ + return QFileInfo(s1->value).created() < QFileInfo(s2->value).created(); +} + +static bool _fileCreationDateGreaterComparator(TrackField* s1, TrackField* s2) +{ + return QFileInfo(s1->value).created() > QFileInfo(s2->value).created(); +} +//by file modification date +static bool _fileModificationDateLessComparator(TrackField* s1, TrackField* s2) +{ + return QFileInfo(s1->value).lastModified() < QFileInfo(s2->value).lastModified(); +} + +static bool _fileModificationDateGreaterComparator(TrackField* s1, TrackField* s2) +{ + return QFileInfo(s1->value).lastModified() > QFileInfo(s2->value).lastModified(); +} +//by file name +static bool _filenameLessComparator(TrackField* s1, TrackField* s2) +{ + QFileInfo i_s1(s1->value); + QFileInfo i_s2(s2->value); + return QString::localeAwareCompare (i_s1.baseName(), i_s2.baseName()) < 0; +} + +static bool _filenameGreaterComparator(TrackField* s1, TrackField* s2) +{ + QFileInfo i_s1(s1->value); + QFileInfo i_s2(s2->value); + return QString::localeAwareCompare (i_s1.baseName(), i_s2.baseName()) > 0; +} +////=============== THE END OF SORT IMPLEMENTATION =======================//// + +PlayListTask::PlayListTask(QObject *parent) : QThread(parent) +{ + m_reverted = true; + m_align_groups = false; + m_current_track = 0; + m_task = EMPTY; + + m_sort_keys.insert(PlayListModel::TITLE, Qmmp::TITLE); + m_sort_keys.insert(PlayListModel::DISCNUMBER, Qmmp::DISCNUMBER); + m_sort_keys.insert(PlayListModel::ALBUM, Qmmp::ALBUM); + m_sort_keys.insert(PlayListModel::ARTIST, Qmmp::ARTIST); + m_sort_keys.insert(PlayListModel::ALBUMARTIST, Qmmp::ALBUMARTIST); + m_sort_keys.insert(PlayListModel::FILENAME, Qmmp::URL); + m_sort_keys.insert(PlayListModel::PATH_AND_FILENAME, Qmmp::URL); + m_sort_keys.insert(PlayListModel::DATE, Qmmp::YEAR); + m_sort_keys.insert(PlayListModel::TRACK, Qmmp::TRACK); + m_sort_keys.insert(PlayListModel::FILE_CREATION_DATE, Qmmp::URL); + m_sort_keys.insert(PlayListModel::FILE_MODIFICATION_DATE, Qmmp::URL); +} + +PlayListTask::~PlayListTask() +{} + +void PlayListTask::sort(QList<PlayListTrack *> tracks, int mode) +{ + if(isRunning()) + return; + clear(); + m_reverted = !m_reverted; + m_sort_mode = mode; + m_task = SORT; + m_input_tracks = tracks; + Qmmp::MetaData key = m_sort_keys.value(mode); + + m_align_groups = QmmpUiSettings::instance()->isGroupsEnabled() && (mode != PlayListModel::GROUP); + + foreach (PlayListTrack *t, tracks) + { + TrackField *f = new TrackField; + f->track = t; + f->value = (mode == PlayListModel::GROUP) ? t->groupName() : t->value(key); + if(m_align_groups) + f->groupName = t->groupName(); + m_fields.append(f); + } + + start(); +} + +void PlayListTask::sortSelection(QList<PlayListTrack *> tracks, int mode) +{ + if(isRunning()) + return; + clear(); + m_reverted = !m_reverted; + m_sort_mode = mode; + m_task = SORT_SELECTION; + m_tracks = tracks; + m_input_tracks = tracks; + Qmmp::MetaData key = m_sort_keys.value(mode); + + for(int i = 0; i < tracks.count(); ++i) + { + if(!tracks[i]->isSelected()) + continue; + + TrackField *f = new TrackField; + f->track = tracks[i]; + f->value = (mode == PlayListModel::GROUP) ? f->track->groupName() : f->track->value(key); + m_fields.append(f); + m_indexes.append(i); + } + + start(); +} + +void PlayListTask::removeInvalidTracks(QList<PlayListTrack *> tracks, PlayListTrack *current_track) +{ + if(isRunning()) + return; + clear(); + m_task = REMOVE_INVALID; + m_input_tracks = tracks; + m_tracks = tracks; + m_current_track = current_track; + + for(int i = 0; i < tracks.count(); ++i) + { + TrackField *f = new TrackField; + f->track = tracks[i]; + f->value = f->track->value(Qmmp::URL); + m_fields.append(f); + } + MetaDataManager::instance()->prepareForAnotherThread(); + start(); +} + +void PlayListTask::removeDuplicates(QList<PlayListTrack *> tracks, PlayListTrack *current_track) +{ + if(isRunning()) + return; + clear(); + m_task = REMOVE_DUPLICATES; + m_input_tracks = tracks; + m_tracks = tracks; + m_current_track = current_track; + + for(int i = 0; i < tracks.count(); ++i) + { + TrackField *f = new TrackField; + f->track = tracks[i]; + f->value = f->track->value(Qmmp::URL); + m_fields.append(f); + } + MetaDataManager::instance()->prepareForAnotherThread(); + start(); } void PlayListTask::run() { + qDebug("PlayListTask: started"); + + if(m_task == SORT || m_task == SORT_SELECTION) + { + bool(*compareLessFunc)(TrackField*, TrackField*) = 0; + bool(*compareGreaterFunc)(TrackField*, TrackField*) = 0; + + QList<TrackField*>::iterator begin = m_fields.begin(); + QList<TrackField*>::iterator end = m_fields.end(); + + if(m_sort_mode == PlayListModel::FILE_CREATION_DATE) + { + compareLessFunc = _fileCreationDateLessComparator; + compareGreaterFunc = _fileCreationDateGreaterComparator; + } + else if(m_sort_mode == PlayListModel::FILE_MODIFICATION_DATE) + { + compareLessFunc = _fileModificationDateLessComparator; + compareGreaterFunc = _fileModificationDateGreaterComparator; + } + else if(m_sort_mode == PlayListModel::TRACK || m_sort_mode == PlayListModel::DATE) + { + compareLessFunc = _numberLessComparator; + compareGreaterFunc = _numberGreaterComparator; + } + else if(m_sort_mode == PlayListModel::FILENAME) + { + compareLessFunc = _filenameLessComparator; + compareGreaterFunc = _filenameGreaterComparator; + } + else + { + compareLessFunc = _stringLessComparator; + compareGreaterFunc = _stringGreaterComparator; + } + + if(m_reverted) + qStableSort(begin,end,compareGreaterFunc); + else + qStableSort(begin,end,compareLessFunc); + + //align track list by group name (optimization) + if(m_align_groups) + { + QList<GroupdField *> groups; + bool found = false; + for(int i = 0; i < m_fields.count(); ++i) + { + found = false; + for(int j = groups.count() - 1; j >= 0; j--) + { + if(groups[j]->groupName == m_fields[i]->groupName) + { + groups[j]->fields.append(m_fields[i]); + found = true; + break; + } + } + + if(!found) + { + groups << new GroupdField; + groups.last()->fields.append(m_fields[i]); + groups.last()->groupName = m_fields[i]->groupName; + } + } + + m_fields.clear(); + for(int j = 0; j < groups.count(); ++j) + { + m_fields.append(groups[j]->fields); + } + qDeleteAll(groups); + groups.clear(); + } + } + else if(m_task == REMOVE_INVALID) + { + TrackField *f = 0; + bool ok = false; + for(int i = 0; i < m_fields.count(); ++i) + { + f = m_fields.at(i); + + if(f->value.contains("://")) + ok = MetaDataManager::instance()->protocols().contains(f->value.section("://",0,0)); //url + else + ok = MetaDataManager::instance()->supports(f->value); //local file + + if(!ok) + m_indexes << i; + } + } + else if(m_task == REMOVE_DUPLICATES) + { + QStringList urls; + TrackField *f = 0; + for(int i = 0; i < m_fields.count(); ++i) + { + f = m_fields.at(i); + + if(urls.contains(f->value)) + { + m_indexes.append(i); + } + else + { + urls.append(f->value); + } + } + } + qDebug("PlayListTask: finished"); +} + +PlayListTask::TaskType PlayListTask::type() const +{ + return m_task; +} + +bool PlayListTask::isChanged(PlayListContainer *container) +{ + if(m_input_tracks.count() != container->trackCount()) + return true; + + return m_input_tracks != container->tracks(); +} +QList<PlayListTrack *> PlayListTask::takeResults(PlayListTrack **current_track) +{ + if(m_task == SORT) + { + foreach (TrackField *f, m_fields) + m_tracks.append(f->track); + } + else if(m_task == SORT_SELECTION) + { + for (int i = 0; i < m_indexes.count(); i++) + m_tracks.replace(m_indexes[i], m_fields[i]->track); + } + else if(m_task == REMOVE_INVALID || m_task == REMOVE_DUPLICATES) + { + int index = 0; + PlayListTrack *t = 0; + for (int i = m_indexes.count() - 1; i >= 0; i--) + { + index = m_indexes.at(i); + t = m_tracks.takeAt(index); + if(t == m_current_track) + { + if(m_tracks.isEmpty()) + m_current_track = 0; + else if(index > 0 && index <= m_tracks.count()) + m_current_track = m_tracks[index - 1]; + else + m_current_track = m_tracks[0]; + *current_track = m_current_track; + } + if(t->isUsed()) + t->deleteLater(); + else + delete t; + } + } + return m_tracks; +} + +void PlayListTask::clear() +{ + qDeleteAll(m_fields); + m_fields.clear(); + m_align_groups = false; + m_indexes.clear(); + m_input_tracks.clear(); + m_tracks.clear(); + m_current_track = 0; } diff --git a/src/qmmpui/playlisttask_p.h b/src/qmmpui/playlisttask_p.h index 39159cfdf..14442b06b 100644 --- a/src/qmmpui/playlisttask_p.h +++ b/src/qmmpui/playlisttask_p.h @@ -21,16 +21,60 @@ #ifndef PLAYLISTTASK_P_H #define PLAYLISTTASK_P_H -#include <QRunnable> +#include <QThread> #include <QObject> +#include <QHash> +#include <QList> +#include "playlistmodel.h" +#include "playlistcontainer_p.h" -class PlayListTask : public QRunnable, public QObject +class PlayListTrack; +struct TrackField; + + +class PlayListTask : public QThread { Q_OBJECT public: - explicit PlayListTask(QObject *parent = 0); -void run(); + enum TaskType + { + EMPTY = -1, + SORT = 0, + SORT_SELECTION, + REMOVE_INVALID, + REMOVE_DUPLICATES + }; + explicit PlayListTask(QObject *parent); + + ~PlayListTask(); + + void sort(QList<PlayListTrack *> tracks, int mode); + void sortSelection(QList<PlayListTrack *> tracks, int mode); + void removeInvalidTracks(QList<PlayListTrack *> tracks, PlayListTrack *current_track); + void removeDuplicates(QList<PlayListTrack *> tracks, PlayListTrack *current_track); + + void run(); + + TaskType type() const; + bool isChanged(PlayListContainer *container); + QList<PlayListTrack *> takeResults(PlayListTrack **current_track); + PlayListTrack *currentTrack() const; + + + +private: + void clear(); + QList <TrackField *> m_fields; + QList <PlayListTrack *> m_tracks; + QList <PlayListTrack *> m_input_tracks; + QList<int> m_indexes; + PlayListTrack *m_current_track; + int m_sort_mode; + TaskType m_task; + bool m_reverted; + bool m_align_groups; + QHash<int, Qmmp::MetaData> m_sort_keys; }; diff --git a/src/qmmpui/playlisttrack.cpp b/src/qmmpui/playlisttrack.cpp index 32a918ffd..e1bee339d 100644 --- a/src/qmmpui/playlisttrack.cpp +++ b/src/qmmpui/playlisttrack.cpp @@ -23,37 +23,46 @@ #include "qmmpuisettings.h" #include "playlisttrack.h" -PlayListTrack::PlayListTrack() : QMap<Qmmp::MetaData, QString>(), PlayListItem(), m_flag(FREE) +PlayListTrack::PlayListTrack() : QMap<Qmmp::MetaData, QString>(), PlayListItem() { m_settings = QmmpUiSettings::instance(); m_length = 0; + m_refCount = 0; + m_sheduledForDeletion = false; } PlayListTrack::PlayListTrack(const PlayListTrack &other) : QMap<Qmmp::MetaData, QString>(other), - PlayListItem(),m_flag(FREE) + PlayListItem() { m_settings = QmmpUiSettings::instance(); + m_refCount = 0; + m_sheduledForDeletion = false; + m_formattedTitle = other.m_formattedTitle; m_group = other.m_group; m_formattedLength = other.m_formattedLength; m_titleFormat = other.m_titleFormat; m_groupFormat = other.m_groupFormat; setSelected(other.isSelected()); - setFlag(other.flag()); m_length = other.m_length; m_formattedLength = other.m_formattedLength; } PlayListTrack::PlayListTrack(FileInfo *info) : QMap<Qmmp::MetaData, QString>(info->metaData()), - PlayListItem(), m_flag(FREE) + PlayListItem() { m_settings = QmmpUiSettings::instance(); setLength(m_length = info->length()); insert(Qmmp::URL, info->path()); + m_refCount = 0; + m_sheduledForDeletion = false; } PlayListTrack::~PlayListTrack() -{} +{ + if(m_refCount != 0) + qWarning("PlayListTrack: deleting busy track"); +} void PlayListTrack::updateMetaData(const QMap <Qmmp::MetaData, QString> &metaData) { @@ -92,6 +101,31 @@ bool PlayListTrack::isGroup() const return false; } +void PlayListTrack::beginUsage() +{ + m_refCount++; +} + +void PlayListTrack::endUsage() +{ + m_refCount--; +} + +void PlayListTrack::deleteLater() +{ + m_sheduledForDeletion = true; +} + +bool PlayListTrack::isSheduledForDeletion() const +{ + return m_sheduledForDeletion; +} + +bool PlayListTrack::isUsed() const +{ + return (m_refCount != 0); +} + const QString PlayListTrack::formattedTitle() { if(m_formattedTitle.isEmpty() || m_titleFormat != m_settings->titleFormat()) @@ -130,16 +164,6 @@ const QString PlayListTrack::url() const return value(Qmmp::URL); } -void PlayListTrack::setFlag(FLAGS f) -{ - m_flag = f; -} - -PlayListTrack::FLAGS PlayListTrack::flag() const -{ - return m_flag; -} - void PlayListTrack::formatTitle() { MetaDataFormatter f(m_settings->titleFormat()); diff --git a/src/qmmpui/playlisttrack.h b/src/qmmpui/playlisttrack.h index e21b8f286..810be411a 100644 --- a/src/qmmpui/playlisttrack.h +++ b/src/qmmpui/playlisttrack.h @@ -34,19 +34,6 @@ class PlayListTrack : public QMap <Qmmp::MetaData, QString>, public PlayListItem { public: /*! - * Current state of playlist item. - * 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, /*!< instance is free and may be deleted */ - EDITING, /*!< instance is currently busy */ - SCHEDULED_FOR_DELETION /*!< instance is sheduled for deletion */ - }; - /*! * Constructs an empty plalist item. */ PlayListTrack(); @@ -100,14 +87,19 @@ public: * Returns \b false. */ bool isGroup() const; + + + void beginUsage(); + void endUsage(); + void deleteLater(); + + + bool isSheduledForDeletion() const; /*! - * Returns current state of the playlist item. - */ - FLAGS flag() const; - /*! - * Sets state of the playlist item. + * Indicates that instance is currently busy in some kind of operation (tags editing etc.) + * and can't be deleted at the moment. Call \b deleteLater() instead of delete operator call. */ - void setFlag(FLAGS); + bool isUsed() const; private: void formatTitle(); @@ -119,7 +111,8 @@ private: QString m_groupFormat; QmmpUiSettings *m_settings; qint64 m_length; - FLAGS m_flag; + int m_refCount; + bool m_sheduledForDeletion; }; #endif diff --git a/src/qmmpui/qmmpuisettings.cpp b/src/qmmpui/qmmpuisettings.cpp index 37b56ec2c..67e5c0559 100644 --- a/src/qmmpui/qmmpuisettings.cpp +++ b/src/qmmpui/qmmpuisettings.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2012-2014 by Ilya Kotov * + * Copyright (C) 2012-2015 by Ilya Kotov * * forkotov02@hotmail.ru * * * * This program is free software; you can redistribute it and/or modify * @@ -146,7 +146,7 @@ void QmmpUiSettings::setGroupFormat(const QString &groupFormat) m_group_format = groupFormat; foreach(PlayListModel *model, PlayListManager::instance()->playLists()) { - model->updateGroups(); + model->rebuildGroups(); } } } diff --git a/src/qmmpui/qmmpuisettings.h b/src/qmmpui/qmmpuisettings.h index b51f778a5..f9d6fd99b 100644 --- a/src/qmmpui/qmmpuisettings.h +++ b/src/qmmpui/qmmpuisettings.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2012 by Ilya Kotov * + * Copyright (C) 2012-2015 by Ilya Kotov * * forkotov02@hotmail.ru * * * * This program is free software; you can redistribute it and/or modify * diff --git a/src/qmmpui/tagupdater.cpp b/src/qmmpui/tagupdater.cpp index 02f0c4590..21bc6aaf9 100644 --- a/src/qmmpui/tagupdater.cpp +++ b/src/qmmpui/tagupdater.cpp @@ -24,7 +24,7 @@ TagUpdater::TagUpdater(QObject* o, QList<PlayListTrack *> tracks) : m_observable { m_tracks = tracks; foreach(PlayListTrack *t, m_tracks) - t->setFlag(PlayListTrack::EDITING); + t->beginUsage(); connect(m_observable, SIGNAL(destroyed(QObject *)),SLOT(updateTags())); connect(m_observable, SIGNAL(destroyed(QObject *)),SLOT(deleteLater())); } @@ -33,7 +33,8 @@ void TagUpdater::updateTags() { foreach (PlayListTrack *t, m_tracks) { - if (t->flag() == PlayListTrack::SCHEDULED_FOR_DELETION) + t->endUsage(); + if (!t->isUsed() && t->isSheduledForDeletion()) { delete t; t = 0; @@ -41,7 +42,6 @@ void TagUpdater::updateTags() else { t->updateMetaData(); - t->setFlag(PlayListTrack::FREE); } } m_tracks.clear(); |
