aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormontellese <montellese@xbmc.org>2012-08-06 14:03:03 +0200
committermontellese <montellese@xbmc.org>2012-10-08 12:03:36 +0200
commit918f64b3477491887279d83fc2b6acdf48e4d66e (patch)
treed539b2ce8b5a62c71ffbea4c32efc0355733bfde
parent3476396155b314dda237dbc2abf090ddc5572afe (diff)
add new dialog CGUIDialogMediaFilter
-rw-r--r--language/English/strings.po24
-rw-r--r--xbmc/Application.cpp4
-rw-r--r--xbmc/dialogs/GUIDialogMediaFilter.cpp904
-rw-r--r--xbmc/dialogs/GUIDialogMediaFilter.h82
-rw-r--r--xbmc/dialogs/Makefile1
-rw-r--r--xbmc/guilib/Key.h1
-rw-r--r--xbmc/input/ButtonTranslator.cpp3
-rw-r--r--xbmc/playlists/SmartPlayList.h2
8 files changed, 1019 insertions, 2 deletions
diff --git a/language/English/strings.po b/language/English/strings.po
index fb5abf8327..e33ba304ed 100644
--- a/language/English/strings.po
+++ b/language/English/strings.po
@@ -3201,6 +3201,12 @@ msgctxt "#1273"
msgid "AirPlay"
msgstr ""
+#empty string id 1274
+
+msgctxt "#1275"
+msgid "Filter %s"
+msgstr ""
+
#empty strings from id 1274 to 1299
msgctxt "#1300"
@@ -9400,7 +9406,23 @@ msgctxt "#21465"
msgid "Above video"
msgstr ""
-#empty strings from id 21466 to 21799
+msgctxt "#21466"
+msgid "between"
+msgstr ""
+
+msgctxt "#21467"
+msgid "%.1f to %.1f"
+msgstr ""
+
+msgctxt "#21468"
+msgid "%d to %d"
+msgstr ""
+
+msgctxt "#21469"
+msgid "%s to %s"
+msgstr ""
+
+#empty strings from id 21470 to 21799
msgctxt "#21800"
msgid "File name"
diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp
index f85326ec5d..92ffb6ff58 100644
--- a/xbmc/Application.cpp
+++ b/xbmc/Application.cpp
@@ -286,6 +286,7 @@
#include "guilib/GUIControlFactory.h"
#include "dialogs/GUIDialogCache.h"
#include "dialogs/GUIDialogPlayEject.h"
+#include "dialogs/GUIDialogMediaFilter.h"
#include "utils/XMLUtils.h"
#include "addons/AddonInstaller.h"
@@ -1299,6 +1300,8 @@ bool CApplication::Initialize()
g_windowManager.Add(new CGUIDialogPeripheralManager);
g_windowManager.Add(new CGUIDialogPeripheralSettings);
+
+ g_windowManager.Add(new CGUIDialogMediaFilter); // window id = 151
g_windowManager.Add(new CGUIWindowMusicPlayList); // window id = 500
g_windowManager.Add(new CGUIWindowMusicSongs); // window id = 501
@@ -3477,6 +3480,7 @@ bool CApplication::Cleanup()
g_windowManager.Delete(WINDOW_DIALOG_ADDON_SETTINGS);
g_windowManager.Delete(WINDOW_DIALOG_ACCESS_POINTS);
g_windowManager.Delete(WINDOW_DIALOG_SLIDER);
+ g_windowManager.Delete(WINDOW_DIALOG_MEDIA_FILTER);
/* Delete PVR related windows and dialogs */
g_windowManager.Delete(WINDOW_PVR);
diff --git a/xbmc/dialogs/GUIDialogMediaFilter.cpp b/xbmc/dialogs/GUIDialogMediaFilter.cpp
new file mode 100644
index 0000000000..23a23c06a1
--- /dev/null
+++ b/xbmc/dialogs/GUIDialogMediaFilter.cpp
@@ -0,0 +1,904 @@
+/*
+ * Copyright (C) 2012 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "GUIDialogMediaFilter.h"
+#include "FileItem.h"
+#include "GUIUserMessages.h"
+#include "XBDateTime.h"
+#include "dialogs/GUIDialogSelect.h"
+#include "guilib/GUIWindowManager.h"
+#include "guilib/LocalizeStrings.h"
+#include "music/MusicDatabase.h"
+#include "playlists/SmartPlayList.h"
+#include "utils/MathUtils.h"
+#include "video/VideoDatabase.h"
+
+// list of controls
+#define CONTROL_HEADING 2
+// list of controls from CGUIDialogSettings
+#define CONTROL_GROUP_LIST 5
+#define CONTROL_DEFAULT_BUTTON 7
+#define CONTROL_DEFAULT_RADIOBUTTON 8
+#define CONTROL_DEFAULT_SPIN 9
+#define CONTROL_DEFAULT_SLIDER 10
+
+#define CONTROL_CLEAR_BUTTON 27
+#define CONTROL_OKAY_BUTTON 28
+#define CONTROL_CANCEL_BUTTON 29
+#define CONTROL_START 30
+
+#define CHECK_ALL -1
+#define CHECK_NO 0
+#define CHECK_YES 1
+#define CHECK_LABEL_ALL 593
+#define CHECK_LABEL_NO 106
+#define CHECK_LABEL_YES 107
+
+using namespace std;
+
+static const CGUIDialogMediaFilter::Filter filterList[] = {
+ { "movies", FieldTitle, 556, SettingInfo::EDIT, CSmartPlaylistRule::OPERATOR_CONTAINS },
+ { "movies", FieldRating, 563, SettingInfo::RANGE, CSmartPlaylistRule::OPERATOR_BETWEEN },
+ //{ "movies", FieldTime, 180, SettingInfo::TODO, CSmartPlaylistRule::TODO },
+ { "movies", FieldInProgress, 575, SettingInfo::CHECK, CSmartPlaylistRule::OPERATOR_FALSE },
+ { "movies", FieldYear, 562, SettingInfo::RANGE, CSmartPlaylistRule::OPERATOR_BETWEEN },
+ { "movies", FieldTag, 20459, SettingInfo::BUTTON, CSmartPlaylistRule::OPERATOR_EQUALS },
+ { "movies", FieldGenre, 515, SettingInfo::BUTTON, CSmartPlaylistRule::OPERATOR_EQUALS },
+ { "movies", FieldActor, 20337, SettingInfo::BUTTON, CSmartPlaylistRule::OPERATOR_EQUALS },
+ { "movies", FieldDirector, 20339, SettingInfo::BUTTON, CSmartPlaylistRule::OPERATOR_EQUALS },
+ { "movies", FieldStudio, 572, SettingInfo::BUTTON, CSmartPlaylistRule::OPERATOR_EQUALS },
+ //{ "movies", FieldLastPlayed, 568, SettingInfo::TODO, CSmartPlaylistRule::TODO },
+ //{ "movies", FieldDateAdded, 570, SettingInfo::TODO, CSmartPlaylistRule::TODO },
+
+ { "tvshows", FieldTitle, 556, SettingInfo::EDIT, CSmartPlaylistRule::OPERATOR_CONTAINS },
+ //{ "tvshows", FieldTvShowStatus, 126, SettingInfo::TODO, CSmartPlaylistRule::TODO },
+ { "tvshows", FieldRating, 563, SettingInfo::RANGE, CSmartPlaylistRule::OPERATOR_BETWEEN },
+ { "tvshows", FieldInProgress, 575, SettingInfo::CHECK, CSmartPlaylistRule::OPERATOR_FALSE },
+ { "tvshows", FieldYear, 562, SettingInfo::RANGE, CSmartPlaylistRule::OPERATOR_BETWEEN },
+ { "tvshows", FieldGenre, 515, SettingInfo::BUTTON, CSmartPlaylistRule::OPERATOR_EQUALS },
+ { "tvshows", FieldActor, 20337, SettingInfo::BUTTON, CSmartPlaylistRule::OPERATOR_EQUALS },
+ { "tvshows", FieldDirector, 20339, SettingInfo::BUTTON, CSmartPlaylistRule::OPERATOR_EQUALS },
+ { "tvshows", FieldStudio, 572, SettingInfo::BUTTON, CSmartPlaylistRule::OPERATOR_EQUALS },
+ //{ "tvshows", FieldDateAdded, 570, SettingInfo::TODO, CSmartPlaylistRule::TODO },
+
+ { "episodes", FieldTitle, 556, SettingInfo::EDIT, CSmartPlaylistRule::OPERATOR_CONTAINS },
+ { "episodes", FieldRating, 563, SettingInfo::RANGE, CSmartPlaylistRule::OPERATOR_BETWEEN },
+ { "episodes", FieldAirDate, 20416, SettingInfo::RANGE, CSmartPlaylistRule::OPERATOR_BETWEEN },
+ { "episodes", FieldInProgress, 575, SettingInfo::CHECK, CSmartPlaylistRule::OPERATOR_FALSE },
+ { "episodes", FieldActor, 20337, SettingInfo::BUTTON, CSmartPlaylistRule::OPERATOR_EQUALS },
+ { "episodes", FieldDirector, 20339, SettingInfo::BUTTON, CSmartPlaylistRule::OPERATOR_EQUALS },
+ //{ "episodes", FieldLastPlayed, 568, SettingInfo::TODO, CSmartPlaylistRule::TODO },
+ //{ "episodes", FieldDateAdded, 570, SettingInfo::TODO, CSmartPlaylistRule::TODO },
+
+ { "musicvideos", FieldTitle, 556, SettingInfo::EDIT, CSmartPlaylistRule::OPERATOR_CONTAINS },
+ { "musicvideos", FieldArtist, 557, SettingInfo::BUTTON, CSmartPlaylistRule::OPERATOR_EQUALS },
+ { "musicvideos", FieldAlbum, 558, SettingInfo::BUTTON, CSmartPlaylistRule::OPERATOR_EQUALS },
+ //{ "musicvideos", FieldTime, 180, SettingInfo::TODO, CSmartPlaylistRule::TODO },
+ { "musicvideos", FieldYear, 562, SettingInfo::RANGE, CSmartPlaylistRule::OPERATOR_BETWEEN },
+ { "musicvideos", FieldGenre, 515, SettingInfo::BUTTON, CSmartPlaylistRule::OPERATOR_EQUALS },
+ { "musicvideos", FieldDirector, 20339, SettingInfo::BUTTON, CSmartPlaylistRule::OPERATOR_EQUALS },
+ { "musicvideos", FieldStudio, 572, SettingInfo::BUTTON, CSmartPlaylistRule::OPERATOR_EQUALS },
+ //{ "musicvideos", FieldLastPlayed, 568, SettingInfo::TODO, CSmartPlaylistRule::TODO },
+ //{ "musicvideos", FieldDateAdded, 570, SettingInfo::TODO, CSmartPlaylistRule::TODO },
+
+ { "artists", FieldArtist, 557, SettingInfo::EDIT, CSmartPlaylistRule::OPERATOR_CONTAINS },
+ { "artists", FieldGenre, 515, SettingInfo::BUTTON, CSmartPlaylistRule::OPERATOR_EQUALS },
+
+ { "albums", FieldAlbum, 556, SettingInfo::EDIT, CSmartPlaylistRule::OPERATOR_CONTAINS },
+ { "albums", FieldArtist, 557, SettingInfo::BUTTON, CSmartPlaylistRule::OPERATOR_EQUALS },
+ { "albums", FieldRating, 563, SettingInfo::RANGE, CSmartPlaylistRule::OPERATOR_BETWEEN },
+ { "albums", FieldAlbumType, 564, SettingInfo::BUTTON, CSmartPlaylistRule::OPERATOR_EQUALS },
+ { "albums", FieldYear, 562, SettingInfo::RANGE, CSmartPlaylistRule::OPERATOR_BETWEEN },
+ { "albums", FieldGenre, 515, SettingInfo::BUTTON, CSmartPlaylistRule::OPERATOR_EQUALS },
+ { "albums", FieldMusicLabel, 21899, SettingInfo::BUTTON, CSmartPlaylistRule::OPERATOR_EQUALS },
+
+ { "songs", FieldTitle, 556, SettingInfo::EDIT, CSmartPlaylistRule::OPERATOR_CONTAINS },
+ { "songs", FieldAlbum, 558, SettingInfo::BUTTON, CSmartPlaylistRule::OPERATOR_EQUALS },
+ { "songs", FieldArtist, 557, SettingInfo::BUTTON, CSmartPlaylistRule::OPERATOR_EQUALS },
+ { "songs", FieldTime, 180, SettingInfo::RANGE, CSmartPlaylistRule::OPERATOR_BETWEEN },
+ { "songs", FieldRating, 563, SettingInfo::RANGE, CSmartPlaylistRule::OPERATOR_BETWEEN },
+ { "songs", FieldYear, 562, SettingInfo::RANGE, CSmartPlaylistRule::OPERATOR_BETWEEN },
+ { "songs", FieldGenre, 515, SettingInfo::BUTTON, CSmartPlaylistRule::OPERATOR_EQUALS },
+ { "songs", FieldPlaycount, 567, SettingInfo::RANGE, CSmartPlaylistRule::OPERATOR_BETWEEN },
+ //{ "songs", FieldLastPlayed, 568, SettingInfo::TODO, CSmartPlaylistRule::TODO },
+ //{ "songs", FieldDateAdded, 570, SettingInfo::TODO, CSmartPlaylistRule::TODO },
+};
+
+#define NUM_FILTERS sizeof(filterList) / sizeof(CGUIDialogMediaFilter::Filter)
+
+CGUIDialogMediaFilter::CGUIDialogMediaFilter()
+ : CGUIDialogSettings(WINDOW_DIALOG_MEDIA_FILTER, "DialogMediaFilter.xml"),
+ m_dbUrl(NULL),
+ m_filter(NULL)
+{ }
+
+CGUIDialogMediaFilter::~CGUIDialogMediaFilter()
+{
+ Reset();
+}
+
+bool CGUIDialogMediaFilter::OnMessage(CGUIMessage& message)
+{
+ switch (message.GetMessage())
+ {
+ case GUI_MSG_CLICKED:
+ {
+ int control = message.GetSenderId();
+
+ if (control == CONTROL_CLEAR_BUTTON)
+ {
+ m_filter->Reset();
+ m_filter->SetType(m_mediaType);
+
+ for (map<uint32_t, Filter>::iterator filter = m_filters.begin(); filter != m_filters.end(); filter++)
+ {
+ filter->second.rule = NULL;
+
+ switch (filter->second.type)
+ {
+ case SettingInfo::STRING:
+ case SettingInfo::EDIT:
+ ((CStdString *)filter->second.data)->clear();
+ break;
+
+ case SettingInfo::CHECK:
+ *(int *)filter->second.data = CHECK_ALL;
+ break;
+
+ case SettingInfo::BUTTON:
+ ((CStdString *)filter->second.data)->clear();
+ SET_CONTROL_LABEL2(filter->second.controlIndex, *(CStdString *)filter->second.data);
+ break;
+
+ case SettingInfo::RANGE:
+ *(((float **)filter->second.data)[0]) = m_settings[filter->second.controlIndex - CONTROL_START].min;
+ *(((float **)filter->second.data)[1]) = m_settings[filter->second.controlIndex - CONTROL_START].max;
+ break;
+
+ default:
+ continue;
+ }
+
+ UpdateSetting(filter->first);
+ }
+
+ CGUIMessage message(GUI_MSG_NOTIFY_ALL, GetID(), 0, GUI_MSG_FILTER_ITEMS, 10); // 10 for advanced
+ g_windowManager.SendMessage(message);
+ return true;
+ }
+ break;
+ }
+
+ case GUI_MSG_WINDOW_DEINIT:
+ {
+ Reset();
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ return CGUIDialogSettings::OnMessage(message);
+}
+
+void CGUIDialogMediaFilter::ShowAndEditMediaFilter(const std::string &path, CSmartPlaylist &filter)
+{
+ CGUIDialogMediaFilter *dialog = (CGUIDialogMediaFilter *)g_windowManager.GetWindow(WINDOW_DIALOG_MEDIA_FILTER);
+ if (dialog == NULL)
+ return;
+
+ // initialize and show the dialog
+ dialog->Initialize();
+ dialog->m_filter = &filter;
+ // must be called after setting the filter/smartplaylist
+ if (!dialog->SetPath(path))
+ return;
+
+ dialog->DoModal();
+}
+
+void CGUIDialogMediaFilter::OnWindowLoaded()
+{
+ CGUIDialogSettings::OnWindowLoaded();
+ // we don't need the cancel button so let's hide it
+ SET_CONTROL_HIDDEN(CONTROL_CANCEL_BUTTON);
+}
+
+void CGUIDialogMediaFilter::CreateSettings()
+{
+ if (m_filter == NULL)
+ return;
+
+ m_settings.clear();
+ int handledRules = 0;
+ for (unsigned int index = 0; index < NUM_FILTERS; index++)
+ {
+ if (filterList[index].mediaType != m_mediaType)
+ continue;
+
+ Filter filter = filterList[index];
+ filter.controlIndex = CONTROL_START + m_settings.size();
+
+ // check the smartplaylist if it contains a matching rule
+ for (vector<CSmartPlaylistRule>::iterator rule = m_filter->m_ruleCombination.m_rules.begin(); rule != m_filter->m_ruleCombination.m_rules.end(); rule++)
+ {
+ if (rule->m_field == filter.field)
+ {
+ filter.rule = &(*rule);
+ handledRules++;
+ break;
+ }
+ }
+
+ switch (filter.type)
+ {
+ case SettingInfo::STRING:
+ case SettingInfo::EDIT:
+ {
+ if (filter.rule != NULL && filter.rule->m_parameter.size() == 1)
+ filter.data = new CStdString(filter.rule->m_parameter.at(0));
+ else
+ filter.data = new CStdString();
+
+ if (filter.type == SettingInfo::STRING)
+ AddString(filter.field, filter.label, (CStdString *)filter.data);
+ else
+ AddEdit(filter.field, filter.label, (CStdString *)filter.data);
+ break;
+ }
+
+ case SettingInfo::CHECK:
+ {
+ if (filter.rule == NULL)
+ filter.data = new int(CHECK_ALL);
+ else
+ filter.data = new int(filter.rule->m_operator == CSmartPlaylistRule::OPERATOR_TRUE ? CHECK_YES : CHECK_NO);
+
+ vector<pair<int, int> > entries;
+ entries.push_back(pair<int, int>(CHECK_ALL, CHECK_LABEL_ALL));
+ entries.push_back(pair<int, int>(CHECK_NO, CHECK_LABEL_NO));
+ entries.push_back(pair<int, int>(CHECK_YES, CHECK_LABEL_YES));
+ AddSpin(filter.field, filter.label, (int *)filter.data, entries);
+ break;
+ }
+
+ case SettingInfo::BUTTON:
+ {
+ CStdString *values = new CStdString();
+ if (filter.rule != NULL && filter.rule->m_parameter.size() > 0)
+ *values = filter.rule->GetLocalizedParameter(m_mediaType);
+ filter.data = values;
+
+ AddButton(filter.field, filter.label);
+ break;
+ }
+
+ case SettingInfo::RANGE:
+ {
+ float min, interval, max;
+ RANGEFORMATFUNCTION format;
+ GetRange(filter, min, interval, max, format);
+
+ // don't create the filter if there's no real range
+ if (min == max)
+ break;
+
+ float *valueLower = new float();
+ float *valueUpper = new float();
+ if (filter.rule != NULL && filter.rule->m_parameter.size() == 2)
+ {
+ *valueLower = (float)strtod(filter.rule->m_parameter.at(0), NULL);
+ *valueUpper = (float)strtod(filter.rule->m_parameter.at(1), NULL);
+ }
+ else
+ {
+ *valueLower = min;
+ *valueUpper = max;
+
+ if (filter.rule != NULL)
+ {
+ DeleteRule(filter.field);
+ filter.rule = NULL;
+ }
+ }
+
+ AddRangeSlider(filter.field, filter.label, valueLower, valueUpper, min, interval, max, format);
+ filter.data = m_settings[filter.controlIndex - CONTROL_START].data;
+ break;
+ }
+
+ default:
+ filter.controlIndex = -1;
+ if (filter.rule != NULL)
+ handledRules--;
+ continue;
+ }
+
+ m_filters[filter.field] = filter;
+ }
+
+ // make sure that no change in capacity size is needed when adding new rules
+ // which would copy around the rules and our pointers in the Filter struct
+ // wouldn't work anymore
+ m_filter->m_ruleCombination.m_rules.reserve(m_filters.size() + (m_filter->m_ruleCombination.m_rules.size() - handledRules));
+}
+
+void CGUIDialogMediaFilter::SetupPage()
+{
+ CGUIDialogSettings::SetupPage();
+
+ // set the heading label based on the media type
+ uint32_t localizedMediaId = 0;
+ if (m_mediaType == "movies")
+ localizedMediaId = 20342;
+ else if (m_mediaType == "tvshows")
+ localizedMediaId = 20343;
+ else if (m_mediaType == "episodes")
+ localizedMediaId = 20360;
+ else if (m_mediaType == "musicvideos")
+ localizedMediaId = 20389;
+ else if (m_mediaType == "artists")
+ localizedMediaId = 133;
+ else if (m_mediaType == "albums")
+ localizedMediaId = 132;
+ else if (m_mediaType == "songs")
+ localizedMediaId = 134;
+
+ CStdString format;
+ format.Format(g_localizeStrings.Get(1275).c_str(), g_localizeStrings.Get(localizedMediaId).c_str());
+ SET_CONTROL_LABEL(CONTROL_HEADING, format);
+
+ // now we can finally set the label/values of the button settings (genre, actors etc)
+ for (map<uint32_t, Filter>::const_iterator filter = m_filters.begin(); filter != m_filters.end(); filter++)
+ {
+ if (filter->second.type == SettingInfo::BUTTON &&
+ filter->second.controlIndex >= 0 && filter->second.data != NULL)
+ SET_CONTROL_LABEL2(filter->second.controlIndex, *(CStdString *)filter->second.data);
+ }
+
+ UpdateControls();
+}
+
+void CGUIDialogMediaFilter::OnSettingChanged(SettingInfo &setting)
+{
+ map<uint32_t, Filter>::iterator it = m_filters.find(setting.id);
+ if (it == m_filters.end())
+ return;
+
+ bool changed = true;
+ bool remove = false;
+ Filter& filter = it->second;
+
+ switch (filter.type)
+ {
+ case SettingInfo::STRING:
+ case SettingInfo::EDIT:
+ {
+ CStdString *str = static_cast<CStdString*>(filter.data);
+ if (!str->empty())
+ {
+ if (filter.rule == NULL)
+ filter.rule = AddRule(filter.field, filter.ruleOperator);
+ filter.rule->m_parameter.clear();
+ filter.rule->m_parameter.push_back(*str);
+ }
+ else
+ remove = true;
+
+ break;
+ }
+
+ case SettingInfo::CHECK:
+ {
+ int choice = *(int *)setting.data;
+ if (choice > CHECK_ALL)
+ {
+ CSmartPlaylistRule::SEARCH_OPERATOR ruleOperator = choice == CHECK_YES ? CSmartPlaylistRule::OPERATOR_TRUE : CSmartPlaylistRule::OPERATOR_FALSE;
+ if (filter.rule == NULL)
+ filter.rule = AddRule(filter.field, ruleOperator);
+ else
+ filter.rule->m_operator = ruleOperator;
+ }
+ else
+ remove = true;
+
+ break;
+ }
+
+ case SettingInfo::BUTTON:
+ {
+ CFileItemList items;
+ OnBrowse(filter, items);
+
+ if (items.Size() > 0)
+ {
+ if (filter.rule == NULL)
+ filter.rule = AddRule(filter.field, filter.ruleOperator);
+
+ filter.rule->m_parameter.clear();
+ for (int index = 0; index < items.Size(); index++)
+ filter.rule->m_parameter.push_back(items[index]->GetLabel());
+
+ *(CStdString *)filter.data = filter.rule->GetLocalizedParameter(m_mediaType);
+ }
+ else
+ {
+ remove = true;
+ *(CStdString *)filter.data = "";
+ }
+
+ SET_CONTROL_LABEL2(filter.controlIndex, *(CStdString *)filter.data);
+ break;
+ }
+
+ case SettingInfo::RANGE:
+ {
+ SettingInfo &setting = m_settings[filter.controlIndex - CONTROL_START];
+ float *valueLower = ((float **)filter.data)[0];
+ float *valueUpper = ((float **)filter.data)[1];
+
+ if (*valueLower > setting.min || *valueUpper < setting.max)
+ {
+ if (filter.rule == NULL)
+ filter.rule = AddRule(filter.field, filter.ruleOperator);
+
+ filter.rule->m_parameter.clear();
+ if (filter.field == FieldAirDate)
+ {
+ CDateTime lower = (time_t)*valueLower;
+ CDateTime upper = (time_t)*valueUpper;
+ filter.rule->m_parameter.push_back(lower.GetAsDBDate());
+ filter.rule->m_parameter.push_back(upper.GetAsDBDate());
+ }
+ else
+ {
+ CStdString tmp;
+ tmp.Format("%.1f", *valueLower);
+ filter.rule->m_parameter.push_back(tmp);
+ tmp.clear();
+ tmp.Format("%.1f", *valueUpper);
+ filter.rule->m_parameter.push_back(tmp);
+ }
+ }
+ else
+ {
+ remove = true;
+ *((float **)filter.data)[0] = setting.min;
+ *((float **)filter.data)[1] = setting.max;
+ }
+ break;
+ }
+
+ default:
+ changed = false;
+ break;
+ }
+
+ // we need to remove the existing rule for the title
+ if (remove && filter.rule != NULL)
+ {
+ DeleteRule(filter.field);
+ filter.rule = NULL;
+ }
+
+ if (changed)
+ {
+ CGUIMessage message(GUI_MSG_NOTIFY_ALL, GetID(), 0, GUI_MSG_FILTER_ITEMS, 10); // 10 for advanced
+ g_windowManager.SendMessage(message);
+
+ UpdateControls();
+ }
+}
+
+void CGUIDialogMediaFilter::Reset()
+{
+ delete m_dbUrl;
+ m_dbUrl = NULL;
+
+ // delete all the setting's data
+ for (map<uint32_t, Filter>::iterator filter = m_filters.begin(); filter != m_filters.end(); filter++)
+ delete filter->second.data;
+
+ m_filters.clear();
+}
+
+bool CGUIDialogMediaFilter::SetPath(const std::string &path)
+{
+ if (path.empty() || m_filter == NULL)
+ return false;
+
+ delete m_dbUrl;
+ bool video = false;
+ if (path.find("videodb://") == 0)
+ {
+ m_dbUrl = new CVideoDbUrl();
+ video = true;
+ }
+ else if (path.find("musicdb://") == 0)
+ m_dbUrl = new CMusicDbUrl();
+ else
+ return false;
+
+ if (!m_dbUrl->FromString(path) ||
+ (video && m_dbUrl->GetType() != "movies" && m_dbUrl->GetType() != "tvshows" && m_dbUrl->GetType() != "episodes" && m_dbUrl->GetType() != "musicvideos") ||
+ (!video && m_dbUrl->GetType() != "artists" && m_dbUrl->GetType() != "albums" && m_dbUrl->GetType() != "songs"))
+ return false;
+
+ // remove "filter" option
+ if (m_dbUrl->HasOption("filter"))
+ m_dbUrl->AddOption("filter", "");
+
+ if (video)
+ m_mediaType = ((CVideoDbUrl*)m_dbUrl)->GetItemType();
+ else
+ m_mediaType = m_dbUrl->GetType();
+
+ m_filter->SetType(m_mediaType);
+ return true;
+}
+
+void CGUIDialogMediaFilter::UpdateControls()
+{
+ for (map<uint32_t, Filter>::iterator itFilter = m_filters.begin(); itFilter != m_filters.end(); itFilter++)
+ {
+ if (itFilter->second.type == SettingInfo::BUTTON)
+ {
+ CFileItemList items;
+ OnBrowse(itFilter->second, items, true);
+ if (items.Size() <= 0 ||
+ (items.Size() == 1 && items[0]->HasProperty("total") && items[0]->GetProperty("total").asInteger() <= 1))
+ CONTROL_DISABLE(itFilter->second.controlIndex);
+ else
+ CONTROL_ENABLE(itFilter->second.controlIndex);
+ }
+ }
+}
+
+void CGUIDialogMediaFilter::OnBrowse(const Filter &filter, CFileItemList &items, bool countOnly /* = false */)
+{
+ CFileItemList selectItems;
+ if (m_mediaType == "movies" || m_mediaType == "tvshows" || m_mediaType == "episodes" || m_mediaType == "musicvideos")
+ {
+ CVideoDatabase videodb;
+ if (!videodb.Open())
+ return;
+
+ CSmartPlaylist tmpFilter = *m_filter;
+ for (vector<CSmartPlaylistRule>::iterator rule = tmpFilter.m_ruleCombination.m_rules.begin(); rule != tmpFilter.m_ruleCombination.m_rules.end(); rule++)
+ {
+ if (rule->m_field == filter.field)
+ {
+ tmpFilter.m_ruleCombination.m_rules.erase(rule);
+ break;
+ }
+ }
+
+ std::set<CStdString> playlists;
+ CDatabase::Filter dbfilter;
+ dbfilter.where = tmpFilter.GetWhereClause(videodb, playlists);
+
+ VIDEODB_CONTENT_TYPE type = VIDEODB_CONTENT_MOVIES;
+ if (m_mediaType == "tvshows")
+ type = VIDEODB_CONTENT_TVSHOWS;
+ else if (m_mediaType == "episodes")
+ type = VIDEODB_CONTENT_EPISODES;
+ else if (m_mediaType == "musicvideos")
+ type = VIDEODB_CONTENT_MUSICVIDEOS;
+
+ if (filter.field == FieldGenre)
+ videodb.GetGenresNav(m_dbUrl->ToString(), selectItems, type, dbfilter, countOnly);
+ else if (filter.field == FieldActor || filter.field == FieldArtist)
+ videodb.GetActorsNav(m_dbUrl->ToString(), selectItems, type, dbfilter, countOnly);
+ else if (filter.field == FieldDirector)
+ videodb.GetDirectorsNav(m_dbUrl->ToString(), selectItems, type, dbfilter, countOnly);
+ else if (filter.field == FieldStudio)
+ videodb.GetStudiosNav(m_dbUrl->ToString(), selectItems, type, dbfilter, countOnly);
+ else if (filter.field == FieldAlbum)
+ videodb.GetMusicVideoAlbumsNav(m_dbUrl->ToString(), selectItems, -1, dbfilter, countOnly);
+ else if (filter.field == FieldTag)
+ videodb.GetTagsNav(m_dbUrl->ToString(), selectItems, type, dbfilter, countOnly);
+ }
+ else if (m_mediaType == "artists" || m_mediaType == "albums" || m_mediaType == "songs")
+ {
+ CMusicDatabase musicdb;
+ if (!musicdb.Open())
+ return;
+
+ CSmartPlaylist tmpFilter = *m_filter;
+ for (vector<CSmartPlaylistRule>::iterator rule = tmpFilter.m_ruleCombination.m_rules.begin(); rule != tmpFilter.m_ruleCombination.m_rules.end(); rule++)
+ {
+ if (rule->m_field == filter.field)
+ {
+ tmpFilter.m_ruleCombination.m_rules.erase(rule);
+ break;
+ }
+ }
+
+ std::set<CStdString> playlists;
+ CDatabase::Filter dbfilter;
+ dbfilter.where = tmpFilter.GetWhereClause(musicdb, playlists);
+
+ if (filter.field == FieldGenre)
+ musicdb.GetGenresNav(m_dbUrl->ToString(), selectItems, dbfilter, countOnly);
+ else if (filter.field == FieldArtist)
+ musicdb.GetArtistsNav(m_dbUrl->ToString(), selectItems, m_mediaType == "albums", -1, -1, -1, dbfilter, SortDescription(), countOnly);
+ else if (filter.field == FieldAlbum)
+ musicdb.GetAlbumsNav(m_dbUrl->ToString(), selectItems, -1, -1, dbfilter, SortDescription(), countOnly);
+ else if (filter.field == FieldAlbumType)
+ musicdb.GetAlbumTypesNav(m_dbUrl->ToString(), selectItems, dbfilter, countOnly);
+ else if (filter.field == FieldMusicLabel)
+ musicdb.GetMusicLabelsNav(m_dbUrl->ToString(), selectItems, dbfilter, countOnly);
+ }
+
+ if (selectItems.Size() <= 0)
+ return;
+
+ if (countOnly)
+ {
+ items.Copy(selectItems);
+ return;
+ }
+
+ // sort the items
+ selectItems.Sort(SORT_METHOD_LABEL, SortOrderAscending);
+
+ CGUIDialogSelect* pDialog = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
+ pDialog->Reset();
+ pDialog->SetItems(&selectItems);
+ CStdString strHeading;
+ strHeading.Format(g_localizeStrings.Get(13401), g_localizeStrings.Get(filter.label));
+ pDialog->SetHeading(strHeading);
+ pDialog->SetMultiSelection(true);
+
+ if (filter.rule != NULL && !filter.rule->m_parameter.empty())
+ pDialog->SetSelected(filter.rule->m_parameter);
+
+ pDialog->DoModal();
+ if (pDialog->IsConfirmed())
+ items.Copy(pDialog->GetSelectedItems());
+ else
+ items.Clear();
+ pDialog->Reset();
+}
+
+CSmartPlaylistRule* CGUIDialogMediaFilter::AddRule(Field field, CSmartPlaylistRule::SEARCH_OPERATOR ruleOperator /* = CSmartPlaylistRule::OPERATOR_CONTAINS */)
+{
+ CSmartPlaylistRule rule;
+ rule.m_field = field;
+ rule.m_operator = ruleOperator;
+
+ m_filter->m_ruleCombination.m_rules.push_back(rule);
+ return &m_filter->m_ruleCombination.m_rules.at(m_filter->m_ruleCombination.m_rules.size() - 1);
+}
+
+void CGUIDialogMediaFilter::DeleteRule(Field field)
+{
+ for (vector<CSmartPlaylistRule>::iterator rule = m_filter->m_ruleCombination.m_rules.begin(); rule != m_filter->m_ruleCombination.m_rules.end(); rule++)
+ {
+ if (rule->m_field == field)
+ {
+ m_filter->m_ruleCombination.m_rules.erase(rule);
+ break;
+ }
+ }
+}
+
+void CGUIDialogMediaFilter::GetRange(const Filter &filter, float &min, float &interval, float &max, RANGEFORMATFUNCTION &formatFunction)
+{
+ if (filter.field == FieldRating)
+ {
+ if (m_mediaType == "movies" || m_mediaType == "tvshows" || m_mediaType == "episodes")
+ {
+ min = 0.0f;
+ interval = 0.1f;
+ max = 10.0f;
+ formatFunction = RangeAsFloat;
+ }
+ else if (m_mediaType == "albums" || m_mediaType == "songs")
+ {
+ min = 0.0f;
+ interval = 1.0f;
+ max = 5.0f;
+ formatFunction = RangeAsInt;
+ }
+ }
+ else if (filter.field == FieldYear)
+ {
+ formatFunction = RangeAsInt;
+ min = 0.0f;
+ interval = 1.0f;
+ max = 0.0f;
+
+ if (m_mediaType == "movies" || m_mediaType == "tvshows" || m_mediaType == "musicvideos")
+ {
+ CStdString table;
+ CStdString year;
+ if (m_mediaType == "movies")
+ {
+ table = "movieview";
+ year.Format("c%02d", VIDEODB_ID_YEAR);
+ }
+ else if (m_mediaType == "tvshows")
+ {
+ table = "tvshowview";
+ year.Format("strftime(\"%%Y\", c%02d)", VIDEODB_ID_TV_PREMIERED);
+ }
+ else if (m_mediaType == "musicvideos")
+ {
+ table = "musicvideoview";
+ year.Format("c%02d", VIDEODB_ID_MUSICVIDEO_YEAR);
+ }
+
+ GetMinMax(table, year, min, max);
+ }
+ else if (m_mediaType == "albums" || m_mediaType == "songs")
+ {
+ CStdString table;
+ if (m_mediaType == "albums")
+ table = "albumview";
+ else if (m_mediaType == "songs")
+ table = "songview";
+
+ CDatabase::Filter filter;
+ filter.where = "iYear > 0";
+ GetMinMax(table, "iYear", min, max, filter);
+ }
+ }
+ else if (filter.field == FieldAirDate)
+ {
+ formatFunction = RangeAsDate;
+ min = 0.0f;
+ interval = 1.0f;
+ max = 0.0f;
+
+ if (m_mediaType == "episodes")
+ {
+ CStdString field; field.Format("CAST(strftime(\"%%s\", c%02d) AS INTEGER)", VIDEODB_ID_EPISODE_AIRED);
+
+ GetMinMax("episodeview", field, min, max);
+ interval = 60 * 60 * 24 * 7; // 1 week
+ }
+ }
+ else if (filter.field == FieldTime)
+ {
+ formatFunction = RangeAsTime;
+ min = 0.0f;
+ interval = 10.0f;
+ max = 0.0f;
+
+ if (m_mediaType == "songs")
+ GetMinMax("songview", "iDuration", min, max);
+ }
+ else if (filter.field == FieldPlaycount)
+ {
+ formatFunction = RangeAsInt;
+ min = 0.0f;
+ interval = 1.0f;
+ max = 0.0f;
+
+ if (m_mediaType == "songs")
+ GetMinMax("songview", "iTimesPlayed", min, max);
+ }
+}
+
+bool CGUIDialogMediaFilter::GetMinMax(const CStdString &table, const CStdString &field, float &min, float &max, const CDatabase::Filter &filter /* = CDatabase::Filter() */)
+{
+ if (table.empty() || field.empty())
+ return false;
+
+ CDatabase *db = NULL;
+ CDbUrl *dbUrl = NULL;
+ if (m_mediaType == "movies" || m_mediaType == "tvshows" || m_mediaType == "episodes" || m_mediaType == "musicvideos")
+ {
+ CVideoDatabase *videodb = new CVideoDatabase();
+ if (!videodb->Open())
+ {
+ delete videodb;
+ return false;
+ }
+
+ db = videodb;
+ dbUrl = new CVideoDbUrl();
+ }
+ else if (m_mediaType == "artists" || m_mediaType == "albums" || m_mediaType == "songs")
+ {
+ CMusicDatabase *musicdb = new CMusicDatabase();
+ if (!musicdb->Open())
+ {
+ delete musicdb;
+ return false;
+ }
+
+ db = musicdb;
+ dbUrl = new CMusicDbUrl();
+ }
+
+ if (db == NULL || !db->IsOpen() || dbUrl == NULL)
+ {
+ delete db;
+ delete dbUrl;
+ return false;
+ }
+
+ CDatabase::Filter extFilter = filter;
+ CStdString strSQLExtra;
+ if (!db->BuildSQL(m_dbUrl->ToString(), strSQLExtra, extFilter, strSQLExtra, *dbUrl))
+ {
+ delete db;
+ delete dbUrl;
+ return false;
+ }
+
+ CStdString strSQL = "SELECT %s FROM %s ";
+
+ min = (float)strtod(db->GetSingleValue(db->PrepareSQL(strSQL, CStdString("MIN(" + field + ")").c_str(), table.c_str()) + strSQLExtra).c_str(), NULL);
+ max = (float)strtod(db->GetSingleValue(db->PrepareSQL(strSQL, CStdString("MAX(" + field + ")").c_str(), table.c_str()) + strSQLExtra).c_str(), NULL);
+
+ db->Close();
+ delete db;
+ delete dbUrl;
+
+ return true;
+}
+
+CStdString CGUIDialogMediaFilter::RangeAsFloat(float valueLower, float valueUpper, float minimum)
+{
+ CStdString text;
+ if (valueLower != valueUpper)
+ text.Format(g_localizeStrings.Get(21467).c_str(), valueLower, valueUpper);
+ else
+ text.Format("%.1f", valueLower);
+ return text;
+}
+
+CStdString CGUIDialogMediaFilter::RangeAsInt(float valueLower, float valueUpper, float minimum)
+{
+ CStdString text;
+ if (valueLower != valueUpper)
+ text.Format(g_localizeStrings.Get(21468).c_str(), MathUtils::round_int((double)valueLower), MathUtils::round_int((double)valueUpper));
+ else
+ text.Format("%d", MathUtils::round_int((double)valueLower));
+ return text;
+}
+
+CStdString CGUIDialogMediaFilter::RangeAsDate(float valueLower, float valueUpper, float minimum)
+{
+ CDateTime from = (time_t)valueLower;
+ CDateTime to = (time_t)valueUpper;
+ CStdString text;
+ if (valueLower != valueUpper)
+ text.Format(g_localizeStrings.Get(21469).c_str(), from.GetAsLocalizedDate(), to.GetAsLocalizedDate());
+ else
+ text.Format("%s", from.GetAsLocalizedDate());
+ return text;
+}
+
+CStdString CGUIDialogMediaFilter::RangeAsTime(float valueLower, float valueUpper, float minimum)
+{
+ CDateTime from = (time_t)valueLower;
+ CDateTime to = (time_t)valueUpper;
+ CStdString text;
+ if (valueLower != valueUpper)
+ text.Format(g_localizeStrings.Get(21469).c_str(), from.GetAsLocalizedTime("mm:ss"), to.GetAsLocalizedTime("mm:ss"));
+ else
+ text.Format("%s", from.GetAsLocalizedTime("mm:ss"));
+ return text;
+}
diff --git a/xbmc/dialogs/GUIDialogMediaFilter.h b/xbmc/dialogs/GUIDialogMediaFilter.h
new file mode 100644
index 0000000000..681f068488
--- /dev/null
+++ b/xbmc/dialogs/GUIDialogMediaFilter.h
@@ -0,0 +1,82 @@
+#pragma once
+/*
+ * Copyright (C) 2012 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <map>
+#include <string>
+
+#include "DbUrl.h"
+#include "dbwrappers/Database.h"
+#include "playlists/SmartPlayList.h"
+#include "settings/GUIDialogSettings.h"
+#include "utils/DatabaseUtils.h"
+#include "utils/StdString.h"
+
+class CFileItemList;
+
+class CGUIDialogMediaFilter : public CGUIDialogSettings
+{
+public:
+ CGUIDialogMediaFilter();
+ virtual ~CGUIDialogMediaFilter();
+
+ virtual bool OnMessage(CGUIMessage& message);
+
+ static void ShowAndEditMediaFilter(const std::string &path, CSmartPlaylist &filter);
+
+ typedef struct {
+ std::string mediaType;
+ Field field;
+ uint32_t label;
+ SettingInfo::SETTING_TYPE type;
+ CSmartPlaylistRule::SEARCH_OPERATOR ruleOperator;
+ void *data;
+ CSmartPlaylistRule *rule;
+ int controlIndex;
+ } Filter;
+
+protected:
+ virtual void OnWindowLoaded();
+
+ virtual void CreateSettings();
+ virtual void SetupPage();
+ virtual void OnSettingChanged(SettingInfo &setting);
+
+ void Reset();
+ bool SetPath(const std::string &path);
+ void UpdateControls();
+
+ void OnBrowse(const Filter &filter, CFileItemList &items, bool countOnly = false);
+ CSmartPlaylistRule* AddRule(Field field, CSmartPlaylistRule::SEARCH_OPERATOR ruleOperator = CSmartPlaylistRule::OPERATOR_CONTAINS);
+ void DeleteRule(Field field);
+ void GetRange(const Filter &filter, float &min, float &interval, float &max, RANGEFORMATFUNCTION &formatFunction);
+
+ bool GetMinMax(const CStdString &table, const CStdString &field, float &min, float &max, const CDatabase::Filter &filter = CDatabase::Filter());
+
+ static CStdString RangeAsFloat(float valueLower, float valueUpper, float minimum);
+ static CStdString RangeAsInt(float valueLower, float valueUpper, float minimum);
+ static CStdString RangeAsDate(float valueLower, float valueUpper, float minimum);
+ static CStdString RangeAsTime(float valueLower, float valueUpper, float minimum);
+
+ CDbUrl* m_dbUrl;
+ std::string m_mediaType;
+ CSmartPlaylist *m_filter;
+ std::map<uint32_t, Filter> m_filters;
+};
diff --git a/xbmc/dialogs/Makefile b/xbmc/dialogs/Makefile
index 50a2974f36..f286370a88 100644
--- a/xbmc/dialogs/Makefile
+++ b/xbmc/dialogs/Makefile
@@ -9,6 +9,7 @@ SRCS=GUIDialogBoxBase.cpp \
GUIDialogGamepad.cpp \
GUIDialogKaiToast.cpp \
GUIDialogKeyboardGeneric.cpp \
+ GUIDialogMediaFilter.cpp \
GUIDialogMediaSource.cpp \
GUIDialogMuteBug.cpp \
GUIDialogNumeric.cpp \
diff --git a/xbmc/guilib/Key.h b/xbmc/guilib/Key.h
index 98634de45e..99b475d87b 100644
--- a/xbmc/guilib/Key.h
+++ b/xbmc/guilib/Key.h
@@ -389,6 +389,7 @@
#define WINDOW_DIALOG_PERIPHERAL_MANAGER 10149
#define WINDOW_DIALOG_PERIPHERAL_SETTINGS 10150
#define WINDOW_DIALOG_EXT_PROGRESS 10151
+#define WINDOW_DIALOG_MEDIA_FILTER 10152
#define WINDOW_MUSIC_PLAYLIST 10500
#define WINDOW_MUSIC_FILES 10501
diff --git a/xbmc/input/ButtonTranslator.cpp b/xbmc/input/ButtonTranslator.cpp
index 5a23dddee2..dfeb2bcebd 100644
--- a/xbmc/input/ButtonTranslator.cpp
+++ b/xbmc/input/ButtonTranslator.cpp
@@ -336,7 +336,8 @@ static const ActionMapping windows[] =
{"startup" , WINDOW_STARTUP_ANIM},
{"peripherals" , WINDOW_DIALOG_PERIPHERAL_MANAGER},
{"peripheralsettings" , WINDOW_DIALOG_PERIPHERAL_SETTINGS},
- {"extendedprogressdialog" , WINDOW_DIALOG_EXT_PROGRESS}};
+ {"extendedprogressdialog" , WINDOW_DIALOG_EXT_PROGRESS},
+ {"mediafilter" , WINDOW_DIALOG_MEDIA_FILTER}};
static const ActionMapping mousecommands[] =
{
diff --git a/xbmc/playlists/SmartPlayList.h b/xbmc/playlists/SmartPlayList.h
index 8a92919365..190abd04b8 100644
--- a/xbmc/playlists/SmartPlayList.h
+++ b/xbmc/playlists/SmartPlayList.h
@@ -138,6 +138,7 @@ public:
private:
friend class CSmartPlaylist;
friend class CGUIDialogSmartPlaylistEditor;
+ friend class CGUIDialogMediaFilter;
Combination m_type;
CSmartPlaylistRuleCombinations m_combinations;
@@ -197,6 +198,7 @@ public:
bool IsEmpty() const { return m_ruleCombination.m_rules.empty() && m_ruleCombination.m_combinations.empty(); }
private:
friend class CGUIDialogSmartPlaylistEditor;
+ friend class CGUIDialogMediaFilter;
TiXmlElement* readName();
TiXmlElement *readNameFromXml(const CStdString &xml);