2 * Copyright (C) 2005-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 "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"
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
40 #define CONTROL_CANCEL 19
41 #define CONTROL_BROWSE 20
45 CGUIDialogSmartPlaylistRule::CGUIDialogSmartPlaylistRule(void)
46 : CGUIDialog(WINDOW_DIALOG_SMART_PLAYLIST_RULE
, "SmartPlaylistRule.xml")
49 m_loadType
= KEEP_IN_MEMORY
;
52 CGUIDialogSmartPlaylistRule::~CGUIDialogSmartPlaylistRule()
56 bool CGUIDialogSmartPlaylistRule::OnBack(int actionID
)
59 return CGUIDialog::OnBack(actionID
);
62 bool CGUIDialogSmartPlaylistRule::OnMessage(CGUIMessage
& message
)
64 switch ( message
.GetMessage() )
68 int iControl
= message
.GetSenderId();
69 if (iControl
== CONTROL_OK
)
71 else if (iControl
== CONTROL_CANCEL
)
73 else if (iControl
== CONTROL_VALUE
)
76 OnEditChanged(iControl
, parameter
);
77 m_rule
.SetParameter(parameter
);
79 else if (iControl
== CONTROL_OPERATOR
)
81 else if (iControl
== CONTROL_FIELD
)
83 else if (iControl
== CONTROL_BROWSE
)
89 case GUI_MSG_VALIDITY_CHANGED
:
90 CONTROL_ENABLE_ON_CONDITION(CONTROL_OK
, message
.GetParam1());
93 return CGUIDialog::OnMessage(message
);
96 void CGUIDialogSmartPlaylistRule::OnOK()
102 void CGUIDialogSmartPlaylistRule::OnBrowse()
105 CMusicDatabase database
;
107 CVideoDatabase videodatabase
;
108 videodatabase
.Open();
110 std::string basePath
;
111 if (CSmartPlaylist::IsMusicType(m_type
))
112 basePath
= "musicdb://";
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
;
135 type
= VIDEODB_CONTENT_EPISODES
;
136 basePath
+= "tvshows/";
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
);
154 else if (m_rule
.m_field
== FieldCountry
)
156 videodatabase
.GetCountriesNav(basePath
, items
, type
);
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
);
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
);
183 else if (m_rule
.m_field
== FieldActor
)
185 videodatabase
.GetActorsNav(basePath
+ "actors/",items
,type
);
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
);
200 else if (m_rule
.m_field
== FieldDirector
)
202 videodatabase
.GetDirectorsNav(basePath
+ "directors/", items
, type
);
205 else if (m_rule
.m_field
== FieldStudio
)
207 videodatabase
.GetStudiosNav(basePath
+ "studios/", items
, type
);
210 else if (m_rule
.m_field
== FieldWriter
)
212 videodatabase
.GetWritersNav(basePath
, items
, type
);
215 else if (m_rule
.m_field
== FieldTvShowTitle
||
216 (m_type
.Equals("tvshows") && m_rule
.m_field
== FieldTitle
))
218 videodatabase
.GetTvShowsNav(basePath
+ "titles/", items
);
221 else if (m_rule
.m_field
== FieldTitle
)
223 if (m_type
.Equals("songs"))
225 database
.GetSongsNav("musicdb://songs/", items
, -1, -1, -1);
228 else if (m_type
.Equals("movies"))
230 videodatabase
.GetMoviesNav(basePath
+ "titles/", items
);
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());
242 else if (m_type
.Equals("musicvideos"))
244 videodatabase
.GetMusicVideosNav(basePath
+ "titles/", items
);
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()))))
277 if (!playlist
.GetName().empty())
278 item
->SetLabel(playlist
.GetName());
282 else if (m_rule
.m_field
== FieldPath
)
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();
299 m_rule
.m_parameter
.push_back(path
);
304 else if (m_rule
.m_field
== FieldSet
)
306 videodatabase
.GetSetsNav("videodb://movies/sets/", items
, VIDEODB_CONTENT_MOVIES
);
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")
319 videodatabase
.GetTagsNav(basePath
+ "tags/", items
, type
);
323 { // TODO: Add browseability in here.
328 items
.Sort(SortByLabel
, SortOrderAscending
, SortAttributeIgnoreArticle
);
330 CGUIDialogSelect
* pDialog
= (CGUIDialogSelect
*)g_windowManager
.GetWindow(WINDOW_DIALOG_SELECT
);
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
);
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());
353 void CGUIDialogSmartPlaylistRule::OnCancel()
359 void CGUIDialogSmartPlaylistRule::OnField()
361 CGUIMessage
msg(GUI_MSG_ITEM_SELECTED
, GetID(), CONTROL_FIELD
);
363 m_rule
.m_field
= (Field
)msg
.GetParam1();
368 void CGUIDialogSmartPlaylistRule::OnOperator()
370 CGUIMessage
msg(GUI_MSG_ITEM_SELECTED
, GetID(), CONTROL_OPERATOR
);
372 m_rule
.m_operator
= (CDatabaseQueryRule::SEARCH_OPERATOR
)msg
.GetParam1();
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
);
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
);
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
);
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
);
415 case CDatabaseQueryRule::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
);
423 case CDatabaseQueryRule::PLAYLIST_FIELD
:
424 CONTROL_ENABLE(CONTROL_BROWSE
);
425 AddOperatorLabel(CDatabaseQueryRule::OPERATOR_EQUALS
);
426 AddOperatorLabel(CDatabaseQueryRule::OPERATOR_DOES_NOT_EQUAL
);
429 case CDatabaseQueryRule::BOOLEAN_FIELD
:
430 CONTROL_DISABLE(CONTROL_VALUE
);
431 AddOperatorLabel(CDatabaseQueryRule::OPERATOR_TRUE
);
432 AddOperatorLabel(CDatabaseQueryRule::OPERATOR_FALSE
);
435 case CDatabaseQueryRule::TEXTIN_FIELD
:
436 AddOperatorLabel(CDatabaseQueryRule::OPERATOR_EQUALS
);
437 AddOperatorLabel(CDatabaseQueryRule::OPERATOR_DOES_NOT_EQUAL
);
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
);
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
);
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
;
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
;
464 type
= CGUIEditControl::INPUT_TYPE_DATE
;
466 case CDatabaseQueryRule::SECONDS_FIELD
:
467 type
= CGUIEditControl::INPUT_TYPE_SECONDS
;
469 case CDatabaseQueryRule::BOOLEAN_FIELD
:
470 type
= CGUIEditControl::INPUT_TYPE_NUMBER
;
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
));
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
]));
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
;