Merge pull request #4314 from MartijnKaijser/beta1
[vuplus_xbmc] / xbmc / settings / dialogs / GUIDialogContentSettings.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://xbmc.org
4  *
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.
9  *
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.
14  *
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/>.
18  *
19  */
20
21 #include "GUIDialogContentSettings.h"
22 #include "addons/GUIDialogAddonSettings.h"
23 #include "guilib/GUIWindowManager.h"
24 #include "guilib/Key.h"
25 #include "addons/IAddon.h"
26 #include "FileItem.h"
27 #include "video/VideoDatabase.h"
28 #include "video/VideoInfoScanner.h"
29 #include "interfaces/Builtins.h"
30 #include "filesystem/AddonsDirectory.h"
31 #include "dialogs/GUIDialogKaiToast.h"
32
33 #include <climits>
34
35 #define CONTROL_CONTENT_TYPE        3
36 #define CONTROL_SCRAPER_LIST        4
37 #define CONTROL_SCRAPER_SETTINGS    6
38 #define CONTROL_START              30
39
40 using namespace std;
41 using namespace ADDON;
42
43 CGUIDialogContentSettings::CGUIDialogContentSettings(void)
44   : CGUIDialogSettings(WINDOW_DIALOG_CONTENT_SETTINGS, "DialogContentSettings.xml"), m_origContent(CONTENT_NONE)
45 {
46   m_bNeedSave = false;
47   m_bShowScanSettings = false;
48   m_bScanRecursive = false;
49   m_bUseDirNames = false;
50   m_bSingleItem = false;
51   m_bExclude = false;
52   m_bNoUpdate = false;
53   m_content = CONTENT_NONE;
54   m_vecItems = new CFileItemList;
55 }
56
57 CGUIDialogContentSettings::~CGUIDialogContentSettings(void)
58 {
59   delete m_vecItems;
60 }
61
62 bool CGUIDialogContentSettings::OnMessage(CGUIMessage &message)
63 {
64   switch (message.GetMessage())
65   {
66   case GUI_MSG_WINDOW_DEINIT:
67     {
68       m_scrapers.clear();
69       m_vecItems->Clear();
70       CGUIDialogSettings::OnMessage(message);
71     }
72     break;
73
74   case GUI_MSG_CLICKED:
75     int iControl = message.GetSenderId();
76
77     if (iControl == CONTROL_CONTENT_TYPE)
78     {
79       CGUIMessage msg(GUI_MSG_ITEM_SELECTED,GetID(), CONTROL_CONTENT_TYPE);
80       g_windowManager.SendMessage(msg);
81       m_content = (CONTENT_TYPE) msg.GetParam1();
82       SetupPage();
83     }
84     if (iControl == CONTROL_SCRAPER_LIST)
85     {
86       // we handle only select actions
87       int action = message.GetParam1();
88       if (!(action == ACTION_SELECT_ITEM || action == ACTION_MOUSE_LEFT_CLICK))
89         break;
90
91       CGUIMessage msg(GUI_MSG_ITEM_SELECTED,GetID(), CONTROL_SCRAPER_LIST);
92       g_windowManager.SendMessage(msg);
93       int iSelected = msg.GetParam1();
94       if (iSelected == m_vecItems->Size() - 1)
95       { // Get More... item, path 'addons://more/<content>'
96         // This is tricky - ideally we want to completely save the state of this dialog,
97         // close it while linking to the addon manager, then reopen it on return.
98         // For now, we just close the dialog + send the GetPath() to open the addons window
99         CStdString content = m_vecItems->Get(iSelected)->GetPath().substr(14);
100         OnCancel();
101         Close();
102         CBuiltins::Execute("ActivateWindow(AddonBrowser,addons://all/xbmc.metadata.scraper." + content + ",return)");
103         return true;
104       }
105       AddonPtr last = m_scraper;
106       m_scraper = m_scrapers[m_content][iSelected];
107       m_lastSelected[m_content] = m_scraper;
108
109       if (m_scraper != last)
110         SetupPage();
111
112       if (m_scraper != last)
113         m_bNeedSave = true;
114       CONTROL_ENABLE_ON_CONDITION(CONTROL_SCRAPER_SETTINGS, m_scraper->HasSettings());
115       SET_CONTROL_FOCUS(CONTROL_START,0);
116     }
117     if (iControl == CONTROL_SCRAPER_SETTINGS)
118     {
119       if (CGUIDialogAddonSettings::ShowAndGetInput(m_scraper, false))
120         m_bNeedSave = true;
121       return m_bNeedSave;
122     }
123   }
124   return CGUIDialogSettings::OnMessage(message);
125 }
126
127 void CGUIDialogContentSettings::SetupPage()
128 {
129   CGUIMessage msgReset(GUI_MSG_LABEL_RESET, GetID(), CONTROL_SCRAPER_LIST);
130   OnMessage(msgReset);
131   m_vecItems->Clear();
132   if (m_content == CONTENT_NONE)
133   {
134     m_bShowScanSettings = false;
135     SET_CONTROL_HIDDEN(CONTROL_SCRAPER_LIST);
136     CONTROL_DISABLE(CONTROL_SCRAPER_SETTINGS);
137   }
138   else
139   {
140     FillListControl();
141     SET_CONTROL_VISIBLE(CONTROL_SCRAPER_LIST);
142     if (m_scraper && m_scraper->Enabled())
143     {
144       m_bShowScanSettings = true;
145       ScraperPtr scraper = boost::dynamic_pointer_cast<CScraper>(m_scraper);
146       if (scraper && scraper->Supports(m_content) && scraper->HasSettings())
147         CONTROL_ENABLE(CONTROL_SCRAPER_SETTINGS);
148     }
149     else
150       CONTROL_DISABLE(CONTROL_SCRAPER_SETTINGS);
151   }
152
153   CreateSettings();
154   CGUIDialogSettings::SetupPage();
155   SET_CONTROL_VISIBLE(CONTROL_CONTENT_TYPE);
156 }
157
158 void CGUIDialogContentSettings::CreateSettings()
159 {
160   // crappy setting dependencies part 1
161   m_settings.clear();
162   switch (m_content)
163   {
164   case CONTENT_TVSHOWS:
165     {
166       AddBool(1,20379,&m_bSingleItem, m_bShowScanSettings);
167       AddBool(2,20432,&m_bNoUpdate, m_bShowScanSettings);
168     }
169     break;
170   case CONTENT_MOVIES:
171     {
172       AddBool(1,20329,&m_bUseDirNames, m_bShowScanSettings);
173       AddBool(2,20346,&m_bScanRecursive, m_bShowScanSettings && ((m_bUseDirNames && !m_bSingleItem) || !m_bUseDirNames));
174       AddBool(3,20383,&m_bSingleItem, m_bShowScanSettings && (m_bUseDirNames && !m_bScanRecursive));
175       AddBool(4,20432,&m_bNoUpdate, m_bShowScanSettings);
176     }
177     break;
178   case CONTENT_MUSICVIDEOS:
179     {
180       AddBool(1,20330,&m_bUseDirNames, m_bShowScanSettings);
181       AddBool(2,20346,&m_bScanRecursive, m_bShowScanSettings && ((m_bUseDirNames && !m_bSingleItem) || !m_bUseDirNames));
182       AddBool(3,20383,&m_bSingleItem, m_bShowScanSettings && (m_bUseDirNames && !m_bScanRecursive));
183       AddBool(4,20432,&m_bNoUpdate, m_bShowScanSettings);
184     }
185     break;
186   case CONTENT_ALBUMS:
187   case CONTENT_ARTISTS:
188     break;
189   case CONTENT_NONE:
190   default:
191     {
192       AddBool(1,20380,&m_bExclude, !m_bShowScanSettings);
193     }
194   }
195 }
196
197 void CGUIDialogContentSettings::OnSettingChanged(SettingInfo &setting)
198 {
199   CreateSettings();
200
201   // crappy setting dependencies part 2
202   if (m_content == CONTENT_MOVIES)
203   {
204     if (setting.id == 2) // use dir names
205     {
206       m_bSingleItem = false;
207       UpdateSetting(3); // scan recursively
208       UpdateSetting(4); // single item
209     }
210     else if (setting.id == 3)
211     {
212       m_bSingleItem = false;
213       UpdateSetting(4);
214     }
215     else if (setting.id == 4)
216     {
217       m_bScanRecursive = false;
218       UpdateSetting(3);
219     }
220   }
221   m_bNeedSave = true;
222 }
223
224 void CGUIDialogContentSettings::OnOkay()
225 { // watch for content change, but same scraper
226   if (m_content != m_origContent)
227     m_bNeedSave = true;
228 }
229
230 void CGUIDialogContentSettings::OnCancel()
231 {
232   m_bNeedSave = false;
233 }
234
235 void CGUIDialogContentSettings::OnInitWindow()
236 {
237   m_lastSelected.clear();
238   // save our current scraper (if any)
239   if (m_scraper)
240     m_lastSelected[m_content] = m_scraper;
241   FillContentTypes();
242   m_bNeedSave = false;
243   CGUIDialogSettings::OnInitWindow();
244 }
245
246 void CGUIDialogContentSettings::FillContentTypes()
247 {
248   CGUIMessage msg(GUI_MSG_LABEL_RESET,GetID(),CONTROL_CONTENT_TYPE);
249   g_windowManager.SendMessage(msg);
250
251   if (m_content == CONTENT_ALBUMS || m_content == CONTENT_ARTISTS)
252   {
253     FillContentTypes(m_content);
254   }
255   else
256   {
257     FillContentTypes(CONTENT_MOVIES);
258     FillContentTypes(CONTENT_TVSHOWS);
259     FillContentTypes(CONTENT_MUSICVIDEOS);
260
261     // add 'None' to spinner
262     CGUIMessage msg2(GUI_MSG_LABEL_ADD,GetID(),CONTROL_CONTENT_TYPE);
263     msg2.SetLabel(TranslateContent(CONTENT_NONE, true));
264     msg2.SetParam1((int) CONTENT_NONE);
265     g_windowManager.SendMessage(msg2);
266   }
267
268   CONTROL_SELECT_ITEM(CONTROL_CONTENT_TYPE, (int) m_content);
269 }
270
271 void CGUIDialogContentSettings::FillContentTypes(const CONTENT_TYPE &content)
272 {
273   // grab all scrapers which support this content-type
274   VECADDONS addons;
275   TYPE type = ScraperTypeFromContent(content);
276   if (!CAddonMgr::Get().GetAddons(type, addons))
277     return;
278
279   AddonPtr addon;
280   CStdString defaultID;
281   if (CAddonMgr::Get().GetDefault(type, addon))
282     defaultID = addon->ID();
283
284   for (IVECADDONS it = addons.begin(); it != addons.end(); it++)
285   {
286     bool isDefault = ((*it)->ID() == defaultID);
287     map<CONTENT_TYPE,VECADDONS>::iterator iter=m_scrapers.find(content);
288
289     AddonPtr scraper = (*it)->Clone();
290
291     if (m_scraper && m_scraper->ID() == (*it)->ID())
292     { // don't overwrite preconfigured scraper
293       scraper = m_scraper;
294     }
295
296     if (iter != m_scrapers.end())
297     {
298       if (isDefault)
299         iter->second.insert(iter->second.begin(), scraper);
300       else
301         iter->second.push_back(scraper);
302     }
303     else
304     {
305       VECADDONS vec;
306       vec.push_back(scraper);
307       m_scrapers.insert(make_pair(content,vec));
308     }
309   }
310
311   // add CONTENT type to spinner
312   CGUIMessage msg(GUI_MSG_LABEL_ADD,GetID(),CONTROL_CONTENT_TYPE);
313   msg.SetLabel(TranslateContent(content, true));
314   msg.SetParam1((int) content);
315   g_windowManager.SendMessage(msg);
316 }
317
318 void CGUIDialogContentSettings::FillListControl()
319 {
320   int iIndex=0;
321   int selectedIndex = 0;
322
323   if (m_lastSelected.find(m_content) != m_lastSelected.end())
324     m_scraper = m_lastSelected[m_content];
325   else
326     CAddonMgr::Get().GetDefault(ScraperTypeFromContent(m_content), m_scraper);
327
328   for (IVECADDONS iter=m_scrapers.find(m_content)->second.begin();iter!=m_scrapers.find(m_content)->second.end();++iter)
329   {
330     CFileItemPtr item(new CFileItem((*iter)->Name()));
331     item->SetPath((*iter)->ID());
332     item->SetArt("thumb", (*iter)->Icon());
333     if (m_scraper && (*iter)->ID() == m_scraper->ID())
334     {
335       item->Select(true);
336       selectedIndex = iIndex;
337     }
338     m_vecItems->Add(item);
339     iIndex++;
340   }
341
342   // add the "Get More..." item
343   m_vecItems->Add(XFILE::CAddonsDirectory::GetMoreItem(TranslateContent(m_content)));
344
345   CGUIMessage msg(GUI_MSG_LABEL_BIND, GetID(), CONTROL_SCRAPER_LIST, 0, 0, m_vecItems);
346   OnMessage(msg);
347   CGUIMessage msg2(GUI_MSG_ITEM_SELECT, GetID(), CONTROL_SCRAPER_LIST, selectedIndex);
348   OnMessage(msg2);
349 }
350
351 CFileItemPtr CGUIDialogContentSettings::GetCurrentListItem(int offset)
352 {
353   int currentItem = -1;
354   if(m_bExclude)
355     return CFileItemPtr();
356   for (int i=0;i<m_vecItems->Size();++i )
357   {
358     if (m_vecItems->Get(i)->IsSelected())
359     {
360       currentItem = i;
361       break;
362     }
363   }
364
365   if (currentItem == -1)
366     return CFileItemPtr();
367
368   int item = (currentItem + offset) % m_vecItems->Size();
369   if (item < 0) item += m_vecItems->Size();
370   return m_vecItems->Get(item);
371 }
372
373 bool CGUIDialogContentSettings::ShowForDirectory(const CStdString& strDirectory, ADDON::ScraperPtr& scraper, VIDEO::SScanSettings& settings)
374 {
375   CVideoDatabase database;
376   database.Open();
377   scraper = database.GetScraperForPath(strDirectory, settings);
378   bool bResult = Show(scraper,settings);
379   if (bResult)
380     database.SetScraperForPath(strDirectory,scraper,settings);
381
382   return bResult;
383 }
384
385 bool CGUIDialogContentSettings::Show(ADDON::ScraperPtr& scraper, CONTENT_TYPE musicContext/*=CONTENT_NONE*/)
386 {
387   VIDEO::SScanSettings dummy;
388   return Show(scraper,dummy,musicContext);
389 }
390
391 bool CGUIDialogContentSettings::Show(ADDON::ScraperPtr& scraper, VIDEO::SScanSettings& settings, CONTENT_TYPE musicContext/*=CONTENT_NONE*/)
392 {
393   CGUIDialogContentSettings *dialog = (CGUIDialogContentSettings *)g_windowManager.GetWindow(WINDOW_DIALOG_CONTENT_SETTINGS);
394   if (!dialog)
395     return false;
396
397   if (scraper)
398   {
399     dialog->m_content = musicContext != CONTENT_NONE ? musicContext : scraper->Content();
400     dialog->m_origContent = dialog->m_content;
401     dialog->m_scraper = scraper;
402     // toast selected but disabled scrapers
403     if (!scraper->Enabled())
404       CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Error, g_localizeStrings.Get(24024), scraper->Name(), 2000, true);
405   }
406
407   dialog->m_bScanRecursive = (settings.recurse > 0 && !settings.parent_name) || (settings.recurse > 1 && settings.parent_name);
408   dialog->m_bUseDirNames   = settings.parent_name;
409   dialog->m_bExclude       = settings.exclude;
410   dialog->m_bSingleItem    = settings.parent_name_root;
411   dialog->m_bNoUpdate      = settings.noupdate;
412   dialog->m_bNeedSave = false;
413   dialog->DoModal();
414   if (dialog->m_bNeedSave)
415   {
416     scraper = boost::dynamic_pointer_cast<CScraper>(dialog->m_scraper);
417     CONTENT_TYPE content = dialog->m_content;
418     if (!scraper || content == CONTENT_NONE)
419     {
420       scraper.reset();
421       settings.exclude = dialog->m_bExclude;
422     }
423     else
424     {
425       settings.exclude = false;
426       settings.noupdate = dialog->m_bNoUpdate;
427       scraper->SetPathSettings(content, "");
428
429       if (content == CONTENT_TVSHOWS)
430       {
431         settings.parent_name = dialog->m_bSingleItem;
432         settings.parent_name_root = dialog->m_bSingleItem;
433         settings.recurse = 0;
434       }
435       else if (content == CONTENT_MOVIES)
436       {
437         if (dialog->m_bUseDirNames)
438         {
439           settings.parent_name = true;
440           settings.parent_name_root = false;
441           settings.recurse = dialog->m_bScanRecursive ? INT_MAX : 1;
442
443           if (dialog->m_bSingleItem)
444           {
445             settings.parent_name_root = true;
446             settings.recurse = 0;
447           }
448         }
449         else
450         {
451           settings.parent_name = false;
452           settings.parent_name_root = false;
453           settings.recurse = dialog->m_bScanRecursive ? INT_MAX : 0;
454         }
455       }
456       else if (content == CONTENT_MUSICVIDEOS)
457       {
458         if (dialog->m_bUseDirNames)
459         {
460           settings.parent_name = true;
461           settings.parent_name_root = false;
462           settings.recurse = dialog->m_bScanRecursive ? INT_MAX : 1;
463
464           if (dialog->m_bSingleItem)
465           {
466             settings.parent_name_root = true;
467             settings.recurse = 0;
468           }
469         }
470         else
471          {
472            settings.parent_name = false;
473            settings.parent_name_root = false;
474            settings.recurse = dialog->m_bScanRecursive ? INT_MAX : 0;
475          }
476       }
477     }
478   }
479
480   dialog->m_scraper.reset();
481   dialog->m_content = dialog->m_origContent = CONTENT_NONE;
482   return dialog->m_bNeedSave;
483 }
484