2 * Copyright (C) 2012-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
21 #include "GUIDialogMediaFilter.h"
23 #include "GUIUserMessages.h"
24 #include "XBDateTime.h"
25 #include "dialogs/GUIDialogSelect.h"
26 #include "guilib/GUIWindowManager.h"
27 #include "guilib/LocalizeStrings.h"
28 #include "music/MusicDatabase.h"
29 #include "playlists/SmartPlayList.h"
30 #include "utils/log.h"
31 #include "utils/MathUtils.h"
32 #include "utils/StringUtils.h"
33 #include "video/VideoDatabase.h"
35 #define TIMEOUT_DELAY 500
38 #define CONTROL_HEADING 2
39 // list of controls from CGUIDialogSettings
40 #define CONTROL_GROUP_LIST 5
41 #define CONTROL_DEFAULT_BUTTON 7
42 #define CONTROL_DEFAULT_RADIOBUTTON 8
43 #define CONTROL_DEFAULT_SPIN 9
44 #define CONTROL_DEFAULT_SLIDER 10
46 #define CONTROL_CLEAR_BUTTON 27
47 #define CONTROL_OKAY_BUTTON 28
48 #define CONTROL_CANCEL_BUTTON 29
49 #define CONTROL_START 30
54 #define CHECK_LABEL_ALL 593
55 #define CHECK_LABEL_NO 106
56 #define CHECK_LABEL_YES 107
60 static const CGUIDialogMediaFilter::Filter filterList[] = {
61 { "movies", FieldTitle, 556, SettingInfo::EDIT, CDatabaseQueryRule::OPERATOR_CONTAINS },
62 { "movies", FieldRating, 563, SettingInfo::RANGE, CDatabaseQueryRule::OPERATOR_BETWEEN },
63 //{ "movies", FieldTime, 180, SettingInfo::TODO, CDatabaseQueryRule::TODO },
64 { "movies", FieldInProgress, 575, SettingInfo::CHECK, CDatabaseQueryRule::OPERATOR_FALSE },
65 { "movies", FieldYear, 562, SettingInfo::RANGE, CDatabaseQueryRule::OPERATOR_BETWEEN },
66 { "movies", FieldTag, 20459, SettingInfo::BUTTON, CDatabaseQueryRule::OPERATOR_EQUALS },
67 { "movies", FieldGenre, 515, SettingInfo::BUTTON, CDatabaseQueryRule::OPERATOR_EQUALS },
68 { "movies", FieldActor, 20337, SettingInfo::BUTTON, CDatabaseQueryRule::OPERATOR_EQUALS },
69 { "movies", FieldDirector, 20339, SettingInfo::BUTTON, CDatabaseQueryRule::OPERATOR_EQUALS },
70 { "movies", FieldStudio, 572, SettingInfo::BUTTON, CDatabaseQueryRule::OPERATOR_EQUALS },
71 //{ "movies", FieldLastPlayed, 568, SettingInfo::TODO, CDatabaseQueryRule::TODO },
72 //{ "movies", FieldDateAdded, 570, SettingInfo::TODO, CDatabaseQueryRule::TODO },
74 { "tvshows", FieldTitle, 556, SettingInfo::EDIT, CDatabaseQueryRule::OPERATOR_CONTAINS },
75 //{ "tvshows", FieldTvShowStatus, 126, SettingInfo::TODO, CDatabaseQueryRule::TODO },
76 { "tvshows", FieldRating, 563, SettingInfo::RANGE, CDatabaseQueryRule::OPERATOR_BETWEEN },
77 { "tvshows", FieldInProgress, 575, SettingInfo::CHECK, CDatabaseQueryRule::OPERATOR_FALSE },
78 { "tvshows", FieldYear, 562, SettingInfo::RANGE, CDatabaseQueryRule::OPERATOR_BETWEEN },
79 { "tvshows", FieldTag, 20459, SettingInfo::BUTTON, CDatabaseQueryRule::OPERATOR_EQUALS },
80 { "tvshows", FieldGenre, 515, SettingInfo::BUTTON, CDatabaseQueryRule::OPERATOR_EQUALS },
81 { "tvshows", FieldActor, 20337, SettingInfo::BUTTON, CDatabaseQueryRule::OPERATOR_EQUALS },
82 { "tvshows", FieldDirector, 20339, SettingInfo::BUTTON, CDatabaseQueryRule::OPERATOR_EQUALS },
83 { "tvshows", FieldStudio, 572, SettingInfo::BUTTON, CDatabaseQueryRule::OPERATOR_EQUALS },
84 //{ "tvshows", FieldDateAdded, 570, SettingInfo::TODO, CDatabaseQueryRule::TODO },
86 { "episodes", FieldTitle, 556, SettingInfo::EDIT, CDatabaseQueryRule::OPERATOR_CONTAINS },
87 { "episodes", FieldRating, 563, SettingInfo::RANGE, CDatabaseQueryRule::OPERATOR_BETWEEN },
88 { "episodes", FieldAirDate, 20416, SettingInfo::RANGE, CDatabaseQueryRule::OPERATOR_BETWEEN },
89 { "episodes", FieldInProgress, 575, SettingInfo::CHECK, CDatabaseQueryRule::OPERATOR_FALSE },
90 { "episodes", FieldActor, 20337, SettingInfo::BUTTON, CDatabaseQueryRule::OPERATOR_EQUALS },
91 { "episodes", FieldDirector, 20339, SettingInfo::BUTTON, CDatabaseQueryRule::OPERATOR_EQUALS },
92 //{ "episodes", FieldLastPlayed, 568, SettingInfo::TODO, CDatabaseQueryRule::TODO },
93 //{ "episodes", FieldDateAdded, 570, SettingInfo::TODO, CDatabaseQueryRule::TODO },
95 { "musicvideos", FieldTitle, 556, SettingInfo::EDIT, CDatabaseQueryRule::OPERATOR_CONTAINS },
96 { "musicvideos", FieldArtist, 557, SettingInfo::BUTTON, CDatabaseQueryRule::OPERATOR_EQUALS },
97 { "musicvideos", FieldAlbum, 558, SettingInfo::BUTTON, CDatabaseQueryRule::OPERATOR_EQUALS },
98 //{ "musicvideos", FieldTime, 180, SettingInfo::TODO, CDatabaseQueryRule::TODO },
99 { "musicvideos", FieldYear, 562, SettingInfo::RANGE, CDatabaseQueryRule::OPERATOR_BETWEEN },
100 { "musicvideos", FieldTag, 20459, SettingInfo::BUTTON, CDatabaseQueryRule::OPERATOR_EQUALS },
101 { "musicvideos", FieldGenre, 515, SettingInfo::BUTTON, CDatabaseQueryRule::OPERATOR_EQUALS },
102 { "musicvideos", FieldDirector, 20339, SettingInfo::BUTTON, CDatabaseQueryRule::OPERATOR_EQUALS },
103 { "musicvideos", FieldStudio, 572, SettingInfo::BUTTON, CDatabaseQueryRule::OPERATOR_EQUALS },
104 //{ "musicvideos", FieldLastPlayed, 568, SettingInfo::TODO, CDatabaseQueryRule::TODO },
105 //{ "musicvideos", FieldDateAdded, 570, SettingInfo::TODO, CDatabaseQueryRule::TODO },
107 { "artists", FieldArtist, 557, SettingInfo::EDIT, CDatabaseQueryRule::OPERATOR_CONTAINS },
108 { "artists", FieldGenre, 515, SettingInfo::BUTTON, CDatabaseQueryRule::OPERATOR_EQUALS },
110 { "albums", FieldAlbum, 556, SettingInfo::EDIT, CDatabaseQueryRule::OPERATOR_CONTAINS },
111 { "albums", FieldArtist, 557, SettingInfo::BUTTON, CDatabaseQueryRule::OPERATOR_EQUALS },
112 { "albums", FieldRating, 563, SettingInfo::RANGE, CDatabaseQueryRule::OPERATOR_BETWEEN },
113 { "albums", FieldAlbumType, 564, SettingInfo::BUTTON, CDatabaseQueryRule::OPERATOR_EQUALS },
114 { "albums", FieldYear, 562, SettingInfo::RANGE, CDatabaseQueryRule::OPERATOR_BETWEEN },
115 { "albums", FieldGenre, 515, SettingInfo::BUTTON, CDatabaseQueryRule::OPERATOR_EQUALS },
116 { "albums", FieldMusicLabel, 21899, SettingInfo::BUTTON, CDatabaseQueryRule::OPERATOR_EQUALS },
118 { "songs", FieldTitle, 556, SettingInfo::EDIT, CDatabaseQueryRule::OPERATOR_CONTAINS },
119 { "songs", FieldAlbum, 558, SettingInfo::BUTTON, CDatabaseQueryRule::OPERATOR_EQUALS },
120 { "songs", FieldArtist, 557, SettingInfo::BUTTON, CDatabaseQueryRule::OPERATOR_EQUALS },
121 { "songs", FieldTime, 180, SettingInfo::RANGE, CDatabaseQueryRule::OPERATOR_BETWEEN },
122 { "songs", FieldRating, 563, SettingInfo::RANGE, CDatabaseQueryRule::OPERATOR_BETWEEN },
123 { "songs", FieldYear, 562, SettingInfo::RANGE, CDatabaseQueryRule::OPERATOR_BETWEEN },
124 { "songs", FieldGenre, 515, SettingInfo::BUTTON, CDatabaseQueryRule::OPERATOR_EQUALS },
125 { "songs", FieldPlaycount, 567, SettingInfo::RANGE, CDatabaseQueryRule::OPERATOR_BETWEEN },
126 //{ "songs", FieldLastPlayed, 568, SettingInfo::TODO, CDatabaseQueryRule::TODO },
127 //{ "songs", FieldDateAdded, 570, SettingInfo::TODO, CDatabaseQueryRule::TODO },
130 #define NUM_FILTERS sizeof(filterList) / sizeof(CGUIDialogMediaFilter::Filter)
132 CGUIDialogMediaFilter::CGUIDialogMediaFilter()
133 : CGUIDialogSettings(WINDOW_DIALOG_MEDIA_FILTER, "DialogMediaFilter.xml"),
137 m_delayTimer = new CTimer(this);
140 CGUIDialogMediaFilter::~CGUIDialogMediaFilter()
146 bool CGUIDialogMediaFilter::OnMessage(CGUIMessage& message)
148 switch (message.GetMessage())
150 case GUI_MSG_CLICKED:
152 int control = message.GetSenderId();
154 if (control == CONTROL_CLEAR_BUTTON)
157 m_filter->SetType(m_mediaType);
158 if (m_delayTimer && m_delayTimer->IsRunning())
159 m_delayTimer->Stop();
161 for (map<uint32_t, Filter>::iterator filter = m_filters.begin(); filter != m_filters.end(); filter++)
163 filter->second.rule = NULL;
165 switch (filter->second.type)
167 case SettingInfo::STRING:
168 case SettingInfo::EDIT:
169 ((CStdString *)filter->second.data)->clear();
172 case SettingInfo::CHECK:
173 *(int *)filter->second.data = CHECK_ALL;
176 case SettingInfo::BUTTON:
177 ((CStdString *)filter->second.data)->clear();
178 SET_CONTROL_LABEL2(filter->second.controlIndex, *(CStdString *)filter->second.data);
181 case SettingInfo::RANGE:
182 *(((float **)filter->second.data)[0]) = m_settings[filter->second.controlIndex - CONTROL_START].min;
183 *(((float **)filter->second.data)[1]) = m_settings[filter->second.controlIndex - CONTROL_START].max;
190 UpdateSetting(filter->first);
199 case GUI_MSG_REFRESH_LIST:
206 case GUI_MSG_WINDOW_DEINIT:
216 return CGUIDialogSettings::OnMessage(message);
219 void CGUIDialogMediaFilter::ShowAndEditMediaFilter(const std::string &path, CSmartPlaylist &filter)
221 CGUIDialogMediaFilter *dialog = (CGUIDialogMediaFilter *)g_windowManager.GetWindow(WINDOW_DIALOG_MEDIA_FILTER);
225 // initialize and show the dialog
226 dialog->Initialize();
227 dialog->m_filter = &filter;
228 // must be called after setting the filter/smartplaylist
229 if (!dialog->SetPath(path))
235 void CGUIDialogMediaFilter::OnWindowLoaded()
237 CGUIDialogSettings::OnWindowLoaded();
238 // we don't need the cancel button so let's hide it
239 SET_CONTROL_HIDDEN(CONTROL_CANCEL_BUTTON);
242 void CGUIDialogMediaFilter::CreateSettings()
244 if (m_filter == NULL)
248 int handledRules = 0;
249 for (unsigned int index = 0; index < NUM_FILTERS; index++)
251 if (filterList[index].mediaType != m_mediaType)
254 Filter filter = filterList[index];
255 filter.controlIndex = CONTROL_START + m_settings.size();
257 // check the smartplaylist if it contains a matching rule
258 for (CDatabaseQueryRules::iterator rule = m_filter->m_ruleCombination.m_rules.begin(); rule != m_filter->m_ruleCombination.m_rules.end(); rule++)
260 if ((*rule)->m_field == filter.field)
262 filter.rule = (CSmartPlaylistRule *)rule->get();
270 case SettingInfo::STRING:
271 case SettingInfo::EDIT:
273 if (filter.rule != NULL && filter.rule->m_parameter.size() == 1)
274 filter.data = new CStdString(filter.rule->m_parameter.at(0));
276 filter.data = new CStdString();
278 if (filter.type == SettingInfo::STRING)
279 AddString(filter.field, filter.label, (CStdString *)filter.data);
281 AddEdit(filter.field, filter.label, (CStdString *)filter.data);
285 case SettingInfo::CHECK:
287 if (filter.rule == NULL)
288 filter.data = new int(CHECK_ALL);
290 filter.data = new int(filter.rule->m_operator == CDatabaseQueryRule::OPERATOR_TRUE ? CHECK_YES : CHECK_NO);
292 vector<pair<int, int> > entries;
293 entries.push_back(pair<int, int>(CHECK_ALL, CHECK_LABEL_ALL));
294 entries.push_back(pair<int, int>(CHECK_NO, CHECK_LABEL_NO));
295 entries.push_back(pair<int, int>(CHECK_YES, CHECK_LABEL_YES));
296 AddSpin(filter.field, filter.label, (int *)filter.data, entries);
300 case SettingInfo::BUTTON:
302 CStdString *values = new CStdString();
303 if (filter.rule != NULL && filter.rule->m_parameter.size() > 0)
304 *values = filter.rule->GetParameter();
305 filter.data = values;
307 AddButton(filter.field, filter.label);
311 case SettingInfo::RANGE:
313 float min = 0, interval = 0, max = 0;
314 RANGEFORMATFUNCTION format;
315 GetRange(filter, min, interval, max, format);
317 // don't create the filter if there's no real range
321 float *valueLower = new float();
322 float *valueUpper = new float();
323 if (filter.rule != NULL && filter.rule->m_parameter.size() == 2)
325 *valueLower = (float)strtod(filter.rule->m_parameter.at(0), NULL);
326 *valueUpper = (float)strtod(filter.rule->m_parameter.at(1), NULL);
333 if (filter.rule != NULL)
335 DeleteRule(filter.field);
340 AddRangeSlider(filter.field, filter.label, valueLower, valueUpper, min, interval, max, format);
341 filter.data = m_settings[filter.controlIndex - CONTROL_START].data;
346 filter.controlIndex = -1;
347 if (filter.rule != NULL)
352 m_filters[filter.field] = filter;
355 // make sure that no change in capacity size is needed when adding new rules
356 // which would copy around the rules and our pointers in the Filter struct
357 // wouldn't work anymore
358 m_filter->m_ruleCombination.m_rules.reserve(m_filters.size() + (m_filter->m_ruleCombination.m_rules.size() - handledRules));
361 void CGUIDialogMediaFilter::SetupPage()
363 CGUIDialogSettings::SetupPage();
365 // set the heading label based on the media type
366 uint32_t localizedMediaId = 0;
367 if (m_mediaType == "movies")
368 localizedMediaId = 20342;
369 else if (m_mediaType == "tvshows")
370 localizedMediaId = 20343;
371 else if (m_mediaType == "episodes")
372 localizedMediaId = 20360;
373 else if (m_mediaType == "musicvideos")
374 localizedMediaId = 20389;
375 else if (m_mediaType == "artists")
376 localizedMediaId = 133;
377 else if (m_mediaType == "albums")
378 localizedMediaId = 132;
379 else if (m_mediaType == "songs")
380 localizedMediaId = 134;
382 CStdString format = StringUtils::Format(g_localizeStrings.Get(1275).c_str(), g_localizeStrings.Get(localizedMediaId).c_str());
383 SET_CONTROL_LABEL(CONTROL_HEADING, format);
385 // now we can finally set the label/values of the button settings (genre, actors etc)
386 for (map<uint32_t, Filter>::const_iterator filter = m_filters.begin(); filter != m_filters.end(); filter++)
388 if (filter->second.type == SettingInfo::BUTTON &&
389 filter->second.controlIndex >= 0 && filter->second.data != NULL)
390 SET_CONTROL_LABEL2(filter->second.controlIndex, *(CStdString *)filter->second.data);
396 void CGUIDialogMediaFilter::OnTimeout()
398 CGUIMessage msg(GUI_MSG_REFRESH_LIST, GetID(), 0);
399 g_windowManager.SendThreadMessage(msg, WINDOW_DIALOG_MEDIA_FILTER);
402 void CGUIDialogMediaFilter::OnSettingChanged(SettingInfo &setting)
404 map<uint32_t, Filter>::iterator it = m_filters.find(setting.id);
405 if (it == m_filters.end())
411 Filter& filter = it->second;
415 case SettingInfo::STRING:
416 case SettingInfo::EDIT:
418 CStdString *str = static_cast<CStdString*>(filter.data);
421 if (filter.rule == NULL)
422 filter.rule = AddRule(filter.field, filter.ruleOperator);
423 filter.rule->m_parameter.clear();
424 filter.rule->m_parameter.push_back(*str);
425 // trigger the live filtering with a delay in case the user
426 // types several characters in a short time
435 case SettingInfo::CHECK:
437 int choice = *(int *)setting.data;
438 if (choice > CHECK_ALL)
440 CDatabaseQueryRule::SEARCH_OPERATOR ruleOperator = choice == CHECK_YES ? CDatabaseQueryRule::OPERATOR_TRUE : CDatabaseQueryRule::OPERATOR_FALSE;
441 if (filter.rule == NULL)
442 filter.rule = AddRule(filter.field, ruleOperator);
444 filter.rule->m_operator = ruleOperator;
452 case SettingInfo::BUTTON:
455 OnBrowse(filter, items);
457 if (items.Size() > 0)
459 if (filter.rule == NULL)
460 filter.rule = AddRule(filter.field, filter.ruleOperator);
462 filter.rule->m_parameter.clear();
463 for (int index = 0; index < items.Size(); index++)
464 filter.rule->m_parameter.push_back(items[index]->GetLabel());
466 *(CStdString *)filter.data = filter.rule->GetParameter();
471 *(CStdString *)filter.data = "";
474 SET_CONTROL_LABEL2(filter.controlIndex, *(CStdString *)filter.data);
478 case SettingInfo::RANGE:
480 SettingInfo &setting = m_settings[filter.controlIndex - CONTROL_START];
481 float *valueLower = ((float **)filter.data)[0];
482 float *valueUpper = ((float **)filter.data)[1];
484 if (*valueLower > setting.min || *valueUpper < setting.max)
486 if (filter.rule == NULL)
487 filter.rule = AddRule(filter.field, filter.ruleOperator);
489 filter.rule->m_parameter.clear();
490 if (filter.field == FieldAirDate)
492 CDateTime lower = (time_t)*valueLower;
493 CDateTime upper = (time_t)*valueUpper;
494 filter.rule->m_parameter.push_back(lower.GetAsDBDate());
495 filter.rule->m_parameter.push_back(upper.GetAsDBDate());
499 CStdString tmp = StringUtils::Format("%.1f", *valueLower);
500 filter.rule->m_parameter.push_back(tmp);
502 tmp = StringUtils::Format("%.1f", *valueUpper);
503 filter.rule->m_parameter.push_back(tmp);
509 *((float **)filter.data)[0] = setting.min;
510 *((float **)filter.data)[1] = setting.max;
513 // trigger the live filtering with a delay in case the user
514 // moves the slider several steps in a short time
524 // we need to remove the existing rule for the title
525 if (remove && filter.rule != NULL)
527 DeleteRule(filter.field);
535 CGUIMessage msg(GUI_MSG_REFRESH_LIST, GetID(), 0);
538 else if (m_delayTimer)
540 if (m_delayTimer->IsRunning())
541 m_delayTimer->Restart();
543 m_delayTimer->Start(TIMEOUT_DELAY, false);
548 void CGUIDialogMediaFilter::Reset()
550 if (m_delayTimer && m_delayTimer->IsRunning())
551 m_delayTimer->Stop();
556 // delete all the setting's data
557 for (map<uint32_t, Filter>::iterator filter = m_filters.begin(); filter != m_filters.end(); filter++)
559 switch (filter->second.type)
561 case SettingInfo::STRING:
562 case SettingInfo::EDIT:
563 case SettingInfo::BUTTON:
564 delete (CStdString *)filter->second.data;
567 case SettingInfo::CHECK:
568 delete (int *)filter->second.data;
571 case SettingInfo::RANGE:
572 if (filter->second.data != NULL)
574 delete ((float **)filter->second.data)[0];
575 delete ((float **)filter->second.data)[1];
577 delete (float *)filter->second.data;
588 bool CGUIDialogMediaFilter::SetPath(const std::string &path)
590 if (path.empty() || m_filter == NULL)
592 CLog::Log(LOGWARNING, "CGUIDialogMediaFilter::SetPath(%s): invalid path or filter", path.c_str());
598 if (path.find("videodb://") == 0)
600 m_dbUrl = new CVideoDbUrl();
603 else if (path.find("musicdb://") == 0)
604 m_dbUrl = new CMusicDbUrl();
607 CLog::Log(LOGWARNING, "CGUIDialogMediaFilter::SetPath(%s): invalid path (neither videodb:// nor musicdb://)", path.c_str());
611 if (!m_dbUrl->FromString(path) ||
612 (video && m_dbUrl->GetType() != "movies" && m_dbUrl->GetType() != "tvshows" && m_dbUrl->GetType() != "episodes" && m_dbUrl->GetType() != "musicvideos") ||
613 (!video && m_dbUrl->GetType() != "artists" && m_dbUrl->GetType() != "albums" && m_dbUrl->GetType() != "songs"))
615 CLog::Log(LOGWARNING, "CGUIDialogMediaFilter::SetPath(%s): invalid media type", path.c_str());
619 // remove "filter" option
620 if (m_dbUrl->HasOption("filter"))
621 m_dbUrl->RemoveOption("filter");
624 m_mediaType = ((CVideoDbUrl*)m_dbUrl)->GetItemType();
626 m_mediaType = m_dbUrl->GetType();
628 m_filter->SetType(m_mediaType);
632 void CGUIDialogMediaFilter::UpdateControls()
634 for (map<uint32_t, Filter>::iterator itFilter = m_filters.begin(); itFilter != m_filters.end(); itFilter++)
636 if (itFilter->second.type == SettingInfo::BUTTON)
639 OnBrowse(itFilter->second, items, true);
641 int size = items.Size();
642 if (items.Size() == 1 && items[0]->HasProperty("total"))
643 size = (int)items[0]->GetProperty("total").asInteger();
645 CStdString label = g_localizeStrings.Get(itFilter->second.label);
647 (size == 1 && itFilter->second.field != FieldSet && itFilter->second.field != FieldTag))
648 CONTROL_DISABLE(itFilter->second.controlIndex);
651 CONTROL_ENABLE(itFilter->second.controlIndex);
652 label = StringUtils::Format("%s [%d]", label.c_str(), size);
654 SET_CONTROL_LABEL(itFilter->second.controlIndex, label);
659 void CGUIDialogMediaFilter::TriggerFilter() const
661 if (m_filter == NULL)
664 CGUIMessage message(GUI_MSG_NOTIFY_ALL, GetID(), 0, GUI_MSG_FILTER_ITEMS, 10); // 10 for advanced
665 g_windowManager.SendThreadMessage(message);
668 void CGUIDialogMediaFilter::OnBrowse(const Filter &filter, CFileItemList &items, bool countOnly /* = false */)
670 CFileItemList selectItems;
671 if (m_mediaType == "movies" || m_mediaType == "tvshows" || m_mediaType == "episodes" || m_mediaType == "musicvideos")
673 CVideoDatabase videodb;
677 CSmartPlaylist tmpFilter = *m_filter;
678 for (CDatabaseQueryRules::iterator rule = tmpFilter.m_ruleCombination.m_rules.begin(); rule != tmpFilter.m_ruleCombination.m_rules.end(); rule++)
680 if ((*rule)->m_field == filter.field)
682 tmpFilter.m_ruleCombination.m_rules.erase(rule);
687 std::set<CStdString> playlists;
688 CDatabase::Filter dbfilter;
689 dbfilter.where = tmpFilter.GetWhereClause(videodb, playlists);
691 VIDEODB_CONTENT_TYPE type = VIDEODB_CONTENT_MOVIES;
692 if (m_mediaType == "tvshows")
693 type = VIDEODB_CONTENT_TVSHOWS;
694 else if (m_mediaType == "episodes")
695 type = VIDEODB_CONTENT_EPISODES;
696 else if (m_mediaType == "musicvideos")
697 type = VIDEODB_CONTENT_MUSICVIDEOS;
699 if (filter.field == FieldGenre)
700 videodb.GetGenresNav(m_dbUrl->ToString(), selectItems, type, dbfilter, countOnly);
701 else if (filter.field == FieldActor || filter.field == FieldArtist)
702 videodb.GetActorsNav(m_dbUrl->ToString(), selectItems, type, dbfilter, countOnly);
703 else if (filter.field == FieldDirector)
704 videodb.GetDirectorsNav(m_dbUrl->ToString(), selectItems, type, dbfilter, countOnly);
705 else if (filter.field == FieldStudio)
706 videodb.GetStudiosNav(m_dbUrl->ToString(), selectItems, type, dbfilter, countOnly);
707 else if (filter.field == FieldAlbum)
708 videodb.GetMusicVideoAlbumsNav(m_dbUrl->ToString(), selectItems, -1, dbfilter, countOnly);
709 else if (filter.field == FieldTag)
710 videodb.GetTagsNav(m_dbUrl->ToString(), selectItems, type, dbfilter, countOnly);
712 else if (m_mediaType == "artists" || m_mediaType == "albums" || m_mediaType == "songs")
714 CMusicDatabase musicdb;
718 CSmartPlaylist tmpFilter = *m_filter;
719 for (CDatabaseQueryRules::iterator rule = tmpFilter.m_ruleCombination.m_rules.begin(); rule != tmpFilter.m_ruleCombination.m_rules.end(); rule++)
721 if ((*rule)->m_field == filter.field)
723 tmpFilter.m_ruleCombination.m_rules.erase(rule);
728 std::set<CStdString> playlists;
729 CDatabase::Filter dbfilter;
730 dbfilter.where = tmpFilter.GetWhereClause(musicdb, playlists);
732 if (filter.field == FieldGenre)
733 musicdb.GetGenresNav(m_dbUrl->ToString(), selectItems, dbfilter, countOnly);
734 else if (filter.field == FieldArtist)
735 musicdb.GetArtistsNav(m_dbUrl->ToString(), selectItems, m_mediaType == "albums", -1, -1, -1, dbfilter, SortDescription(), countOnly);
736 else if (filter.field == FieldAlbum)
737 musicdb.GetAlbumsNav(m_dbUrl->ToString(), selectItems, -1, -1, dbfilter, SortDescription(), countOnly);
738 else if (filter.field == FieldAlbumType)
739 musicdb.GetAlbumTypesNav(m_dbUrl->ToString(), selectItems, dbfilter, countOnly);
740 else if (filter.field == FieldMusicLabel)
741 musicdb.GetMusicLabelsNav(m_dbUrl->ToString(), selectItems, dbfilter, countOnly);
744 if (selectItems.Size() <= 0)
749 items.Copy(selectItems);
754 selectItems.Sort(SortByLabel, SortOrderAscending);
756 CGUIDialogSelect* pDialog = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
758 pDialog->SetItems(&selectItems);
759 CStdString strHeading = StringUtils::Format(g_localizeStrings.Get(13401), g_localizeStrings.Get(filter.label).c_str());
760 pDialog->SetHeading(strHeading);
761 pDialog->SetMultiSelection(true);
763 if (filter.rule != NULL && !filter.rule->m_parameter.empty())
764 pDialog->SetSelected(filter.rule->m_parameter);
767 if (pDialog->IsConfirmed())
768 items.Copy(pDialog->GetSelectedItems());
774 CSmartPlaylistRule* CGUIDialogMediaFilter::AddRule(Field field, CDatabaseQueryRule::SEARCH_OPERATOR ruleOperator /* = CDatabaseQueryRule::OPERATOR_CONTAINS */)
776 CSmartPlaylistRule rule;
777 rule.m_field = field;
778 rule.m_operator = ruleOperator;
780 m_filter->m_ruleCombination.AddRule(rule);
781 return (CSmartPlaylistRule *)m_filter->m_ruleCombination.m_rules.back().get();
784 void CGUIDialogMediaFilter::DeleteRule(Field field)
786 for (CDatabaseQueryRules::iterator rule = m_filter->m_ruleCombination.m_rules.begin(); rule != m_filter->m_ruleCombination.m_rules.end(); rule++)
788 if ((*rule)->m_field == field)
790 m_filter->m_ruleCombination.m_rules.erase(rule);
796 void CGUIDialogMediaFilter::GetRange(const Filter &filter, float &min, float &interval, float &max, RANGEFORMATFUNCTION &formatFunction)
798 if (filter.field == FieldRating)
800 if (m_mediaType == "movies" || m_mediaType == "tvshows" || m_mediaType == "episodes")
805 formatFunction = RangeAsFloat;
807 else if (m_mediaType == "albums" || m_mediaType == "songs")
812 formatFunction = RangeAsInt;
815 else if (filter.field == FieldYear)
817 formatFunction = RangeAsInt;
822 if (m_mediaType == "movies" || m_mediaType == "tvshows" || m_mediaType == "musicvideos")
826 if (m_mediaType == "movies")
829 year = DatabaseUtils::GetField(FieldYear, MediaTypeMovie, DatabaseQueryPartWhere);
831 else if (m_mediaType == "tvshows")
833 table = "tvshowview";
834 year = StringUtils::Format("strftime(\"%%Y\", %s)", DatabaseUtils::GetField(FieldYear, MediaTypeTvShow, DatabaseQueryPartWhere).c_str());
836 else if (m_mediaType == "musicvideos")
838 table = "musicvideoview";
839 year = DatabaseUtils::GetField(FieldYear, MediaTypeMusicVideo, DatabaseQueryPartWhere);
842 CDatabase::Filter filter;
843 filter.where = year + " > 0";
844 GetMinMax(table, year, min, max, filter);
846 else if (m_mediaType == "albums" || m_mediaType == "songs")
850 if (m_mediaType == "albums")
853 mediaType = MediaTypeAlbum;
855 else if (m_mediaType == "songs")
858 mediaType = MediaTypeSong;
863 CDatabase::Filter filter;
864 filter.where = DatabaseUtils::GetField(FieldYear, mediaType, DatabaseQueryPartWhere) + " > 0";
865 GetMinMax(table, DatabaseUtils::GetField(FieldYear, mediaType, DatabaseQueryPartSelect), min, max, filter);
868 else if (filter.field == FieldAirDate)
870 formatFunction = RangeAsDate;
875 if (m_mediaType == "episodes")
877 CStdString field = StringUtils::Format("CAST(strftime(\"%%s\", c%02d) AS INTEGER)", VIDEODB_ID_EPISODE_AIRED);
879 GetMinMax("episodeview", field, min, max);
880 interval = 60 * 60 * 24 * 7; // 1 week
883 else if (filter.field == FieldTime)
885 formatFunction = RangeAsTime;
890 if (m_mediaType == "songs")
891 GetMinMax("songview", "iDuration", min, max);
893 else if (filter.field == FieldPlaycount)
895 formatFunction = RangeAsInt;
900 if (m_mediaType == "songs")
901 GetMinMax("songview", "iTimesPlayed", min, max);
905 bool CGUIDialogMediaFilter::GetMinMax(const CStdString &table, const CStdString &field, float &min, float &max, const CDatabase::Filter &filter /* = CDatabase::Filter() */)
907 if (table.empty() || field.empty())
910 CDatabase *db = NULL;
911 CDbUrl *dbUrl = NULL;
912 if (m_mediaType == "movies" || m_mediaType == "tvshows" || m_mediaType == "episodes" || m_mediaType == "musicvideos")
914 CVideoDatabase *videodb = new CVideoDatabase();
915 if (!videodb->Open())
922 dbUrl = new CVideoDbUrl();
924 else if (m_mediaType == "artists" || m_mediaType == "albums" || m_mediaType == "songs")
926 CMusicDatabase *musicdb = new CMusicDatabase();
927 if (!musicdb->Open())
934 dbUrl = new CMusicDbUrl();
937 if (db == NULL || !db->IsOpen() || dbUrl == NULL)
944 CDatabase::Filter extFilter = filter;
945 CStdString strSQLExtra;
946 if (!db->BuildSQL(m_dbUrl->ToString(), strSQLExtra, extFilter, strSQLExtra, *dbUrl))
953 CStdString strSQL = "SELECT %s FROM %s ";
955 min = (float)strtod(db->GetSingleValue(db->PrepareSQL(strSQL, CStdString("MIN(" + field + ")").c_str(), table.c_str()) + strSQLExtra).c_str(), NULL);
956 max = (float)strtod(db->GetSingleValue(db->PrepareSQL(strSQL, CStdString("MAX(" + field + ")").c_str(), table.c_str()) + strSQLExtra).c_str(), NULL);
965 CStdString CGUIDialogMediaFilter::RangeAsFloat(float valueLower, float valueUpper, float minimum)
968 if (valueLower != valueUpper)
969 text = StringUtils::Format(g_localizeStrings.Get(21467).c_str(), valueLower, valueUpper);
971 text = StringUtils::Format("%.1f", valueLower);
975 CStdString CGUIDialogMediaFilter::RangeAsInt(float valueLower, float valueUpper, float minimum)
978 if (valueLower != valueUpper)
979 text = StringUtils::Format(g_localizeStrings.Get(21468).c_str(),
980 MathUtils::round_int((double)valueLower),
981 MathUtils::round_int((double)valueUpper));
983 text = StringUtils::Format("%d", MathUtils::round_int((double)valueLower));
987 CStdString CGUIDialogMediaFilter::RangeAsDate(float valueLower, float valueUpper, float minimum)
989 CDateTime from = (time_t)valueLower;
990 CDateTime to = (time_t)valueUpper;
992 if (valueLower != valueUpper)
993 text = StringUtils::Format(g_localizeStrings.Get(21469).c_str(),
994 from.GetAsLocalizedDate().c_str(),
995 to.GetAsLocalizedDate().c_str());
997 text = StringUtils::Format("%s",
998 from.GetAsLocalizedDate().c_str());
1002 CStdString CGUIDialogMediaFilter::RangeAsTime(float valueLower, float valueUpper, float minimum)
1004 CDateTime from = (time_t)valueLower;
1005 CDateTime to = (time_t)valueUpper;
1007 if (valueLower != valueUpper)
1008 text = StringUtils::Format(g_localizeStrings.Get(21469).c_str(),
1009 from.GetAsLocalizedTime("mm:ss").c_str(),
1010 to.GetAsLocalizedTime("mm:ss").c_str());
1012 text = StringUtils::Format("%s", from.GetAsLocalizedTime("mm:ss").c_str());