Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

smartplaylists: extend to support nested AND/OR rules (only from/to J…

…SON)
  • Loading branch information...
commit a1f8346b72e578a5cb2098264e25c44cd8d27426 1 parent 8aaa44d
Sascha Montellese authored August 07, 2012
38  xbmc/dialogs/GUIDialogSmartPlaylistEditor.cpp
@@ -150,12 +150,12 @@ bool CGUIDialogSmartPlaylistEditor::OnMessage(CGUIMessage& message)
150 150
 
151 151
 void CGUIDialogSmartPlaylistEditor::OnRuleList(int item)
152 152
 {
153  
-  if (item < 0 || item >= (int)m_playlist.m_playlistRules.size()) return;
  153
+  if (item < 0 || item >= (int)m_playlist.m_ruleCombination.m_rules.size()) return;
154 154
 
155  
-  CSmartPlaylistRule rule = m_playlist.m_playlistRules[item];
  155
+  CSmartPlaylistRule rule = m_playlist.m_ruleCombination.m_rules[item];
156 156
 
157 157
   if (CGUIDialogSmartPlaylistRule::EditRule(rule,m_playlist.GetType()))
158  
-    m_playlist.m_playlistRules[item] = rule;
  158
+    m_playlist.m_ruleCombination.m_rules[item] = rule;
159 159
 
160 160
   UpdateButtons();
161 161
 }
@@ -213,7 +213,7 @@ void CGUIDialogSmartPlaylistEditor::OnMatch()
213 213
 {
214 214
   CGUIMessage msg(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_MATCH);
215 215
   OnMessage(msg);
216  
-  m_playlist.m_matchAllRules = (msg.GetParam1() == 0);
  216
+  m_playlist.m_ruleCombination.SetType(msg.GetParam1() == 0 ? CSmartPlaylistRuleCombination::CombinationAnd : CSmartPlaylistRuleCombination::CombinationOr);
217 217
   UpdateButtons();
218 218
 }
219 219
 
@@ -262,20 +262,20 @@ void CGUIDialogSmartPlaylistEditor::UpdateButtons()
262 262
   SET_CONTROL_LABEL2(CONTROL_NAME, m_playlist.m_playlistName);
263 263
   }
264 264
 
265  
-  CONTROL_ENABLE_ON_CONDITION(CONTROL_RULE_REMOVE, m_playlist.m_playlistRules.size() > 0);
266  
-  CONTROL_ENABLE_ON_CONDITION(CONTROL_MATCH, m_playlist.m_playlistRules.size() > 1);
  265
+  CONTROL_ENABLE_ON_CONDITION(CONTROL_RULE_REMOVE, m_playlist.m_ruleCombination.m_rules.size() > 0);
  266
+  CONTROL_ENABLE_ON_CONDITION(CONTROL_MATCH, m_playlist.m_ruleCombination.m_rules.size() > 1);
267 267
 
268 268
   int currentItem = GetSelectedItem();
269 269
   CGUIMessage msgReset(GUI_MSG_LABEL_RESET, GetID(), CONTROL_RULE_LIST);
270 270
   OnMessage(msgReset);
271 271
   m_ruleLabels->Clear();
272  
-  for (unsigned int i = 0; i < m_playlist.m_playlistRules.size(); i++)
  272
+  for (unsigned int i = 0; i < m_playlist.m_ruleCombination.m_rules.size(); i++)
273 273
   {
274 274
     CFileItemPtr item(new CFileItem("", false));
275  
-    if (m_playlist.m_playlistRules[i].m_field == FieldNone)
  275
+    if (m_playlist.m_ruleCombination.m_rules[i].m_field == FieldNone)
276 276
       item->SetLabel(g_localizeStrings.Get(21423));
277 277
     else
278  
-      item->SetLabel(m_playlist.m_playlistRules[i].GetLocalizedRule(m_playlist.GetType()));
  278
+      item->SetLabel(m_playlist.m_ruleCombination.m_rules[i].GetLocalizedRule(m_playlist.GetType()));
279 279
     m_ruleLabels->Add(item);
280 280
   }
