fixed: re-saving of smart folders would actually just delete.
[xbmc:xbmc-antiquated.git] / xbmc / GUIDialogSmartPlaylistEditor.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 "GUIDialogSmartPlaylistEditor.h"\r
24 #include "GUIDialogKeyboard.h"\r
25 #include "Util.h"\r
26 #include "GUIDialogSmartPlaylistRule.h"\r
27 #include "GUIWindowManager.h"\r
28 #include "FileSystem/File.h"\r
29 #include "GUISettings.h"\r
30 #include "FileItem.h"\r
31 \r
32 #define CONTROL_HEADING         2\r
33 #define CONTROL_RULE_LIST       10\r
34 #define CONTROL_NAME            12\r
35 #define CONTROL_RULE_ADD        13\r
36 #define CONTROL_RULE_REMOVE     14\r
37 #define CONTROL_RULE_EDIT       15\r
38 #define CONTROL_MATCH           16\r
39 #define CONTROL_LIMIT           17\r
40 #define CONTROL_ORDER_FIELD     18\r
41 #define CONTROL_ORDER_DIRECTION 19\r
42 \r
43 #define CONTROL_OK              20\r
44 #define CONTROL_CANCEL          21\r
45 #define CONTROL_TYPE            22\r
46 \r
47 using namespace PLAYLIST;\r
48 \r
49 CGUIDialogSmartPlaylistEditor::CGUIDialogSmartPlaylistEditor(void)\r
50     : CGUIDialog(WINDOW_DIALOG_SMART_PLAYLIST_EDITOR, "SmartPlaylistEditor.xml")\r
51 {\r
52   m_cancelled = false;\r
53   m_ruleLabels = new CFileItemList;\r
54 }\r
55 \r
56 CGUIDialogSmartPlaylistEditor::~CGUIDialogSmartPlaylistEditor()\r
57 {\r
58   delete m_ruleLabels;\r
59 }\r
60 \r
61 bool CGUIDialogSmartPlaylistEditor::OnAction(const CAction &action)\r
62 {\r
63   if (action.wID == ACTION_PREVIOUS_MENU)\r
64     m_cancelled = true;\r
65   return CGUIDialog::OnAction(action);\r
66 }\r
67 \r
68 bool CGUIDialogSmartPlaylistEditor::OnMessage(CGUIMessage& message)\r
69 {\r
70   switch ( message.GetMessage() )\r
71   {\r
72   case GUI_MSG_CLICKED:\r
73     {\r
74       int iControl = message.GetSenderId();\r
75       int iAction = message.GetParam1();\r
76       if (iControl == CONTROL_RULE_LIST && iAction == ACTION_SELECT_ITEM || iAction == ACTION_MOUSE_LEFT_CLICK)\r
77         OnRuleList(GetSelectedItem());\r
78       else if (iControl == CONTROL_RULE_ADD)\r
79         OnRuleAdd();\r
80       else if (iControl == CONTROL_RULE_EDIT)\r
81         OnRuleList(GetSelectedItem());\r
82       else if (iControl == CONTROL_RULE_REMOVE)\r
83         OnRuleRemove(GetSelectedItem());\r
84       else if (iControl == CONTROL_NAME)\r
85         OnName();\r
86       else if (iControl == CONTROL_OK)\r
87         OnOK();\r
88       else if (iControl == CONTROL_CANCEL)\r
89         OnCancel();\r
90       else if (iControl == CONTROL_MATCH)\r
91         OnMatch();\r
92       else if (iControl == CONTROL_LIMIT)\r
93         OnLimit();\r
94       else if (iControl == CONTROL_ORDER_FIELD)\r
95         OnOrder();\r
96       else if (iControl == CONTROL_ORDER_DIRECTION)\r
97         OnOrderDirection();\r
98       else if (iControl == CONTROL_TYPE)\r
99         OnType();\r
100       else\r
101         return CGUIDialog::OnMessage(message);\r
102       return true;\r
103     }\r
104     break;\r
105   case GUI_MSG_WINDOW_INIT:\r
106     {\r
107       m_cancelled = false;\r
108       UpdateButtons();\r
109     }\r
110     break;\r
111   case GUI_MSG_WINDOW_DEINIT:\r
112     {\r
113       CGUIDialog::OnMessage(message);\r
114       // clear the rule list\r
115       CGUIMessage msg(GUI_MSG_LABEL_RESET, GetID(), CONTROL_RULE_LIST);\r
116       OnMessage(msg);\r
117       m_ruleLabels->Clear();\r
118     }\r
119     break;\r
120   case GUI_MSG_FOCUSED:\r
121     if (message.GetControlId() == CONTROL_RULE_REMOVE ||\r
122         message.GetControlId() == CONTROL_RULE_EDIT)\r
123       HighlightItem(GetSelectedItem());\r
124     else\r
125       HighlightItem(-1);\r
126     break;\r
127   }\r
128   return CGUIDialog::OnMessage(message);\r
129 }\r
130 \r
131 void CGUIDialogSmartPlaylistEditor::OnRuleList(int item)\r
132 {\r
133   if (item < 0 || item >= (int)m_playlist.m_playlistRules.size()) return;\r
134 \r
135   CSmartPlaylistRule rule = m_playlist.m_playlistRules[item];\r
136 \r
137   if (CGUIDialogSmartPlaylistRule::EditRule(rule,m_playlist.GetType()))\r
138     m_playlist.m_playlistRules[item] = rule;\r
139 \r
140   UpdateButtons();\r
141 }\r
142 \r
143 void CGUIDialogSmartPlaylistEditor::OnName()\r
144 {\r
145   CGUIDialogKeyboard::ShowAndGetInput(m_playlist.m_playlistName, g_localizeStrings.Get(1022), false);\r
146   UpdateButtons();\r
147 }\r
148 \r
149 void CGUIDialogSmartPlaylistEditor::OnOK()\r
150 {\r
151   // save our playlist\r
152   if (m_path.IsEmpty())\r
153   {\r
154     CStdString filename(m_playlist.m_playlistName);\r
155     CStdString path;\r
156     if (CGUIDialogKeyboard::ShowAndGetInput(filename, g_localizeStrings.Get(16013), false))\r
157     {\r
158       CStdString strTmp;\r
159       if (m_playlist.m_playlistType != "music")\r
160         CUtil::AddFileToFolder("video",filename,strTmp);\r
161       CUtil::AddFileToFolder(g_guiSettings.GetString("system.playlistspath"),strTmp,path);\r
162     }\r
163     else\r
164       return;\r
165     if (CUtil::GetExtension(path) != ".xsp")\r
166       path += ".xsp";\r
167 \r
168     // should we check whether we should overwrite?\r
169     m_path = path;\r
170   }\r
171   else\r
172   {\r
173     if (m_path.Left(g_guiSettings.GetString("system.playlistspath").size()).Equals(g_guiSettings.GetString("system.playlistspath"))) // fugly, well aware\r
174     {\r
175       CStdString filename = CUtil::GetFileName(m_path);\r
176       CStdString strType = m_path.Mid(g_guiSettings.GetString("system.playlistspath").size(),m_path.size()-filename.size()-g_guiSettings.GetString("system.playlistspath").size()-1);\r
177       // TODO: This probably needs to be rethought somewhat - ideally we'd just have a couple of folders involved, \r
178       //       as they're really "smart folders" more than playlists at this point\r
179       if ((strType == "music" || strType == "video" || strType == "mixed") && strType != m_playlist.m_playlistType &&\r
180           (m_playlist.m_playlistType == "music" || m_playlist.m_playlistType == "video" || m_playlist.m_playlistType == "mixed"))\r
181       { // significant type change, move to the correct folder\r
182         XFILE::CFile::Delete(m_path);\r
183         CStdString strTmp;\r
184         CUtil::AddFileToFolder(m_playlist.m_playlistType,filename,strTmp);\r
185         CUtil::AddFileToFolder(g_guiSettings.GetString("system.playlistspath"),strTmp,m_path);\r
186       }\r
187     }\r
188   }\r
189 \r
190   m_playlist.Save(m_path);\r
191 \r
192   m_cancelled = false;\r
193   Close();\r
194 }\r
195 \r
196 void CGUIDialogSmartPlaylistEditor::OnCancel()\r
197 {\r
198   m_cancelled = true;\r
199   Close();\r
200 }\r
201 \r
202 void CGUIDialogSmartPlaylistEditor::OnMatch()\r
203 {\r
204   CGUIMessage msg(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_MATCH);\r
205   OnMessage(msg);\r
206   m_playlist.m_matchAllRules = (msg.GetParam1() == 0);\r
207   UpdateButtons();\r
208 }\r
209 \r
210 void CGUIDialogSmartPlaylistEditor::OnLimit()\r
211 {\r
212   CGUIMessage msg(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_LIMIT);\r
213   OnMessage(msg);\r
214   m_playlist.m_limit = msg.GetParam1();\r
215   UpdateButtons();\r
216 }\r
217 \r
218 void CGUIDialogSmartPlaylistEditor::OnType()\r
219 {\r
220   CGUIMessage msg(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_TYPE);\r
221   OnMessage(msg);\r
222   if (msg.GetParam1() == 1)\r
223     m_playlist.SetType("music");\r
224   if (msg.GetParam1() == 2)\r
225       m_playlist.SetType("musicvideos");\r
226   if (msg.GetParam1() == 3)\r
227     m_playlist.SetType("mixed");\r
228   if (msg.GetParam1() == 4)\r
229     m_playlist.SetType("tvshows");\r
230   if (msg.GetParam1() == 5)\r
231     m_playlist.SetType("episodes");\r
232   if (msg.GetParam1() == 6)\r
233     m_playlist.SetType("movies");\r
234   UpdateButtons();\r
235 }\r
236 \r
237 void CGUIDialogSmartPlaylistEditor::OnOrder()\r
238 {\r
239   CGUIMessage msg(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_ORDER_FIELD);\r
240   OnMessage(msg);\r
241   m_playlist.m_orderField = (CSmartPlaylistRule::DATABASE_FIELD)msg.GetParam1();\r
242   UpdateButtons();\r
243 }\r
244 \r
245 void CGUIDialogSmartPlaylistEditor::OnOrderDirection()\r
246 {\r
247   m_playlist.m_orderAscending = !m_playlist.m_orderAscending;\r
248   UpdateButtons();\r
249 }\r
250 \r
251 void CGUIDialogSmartPlaylistEditor::UpdateButtons()\r
252 {\r
253   CONTROL_ENABLE(CONTROL_OK) // always enabled since we can have no rules -> match everything (as we do with default partymode playlists)\r
254 \r
255   if (m_playlist.m_playlistRules.size() <= 1)\r
256   {\r
257     CONTROL_DISABLE(CONTROL_RULE_REMOVE)\r
258     CONTROL_DISABLE(CONTROL_MATCH)\r
259   }\r
260   else\r
261   {\r
262     CONTROL_ENABLE(CONTROL_RULE_REMOVE)\r
263     CONTROL_ENABLE(CONTROL_MATCH)\r
264   }\r
265   // name\r
266   SET_CONTROL_LABEL(CONTROL_NAME, m_playlist.m_playlistName)\r
267 \r
268   int currentItem = GetSelectedItem();\r
269   CGUIMessage msgReset(GUI_MSG_LABEL_RESET, GetID(), CONTROL_RULE_LIST);\r
270   OnMessage(msgReset);\r
271   m_ruleLabels->Clear();\r
272   for (unsigned int i = 0; i < m_playlist.m_playlistRules.size(); i++)\r
273   {\r
274     CFileItem* item = new CFileItem("", false);\r
275     if (m_playlist.m_playlistRules[i].m_field == CSmartPlaylistRule::FIELD_NONE)\r
276       item->SetLabel(g_localizeStrings.Get(21423));\r
277     else\r
278       item->SetLabel(m_playlist.m_playlistRules[i].GetLocalizedRule());\r
279     m_ruleLabels->Add(item);\r
280     CGUIMessage msg(GUI_MSG_LABEL_ADD, GetID(), CONTROL_RULE_LIST, 0, 0, (void*)item);\r
281     OnMessage(msg);\r
282   }\r
283   CGUIMessage msg(GUI_MSG_ITEM_SELECT, GetID(), CONTROL_RULE_LIST, currentItem);\r
284   OnMessage(msg);\r
285 \r
286   if (m_playlist.m_orderAscending)\r
287   {\r
288     CONTROL_SELECT(CONTROL_ORDER_DIRECTION);\r
289   }\r
290   else\r
291   {\r
292     CONTROL_DESELECT(CONTROL_ORDER_DIRECTION);\r
293   }\r
294 }\r
295 \r
296 void CGUIDialogSmartPlaylistEditor::OnWindowLoaded()\r
297 {\r
298   CGUIDialog::OnWindowLoaded();\r
299   // setup the match spinner\r
300   {\r
301     CGUIMessage msg(GUI_MSG_LABEL_ADD, GetID(), CONTROL_MATCH, 0);\r
302     msg.SetLabel(21425);\r
303     OnMessage(msg);\r
304   }\r
305   {\r
306     CGUIMessage msg(GUI_MSG_LABEL_ADD, GetID(), CONTROL_MATCH, 1);\r
307     msg.SetLabel(21426);\r
308     OnMessage(msg);\r
309   }\r
310   {\r
311     CGUIMessage msg(GUI_MSG_ITEM_SELECT, GetID(), CONTROL_MATCH, m_playlist.m_matchAllRules ? 0 : 1);\r
312     OnMessage(msg);\r
313   }\r
314   // and now the limit spinner\r
315   {\r
316     CGUIMessage msg(GUI_MSG_LABEL_ADD, GetID(), CONTROL_LIMIT, 0);\r
317     msg.SetLabel(21428);\r
318     OnMessage(msg);\r
319   }\r
320   const int limits[] = { 10, 25, 50, 100, 250, 500, 1000 };\r
321   for (unsigned int i = 0; i < sizeof(limits) / sizeof(int); i++)\r
322   {\r
323     CGUIMessage msg(GUI_MSG_LABEL_ADD, GetID(), CONTROL_LIMIT, limits[i]);\r
324     CStdString label; label.Format(g_localizeStrings.Get(21436).c_str(), limits[i]);\r
325     msg.SetLabel(label);\r
326     OnMessage(msg);\r
327   }\r
328   {\r
329     CGUIMessage msg(GUI_MSG_ITEM_SELECT, GetID(), CONTROL_LIMIT, m_playlist.m_limit);\r
330     OnMessage(msg);\r
331   }\r
332   // and the order by spinner\r
333   for (int field = CSmartPlaylistRule::FIELD_NONE; field <= CSmartPlaylistRule::FIELD_RANDOM; field++)\r
334   {\r
335     CGUIMessage msg(GUI_MSG_LABEL_ADD, GetID(), CONTROL_ORDER_FIELD, field);\r
336     msg.SetLabel(CSmartPlaylistRule::GetLocalizedField((CSmartPlaylistRule::DATABASE_FIELD)field));\r
337     OnMessage(msg);\r
338   }\r
339   {\r
340     CGUIMessage msg(GUI_MSG_ITEM_SELECT, GetID(), CONTROL_ORDER_FIELD, m_playlist.m_orderField);\r
341     OnMessage(msg);\r
342   }\r
343   // type\r
344   if (m_playlist.GetType().Equals("tvshows"))\r
345   {\r
346     CGUIMessage msg(GUI_MSG_LABEL_ADD, GetID(), CONTROL_TYPE, 4);\r
347     CStdString label = g_localizeStrings.Get(20343);    // tvshows\r
348     msg.SetLabel(label);\r
349     OnMessage(msg);\r
350     CGUIMessage msg2(GUI_MSG_ITEM_SELECT, GetID(), CONTROL_TYPE, 4);\r
351     OnMessage(msg2);\r
352     return;\r
353   }\r
354   else if (m_playlist.GetType().Equals("episodes"))\r
355   {\r
356     CGUIMessage msg(GUI_MSG_LABEL_ADD, GetID(), CONTROL_TYPE, 5);\r
357     CStdString label = g_localizeStrings.Get(20360);    // episodes\r
358     msg.SetLabel(label);\r
359     OnMessage(msg);\r
360     CGUIMessage msg2(GUI_MSG_ITEM_SELECT, GetID(), CONTROL_TYPE, 5);\r
361     OnMessage(msg2);\r
362     return;\r
363   }\r
364   else if (m_playlist.GetType().Equals("movies"))\r
365   {\r
366     CGUIMessage msg(GUI_MSG_LABEL_ADD, GetID(), CONTROL_TYPE, 6);\r
367     CStdString label = g_localizeStrings.Get(342);    // movies\r
368     msg.SetLabel(label);\r
369     OnMessage(msg);\r
370     CGUIMessage msg2(GUI_MSG_ITEM_SELECT, GetID(), CONTROL_TYPE, 6);\r
371     OnMessage(msg2);\r
372     return;\r
373   }\r
374   if (m_isPartyMode != 2)\r
375   {\r
376     CGUIMessage msg(GUI_MSG_LABEL_ADD, GetID(), CONTROL_TYPE, 1);\r
377     CStdString label = g_localizeStrings.Get(2);    // music\r
378     msg.SetLabel(label);\r
379     OnMessage(msg);\r
380   }\r
381   if (m_isPartyMode != 1)\r
382   {\r
383     CGUIMessage msg(GUI_MSG_LABEL_ADD, GetID(), CONTROL_TYPE, 2);\r
384     CStdString label = g_localizeStrings.Get(3);    // video (music video!)\r
385     msg.SetLabel(label);\r
386     OnMessage(msg);\r
387   }\r
388   {\r
389     CGUIMessage msg(GUI_MSG_LABEL_ADD, GetID(), CONTROL_TYPE, 3);\r
390     CStdString label= g_localizeStrings.Get(20395); // mixed\r
391     msg.SetLabel(label);\r
392     OnMessage(msg);\r
393   }\r
394   {\r
395     int iType=1;\r
396     if (m_playlist.GetType().Equals("music"))\r
397     {\r
398       if (m_isPartyMode == 2) // unallowed type - reset to video\r
399       {\r
400         m_playlist.SetType("musicvideos");\r
401         iType = 2;\r
402       }\r
403     }\r
404     if (m_playlist.GetType().Equals("musicvideos"))\r
405     {\r
406       if (m_isPartyMode == 1) // unallowed type - reset to music\r
407       {\r
408         m_playlist.SetType("music");\r
409         iType = 1;\r
410       }\r
411       else \r
412         iType = 2;\r
413     }\r
414     if (m_playlist.GetType().Equals("mixed"))\r
415       iType = 3;\r
416 \r
417     CGUIMessage msg(GUI_MSG_ITEM_SELECT, GetID(), CONTROL_TYPE, iType);\r
418     OnMessage(msg);\r
419   }\r
420 \r
421 }\r
422 \r
423 int CGUIDialogSmartPlaylistEditor::GetSelectedItem()\r
424 {\r
425   CGUIMessage message(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_RULE_LIST);\r
426   OnMessage(message);\r
427   return message.GetParam1();\r
428 }\r
429 \r
430 void CGUIDialogSmartPlaylistEditor::HighlightItem(int item)\r
431 {\r
432   for (int i = 0; i < m_ruleLabels->Size(); i++)\r
433     (*m_ruleLabels)[i]->Select(false);\r
434   if (item >= 0 && item < m_ruleLabels->Size())\r
435     (*m_ruleLabels)[item]->Select(true);\r
436   CGUIMessage msg(GUI_MSG_ITEM_SELECT, GetID(), CONTROL_RULE_LIST, item);\r
437   OnMessage(msg);\r
438 }\r
439 \r
440 void CGUIDialogSmartPlaylistEditor::OnRuleRemove(int item)\r
441 {\r
442   if (item < 0 || item >= (int)m_playlist.m_playlistRules.size()) return;\r
443   m_playlist.m_playlistRules.erase(m_playlist.m_playlistRules.begin() + item);\r
444 \r
445   UpdateButtons();\r
446   if (item >= m_ruleLabels->Size())\r
447     HighlightItem(m_ruleLabels->Size() - 1);\r
448   else\r
449     HighlightItem(item);\r
450   if (m_ruleLabels->Size() <= 1)\r
451   {\r
452     SET_CONTROL_FOCUS(CONTROL_RULE_ADD, 0);\r
453   }\r
454 }\r
455 \r
456 void CGUIDialogSmartPlaylistEditor::OnRuleAdd()\r
457 {\r
458   CSmartPlaylistRule rule;\r
459   if (CGUIDialogSmartPlaylistRule::EditRule(rule,m_playlist.GetType()))\r
460   {\r
461     if (m_playlist.m_playlistRules.size() == 1 && m_playlist.m_playlistRules[0].m_field == CSmartPlaylistRule::FIELD_NONE)\r
462       m_playlist.m_playlistRules[0] = rule;\r
463     else\r
464       m_playlist.m_playlistRules.push_back(rule);\r
465   }\r
466   UpdateButtons();\r
467 }\r
468 \r
469 bool CGUIDialogSmartPlaylistEditor::NewPlaylist(const CStdString &type)\r
470 {\r
471   CGUIDialogSmartPlaylistEditor *editor = (CGUIDialogSmartPlaylistEditor *)m_gWindowManager.GetWindow(WINDOW_DIALOG_SMART_PLAYLIST_EDITOR);\r
472   if (!editor) return false;\r
473 \r
474   editor->m_path = "";\r
475   editor->m_playlist = CSmartPlaylist();\r
476   editor->m_playlist.m_playlistRules.push_back(CSmartPlaylistRule());\r
477   editor->m_playlist.SetType(type);\r
478   editor->m_isPartyMode = 0;\r
479   editor->Initialize();\r
480   editor->DoModal(m_gWindowManager.GetActiveWindow());\r
481   return !editor->m_cancelled;\r
482 }\r
483 \r
484 bool CGUIDialogSmartPlaylistEditor::EditPlaylist(const CStdString &path)\r
485 {\r
486   CGUIDialogSmartPlaylistEditor *editor = (CGUIDialogSmartPlaylistEditor *)m_gWindowManager.GetWindow(WINDOW_DIALOG_SMART_PLAYLIST_EDITOR);\r
487   if (!editor) return false;\r
488 \r
489   editor->m_isPartyMode = 0;\r
490   if (path.Equals("P:\\PartyMode.xsp"))\r
491     editor->m_isPartyMode = 1;\r
492   if (path.Equals("P:\\PartyMode-Video.xsp"))\r
493     editor->m_isPartyMode = 2;\r
494 \r
495   CSmartPlaylist playlist;\r
496   bool loaded(playlist.Load(path));\r
497   if (!loaded)\r
498   { // failed to load\r
499     if (editor->m_isPartyMode == 0)\r
500       return false; // only edit normal playlists that exist\r
501     // party mode playlists can be editted even if they don't exist\r
502     playlist.m_playlistRules.push_back(CSmartPlaylistRule());\r
503     playlist.SetType(editor->m_isPartyMode == 1 ? "music" : "video");\r
504   }\r
505 \r
506   editor->m_playlist = playlist;\r
507   editor->m_path = path;\r
508   editor->Initialize();\r
509   editor->DoModal(m_gWindowManager.GetActiveWindow());\r
510   return !editor->m_cancelled;\r
511 }\r