make playlist and playlist editor share code responsible for moving items
This commit is contained in:
196
src/actions.cpp
196
src/actions.cpp
@@ -778,48 +778,17 @@ void Delete::Run()
|
||||
|
||||
if (!myPlaylist->Items->empty() && myScreen == myPlaylist)
|
||||
{
|
||||
if (myPlaylist->Items->hasSelected())
|
||||
auto list = getSelectedOrCurrent(myPlaylist->Items->begin(), myPlaylist->Items->end(), myPlaylist->Items->currentI());
|
||||
Mpd.StartCommandsList();
|
||||
for (auto it = list.rbegin(); it != list.rend(); ++it)
|
||||
Mpd.DeleteID((*it)->value().getID());
|
||||
if (Mpd.CommitCommandsList())
|
||||
{
|
||||
std::vector<size_t> list;
|
||||
myPlaylist->Items->getSelected(list);
|
||||
Mpd.StartCommandsList();
|
||||
for (std::vector<size_t>::reverse_iterator it = list.rbegin(); it != list.rend(); ++it)
|
||||
Mpd.DeleteID((*myPlaylist->Items)[*it].value().getID());
|
||||
if (Mpd.CommitCommandsList())
|
||||
{
|
||||
for (auto it = myPlaylist->Items->begin(); it != myPlaylist->Items->end(); ++it)
|
||||
it->setSelected(false);
|
||||
for (auto it = list.begin(); it != list.end(); ++it)
|
||||
(*it)->setSelected(false);
|
||||
if (list.size() > 1)
|
||||
ShowMessage("Selected items deleted");
|
||||
}
|
||||
}
|
||||
else
|
||||
Mpd.DeleteID(myPlaylist->currentSong()->getID());
|
||||
}
|
||||
else if (
|
||||
(myScreen == myBrowser && !myBrowser->Main()->empty() && myBrowser->CurrentDir() == "/" && myBrowser->Main()->current().value().type == itPlaylist)
|
||||
|| (myScreen->ActiveWindow() == myPlaylistEditor->Playlists)
|
||||
)
|
||||
{
|
||||
std::string name;
|
||||
if (myScreen == myBrowser)
|
||||
name = myBrowser->Main()->current().value().name;
|
||||
else
|
||||
name = myPlaylistEditor->Playlists->current().value();
|
||||
bool yes = AskYesNoQuestion("Delete playlist \"" + Shorten(TO_WSTRING(name), COLS-28) + "\"?", TraceMpdStatus);
|
||||
if (yes)
|
||||
{
|
||||
if (Mpd.DeletePlaylist(locale_to_utf_cpy(name)))
|
||||
{
|
||||
const char msg[] = "Playlist \"%s\" deleted";
|
||||
ShowMessage(msg, Shorten(TO_WSTRING(name), COLS-const_strlen(msg)).c_str());
|
||||
if (myBrowser->Main() && !myBrowser->isLocal() && myBrowser->CurrentDir() == "/")
|
||||
myBrowser->GetDirectory("/");
|
||||
}
|
||||
}
|
||||
else
|
||||
ShowMessage("Aborted");
|
||||
if (myPlaylistEditor->Main()) // check if initialized
|
||||
myPlaylistEditor->Playlists->clear(); // make playlists list update itself
|
||||
}
|
||||
# ifndef WIN32
|
||||
else if (myScreen == myBrowser && !myBrowser->Main()->empty())
|
||||
@@ -827,46 +796,29 @@ void Delete::Run()
|
||||
if (!myBrowser->isLocal() && !isMPDMusicDirSet())
|
||||
return;
|
||||
|
||||
MPD::Item &item = myBrowser->Main()->current().value();
|
||||
|
||||
if (item.type == itSong && !Config.allow_physical_files_deletion)
|
||||
{
|
||||
ShowMessage("Deleting files is disabled by default, see man page for more details");
|
||||
return;
|
||||
}
|
||||
if (item.type == itDirectory && !Config.allow_physical_directories_deletion)
|
||||
{
|
||||
ShowMessage("Deleting directories is disabled by default, see man page for more details");
|
||||
return;
|
||||
}
|
||||
if (myBrowser->isParentDirectory(item))
|
||||
return;
|
||||
|
||||
std::string name = item.type == itSong ? item.song->getName() : item.name;
|
||||
std::string question;
|
||||
if (myBrowser->Main()->hasSelected())
|
||||
question = "Delete selected items?";
|
||||
else
|
||||
{
|
||||
MPD::Item &item = myBrowser->Main()->current().value();
|
||||
std::string name = item.type == itSong ? item.song->getName() : item.name;
|
||||
question = "Delete ";
|
||||
question += (item.type == itSong ? "file" : item.type == itDirectory ? "directory" : "playlist");
|
||||
question += itemTypeToString(item.type);
|
||||
question += " \"";
|
||||
question += Shorten(TO_WSTRING(name), COLS-30);
|
||||
question += Shorten(TO_WSTRING(name), COLS-question.size()-10);
|
||||
question += "\"?";
|
||||
}
|
||||
bool yes = AskYesNoQuestion(question, TraceMpdStatus);
|
||||
if (yes)
|
||||
{
|
||||
std::vector<size_t> list;
|
||||
myBrowser->Main()->getSelected(list);
|
||||
if (list.empty())
|
||||
list.push_back(myBrowser->Main()->choice());
|
||||
bool success = 1;
|
||||
for (size_t i = 0; i < list.size(); ++i)
|
||||
bool success = true;
|
||||
auto list = getSelectedOrCurrent(myBrowser->Main()->begin(), myBrowser->Main()->end(), myBrowser->Main()->currentI());
|
||||
for (auto it = list.begin(); it != list.end(); ++it)
|
||||
{
|
||||
const MPD::Item &it = (*myBrowser->Main())[list[i]].value();
|
||||
name = it.type == itSong ? it.song->getName() : it.name;
|
||||
if (myBrowser->deleteItem(it))
|
||||
const MPD::Item &i = (*it)->value();
|
||||
std::string name = i.type == itSong ? i.song->getName() : i.name;
|
||||
if (myBrowser->deleteItem(i))
|
||||
{
|
||||
const char msg[] = "\"%s\" deleted";
|
||||
ShowMessage(msg, Shorten(TO_WSTRING(name), COLS-const_strlen(msg)).c_str());
|
||||
@@ -875,7 +827,7 @@ void Delete::Run()
|
||||
{
|
||||
const char msg[] = "Couldn't delete \"%s\": %s";
|
||||
ShowMessage(msg, Shorten(TO_WSTRING(name), COLS-const_strlen(msg)-25).c_str(), strerror(errno));
|
||||
success = 0;
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -883,8 +835,6 @@ void Delete::Run()
|
||||
{
|
||||
if (!myBrowser->isLocal())
|
||||
Mpd.UpdateDirectory(myBrowser->CurrentDir());
|
||||
else
|
||||
myBrowser->GetDirectory(myBrowser->CurrentDir());
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -892,27 +842,47 @@ void Delete::Run()
|
||||
|
||||
}
|
||||
# endif // !WIN32
|
||||
else if (myScreen->ActiveWindow() == myPlaylistEditor->Content && !myPlaylistEditor->Content->empty())
|
||||
else if (myScreen == myPlaylistEditor && !myPlaylistEditor->Content->empty())
|
||||
{
|
||||
if (myPlaylistEditor->Content->hasSelected())
|
||||
if (myScreen->ActiveWindow() == myPlaylistEditor->Playlists)
|
||||
{
|
||||
std::vector<size_t> list;
|
||||
myPlaylistEditor->Content->getSelected(list);
|
||||
std::string playlist = locale_to_utf_cpy(myPlaylistEditor->Playlists->current().value());
|
||||
ShowMessage("Deleting selected items...");
|
||||
Mpd.StartCommandsList();
|
||||
for (std::vector<size_t>::reverse_iterator it = list.rbegin(); it != list.rend(); ++it)
|
||||
std::string question;
|
||||
if (myPlaylistEditor->Playlists->hasSelected())
|
||||
question = "Delete selected playlists?";
|
||||
else
|
||||
{
|
||||
Mpd.Delete(playlist, *it);
|
||||
myPlaylistEditor->Content->deleteItem(*it);
|
||||
question = "Delete playlist \"";
|
||||
question += Shorten(TO_WSTRING(myPlaylistEditor->Playlists->current().value()), COLS-question.size()-10);
|
||||
question += "\"?";
|
||||
}
|
||||
Mpd.CommitCommandsList();
|
||||
ShowMessage("Selected items deleted from playlist \"%s\"", myPlaylistEditor->Playlists->current().value().c_str());
|
||||
bool yes = AskYesNoQuestion(question, TraceMpdStatus);
|
||||
if (yes)
|
||||
{
|
||||
auto list = getSelectedOrCurrent(myPlaylistEditor->Playlists->begin(), myPlaylistEditor->Playlists->end(), myPlaylistEditor->Playlists->currentI());
|
||||
Mpd.StartCommandsList();
|
||||
for (auto it = list.begin(); it != list.end(); ++it)
|
||||
Mpd.DeletePlaylist((*it)->value());
|
||||
if (Mpd.CommitCommandsList())
|
||||
ShowMessage("Playlist%s deleted", list.size() == 1 ? "" : "s");
|
||||
}
|
||||
else
|
||||
ShowMessage("Aborted");
|
||||
}
|
||||
else
|
||||
else if (myScreen->ActiveWindow() == myPlaylistEditor->Content)
|
||||
{
|
||||
if (Mpd.Delete(myPlaylistEditor->Playlists->current().value(), myPlaylistEditor->Content->choice()))
|
||||
myPlaylistEditor->Content->deleteItem(myPlaylistEditor->Content->choice());
|
||||
// select current song so we won't lost track of it after filtering is canceled
|
||||
selectCurrentIfNoneSelected(*myPlaylistEditor->Content);
|
||||
myPlaylistEditor->Content->showAll();
|
||||
auto list = getSelected(myPlaylistEditor->Content->begin(), myPlaylistEditor->Content->end());
|
||||
Mpd.StartCommandsList();
|
||||
auto begin = myPlaylistEditor->Content->begin();
|
||||
for (auto it = list.rbegin(); it != list.rend(); ++it)
|
||||
Mpd.Delete(myPlaylistEditor->Playlists->current().value(), *it-begin);
|
||||
if (Mpd.CommitCommandsList())
|
||||
{
|
||||
if (list.size() > 1)
|
||||
ShowMessage("Selected items deleted");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1052,56 +1022,18 @@ void MoveSelectedItemsDown::Run()
|
||||
myPlaylistEditor->MoveSelectedItems(Playlist::mDown);
|
||||
}
|
||||
|
||||
bool MoveSelectedItemsTo::canBeRun() const
|
||||
{
|
||||
return myScreen->ActiveWindow() == myPlaylist->Items
|
||||
|| myScreen->ActiveWindow() == myPlaylistEditor->Content;
|
||||
}
|
||||
|
||||
void MoveSelectedItemsTo::Run()
|
||||
{
|
||||
if (myPlaylist->isFiltered())
|
||||
return;
|
||||
if (!myPlaylist->Items->hasSelected())
|
||||
{
|
||||
ShowMessage("No selected items to move");
|
||||
return;
|
||||
}
|
||||
size_t pos = myPlaylist->Items->choice();
|
||||
std::vector<size_t> list;
|
||||
myPlaylist->Items->getSelected(list);
|
||||
if (pos >= list.front() && pos <= list.back()) // can't move to the middle of selected items
|
||||
return;
|
||||
++pos; // always move after currently highlighted item
|
||||
int diff = pos-list.front();
|
||||
Mpd.StartCommandsList();
|
||||
if (diff > 0)
|
||||
{
|
||||
pos -= list.size();
|
||||
size_t i = list.size()-1;
|
||||
std::vector<size_t>::reverse_iterator it = list.rbegin();
|
||||
for (; it != list.rend(); ++it, --i)
|
||||
Mpd.Move(*it, pos+i);
|
||||
if (Mpd.CommitCommandsList())
|
||||
{
|
||||
i = list.size()-1;
|
||||
for (it = list.rbegin(); it != list.rend(); ++it, --i)
|
||||
{
|
||||
myPlaylist->Items->at(*it).setSelected(false);
|
||||
myPlaylist->Items->at(pos+i).setSelected(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (diff < 0)
|
||||
{
|
||||
size_t i = 0;
|
||||
std::vector<size_t>::const_iterator it = list.begin();
|
||||
for (; it != list.end(); ++it, ++i)
|
||||
Mpd.Move(*it, pos+i);
|
||||
if (Mpd.CommitCommandsList())
|
||||
{
|
||||
i = 0;
|
||||
for (it = list.begin(); it != list.end(); ++it, ++i)
|
||||
{
|
||||
myPlaylist->Items->at(*it).setSelected(false);
|
||||
myPlaylist->Items->at(pos+i).setSelected(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (myScreen == myPlaylist)
|
||||
moveSelectedItemsTo(*myPlaylist->Items, std::bind(&MPD::Connection::Move, _1, _2, _3));
|
||||
else
|
||||
moveSelectedItemsTo(*myPlaylistEditor->Content, std::bind(&MPD::Connection::PlaylistMove, _1, myPlaylistEditor->Playlists->current().value(), _2, _3));
|
||||
}
|
||||
|
||||
bool Add::canBeRun() const
|
||||
|
||||
@@ -355,6 +355,7 @@ struct MoveSelectedItemsDown : public Action
|
||||
struct MoveSelectedItemsTo : public Action
|
||||
{
|
||||
MoveSelectedItemsTo() : Action(aMoveSelectedItemsTo, "move_selected_items_to") { }
|
||||
virtual bool canBeRun() const;
|
||||
virtual void Run();
|
||||
};
|
||||
|
||||
|
||||
192
src/helpers.h
192
src/helpers.h
@@ -50,6 +50,189 @@ inline MPD::Song *currentSong(BasicScreen *screen)
|
||||
return ptr;
|
||||
}
|
||||
|
||||
template <typename Iterator> bool hasSelected(Iterator first, Iterator last)
|
||||
{
|
||||
for (; first != last; ++first)
|
||||
if (first->isSelected())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename Iterator> std::vector<Iterator> getSelected(Iterator first, Iterator last)
|
||||
{
|
||||
std::vector<Iterator> result;
|
||||
for (; first != last; ++first)
|
||||
if (first->isSelected())
|
||||
result.push_back(first);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T> void selectCurrentIfNoneSelected(NC::Menu<T> &m)
|
||||
{
|
||||
if (!hasSelected(m.begin(), m.end()))
|
||||
m.current().setSelected(true);
|
||||
}
|
||||
|
||||
template <typename Iterator>
|
||||
std::vector<Iterator> getSelectedOrCurrent(Iterator first, Iterator last, Iterator current)
|
||||
{
|
||||
std::vector<Iterator> result = getSelected(first, last);
|
||||
if (result.empty())
|
||||
result.push_back(current);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, typename F> void withUnfilteredMenu(NC::Menu<T> &m, F action)
|
||||
{
|
||||
bool is_filtered = m.isFiltered();
|
||||
m.showAll();
|
||||
action();
|
||||
if (is_filtered)
|
||||
m.showFiltered();
|
||||
}
|
||||
|
||||
template <typename T, typename F>
|
||||
void withUnfilteredMenuReapplyFilter(NC::Menu<T> &m, F action)
|
||||
{
|
||||
m.showAll();
|
||||
action();
|
||||
if (m.getFilter())
|
||||
{
|
||||
m.applyCurrentFilter(m.begin(), m.end());
|
||||
if (m.empty())
|
||||
{
|
||||
m.clearFilter();
|
||||
m.clearFilterResults();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename F>
|
||||
void moveSelectedItemsUp(NC::Menu<T> &m, F swap_fun)
|
||||
{
|
||||
if (m.choice() > 0)
|
||||
selectCurrentIfNoneSelected(m);
|
||||
auto list = getSelected(m.begin(), m.end());
|
||||
auto begin = m.begin();
|
||||
if (!list.empty() && list.front() != m.begin())
|
||||
{
|
||||
Mpd.StartCommandsList();
|
||||
for (auto it = list.begin(); it != list.end(); ++it)
|
||||
swap_fun(Mpd, *it - begin, *it - begin - 1);
|
||||
if (Mpd.CommitCommandsList())
|
||||
{
|
||||
if (list.size() > 1)
|
||||
{
|
||||
for (auto it = list.begin(); it != list.end(); ++it)
|
||||
{
|
||||
(*it)->setSelected(false);
|
||||
(*it-1)->setSelected(true);
|
||||
}
|
||||
m.highlight(list[(list.size())/2] - begin - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// if we move only one item, do not select it. however, if single item
|
||||
// was selected prior to move, it'll deselect it. oh well.
|
||||
list[0]->setSelected(false);
|
||||
m.scroll(NC::wUp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename F>
|
||||
void moveSelectedItemsDown(NC::Menu<T> &m, F swap_fun)
|
||||
{
|
||||
if (m.choice() < m.size()-1)
|
||||
selectCurrentIfNoneSelected(m);
|
||||
auto list = getSelected(m.rbegin(), m.rend());
|
||||
auto begin = m.begin() + 1; // reverse iterators add 1, so we need to cancel it
|
||||
if (!list.empty() && list.front() != m.rbegin())
|
||||
{
|
||||
Mpd.StartCommandsList();
|
||||
for (auto it = list.begin(); it != list.end(); ++it)
|
||||
swap_fun(Mpd, it->base() - begin, it->base() - begin + 1);
|
||||
if (Mpd.CommitCommandsList())
|
||||
{
|
||||
if (list.size() > 1)
|
||||
{
|
||||
for (auto it = list.begin(); it != list.end(); ++it)
|
||||
{
|
||||
(*it)->setSelected(false);
|
||||
(*it-1)->setSelected(true);
|
||||
}
|
||||
m.highlight(list[(list.size())/2].base() - begin + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// if we move only one item, do not select it. however, if single item
|
||||
// was selected prior to move, it'll deselect it. oh well.
|
||||
list[0]->setSelected(false);
|
||||
m.scroll(NC::wDown);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename F>
|
||||
void moveSelectedItemsTo(NC::Menu<T> &m, F move_fun)
|
||||
{
|
||||
if (m.empty())
|
||||
return;
|
||||
auto cur_ptr = &m.current().value();
|
||||
withUnfilteredMenu(m, [&]() {
|
||||
// this is kinda shitty, but there is no other way to know
|
||||
// what position current item has in unfiltered menu.
|
||||
ptrdiff_t pos = 0;
|
||||
for (auto it = m.begin(); it != m.end(); ++it, ++pos)
|
||||
if (&it->value() == cur_ptr)
|
||||
break;
|
||||
auto begin = m.begin();
|
||||
auto list = getSelected(m.begin(), m.end());
|
||||
// we move only truly selected items
|
||||
if (list.empty())
|
||||
return;
|
||||
// we can't move to the middle of selected items
|
||||
//(this also handles case when list.size() == 1)
|
||||
if (pos >= (list.front() - begin) && pos <= (list.back() - begin))
|
||||
return;
|
||||
int diff = pos - (list.front() - begin);
|
||||
Mpd.StartCommandsList();
|
||||
if (diff > 0) // move down
|
||||
{
|
||||
pos -= list.size();
|
||||
size_t i = list.size()-1;
|
||||
for (auto it = list.rbegin(); it != list.rend(); ++it, --i)
|
||||
move_fun(Mpd, *it - begin, pos+i);
|
||||
if (Mpd.CommitCommandsList())
|
||||
{
|
||||
i = list.size()-1;
|
||||
for (auto it = list.rbegin(); it != list.rend(); ++it, --i)
|
||||
{
|
||||
(*it)->setSelected(false);
|
||||
m[pos+i].setSelected(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (diff < 0) // move up
|
||||
{
|
||||
size_t i = 0;
|
||||
for (auto it = list.begin(); it != list.end(); ++it, ++i)
|
||||
move_fun(Mpd, *it - begin, pos+i);
|
||||
if (Mpd.CommitCommandsList())
|
||||
{
|
||||
i = 0;
|
||||
for (auto it = list.begin(); it != list.end(); ++it, ++i)
|
||||
{
|
||||
(*it)->setSelected(false);
|
||||
m[pos+i].setSelected(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template <typename Iterator> void reverseSelectionHelper(Iterator first, Iterator last)
|
||||
{
|
||||
for (; first != last; ++first)
|
||||
@@ -69,15 +252,6 @@ template <typename Iterator> std::string getSharedDirectory(Iterator first, Iter
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T> void withUnfilteredMenu(NC::Menu<T> &menu, std::function<void()> action)
|
||||
{
|
||||
bool is_filtered = menu.isFiltered();
|
||||
menu.showAll();
|
||||
action();
|
||||
if (is_filtered)
|
||||
menu.showFiltered();
|
||||
}
|
||||
|
||||
void ParseArgv(int, char **);
|
||||
|
||||
template <typename T> struct StringConverter {
|
||||
|
||||
50
src/menu.h
50
src/menu.h
@@ -60,6 +60,10 @@ template <typename T> struct Menu : public Window
|
||||
bool isSeparator() const { return m_is_separator; }
|
||||
|
||||
private:
|
||||
// make those private, they shouldn't be used
|
||||
Item(const Item &) { assert(false); }
|
||||
Item &operator=(const Item &) { assert(false); }
|
||||
|
||||
static Item *mkSeparator()
|
||||
{
|
||||
Item *i = new Item;
|
||||
@@ -234,10 +238,6 @@ template <typename T> struct Menu : public Window
|
||||
/// @return true if it contains them, false otherwise
|
||||
bool hasSelected() const;
|
||||
|
||||
/// Gets positions of items that are selected
|
||||
/// @param v vector to be filled with selected positions numbers
|
||||
void getSelected(std::vector<size_t> &v) const;
|
||||
|
||||
/// Highlights given position
|
||||
/// @param pos position to be highlighted
|
||||
void highlight(size_t pos);
|
||||
@@ -247,11 +247,15 @@ template <typename T> struct Menu : public Window
|
||||
|
||||
void filter(ConstIterator first, ConstIterator last, const FilterFunction &f);
|
||||
|
||||
void applyCurrentFilter(ConstIterator first, ConstIterator last);
|
||||
|
||||
bool search(ConstIterator first, ConstIterator last, const FilterFunction &f);
|
||||
|
||||
/// Clears filter results
|
||||
void clearFilterResults();
|
||||
|
||||
void clearFilter();
|
||||
|
||||
/// Clears search results
|
||||
void clearSearchResults();
|
||||
|
||||
@@ -378,6 +382,11 @@ template <typename T> struct Menu : public Window
|
||||
/// @return const reference to item at given position
|
||||
Menu<T>::Item &operator[](size_t pos) { return *(*m_options_ptr)[pos]; }
|
||||
|
||||
Iterator currentI() { return Iterator(m_options_ptr->begin() + m_highlight); }
|
||||
ConstIterator currentI() const { return ConstIterator(m_options_ptr->begin() + m_highlight); }
|
||||
ValueIterator currentVI() { return ValueIterator(m_options_ptr->begin() + m_highlight); }
|
||||
ConstValueIterator currentVI() const { return ConstValueIterator(m_options_ptr->begin() + m_highlight); }
|
||||
|
||||
Iterator begin() { return Iterator(m_options_ptr->begin()); }
|
||||
ConstIterator begin() const { return ConstIterator(m_options_ptr->begin()); }
|
||||
Iterator end() { return Iterator(m_options_ptr->end()); }
|
||||
@@ -412,7 +421,6 @@ private:
|
||||
std::vector<Item *> *m_options_ptr;
|
||||
std::vector<Item *> m_options;
|
||||
std::vector<Item *> m_filtered_options;
|
||||
std::vector<size_t> m_filtered_positions;
|
||||
std::set<size_t> m_found_positions;
|
||||
|
||||
size_t m_beginning;
|
||||
@@ -697,13 +705,6 @@ template <typename T> bool Menu<T>::hasSelected() const
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T> void Menu<T>::getSelected(std::vector<size_t> &v) const
|
||||
{
|
||||
for (size_t i = 0; i < m_options_ptr->size(); ++i)
|
||||
if ((*m_options_ptr)[i]->isSelected())
|
||||
v.push_back(i);
|
||||
}
|
||||
|
||||
template <typename T> void Menu<T>::highlight(size_t pos)
|
||||
{
|
||||
m_highlight = pos;
|
||||
@@ -727,24 +728,33 @@ void Menu<T>::filter(ConstIterator first, ConstIterator last, const FilterFuncti
|
||||
clearFilterResults();
|
||||
m_filter = f;
|
||||
for (auto it = first; it != last; ++it)
|
||||
{
|
||||
if (m_filter(*it))
|
||||
{
|
||||
size_t pos = it-begin();
|
||||
m_filtered_positions.push_back(pos);
|
||||
m_filtered_options.push_back(*it.base());
|
||||
}
|
||||
}
|
||||
m_options_ptr = &m_filtered_options;
|
||||
if (m_filtered_options == m_options)
|
||||
m_filtered_options.clear();
|
||||
else
|
||||
m_options_ptr = &m_filtered_options;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Menu<T>::applyCurrentFilter(ConstIterator first, ConstIterator last)
|
||||
{
|
||||
assert(m_filter);
|
||||
filter(first, last, m_filter);
|
||||
}
|
||||
|
||||
|
||||
template <typename T> void Menu<T>::clearFilterResults()
|
||||
{
|
||||
m_filtered_options.clear();
|
||||
m_filtered_positions.clear();
|
||||
m_options_ptr = &m_options;
|
||||
}
|
||||
|
||||
template <typename T> void Menu<T>::clearFilter()
|
||||
{
|
||||
m_filter = 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool Menu<T>::search(ConstIterator first, ConstIterator last, const FilterFunction &f)
|
||||
{
|
||||
|
||||
@@ -241,6 +241,8 @@ void MPD::Connection::UpdateStatus()
|
||||
{
|
||||
if (idle_mask != 0)
|
||||
{
|
||||
itsChanges.Playlist = idle_mask & MPD_IDLE_QUEUE;
|
||||
itsChanges.StoredPlaylists = idle_mask & MPD_IDLE_STORED_PLAYLIST;
|
||||
itsChanges.Database = idle_mask & MPD_IDLE_DATABASE;
|
||||
itsChanges.DBUpdating = idle_mask & MPD_IDLE_UPDATE;
|
||||
itsChanges.Volume = idle_mask & MPD_IDLE_MIXER;
|
||||
@@ -249,6 +251,9 @@ void MPD::Connection::UpdateStatus()
|
||||
}
|
||||
else
|
||||
{
|
||||
itsChanges.Playlist = mpd_status_get_queue_version(itsOldStatus)
|
||||
!= mpd_status_get_queue_version(itsCurrentStatus);
|
||||
|
||||
itsChanges.ElapsedTime = mpd_status_get_elapsed_time(itsOldStatus)
|
||||
!= mpd_status_get_elapsed_time(itsCurrentStatus);
|
||||
|
||||
@@ -273,9 +278,6 @@ void MPD::Connection::UpdateStatus()
|
||||
itsChanges.Outputs = 0;
|
||||
}
|
||||
|
||||
itsChanges.Playlist = mpd_status_get_queue_version(itsOldStatus)
|
||||
!= mpd_status_get_queue_version(itsCurrentStatus);
|
||||
|
||||
itsChanges.SongID = mpd_status_get_song_id(itsOldStatus)
|
||||
!= mpd_status_get_song_id(itsCurrentStatus);
|
||||
|
||||
@@ -588,7 +590,7 @@ void MPD::Connection::AddToPlaylist(const std::string &path, const std::string &
|
||||
}
|
||||
}
|
||||
|
||||
bool MPD::Connection::Move(const std::string &path, int from, int to)
|
||||
bool MPD::Connection::PlaylistMove(const std::string &path, int from, int to)
|
||||
{
|
||||
if (!itsConnection)
|
||||
return false;
|
||||
|
||||
@@ -42,8 +42,9 @@ namespace MPD
|
||||
|
||||
struct StatusChanges
|
||||
{
|
||||
StatusChanges() : Playlist(0), SongID(0), Database(0), DBUpdating(0), Volume(0), ElapsedTime(0), Crossfade(0), Random(0), Repeat(0), Single(0), Consume(0), PlayerState(0), StatusFlags(0), Outputs(0) { }
|
||||
StatusChanges() : Playlist(0), StoredPlaylists(0), SongID(0), Database(0), DBUpdating(0), Volume(0), ElapsedTime(0), Crossfade(0), Random(0), Repeat(0), Single(0), Consume(0), PlayerState(0), StatusFlags(0), Outputs(0) { }
|
||||
bool Playlist:1;
|
||||
bool StoredPlaylists:1;
|
||||
bool SongID:1;
|
||||
bool Database:1;
|
||||
bool DBUpdating:1;
|
||||
@@ -193,7 +194,7 @@ namespace MPD
|
||||
bool ClearPlaylist(const std::string &);
|
||||
void AddToPlaylist(const std::string &, const Song &);
|
||||
void AddToPlaylist(const std::string &, const std::string &);
|
||||
bool Move(const std::string &, int, int);
|
||||
bool PlaylistMove(const std::string &, int, int);
|
||||
bool Rename(const std::string &, const std::string &);
|
||||
|
||||
void StartSearch(bool);
|
||||
|
||||
@@ -167,14 +167,14 @@ void Playlist::EnterPressed()
|
||||
{
|
||||
size_t pos = SortDialog->choice();
|
||||
|
||||
size_t beginning = 0;
|
||||
size_t end = Items->size();
|
||||
auto begin = Items->begin(), end = Items->end();
|
||||
// if songs are selected, sort range from first selected to last selected
|
||||
if (Items->hasSelected())
|
||||
{
|
||||
std::vector<size_t> list;
|
||||
Items->getSelected(list);
|
||||
beginning = *list.begin();
|
||||
end = *list.rbegin()+1;
|
||||
while (!begin->isSelected())
|
||||
++begin;
|
||||
while (!(end-1)->isSelected())
|
||||
--end;
|
||||
}
|
||||
|
||||
if (pos > SortOptions)
|
||||
@@ -191,10 +191,11 @@ void Playlist::EnterPressed()
|
||||
return;
|
||||
}
|
||||
|
||||
size_t start_pos = begin-Items->begin();
|
||||
MPD::SongList playlist;
|
||||
playlist.reserve(end-beginning);
|
||||
for (size_t i = beginning; i < end; ++i)
|
||||
playlist.push_back((*Items)[i].value());
|
||||
playlist.reserve(end-begin);
|
||||
for (; begin != end; ++begin)
|
||||
playlist.push_back(begin->value());
|
||||
|
||||
std::function<void(MPD::SongList::iterator, MPD::SongList::iterator)> iter_swap, quick_sort;
|
||||
auto song_cmp = [](const MPD::Song &a, const MPD::Song &b) -> bool {
|
||||
@@ -204,9 +205,9 @@ void Playlist::EnterPressed()
|
||||
return ret < 0;
|
||||
return a.getPosition() < b.getPosition();
|
||||
};
|
||||
iter_swap = [&playlist](MPD::SongList::iterator a, MPD::SongList::iterator b) {
|
||||
iter_swap = [&playlist, &start_pos](MPD::SongList::iterator a, MPD::SongList::iterator b) {
|
||||
std::iter_swap(a, b);
|
||||
Mpd.Swap(a-playlist.begin(), b-playlist.begin());
|
||||
Mpd.Swap(start_pos+a-playlist.begin(), start_pos+b-playlist.begin());
|
||||
};
|
||||
quick_sort = [this, &song_cmp, &quick_sort, &iter_swap](MPD::SongList::iterator first, MPD::SongList::iterator last) {
|
||||
if (last-first > 1)
|
||||
@@ -398,65 +399,12 @@ void Playlist::MoveSelectedItems(Movement where)
|
||||
{
|
||||
case mUp:
|
||||
{
|
||||
if (Items->hasSelected())
|
||||
{
|
||||
std::vector<size_t> list;
|
||||
myPlaylist->Items->getSelected(list);
|
||||
if (list.front() > 0)
|
||||
{
|
||||
Mpd.StartCommandsList();
|
||||
std::vector<size_t>::const_iterator it = list.begin();
|
||||
for (; it != list.end(); ++it)
|
||||
Mpd.Move(*it-1, *it);
|
||||
if (Mpd.CommitCommandsList())
|
||||
{
|
||||
Items->at(list.back()).setSelected(false);
|
||||
Items->at(list.front()-1).setSelected(true);
|
||||
Items->highlight(list[(list.size()-1)/2]-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t pos = myPlaylist->Items->choice();
|
||||
if (pos > 0)
|
||||
{
|
||||
if (Mpd.Move(pos-1, pos))
|
||||
Items->scroll(NC::wUp);
|
||||
}
|
||||
}
|
||||
moveSelectedItemsUp(*Items, std::bind(&MPD::Connection::Move, _1, _2, _3));
|
||||
break;
|
||||
}
|
||||
case mDown:
|
||||
{
|
||||
if (Items->hasSelected())
|
||||
{
|
||||
std::vector<size_t> list;
|
||||
Items->getSelected(list);
|
||||
|
||||
if (list.back() < Items->size()-1)
|
||||
{
|
||||
Mpd.StartCommandsList();
|
||||
std::vector<size_t>::const_reverse_iterator it = list.rbegin();
|
||||
for (; it != list.rend(); ++it)
|
||||
Mpd.Move(*it, *it+1);
|
||||
if (Mpd.CommitCommandsList())
|
||||
{
|
||||
Items->at(list.front()).setSelected(false);
|
||||
Items->at(list.back()+1).setSelected(true);
|
||||
Items->highlight(list[(list.size()-1)/2]+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t pos = Items->choice();
|
||||
if (pos < Items->size()-1)
|
||||
{
|
||||
if (Mpd.Move(pos, pos+1))
|
||||
Items->scroll(NC::wDown);
|
||||
}
|
||||
}
|
||||
moveSelectedItemsDown(*Items, std::bind(&MPD::Connection::Move, _1, _2, _3));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -675,13 +623,10 @@ void Playlist::PlayNewlyAddedSongs()
|
||||
|
||||
void Playlist::SetSelectedItemsPriority(int prio)
|
||||
{
|
||||
std::vector<size_t> list;
|
||||
myPlaylist->Items->getSelected(list);
|
||||
if (list.empty())
|
||||
list.push_back(Items->choice());
|
||||
auto list = getSelectedOrCurrent(Items->begin(), Items->end(), Items->currentI());
|
||||
Mpd.StartCommandsList();
|
||||
for (std::vector<size_t>::const_iterator it = list.begin(); it != list.end(); ++it)
|
||||
Mpd.SetPriority((*Items)[*it].value(), prio);
|
||||
for (auto it = list.begin(); it != list.end(); ++it)
|
||||
Mpd.SetPriority((*it)->value(), prio);
|
||||
if (Mpd.CommitCommandsList())
|
||||
ShowMessage("Priority set");
|
||||
}
|
||||
|
||||
@@ -133,46 +133,64 @@ void PlaylistEditor::SwitchTo()
|
||||
Global::myPrevScreen = myScreen;
|
||||
myScreen = this;
|
||||
Global::RedrawHeader = true;
|
||||
Refresh();
|
||||
UpdateSongList(Content);
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void PlaylistEditor::Update()
|
||||
{
|
||||
if (Playlists->reallyEmpty())
|
||||
if (Playlists->reallyEmpty() || playlistsUpdateRequested)
|
||||
{
|
||||
Content->clear();
|
||||
auto list = Mpd.GetPlaylists();
|
||||
std::sort(list.begin(), list.end(), CaseInsensitiveSorting());
|
||||
for (auto it = list.begin(); it != list.end(); ++it)
|
||||
Playlists->addItem(*it);
|
||||
playlistsUpdateRequested = false;
|
||||
Playlists->clearSearchResults();
|
||||
withUnfilteredMenuReapplyFilter(*Playlists, [this]() {
|
||||
auto list = Mpd.GetPlaylists();
|
||||
std::sort(list.begin(), list.end(), CaseInsensitiveSorting());
|
||||
auto playlist = list.begin();
|
||||
if (Playlists->size() > list.size())
|
||||
Playlists->resizeList(list.size());
|
||||
for (auto it = Playlists->begin(); it != Playlists->end(); ++it, ++playlist)
|
||||
it->value() = *playlist;
|
||||
for (; playlist != list.end(); ++playlist)
|
||||
Playlists->addItem(*playlist);
|
||||
});
|
||||
Playlists->refresh();
|
||||
}
|
||||
|
||||
if (!Playlists->empty() && Content->reallyEmpty())
|
||||
if (!Playlists->empty() && (Content->reallyEmpty() || contentUpdateRequested))
|
||||
{
|
||||
Content->reset();
|
||||
size_t plsize = 0;
|
||||
auto songs = Mpd.GetPlaylistContent(Playlists->current().value());
|
||||
for (auto s = songs.begin(); s != songs.end(); ++s, ++plsize)
|
||||
Content->addItem(*s, myPlaylist->checkForSong(*s));
|
||||
std::string title;
|
||||
if (Config.titles_visibility)
|
||||
{
|
||||
title = "Playlist content";
|
||||
if (plsize > 0)
|
||||
contentUpdateRequested = false;
|
||||
Content->clearSearchResults();
|
||||
withUnfilteredMenuReapplyFilter(*Content, [this]() {
|
||||
auto list = Mpd.GetPlaylistContent(Playlists->current().value());
|
||||
auto song = list.begin();
|
||||
if (Content->size() > list.size())
|
||||
Content->resizeList(list.size());
|
||||
for (auto it = Content->begin(); it != Content->end(); ++it, ++song)
|
||||
{
|
||||
title += " (";
|
||||
title += unsignedLongIntTo<std::string>::apply(plsize);
|
||||
title += " item";
|
||||
if (plsize == 1)
|
||||
title += ")";
|
||||
else
|
||||
title += "s)";
|
||||
it->value() = *song;
|
||||
it->setBold(myPlaylist->checkForSong(*song));
|
||||
}
|
||||
title.resize(Content->getWidth());
|
||||
}
|
||||
Content->setTitle(title);
|
||||
for (; song != list.end(); ++song)
|
||||
Content->addItem(*song, myPlaylist->checkForSong(*song));
|
||||
std::string title;
|
||||
if (Config.titles_visibility)
|
||||
{
|
||||
title = "Playlist content";
|
||||
if (list.size() > 0)
|
||||
{
|
||||
title += " (";
|
||||
title += unsignedLongIntTo<std::string>::apply(list.size());
|
||||
title += " item";
|
||||
if (list.size() == 1)
|
||||
title += ")";
|
||||
else
|
||||
title += "s)";
|
||||
}
|
||||
title.resize(Content->getWidth());
|
||||
}
|
||||
Content->setTitle(title);
|
||||
});
|
||||
Content->display();
|
||||
}
|
||||
|
||||
@@ -192,83 +210,19 @@ void PlaylistEditor::Update()
|
||||
|
||||
void PlaylistEditor::MoveSelectedItems(Playlist::Movement where)
|
||||
{
|
||||
if (Content->empty())
|
||||
if (Content->empty() || isContentFiltered())
|
||||
return;
|
||||
|
||||
// remove search results as we may move them to different positions, but
|
||||
// search rememebers positions and may point to wrong ones after that.
|
||||
Content->clearSearchResults();
|
||||
|
||||
switch (where)
|
||||
{
|
||||
case Playlist::mUp:
|
||||
{
|
||||
if (Content->hasSelected())
|
||||
{
|
||||
std::vector<size_t> list;
|
||||
Content->getSelected(list);
|
||||
|
||||
if (list.front() > 0)
|
||||
{
|
||||
Mpd.StartCommandsList();
|
||||
std::vector<size_t>::const_iterator it = list.begin();
|
||||
for (; it != list.end(); ++it)
|
||||
Mpd.Move(Playlists->current().value(), *it-1, *it);
|
||||
if (Mpd.CommitCommandsList())
|
||||
{
|
||||
for (it = list.begin(); it != list.end(); ++it)
|
||||
Content->Swap(*it-1, *it);
|
||||
Content->highlight(list[(list.size()-1)/2]-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t pos = Content->choice();
|
||||
if (pos > 0)
|
||||
{
|
||||
if (Mpd.Move(Playlists->current().value(), pos-1, pos))
|
||||
{
|
||||
Content->scroll(NC::wUp);
|
||||
Content->Swap(pos-1, pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
moveSelectedItemsUp(*Content, std::bind(&MPD::Connection::PlaylistMove, _1, Playlists->current().value(), _2, _3));
|
||||
break;
|
||||
}
|
||||
case Playlist::mDown:
|
||||
{
|
||||
if (Content->hasSelected())
|
||||
{
|
||||
std::vector<size_t> list;
|
||||
Content->getSelected(list);
|
||||
|
||||
if (list.back() < Content->size()-1)
|
||||
{
|
||||
Mpd.StartCommandsList();
|
||||
std::vector<size_t>::const_reverse_iterator it = list.rbegin();
|
||||
for (; it != list.rend(); ++it)
|
||||
Mpd.Move(Playlists->current().value(), *it, *it+1);
|
||||
if (Mpd.CommitCommandsList())
|
||||
{
|
||||
Content->highlight(list[(list.size()-1)/2]+1);
|
||||
for (it = list.rbegin(); it != list.rend(); ++it)
|
||||
Content->Swap(*it, *it+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t pos = Content->choice();
|
||||
if (pos < Content->size()-1)
|
||||
{
|
||||
if (Mpd.Move(Playlists->current().value(), pos, pos+1))
|
||||
{
|
||||
Content->scroll(NC::wDown);
|
||||
Content->Swap(pos, pos+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
moveSelectedItemsDown(*Content, std::bind(&MPD::Connection::PlaylistMove, _1, Playlists->current().value(), _2, _3));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +63,9 @@ class PlaylistEditor : public Screen<NC::Window>, public Filterable, public HasS
|
||||
|
||||
void MoveSelectedItems(Playlist::Movement where);
|
||||
|
||||
void requestPlaylistsUpdate() { playlistsUpdateRequested = true; }
|
||||
void requestContentsUpdate() { contentUpdateRequested = true; }
|
||||
|
||||
bool isContentFiltered();
|
||||
bool isNextColumnAvailable();
|
||||
bool NextColumn();
|
||||
@@ -78,6 +81,9 @@ class PlaylistEditor : public Screen<NC::Window>, public Filterable, public HasS
|
||||
|
||||
private:
|
||||
void AddToPlaylist(bool);
|
||||
|
||||
bool playlistsUpdateRequested;
|
||||
bool contentUpdateRequested;
|
||||
};
|
||||
|
||||
extern PlaylistEditor *myPlaylistEditor;
|
||||
|
||||
@@ -228,52 +228,37 @@ void NcmpcppStatusChanged(MPD::Connection *, MPD::StatusChanges changed, void *)
|
||||
WindowTitle(np.toString(Config.song_window_title_format));
|
||||
|
||||
myPlaylist->Items->clearSearchResults();
|
||||
|
||||
bool is_filtered = myPlaylist->Items->isFiltered();
|
||||
myPlaylist->Items->showAll();
|
||||
|
||||
size_t playlist_length = Mpd.GetPlaylistLength();
|
||||
if (playlist_length < myPlaylist->Items->size())
|
||||
{
|
||||
auto it = myPlaylist->Items->begin()+playlist_length;
|
||||
auto end = myPlaylist->Items->end();
|
||||
for (; it != end; ++it)
|
||||
myPlaylist->unregisterHash(it->value().getHash());
|
||||
myPlaylist->Items->resizeList(playlist_length);
|
||||
}
|
||||
|
||||
auto songs = Mpd.GetPlaylistChanges(Mpd.GetOldPlaylistID());
|
||||
for (auto s = songs.begin(); s != songs.end(); ++s)
|
||||
{
|
||||
size_t pos = s->getPosition();
|
||||
if (pos < myPlaylist->Items->size())
|
||||
withUnfilteredMenuReapplyFilter(*myPlaylist->Items, []() {
|
||||
size_t playlist_length = Mpd.GetPlaylistLength();
|
||||
if (playlist_length < myPlaylist->Items->size())
|
||||
{
|
||||
// if song's already in playlist, replace it with a new one
|
||||
MPD::Song &old_s = myPlaylist->Items->at(pos).value();
|
||||
myPlaylist->unregisterHash(old_s.getHash());
|
||||
old_s = *s;
|
||||
auto it = myPlaylist->Items->begin()+playlist_length;
|
||||
auto end = myPlaylist->Items->end();
|
||||
for (; it != end; ++it)
|
||||
myPlaylist->unregisterHash(it->value().getHash());
|
||||
myPlaylist->Items->resizeList(playlist_length);
|
||||
}
|
||||
else
|
||||
|
||||
auto songs = Mpd.GetPlaylistChanges(Mpd.GetOldPlaylistID());
|
||||
for (auto s = songs.begin(); s != songs.end(); ++s)
|
||||
{
|
||||
// otherwise just add it to playlist
|
||||
myPlaylist->Items->addItem(*s);
|
||||
size_t pos = s->getPosition();
|
||||
if (pos < myPlaylist->Items->size())
|
||||
{
|
||||
// if song's already in playlist, replace it with a new one
|
||||
MPD::Song &old_s = (*myPlaylist->Items)[pos].value();
|
||||
myPlaylist->unregisterHash(old_s.getHash());
|
||||
old_s = *s;
|
||||
}
|
||||
else // otherwise just add it to playlist
|
||||
myPlaylist->Items->addItem(*s);
|
||||
myPlaylist->registerHash(s->getHash());
|
||||
}
|
||||
myPlaylist->registerHash(s->getHash());
|
||||
}
|
||||
|
||||
if (is_filtered)
|
||||
{
|
||||
myPlaylist->applyFilter(myPlaylist->currentFilter());
|
||||
if (myPlaylist->Items->empty())
|
||||
myPlaylist->Items->showAll();
|
||||
}
|
||||
});
|
||||
|
||||
Playlist::ReloadTotalLength = true;
|
||||
Playlist::ReloadRemaining = true;
|
||||
|
||||
if (myPlaylist->Items->empty())
|
||||
myPlaylist->Items->reset();
|
||||
|
||||
if (isVisible(myBrowser))
|
||||
myBrowser->UpdateItemList();
|
||||
if (isVisible(mySearcher))
|
||||
@@ -283,6 +268,20 @@ void NcmpcppStatusChanged(MPD::Connection *, MPD::StatusChanges changed, void *)
|
||||
if (isVisible(myPlaylistEditor))
|
||||
UpdateSongList(myPlaylistEditor->Content);
|
||||
}
|
||||
if (changed.StoredPlaylists)
|
||||
{
|
||||
if (myPlaylistEditor->Main())
|
||||
{
|
||||
myPlaylistEditor->requestPlaylistsUpdate();
|
||||
myPlaylistEditor->requestContentsUpdate();
|
||||
}
|
||||
if (myBrowser->Main() && myBrowser->CurrentDir() == "/")
|
||||
{
|
||||
myBrowser->GetDirectory("/");
|
||||
if (isVisible(myBrowser))
|
||||
myBrowser->Refresh();
|
||||
}
|
||||
}
|
||||
if (changed.Database)
|
||||
{
|
||||
if (myBrowser->Main())
|
||||
|
||||
@@ -526,14 +526,15 @@ void TagEditor::EnterPressed()
|
||||
EditedSongs.clear();
|
||||
if (Tags->hasSelected()) // if there are selected songs, perform operations only on them
|
||||
{
|
||||
std::vector<size_t> selected;
|
||||
Tags->getSelected(selected);
|
||||
for (auto it = selected.begin(); it != selected.end(); ++it)
|
||||
EditedSongs.push_back(&(*Tags)[*it].value());
|
||||
for (auto it = Tags->begin(); it != Tags->end(); ++it)
|
||||
if (it->isSelected())
|
||||
EditedSongs.push_back(&it->value());
|
||||
}
|
||||
else
|
||||
for (size_t i = 0; i < Tags->size(); ++i)
|
||||
EditedSongs.push_back(&(*Tags)[i].value());
|
||||
{
|
||||
for (auto it = Tags->begin(); it != Tags->end(); ++it)
|
||||
EditedSongs.push_back(&it->value());
|
||||
}
|
||||
|
||||
size_t id = TagTypes->choice();
|
||||
|
||||
|
||||
@@ -155,3 +155,21 @@ MPD::Song::GetFunction charToGetFunction(char c)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::string itemTypeToString(MPD::ItemType type)
|
||||
{
|
||||
std::string result;
|
||||
switch (type)
|
||||
{
|
||||
case MPD::itDirectory:
|
||||
result = "directory";
|
||||
break;
|
||||
case MPD::itSong:
|
||||
result = "song";
|
||||
break;
|
||||
case MPD::itPlaylist:
|
||||
result = "playlist";
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#ifndef _UTILITY_TYPE_CONVERSIONS
|
||||
#define _UTILITY_TYPE_CONVERSIONS
|
||||
|
||||
#include "mpdpp.h"
|
||||
#include "mutable_song.h"
|
||||
|
||||
std::string tagTypeToString(mpd_tag_type tag);
|
||||
@@ -29,4 +30,6 @@ MPD::MutableSong::SetFunction tagTypeToSetFunction(mpd_tag_type tag);
|
||||
mpd_tag_type charToTagType(char c);
|
||||
MPD::Song::GetFunction charToGetFunction(char c);
|
||||
|
||||
std::string itemTypeToString(MPD::ItemType type);
|
||||
|
||||
#endif // _UTILITY_TYPE_CONVERSIONS
|
||||
|
||||
Reference in New Issue
Block a user