Merge pull request #3819 from arnova/subtitles_for_stacks
[vuplus_xbmc] / xbmc / pvr / windows / GUIWindowPVRCommon.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 "GUIWindowPVRCommon.h"
22
23 #include "Application.h"
24 #include "ApplicationMessenger.h"
25 #include "dialogs/GUIDialogKaiToast.h"
26 #include "dialogs/GUIDialogOK.h"
27 #include "dialogs/GUIDialogYesNo.h"
28 #include "filesystem/StackDirectory.h"
29 #include "guilib/GUIMessage.h"
30 #include "guilib/GUIWindowManager.h"
31 #include "guilib/Key.h"
32 #include "guilib/LocalizeStrings.h"
33 #include "pvr/PVRManager.h"
34 #include "pvr/channels/PVRChannelGroupsContainer.h"
35 #include "pvr/dialogs/GUIDialogPVRGuideInfo.h"
36 #include "pvr/dialogs/GUIDialogPVRRecordingInfo.h"
37 #include "pvr/dialogs/GUIDialogPVRTimerSettings.h"
38 #include "epg/Epg.h"
39 #include "pvr/timers/PVRTimers.h"
40 #include "pvr/addons/PVRClients.h"
41 #include "pvr/windows/GUIWindowPVR.h"
42 #include "pvr/windows/GUIWindowPVRSearch.h"
43 #include "pvr/recordings/PVRRecordings.h"
44 #include "settings/MediaSettings.h"
45 #include "settings/Settings.h"
46 #include "utils/log.h"
47 #include "utils/URIUtils.h"
48 #include "GUIUserMessages.h"
49 #include "cores/IPlayer.h"
50
51 using namespace std;
52 using namespace PVR;
53 using namespace EPG;
54
55 CGUIWindowPVRCommon::CGUIWindowPVRCommon(CGUIWindowPVR *parent, PVRWindow window,
56     unsigned int iControlButton, unsigned int iControlList)
57 {
58   m_parent          = parent;
59   m_window          = window;
60   m_iControlButton  = iControlButton;
61   m_iControlList    = iControlList;
62   m_bUpdateRequired = false;
63   m_iSelected       = 0;
64   m_iSortOrder      = SortOrderAscending;
65   m_iSortMethod     = SortByDate;
66   m_iSortAttributes = SortAttributeNone;
67   if( m_parent->GetViewState() )
68   {
69     SortDescription sorting = m_parent->GetViewState()->GetSortMethod();
70     m_iSortOrder      = sorting.sortOrder;
71     m_iSortMethod     = sorting.sortBy;
72     m_iSortAttributes = sorting.sortAttributes;
73   }
74 }
75
76 bool CGUIWindowPVRCommon::operator ==(const CGUIWindowPVRCommon &right) const
77 {
78   return (this == &right || m_window == right.m_window);
79 }
80
81 bool CGUIWindowPVRCommon::operator !=(const CGUIWindowPVRCommon &right) const
82 {
83   return !(*this == right);
84 }
85
86 const char *CGUIWindowPVRCommon::GetName(void) const
87 {
88   switch(m_window)
89   {
90   case PVR_WINDOW_EPG:
91     return "epg";
92   case PVR_WINDOW_CHANNELS_RADIO:
93     return "radio";
94   case PVR_WINDOW_CHANNELS_TV:
95     return "tv";
96   case PVR_WINDOW_RECORDINGS:
97     return "recordings";
98   case PVR_WINDOW_SEARCH:
99     return "search";
100   case PVR_WINDOW_TIMERS:
101     return "timers";
102   default:
103     return "unknown";
104   }
105 }
106
107 bool CGUIWindowPVRCommon::IsFocused(void) const
108 {
109   return !g_application.IsPlayingFullScreenVideo() &&
110       g_windowManager.GetFocusedWindow() == WINDOW_PVR &&
111       IsActive();
112 }
113
114 bool CGUIWindowPVRCommon::IsVisible(void) const
115 {
116   return !g_application.IsPlayingFullScreenVideo() &&
117       g_windowManager.GetActiveWindow() == WINDOW_PVR &&
118       IsActive();
119 }
120
121 bool CGUIWindowPVRCommon::IsActive(void) const
122 {
123   CGUIWindowPVRCommon *window = m_parent->GetActiveView();
124   return (window && *window == *this);
125 }
126
127 bool CGUIWindowPVRCommon::IsSavedView(void) const
128 {
129   CGUIWindowPVRCommon *window = m_parent->GetSavedView();
130   return (window && *window == *this);
131 }
132
133 bool CGUIWindowPVRCommon::IsSelectedButton(CGUIMessage &message) const
134 {
135   return (message.GetSenderId() == (int) m_iControlButton);
136 }
137
138 bool CGUIWindowPVRCommon::IsSelectedControl(CGUIMessage &message) const
139 {
140   return (message.GetControlId() == (int) m_iControlButton);
141 }
142
143 bool CGUIWindowPVRCommon::IsSelectedList(CGUIMessage &message) const
144 {
145   return (message.GetSenderId() == (int) m_iControlList);
146 }
147
148 void CGUIWindowPVRCommon::SetInvalid()
149 {
150   for (int iItemPtr = 0; iItemPtr < m_parent->m_vecItems->Size(); iItemPtr++)
151     m_parent->m_vecItems->Get(iItemPtr)->SetInvalid();
152   m_parent->SetInvalid();
153 }
154
155 void CGUIWindowPVRCommon::OnInitWindow()
156 {
157   m_parent->m_viewControl.SetCurrentView(m_iControlList);
158 }
159
160 bool CGUIWindowPVRCommon::SelectPlayingFile(void)
161 {
162   bool bReturn(false);
163
164   if (g_PVRManager.IsPlaying())
165   {
166     m_parent->m_viewControl.SetSelectedItem(g_application.CurrentFile());
167     bReturn = true;
168   }
169
170   return bReturn;
171 }
172
173 bool CGUIWindowPVRCommon::OnMessageFocus(CGUIMessage &message)
174 {
175   bool bReturn = false;
176
177   if (message.GetMessage() == GUI_MSG_FOCUSED &&
178       (IsSelectedControl(message) || IsSavedView()))
179   {
180     CLog::Log(LOGDEBUG, "CGUIWindowPVRCommon - %s - focus set to window '%s'", __FUNCTION__, GetName());
181     bool bIsActive = IsActive();
182     m_parent->SetActiveView(this);
183
184     if (!bIsActive || m_bUpdateRequired)
185       UpdateData();
186
187     bReturn = true;
188   }
189
190   return bReturn;
191 }
192
193 void CGUIWindowPVRCommon::OnWindowUnload(void)
194 {
195   m_iSelected = m_parent->m_viewControl.GetSelectedItem();
196   m_history = m_parent->m_history;
197 }
198
199 bool CGUIWindowPVRCommon::OnAction(const CAction &action)
200 {
201   return false; // CGUIWindowPVR will handle any default actions
202 }
203
204 bool CGUIWindowPVRCommon::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
205 {
206   if (itemNumber < 0 || itemNumber >= (int) m_parent->m_vecItems->Size())
207     return false;
208   CFileItemPtr pItem = m_parent->m_vecItems->Get(itemNumber);
209
210   return (OnContextButtonSortAsc(pItem.get(), button) ||
211       OnContextButtonSortBy(pItem.get(), button) ||
212       OnContextButtonSortByChannel(pItem.get(), button) ||
213       OnContextButtonSortByName(pItem.get(), button) ||
214       OnContextButtonSortByDate(pItem.get(), button) ||
215       OnContextButtonFind(pItem.get(), button) ||
216       OnContextButtonMenuHooks(pItem.get(), button));
217 }
218
219 bool CGUIWindowPVRCommon::OnContextButtonSortByDate(CFileItem *item, CONTEXT_BUTTON button)
220 {
221   bool bReturn = false;
222
223   if (button == CONTEXT_BUTTON_SORTBY_DATE)
224   {
225     bReturn = true;
226
227     if (m_iSortMethod != SortByDate)
228     {
229       m_iSortMethod = SortByDate;
230       m_iSortOrder  = SortOrderAscending;
231       CGUIMessage message(GUI_MSG_CHANGE_SORT_METHOD, m_parent->GetID(), 0, m_iSortMethod, 0); 
232       m_parent->OnMessage(message);
233     }
234     else
235     {
236       m_iSortOrder = m_iSortOrder == SortOrderAscending ? SortOrderDescending : SortOrderAscending;
237     }
238     CGUIMessage message(GUI_MSG_CHANGE_SORT_DIRECTION, m_parent->GetID(), 0, m_iSortOrder, 0); 
239     m_parent->OnMessage(message);
240     UpdateData();
241   }
242
243   return bReturn;
244 }
245
246 bool CGUIWindowPVRCommon::OnContextButtonSortByName(CFileItem *item, CONTEXT_BUTTON button)
247 {
248   bool bReturn = false;
249
250   if (button == CONTEXT_BUTTON_SORTBY_NAME)
251   {
252     bReturn = true;
253
254     if (m_iSortMethod != SortByLabel)
255     {
256       m_iSortMethod = SortByLabel;
257       m_iSortOrder  = SortOrderAscending;
258       CGUIMessage message(GUI_MSG_CHANGE_SORT_METHOD, m_parent->GetID(), 0, m_iSortMethod, 0); 
259       m_parent->OnMessage(message);
260     }
261     else
262     {
263       m_iSortOrder = m_iSortOrder == SortOrderAscending ? SortOrderDescending : SortOrderAscending;
264     }
265     CGUIMessage message(GUI_MSG_CHANGE_SORT_DIRECTION, m_parent->GetID(), 0, m_iSortOrder, 0); 
266     m_parent->OnMessage(message);
267     UpdateData();
268   }
269
270   return bReturn;
271 }
272
273 bool CGUIWindowPVRCommon::OnContextButtonSortByChannel(CFileItem *item, CONTEXT_BUTTON button)
274 {
275   bool bReturn = false;
276
277   if (button == CONTEXT_BUTTON_SORTBY_CHANNEL)
278   {
279     bReturn = true;
280
281     if (m_iSortMethod != SortByChannel)
282     {
283       m_iSortMethod = SortByChannel;
284       m_iSortOrder  = SortOrderAscending;
285     }
286     else
287     {
288       m_iSortOrder = m_iSortOrder == SortOrderAscending ? SortOrderDescending : SortOrderAscending;
289     }
290
291     UpdateData();
292   }
293
294   return bReturn;
295 }
296
297 bool CGUIWindowPVRCommon::OnContextButtonSortAsc(CFileItem *item, CONTEXT_BUTTON button)
298 {
299   bool bReturn = false;
300
301   if (button == CONTEXT_BUTTON_SORTASC)
302   {
303     bReturn = true;
304
305     if (m_parent->m_guiState.get())
306       m_parent->m_guiState->SetNextSortOrder();
307     m_parent->UpdateFileList();
308   }
309
310   return bReturn;
311 }
312
313 bool CGUIWindowPVRCommon::OnContextButtonSortBy(CFileItem *item, CONTEXT_BUTTON button)
314 {
315   bool bReturn = false;
316
317   if (button == CONTEXT_BUTTON_SORTBY)
318   {
319     bReturn = true;
320
321     if (m_parent->m_guiState.get())
322       m_parent->m_guiState->SetNextSortMethod();
323
324     m_parent->UpdateFileList();
325   }
326
327   return bReturn;
328 }
329
330 bool CGUIWindowPVRCommon::OnContextButtonMenuHooks(CFileItem *item, CONTEXT_BUTTON button)
331 {
332   bool bReturn = false;
333
334   if (button == CONTEXT_BUTTON_MENU_HOOKS)
335   {
336     bReturn = true;
337
338     if (item->IsEPG() && item->GetEPGInfoTag()->HasPVRChannel())
339       g_PVRClients->ProcessMenuHooks(item->GetEPGInfoTag()->ChannelTag()->ClientID(), PVR_MENUHOOK_EPG, item);
340     else if (item->IsPVRChannel())
341       g_PVRClients->ProcessMenuHooks(item->GetPVRChannelInfoTag()->ClientID(), PVR_MENUHOOK_CHANNEL, item);
342     else if (item->IsPVRRecording())
343       g_PVRClients->ProcessMenuHooks(item->GetPVRRecordingInfoTag()->m_iClientId, PVR_MENUHOOK_RECORDING, item);
344     else if (item->IsPVRTimer())
345       g_PVRClients->ProcessMenuHooks(item->GetPVRTimerInfoTag()->m_iClientId, PVR_MENUHOOK_TIMER, item);
346   }
347
348   return bReturn;
349 }
350
351 bool CGUIWindowPVRCommon::ActionDeleteTimer(CFileItem *item)
352 {
353   /* check if the timer tag is valid */
354   CPVRTimerInfoTag *timerTag = item->GetPVRTimerInfoTag();
355   if (!timerTag || timerTag->m_iClientIndex < 0)
356     return false;
357
358   /* show a confirmation dialog */
359   CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
360   if (!pDialog)
361     return false;
362   pDialog->SetHeading(122);
363   pDialog->SetLine(0, 19040);
364   pDialog->SetLine(1, "");
365   pDialog->SetLine(2, timerTag->m_strTitle);
366   pDialog->DoModal();
367
368   /* prompt for the user's confirmation */
369   if (!pDialog->IsConfirmed())
370     return false;
371
372   /* delete the timer */
373   return g_PVRTimers->DeleteTimer(*item);
374 }
375
376 bool CGUIWindowPVRCommon::ShowNewTimerDialog(void)
377 {
378   bool bReturn(false);
379
380   CPVRTimerInfoTag *newTimer = new CPVRTimerInfoTag;
381   CFileItem *newItem = new CFileItem(*newTimer);
382   if (ShowTimerSettings(newItem))
383   {
384     /* Add timer to backend */
385     bReturn = g_PVRTimers->AddTimer(*newItem->GetPVRTimerInfoTag());
386   }
387
388   delete newItem;
389   delete newTimer;
390
391   return bReturn;
392 }
393
394 bool CGUIWindowPVRCommon::ActionShowTimer(CFileItem *item)
395 {
396   bool bReturn = false;
397
398   /* Check if "Add timer..." entry is pressed by OK, if yes
399      create a new timer and open settings dialog, otherwise
400      open settings for selected timer entry */
401   if (item->GetPath() == "pvr://timers/add.timer")
402   {
403     bReturn = ShowNewTimerDialog();
404   }
405   else
406   {
407     if (ShowTimerSettings(item))
408     {
409       /* Update timer on pvr backend */
410       bReturn = g_PVRTimers->UpdateTimer(*item);
411     }
412   }
413
414   return bReturn;
415 }
416
417 bool CGUIWindowPVRCommon::ActionRecord(CFileItem *item)
418 {
419   bool bReturn = false;
420
421   CEpgInfoTag *epgTag = item->GetEPGInfoTag();
422   if (!epgTag)
423     return bReturn;
424
425   CPVRChannelPtr channel = epgTag->ChannelTag();
426   if (!channel || !g_PVRManager.CheckParentalLock(*channel))
427     return bReturn;
428
429   if (epgTag->Timer() == NULL)
430   {
431     /* create a confirmation dialog */
432     CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*) g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
433     if (!pDialog)
434       return bReturn;
435
436     pDialog->SetHeading(264);
437     pDialog->SetLine(0, "");
438     pDialog->SetLine(1, epgTag->Title());
439     pDialog->SetLine(2, "");
440     pDialog->DoModal();
441
442     /* prompt for the user's confirmation */
443     if (!pDialog->IsConfirmed())
444       return bReturn;
445
446     CPVRTimerInfoTag *newTimer = CPVRTimerInfoTag::CreateFromEpg(*epgTag);
447     if (newTimer)
448     {
449       bReturn = g_PVRTimers->AddTimer(*newTimer);
450       delete newTimer;
451     }
452     else
453     {
454       bReturn = false;
455     }
456   }
457   else
458   {
459     CGUIDialogOK::ShowAndGetInput(19033,19034,0,0);
460     bReturn = true;
461   }
462
463   return bReturn;
464 }
465
466
467 bool CGUIWindowPVRCommon::ActionDeleteRecording(CFileItem *item)
468 {
469   bool bReturn = false;
470
471   /* check if the recording tag is valid */
472   CPVRRecording *recTag = (CPVRRecording *) item->GetPVRRecordingInfoTag();
473   if (!recTag || recTag->m_strRecordingId.empty())
474     return bReturn;
475
476   /* show a confirmation dialog */
477   CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
478   if (!pDialog)
479     return bReturn;
480   pDialog->SetHeading(122);
481   pDialog->SetLine(0, 19043);
482   pDialog->SetLine(1, "");
483   pDialog->SetLine(2, recTag->m_strTitle);
484   pDialog->DoModal();
485
486   /* prompt for the user's confirmation */
487   if (!pDialog->IsConfirmed())
488     return bReturn;
489
490   /* delete the recording */
491   if (g_PVRRecordings->DeleteRecording(*item))
492   {
493     g_PVRManager.TriggerRecordingsUpdate();
494     bReturn = true;
495   }
496
497   return bReturn;
498 }
499
500 bool CGUIWindowPVRCommon::ActionPlayChannel(CFileItem *item)
501 {
502   bool bReturn = false;
503
504   if (item->GetPath() == "pvr://channels/.add.channel")
505   {
506     /* show "add channel" dialog */
507     CGUIDialogOK::ShowAndGetInput(19033,0,19038,0);
508     bReturn = true;
509   }
510   else
511   {
512     /* open channel */
513     bReturn = PlayFile(item, CSettings::Get().GetBool("pvrplayback.playminimized"));
514   }
515
516   return bReturn;
517 }
518
519 bool CGUIWindowPVRCommon::ActionPlayEpg(CFileItem *item)
520 {
521   CPVRChannelPtr channel;
522   if (item && item->HasEPGInfoTag() && item->GetEPGInfoTag()->HasPVRChannel())
523     channel = item->GetEPGInfoTag()->ChannelTag();
524   
525   if (!channel || !g_PVRManager.CheckParentalLock(*channel))
526     return false;
527   
528   CFileItem channelItem = CFileItem(*channel);
529   g_application.SwitchToFullScreen();
530   if (!PlayFile(&channelItem))
531   {
532     // CHANNELNAME could not be played. Check the log for details.
533     CStdString msg = StringUtils::Format(g_localizeStrings.Get(19035).c_str(), channel->ChannelName().c_str());
534     CGUIDialogOK::ShowAndGetInput(19033, 0, msg, 0);
535     return false;
536   }
537   
538   return true;
539 }
540
541 bool CGUIWindowPVRCommon::ActionDeleteChannel(CFileItem *item)
542 {
543   CPVRChannel *channel = item->GetPVRChannelInfoTag();
544
545   /* check if the channel tag is valid */
546   if (!channel || channel->ChannelNumber() <= 0)
547     return false;
548
549   /* show a confirmation dialog */
550   CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*) g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
551   if (!pDialog)
552     return false;
553   pDialog->SetHeading(19039);
554   pDialog->SetLine(0, "");
555   pDialog->SetLine(1, channel->ChannelName());
556   pDialog->SetLine(2, "");
557   pDialog->DoModal();
558
559   /* prompt for the user's confirmation */
560   if (!pDialog->IsConfirmed())
561     return false;
562
563   g_PVRChannelGroups->GetGroupAll(channel->IsRadio())->RemoveFromGroup(*channel);
564   UpdateData();
565
566   return true;
567 }
568
569 bool CGUIWindowPVRCommon::UpdateEpgForChannel(CFileItem *item)
570 {
571   CPVRChannel *channel = item->GetPVRChannelInfoTag();
572   CEpg *epg = channel->GetEPG();
573   if (!epg)
574     return false;
575
576   epg->ForceUpdate();
577   return true;
578 }
579
580 bool CGUIWindowPVRCommon::ShowTimerSettings(CFileItem *item)
581 {
582   /* Check item is TV timer information tag */
583   if (!item->IsPVRTimer())
584   {
585     CLog::Log(LOGERROR, "CGUIWindowPVRTimers: Can't open timer settings dialog, no timer info tag!");
586     return false;
587   }
588
589   /* Load timer settings dialog */
590   CGUIDialogPVRTimerSettings* pDlgInfo = (CGUIDialogPVRTimerSettings*)g_windowManager.GetWindow(WINDOW_DIALOG_PVR_TIMER_SETTING);
591
592   if (!pDlgInfo)
593     return false;
594
595   /* inform dialog about the file item */
596   pDlgInfo->SetTimer(item);
597
598   /* Open dialog window */
599   pDlgInfo->DoModal();
600
601   /* Get modify flag from window and return it to caller */
602   return pDlgInfo->GetOK();
603 }
604
605
606 bool CGUIWindowPVRCommon::PlayRecording(CFileItem *item, bool bPlayMinimized /* = false */)
607 {
608   if (!item->HasPVRRecordingInfoTag())
609     return false;
610
611   CStdString stream = item->GetPVRRecordingInfoTag()->m_strStreamURL;
612   if (stream == "")
613   {
614     CApplicationMessenger::Get().PlayFile(*item, false);
615     return true;
616   }
617
618   /* Isolate the folder from the filename */
619   size_t found = stream.find_last_of("/");
620   if (found == CStdString::npos)
621     found = stream.find_last_of("\\");
622
623   if (found != CStdString::npos)
624   {
625     /* Check here for asterisk at the begin of the filename */
626     if (stream[found+1] == '*')
627     {
628       /* Create a "stack://" url with all files matching the extension */
629       CStdString ext = URIUtils::GetExtension(stream);
630       CStdString dir = stream.substr(0, found).c_str();
631
632       CFileItemList items;
633       CDirectory::GetDirectory(dir, items);
634       items.Sort(SortByFile, SortOrderAscending);
635
636       vector<int> stack;
637       for (int i = 0; i < items.Size(); ++i)
638       {
639         if (URIUtils::HasExtension(items[i]->GetPath(), ext))
640           stack.push_back(i);
641       }
642
643       if (stack.size() > 0)
644       {
645         /* If we have a stack change the path of the item to it */
646         CStackDirectory dir;
647         CStdString stackPath = dir.ConstructStackPath(items, stack);
648         item->SetPath(stackPath);
649       }
650     }
651     else
652     {
653       /* If no asterisk is present play only the given stream URL */
654       item->SetPath(stream);
655     }
656   }
657   else
658   {
659     CLog::Log(LOGERROR, "PVRManager - %s - can't open recording: no valid filename", __FUNCTION__);
660     CGUIDialogOK::ShowAndGetInput(19033,0,19036,0);
661     return false;
662   }
663
664   CApplicationMessenger::Get().PlayFile(*item, false);
665
666   return true;
667 }
668
669 bool CGUIWindowPVRCommon::PlayFile(CFileItem *item, bool bPlayMinimized /* = false */)
670 {
671   if (item->m_bIsFolder)
672   {
673     return false;
674   }
675
676   if (item->GetPath() == g_application.CurrentFile())
677   {
678     CGUIMessage msg(GUI_MSG_FULLSCREEN, 0, m_parent->GetID());
679     g_windowManager.SendMessage(msg);
680     return true;
681   }
682
683   CMediaSettings::Get().SetVideoStartWindowed(bPlayMinimized);
684
685   if (item->HasPVRRecordingInfoTag())
686   {
687     return PlayRecording(item, bPlayMinimized);
688   }
689   else
690   {
691     bool bSwitchSuccessful(false);
692
693     CPVRChannel *channel = item->HasPVRChannelInfoTag() ? item->GetPVRChannelInfoTag() : NULL;
694
695     if (channel && g_PVRManager.CheckParentalLock(*channel))
696     {
697       /* try a fast switch */
698       if (channel && (g_PVRManager.IsPlayingTV() || g_PVRManager.IsPlayingRadio()) &&
699          (channel->IsRadio() == g_PVRManager.IsPlayingRadio()))
700       {
701         if (channel->StreamURL().empty())
702           bSwitchSuccessful = g_application.m_pPlayer->SwitchChannel(*channel);
703       }
704
705       if (!bSwitchSuccessful)
706       {
707         CApplicationMessenger::Get().PlayFile(*item, false);
708         return true;
709       }
710     }
711
712     if (!bSwitchSuccessful)
713     {
714       CStdString channelName = g_localizeStrings.Get(19029); // Channel
715       if (channel)
716         channelName = channel->ChannelName();
717       CStdString msg = StringUtils::Format(g_localizeStrings.Get(19035).c_str(), channelName.c_str()); // CHANNELNAME could not be played. Check the log for details.
718
719       CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Error,
720               g_localizeStrings.Get(19166), // PVR information
721               msg);
722       return false;
723     }
724   }
725
726   return true;
727 }
728
729 bool CGUIWindowPVRCommon::StartRecordFile(CFileItem *item)
730 {
731   if (!item->HasEPGInfoTag())
732     return false;
733
734   CEpgInfoTag *tag = item->GetEPGInfoTag();
735   CPVRChannelPtr channel;
736   if (tag)
737     channel = tag->ChannelTag();
738
739   if (!channel || !g_PVRManager.CheckParentalLock(*channel))
740     return false;
741
742   CFileItemPtr timer = g_PVRTimers->GetTimerForEpgTag(item);
743   if (timer && timer->HasPVRTimerInfoTag())
744   {
745     CGUIDialogOK::ShowAndGetInput(19033,19034,0,0);
746     return false;
747   }
748
749   CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
750   if (!pDialog)
751     return false;
752   pDialog->SetHeading(264);
753   pDialog->SetLine(0, tag->PVRChannelName());
754   pDialog->SetLine(1, "");
755   pDialog->SetLine(2, tag->Title());
756   pDialog->DoModal();
757
758   if (!pDialog->IsConfirmed())
759     return false;
760
761   CPVRTimerInfoTag *newTimer = CPVRTimerInfoTag::CreateFromEpg(*tag);
762   bool bReturn(false);
763   if (newTimer)
764   {
765     bReturn = g_PVRTimers->AddTimer(*newTimer);
766     delete newTimer;
767   }
768   return bReturn;
769 }
770
771 bool CGUIWindowPVRCommon::StopRecordFile(CFileItem *item)
772 {
773   if (!item->HasEPGInfoTag())
774     return false;
775
776   CEpgInfoTag *tag = item->GetEPGInfoTag();
777   if (!tag || !tag->HasPVRChannel())
778     return false;
779
780   CFileItemPtr timer = g_PVRTimers->GetTimerForEpgTag(item);
781   if (!timer || !timer->HasPVRTimerInfoTag() || timer->GetPVRTimerInfoTag()->m_bIsRepeating)
782     return false;
783
784   return g_PVRTimers->DeleteTimer(*timer);
785 }
786
787 void CGUIWindowPVRCommon::ShowEPGInfo(CFileItem *item)
788 {
789   CFileItem *tag = NULL;
790   bool bHasChannel(false);
791   CPVRChannel channel;
792   if (item->IsEPG())
793   {
794     tag = new CFileItem(*item);
795     if (item->GetEPGInfoTag()->HasPVRChannel())
796     {
797       channel = *item->GetEPGInfoTag()->ChannelTag();
798       bHasChannel = true;
799     }
800   }
801   else if (item->IsPVRChannel())
802   {
803     CEpgInfoTag epgnow;
804     channel = *item->GetPVRChannelInfoTag();
805     bHasChannel = true;
806     if (!item->GetPVRChannelInfoTag()->GetEPGNow(epgnow))
807     {
808       CGUIDialogOK::ShowAndGetInput(19033,0,19055,0);
809       return;
810     }
811     tag = new CFileItem(epgnow);
812   }
813
814   if (tag)
815   {
816     if (!bHasChannel || g_PVRManager.CheckParentalLock(channel))
817     {
818       CGUIDialogPVRGuideInfo* pDlgInfo = (CGUIDialogPVRGuideInfo*)g_windowManager.GetWindow(WINDOW_DIALOG_PVR_GUIDE_INFO);
819       if (pDlgInfo)
820       {
821         pDlgInfo->SetProgInfo(tag);
822         pDlgInfo->DoModal();
823       }
824     }
825     delete tag;
826   }
827 }
828
829 void CGUIWindowPVRCommon::ShowRecordingInfo(CFileItem *item)
830 {
831   if (!item->IsPVRRecording())
832     return;
833
834   CGUIDialogPVRRecordingInfo* pDlgInfo = (CGUIDialogPVRRecordingInfo*)g_windowManager.GetWindow(WINDOW_DIALOG_PVR_RECORDING_INFO);
835   if (!pDlgInfo)
836     return;
837
838   pDlgInfo->SetRecording(item);
839   pDlgInfo->DoModal();
840 }
841
842 bool CGUIWindowPVRCommon::OnContextButtonFind(CFileItem *item, CONTEXT_BUTTON button)
843 {
844   bool bReturn = false;
845
846   if (button == CONTEXT_BUTTON_FIND)
847   {
848     bReturn = true;
849     if (m_parent->m_windowSearch)
850     {
851       CEpgInfoTag tag;
852       m_parent->m_windowSearch->m_searchfilter.Reset();
853       if (item->IsEPG())
854         m_parent->m_windowSearch->m_searchfilter.m_strSearchTerm = "\"" + item->GetEPGInfoTag()->Title() + "\"";
855       else if (item->IsPVRChannel() && item->GetPVRChannelInfoTag()->GetEPGNow(tag))
856         m_parent->m_windowSearch->m_searchfilter.m_strSearchTerm = "\"" + tag.Title() + "\"";
857       else if (item->IsPVRRecording())
858         m_parent->m_windowSearch->m_searchfilter.m_strSearchTerm = "\"" + item->GetPVRRecordingInfoTag()->m_strTitle + "\"";
859       else if (item->IsPVRTimer())
860         m_parent->m_windowSearch->m_searchfilter.m_strSearchTerm = "\"" + item->GetPVRTimerInfoTag()->m_strTitle + "\"";
861
862       m_parent->m_windowSearch->m_bSearchConfirmed = true;
863       m_parent->SetLabel(m_iControlButton, 0);
864       m_parent->SetActiveView(m_parent->m_windowSearch);
865       m_parent->m_windowSearch->UpdateData();
866       m_parent->SetLabel(m_iControlList, 0);
867       m_parent->m_viewControl.SetFocused();
868     }
869   }
870
871   return bReturn;
872 }
873
874 void CGUIWindowPVRCommon::ShowBusyItem(void)
875 {
876   // FIXME: display a temporary entry so that the list can keep its focus
877   // busy_items has to be static, because m_viewControl holds the pointer to it
878   static CFileItemList busy_items;
879   if (busy_items.IsEmpty())
880   {
881     CFileItemPtr pItem(new CFileItem(g_localizeStrings.Get(1040)));
882     busy_items.AddFront(pItem, 0);
883   }
884   m_parent->m_viewControl.SetItems(busy_items);
885 }