added: Smartplaylists for tvshows and episodes. Needs decent testing + cleanup.
[xbmc:xbmc-antiquated.git] / xbmc / GUIDialogSmartPlaylistRule.cpp
1 /*\r
2  *      Copyright (C) 2005-2007 Team XboxMediaCenter\r
3  *      http://www.xboxmediacenter.com\r
4  *\r
5  *  This Program is free software; you can redistribute it and/or modify\r
6  *  it under the terms of the GNU General Public License as published by\r
7  *  the Free Software Foundation; either version 2, or (at your option)\r
8  *  any later version.\r
9  *\r
10  *  This Program is distributed in the hope that it will be useful,\r
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
13  *  GNU General Public License for more details.\r
14  *\r
15  *  You should have received a copy of the GNU General Public License\r
16  *  along with GNU Make; see the file COPYING.  If not, write to\r
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.\r
18  *  http://www.gnu.org/copyleft/gpl.html\r
19  *\r
20  */\r
21 \r
22 #include "stdafx.h"\r
23 #include "GUIDialogSmartPlaylistRule.h"\r
24 #include "GUIDialogKeyboard.h"\r
25 #include "GUIDialogNumeric.h"\r
26 #include "GUIDialogFileBrowser.h"\r
27 #include "Util.h"\r
28 #include "MusicDatabase.h"\r
29 #include "VideoDatabase.h"\r
30 \r
31 #define CONTROL_FIELD           15\r
32 #define CONTROL_OPERATOR        16\r
33 #define CONTROL_VALUE           17\r
34 #define CONTROL_OK              18\r
35 #define CONTROL_CANCEL          19\r
36 #define CONTROL_BROWSE          20\r
37 \r
38 using namespace std;\r
39 using namespace PLAYLIST;\r
40 \r
41 CGUIDialogSmartPlaylistRule::CGUIDialogSmartPlaylistRule(void)\r
42     : CGUIDialog(WINDOW_DIALOG_SMART_PLAYLIST_RULE, "SmartPlaylistRule.xml")\r
43 {\r
44   m_cancelled = false;\r
45 }\r
46 \r
47 CGUIDialogSmartPlaylistRule::~CGUIDialogSmartPlaylistRule()\r
48 {\r
49 }\r
50 \r
51 bool CGUIDialogSmartPlaylistRule::OnAction(const CAction &action)\r
52 {\r
53   if (action.wID == ACTION_PREVIOUS_MENU)\r
54     m_cancelled = true;\r
55   return CGUIDialog::OnAction(action);\r
56 }\r
57 \r
58 bool CGUIDialogSmartPlaylistRule::OnMessage(CGUIMessage& message)\r
59 {\r
60   switch ( message.GetMessage() )\r
61   {\r
62   case GUI_MSG_CLICKED:\r
63     {\r
64       int iControl = message.GetSenderId();\r
65       if (iControl == CONTROL_OK)\r
66         OnOK();\r
67       else if (iControl == CONTROL_CANCEL)\r
68         OnCancel();\r
69       else if (iControl == CONTROL_VALUE)\r
70         OnValue();\r
71       else if (iControl == CONTROL_OPERATOR)\r
72         OnOperator();\r
73       else if (iControl == CONTROL_FIELD)\r
74         OnField();\r
75       else if (iControl == CONTROL_BROWSE)\r
76         OnBrowse();\r
77       return true;\r
78     }\r
79     break;\r
80   }\r
81   return CGUIDialog::OnMessage(message);\r
82 }\r
83 \r
84 void CGUIDialogSmartPlaylistRule::OnOK()\r
85 {\r
86   m_cancelled = false;\r
87   Close();\r
88 }\r
89 \r
90 void CGUIDialogSmartPlaylistRule::OnBrowse()\r
91 {\r
92   CFileItemList items;\r
93   CMusicDatabase database;\r
94   database.Open();\r
95   CVideoDatabase videodatabase;\r
96   videodatabase.Open();\r
97 \r
98   int iLabel;\r
99   if (m_rule.m_field == CSmartPlaylistRule::FIELD_GENRE)\r
100   {\r
101     if (m_type.Equals("music") || m_type.Equals("mixed"))\r
102       database.GetGenresNav("musicdb://4/",items);\r
103     if (m_type.Equals("video") || m_type.Equals("mixed"))\r
104     {\r
105       CFileItemList items2;\r
106       videodatabase.GetGenresNav("videodb://3/1/",items2,VIDEODB_CONTENT_MUSICVIDEOS);\r
107       items.AppendPointer(items2);\r
108       items2.ClearKeepPointer();\r
109     }\r
110     if (m_type.Equals("tvshows") || m_type.Equals("episodes"))\r
111     {\r
112       CFileItemList items2;\r
113       videodatabase.GetGenresNav("videodb://3/1/",items2,VIDEODB_CONTENT_TVSHOWS);\r
114       items.AppendPointer(items2);\r
115       items2.ClearKeepPointer();\r
116     }\r
117 \r
118     iLabel = 515;\r
119   }\r
120   if (m_rule.m_field == CSmartPlaylistRule::SONG_ARTIST || m_rule.m_field == CSmartPlaylistRule::SONG_ALBUM_ARTIST)\r
121   {\r
122     if (m_type.Equals("music") || m_type.Equals("mixed"))\r
123       database.GetArtistsNav("musicdb://5/",items,-1,m_rule.m_field == CSmartPlaylistRule::SONG_ALBUM_ARTIST);\r
124     if (m_type.Equals("video") || m_type.Equals("mixed"))\r
125     {\r
126       CFileItemList items2;\r
127       videodatabase.GetMusicVideoArtistsByName("",items2);\r
128       items.Append(items2);\r
129     }\r
130     iLabel = 484;\r
131   }\r
132   if (m_rule.m_field == CSmartPlaylistRule::SONG_ALBUM)\r
133   {\r
134     if (m_type.Equals("music") || m_type.Equals("mixed"))\r
135       database.GetAlbumsNav("musicdb://6/",items,-1,-1);\r
136     if (m_type.Equals("video") || m_type.Equals("mixed"))\r
137     {\r
138       CFileItemList items2;\r
139       videodatabase.GetMusicVideoAlbumsByName("",items2);\r
140       items.Append(items2);\r
141     }\r
142     iLabel = 483;\r
143   }\r
144   // TODO: SMARTPLAYLISTS add support for different types of content + directors\r
145   if (m_rule.m_field == CSmartPlaylistRule::VIDEO_ACTOR)\r
146   { \r
147     videodatabase.GetActorsNav("",items,VIDEODB_CONTENT_TVSHOWS);\r
148     iLabel = 20337;\r
149   }\r
150 \r
151   CGUIDialogSelect* pDialog = (CGUIDialogSelect*)m_gWindowManager.GetWindow(WINDOW_DIALOG_SELECT);\r
152   pDialog->Reset();\r
153   pDialog->SetItems(&items);\r
154   CStdString strHeading;\r
155   strHeading.Format(g_localizeStrings.Get(13401),g_localizeStrings.Get(iLabel));\r
156   pDialog->SetHeading(strHeading);\r
157   pDialog->DoModal();\r
158   if (pDialog->GetSelectedLabel() > -1)\r
159   {\r
160     m_rule.m_parameter = pDialog->GetSelectedLabelText();\r
161     UpdateButtons();\r
162   }\r
163   pDialog->Reset();\r
164 }\r
165 \r
166 void CGUIDialogSmartPlaylistRule::OnCancel()\r
167 {\r
168   m_cancelled = true;\r
169   Close();\r
170 }\r
171 \r
172 void CGUIDialogSmartPlaylistRule::OnValue()\r
173 {\r
174   CStdString value(m_rule.m_parameter);\r
175   switch (GetFieldType(m_rule.m_field))\r
176   {\r
177   case TEXT_FIELD:\r
178     if (CGUIDialogKeyboard::ShowAndGetInput(value, g_localizeStrings.Get(21420), false))\r
179       m_rule.m_parameter = value;\r
180     break;\r
181   case DATE_FIELD:\r
182     if (m_rule.m_operator == CSmartPlaylistRule::OPERATOR_IN_THE_LAST)\r
183     {\r
184       if (CGUIDialogKeyboard::ShowAndGetInput(value, g_localizeStrings.Get(21420), false))\r
185         m_rule.m_parameter = value;\r
186     }\r
187     else\r
188     {\r
189       CDateTime dateTime;\r
190       dateTime.SetFromDBDate(m_rule.m_parameter);\r
191       if (dateTime < CDateTime(2000,1, 1, 0, 0, 0))\r
192         dateTime = CDateTime(2000, 1, 1, 0, 0, 0);\r
193       SYSTEMTIME date;\r
194       dateTime.GetAsSystemTime(date);\r
195       if (CGUIDialogNumeric::ShowAndGetDate(date, g_localizeStrings.Get(21420)))\r
196       {\r
197         dateTime = CDateTime(date);\r
198         m_rule.m_parameter = dateTime.GetAsDBDate();\r
199       }\r
200     }\r
201     break;\r
202   case SECONDS_FIELD:\r
203     if (CGUIDialogNumeric::ShowAndGetSeconds(value, g_localizeStrings.Get(21420)))\r
204       m_rule.m_parameter = value;\r
205     break;\r
206   case NUMERIC_FIELD:\r
207     if (CGUIDialogNumeric::ShowAndGetNumber(value, g_localizeStrings.Get(21420)))\r
208       m_rule.m_parameter = value;\r
209     break;\r
210   case PLAYLIST_FIELD:\r
211     // use filebrowser to grab another smart playlist\r
212 \r
213     // Note: This can cause infinite loops (playlist that refers to the same playlist) but I don't\r
214     //       think there's any decent way to deal with this, as the infinite loop may be an arbitrary\r
215     //       number of playlists deep, eg playlist1 -> playlist2 -> playlist3 ... -> playlistn -> playlist1\r
216     CStdString path = "special://musicplaylists/";\r
217     if (m_type.Equals("video"))\r
218       path = "special://videoplaylists/";\r
219     if (CGUIDialogFileBrowser::ShowAndGetFile(path, ".xsp", g_localizeStrings.Get(656), path))\r
220     {\r
221       CSmartPlaylist playlist;\r
222       if (playlist.Load(path))\r
223         m_rule.m_parameter = !playlist.GetName().IsEmpty() ? playlist.GetName() : CUtil::GetTitleFromPath(path);\r
224     }\r
225     break;\r
226   }\r
227   UpdateButtons();\r
228 }\r
229 \r
230 void CGUIDialogSmartPlaylistRule::OnField()\r
231 {\r
232   CGUIMessage msg(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_FIELD);\r
233   OnMessage(msg);\r
234   m_rule.m_field = (CSmartPlaylistRule::DATABASE_FIELD)msg.GetParam1();\r
235 \r
236   UpdateButtons();\r
237 }\r
238 \r
239 void CGUIDialogSmartPlaylistRule::OnOperator()\r
240 {\r
241   CGUIMessage msg(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_OPERATOR);\r
242   OnMessage(msg);\r
243   m_rule.m_operator = (CSmartPlaylistRule::SEARCH_OPERATOR)msg.GetParam1();\r
244 \r
245   UpdateButtons();\r
246 }\r
247 \r
248 void CGUIDialogSmartPlaylistRule::UpdateButtons()\r
249 {\r
250   if (m_rule.m_parameter.size() == 0)\r
251   {\r
252     CONTROL_DISABLE(CONTROL_OK)\r
253   }\r
254   else\r
255   {\r
256     CONTROL_ENABLE(CONTROL_OK)\r
257   }\r
258 \r
259   // update the field control\r
260   CGUIMessage msg(GUI_MSG_ITEM_SELECT, GetID(), CONTROL_FIELD, m_rule.m_field);\r
261   OnMessage(msg);\r
262   CGUIMessage msg2(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_FIELD);\r
263   OnMessage(msg2);\r
264   m_rule.m_field = (CSmartPlaylistRule::DATABASE_FIELD)msg2.GetParam1();\r
265 \r
266   // and now update the operator set\r
267   CGUIMessage reset(GUI_MSG_LABEL_RESET, GetID(), CONTROL_OPERATOR);\r
268   OnMessage(reset);\r
269 \r
270   switch (GetFieldType(m_rule.m_field))\r
271   {\r
272   case TEXT_FIELD:\r
273     // text fields - add the usual comparisons\r
274     AddOperatorLabel(CSmartPlaylistRule::OPERATOR_EQUALS);\r
275     AddOperatorLabel(CSmartPlaylistRule::OPERATOR_DOES_NOT_EQUAL);\r
276     AddOperatorLabel(CSmartPlaylistRule::OPERATOR_CONTAINS);\r
277     AddOperatorLabel(CSmartPlaylistRule::OPERATOR_DOES_NOT_CONTAIN);\r
278     AddOperatorLabel(CSmartPlaylistRule::OPERATOR_STARTS_WITH);\r
279     AddOperatorLabel(CSmartPlaylistRule::OPERATOR_ENDS_WITH);\r
280     break;\r
281 \r
282   case NUMERIC_FIELD:\r
283   case SECONDS_FIELD:\r
284     // numerical fields - less than greater than\r
285     AddOperatorLabel(CSmartPlaylistRule::OPERATOR_EQUALS);\r
286     AddOperatorLabel(CSmartPlaylistRule::OPERATOR_DOES_NOT_EQUAL);\r
287     AddOperatorLabel(CSmartPlaylistRule::OPERATOR_GREATER_THAN);\r
288     AddOperatorLabel(CSmartPlaylistRule::OPERATOR_LESS_THAN);\r
289     break;\r
290 \r
291   case DATE_FIELD:\r
292     // date field\r
293     AddOperatorLabel(CSmartPlaylistRule::OPERATOR_AFTER);\r
294     AddOperatorLabel(CSmartPlaylistRule::OPERATOR_BEFORE);\r
295     AddOperatorLabel(CSmartPlaylistRule::OPERATOR_IN_THE_LAST);\r
296     AddOperatorLabel(CSmartPlaylistRule::OPERATOR_NOT_IN_THE_LAST);\r
297     break;\r
298 \r
299   case PLAYLIST_FIELD:\r
300     AddOperatorLabel(CSmartPlaylistRule::OPERATOR_EQUALS);\r
301     AddOperatorLabel(CSmartPlaylistRule::OPERATOR_DOES_NOT_EQUAL);\r
302     break;\r
303   }\r
304 \r
305   CGUIMessage select(GUI_MSG_ITEM_SELECT, GetID(), CONTROL_OPERATOR, m_rule.m_operator);\r
306   OnMessage(select);\r
307   CGUIMessage selected(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_OPERATOR);\r
308   OnMessage(selected);\r
309   m_rule.m_operator = (CSmartPlaylistRule::SEARCH_OPERATOR)selected.GetParam1();\r
310   if ((m_rule.m_field == CSmartPlaylistRule::SONG_ALBUM || m_rule.m_field == CSmartPlaylistRule::SONG_ARTIST || m_rule.m_field == CSmartPlaylistRule::FIELD_GENRE || m_rule.m_field == CSmartPlaylistRule::SONG_ALBUM_ARTIST) && (m_rule.m_operator == CSmartPlaylistRule::OPERATOR_EQUALS || m_rule.m_operator == CSmartPlaylistRule::OPERATOR_DOES_NOT_EQUAL))\r
311   {\r
312     CONTROL_ENABLE(CONTROL_BROWSE)\r
313   }\r
314   else\r
315   {\r
316     CONTROL_DISABLE(CONTROL_BROWSE)\r
317   }\r
318 \r
319   SET_CONTROL_LABEL(CONTROL_VALUE, m_rule.m_parameter);\r
320 }\r
321 \r
322 void CGUIDialogSmartPlaylistRule::AddOperatorLabel(CSmartPlaylistRule::SEARCH_OPERATOR op)\r
323 {\r
324   CGUIMessage select(GUI_MSG_LABEL_ADD, GetID(), CONTROL_OPERATOR, op);\r
325   select.SetLabel(CSmartPlaylistRule::GetLocalizedOperator(op));\r
326   OnMessage(select);\r
327 }\r
328 \r
329 void CGUIDialogSmartPlaylistRule::OnInitWindow()\r
330 {\r
331   CGUIDialog::OnInitWindow();\r
332   // add the fields to the field spincontrol\r
333   vector<CSmartPlaylistRule::DATABASE_FIELD> fields = CSmartPlaylistRule::GetFields(m_type);\r
334   for (unsigned int i = 0; i < fields.size(); i++)\r
335   {\r
336     CGUIMessage msg(GUI_MSG_LABEL_ADD, GetID(), CONTROL_FIELD, fields[i]);\r
337     msg.SetLabel(CSmartPlaylistRule::GetLocalizedField(fields[i]));\r
338     OnMessage(msg);\r
339   }\r
340   UpdateButtons();\r
341 }\r
342 \r
343 bool CGUIDialogSmartPlaylistRule::EditRule(CSmartPlaylistRule &rule, const CStdString& type)\r
344 {\r
345   CGUIDialogSmartPlaylistRule *editor = (CGUIDialogSmartPlaylistRule *)m_gWindowManager.GetWindow(WINDOW_DIALOG_SMART_PLAYLIST_RULE);\r
346   if (!editor) return false;\r
347   \r
348   editor->m_rule = rule;\r
349   editor->m_type = type;\r
350   editor->DoModal(m_gWindowManager.GetActiveWindow());\r
351   rule = editor->m_rule;\r
352   return !editor->m_cancelled;\r
353 }\r
354 \r
355 CGUIDialogSmartPlaylistRule::FIELD CGUIDialogSmartPlaylistRule::GetFieldType(CSmartPlaylistRule::DATABASE_FIELD field)\r
356 {\r
357   switch (field)\r
358   {\r
359   case CSmartPlaylistRule::FIELD_GENRE:\r
360   case CSmartPlaylistRule::SONG_ALBUM:\r
361   case CSmartPlaylistRule::SONG_ARTIST:\r
362   case CSmartPlaylistRule::SONG_ALBUM_ARTIST:\r
363   case CSmartPlaylistRule::FIELD_TITLE:\r
364   case CSmartPlaylistRule::SONG_FILENAME:\r
365   case CSmartPlaylistRule::SONG_COMMENT:\r
366     return TEXT_FIELD;\r
367 \r
368   case CSmartPlaylistRule::FIELD_YEAR:\r
369   case CSmartPlaylistRule::SONG_TRACKNUMBER:\r
370   case CSmartPlaylistRule::FIELD_PLAYCOUNT:\r
371   case CSmartPlaylistRule::FIELD_RATING:\r
372     return NUMERIC_FIELD;\r
373 \r
374   case CSmartPlaylistRule::FIELD_TIME:\r
375     return SECONDS_FIELD;\r
376 \r
377   case CSmartPlaylistRule::SONG_LASTPLAYED:\r
378     return DATE_FIELD;\r
379 \r
380   case CSmartPlaylistRule::FIELD_PLAYLIST:\r
381     return PLAYLIST_FIELD;\r
382 \r
383   default:\r
384     break;\r
385   }\r
386   return TEXT_FIELD;\r
387 }\r
388 \r