281 281
   CGUIMessage msg(GUI_MSG_LABEL_BIND, GetID(), CONTROL_RULE_LIST, 0, 0, m_ruleLabels);
@@ -325,7 +325,7 @@ void CGUIDialogSmartPlaylistEditor::OnWindowLoaded()
325 325
     msg.SetLabel(21426);
326 326
     OnMessage(msg);
327 327
   }
328  
-  SendMessage(GUI_MSG_ITEM_SELECT, CONTROL_MATCH, m_playlist.m_matchAllRules ? 0 : 1);
  328
+  SendMessage(GUI_MSG_ITEM_SELECT, CONTROL_MATCH, m_playlist.m_ruleCombination.GetType() == CSmartPlaylistRuleCombination::CombinationAnd ? 0 : 1);
329 329
   // and now the limit spinner
330 330
   {
331 331
     CGUIMessage msg(GUI_MSG_LABEL_ADD, GetID(), CONTROL_LIMIT, 0);
@@ -434,8 +434,8 @@ void CGUIDialogSmartPlaylistEditor::HighlightItem(int item)
434 434
 
435 435
 void CGUIDialogSmartPlaylistEditor::OnRuleRemove(int item)
436 436
 {
437  
-  if (item < 0 || item >= (int)m_playlist.m_playlistRules.size()) return;
438  
-  m_playlist.m_playlistRules.erase(m_playlist.m_playlistRules.begin() + item);
  437
+  if (item < 0 || item >= (int)m_playlist.m_ruleCombination.m_rules.size()) return;
  438
+  m_playlist.m_ruleCombination.m_rules.erase(m_playlist.m_ruleCombination.m_rules.begin() + item);
439 439
 
440 440
   UpdateButtons();
441 441
   if (item >= m_ruleLabels->Size())
@@ -453,10 +453,10 @@ void CGUIDialogSmartPlaylistEditor::OnRuleAdd()
453 453
   CSmartPlaylistRule rule;
454 454
   if (CGUIDialogSmartPlaylistRule::EditRule(rule,m_playlist.GetType()))
455 455
   {
456  
-    if (m_playlist.m_playlistRules.size() == 1 && m_playlist.m_playlistRules[0].m_field == FieldNone)
457  
-      m_playlist.m_playlistRules[0] = rule;
  456
+    if (m_playlist.m_ruleCombination.m_rules.size() == 1 && m_playlist.m_ruleCombination.m_rules[0].m_field == FieldNone)
  457
+      m_playlist.m_ruleCombination.m_rules[0] = rule;
458 458
     else
459  
-      m_playlist.m_playlistRules.push_back(rule);
  459
+      m_playlist.m_ruleCombination.m_rules.push_back(rule);
460 460
   }
461 461
   UpdateButtons();
462 462
 }
@@ -468,7 +468,7 @@ bool CGUIDialogSmartPlaylistEditor::NewPlaylist(const CStdString &type)
468 468
 
469 469
   editor->m_path = "";
470 470
   editor->m_playlist = CSmartPlaylist();
471  
-  editor->m_playlist.m_playlistRules.push_back(CSmartPlaylistRule());
  471
+  editor->m_playlist.m_ruleCombination.m_rules.push_back(CSmartPlaylistRule());
472 472
   editor->m_mode = type;
473 473
   editor->Initialize();
474 474
   editor->DoModal(g_windowManager.GetActiveWindow());
@@ -493,13 +493,13 @@ bool CGUIDialogSmartPlaylistEditor::EditPlaylist(const CStdString &path, const C
493 493
     if (!editor->m_mode.Left(5).Equals("party"))
494 494
       return false; // only edit normal playlists that exist
495 495
     // party mode playlists can be editted even if they don't exist
496  
-    playlist.m_playlistRules.push_back(CSmartPlaylistRule());
  496
+    playlist.m_ruleCombination.m_rules.push_back(CSmartPlaylistRule());
497 497
     playlist.SetType(editor->m_mode == "partymusic" ? "songs" : "musicvideos");
498 498
   }
499 499
 
500 500
   editor->m_playlist = playlist;
501  
-  if (editor->m_playlist.m_playlistRules.size() <= 0)
502  
-    editor->m_playlist.m_playlistRules.push_back(CSmartPlaylistRule());
  501
+  if (editor->m_playlist.m_ruleCombination.m_rules.size() <= 0)
  502
+    editor->m_playlist.m_ruleCombination.m_rules.push_back(CSmartPlaylistRule());
503 503
   editor->m_path = path;
504 504
   editor->Initialize();
505 505
   editor->DoModal(g_windowManager.GetActiveWindow());
249  xbmc/playlists/SmartPlayList.cpp
@@ -267,15 +267,13 @@ bool CSmartPlaylistRule::Save(CVariant &obj) const
267 267
   if (obj.isNull() || (m_parameter.empty() && m_operator != OPERATOR_TRUE && m_operator != OPERATOR_FALSE))
268 268
     return false;
269 269
 
270  
-  CVariant rule(CVariant::VariantTypeObject);
271  
-  rule["field"] = TranslateField(m_field);
272  
-  rule["operator"] = TranslateOperator(m_operator);
  270
+  obj["field"] = TranslateField(m_field);
  271
+  obj["operator"] = TranslateOperator(m_operator);
273 272
 
274  
-  rule["value"] = CVariant(CVariant::VariantTypeArray);
  273
+  obj["value"] = CVariant(CVariant::VariantTypeArray);
275 274
   for (vector<CStdString>::const_iterator it = m_parameter.begin(); it != m_parameter.end(); it++)
276  
-    rule["value"].push_back(*it);
  275
+    obj["value"].push_back(*it);
277 276
 
278  
-  obj.push_back(rule);
279 277
   return true;
280 278
 }
281 279
 
@@ -915,9 +913,160 @@ CStdString CSmartPlaylistRule::GetField(Field field, const CStdString& type)
915 913
   return DatabaseUtils::GetField(field, DatabaseUtils::MediaTypeFromString(type), DatabaseQueryPartWhere);
916 914
 }
917 915
 
  916
+CSmartPlaylistRuleCombination::CSmartPlaylistRuleCombination()
  917
+  : m_type(CombinationAnd)
  918
+{ }
  919
+
  920
+CStdString CSmartPlaylistRuleCombination::GetWhereClause(const CDatabase &db, const CStdString& strType, std::set<CStdString> &referencedPlaylists) const
  921
+{
  922
+  CStdString rule, currentRule;
  923
+  
  924
+  // translate the combinations into SQL
  925
+  for (vector<CSmartPlaylistRuleCombination>::const_iterator it = m_combinations.begin(); it != m_combinations.end(); ++it)
  926
+  {
  927
+    if (it != m_combinations.begin())
  928
+      rule += m_type == CombinationAnd ? " AND " : " OR ";
  929
+    rule += "(" + it->GetWhereClause(db, strType, referencedPlaylists) + ")";
  930
+  }
  931
+
  932
+  // translate the rules into SQL
  933
+  for (CSmartPlaylistRules::const_iterator it = m_rules.begin(); it != m_rules.end(); ++it)
  934
+  {
  935
+    if (!rule.empty())
  936
+      rule += m_type == CombinationAnd ? " AND " : " OR ";
  937
+    rule += "(";
  938
+    CStdString currentRule;
  939
+    if (it->m_field == FieldPlaylist)
  940
+    {
  941
+      CStdString playlistFile = CSmartPlaylistDirectory::GetPlaylistByName(it->m_parameter.at(0), strType);
  942
+      if (!playlistFile.IsEmpty() && referencedPlaylists.find(playlistFile) == referencedPlaylists.end())
  943
+      {
  944
+        referencedPlaylists.insert(playlistFile);
  945
+        CSmartPlaylist playlist;
  946
+        playlist.Load(playlistFile);
  947
+        CStdString playlistQuery;
  948
+        // only playlists of same type will be part of the query
  949
+        if (playlist.GetType().Equals(strType) || (playlist.GetType().Equals("mixed") && (strType == "songs" || strType == "musicvideos")) || playlist.GetType().IsEmpty())
  950
+        {
  951
+          playlist.SetType(strType);
  952
+          playlistQuery = playlist.GetWhereClause(db, referencedPlaylists);
  953
+        }
  954
+        if (playlist.GetType().Equals(strType))
  955
+        {
  956
+          if (it->m_operator == CSmartPlaylistRule::OPERATOR_DOES_NOT_EQUAL)
  957
+            currentRule.Format("NOT (%s)", playlistQuery.c_str());
  958
+          else
  959
+            currentRule = playlistQuery;
  960
+        }
  961
+      }
  962
+    }
  963
+    else
  964
+      currentRule = (*it).GetWhereClause(db, strType);
  965
+    // if we don't get a rule, we add '1' or '0' so the query is still valid and doesn't fail
  966
+    if (currentRule.IsEmpty())
  967
+      currentRule = m_type == CombinationAnd ? "'1'" : "'0'";
  968
+    rule += currentRule;
  969
+    rule += ")";
  970
+  }
  971
+
  972
+  return rule;
  973
+}
  974
+
  975
+bool CSmartPlaylistRuleCombination::Load(const CVariant &obj)
  976
+{
  977
+  if (!obj.isObject() && !obj.isArray())
  978
+    return false;
  979
+  
  980
+  CVariant child;
  981
+  if (obj.isObject())
  982
+  {
  983
+    if (obj.isMember("and") && obj["and"].isArray())
  984
+    {
  985
+      m_type = CombinationAnd;
  986
+      child = obj["and"];
  987
+    }
  988
+    else if (obj.isMember("or") && obj["or"].isArray())
  989
+    {
  990
+      m_type = CombinationOr;
  991
+      child = obj["or"];
  992
+    }
  993
+    else
  994
+      return false;
  995
+  }
  996
+  else
  997
+    child = obj;
  998
+
  999
+  for (CVariant::const_iterator_array it = child.begin_array(); it != child.end_array(); it++)
  1000
+  {
  1001
+    if (!it->isObject())
  1002
+      continue;
  1003
+
  1004
+    if (it->isMember("and") || it->isMember("or"))
  1005
+    {
  1006
+      CSmartPlaylistRuleCombination combo;
  1007
+      if (combo.Load(*it))
  1008
+        m_combinations.push_back(combo);
  1009
+    }
  1010
+    else
  1011
+    {
  1012
+      CSmartPlaylistRule rule;
  1013
+      if (rule.Load(*it))
  1014
+        m_rules.push_back(rule);
  1015
+    }
  1016
+  }
  1017
+
  1018
+  return true;
  1019
+}
  1020
+
  1021
+bool CSmartPlaylistRuleCombination::Save(CVariant &obj) const
  1022
+{
  1023
+  if (!obj.isObject() || (m_combinations.empty() && m_rules.empty()))
  1024
+    return false;
  1025
+
  1026
+  CVariant comboArray(CVariant::VariantTypeArray);
  1027
+  if (!m_combinations.empty())
  1028
+  {
  1029
+    for (CSmartPlaylistRuleCombinations::const_iterator combo = m_combinations.begin(); combo != m_combinations.end(); combo++)
  1030
+    {
  1031
+      CVariant comboObj(CVariant::VariantTypeObject);
  1032
+      if (combo->Save(comboObj))
  1033
+        comboArray.push_back(comboObj);
  1034
+    }
  1035
+
  1036
+  }
  1037
+  if (!m_rules.empty())
  1038
+  {
  1039
+    for (CSmartPlaylistRules::const_iterator rule = m_rules.begin(); rule != m_rules.end(); rule++)
  1040
+    {
  1041
+      CVariant ruleObj(CVariant::VariantTypeObject);
  1042
+      if (rule->Save(ruleObj))
  1043
+        comboArray.push_back(ruleObj);
  1044
+    }
  1045
+  }
  1046
+
  1047
+  obj[TranslateCombinationType()] = comboArray;
  1048
+
  1049
+  return true;
  1050
+}
  1051
+
  1052
+std::string CSmartPlaylistRuleCombination::TranslateCombinationType() const
  1053
+{
  1054
+  return m_type == CombinationAnd ? "and" : "or";
  1055
+}
  1056
+
  1057
+void CSmartPlaylistRuleCombination::AddRule(const CSmartPlaylistRule &rule)
  1058
+{
  1059
+  m_rules.push_back(rule);
  1060
+}
  1061
+
  1062
+void CSmartPlaylistRuleCombination::AddCombination(const CSmartPlaylistRuleCombination &combination)
  1063
+{
  1064
+  m_combinations.push_back(combination);
  1065
+}
  1066
+
918 1067
 CSmartPlaylist::CSmartPlaylist()
919 1068
 {
920  
-  m_matchAllRules = true;
  1069
+  m_ruleCombination.SetType(CSmartPlaylistRuleCombination::CombinationAnd);
921 1070
   m_limit = 0;
922 1071
   m_orderField = SortByNone;
923 1072
   m_orderAscending = true;
@@ -1003,15 +1152,14 @@ bool CSmartPlaylist::Load(const CStdString &path)
1003 1152
 
1004 1153
 bool CSmartPlaylist::Load(const CVariant &obj)
1005 1154
 {
1006  
-  if (!obj.isObject() ||
1007  
-      !obj.isMember("match") || !obj["match"].isString() ||
1008  
-      !obj.isMember("rules") || !obj["rules"].isArray())
  1155
+  if (!obj.isObject())
1009 1156
     return false;
1010 1157
 
1011 1158
   // load the playlist type
1012 1159
   if (obj.isMember("type") && obj["type"].isString())
1013 1160
     m_playlistType = obj["type"].asString();
1014  
-  // backward compatibility:
  1161
+
  1162
+  // backward compatibility
1015 1163
   if (m_playlistType == "music")
1016 1164
     m_playlistType = "songs";
1017 1165
   if (m_playlistType == "video")
@@ -1021,15 +1169,8 @@ bool CSmartPlaylist::Load(const CVariant &obj)
1021 1169
   if (obj.isMember("name") && obj["name"].isString())
1022 1170
     m_playlistName = obj["name"].asString();
1023 1171
 
1024  
-  m_matchAllRules = strcmpi(obj["match"].asString().c_str(), "all") == 0;
1025  
-
1026  
-  // now the rules
1027  
-  for (CVariant::const_iterator_array it = obj["rules"].begin_array(); it != obj["rules"].end_array(); it++)
1028  
-  {
1029  
-    CSmartPlaylistRule rule;
1030  
-    if (rule.Load(*it))
1031  
-      m_playlistRules.push_back(rule);
1032  
-  }
  1172
+  if (obj.isMember("rules"))
  1173
+    m_ruleCombination.Load(obj["rules"]);
1033 1174
 
1034 1175
   // now any limits
1035 1176
   if (obj.isMember("limit") && (obj["limit"].isInteger() || obj["limit"].isUnsignedInteger()) && obj["limit"].asUnsignedInteger() > 0)
@@ -1072,7 +1213,7 @@ bool CSmartPlaylist::LoadFromXML(TiXmlElement *root, const CStdString &encoding)
1072 1213
 
1073 1214
   TiXmlHandle match = ((TiXmlHandle)root->FirstChild("match")).FirstChild();
1074 1215
   if (match.Node())
1075  
-    m_matchAllRules = strcmpi(match.Node()->Value(), "all") == 0;
  1216
+    m_ruleCombination.SetType(strcmpi(match.Node()->Value(), "all") == 0 ? CSmartPlaylistRuleCombination::CombinationAnd : CSmartPlaylistRuleCombination::CombinationOr);
1076 1217
 
1077 1218
   // now the rules
1078 1219
   TiXmlElement *ruleElement = root->FirstChildElement("rule");
@@ -1080,7 +1221,7 @@ bool CSmartPlaylist::LoadFromXML(TiXmlElement *root, const CStdString &encoding)
1080 1221
   {
1081 1222
     CSmartPlaylistRule rule;
1082 1223
     if (rule.Load(ruleElement, encoding))
1083  
-      m_playlistRules.push_back(rule);
  1224
+      m_ruleCombination.AddRule(rule);
1084 1225
 
1085 1226
     ruleElement = ruleElement->NextSiblingElement("rule");
1086 1227
   }
@@ -1132,13 +1273,13 @@ bool CSmartPlaylist::Save(const CStdString &path) const
1132 1273
   pRoot->InsertEndChild(nodeName);
1133 1274
 
1134 1275
   // add the <match> tag
1135  
-  TiXmlText match(m_matchAllRules ? "all" : "one");
  1276
+  TiXmlText match(m_ruleCombination.GetType() == CSmartPlaylistRuleCombination::CombinationAnd ? "all" : "one");
1136 1277
   TiXmlElement nodeMatch("match");
1137 1278
   nodeMatch.InsertEndChild(match);
1138 1279
   pRoot->InsertEndChild(nodeMatch);
1139 1280
 
1140 1281
   // add <rule> tags
1141  
-  for (vector<CSmartPlaylistRule>::const_iterator it = m_playlistRules.begin(); it != m_playlistRules.end(); ++it)
  1282
+  for (CSmartPlaylistRules::const_iterator it = m_ruleCombination.m_rules.begin(); it != m_ruleCombination.m_rules.end(); ++it)
1142 1283
     it->Save(pRoot);
1143 1284
 
1144 1285
   // add <limit> tag
@@ -1170,17 +1311,16 @@ bool CSmartPlaylist::Save(CVariant &obj, bool full /* = true */) const
1170 1311
     return false;
1171 1312
 
1172 1313
   obj.clear();
1173  
-  // add "type", "name" and "match"
  1314
+  // add "type" and "name"
1174 1315
   obj["type"] = m_playlistType;
1175  
-  obj["match"] = m_matchAllRules ? "all" : "one";
1176 1316
 
1177 1317
   if (full)
1178 1318
     obj["name"] = m_playlistName;
1179 1319
 
1180 1320
   // add "rules"
1181  
-  obj["rules"] = CVariant(CVariant::VariantTypeArray);
1182  
-  for (vector<CSmartPlaylistRule>::const_iterator it = m_playlistRules.begin(); it != m_playlistRules.end(); ++it)
1183  
-    it->Save(obj["rules"]);
  1321
+  CVariant rulesObj = CVariant(CVariant::VariantTypeObject);
  1322
+  if (m_ruleCombination.Save(rulesObj))
  1323
+    obj["rules"] = rulesObj;
1184 1324
 
1185 1325
   // add "limit"
1186 1326
   if (full && m_limit)
@@ -1217,58 +1357,9 @@ void CSmartPlaylist::SetType(const CStdString &type)
1217 1357
   m_playlistType = type;
1218 1358
 }
1219 1359
 
1220  
-void CSmartPlaylist::AddRule(const CSmartPlaylistRule &rule)
1221  
-{
1222  
-  m_playlistRules.push_back(rule);
1223  
-}
1224  
-
1225 1360
 CStdString CSmartPlaylist::GetWhereClause(const CDatabase &db, set<CStdString> &referencedPlaylists) const
1226 1361
 {
1227  
-  CStdString rule, currentRule;
1228  
-  for (vector<CSmartPlaylistRule>::const_iterator it = m_playlistRules.begin(); it != m_playlistRules.end(); ++it)
1229  
-  {
1230  
-    if (it != m_playlistRules.begin())
1231  
-      rule += m_matchAllRules ? " AND " : " OR ";
1232  
-    rule += "(";
1233  
-    CStdString currentRule;
1234  
-    if (it->m_field == FieldPlaylist)
1235  
-    {
1236  
-      CStdString playlistFile = CSmartPlaylistDirectory::GetPlaylistByName(it->m_parameter.at(0), GetType());
1237  
-      if (!playlistFile.IsEmpty() && referencedPlaylists.find(playlistFile) == referencedPlaylists.end())
1238  
-      {
1239  
-        referencedPlaylists.insert(playlistFile);
1240  
-        CSmartPlaylist playlist;
1241  
-        playlist.Load(playlistFile);
1242  
-        CStdString playlistQuery;
1243  
-        // only playlists of same type will be part of the query
1244  
-        if (playlist.GetType().Equals(GetType()) || (playlist.GetType().Equals("mixed") && (GetType() == "songs" || GetType() == "musicvideos")) || playlist.GetType().IsEmpty())
1245  
-        {
1246  
-          playlist.SetType(GetType());
1247  
-          playlistQuery = playlist.GetWhereClause(db, referencedPlaylists);
1248  
-        }
1249  
-        if (playlist.GetType().Equals(GetType()))
1250  
-        {
1251  
-          if (it->m_operator == CSmartPlaylistRule::OPERATOR_DOES_NOT_EQUAL)
1252  
-            currentRule.Format("NOT (%s)", playlistQuery.c_str());
1253  
-          else
1254  
-            currentRule = playlistQuery;
1255  
-        }
1256  
-      }
1257  
-    }
1258  
-    else
1259  
-      currentRule = (*it).GetWhereClause(db, GetType());
1260  
-    // if we don't get a rule, we add '1' or '0' so the query is still valid and doesn't fail
1261  
-    if (currentRule.IsEmpty())
1262  
-      currentRule = m_matchAllRules ? "'1'" : "'0'";
1263  
-    rule += currentRule;
1264  
-    rule += ")";
1265  
-  }
1266  
-  return rule;
1267  
-}
1268  
-
1269  
-const vector<CSmartPlaylistRule> &CSmartPlaylist::GetRules() const
1270  
-{
1271  
-  return m_playlistRules;
  1362
+  return m_ruleCombination.GetWhereClause(db, GetType(), referencedPlaylists);
1272 1363
 }
1273 1364
 
1274 1365
 CStdString CSmartPlaylist::GetSaveLocation() const
72  xbmc/playlists/SmartPlayList.h
@@ -30,7 +30,18 @@
30 30
 class CDatabase;
31 31
 class CVariant;
32 32
 
33  
-class CSmartPlaylistRule
  33
+class ISmartPlaylistRule
  34
+{
  35
+public:
  36
+  virtual ~ISmartPlaylistRule() { }
  37
+
  38
+  virtual bool Load(TiXmlElement *element, const CStdString &encoding = "UTF-8") = 0;
  39
+  virtual bool Load(const CVariant &obj) = 0;
  40
+  virtual bool Save(TiXmlNode *parent) const = 0;
  41
+  virtual bool Save(CVariant &obj) const = 0;
  42
+};
  43
+
  44
+class CSmartPlaylistRule : public ISmartPlaylistRule
34 45
 {
35 46
 public:
36 47
   CSmartPlaylistRule();
@@ -63,10 +74,10 @@ class CSmartPlaylistRule
63 74
                     TEXTIN_FIELD
64 75
                   };
65 76
 
66  
-  bool Load(TiXmlElement *element, const CStdString &encoding = "UTF-8");
67  
-  bool Load(const CVariant &obj);
68  
-  bool Save(TiXmlNode *parent) const;
69  
-  bool Save(CVariant &obj) const;
  77
+  virtual bool Load(TiXmlElement *element, const CStdString &encoding = "UTF-8");
  78
+  virtual bool Load(const CVariant &obj);
  79
+  virtual bool Save(TiXmlNode *parent) const;
  80
+  virtual bool Save(CVariant &obj) const;
70 81
 
71 82
   CStdString                  GetWhereClause(const CDatabase &db, const CStdString& strType) const;
72 83
   static Field                TranslateField(const char *field);
@@ -95,6 +106,44 @@ class CSmartPlaylistRule
95 106
   CStdString GetVideoResolutionQuery(const CStdString &parameter) const;
96 107
 };
97 108
 
  109
+class CSmartPlaylistRuleCombination;
  110
+
  111
+typedef std::vector<CSmartPlaylistRule> CSmartPlaylistRules;
  112
+typedef std::vector<CSmartPlaylistRuleCombination> CSmartPlaylistRuleCombinations;
  113
+
  114
+class CSmartPlaylistRuleCombination : public ISmartPlaylistRule
  115
+{
  116
+public:
  117
+  CSmartPlaylistRuleCombination();
  118
+
  119
+  typedef enum {
  120
+    CombinationOr = 0,
  121
+    CombinationAnd
  122
+  } Combination;
  123
+
  124
+  virtual bool Load(TiXmlElement *element, const CStdString &encoding = "UTF-8") { return false; }
  125
+  virtual bool Load(const CVariant &obj);
  126
+  virtual bool Save(TiXmlNode *parent) const { return false; }
  127
+  virtual bool Save(CVariant &obj) const;
  128
+
  129
+  CStdString GetWhereClause(const CDatabase &db, const CStdString& strType, std::set<CStdString> &referencedPlaylists) const;
  130
+  std::string TranslateCombinationType() const;
  131
+
  132
+  Combination GetType() const { return m_type; }
  133
+  void SetType(Combination combination) { m_type = combination; }
  134
+
  135
+  void AddRule(const CSmartPlaylistRule &rule);
  136
+  void AddCombination(const CSmartPlaylistRuleCombination &rule);
  137
+
  138
+private:
  139
+  friend class CSmartPlaylist;
  140
+  friend class CGUIDialogSmartPlaylistEditor;
  141
+
  142
+  Combination m_type;
  143
+  CSmartPlaylistRuleCombinations m_combinations;
  144
+  CSmartPlaylistRules m_rules;
  145
+};
  146
