/*************************************************************************** begin : Thu Aug 19 2004 copyright : (C) 2002 - 2004 by Michael Pyne email : michael.pyne@kde.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include #include #include #include "tracksequenceiterator.h" #include "playlist.h" #include "actioncollection.h" #include "tag.h" #include "filehandle.h" using namespace ActionCollection; TrackSequenceIterator::TrackSequenceIterator() : m_current(0) { } TrackSequenceIterator::TrackSequenceIterator(const TrackSequenceIterator &other) : m_current(other.m_current) { } TrackSequenceIterator::~TrackSequenceIterator() { } void TrackSequenceIterator::setCurrent(PlaylistItem *current) { m_current = current; } void TrackSequenceIterator::playlistChanged() { } void TrackSequenceIterator::itemAboutToDie(const PlaylistItem *) { } DefaultSequenceIterator::DefaultSequenceIterator() : TrackSequenceIterator() { } DefaultSequenceIterator::DefaultSequenceIterator(const DefaultSequenceIterator &other) : TrackSequenceIterator(other) { } DefaultSequenceIterator::~DefaultSequenceIterator() { } void DefaultSequenceIterator::advance() { if(!current()) return; bool isRandom = action("randomPlay") && action("randomPlay")->isChecked(); bool loop = action("loopPlaylist") && action("loopPlaylist")->isChecked(); bool albumRandom = action("albumRandomPlay") && action("albumRandomPlay")->isChecked(); if(isRandom || albumRandom) { if(m_randomItems.isEmpty() && loop) { // Since refillRandomList will remove the currently playing item, // we should clear it out first since that's not good for e.g. // lists with 1-2 items. We need to remember the Playlist though. Playlist *playlist = current()->playlist(); setCurrent(0); refillRandomList(playlist); } if(m_randomItems.isEmpty()) { setCurrent(0); return; } PlaylistItem *item; if(albumRandom) { if(m_albumSearch.isNull() || m_albumSearch.matchedItems().isEmpty()) { item = m_randomItems[TDEApplication::random() % m_randomItems.count()]; initAlbumSearch(item); } // This can be null if initAlbumSearch() left the m_albumSearch // empty because the album text was empty. Since we initAlbumSearch() // with an item, the matchedItems() should never be empty. if(!m_albumSearch.isNull()) { PlaylistItemList albumMatches = m_albumSearch.matchedItems(); if(albumMatches.isEmpty()) { kdError(65432) << "Unable to initialize album random play.\n"; kdError(65432) << "List of potential results is empty.\n"; return; // item is still set to random song from a few lines earlier. } item = albumMatches[0]; // Pick first song remaining in list. for(unsigned i = 0; i < albumMatches.count(); ++i) if(albumMatches[i]->file().tag()->track() < item->file().tag()->track()) item = albumMatches[i]; m_albumSearch.clearItem(item); if(m_albumSearch.matchedItems().isEmpty()) { m_albumSearch.clearComponents(); m_albumSearch.search(); } } else kdError(65432) << "Unable to perform album random play on " << *item << endl; } else item = m_randomItems[TDEApplication::random() % m_randomItems.count()]; setCurrent(item); m_randomItems.remove(item); } else { PlaylistItem *next = current()->itemBelow(); if(!next && loop) { Playlist *p = current()->playlist(); next = p->firstChild(); while(next && !next->isVisible()) next = static_cast(next->nextSibling()); } setCurrent(next); } } void DefaultSequenceIterator::backup() { if(!current()) return; PlaylistItem *item = current()->itemAbove(); if(item) setCurrent(item); } void DefaultSequenceIterator::prepareToPlay(Playlist *playlist) { bool random = action("randomPlay") && action("randomPlay")->isChecked(); bool albumRandom = action("albumRandomPlay") && action("albumRandomPlay")->isChecked(); if(random || albumRandom) { PlaylistItemList items = playlist->selectedItems(); if(items.isEmpty()) items = playlist->visibleItems(); PlaylistItem *newItem = 0; if(!items.isEmpty()) newItem = items[TDEApplication::random() % items.count()]; setCurrent(newItem); refillRandomList(); } else { TQListViewItemIterator it(playlist, TQListViewItemIterator::Visible | TQListViewItemIterator::Selected); if(!it.current()) it = TQListViewItemIterator(playlist, TQListViewItemIterator::Visible); setCurrent(static_cast(it.current())); } } void DefaultSequenceIterator::reset() { m_randomItems.clear(); m_albumSearch.clearComponents(); m_albumSearch.search(); setCurrent(0); } void DefaultSequenceIterator::playlistChanged() { refillRandomList(); } void DefaultSequenceIterator::itemAboutToDie(const PlaylistItem *item) { PlaylistItem *stfu_gcc = const_cast(item); m_randomItems.remove(stfu_gcc); } void DefaultSequenceIterator::setCurrent(PlaylistItem *current) { PlaylistItem *oldCurrent = DefaultSequenceIterator::current(); TrackSequenceIterator::setCurrent(current); bool random = action("randomPlay") && action("randomPlay")->isChecked(); bool albumRandom = action("albumRandomPlay") && action("albumRandomPlay")->isChecked(); if((albumRandom || random) && current && m_randomItems.isEmpty()) { // We're setting a current item, refill the random list now, and remove // the current item. refillRandomList(); } m_randomItems.remove(current); if(albumRandom && current && !oldCurrent) { // Same idea as above initAlbumSearch(current); m_albumSearch.clearItem(current); } } DefaultSequenceIterator *DefaultSequenceIterator::clone() const { return new DefaultSequenceIterator(*this); } void DefaultSequenceIterator::refillRandomList(Playlist *p) { if(!p) { if (!current()) return; p = current()->playlist(); if(!p) { kdError(65432) << k_funcinfo << "Item has no playlist!\n"; return; } } m_randomItems = p->visibleItems(); m_randomItems.remove(current()); m_albumSearch.clearComponents(); m_albumSearch.search(); } void DefaultSequenceIterator::initAlbumSearch(PlaylistItem *searchItem) { if(!searchItem) return; m_albumSearch.clearPlaylists(); m_albumSearch.addPlaylist(searchItem->playlist()); ColumnList columns; m_albumSearch.setSearchMode(PlaylistSearch::MatchAll); m_albumSearch.clearComponents(); // If the album name is empty, it will mess up the search, // so ignore empty album names. if(searchItem->file().tag()->album().isEmpty()) return; columns.append(PlaylistItem::AlbumColumn); m_albumSearch.addComponent(PlaylistSearch::Component( searchItem->file().tag()->album(), true, columns, PlaylistSearch::Component::Exact) ); // If there is an Artist tag with the track, match against it as well // to avoid things like multiple "Greatest Hits" albums matching the // search. if(!searchItem->file().tag()->artist().isEmpty()) { kdDebug(65432) << "Searching both artist and album.\n"; columns[0] = PlaylistItem::ArtistColumn; m_albumSearch.addComponent(PlaylistSearch::Component( searchItem->file().tag()->artist(), true, columns, PlaylistSearch::Component::Exact) ); } m_albumSearch.search(); } // vim: set et sw=4 tw=0: