use SongIterator

This commit is contained in:
Andrzej Rybczak
2014-11-01 19:45:19 +01:00
parent 485e6ee4a3
commit 4ad5c33f32
10 changed files with 138 additions and 100 deletions

View File

@@ -1319,30 +1319,31 @@ void EditLibraryTag::run()
if (!new_tag.empty() && new_tag != myLibrary->Tags.current().value().tag()) if (!new_tag.empty() && new_tag != myLibrary->Tags.current().value().tag())
{ {
Statusbar::print("Updating tags..."); Statusbar::print("Updating tags...");
Mpd.StartSearch(1); Mpd.StartSearch(true);
Mpd.AddSearch(Config.media_lib_primary_tag, myLibrary->Tags.current().value().tag()); Mpd.AddSearch(Config.media_lib_primary_tag, myLibrary->Tags.current().value().tag());
MPD::MutableSong::SetFunction set = tagTypeToSetFunction(Config.media_lib_primary_tag); MPD::MutableSong::SetFunction set = tagTypeToSetFunction(Config.media_lib_primary_tag);
assert(set); assert(set);
bool success = true; bool success = true;
std::string dir_to_update; std::string dir_to_update;
Mpd.CommitSearchSongs([set, &dir_to_update, &new_tag, &success](MPD::Song s) { for (MPD::SongIterator s = Mpd.CommitSearchSongs(), end; s != end; ++s)
if (!success) {
return; MPD::MutableSong ms = std::move(*s);
MPD::MutableSong ms = s;
ms.setTags(set, new_tag, Config.tags_separator); ms.setTags(set, new_tag, Config.tags_separator);
Statusbar::printf("Updating tags in \"%1%\"...", ms.getName()); Statusbar::printf("Updating tags in \"%1%\"...", ms.getName());
std::string path = Config.mpd_music_dir + ms.getURI(); std::string path = Config.mpd_music_dir + ms.getURI();
if (!Tags::write(ms)) if (!Tags::write(ms))
{ {
success = false;
const char msg[] = "Error while updating tags in \"%1%\""; const char msg[] = "Error while updating tags in \"%1%\"";
Statusbar::printf(msg, wideShorten(ms.getURI(), COLS-const_strlen(msg))); Statusbar::printf(msg, wideShorten(ms.getURI(), COLS-const_strlen(msg)));
success = false; s.finish();
break;
} }
if (dir_to_update.empty()) if (dir_to_update.empty())
dir_to_update = s.getURI(); dir_to_update = ms.getURI();
else else
dir_to_update = getSharedDirectory(dir_to_update, s.getURI()); dir_to_update = getSharedDirectory(dir_to_update, ms.getURI());
}); };
if (success) if (success)
{ {
Mpd.UpdateDirectory(dir_to_update); Mpd.UpdateDirectory(dir_to_update);

View File

@@ -139,8 +139,10 @@ void Browser::enterPressed()
} }
case itPlaylist: case itPlaylist:
{ {
MPD::SongList list; MPD::SongList list(
Mpd.GetPlaylistContentNoInfo(item.name, vectorMoveInserter(list)); std::make_move_iterator(Mpd.GetPlaylistContentNoInfo(item.name)),
std::make_move_iterator(MPD::SongIterator())
);
bool success = addSongsToPlaylist(list.begin(), list.end(), true, -1); bool success = addSongsToPlaylist(list.begin(), list.end(), true, -1);
Statusbar::printf("Playlist \"%1%\" loaded%2%", Statusbar::printf("Playlist \"%1%\" loaded%2%",
item.name, withErrors(success) item.name, withErrors(success)
@@ -366,7 +368,11 @@ MPD::SongList Browser::getSelectedSongs()
result.push_back(*item.song); result.push_back(*item.song);
else if (item.type == itPlaylist) else if (item.type == itPlaylist)
{ {
Mpd.GetPlaylistContent(item.name, vectorMoveInserter(result)); std::copy(
std::make_move_iterator(Mpd.GetPlaylistContent(item.name)),
std::make_move_iterator(MPD::SongIterator()),
std::back_inserter(result)
);
} }
}; };
for (auto it = w.begin(); it != w.end(); ++it) for (auto it = w.begin(); it != w.end(); ++it)

View File

@@ -350,14 +350,15 @@ void MediaLibrary::update()
Mpd.StartSearch(true); Mpd.StartSearch(true);
Mpd.AddSearch(Config.media_lib_primary_tag, primary_tag); Mpd.AddSearch(Config.media_lib_primary_tag, primary_tag);
std::map<std::tuple<std::string, std::string>, time_t> albums; std::map<std::tuple<std::string, std::string>, time_t> albums;
Mpd.CommitSearchSongs([&albums](MPD::Song s) { for (MPD::SongIterator s = Mpd.CommitSearchSongs(), end; s != end; ++s)
auto key = std::make_tuple(s.getAlbum(), s.getDate()); {
auto key = std::make_tuple(s->getAlbum(), s->getDate());
auto it = albums.find(key); auto it = albums.find(key);
if (it == albums.end()) if (it == albums.end())
albums[key] = s.getMTime(); albums[key] = s->getMTime();
else else
it->second = s.getMTime(); it->second = s->getMTime();
}); };
withUnfilteredMenuReapplyFilter(Albums, [this, &albums, &primary_tag]() { withUnfilteredMenuReapplyFilter(Albums, [this, &albums, &primary_tag]() {
size_t idx = 0; size_t idx = 0;
for (auto it = albums.begin(); it != albums.end(); ++it, ++idx) for (auto it = albums.begin(); it != albums.end(); ++it, ++idx)
@@ -404,17 +405,17 @@ void MediaLibrary::update()
} }
withUnfilteredMenuReapplyFilter(Songs, [this, &album]() { withUnfilteredMenuReapplyFilter(Songs, [this, &album]() {
size_t idx = 0; size_t idx = 0;
Mpd.CommitSearchSongs([this, &idx](MPD::Song s) { for (MPD::SongIterator s = Mpd.CommitSearchSongs(), end; s != end; ++s, ++idx)
bool is_playlist = myPlaylist->checkForSong(s); {
bool is_playlist = myPlaylist->checkForSong(*s);
if (idx < Songs.size()) if (idx < Songs.size())
{ {
Songs[idx].value() = s; Songs[idx].value() = std::move(*s);
Songs[idx].setBold(is_playlist); Songs[idx].setBold(is_playlist);
} }
else else
Songs.addItem(s, is_playlist); Songs.addItem(std::move(*s), is_playlist);
++idx; };
});
if (idx < Songs.size()) if (idx < Songs.size())
Songs.resizeList(idx); Songs.resizeList(idx);
std::sort(Songs.begin(), Songs.end(), SortSongs(!album.isAllTracksEntry())); std::sort(Songs.begin(), Songs.end(), SortSongs(!album.isAllTracksEntry()));
@@ -738,7 +739,11 @@ MPD::SongList MediaLibrary::getSelectedSongs()
auto tag_handler = [&result](const std::string &tag) { auto tag_handler = [&result](const std::string &tag) {
Mpd.StartSearch(true); Mpd.StartSearch(true);
Mpd.AddSearch(Config.media_lib_primary_tag, tag); Mpd.AddSearch(Config.media_lib_primary_tag, tag);
Mpd.CommitSearchSongs(vectorMoveInserter(result)); std::copy(
std::make_move_iterator(Mpd.CommitSearchSongs()),
std::make_move_iterator(MPD::SongIterator()),
std::back_inserter(result)
);
}; };
bool any_selected = false; bool any_selected = false;
for (auto &e : Tags) for (auto &e : Tags)
@@ -771,7 +776,11 @@ MPD::SongList MediaLibrary::getSelectedSongs()
Mpd.AddSearch(MPD_TAG_ALBUM, sc.entry().album()); Mpd.AddSearch(MPD_TAG_ALBUM, sc.entry().album());
Mpd.AddSearch(MPD_TAG_DATE, sc.entry().date()); Mpd.AddSearch(MPD_TAG_DATE, sc.entry().date());
size_t begin = result.size(); size_t begin = result.size();
Mpd.CommitSearchSongs(vectorMoveInserter(result)); std::copy(
std::make_move_iterator(Mpd.CommitSearchSongs()),
std::make_move_iterator(MPD::SongIterator()),
std::back_inserter(result)
);
std::sort(result.begin()+begin, result.end(), SortSongs(false)); std::sort(result.begin()+begin, result.end(), SortSongs(false));
} }
} }
@@ -1046,10 +1055,12 @@ void MediaLibrary::AddToPlaylist(bool add_n_play)
if ((!Tags.empty() && isActiveWindow(Tags)) if ((!Tags.empty() && isActiveWindow(Tags))
|| (isActiveWindow(Albums) && Albums.current().value().isAllTracksEntry())) || (isActiveWindow(Albums) && Albums.current().value().isAllTracksEntry()))
{ {
MPD::SongList list;
Mpd.StartSearch(true); Mpd.StartSearch(true);
Mpd.AddSearch(Config.media_lib_primary_tag, Tags.current().value().tag()); Mpd.AddSearch(Config.media_lib_primary_tag, Tags.current().value().tag());
Mpd.CommitSearchSongs(vectorMoveInserter(list)); MPD::SongList list(
std::make_move_iterator(Mpd.CommitSearchSongs()),
std::make_move_iterator(MPD::SongIterator())
);
bool success = addSongsToPlaylist(list.begin(), list.end(), add_n_play, -1); bool success = addSongsToPlaylist(list.begin(), list.end(), add_n_play, -1);
std::string tag_type = boost::locale::to_lower( std::string tag_type = boost::locale::to_lower(
tagTypeToString(Config.media_lib_primary_tag)); tagTypeToString(Config.media_lib_primary_tag));

View File

@@ -33,37 +33,43 @@ namespace MPD {
SongIterator::~SongIterator() SongIterator::~SongIterator()
{ {
// if iterator wasn't fully traversed, clean up if (m_connection)
if (m_connection.get() != nullptr) finish();
mpd_response_finish(m_connection.get());
} }
Song &SongIterator::operator*() void SongIterator::finish()
{ {
assert(m_connection.get() != nullptr); // clean up
assert(!m_song.empty()); assert(m_connection);
return m_song; mpd_response_finish(m_connection.get());
m_song = Song();
m_connection = nullptr;
} }
Song *SongIterator::operator->() Song &SongIterator::operator*() const
{ {
assert(m_connection.get() != nullptr); assert(m_connection);
assert(!m_song.empty()); assert(!m_song.empty());
return &m_song; // we could make m_song a pointer to a Song and dereference here,
// but it's retarded as Song itself is essentially wrapper to
// std::shared_ptr. on the other hand, we need constness for the
// iterator to be able to play along with std::move_iterator.
return const_cast<Song &>(m_song);
}
Song *SongIterator::operator->() const
{
return &**this;
} }
SongIterator &SongIterator::operator++() SongIterator &SongIterator::operator++()
{ {
assert(m_connection.get() != nullptr); assert(m_connection);
mpd_song *s = mpd_recv_song(m_connection.get()); mpd_song *s = mpd_recv_song(m_connection.get());
if (s != nullptr) if (s != nullptr)
m_song = Song(s); m_song = Song(s);
else else
{ finish();
mpd_response_finish(m_connection.get());
m_song = Song();
m_connection = nullptr;
}
return *this; return *this;
} }
@@ -74,6 +80,13 @@ SongIterator SongIterator::operator++(int)
return it; return it;
} }
SongIterator::SongIterator(std::shared_ptr<mpd_connection> conn)
: m_connection(std::move(conn))
{
// get the first element
++*this;
}
Connection::Connection() : m_connection(nullptr), Connection::Connection() : m_connection(nullptr),
m_command_list_active(false), m_command_list_active(false),
m_idle(false), m_idle(false),
@@ -336,14 +349,12 @@ void Connection::Rename(const std::string &from, const std::string &to)
checkErrors(); checkErrors();
} }
void Connection::GetPlaylistChanges(unsigned version, SongConsumer f) SongIterator Connection::GetPlaylistChanges(unsigned version)
{ {
prechecksNoCommandsList(); prechecksNoCommandsList();
mpd_send_queue_changes_meta(m_connection.get(), version); mpd_send_queue_changes_meta(m_connection.get(), version);
while (mpd_song *s = mpd_recv_song(m_connection.get()))
f(Song(s));
mpd_response_finish(m_connection.get());
checkErrors(); checkErrors();
return SongIterator(m_connection);
} }
Song Connection::GetCurrentSong() Song Connection::GetCurrentSong()
@@ -366,24 +377,22 @@ Song Connection::GetSong(const std::string &path)
return Song(s); return Song(s);
} }
void Connection::GetPlaylistContent(const std::string &path, SongConsumer f) SongIterator Connection::GetPlaylistContent(const std::string &path)
{ {
prechecksNoCommandsList(); prechecksNoCommandsList();
mpd_send_list_playlist_meta(m_connection.get(), path.c_str()); mpd_send_list_playlist_meta(m_connection.get(), path.c_str());
while (mpd_song *s = mpd_recv_song(m_connection.get())) SongIterator result(m_connection);
f(Song(s));
mpd_response_finish(m_connection.get());
checkErrors(); checkErrors();
return result;
} }
void Connection::GetPlaylistContentNoInfo(const std::string &path, SongConsumer f) SongIterator Connection::GetPlaylistContentNoInfo(const std::string &path)
{ {
prechecksNoCommandsList(); prechecksNoCommandsList();
mpd_send_list_playlist(m_connection.get(), path.c_str()); mpd_send_list_playlist(m_connection.get(), path.c_str());
while (mpd_song *s = mpd_recv_song(m_connection.get())) SongIterator result(m_connection);
f(Song(s));
mpd_response_finish(m_connection.get());
checkErrors(); checkErrors();
return result;
} }
void Connection::GetSupportedExtensions(std::set<std::string> &acc) void Connection::GetSupportedExtensions(std::set<std::string> &acc)
@@ -546,15 +555,15 @@ bool Connection::AddRandomTag(mpd_tag_type tag, size_t number)
auto it = tags.begin()+rand()%(tags.size()-number); auto it = tags.begin()+rand()%(tags.size()-number);
for (size_t i = 0; i < number && it != tags.end(); ++i) for (size_t i = 0; i < number && it != tags.end(); ++i)
{ {
StartSearch(1); StartSearch(true);
AddSearch(tag, *it++); AddSearch(tag, *it++);
SongList songs; std::vector<std::string> paths;
CommitSearchSongs([&songs](MPD::Song s) { MPD::SongIterator s = CommitSearchSongs(), end;
songs.push_back(s); for (; s != end; ++s)
}); paths.push_back(s->getURI());
StartCommandsList(); StartCommandsList();
for (auto s = songs.begin(); s != songs.end(); ++s) for (const auto &path : paths)
AddSong(*s); AddSong(path);
CommitCommandsList(); CommitCommandsList();
} }
} }
@@ -706,14 +715,12 @@ void Connection::AddSearchURI(const std::string &str) const
mpd_search_add_uri_constraint(m_connection.get(), MPD_OPERATOR_DEFAULT, str.c_str()); mpd_search_add_uri_constraint(m_connection.get(), MPD_OPERATOR_DEFAULT, str.c_str());
} }
void Connection::CommitSearchSongs(SongConsumer f) SongIterator Connection::CommitSearchSongs()
{ {
prechecksNoCommandsList(); prechecksNoCommandsList();
mpd_search_commit(m_connection.get()); mpd_search_commit(m_connection.get());
while (mpd_song *s = mpd_recv_song(m_connection.get()))
f(Song(s));
mpd_response_finish(m_connection.get());
checkErrors(); checkErrors();
return SongIterator(m_connection);
} }
void Connection::CommitSearchTags(StringConsumer f) void Connection::CommitSearchTags(StringConsumer f)
@@ -786,14 +793,12 @@ void Connection::GetDirectories(const std::string &directory, StringConsumer f)
checkErrors(); checkErrors();
} }
void Connection::GetSongs(const std::string &directory, SongConsumer f) SongIterator Connection::GetSongs(const std::string &directory)
{ {
prechecksNoCommandsList(); prechecksNoCommandsList();
mpd_send_list_meta(m_connection.get(), directory.c_str()); mpd_send_list_meta(m_connection.get(), directory.c_str());
while (mpd_song *s = mpd_recv_song(m_connection.get()))
f(Song(s));
mpd_response_finish(m_connection.get());
checkErrors(); checkErrors();
return SongIterator(m_connection);
} }
void Connection::GetOutputs(OutputConsumer f) void Connection::GetOutputs(OutputConsumer f)

View File

@@ -152,8 +152,10 @@ struct SongIterator : std::iterator<std::forward_iterator_tag, Song>
SongIterator() : m_connection(nullptr) { } SongIterator() : m_connection(nullptr) { }
~SongIterator(); ~SongIterator();
Song &operator*(); void finish();
Song *operator->();
Song &operator*() const;
Song *operator->() const;
SongIterator &operator++(); SongIterator &operator++();
SongIterator operator++(int); SongIterator operator++(int);
@@ -167,7 +169,7 @@ struct SongIterator : std::iterator<std::forward_iterator_tag, Song>
} }
private: private:
SongIterator(std::shared_ptr<mpd_connection> conn) : m_connection(std::move(conn)) { } SongIterator(std::shared_ptr<mpd_connection> conn);
std::shared_ptr<mpd_connection> m_connection; std::shared_ptr<mpd_connection> m_connection;
Song m_song; Song m_song;
@@ -175,8 +177,6 @@ private:
class Connection : private boost::noncopyable class Connection : private boost::noncopyable
{ {
typedef void (*ErrorHandler) (Connection *, int, const char *, void *);
typedef std::function<void(Item)> ItemConsumer; typedef std::function<void(Item)> ItemConsumer;
typedef std::function<void(Output)> OutputConsumer; typedef std::function<void(Output)> OutputConsumer;
typedef std::function<void(Song)> SongConsumer; typedef std::function<void(Song)> SongConsumer;
@@ -221,12 +221,12 @@ public:
void Shuffle(); void Shuffle();
void ClearMainPlaylist(); void ClearMainPlaylist();
void GetPlaylistChanges(unsigned, SongConsumer f); SongIterator GetPlaylistChanges(unsigned);
Song GetCurrentSong(); Song GetCurrentSong();
Song GetSong(const std::string &); Song GetSong(const std::string &);
void GetPlaylistContent(const std::string &name, SongConsumer f); SongIterator GetPlaylistContent(const std::string &name);
void GetPlaylistContentNoInfo(const std::string &name, SongConsumer f); SongIterator GetPlaylistContentNoInfo(const std::string &name);
void GetSupportedExtensions(std::set<std::string> &); void GetSupportedExtensions(std::set<std::string> &);
@@ -266,14 +266,14 @@ public:
void AddSearch(mpd_tag_type item, const std::string &str) const; void AddSearch(mpd_tag_type item, const std::string &str) const;
void AddSearchAny(const std::string &str) const; void AddSearchAny(const std::string &str) const;
void AddSearchURI(const std::string &str) const; void AddSearchURI(const std::string &str) const;
void CommitSearchSongs(SongConsumer f); SongIterator CommitSearchSongs();
void CommitSearchTags(StringConsumer f); void CommitSearchTags(StringConsumer f);
void GetPlaylists(StringConsumer f); void GetPlaylists(StringConsumer f);
void GetList(mpd_tag_type type, StringConsumer f); void GetList(mpd_tag_type type, StringConsumer f);
void GetDirectory(const std::string &directory, ItemConsumer f); void GetDirectory(const std::string &directory, ItemConsumer f);
void GetDirectoryRecursive(const std::string &directory, SongConsumer f); void GetDirectoryRecursive(const std::string &directory, SongConsumer f);
void GetSongs(const std::string &directory, SongConsumer f); SongIterator GetSongs(const std::string &directory);
void GetDirectories(const std::string &directory, StringConsumer f); void GetDirectories(const std::string &directory, StringConsumer f);
void GetOutputs(OutputConsumer f); void GetOutputs(OutputConsumer f);

View File

@@ -167,16 +167,18 @@ void PlaylistEditor::update()
Content.clearSearchResults(); Content.clearSearchResults();
withUnfilteredMenuReapplyFilter(Content, [this]() { withUnfilteredMenuReapplyFilter(Content, [this]() {
size_t idx = 0; size_t idx = 0;
Mpd.GetPlaylistContent(Playlists.current().value(), [this, &idx](MPD::Song s) { MPD::SongIterator s = Mpd.GetPlaylistContent(Playlists.current().value()), end;
for (; s != end; ++s, ++idx)
{
bool is_bold = myPlaylist->checkForSong(*s);
if (idx < Content.size()) if (idx < Content.size())
{ {
Content[idx].value() = s; Content[idx].setBold(is_bold);
Content[idx].setBold(myPlaylist->checkForSong(s)); Content[idx].value() = std::move(*s);
} }
else else
Content.addItem(s, myPlaylist->checkForSong(s)); Content.addItem(std::move(*s), is_bold);
++idx; }
});
if (idx < Content.size()) if (idx < Content.size())
Content.resizeList(idx); Content.resizeList(idx);
std::string title; std::string title;
@@ -484,14 +486,18 @@ MPD::SongList PlaylistEditor::getSelectedSongs()
if (e.isSelected()) if (e.isSelected())
{ {
any_selected = true; any_selected = true;
Mpd.GetPlaylistContent(e.value(), vectorMoveInserter(result)); std::copy(
std::make_move_iterator(Mpd.GetPlaylistContent(e.value())),
std::make_move_iterator(MPD::SongIterator()),
std::back_inserter(result)
);
} }
} }
// if no item is selected, add songs from right column // if no item is selected, add songs from right column
if (!any_selected && !Content.empty()) if (!any_selected && !Content.empty())
{ {
withUnfilteredMenu(Content, [this, &result]() { withUnfilteredMenu(Content, [this, &result]() {
result.insert(result.end(), Content.beginV(), Content.endV()); std::copy(Content.beginV(), Content.endV(), std::back_inserter(result));
}); });
} }
} }

View File

@@ -439,9 +439,8 @@ void SearchEngine::Search()
Mpd.AddSearch(MPD_TAG_DATE, itsConstraints[9]); Mpd.AddSearch(MPD_TAG_DATE, itsConstraints[9]);
if (!itsConstraints[10].empty()) if (!itsConstraints[10].empty())
Mpd.AddSearch(MPD_TAG_COMMENT, itsConstraints[10]); Mpd.AddSearch(MPD_TAG_COMMENT, itsConstraints[10]);
Mpd.CommitSearchSongs([this](MPD::Song s) { for (MPD::SongIterator s = Mpd.CommitSearchSongs(), end; s != end; ++s)
w.addItem(s); w.addItem(std::move(*s));
});
return; return;
} }

