[cstdstring] demise Format, replacing with StringUtils::Format
[vuplus_xbmc] / xbmc / pvr / windows / GUIWindowPVRChannels.cpp
1 /*
2  *      Copyright (C) 2012-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 "GUIWindowPVRChannels.h"
22
23 #include "dialogs/GUIDialogFileBrowser.h"
24 #include "dialogs/GUIDialogNumeric.h"
25 #include "dialogs/GUIDialogKaiToast.h"
26 #include "dialogs/GUIDialogOK.h"
27 #include "dialogs/GUIDialogYesNo.h"
28 #include "guilib/GUIKeyboardFactory.h"
29 #include "guilib/GUIWindowManager.h"
30 #include "guilib/Key.h"
31 #include "GUIInfoManager.h"
32 #include "profiles/ProfilesManager.h"
33 #include "pvr/PVRManager.h"
34 #include "pvr/channels/PVRChannelGroupsContainer.h"
35 #include "pvr/dialogs/GUIDialogPVRGroupManager.h"
36 #include "pvr/windows/GUIWindowPVR.h"
37 #include "pvr/addons/PVRClients.h"
38 #include "pvr/timers/PVRTimers.h"
39 #include "epg/EpgContainer.h"
40 #include "settings/Settings.h"
41 #include "storage/MediaManager.h"
42 #include "utils/log.h"
43 #include "threads/SingleLock.h"
44
45 using namespace PVR;
46 using namespace EPG;
47
48 CGUIWindowPVRChannels::CGUIWindowPVRChannels(CGUIWindowPVR *parent, bool bRadio) :
49   CGUIWindowPVRCommon(parent,
50                       bRadio ? PVR_WINDOW_CHANNELS_RADIO : PVR_WINDOW_CHANNELS_TV,
51                       bRadio ? CONTROL_BTNCHANNELS_RADIO : CONTROL_BTNCHANNELS_TV,
52                       bRadio ? CONTROL_LIST_CHANNELS_RADIO: CONTROL_LIST_CHANNELS_TV)
53 {
54   m_bRadio              = bRadio;
55   m_bShowHiddenChannels = false;
56 }
57
58 CGUIWindowPVRChannels::~CGUIWindowPVRChannels(void)
59 {
60 }
61
62 void CGUIWindowPVRChannels::ResetObservers(void)
63 {
64   CSingleLock lock(m_critSection);
65   g_EpgContainer.RegisterObserver(this);
66   g_PVRTimers->RegisterObserver(this);
67   g_infoManager.RegisterObserver(this);
68 }
69
70 void CGUIWindowPVRChannels::UnregisterObservers(void)
71 {
72   CSingleLock lock(m_critSection);
73   g_EpgContainer.UnregisterObserver(this);
74   if (g_PVRTimers)
75     g_PVRTimers->UnregisterObserver(this);
76   g_infoManager.UnregisterObserver(this);
77 }
78
79 void CGUIWindowPVRChannels::GetContextButtons(int itemNumber, CContextButtons &buttons) const
80 {
81   if (itemNumber < 0 || itemNumber >= m_parent->m_vecItems->Size())
82     return;
83   CFileItemPtr pItem = m_parent->m_vecItems->Get(itemNumber);
84   CPVRChannel *channel = pItem->GetPVRChannelInfoTag();
85
86   if (pItem->GetPath() == "pvr://channels/.add.channel")
87   {
88     /* If yes show only "New Channel" on context menu */
89     buttons.Add(CONTEXT_BUTTON_ADD, 19046);                                           /* add new channel */
90   }
91   else
92   {
93     buttons.Add(CONTEXT_BUTTON_INFO, 19047);                                          /* channel info */
94     buttons.Add(CONTEXT_BUTTON_FIND, 19003);                                          /* find similar program */
95     buttons.Add(CONTEXT_BUTTON_PLAY_ITEM, 19000);                                     /* switch to channel */
96     buttons.Add(CONTEXT_BUTTON_RECORD_ITEM, channel->IsRecording() ? 19256 : 19255);  /* start/stop recording on channel */
97     buttons.Add(CONTEXT_BUTTON_SET_THUMB, 20019);                                     /* change icon */
98     buttons.Add(CONTEXT_BUTTON_GROUP_MANAGER, 19048);                                 /* group manager */
99     buttons.Add(CONTEXT_BUTTON_HIDE, m_bShowHiddenChannels ? 19049 : 19054);          /* show/hide channel */
100
101     if (m_parent->m_vecItems->Size() > 1 && !m_bShowHiddenChannels)
102       buttons.Add(CONTEXT_BUTTON_MOVE, 116);                                          /* move channel up or down */
103
104     if (m_bShowHiddenChannels || g_PVRChannelGroups->GetGroupAllTV()->GetNumHiddenChannels() > 0)
105       buttons.Add(CONTEXT_BUTTON_SHOW_HIDDEN, m_bShowHiddenChannels ? 19050 : 19051); /* show hidden/visible channels */
106
107     if (g_PVRClients->HasMenuHooks(pItem->GetPVRChannelInfoTag()->ClientID(), PVR_MENUHOOK_CHANNEL))
108       buttons.Add(CONTEXT_BUTTON_MENU_HOOKS, 19195);                                  /* PVR client specific action */
109
110     CPVRChannel *channel = pItem->GetPVRChannelInfoTag();
111     buttons.Add(CONTEXT_BUTTON_ADD_LOCK, channel->IsLocked() ? 19258 : 19257);        /* show lock/unlock channel */
112
113     buttons.Add(CONTEXT_BUTTON_FILTER, 19249);                                        /* filter channels */
114     buttons.Add(CONTEXT_BUTTON_UPDATE_EPG, 19251);                                    /* update EPG information */
115   }
116 }
117
118 bool CGUIWindowPVRChannels::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
119 {
120   if (itemNumber < 0 || itemNumber >= (int) m_parent->m_vecItems->Size())
121     return false;
122   CFileItemPtr pItem = m_parent->m_vecItems->Get(itemNumber);
123
124   return OnContextButtonPlay(pItem.get(), button) ||
125       OnContextButtonMove(pItem.get(), button) ||
126       OnContextButtonHide(pItem.get(), button) ||
127       OnContextButtonShowHidden(pItem.get(), button) ||
128       OnContextButtonSetThumb(pItem.get(), button) ||
129       OnContextButtonAdd(pItem.get(), button) ||
130       OnContextButtonInfo(pItem.get(), button) ||
131       OnContextButtonGroupManager(pItem.get(), button) ||
132       OnContextButtonFilter(pItem.get(), button) ||
133       OnContextButtonUpdateEpg(pItem.get(), button) ||
134       OnContextButtonRecord(pItem.get(), button) ||
135       OnContextButtonLock(pItem.get(), button) ||
136       CGUIWindowPVRCommon::OnContextButton(itemNumber, button);
137 }
138
139 CPVRChannelGroupPtr CGUIWindowPVRChannels::SelectedGroup(void)
140 {
141   if (!m_selectedGroup)
142     SetSelectedGroup(g_PVRManager.GetPlayingGroup(m_bRadio));
143
144   return m_selectedGroup;
145 }
146
147 void CGUIWindowPVRChannels::SetSelectedGroup(CPVRChannelGroupPtr group)
148 {
149   if (!group)
150     return;
151
152   if (m_selectedGroup)
153     m_selectedGroup->UnregisterObserver(this);
154   m_selectedGroup = group;
155   m_selectedGroup->RegisterObserver(this);
156   g_PVRManager.SetPlayingGroup(m_selectedGroup);
157 }
158
159 void CGUIWindowPVRChannels::Notify(const Observable &obs, const ObservableMessage msg)
160 {
161   if (msg == ObservableMessageChannelGroup || msg == ObservableMessageTimers || msg == ObservableMessageEpgActiveItem || msg == ObservableMessageCurrentItem)
162   {
163     if (IsVisible())
164       SetInvalid();
165     else
166       m_bUpdateRequired = true;
167   }
168   else if (msg == ObservableMessageChannelGroupReset)
169   {
170     if (IsVisible())
171       UpdateData(true);
172     else
173       m_bUpdateRequired = true;
174   }
175 }
176
177 CPVRChannelGroupPtr CGUIWindowPVRChannels::SelectNextGroup(void)
178 {
179   CPVRChannelGroupPtr currentGroup = SelectedGroup();
180   CPVRChannelGroupPtr nextGroup = currentGroup->GetNextGroup();
181   while (nextGroup && nextGroup->Size() == 0 &&
182       // break if the group matches
183       *nextGroup != *currentGroup &&
184       // or if we hit the first group
185       !nextGroup->IsInternalGroup())
186     nextGroup = nextGroup->GetNextGroup();
187
188   /* always update so users can reset the list */
189   if (nextGroup)
190   {
191     SetSelectedGroup(nextGroup);
192     UpdateData();
193   }
194
195   return m_selectedGroup;
196 }
197
198 void CGUIWindowPVRChannels::UpdateData(bool bUpdateSelectedFile /* = true */)
199 {
200   CSingleLock lock(m_critSection);
201   CLog::Log(LOGDEBUG, "CGUIWindowPVRChannels - %s - update window '%s'. set view to %d",
202       __FUNCTION__, GetName(), m_iControlList);
203   m_bUpdateRequired = false;
204
205   /* lock the graphics context while updating */
206   CSingleLock graphicsLock(g_graphicsContext);
207
208   CPVRChannelGroupPtr selectedGroup = SelectedGroup();
209
210   if (!bUpdateSelectedFile)
211     m_iSelected = m_parent->m_viewControl.GetSelectedItem();
212   else
213     m_parent->m_viewControl.SetSelectedItem(0);
214
215   m_parent->m_viewControl.SetCurrentView(m_iControlList);
216   ShowBusyItem();
217   m_parent->m_vecItems->Clear();
218
219   CPVRChannelGroupPtr currentGroup = g_PVRManager.GetPlayingGroup(m_bRadio);
220   if (!currentGroup)
221     return;
222
223   SetSelectedGroup(currentGroup);
224
225   CStdString strPath;
226   strPath = StringUtils::Format("pvr://channels/%s/%s/",
227       m_bRadio ? "radio" : "tv",
228       m_bShowHiddenChannels ? ".hidden" : currentGroup->GroupName().c_str());
229
230   m_parent->m_vecItems->SetPath(strPath);
231   m_parent->Update(m_parent->m_vecItems->GetPath());
232   m_parent->m_viewControl.SetItems(*m_parent->m_vecItems);
233
234   if (bUpdateSelectedFile)
235   {
236     if (!SelectPlayingFile())
237       m_parent->m_viewControl.SetSelectedItem(m_iSelected);
238   }
239
240   /* empty list */
241   if (m_parent->m_vecItems->Size() == 0)
242   {
243     if (m_bShowHiddenChannels)
244     {
245       /* show the visible channels instead */
246       m_bShowHiddenChannels = false;
247       graphicsLock.Leave();
248       lock.Leave();
249
250       UpdateData(bUpdateSelectedFile);
251       return;
252     }
253     else if (currentGroup->GroupID() > 0)
254     {
255       if (*currentGroup != *SelectNextGroup())
256         return;
257     }
258   }
259
260   m_parent->SetLabel(CONTROL_LABELHEADER, g_localizeStrings.Get(m_bRadio ? 19024 : 19023));
261   if (m_bShowHiddenChannels)
262     m_parent->SetLabel(CONTROL_LABELGROUP, g_localizeStrings.Get(19022));
263   else
264     m_parent->SetLabel(CONTROL_LABELGROUP, currentGroup->GroupName());
265 }
266
267 bool CGUIWindowPVRChannels::OnClickButton(CGUIMessage &message)
268 {
269   bool bReturn = false;
270
271   if (IsSelectedButton(message))
272   {
273     bReturn = true;
274     SelectNextGroup();
275   }
276
277   return bReturn;
278 }
279
280 bool CGUIWindowPVRChannels::OnClickList(CGUIMessage &message)
281 {
282   bool bReturn = false;
283
284   if (IsSelectedList(message))
285   {
286     bReturn = true;
287     int iAction = message.GetParam1();
288     int iItem = m_parent->m_viewControl.GetSelectedItem();
289
290     if (iItem < 0 || iItem >= (int) m_parent->m_vecItems->Size())
291       return bReturn;
292     CFileItemPtr pItem = m_parent->m_vecItems->Get(iItem);
293
294     /* process actions */
295     if (iAction == ACTION_SELECT_ITEM || iAction == ACTION_MOUSE_LEFT_CLICK || iAction == ACTION_PLAY)
296       ActionPlayChannel(pItem.get());
297     else if (iAction == ACTION_SHOW_INFO)
298       ShowEPGInfo(pItem.get());
299     else if (iAction == ACTION_DELETE_ITEM)
300       ActionDeleteChannel(pItem.get());
301     else if (iAction == ACTION_CONTEXT_MENU || iAction == ACTION_MOUSE_RIGHT_CLICK)
302       m_parent->OnPopupMenu(iItem);
303     else
304       bReturn = false;
305   }
306
307   return bReturn;
308 }
309
310 bool CGUIWindowPVRChannels::OnContextButtonAdd(CFileItem *item, CONTEXT_BUTTON button)
311 {
312   bool bReturn = false;
313
314   if (button == CONTEXT_BUTTON_ADD)
315   {
316     CGUIDialogOK::ShowAndGetInput(19033,0,19038,0);
317     bReturn = true;
318   }
319
320   return bReturn;
321 }
322
323 bool CGUIWindowPVRChannels::OnContextButtonGroupManager(CFileItem *item, CONTEXT_BUTTON button)
324 {
325   bool bReturn = false;
326
327   if (button == CONTEXT_BUTTON_GROUP_MANAGER)
328   {
329     ShowGroupManager();
330     bReturn = true;
331   }
332
333   return bReturn;
334 }
335
336 bool CGUIWindowPVRChannels::OnContextButtonHide(CFileItem *item, CONTEXT_BUTTON button)
337 {
338   bool bReturn = false;
339
340   if (button == CONTEXT_BUTTON_HIDE)
341   {
342     CPVRChannel *channel = item->GetPVRChannelInfoTag();
343     if (!channel || channel->IsRadio() != m_bRadio)
344       return bReturn;
345
346     CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
347     if (!pDialog)
348       return bReturn;
349
350     pDialog->SetHeading(19039);
351     pDialog->SetLine(0, "");
352     pDialog->SetLine(1, channel->ChannelName());
353     pDialog->SetLine(2, "");
354     pDialog->DoModal();
355
356     if (!pDialog->IsConfirmed())
357       return bReturn;
358
359     g_PVRManager.GetPlayingGroup(m_bRadio)->RemoveFromGroup(*channel);
360     UpdateData();
361
362     bReturn = true;
363   }
364
365   return bReturn;
366 }
367
368 bool CGUIWindowPVRChannels::OnContextButtonLock(CFileItem *item, CONTEXT_BUTTON button)
369 {
370   bool bReturn = false;
371
372   if (button == CONTEXT_BUTTON_ADD_LOCK)
373   {
374     // ask for PIN first
375     if (!g_PVRManager.CheckParentalPIN(g_localizeStrings.Get(19262).c_str()))
376       return bReturn;
377
378     CPVRChannelGroupPtr group = g_PVRChannelGroups->GetGroupAll(m_bRadio);
379     if (!group)
380       return bReturn;
381
382     group->ToggleChannelLocked(*item);
383     UpdateData();
384
385     bReturn = true;
386   }
387
388   return bReturn;
389 }
390
391 bool CGUIWindowPVRChannels::OnContextButtonInfo(CFileItem *item, CONTEXT_BUTTON button)
392 {
393   bool bReturn = false;
394
395   if (button == CONTEXT_BUTTON_INFO)
396   {
397     ShowEPGInfo(item);
398     bReturn = true;
399   }
400
401   return bReturn;
402 }
403
404 bool CGUIWindowPVRChannels::OnContextButtonMove(CFileItem *item, CONTEXT_BUTTON button)
405 {
406   bool bReturn = false;
407
408   if (button == CONTEXT_BUTTON_MOVE)
409   {
410     CPVRChannel *channel = item->GetPVRChannelInfoTag();
411     if (!channel || channel->IsRadio() != m_bRadio)
412       return bReturn;
413
414     CStdString strIndex;
415     strIndex = StringUtils::Format("%i", channel->ChannelNumber());
416     CGUIDialogNumeric::ShowAndGetNumber(strIndex, g_localizeStrings.Get(19052));
417     int newIndex = atoi(strIndex.c_str());
418
419     if (newIndex != channel->ChannelNumber())
420     {
421       g_PVRManager.GetPlayingGroup()->MoveChannel(channel->ChannelNumber(), newIndex);
422       UpdateData();
423     }
424
425     bReturn = true;
426   }
427
428   return bReturn;
429 }
430
431 bool CGUIWindowPVRChannels::OnContextButtonPlay(CFileItem *item, CONTEXT_BUTTON button)
432 {
433   bool bReturn = false;
434
435   if (button == CONTEXT_BUTTON_PLAY_ITEM)
436   {
437     /* play channel */
438     bReturn = PlayFile(item, CSettings::Get().GetBool("pvrplayback.playminimized"));
439   }
440
441   return bReturn;
442 }
443
444 bool CGUIWindowPVRChannels::OnContextButtonSetThumb(CFileItem *item, CONTEXT_BUTTON button)
445 {
446   bool bReturn = false;
447
448   if (button == CONTEXT_BUTTON_SET_THUMB)
449   {
450     if (CProfilesManager::Get().GetCurrentProfile().canWriteSources() && !g_passwordManager.IsProfileLockUnlocked())
451       return bReturn;
452     else if (!g_passwordManager.IsMasterLockUnlocked(true))
453       return bReturn;
454
455     /* setup our thumb list */
456     CFileItemList items;
457     CPVRChannel *channel = item->GetPVRChannelInfoTag();
458
459     if (!channel->IconPath().IsEmpty())
460     {
461       /* add the current thumb, if available */
462       CFileItemPtr current(new CFileItem("thumb://Current", false));
463       current->SetArt("thumb", channel->IconPath());
464       current->SetLabel(g_localizeStrings.Get(20016));
465       items.Add(current);
466     }
467     else if (item->HasArt("thumb"))
468     {
469       /* already have a thumb that the share doesn't know about - must be a local one, so we may as well reuse it */
470       CFileItemPtr current(new CFileItem("thumb://Current", false));
471       current->SetArt("thumb", item->GetArt("thumb"));
472       current->SetLabel(g_localizeStrings.Get(20016));
473       items.Add(current);
474     }
475
476     /* and add a "no thumb" entry as well */
477     CFileItemPtr nothumb(new CFileItem("thumb://None", false));
478     nothumb->SetIconImage(item->GetIconImage());
479     nothumb->SetLabel(g_localizeStrings.Get(20018));
480     items.Add(nothumb);
481
482     CStdString strThumb;
483     VECSOURCES shares;
484     if (CSettings::Get().GetString("pvrmenu.iconpath") != "")
485     {
486       CMediaSource share1;
487       share1.strPath = CSettings::Get().GetString("pvrmenu.iconpath");
488       share1.strName = g_localizeStrings.Get(19018);
489       shares.push_back(share1);
490     }
491     g_mediaManager.GetLocalDrives(shares);
492     if (!CGUIDialogFileBrowser::ShowAndGetImage(items, shares, g_localizeStrings.Get(1030), strThumb))
493       return bReturn;
494
495     if (strThumb != "thumb://Current")
496     {
497       if (strThumb == "thumb://None")
498         strThumb = "";
499
500       channel->SetIconPath(strThumb, true);
501       channel->Persist();
502       UpdateData();
503     }
504
505     bReturn = true;
506   }
507
508   return bReturn;
509 }
510
511 bool CGUIWindowPVRChannels::OnContextButtonShowHidden(CFileItem *item, CONTEXT_BUTTON button)
512 {
513   bool bReturn = false;
514
515   if (button == CONTEXT_BUTTON_SHOW_HIDDEN)
516   {
517     m_bShowHiddenChannels = !m_bShowHiddenChannels;
518     UpdateData();
519     bReturn = true;
520   }
521
522   return bReturn;
523 }
524
525 bool CGUIWindowPVRChannels::OnContextButtonFilter(CFileItem *item, CONTEXT_BUTTON button)
526 {
527   bool bReturn = false;
528
529   if (button == CONTEXT_BUTTON_FILTER)
530   {
531     CStdString filter = m_parent->GetProperty("filter").asString();
532     CGUIKeyboardFactory::ShowAndGetFilter(filter, false);
533     m_parent->OnFilterItems(filter);
534
535     bReturn = true;
536   }
537
538   return bReturn;
539 }
540
541 bool CGUIWindowPVRChannels::OnContextButtonRecord(CFileItem *item, CONTEXT_BUTTON button)
542 {
543   bool bReturn(false);
544   
545   if (button == CONTEXT_BUTTON_RECORD_ITEM)
546   {
547     CPVRChannel *channel = item->GetPVRChannelInfoTag();
548
549     if (channel)
550       return g_PVRManager.ToggleRecordingOnChannel(channel->ChannelID());
551   }
552
553   return bReturn;
554 }
555
556 bool CGUIWindowPVRChannels::OnContextButtonUpdateEpg(CFileItem *item, CONTEXT_BUTTON button)
557 {
558   bool bReturn = false;
559
560   if (button == CONTEXT_BUTTON_UPDATE_EPG)
561   {
562     CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
563     if (!pDialog)
564       return bReturn;
565
566     CPVRChannel *channel = item->GetPVRChannelInfoTag();
567     pDialog->SetHeading(19251);
568     pDialog->SetLine(0, g_localizeStrings.Get(19252));
569     pDialog->SetLine(1, channel->ChannelName());
570     pDialog->SetLine(2, "");
571     pDialog->DoModal();
572
573     if (!pDialog->IsConfirmed())
574       return bReturn;
575
576     bReturn = UpdateEpgForChannel(item);
577
578     CStdString strMessage = StringUtils::Format("%s: '%s'", g_localizeStrings.Get(bReturn ? 19253 : 19254).c_str(), channel->ChannelName().c_str());
579     CGUIDialogKaiToast::QueueNotification(bReturn ? CGUIDialogKaiToast::Info : CGUIDialogKaiToast::Error,
580         g_localizeStrings.Get(19166),
581         strMessage);
582   }
583
584   return bReturn;
585 }
586
587 void CGUIWindowPVRChannels::ShowGroupManager(void)
588 {
589   /* Load group manager dialog */
590   CGUIDialogPVRGroupManager* pDlgInfo = (CGUIDialogPVRGroupManager*)g_windowManager.GetWindow(WINDOW_DIALOG_PVR_GROUP_MANAGER);
591   if (!pDlgInfo)
592     return;
593
594   pDlgInfo->SetRadio(m_bRadio);
595   pDlgInfo->DoModal();
596
597   return;
598 }