Exemple #1
0
std::string FindSharedDir(Menu<MPD::Song> *menu)
{
	MPD::SongList list;
	for (size_t i = 0; i < menu->Size(); ++i)
		list.push_back(&(*menu)[i]);
	return FindSharedDir(list);
}
void PlaylistEditor::Update()
{
	if (Playlists->ReallyEmpty())
	{
		Content->Clear();
		MPD::TagList list;
		Mpd.GetPlaylists(list);
		sort(list.begin(), list.end(), CaseInsensitiveSorting());
		for (MPD::TagList::iterator it = list.begin(); it != list.end(); ++it)
		{
			utf_to_locale(*it);
			Playlists->AddOption(*it);
		}
		Playlists->Window::Clear();
		Playlists->Refresh();
	}
	
	if (!Playlists->Empty() && Content->ReallyEmpty())
	{
		Content->Reset();
		MPD::SongList list;
		Mpd.GetPlaylistContent(locale_to_utf_cpy(Playlists->Current()), list);
		if (!list.empty())
			Content->SetTitle(Config.titles_visibility ? "Playlist's content (" + IntoStr(list.size()) + " item" + (list.size() == 1 ? ")" : "s)") : "");
		else
			Content->SetTitle(Config.titles_visibility ? "Playlist's content" : "");
		bool bold = 0;
		for (MPD::SongList::const_iterator it = list.begin(); it != list.end(); ++it)
		{
			for (size_t j = 0; j < myPlaylist->Items->Size(); ++j)
			{
				if ((*it)->GetHash() == myPlaylist->Items->at(j).GetHash())
				{
					bold = 1;
					break;
				}
			}
			Content->AddOption(**it, bold);
			bold = 0;
		}
		MPD::FreeSongList(list);
		Content->Window::Clear();
		Content->Display();
	}
	
	if (w == Content && Content->ReallyEmpty())
	{
		Content->HighlightColor(Config.main_highlight_color);
		Playlists->HighlightColor(Config.active_column_color);
		w = Playlists;
	}
	
	if (Content->ReallyEmpty())
	{
		*Content << XY(0, 0) << "Playlist is empty.";
		Content->Window::Refresh();
	}
}
void Browser::spacePressed()
{
	if (w.empty())
		return;
	
	size_t i = itsBrowsedDir != "/" ? 1 : 0;
	if (Config.space_selects && w.choice() >= i)
	{
		i = w.choice();
		w.at(i).setSelected(!w.at(i).isSelected());
		w.scroll(NC::wDown);
		return;
	}
	
	const MPD::Item &item = w.current().value();
	
	if (isParentDirectory(item))
		return;
	
	switch (item.type)
	{
		case itDirectory:
		{
			bool result;
#			ifndef WIN32
			if (isLocal())
			{
				MPD::SongList list;
				MPD::ItemList items;
				Statusbar::msg("Scanning directory \"%s\"...", item.name.c_str());
				myBrowser->GetLocalDirectory(items, item.name, 1);
				list.reserve(items.size());
				for (MPD::ItemList::const_iterator it = items.begin(); it != items.end(); ++it)
					list.push_back(*it->song);
				result = addSongsToPlaylist(list, false, -1);
			}
			else
#			endif // !WIN32
				result = Mpd.Add(item.name);
			if (result)
				Statusbar::msg("Directory \"%s\" added", item.name.c_str());
			break;
		}
		case itSong:
		{
			addSongToPlaylist(*item.song, false);
			break;
		}
		case itPlaylist:
		{
			if (Mpd.LoadPlaylist(item.name))
				Statusbar::msg("Playlist \"%s\" loaded", item.name.c_str());
			break;
		}
	}
	w.scroll(NC::wDown);
}
bool addSongsToPlaylist(const MPD::SongList &list, bool play, size_t position)
{
	if (list.empty())
		return false;
	position = std::min(position, Mpd.GetPlaylistLength());
	Mpd.StartCommandsList();
	for (auto s = list.rbegin(); s != list.rend(); ++s)
		if (Mpd.AddSong(*s, position) < 0)
			break;
	if (play)
		Mpd.Play(position);
	return Mpd.CommitCommandsList();
}
Exemple #5
0
std::string FindSharedDir(const MPD::SongList &v)
{
	if (v.empty()) // this should never happen, but in case...
		FatalError("empty SongList passed to FindSharedDir(const SongList &)!");
	size_t i = -1;
	std::string first = v.front()->GetDirectory();
	for (MPD::SongList::const_iterator it = ++v.begin(); it != v.end(); ++it)
	{
		size_t j = 0;
		std::string dir = (*it)->GetDirectory();
		size_t length = std::min(first.length(), dir.length());
		while (!first.compare(j, 1, dir, j, 1) && j < length && j < i)
			++j;
		i = j;
	}
	return i ? first.substr(0, i) : "/";
}
MPD::SongList SearchEngine::getSelectedSongs()
{
	MPD::SongList result;
	for (auto it = w.begin(); it != w.end(); ++it)
	{
		if (it->isSelected())
		{
			assert(it->value().isSong());
			result.push_back(it->value().song());
		}
	}
	// if no item is selected, add current one
	if (result.empty() && !w.empty())
	{
		assert(w.current().value().isSong());
		result.push_back(w.current().value().song());
	}
	return result;
}
void PlaylistEditor::GetSelectedSongs(MPD::SongList &v)
{
	std::vector<size_t> selected;
	Content->GetSelected(selected);
	if (selected.empty())
		selected.push_back(Content->Choice());
	for (std::vector<size_t>::const_iterator it = selected.begin(); it != selected.end(); ++it)
	{
		v.push_back(new MPD::Song(Content->at(*it)));
	}
}
Exemple #8
0
void SearchEngine::GetSelectedSongs(MPD::SongList &v)
{
	if (w->Empty())
		return;
	std::vector<size_t> selected;
	w->GetSelected(selected);
	if (selected.empty() && w->Choice() >= StaticOptions)
		selected.push_back(w->Choice());
	for (std::vector<size_t>::const_iterator it = selected.begin(); it != selected.end(); ++it)
		v.push_back(new MPD::Song(*w->at(*it).second));
}
Exemple #9
0
void MediaLibrary::AddToPlaylist(bool add_n_play)
{
	if (isActiveWindow(Songs) && !Songs.empty())
		addSongToPlaylist(Songs.current().value(), add_n_play);
	else
	{
		if ((!Tags.empty() && isActiveWindow(Tags))
		||  (isActiveWindow(Albums) && Albums.current().value().isAllTracksEntry()))
		{
			MPD::SongList list;
			Mpd.StartSearch(true);
			Mpd.AddSearch(Config.media_lib_primary_tag, Tags.current().value().tag());
			Mpd.CommitSearchSongs(vectorMoveInserter(list));
			addSongsToPlaylist(list.begin(), list.end(), add_n_play, -1);
			std::string tag_type = boost::locale::to_lower(
				tagTypeToString(Config.media_lib_primary_tag));
			Statusbar::msg("Songs with %s = \"%s\" added",
				tag_type.c_str(), Tags.current().value().tag().c_str());
		}
		else if (isActiveWindow(Albums))
		{
			withUnfilteredMenu(Songs, [&]() {
				addSongsToPlaylist(Songs.beginV(), Songs.endV(), add_n_play, -1);
			});
			Statusbar::msg("Songs from album \"%s\" added",
				Albums.current().value().entry().album().c_str());
		}
	}
	
	if (!add_n_play)
	{
		w->scroll(NC::Scroll::Down);
		if (isActiveWindow(Tags))
		{
			Albums.clear();
			Songs.clear();
		}
		else if (isActiveWindow(Albums))
			Songs.clear();
	}
}
void SortPlaylistDialog::sort() const
{
	auto &pl = myPlaylist->main();
	auto begin = pl.begin(), end = pl.end();
	std::tie(begin, end) = getSelectedRange(begin, end);
	
	size_t start_pos = begin - pl.begin();
	MPD::SongList playlist;
	playlist.reserve(end - begin);
	for (; begin != end; ++begin)
		playlist.push_back(begin->value());
	
	typedef MPD::SongList::iterator Iterator;
	LocaleStringComparison cmp(std::locale(), Config.ignore_leading_the);
	std::function<void(Iterator, Iterator)> iter_swap, quick_sort;
	auto song_cmp = [this, &cmp](const MPD::Song &a, const MPD::Song &b) -> bool {
		for (auto it = w.beginV();  it->item().second; ++it)
		{
			int res = cmp(a.getTags(it->item().second, Config.tags_separator),
			              b.getTags(it->item().second, Config.tags_separator));
			if (res != 0)
				return res < 0;
		}
		return a.getPosition() < b.getPosition();
	};
	iter_swap = [&playlist, &start_pos](Iterator a, Iterator b) {
		std::iter_swap(a, b);
		Mpd.Swap(start_pos+a-playlist.begin(), start_pos+b-playlist.begin());
	};
	quick_sort = [this, &song_cmp, &quick_sort, &iter_swap](Iterator first, Iterator last) {
		if (last-first > 1)
		{
			Iterator pivot = first+rand()%(last-first);
			iter_swap(pivot, last-1);
			pivot = last-1;
			
			Iterator tmp = first;
			for (Iterator i = first; i != pivot; ++i)
				if (song_cmp(*i, *pivot))
					iter_swap(i, tmp++);
			iter_swap(tmp, pivot);
			
			quick_sort(first, tmp);
			quick_sort(tmp+1, last);
		}
	};
	
	Statusbar::msg("Sorting...");
	Mpd.StartCommandsList();
	quick_sort(playlist.begin(), playlist.end());
	if (Mpd.CommitCommandsList())
	{
		Statusbar::msg("Playlist sorted");	
		switchToPreviousScreen();
	}
}
Exemple #11
0
void Browser::GetSelectedSongs(MPD::SongList &v)
{
	if (w->Empty())
		return;
	std::vector<size_t> selected;
	w->GetSelected(selected);
	if (selected.empty())
		selected.push_back(w->Choice());
	for (std::vector<size_t>::const_iterator it = selected.begin(); it != selected.end(); ++it)
	{
		const MPD::Item &item = w->at(*it);
		switch (item.type)
		{
			case itDirectory:
			{
#				ifndef WIN32
				if (isLocal())
				{
					MPD::ItemList list;
					GetLocalDirectory(list, item.name, 1);
					for (MPD::ItemList::const_iterator j = list.begin(); j != list.end(); ++j)
						v.push_back(j->song);
				}
				else
#				endif // !WIN32
					Mpd.GetDirectoryRecursive(locale_to_utf_cpy(item.name), v);
				break;
			}
			case itSong:
			{
				v.push_back(new MPD::Song(*item.song));
				break;
			}
			case itPlaylist:
			{
				Mpd.GetPlaylistContent(locale_to_utf_cpy(item.name), v);
				break;
			}
		}
	}
}
MPD::SongList Browser::getSelectedSongs()
{
	MPD::SongList result;
	auto item_handler = [this, &result](const MPD::Item &item) {
		if (item.type == itDirectory)
		{
#			ifndef WIN32
			if (isLocal())
			{
				MPD::ItemList list;
				GetLocalDirectory(list, item.name, true);
				for (auto it = list.begin(); it != list.end(); ++it)
					result.push_back(*it->song);
			}
			else
#			endif // !WIN32
			{
				auto list = Mpd.GetDirectoryRecursive(item.name);
				result.insert(result.end(), list.begin(), list.end());
			}
		}
		else if (item.type == itSong)
			result.push_back(*item.song);
		else if (item.type == itPlaylist)
		{
			auto list = Mpd.GetPlaylistContent(item.name);
			result.insert(result.end(), list.begin(), list.end());
		}
	};
	for (auto it = w.begin(); it != w.end(); ++it)
		if (it->isSelected())
			item_handler(it->value());
	// if no item is selected, add current one
	if (result.empty() && !w.empty())
		item_handler(w.current().value());
	return result;
}
Exemple #13
0
MPD::SongList MediaLibrary::getSelectedSongs()
{
	MPD::SongList result;
	if (isActiveWindow(Tags))
	{
		auto tag_handler = [&result](const std::string &tag) {
			Mpd.StartSearch(true);
			Mpd.AddSearch(Config.media_lib_primary_tag, tag);
			Mpd.CommitSearchSongs(vectorMoveInserter(result));
		};
		bool any_selected = false;
		for (auto &e : Tags)
		{
			if (e.isSelected())
			{
				any_selected = true;
				tag_handler(e.value().tag());
			}
		}
		// if no item is selected, add current one
		if (!any_selected && !Tags.empty())
			tag_handler(Tags.current().value().tag());
	}
	else if (isActiveWindow(Albums))
	{
		bool any_selected = false;
		for (auto it = Albums.begin(); it != Albums.end() && !it->isSeparator(); ++it)
		{
			if (it->isSelected())
			{
				any_selected = true;
				auto &sc = it->value();
				Mpd.StartSearch(true);
				if (hasTwoColumns)
					Mpd.AddSearch(Config.media_lib_primary_tag, sc.entry().tag());
				else
					Mpd.AddSearch(Config.media_lib_primary_tag,
					              Tags.current().value().tag());
					Mpd.AddSearch(MPD_TAG_ALBUM, sc.entry().album());
				Mpd.AddSearch(MPD_TAG_DATE, sc.entry().date());
				size_t begin = result.size();
				Mpd.CommitSearchSongs(vectorMoveInserter(result));
				std::sort(result.begin()+begin, result.end(), SortSongs(false));
			}
		}
		// if no item is selected, add songs from right column
		if (!any_selected && !Albums.empty())
		{
			withUnfilteredMenu(Songs, [this, &result]() {
				result.insert(result.end(), Songs.beginV(), Songs.endV());
			});
		}
	}
	else if (isActiveWindow(Songs))
	{
		for (auto it = Songs.begin(); it != Songs.end(); ++it)
			if (it->isSelected())
				result.push_back(it->value());
		// if no item is selected, add current one
		if (result.empty() && !Songs.empty())
			result.push_back(Songs.current().value());
	}
	return result;
}
Exemple #14
0
void Browser::SpacePressed()
{
	if (w->Empty())
		return;
	
	if (Config.space_selects && w->Choice() >= (itsBrowsedDir != "/" ? 1 : 0))
	{
		w->Select(w->Choice(), !w->isSelected());
		w->Scroll(wDown);
		return;
	}
	
	if (itsBrowsedDir != "/" && w->Choice() == 0 /* parent dir */)
		return;
	
	const MPD::Item &item = w->Current();
	switch (item.type)
	{
		case itDirectory:
		{
			if (itsBrowsedDir != "/" && !w->Choice())
				break; // do not let add parent dir.
			
			MPD::SongList list;
#			ifndef WIN32
			if (isLocal())
			{
				MPD::ItemList items;
				ShowMessage(_("Scanning \"%s\"..."), item.name.c_str());
				myBrowser->GetLocalDirectory(items, item.name, 1);
				list.reserve(items.size());
				for (MPD::ItemList::const_iterator it = items.begin(); it != items.end(); ++it)
					list.push_back(it->song);
			}
			else
#			endif // !WIN32
				Mpd.GetDirectoryRecursive(locale_to_utf_cpy(item.name), list);
			
			if (myPlaylist->Add(list, 0))
				ShowMessage(_("Added folder: %s"), item.name.c_str());
			
			FreeSongList(list);
			break;
		}
		case itSong:
		{
			w->Bold(w->Choice(), myPlaylist->Add(*item.song, w->isBold(), 0));
			break;
		}
		case itPlaylist:
		{
			std::string name = item.name;
			ShowMessage(_("Loading playlist %s..."), name.c_str());
			locale_to_utf(name);
			if (!Mpd.LoadPlaylist(name))
				ShowMessage(_("Couldn't load playlist."));
			break;
		}
	}
	w->Scroll(wDown);
}
Exemple #15
0
void SearchEngine::Search()
{
	bool constraints_empty = 1;
	for (size_t i = 0; i < ConstraintsNumber; ++i)
	{
		if (!itsConstraints[i].empty())
		{
			constraints_empty = 0;
			break;
		}
	}
	if (constraints_empty)
		return;
	
	if (Config.search_in_db && (SearchMode == &SearchModes[0] || SearchMode == &SearchModes[2])) // use built-in mpd searching
	{
		Mpd.StartSearch(SearchMode == &SearchModes[2]);
		if (!itsConstraints[0].empty())
			Mpd.AddSearchAny(itsConstraints[0]);
		if (!itsConstraints[1].empty())
			Mpd.AddSearch(MPD_TAG_ARTIST, itsConstraints[1]);
		if (!itsConstraints[2].empty())
			Mpd.AddSearch(MPD_TAG_TITLE, itsConstraints[2]);
		if (!itsConstraints[3].empty())
			Mpd.AddSearch(MPD_TAG_ALBUM, itsConstraints[3]);
		if (!itsConstraints[4].empty())
			Mpd.AddSearchURI(itsConstraints[4]);
		if (!itsConstraints[5].empty())
			Mpd.AddSearch(MPD_TAG_COMPOSER, itsConstraints[5]);
		if (!itsConstraints[6].empty())
			Mpd.AddSearch(MPD_TAG_PERFORMER, itsConstraints[6]);
		if (!itsConstraints[7].empty())
			Mpd.AddSearch(MPD_TAG_GENRE, itsConstraints[7]);
		if (!itsConstraints[8].empty())
			Mpd.AddSearch(MPD_TAG_DATE, itsConstraints[8]);
		if (!itsConstraints[9].empty())
			Mpd.AddSearch(MPD_TAG_COMMENT, itsConstraints[9]);
		MPD::SongList results;
		Mpd.CommitSearch(results);
		for (MPD::SongList::const_iterator it = results.begin(); it != results.end(); ++it)
			w->AddOption(std::make_pair(static_cast<Buffer *>(0), *it));
		return;
	}
	
	MPD::SongList list;
	if (Config.search_in_db)
		Mpd.GetDirectoryRecursive("/", list);
	else
	{
		list.reserve(myPlaylist->Items->Size());
		for (size_t i = 0; i < myPlaylist->Items->Size(); ++i)
			list.push_back(&(*myPlaylist->Items)[i]);
	}
	
	bool any_found = 1;
	bool found = 1;
	
	for (MPD::SongList::const_iterator it = list.begin(); it != list.end(); ++it)
	{
		if (SearchMode != &SearchModes[2]) // match to pattern
		{
			regex_t rx;
			if (!itsConstraints[0].empty())
			{
				if (regcomp(&rx, itsConstraints[0].c_str(), REG_ICASE | Config.regex_type) == 0)
				{
					any_found =
						!regexec(&rx, (*it)->GetArtist().c_str(), 0, 0, 0)
					||	!regexec(&rx, (*it)->GetTitle().c_str(), 0, 0, 0)
					||	!regexec(&rx, (*it)->GetAlbum().c_str(), 0, 0, 0)
					||	!regexec(&rx, (*it)->GetName().c_str(), 0, 0, 0)
					||	!regexec(&rx, (*it)->GetComposer().c_str(), 0, 0, 0)
					||	!regexec(&rx, (*it)->GetPerformer().c_str(), 0, 0, 0)
					||	!regexec(&rx, (*it)->GetGenre().c_str(), 0, 0, 0)
					||	!regexec(&rx, (*it)->GetDate().c_str(), 0, 0, 0)
					||	!regexec(&rx, (*it)->GetComment().c_str(), 0, 0, 0);
				}
				regfree(&rx);
			}
			
			if (found && !itsConstraints[1].empty())
			{
				if (!regcomp(&rx, itsConstraints[1].c_str(), REG_ICASE | Config.regex_type))
					found = !regexec(&rx, (*it)->GetArtist().c_str(), 0, 0, 0);
				regfree(&rx);
			}
			if (found && !itsConstraints[2].empty())
			{
				if (!regcomp(&rx, itsConstraints[2].c_str(), REG_ICASE | Config.regex_type))
					found = !regexec(&rx, (*it)->GetTitle().c_str(), 0, 0, 0);
				regfree(&rx);
			}
			if (found && !itsConstraints[3].empty())
			{
				if (!regcomp(&rx, itsConstraints[3].c_str(), REG_ICASE | Config.regex_type))
					found = !regexec(&rx, (*it)->GetAlbum().c_str(), 0, 0, 0);
				regfree(&rx);
			}
			if (found && !itsConstraints[4].empty())
			{
				if (!regcomp(&rx, itsConstraints[4].c_str(), REG_ICASE | Config.regex_type))
					found = !regexec(&rx, (*it)->GetName().c_str(), 0, 0, 0);
				regfree(&rx);
			}
			if (found && !itsConstraints[5].empty())
			{
				if (!regcomp(&rx, itsConstraints[5].c_str(), REG_ICASE | Config.regex_type))
					found = !regexec(&rx, (*it)->GetComposer().c_str(), 0, 0, 0);
				regfree(&rx);
			}
			if (found && !itsConstraints[6].empty())
			{
				if (!regcomp(&rx, itsConstraints[6].c_str(), REG_ICASE | Config.regex_type))
					found = !regexec(&rx, (*it)->GetPerformer().c_str(), 0, 0, 0);
				regfree(&rx);
			}
			if (found && !itsConstraints[7].empty())
			{
				if (!regcomp(&rx, itsConstraints[7].c_str(), REG_ICASE | Config.regex_type))
					found = !regexec(&rx, (*it)->GetGenre().c_str(), 0, 0, 0);
				regfree(&rx);
			}
			if (found && !itsConstraints[8].empty())
			{
				if (!regcomp(&rx, itsConstraints[8].c_str(), REG_ICASE | Config.regex_type))
					found = !regexec(&rx, (*it)->GetDate().c_str(), 0, 0, 0);
				regfree(&rx);
			}
			if (found && !itsConstraints[9].empty())
			{
				if (!regcomp(&rx, itsConstraints[9].c_str(), REG_ICASE | Config.regex_type))
					found = !regexec(&rx, (*it)->GetComment().c_str(), 0, 0, 0);
				regfree(&rx);
			}
		}
		else // match only if values are equal
		{
			CaseInsensitiveStringComparison cmp;
			
			if (!itsConstraints[0].empty())
				any_found =
					!cmp((*it)->GetArtist(), itsConstraints[0])
				||	!cmp((*it)->GetTitle(), itsConstraints[0])
				||	!cmp((*it)->GetAlbum(), itsConstraints[0])
				||	!cmp((*it)->GetName(), itsConstraints[0])
				||	!cmp((*it)->GetComposer(), itsConstraints[0])
				||	!cmp((*it)->GetPerformer(), itsConstraints[0])
				||	!cmp((*it)->GetGenre(), itsConstraints[0])
				||	!cmp((*it)->GetDate(), itsConstraints[0])
				||	!cmp((*it)->GetComment(), itsConstraints[0]);
			
			if (found && !itsConstraints[1].empty())
				found = !cmp((*it)->GetArtist(), itsConstraints[1]);
			if (found && !itsConstraints[2].empty())
				found = !cmp((*it)->GetTitle(), itsConstraints[2]);
			if (found && !itsConstraints[3].empty())
				found = !cmp((*it)->GetAlbum(), itsConstraints[3]);
			if (found && !itsConstraints[4].empty())
				found = !cmp((*it)->GetName(), itsConstraints[4]);
			if (found && !itsConstraints[5].empty())
				found = !cmp((*it)->GetComposer(), itsConstraints[5]);
			if (found && !itsConstraints[6].empty())
				found = !cmp((*it)->GetPerformer(), itsConstraints[6]);
			if (found && !itsConstraints[7].empty())
				found = !cmp((*it)->GetGenre(), itsConstraints[7]);
			if (found && !itsConstraints[8].empty())
				found = !cmp((*it)->GetDate(), itsConstraints[8]);
			if (found && !itsConstraints[9].empty())
				found = !cmp((*it)->GetComment(), itsConstraints[9]);
		}
		
		if (found && any_found)
		{
			MPD::Song *ss = Config.search_in_db ? *it : new MPD::Song(**it);
			w->AddOption(std::make_pair(static_cast<Buffer *>(0), ss));
			list[it-list.begin()] = 0;
		}
		found = 1;
		any_found = 1;
	}
	if (Config.search_in_db) // free song list only if it's database
		MPD::FreeSongList(list);
}
void SearchEngine::Search()
{
	bool constraints_empty = 1;
	for (size_t i = 0; i < ConstraintsNumber; ++i)
	{
		if (!itsConstraints[i].empty())
		{
			constraints_empty = 0;
			break;
		}
	}
	if (constraints_empty)
		return;
	
	if (Config.search_in_db && (SearchMode == &SearchModes[0] || SearchMode == &SearchModes[2])) // use built-in mpd searching
	{
		Mpd.StartSearch(SearchMode == &SearchModes[2]);
		if (!itsConstraints[0].empty())
			Mpd.AddSearchAny(itsConstraints[0]);
		if (!itsConstraints[1].empty())
			Mpd.AddSearch(MPD_TAG_ARTIST, itsConstraints[1]);
		if (!itsConstraints[2].empty())
			Mpd.AddSearch(MPD_TAG_ALBUM_ARTIST, itsConstraints[2]);
		if (!itsConstraints[3].empty())
			Mpd.AddSearch(MPD_TAG_TITLE, itsConstraints[3]);
		if (!itsConstraints[4].empty())
			Mpd.AddSearch(MPD_TAG_ALBUM, itsConstraints[4]);
		if (!itsConstraints[5].empty())
			Mpd.AddSearchURI(itsConstraints[5]);
		if (!itsConstraints[6].empty())
			Mpd.AddSearch(MPD_TAG_COMPOSER, itsConstraints[6]);
		if (!itsConstraints[7].empty())
			Mpd.AddSearch(MPD_TAG_PERFORMER, itsConstraints[7]);
		if (!itsConstraints[8].empty())
			Mpd.AddSearch(MPD_TAG_GENRE, itsConstraints[8]);
		if (!itsConstraints[9].empty())
			Mpd.AddSearch(MPD_TAG_DATE, itsConstraints[9]);
		if (!itsConstraints[10].empty())
			Mpd.AddSearch(MPD_TAG_COMMENT, itsConstraints[10]);
		auto songs = Mpd.CommitSearchSongs();
		for (auto s = songs.begin(); s != songs.end(); ++s)
			w.addItem(*s);
		return;
	}
	
	MPD::SongList list;
	if (Config.search_in_db)
		list = Mpd.GetDirectoryRecursive("/");
	else
	{
		list.reserve(myPlaylist->main().size());
		for (auto s = myPlaylist->main().beginV(); s != myPlaylist->main().endV(); ++s)
			list.push_back(*s);
	}
	
	bool any_found = 1;
	bool found = 1;
	
	LocaleStringComparison cmp(std::locale(), Config.ignore_leading_the);
	for (auto it = list.begin(); it != list.end(); ++it)
	{
		if (SearchMode != &SearchModes[2]) // match to pattern
		{
			regex_t rx;
			if (!itsConstraints[0].empty())
			{
				if (regcomp(&rx, itsConstraints[0].c_str(), REG_ICASE | Config.regex_type) == 0)
				{
					any_found =
						!regexec(&rx, it->getArtist().c_str(), 0, 0, 0)
					||	!regexec(&rx, it->getAlbumArtist().c_str(), 0, 0, 0)
					||	!regexec(&rx, it->getTitle().c_str(), 0, 0, 0)
					||	!regexec(&rx, it->getAlbum().c_str(), 0, 0, 0)
					||	!regexec(&rx, it->getName().c_str(), 0, 0, 0)
					||	!regexec(&rx, it->getComposer().c_str(), 0, 0, 0)
					||	!regexec(&rx, it->getPerformer().c_str(), 0, 0, 0)
					||	!regexec(&rx, it->getGenre().c_str(), 0, 0, 0)
					||	!regexec(&rx, it->getDate().c_str(), 0, 0, 0)
					||	!regexec(&rx, it->getComment().c_str(), 0, 0, 0);
				}
				regfree(&rx);
			}
			
			if (found && !itsConstraints[1].empty())
			{
				if (!regcomp(&rx, itsConstraints[1].c_str(), REG_ICASE | Config.regex_type))
					found = !regexec(&rx, it->getArtist().c_str(), 0, 0, 0);
				regfree(&rx);
			}
			if (found && !itsConstraints[2].empty())
			{
				if (!regcomp(&rx, itsConstraints[2].c_str(), REG_ICASE | Config.regex_type))
					found = !regexec(&rx, it->getAlbumArtist().c_str(), 0, 0, 0);
				regfree(&rx);
			}
			if (found && !itsConstraints[3].empty())
			{
				if(!regcomp(&rx, itsConstraints[3].c_str(), REG_ICASE | Config.regex_type))
					found = !regexec(&rx, it->getTitle().c_str(), 0, 0, 0);
				regfree(&rx);
			}
			if (found && !itsConstraints[4].empty())
			{
				if (!regcomp(&rx, itsConstraints[4].c_str(), REG_ICASE | Config.regex_type))
					found = !regexec(&rx, it->getAlbum().c_str(), 0, 0, 0);
				regfree(&rx);
			}
			if (found && !itsConstraints[5].empty())
			{
				if (!regcomp(&rx, itsConstraints[5].c_str(), REG_ICASE | Config.regex_type))
					found = !regexec(&rx, it->getName().c_str(), 0, 0, 0);
				regfree(&rx);
			}
			if (found && !itsConstraints[6].empty())
			{
				if (!regcomp(&rx, itsConstraints[6].c_str(), REG_ICASE | Config.regex_type))
					found = !regexec(&rx, it->getComposer().c_str(), 0, 0, 0);
				regfree(&rx);
			}
			if (found && !itsConstraints[7].empty())
			{
				if (!regcomp(&rx, itsConstraints[7].c_str(), REG_ICASE | Config.regex_type))
					found = !regexec(&rx, it->getPerformer().c_str(), 0, 0, 0);
				regfree(&rx);
			}
			if (found && !itsConstraints[8].empty())
			{
				if (!regcomp(&rx, itsConstraints[8].c_str(), REG_ICASE | Config.regex_type))
					found = !regexec(&rx, it->getGenre().c_str(), 0, 0, 0);
				regfree(&rx);
			}
			if (found && !itsConstraints[9].empty())
			{
				if (!regcomp(&rx, itsConstraints[9].c_str(), REG_ICASE | Config.regex_type))
					found = !regexec(&rx, it->getDate().c_str(), 0, 0, 0);
				regfree(&rx);
			}
			if (found && !itsConstraints[10].empty())
			{
				if (!regcomp(&rx, itsConstraints[10].c_str(), REG_ICASE | Config.regex_type))
					found = !regexec(&rx, it->getComment().c_str(), 0, 0, 0);
				regfree(&rx);
			}
		}
		else // match only if values are equal
		{
			if (!itsConstraints[0].empty())
				any_found =
					!cmp(it->getArtist(), itsConstraints[0])
				||	!cmp(it->getAlbumArtist(), itsConstraints[0])
				||	!cmp(it->getTitle(), itsConstraints[0])
				||	!cmp(it->getAlbum(), itsConstraints[0])
				||	!cmp(it->getName(), itsConstraints[0])
				||	!cmp(it->getComposer(), itsConstraints[0])
				||	!cmp(it->getPerformer(), itsConstraints[0])
				||	!cmp(it->getGenre(), itsConstraints[0])
				||	!cmp(it->getDate(), itsConstraints[0])
				||	!cmp(it->getComment(), itsConstraints[0]);
			
			if (found && !itsConstraints[1].empty())
				found = !cmp(it->getArtist(), itsConstraints[1]);
			if (found && !itsConstraints[2].empty())
				found = !cmp(it->getAlbumArtist(), itsConstraints[2]);
			if (found && !itsConstraints[3].empty())
				found = !cmp(it->getTitle(), itsConstraints[3]);
			if (found && !itsConstraints[4].empty())
				found = !cmp(it->getAlbum(), itsConstraints[4]);
			if (found && !itsConstraints[5].empty())
				found = !cmp(it->getName(), itsConstraints[5]);
			if (found && !itsConstraints[6].empty())
				found = !cmp(it->getComposer(), itsConstraints[6]);
			if (found && !itsConstraints[7].empty())
				found = !cmp(it->getPerformer(), itsConstraints[7]);
			if (found && !itsConstraints[8].empty())
				found = !cmp(it->getGenre(), itsConstraints[8]);
			if (found && !itsConstraints[9].empty())
				found = !cmp(it->getDate(), itsConstraints[9]);
			if (found && !itsConstraints[10].empty())
				found = !cmp(it->getComment(), itsConstraints[10]);
		}
		
		if (found && any_found)
			w.addItem(*it);
		found = 1;
		any_found = 1;
	}
}