Merge pull request #4594 from FernetMenta/paplayer
[xbmc.git] / xbmc / dialogs / GUIDialogSmartPlaylistRule.cpp
blob27966fb5e9312de602cc105d03bc3f414ea97255
1 /*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://xbmc.org
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)
8 * any later version.
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 "GUIDialogSmartPlaylistRule.h"
22 #include "GUIDialogFileBrowser.h"
23 #include "music/MusicDatabase.h"
24 #include "video/VideoDatabase.h"
25 #include "guilib/GUIWindowManager.h"
26 #include "GUIDialogSelect.h"
27 #include "filesystem/Directory.h"
28 #include "FileItem.h"
29 #include "guilib/GUIEditControl.h"
30 #include "guilib/LocalizeStrings.h"
31 #include "settings/MediaSourceSettings.h"
32 #include "storage/MediaManager.h"
33 #include "utils/LabelFormatter.h"
34 #include "utils/StringUtils.h"
36 #define CONTROL_FIELD 15
37 #define CONTROL_OPERATOR 16
38 #define CONTROL_VALUE 17
39 #define CONTROL_OK 18
40 #define CONTROL_CANCEL 19
41 #define CONTROL_BROWSE 20
43 using namespace std;
45 CGUIDialogSmartPlaylistRule::CGUIDialogSmartPlaylistRule(void)
46 : CGUIDialog(WINDOW_DIALOG_SMART_PLAYLIST_RULE, "SmartPlaylistRule.xml")
48 m_cancelled = false;
49 m_loadType = KEEP_IN_MEMORY;
52 CGUIDialogSmartPlaylistRule::~CGUIDialogSmartPlaylistRule()
56 bool CGUIDialogSmartPlaylistRule::OnBack(int actionID)
58 m_cancelled = true;
59 return CGUIDialog::OnBack(actionID);
62 bool CGUIDialogSmartPlaylistRule::OnMessage(CGUIMessage& message)
64 switch ( message.GetMessage() )
66 case GUI_MSG_CLICKED:
68 int iControl = message.GetSenderId();
69 if (iControl == CONTROL_OK)
70 OnOK();
71 else if (iControl == CONTROL_CANCEL)
72 OnCancel();
73 else if (iControl == CONTROL_VALUE)
75 CStdString parameter;
76 OnEditChanged(iControl, parameter);
77 m_rule.SetParameter(parameter);
79 else if (iControl == CONTROL_OPERATOR)
80 OnOperator();
81 else if (iControl == CONTROL_FIELD)
82 OnField();
83 else if (iControl == CONTROL_BROWSE)
84 OnBrowse();
85 return true;
87 break;
89 case GUI_MSG_VALIDITY_CHANGED:
90 CONTROL_ENABLE_ON_CONDITION(CONTROL_OK, message.GetParam1());
91 break;
93 return CGUIDialog::OnMessage(message);
96 void CGUIDialogSmartPlaylistRule::OnOK()
98 m_cancelled = false;
99 Close();
102 void CGUIDialogSmartPlaylistRule::OnBrowse()
104 CFileItemList items;
105 CMusicDatabase database;
106 database.Open();
107 CVideoDatabase videodatabase;
108 videodatabase.Open();
110 std::string basePath;
111 if (CSmartPlaylist::IsMusicType(m_type))
112 basePath = "musicdb://";
113 else
114 basePath = "videodb://";
116 VIDEODB_CONTENT_TYPE type = VIDEODB_CONTENT_MOVIES;
117 if (m_type.Equals("movies"))
118 basePath += "movies/";
119 else if (m_type.Equals("tvshows"))
121 type = VIDEODB_CONTENT_TVSHOWS;
122 basePath += "tvshows/";
124 else if (m_type.Equals("musicvideos"))
126 type = VIDEODB_CONTENT_MUSICVIDEOS;
127 basePath += "musicvideos/";
129 else if (m_type.Equals("episodes"))
131 if (m_rule.m_field == FieldGenre || m_rule.m_field == FieldYear ||
132 m_rule.m_field == FieldStudio)
133 type = VIDEODB_CONTENT_TVSHOWS;
134 else
135 type = VIDEODB_CONTENT_EPISODES;
136 basePath += "tvshows/";
139 int iLabel = 0;
140 if (m_rule.m_field == FieldGenre)
142 if (m_type.Equals("tvshows") || m_type.Equals("episodes") || m_type.Equals("movies"))
143 videodatabase.GetGenresNav(basePath + "genres/", items, type);
144 else if (m_type.Equals("songs") || m_type.Equals("albums") || m_type.Equals("artists") || m_type.Equals("mixed"))
145 database.GetGenresNav("musicdb://genres/",items);
146 if (m_type.Equals("musicvideos") || m_type.Equals("mixed"))
148 CFileItemList items2;
149 videodatabase.GetGenresNav("videodb://musicvideos/genres/",items2,VIDEODB_CONTENT_MUSICVIDEOS);
150 items.Append(items2);
152 iLabel = 515;
154 else if (m_rule.m_field == FieldCountry)
156 videodatabase.GetCountriesNav(basePath, items, type);
157 iLabel = 574;
159 else if (m_rule.m_field == FieldArtist || m_rule.m_field == FieldAlbumArtist)
161 if (CSmartPlaylist::IsMusicType(m_type))
162 database.GetArtistsNav("musicdb://artists/", items, m_rule.m_field == FieldAlbumArtist, -1);
163 if (m_type.Equals("musicvideos") || m_type.Equals("mixed"))
165 CFileItemList items2;
166 videodatabase.GetMusicVideoArtistsByName("", items2);
167 items.Append(items2);
169 iLabel = 557;
171 else if (m_rule.m_field == FieldAlbum)
173 if (CSmartPlaylist::IsMusicType(m_type))
174 database.GetAlbumsNav("musicdb://albums/", items);
175 if (m_type.Equals("musicvideos") || m_type.Equals("mixed"))
177 CFileItemList items2;
178 videodatabase.GetMusicVideoAlbumsByName("", items2);
179 items.Append(items2);
181 iLabel = 558;
183 else if (m_rule.m_field == FieldActor)
185 videodatabase.GetActorsNav(basePath + "actors/",items,type);
186 iLabel = 20337;
188 else if (m_rule.m_field == FieldYear)
190 if (CSmartPlaylist::IsMusicType(m_type))
191 database.GetYearsNav("musicdb://years/", items);
192 if (!m_type.Equals("songs") && !m_type.Equals("albums") && !m_type.Equals("artists"))
194 CFileItemList items2;
195 videodatabase.GetYearsNav(basePath + "years/", items2, type);
196 items.Append(items2);
198 iLabel = 562;
200 else if (m_rule.m_field == FieldDirector)
202 videodatabase.GetDirectorsNav(basePath + "directors/", items, type);
203 iLabel = 20339;
205 else if (m_rule.m_field == FieldStudio)
207 videodatabase.GetStudiosNav(basePath + "studios/", items, type);
208 iLabel = 572;
210 else if (m_rule.m_field == FieldWriter)
212 videodatabase.GetWritersNav(basePath, items, type);
213 iLabel = 20417;
215 else if (m_rule.m_field == FieldTvShowTitle ||
216 (m_type.Equals("tvshows") && m_rule.m_field == FieldTitle))
218 videodatabase.GetTvShowsNav(basePath + "titles/", items);
219 iLabel = 20343;
221 else if (m_rule.m_field == FieldTitle)
223 if (m_type.Equals("songs"))
225 database.GetSongsNav("musicdb://songs/", items, -1, -1, -1);
226 iLabel = 134;
228 else if (m_type.Equals("movies"))
230 videodatabase.GetMoviesNav(basePath + "titles/", items);
231 iLabel = 20342;
233 else if (m_type.Equals("episodes"))
235 videodatabase.GetEpisodesNav(basePath + "titles/-1/-1/", items);
236 // we need to replace the db label (<season>x<episode> <title>) with the title only
237 CLabelFormatter format("%T", "");
238 for (int i = 0; i < items.Size(); i++)
239 format.FormatLabel(items[i].get());
240 iLabel = 20360;
242 else if (m_type.Equals("musicvideos"))
244 videodatabase.GetMusicVideosNav(basePath + "titles/", items);
245 iLabel = 20389;
247 else
248 assert(false);
250 else if (m_rule.m_field == FieldPlaylist || m_rule.m_field == FieldVirtualFolder)
252 // use filebrowser to grab another smart playlist
254 // Note: This can cause infinite loops (playlist that refers to the same playlist) but I don't
255 // think there's any decent way to deal with this, as the infinite loop may be an arbitrary
256 // number of playlists deep, eg playlist1 -> playlist2 -> playlist3 ... -> playlistn -> playlist1
257 CStdString path = "special://videoplaylists/";
258 if (m_type.Equals("songs") || m_type.Equals("albums") || m_type.Equals("artists"))
259 path = "special://musicplaylists/";
260 XFILE::CDirectory::GetDirectory(path, items, ".xsp", XFILE::DIR_FLAG_NO_FILE_DIRS);
261 for (int i = 0; i < items.Size(); i++)
263 CFileItemPtr item = items[i];
264 CSmartPlaylist playlist;
265 // don't list unloadable smartplaylists or any referencable smartplaylists
266 // which do not match the type of the current smartplaylist
267 if (!playlist.Load(item->GetPath()) ||
268 (m_rule.m_field == FieldPlaylist &&
269 (!CSmartPlaylist::CheckTypeCompatibility(m_type, playlist.GetType()) ||
270 (!playlist.GetGroup().empty() || playlist.IsGroupMixed()))))
272 items.Remove(i);
273 i -= 1;
274 continue;
277 if (!playlist.GetName().empty())
278 item->SetLabel(playlist.GetName());
280 iLabel = 559;
282 else if (m_rule.m_field == FieldPath)
284 VECSOURCES sources;
285 if (m_type == "songs" || m_type == "mixed")
286 sources = *CMediaSourceSettings::Get().GetSources("music");
287 if (m_type != "songs")
289 VECSOURCES sources2 = *CMediaSourceSettings::Get().GetSources("video");
290 sources.insert(sources.end(),sources2.begin(),sources2.end());
292 g_mediaManager.GetLocalDrives(sources);
294 CStdString path = m_rule.GetParameter();
295 CGUIDialogFileBrowser::ShowAndGetDirectory(sources, g_localizeStrings.Get(657), path, false);
296 if (m_rule.m_parameter.size() > 0)
297 m_rule.m_parameter.clear();
298 if (!path.empty())
299 m_rule.m_parameter.push_back(path);
301 UpdateButtons();
302 return;
304 else if (m_rule.m_field == FieldSet)
306 videodatabase.GetSetsNav("videodb://movies/sets/", items, VIDEODB_CONTENT_MOVIES);
307 iLabel = 20434;
309 else if (m_rule.m_field == FieldTag)
311 VIDEODB_CONTENT_TYPE type = VIDEODB_CONTENT_MOVIES;
312 if (m_type == "tvshows")
313 type = VIDEODB_CONTENT_TVSHOWS;
314 else if (m_type == "musicvideos")
315 type = VIDEODB_CONTENT_MUSICVIDEOS;
316 else if (m_type != "movies")
317 return;
319 videodatabase.GetTagsNav(basePath + "tags/", items, type);
320 iLabel = 20459;
322 else
323 { // TODO: Add browseability in here.
324 assert(false);
327 // sort the items
328 items.Sort(SortByLabel, SortOrderAscending, SortAttributeIgnoreArticle);
330 CGUIDialogSelect* pDialog = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
331 pDialog->Reset();
332 pDialog->SetItems(&items);
333 CStdString strHeading = StringUtils::Format(g_localizeStrings.Get(13401).c_str(), g_localizeStrings.Get(iLabel).c_str());
334 pDialog->SetHeading(strHeading);
335 pDialog->SetMultiSelection(m_rule.m_field != FieldPlaylist && m_rule.m_field != FieldVirtualFolder);
337 if (!m_rule.m_parameter.empty())
338 pDialog->SetSelected(m_rule.m_parameter);
340 pDialog->DoModal();
341 if (pDialog->IsConfirmed())
343 const CFileItemList &items = pDialog->GetSelectedItems();
344 m_rule.m_parameter.clear();
345 for (int index = 0; index < items.Size(); index++)
346 m_rule.m_parameter.push_back(items[index]->GetLabel());
348 UpdateButtons();
350 pDialog->Reset();
353 void CGUIDialogSmartPlaylistRule::OnCancel()
355 m_cancelled = true;
356 Close();
359 void CGUIDialogSmartPlaylistRule::OnField()
361 CGUIMessage msg(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_FIELD);
362 OnMessage(msg);
363 m_rule.m_field = (Field)msg.GetParam1();
365 UpdateButtons();
368 void CGUIDialogSmartPlaylistRule::OnOperator()
370 CGUIMessage msg(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_OPERATOR);
371 OnMessage(msg);
372 m_rule.m_operator = (CDatabaseQueryRule::SEARCH_OPERATOR)msg.GetParam1();
374 UpdateButtons();
377 void CGUIDialogSmartPlaylistRule::UpdateButtons()
379 // update the field control
380 SendMessage(GUI_MSG_ITEM_SELECT, CONTROL_FIELD, m_rule.m_field);
381 CGUIMessage msg2(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_FIELD);
382 OnMessage(msg2);
383 m_rule.m_field = (Field)msg2.GetParam1();
385 // and now update the operator set
386 SendMessage(GUI_MSG_LABEL_RESET, CONTROL_OPERATOR);
388 CONTROL_ENABLE(CONTROL_VALUE);
389 if (CSmartPlaylistRule::IsFieldBrowseable(m_rule.m_field))
390 CONTROL_ENABLE(CONTROL_BROWSE);
391 else
392 CONTROL_DISABLE(CONTROL_BROWSE);
394 switch (m_rule.GetFieldType(m_rule.m_field))
396 case CDatabaseQueryRule::TEXT_FIELD:
397 // text fields - add the usual comparisons
398 AddOperatorLabel(CDatabaseQueryRule::OPERATOR_EQUALS);
399 AddOperatorLabel(CDatabaseQueryRule::OPERATOR_DOES_NOT_EQUAL);
400 AddOperatorLabel(CDatabaseQueryRule::OPERATOR_CONTAINS);
401 AddOperatorLabel(CDatabaseQueryRule::OPERATOR_DOES_NOT_CONTAIN);
402 AddOperatorLabel(CDatabaseQueryRule::OPERATOR_STARTS_WITH);
403 AddOperatorLabel(CDatabaseQueryRule::OPERATOR_ENDS_WITH);
404 break;
406 case CDatabaseQueryRule::NUMERIC_FIELD:
407 case CDatabaseQueryRule::SECONDS_FIELD:
408 // numerical fields - less than greater than
409 AddOperatorLabel(CDatabaseQueryRule::OPERATOR_EQUALS);
410 AddOperatorLabel(CDatabaseQueryRule::OPERATOR_DOES_NOT_EQUAL);
411 AddOperatorLabel(CDatabaseQueryRule::OPERATOR_GREATER_THAN);
412 AddOperatorLabel(CDatabaseQueryRule::OPERATOR_LESS_THAN);
413 break;
415 case CDatabaseQueryRule::DATE_FIELD:
416 // date field
417 AddOperatorLabel(CDatabaseQueryRule::OPERATOR_AFTER);
418 AddOperatorLabel(CDatabaseQueryRule::OPERATOR_BEFORE);
419 AddOperatorLabel(CDatabaseQueryRule::OPERATOR_IN_THE_LAST);
420 AddOperatorLabel(CDatabaseQueryRule::OPERATOR_NOT_IN_THE_LAST);
421 break;
423 case CDatabaseQueryRule::PLAYLIST_FIELD:
424 CONTROL_ENABLE(CONTROL_BROWSE);
425 AddOperatorLabel(CDatabaseQueryRule::OPERATOR_EQUALS);
426 AddOperatorLabel(CDatabaseQueryRule::OPERATOR_DOES_NOT_EQUAL);
427 break;
429 case CDatabaseQueryRule::BOOLEAN_FIELD:
430 CONTROL_DISABLE(CONTROL_VALUE);
431 AddOperatorLabel(CDatabaseQueryRule::OPERATOR_TRUE);
432 AddOperatorLabel(CDatabaseQueryRule::OPERATOR_FALSE);
433 break;
435 case CDatabaseQueryRule::TEXTIN_FIELD:
436 AddOperatorLabel(CDatabaseQueryRule::OPERATOR_EQUALS);
437 AddOperatorLabel(CDatabaseQueryRule::OPERATOR_DOES_NOT_EQUAL);
438 break;
441 // check our operator is valid, and update if not
442 SendMessage(GUI_MSG_ITEM_SELECT, CONTROL_OPERATOR, m_rule.m_operator);
443 CGUIMessage selected(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_OPERATOR);
444 OnMessage(selected);
445 m_rule.m_operator = (CDatabaseQueryRule::SEARCH_OPERATOR)selected.GetParam1();
447 // update the parameter edit control appropriately
448 SET_CONTROL_LABEL2(CONTROL_VALUE, m_rule.GetParameter());
449 CGUIEditControl::INPUT_TYPE type = CGUIEditControl::INPUT_TYPE_TEXT;
450 CDatabaseQueryRule::FIELD_TYPE fieldType = m_rule.GetFieldType(m_rule.m_field);
451 switch (fieldType)
453 case CDatabaseQueryRule::TEXT_FIELD:
454 case CDatabaseQueryRule::PLAYLIST_FIELD:
455 case CDatabaseQueryRule::TEXTIN_FIELD:
456 case CDatabaseQueryRule::NUMERIC_FIELD:
457 type = CGUIEditControl::INPUT_TYPE_TEXT;
458 break;
459 case CDatabaseQueryRule::DATE_FIELD:
460 if (m_rule.m_operator == CDatabaseQueryRule::OPERATOR_IN_THE_LAST ||
461 m_rule.m_operator == CDatabaseQueryRule::OPERATOR_NOT_IN_THE_LAST)
462 type = CGUIEditControl::INPUT_TYPE_TEXT;
463 else
464 type = CGUIEditControl::INPUT_TYPE_DATE;
465 break;
466 case CDatabaseQueryRule::SECONDS_FIELD:
467 type = CGUIEditControl::INPUT_TYPE_SECONDS;
468 break;
469 case CDatabaseQueryRule::BOOLEAN_FIELD:
470 type = CGUIEditControl::INPUT_TYPE_NUMBER;
471 break;
473 SendMessage(GUI_MSG_SET_TYPE, CONTROL_VALUE, type, 21420);
476 void CGUIDialogSmartPlaylistRule::AddOperatorLabel(CDatabaseQueryRule::SEARCH_OPERATOR op)
478 CGUIMessage select(GUI_MSG_LABEL_ADD, GetID(), CONTROL_OPERATOR, op);
479 select.SetLabel(CSmartPlaylistRule::GetLocalizedOperator(op));
480 OnMessage(select);
483 void CGUIDialogSmartPlaylistRule::OnWindowLoaded()
485 CGUIWindow::OnWindowLoaded();
486 ChangeButtonToEdit(CONTROL_VALUE, true); // true for single label
489 void CGUIDialogSmartPlaylistRule::OnInitWindow()
491 CGUIDialog::OnInitWindow();
493 SendMessage(GUI_MSG_LABEL_RESET, CONTROL_FIELD);
494 // add the fields to the field spincontrol
495 vector<Field> fields = CSmartPlaylistRule::GetFields(m_type);
496 for (unsigned int i = 0; i < fields.size(); i++)
498 CGUIMessage msg(GUI_MSG_LABEL_ADD, GetID(), CONTROL_FIELD, fields[i]);
499 msg.SetLabel(CSmartPlaylistRule::GetLocalizedField(fields[i]));
500 OnMessage(msg);
502 UpdateButtons();
504 CGUIEditControl *editControl = (CGUIEditControl*)GetControl(CONTROL_VALUE);
505 if (editControl != NULL)
506 editControl->SetInputValidation(CSmartPlaylistRule::Validate, &m_rule);
509 void CGUIDialogSmartPlaylistRule::OnDeinitWindow(int nextWindowID)
511 CGUIDialog::OnDeinitWindow(nextWindowID);
513 // reset field spincontrolex
514 SendMessage(GUI_MSG_LABEL_RESET, CONTROL_FIELD);
515 // reset operator spincontrolex
516 SendMessage(GUI_MSG_LABEL_RESET, CONTROL_OPERATOR);
519 bool CGUIDialogSmartPlaylistRule::EditRule(CSmartPlaylistRule &rule, const CStdString& type)
521 CGUIDialogSmartPlaylistRule *editor = (CGUIDialogSmartPlaylistRule *)g_windowManager.GetWindow(WINDOW_DIALOG_SMART_PLAYLIST_RULE);
522 if (!editor) return false;
524 editor->m_rule = rule;
525 editor->m_type = type == "mixed" ? "songs" : type;
526 editor->DoModal(g_windowManager.GetActiveWindow());
527 rule = editor->m_rule;
528 return !editor->m_cancelled;