+
98 147
 class CSmartPlaylist
99 148
 {
100 149
 public:
@@ -116,8 +165,8 @@ class CSmartPlaylist
116 165
   const CStdString& GetName() const { return m_playlistName; };
117 166
   const CStdString& GetType() const { return m_playlistType; };
118 167
 
119  
-  void SetMatchAllRules(bool matchAll) { m_matchAllRules = matchAll; };
120  
-  bool GetMatchAllRules() const { return m_matchAllRules; };
  168
+  void SetMatchAllRules(bool matchAll) { m_ruleCombination.SetType(matchAll ? CSmartPlaylistRuleCombination::CombinationAnd : CSmartPlaylistRuleCombination::CombinationOr); }
  169
+  bool GetMatchAllRules() const { return m_ruleCombination.GetType() == CSmartPlaylistRuleCombination::CombinationAnd; }
121 170
 
122 171
   void SetLimit(unsigned int limit) { m_limit = limit; };
123 172
   unsigned int GetLimit() const { return m_limit; };
@@ -128,8 +177,6 @@ class CSmartPlaylist
128 177
   void SetOrderAscending(bool orderAscending) { m_orderAscending = orderAscending; };
129 178
   bool GetOrderAscending() const { return m_orderAscending; };
130 179
 
131  
-  void AddRule(const CSmartPlaylistRule &rule);
132  
-
133 180
   /*! \brief get the where clause for a playlist
134 181
    We handle playlists inside playlists separately in order to ensure we don't introduce infinite loops
135 182
    by playlist A including playlist B which also (perhaps via other playlists) then includes playlistA.
@@ -140,9 +187,8 @@ class CSmartPlaylist
140 187
    */
141 188
   CStdString GetWhereClause(const CDatabase &db, std::set<CStdString> &referencedPlaylists) const;
142 189
 
143  
-  const std::vector<CSmartPlaylistRule> &GetRules() const;
144  
-
145 190
   CStdString GetSaveLocation() const;
  191
+
146 192
 private:
147 193
   friend class CGUIDialogSmartPlaylistEditor;
148 194
 
@@ -150,10 +196,10 @@ class CSmartPlaylist
150 196
   TiXmlElement *readNameFromXml(const CStdString &xml);
151 197
   bool load(TiXmlElement *root);
152 198
 
153  
-  std::vector<CSmartPlaylistRule> m_playlistRules;
  199
+  CSmartPlaylistRuleCombination m_ruleCombination;
154 200
   CStdString m_playlistName;
155 201
   CStdString m_playlistType;
156  
-  bool m_matchAllRules;
  202
+
157 203
   // order information
158 204
   unsigned int m_limit;
159 205
   SortBy m_orderField;

0 notes on commit a1f8346

Please sign in to comment.
Something went wrong with that request. Please try again.