/*************************************************************************** * Copyright (C) 2013-2021 by Ilya Kotov * * forkotov02@ya.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., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "playlistmodel.h" #include "groupedcontainer_p.h" #if QT_VERSION < QT_VERSION_CHECK(5, 13, 0) #define swapItemsAt swap #endif GroupedContainer::GroupedContainer() {} GroupedContainer::~GroupedContainer() { clear(); } void GroupedContainer::addTrack(PlayListTrack *track) { int firstIndex = 0, lastIndex = 0; //insert if possible for(int i = 0; i < m_groups.count(); ++i) { if(i == 0) { firstIndex = 0; lastIndex = m_groups[i]->count(); } else { firstIndex = lastIndex + 1; lastIndex = firstIndex + m_groups[i]->count(); } if(track->groupName() == m_groups[i]->formattedTitle()) { m_groups[i]->trackList.append(track); m_items.insert(lastIndex + 1, track); m_update = true; return; } } PlayListGroup *group = new PlayListGroup(track->groupName()); group->trackList.append(track); m_groups.append(group); m_items.append(group); m_items.append(track); track->setTrackIndex(trackCount() - 1); } void GroupedContainer::addTracks(const QList &tracks) { for(int i = 0; i < tracks.count(); ++i) { bool found = false; for(int j = m_groups.count() - 1; j >= 0; --j) { if(m_groups.at(j)->formattedTitle() == tracks.at(i)->groupName()) { found = true; m_groups.at(j)->trackList.append(tracks[i]); break; } } if(found) continue; m_groups << new PlayListGroup(tracks.at(i)->groupName()); m_groups.last()->trackList.append(tracks.at(i)); } m_update = true; } void GroupedContainer::insertTrack(int index, PlayListTrack *track) { int firstIndex = 0, lastIndex = 0; //insert if possible for(int i = 0; i < m_groups.count(); ++i) { if(i == 0) { firstIndex = 0; lastIndex = m_groups[i]->count(); } else { firstIndex = lastIndex + 1; lastIndex = firstIndex + m_groups[i]->count(); } if(track->groupName() == m_groups[i]->formattedTitle() && index > firstIndex && index <= lastIndex + 1) { m_groups[i]->trackList.insert(index - firstIndex - 1, track); m_update = true; return; } } //just add otherwise addTrack(track); } void GroupedContainer::replaceTracks(const QList &tracks) { for(PlayListGroup *g : qAsConst(m_groups)) { g->trackList.clear(); } clear(); addTracks(tracks); } QList GroupedContainer::groups() const { return m_groups; } QList GroupedContainer::tracks() const { QList trackList; for(int i = 0; i < m_groups.count(); ++i) { trackList.append(m_groups[i]->trackList); } return trackList; } QList GroupedContainer::items() const { updateCache(); return m_items; } int GroupedContainer::count() const { updateCache(); return m_items.count(); } int GroupedContainer::trackCount() const { updateCache(); return m_items.count() - m_groups.count(); } QList GroupedContainer::mid(int pos, int count) const { updateCache(); return m_items.mid(pos, count); } bool GroupedContainer::isEmpty() const { return m_groups.isEmpty(); } bool GroupedContainer::isSelected(int index) const { updateCache(); if (0 <= index && index < m_items.count()) return m_items.at(index)->isSelected(); return false; } void GroupedContainer::setSelected(int index, bool selected) { updateCache(); if (0 <= index && index < m_items.count())// && !m_items.at(index)->isGroup()) m_items.at(index)->setSelected(selected); } void GroupedContainer::clearSelection() { updateCache(); for(PlayListItem *item : qAsConst(m_items)) { item->setSelected(false); } } int GroupedContainer::indexOf(PlayListItem *item) const { updateCache(); return m_items.indexOf(item); } PlayListItem *GroupedContainer::item(int index) const { updateCache(); if(index >= count() || index < 0) { qWarning("GroupedContainer: index is out of range"); return nullptr; } return m_items.at(index); } PlayListTrack *GroupedContainer::track(int index) const { updateCache(); PlayListItem *i = item(index); if(!i || i->isGroup()) return nullptr; return static_cast (i); } PlayListGroup *GroupedContainer::group(int index) const { PlayListItem *i = item(index); if(i && i->isGroup()) return static_cast (i); return nullptr; } bool GroupedContainer::contains(PlayListItem *item) const { updateCache(); return m_items.contains(item); } int GroupedContainer::indexOfTrack(int index) const { updateCache(); if(index >= count() || index < 0) { qWarning("GroupedContainer: index is out of range"); return -1; } return m_items.at(index)->trackIndex(); } PlayListTrack *GroupedContainer::findTrack(int number) const { int firstNumber = 0; for(const PlayListGroup *group : qAsConst(m_groups)) { if(number >= firstNumber && number < firstNumber + group->count()) { return group->trackList.at(number - firstNumber); } firstNumber += group->count(); } return nullptr; } void GroupedContainer::removeTrack(PlayListTrack *track) { QList::iterator it = m_groups.begin(); while(it != m_groups.end()) { if((*it)->contains(track)) { (*it)->trackList.removeAll(track); m_items.removeAll(track); if((*it)->isEmpty()) { PlayListGroup *group = *it; m_groups.removeAll(group); m_items.removeAll(group); delete group; } return; } ++it; } } void GroupedContainer::removeTracks(QList tracks) { for(PlayListTrack *t : qAsConst(tracks)) removeTrack(t); } bool GroupedContainer::move(const QList &indexes, int from, int to) { updateCache(); PlayListGroup *group = nullptr; int firstIndex = 0, lastIndex = 0; for(int i = 0; i < m_groups.count(); ++i) { if(i == 0) { firstIndex = 0; lastIndex = m_groups[i]->count(); } else { firstIndex = lastIndex + 1; lastIndex = firstIndex + m_groups[i]->count(); } if(from > firstIndex && from <= lastIndex && to > firstIndex && to <= lastIndex) { group = m_groups.at(i); break; } } if(!group) return false; for(int i : qAsConst(indexes)) { if(i <= firstIndex || i > lastIndex) return false; if(i + to - from - firstIndex - 1 >= group->count()) return false; if(i + to - from - firstIndex - 1 < 0) return false; if(i + to - from < 0) return false; } if (from > to) { for(const int &i : qAsConst(indexes)) { if (i + to - from < 0) break; else { m_items.move(i,i + to - from); swapTrackNumbers(&m_items,i,i + to - from); group->trackList.move(i - firstIndex - 1, i + to - from - firstIndex - 1); } } } else { for (int i = indexes.count() - 1; i >= 0; i--) { if (indexes[i] + to - from >= m_items.count()) break; else { m_items.move(indexes[i], indexes[i] + to - from); swapTrackNumbers(&m_items,indexes[i], indexes[i] + to - from); group->trackList.move(indexes[i] - firstIndex - 1, indexes[i] + to - from - firstIndex - 1); } } } return true; } QList GroupedContainer::takeAllTracks() { QList tracks; for(PlayListGroup *g : qAsConst(m_groups)) { tracks.append(g->trackList); g->trackList.clear(); } clear(); return tracks; } void GroupedContainer::clear() { while(!m_groups.isEmpty()) { delete m_groups.takeFirst(); } m_items.clear(); } void GroupedContainer::reverseList() { QList tracks = takeAllTracks(); for (int i = 0; i < tracks.size()/2 ;i++) tracks.swapItemsAt(i, tracks.size() - i - 1); addTracks(tracks); } void GroupedContainer::randomizeList() { for(int i = 0; i < m_groups.count(); ++i) { for (int j = 0; j < m_groups[i]->trackList.size(); j++) { m_groups[i]->trackList.swapItemsAt(qrand() % m_groups[i]->trackList.size(), qrand() % m_groups[i]->trackList.size()); } } for(int i = 0; i < m_groups.count(); ++i) { m_groups.swapItemsAt(qrand() % m_groups.size(), qrand() % m_groups.size()); } m_update = true; } void GroupedContainer::updateCache() const { if(!m_update) return; m_items.clear(); int t = 0; for(int i = 0; i < m_groups.count(); ++i) { m_items.append(m_groups.at(i)); for(PlayListTrack *track : m_groups.at(i)->trackList) { track->setTrackIndex(t++); m_items.append(track); } } m_update = false; }