View File

@@ -43,6 +43,14 @@ struct Song
virtual ~Song() { } virtual ~Song() { }
Song(mpd_song *s); Song(mpd_song *s);
Song(const Song &rhs) : m_song(rhs.m_song), m_hash(rhs.m_hash) { }
Song(Song &&rhs) : m_song(std::move(rhs.m_song)), m_hash(rhs.m_hash) { }
Song &operator=(Song rhs) {
m_song = std::move(rhs.m_song);
m_hash = rhs.m_hash;
return *this;
}
std::string get(mpd_tag_type type, unsigned idx = 0) const; std::string get(mpd_tag_type type, unsigned idx = 0) const;

View File

@@ -398,19 +398,21 @@ void Status::Changes::playlist(unsigned previous_version)
myPlaylist->main().resizeList(m_playlist_length); myPlaylist->main().resizeList(m_playlist_length);
} }
Mpd.GetPlaylistChanges(previous_version, [](MPD::Song s) { MPD::SongIterator s = Mpd.GetPlaylistChanges(previous_version), end;
size_t pos = s.getPosition(); for (; s != end; ++s)
{
size_t pos = s->getPosition();
myPlaylist->registerSong(*s);
if (pos < myPlaylist->main().size()) if (pos < myPlaylist->main().size())
{ {
// if song's already in playlist, replace it with a new one // if song's already in playlist, replace it with a new one
MPD::Song &old_s = myPlaylist->main()[pos].value(); MPD::Song &old_s = myPlaylist->main()[pos].value();
myPlaylist->unregisterSong(old_s); myPlaylist->unregisterSong(old_s);
old_s = s; old_s = std::move(*s);
} }
else // otherwise just add it to playlist else // otherwise just add it to playlist
myPlaylist->main().addItem(s); myPlaylist->main().addItem(std::move(*s));
myPlaylist->registerSong(s); }
});
}); });
myPlaylist->reloadTotalLength(); myPlaylist->reloadTotalLength();

View File

@@ -252,9 +252,9 @@ void TagEditor::update()
if (Tags->reallyEmpty()) if (Tags->reallyEmpty())
{ {
Tags->reset(); Tags->reset();
Mpd.GetSongs(Dirs->current().value().second, [this](MPD::Song s) { MPD::SongIterator s = Mpd.GetSongs(Dirs->current().value().second), end;
Tags->addItem(s); for (; s != end; ++s)
}); Tags->addItem(std::move(*s));
std::sort(Tags->beginV(), Tags->endV(), std::sort(Tags->beginV(), Tags->endV(),
LocaleBasedSorting(std::locale(), Config.ignore_leading_the)); LocaleBasedSorting(std::locale(), Config.ignore_leading_the));
Tags->refresh(); Tags->refresh();