[cosmetics] update date in GPL header
[vuplus_xbmc] / xbmc / pvr / windows / GUIWindowPVRGuide.cpp
1 /*
2  *      Copyright (C) 2012-2013 Team XBMC
3  *      http://www.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 "GUIWindowPVRGuide.h"
22
23 #include "Application.h"
24 #include "dialogs/GUIDialogOK.h"
25 #include "guilib/GUIWindowManager.h"
26 #include "pvr/PVRManager.h"
27 #include "pvr/channels/PVRChannelGroupsContainer.h"
28 #include "epg/EpgContainer.h"
29 #include "pvr/windows/GUIWindowPVR.h"
30 #include "settings/AdvancedSettings.h"
31 #include "settings/GUISettings.h"
32 #include "settings/Settings.h"
33 #include "threads/SingleLock.h"
34 #include "utils/log.h"
35 #include "pvr/addons/PVRClients.h"
36 #include "pvr/timers/PVRTimers.h"
37
38 using namespace PVR;
39 using namespace EPG;
40
41 CGUIWindowPVRGuide::CGUIWindowPVRGuide(CGUIWindowPVR *parent) :
42   CGUIWindowPVRCommon(parent, PVR_WINDOW_EPG, CONTROL_BTNGUIDE, CONTROL_LIST_GUIDE_NOW_NEXT),
43   Observer(),
44   m_iGuideView(g_guiSettings.GetInt("epg.defaultguideview"))
45 {
46   m_cachedTimeline = new CFileItemList;
47   m_cachedChannelGroup = CPVRChannelGroupPtr(new CPVRChannelGroup);
48 }
49
50 CGUIWindowPVRGuide::~CGUIWindowPVRGuide(void)
51 {
52   delete m_cachedTimeline;
53 }
54
55 void CGUIWindowPVRGuide::UnregisterObservers(void)
56 {
57   g_EpgContainer.UnregisterObserver(this);
58 }
59
60 void CGUIWindowPVRGuide::ResetObservers(void)
61 {
62   g_EpgContainer.RegisterObserver(this);
63 }
64
65 void CGUIWindowPVRGuide::Notify(const Observable &obs, const ObservableMessage msg)
66 {
67   if (msg == ObservableMessageEpg || msg == ObservableMessageEpgContainer)
68   {
69     m_bUpdateRequired = true;
70
71     /* update the current window if the EPG timeline view is visible */
72     if (IsFocused() && m_iGuideView == GUIDE_VIEW_TIMELINE)
73       UpdateData(false);
74   }
75   else if (msg == ObservableMessageEpgActiveItem)
76   {
77     if (IsVisible() && m_iGuideView != GUIDE_VIEW_TIMELINE)
78       SetInvalid();
79     else
80       m_bUpdateRequired = true;
81   }
82 }
83
84 void CGUIWindowPVRGuide::GetContextButtons(int itemNumber, CContextButtons &buttons) const
85 {
86   if (itemNumber < 0 || itemNumber >= m_parent->m_vecItems->Size())
87     return;
88   CFileItemPtr pItem = m_parent->m_vecItems->Get(itemNumber);
89
90   CFileItemPtr timer = g_PVRTimers->GetTimerForEpgTag(pItem.get());
91   if (timer && timer->HasPVRTimerInfoTag())
92   {
93     if (timer->GetPVRTimerInfoTag()->IsRecording())
94       buttons.Add(CONTEXT_BUTTON_STOP_RECORD, 19059);  /* stop recording */
95     else
96       buttons.Add(CONTEXT_BUTTON_STOP_RECORD, 19060);  /* delete timer */
97   }
98   else if (pItem->GetEPGInfoTag()->EndAsLocalTime() > CDateTime::GetCurrentDateTime())
99   {
100     if (pItem->GetEPGInfoTag()->StartAsLocalTime() < CDateTime::GetCurrentDateTime())
101       buttons.Add(CONTEXT_BUTTON_START_RECORD, 264);   /* record */
102     else
103       buttons.Add(CONTEXT_BUTTON_START_RECORD, 19061); /* add timer */
104   }
105
106   buttons.Add(CONTEXT_BUTTON_INFO, 19047);              /* epg info */
107   buttons.Add(CONTEXT_BUTTON_PLAY_ITEM, 19000);         /* switch channel */
108   buttons.Add(CONTEXT_BUTTON_FIND, 19003);              /* find similar program */
109   if (m_iGuideView == GUIDE_VIEW_TIMELINE)
110   {
111     buttons.Add(CONTEXT_BUTTON_BEGIN, 19063);           /* go to begin */
112     buttons.Add(CONTEXT_BUTTON_END, 19064);             /* go to end */
113   }
114   if (pItem->GetEPGInfoTag()->HasPVRChannel() &&
115       g_PVRClients->HasMenuHooks(pItem->GetEPGInfoTag()->ChannelTag()->ClientID(), PVR_MENUHOOK_EPG))
116     buttons.Add(CONTEXT_BUTTON_MENU_HOOKS, 19195);      /* PVR client specific action */
117 }
118
119
120 bool CGUIWindowPVRGuide::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
121 {
122   if (itemNumber < 0 || itemNumber >= (int) m_parent->m_vecItems->Size())
123     return false;
124   CFileItemPtr pItem = m_parent->m_vecItems->Get(itemNumber);
125
126   return OnContextButtonPlay(pItem.get(), button) ||
127       OnContextButtonInfo(pItem.get(), button) ||
128       OnContextButtonStartRecord(pItem.get(), button) ||
129       OnContextButtonStopRecord(pItem.get(), button) ||
130       OnContextButtonBegin(pItem.get(), button) ||
131       OnContextButtonEnd(pItem.get(), button) ||
132       CGUIWindowPVRCommon::OnContextButton(itemNumber, button);
133 }
134
135 void CGUIWindowPVRGuide::UpdateViewChannel(bool bUpdateSelectedFile)
136 {
137   CPVRChannelPtr CurrentChannel;
138   bool bGotCurrentChannel = g_PVRManager.GetCurrentChannel(CurrentChannel);
139
140   m_parent->m_guideGrid = NULL;
141   m_parent->m_viewControl.SetCurrentView(CONTROL_LIST_GUIDE_CHANNEL);
142
143   m_parent->SetLabel(m_iControlButton, g_localizeStrings.Get(19222) + ": " + g_localizeStrings.Get(19029));
144   if (bGotCurrentChannel && CurrentChannel.get())
145     m_parent->SetLabel(CONTROL_LABELGROUP, CurrentChannel->ChannelName().c_str());
146
147   if ((!bGotCurrentChannel || g_PVRManager.GetCurrentEpg(*m_parent->m_vecItems) == 0) && CurrentChannel.get())
148   {
149     CFileItemPtr item;
150     item.reset(new CFileItem("pvr://guide/" + CurrentChannel->ChannelName() + "/empty.epg", false));
151     item->SetLabel(g_localizeStrings.Get(19028));
152     item->SetLabelPreformated(true);
153     m_parent->m_vecItems->Add(item);
154   }
155   m_parent->m_viewControl.SetItems(*m_parent->m_vecItems);
156 }
157
158 void CGUIWindowPVRGuide::UpdateViewNow(bool bUpdateSelectedFile)
159 {
160   CPVRChannelPtr CurrentChannel;
161   bool bGotCurrentChannel = g_PVRManager.GetCurrentChannel(CurrentChannel);
162   bool bRadio = bGotCurrentChannel ? CurrentChannel->IsRadio() : false;
163
164   m_parent->m_guideGrid = NULL;
165   m_parent->m_viewControl.SetCurrentView(CONTROL_LIST_GUIDE_NOW_NEXT);
166
167   m_parent->SetLabel(m_iControlButton, g_localizeStrings.Get(19222) + ": " + g_localizeStrings.Get(19030));
168   m_parent->SetLabel(CONTROL_LABELGROUP, g_localizeStrings.Get(19030));
169
170   int iEpgItems = g_PVRManager.GetPlayingGroup(bRadio)->GetEPGNow(*m_parent->m_vecItems);
171   if (iEpgItems == 0 && bRadio)
172     // if we didn't get any events for radio, get tv instead
173     iEpgItems = g_PVRManager.GetPlayingGroup(false)->GetEPGNow(*m_parent->m_vecItems);
174
175   if (iEpgItems == 0)
176   {
177     CFileItemPtr item;
178     item.reset(new CFileItem("pvr://guide/now/empty.epg", false));
179     item->SetLabel(g_localizeStrings.Get(19028));
180     item->SetLabelPreformated(true);
181     m_parent->m_vecItems->Add(item);
182   }
183   m_parent->m_viewControl.SetItems(*m_parent->m_vecItems);
184 }
185
186 void CGUIWindowPVRGuide::UpdateViewNext(bool bUpdateSelectedFile)
187 {
188   CPVRChannelPtr CurrentChannel;
189   bool bGotCurrentChannel = g_PVRManager.GetCurrentChannel(CurrentChannel);
190   bool bRadio = bGotCurrentChannel ? CurrentChannel->IsRadio() : false;
191
192   m_parent->m_guideGrid = NULL;
193   m_parent->m_viewControl.SetCurrentView(CONTROL_LIST_GUIDE_NOW_NEXT);
194
195   m_parent->SetLabel(m_iControlButton, g_localizeStrings.Get(19222) + ": " + g_localizeStrings.Get(19031));
196   m_parent->SetLabel(CONTROL_LABELGROUP, g_localizeStrings.Get(19031));
197
198   int iEpgItems = g_PVRManager.GetPlayingGroup(bRadio)->GetEPGNext(*m_parent->m_vecItems);
199   if (iEpgItems == 0 && bRadio)
200     // if we didn't get any events for radio, get tv instead
201     iEpgItems = g_PVRManager.GetPlayingGroup(false)->GetEPGNext(*m_parent->m_vecItems);
202
203   if (iEpgItems)
204   {
205     CFileItemPtr item;
206     item.reset(new CFileItem("pvr://guide/next/empty.epg", false));
207     item->SetLabel(g_localizeStrings.Get(19028));
208     item->SetLabelPreformated(true);
209     m_parent->m_vecItems->Add(item);
210   }
211   m_parent->m_viewControl.SetItems(*m_parent->m_vecItems);
212 }
213
214 void CGUIWindowPVRGuide::UpdateViewTimeline(bool bUpdateSelectedFile)
215 {
216   m_parent->m_guideGrid = (CGUIEPGGridContainer*) m_parent->GetControl(CONTROL_LIST_TIMELINE);
217   if (!m_parent->m_guideGrid)
218     return;
219
220   CPVRChannelPtr CurrentChannel;
221   bool bGotCurrentChannel = g_PVRManager.GetCurrentChannel(CurrentChannel);
222   bool bRadio = bGotCurrentChannel ? CurrentChannel->IsRadio() : false;
223
224   if (m_bUpdateRequired || m_cachedTimeline->IsEmpty() ||
225       *m_cachedChannelGroup != *g_PVRManager.GetPlayingGroup(bRadio))
226   {
227     m_bUpdateRequired = false;
228
229     m_cachedTimeline->Clear();
230     m_cachedChannelGroup = g_PVRManager.GetPlayingGroup(bRadio);
231     if (m_cachedChannelGroup->GetEPGAll(*m_cachedTimeline) == 0 && bRadio)
232     {
233       // if we didn't get any events for radio, get tv instead
234       m_cachedChannelGroup = g_PVRManager.GetPlayingGroup(false);
235       m_cachedChannelGroup->GetEPGAll(*m_cachedTimeline);
236     }
237   }
238
239   m_parent->m_vecItems->RemoveDiscCache(m_parent->GetID());
240   m_parent->m_vecItems->Assign(*m_cachedTimeline, false);
241
242   CDateTime gridStart = CDateTime::GetCurrentDateTime().GetAsUTCDateTime();
243   CDateTime firstDate(g_EpgContainer.GetFirstEPGDate());
244   CDateTime lastDate(g_EpgContainer.GetLastEPGDate());
245   m_parent->m_guideGrid->SetStartEnd(firstDate > gridStart ? firstDate : gridStart, lastDate);
246
247   m_parent->SetLabel(m_iControlButton, g_localizeStrings.Get(19222) + ": " + g_localizeStrings.Get(19032));
248   m_parent->SetLabel(CONTROL_LABELGROUP, g_localizeStrings.Get(19032));
249   m_parent->m_viewControl.SetCurrentView(CONTROL_LIST_TIMELINE, true);
250
251   if (bUpdateSelectedFile)
252     SelectPlayingFile();
253 }
254
255 bool CGUIWindowPVRGuide::SelectPlayingFile(void)
256 {
257   if (m_iGuideView == GUIDE_VIEW_TIMELINE)
258   {
259     if (m_parent->m_guideGrid && g_PVRManager.IsPlaying())
260       m_parent->m_guideGrid->SetChannel(g_application.CurrentFile());
261     return true;
262   }
263   return false;
264 }
265
266 void CGUIWindowPVRGuide::UpdateData(bool bUpdateSelectedFile /* = true */)
267 {
268   CSingleLock lock(m_critSection);
269   CLog::Log(LOGDEBUG, "CGUIWindowPVRGuide - %s - update window '%s'. set view to %d", __FUNCTION__, GetName(), m_iControlList);
270
271   /* lock the graphics context while updating */
272   CSingleLock graphicsLock(g_graphicsContext);
273   m_parent->m_viewControl.Clear();
274   m_parent->m_vecItems->Clear();
275
276   if (m_iGuideView == GUIDE_VIEW_CHANNEL)
277     UpdateViewChannel(bUpdateSelectedFile);
278   else if (m_iGuideView == GUIDE_VIEW_NOW)
279     UpdateViewNow(bUpdateSelectedFile);
280   else if (m_iGuideView == GUIDE_VIEW_NEXT)
281     UpdateViewNext(bUpdateSelectedFile);
282   else if (m_iGuideView == GUIDE_VIEW_TIMELINE)
283     UpdateViewTimeline(bUpdateSelectedFile);
284
285   m_bUpdateRequired = false;
286   m_parent->SetLabel(CONTROL_LABELHEADER, g_localizeStrings.Get(19222));
287   UpdateButtons();
288 }
289
290 bool CGUIWindowPVRGuide::IsSelectedButton(CGUIMessage &message) const
291 {
292   unsigned int iControl = message.GetSenderId();
293   return (iControl == CONTROL_BTNGUIDE ||
294       iControl == CONTROL_BTNGUIDE_CHANNEL ||
295       iControl == CONTROL_BTNGUIDE_NOW ||
296       iControl == CONTROL_BTNGUIDE_NEXT ||
297       iControl == CONTROL_BTNGUIDE_TIMELINE);
298 }
299
300 bool CGUIWindowPVRGuide::IsSelectedList(CGUIMessage &message) const
301 {
302   return ((message.GetSenderId() == CONTROL_LIST_TIMELINE && m_iGuideView == GUIDE_VIEW_TIMELINE) ||
303       (message.GetSenderId() == CONTROL_LIST_GUIDE_CHANNEL && m_iGuideView == GUIDE_VIEW_CHANNEL) ||
304       (message.GetSenderId() == CONTROL_LIST_GUIDE_NOW_NEXT && (m_iGuideView == GUIDE_VIEW_NOW || m_iGuideView == GUIDE_VIEW_NEXT)));
305 }
306
307 bool CGUIWindowPVRGuide::OnClickButton(CGUIMessage &message)
308 {
309   bool bReturn = false;
310
311   if (IsSelectedButton(message))
312   {
313     unsigned int iControl = message.GetSenderId();
314     bReturn = true;
315
316     if (iControl == CONTROL_BTNGUIDE)
317     {
318       if (++m_iGuideView > GUIDE_VIEW_TIMELINE)
319         m_iGuideView = GUIDE_VIEW_CHANNEL;
320     }
321     else if (iControl == CONTROL_BTNGUIDE_CHANNEL)
322       m_iGuideView = GUIDE_VIEW_CHANNEL;
323     else if (iControl == CONTROL_BTNGUIDE_NOW)
324       m_iGuideView = GUIDE_VIEW_NOW;
325     else if (iControl == CONTROL_BTNGUIDE_NEXT)
326       m_iGuideView = GUIDE_VIEW_NEXT;
327     else if (iControl == CONTROL_BTNGUIDE_TIMELINE)
328       m_iGuideView = GUIDE_VIEW_TIMELINE;
329     else
330       bReturn = false;
331
332     if (bReturn)
333       UpdateData();
334   }
335
336   return bReturn;
337 }
338
339 bool CGUIWindowPVRGuide::OnClickList(CGUIMessage &message)
340 {
341   bool bReturn = false;
342
343   if (IsSelectedList(message))
344   {
345     int iAction = message.GetParam1();
346     int iItem = m_parent->m_viewControl.GetSelectedItem();
347
348     /* get the fileitem pointer */
349     if (iItem < 0 || iItem >= (int) m_parent->m_vecItems->Size())
350       return bReturn;
351     CFileItemPtr pItem = m_parent->m_vecItems->Get(iItem);
352
353     /* process actions */
354     bReturn = true;
355     if (iAction == ACTION_SELECT_ITEM || iAction == ACTION_MOUSE_LEFT_CLICK)
356     {
357       if (g_advancedSettings.m_bPVRShowEpgInfoOnEpgItemSelect)
358         ShowEPGInfo(pItem.get());
359       else
360         PlayEpgItem(pItem.get());
361     }
362     else if (iAction == ACTION_SHOW_INFO)
363       ShowEPGInfo(pItem.get());
364     else if (iAction == ACTION_RECORD)
365       ActionRecord(pItem.get());
366     else if (iAction == ACTION_PLAY)
367       ActionPlayEpg(pItem.get());
368     else if (iAction == ACTION_CONTEXT_MENU || iAction == ACTION_MOUSE_RIGHT_CLICK)
369       m_parent->OnPopupMenu(iItem);
370     else
371       bReturn = false;
372   }
373
374   return bReturn;
375 }
376
377 bool CGUIWindowPVRGuide::OnContextButtonBegin(CFileItem *item, CONTEXT_BUTTON button)
378 {
379   bool bReturn = false;
380
381   if (button == CONTEXT_BUTTON_BEGIN)
382   {
383     CGUIWindowPVR *pWindow = (CGUIWindowPVR *) g_windowManager.GetWindow(WINDOW_PVR);
384     if (pWindow)
385       pWindow->m_guideGrid->GoToBegin();
386     bReturn = true;
387   }
388
389   return bReturn;
390 }
391
392 bool CGUIWindowPVRGuide::OnContextButtonEnd(CFileItem *item, CONTEXT_BUTTON button)
393 {
394   bool bReturn = false;
395
396   if (button == CONTEXT_BUTTON_END)
397   {
398     CGUIWindowPVR *pWindow = (CGUIWindowPVR *) g_windowManager.GetWindow(WINDOW_PVR);
399     if (pWindow)
400       pWindow->m_guideGrid->GoToEnd();
401     bReturn = true;
402   }
403
404   return bReturn;
405 }
406
407 bool CGUIWindowPVRGuide::OnContextButtonInfo(CFileItem *item, CONTEXT_BUTTON button)
408 {
409   bool bReturn = false;
410
411   if (button == CONTEXT_BUTTON_INFO)
412   {
413     ShowEPGInfo(item);
414     bReturn = true;
415   }
416
417   return bReturn;
418 }
419
420 bool CGUIWindowPVRGuide::PlayEpgItem(CFileItem *item)
421 {
422   CPVRChannelPtr channel;
423   if (item && item->HasEPGInfoTag() && item->GetEPGInfoTag()->HasPVRChannel())
424     channel = item->GetEPGInfoTag()->ChannelTag();
425
426   if (!channel || !g_PVRManager.CheckParentalLock(*channel))
427     return false;
428
429   CLog::Log(LOGDEBUG, "play channel '%s'", channel->ChannelName().c_str());
430   bool bReturn = g_application.PlayFile(CFileItem(*channel));
431   if (!bReturn)
432     CGUIDialogOK::ShowAndGetInput(19033,0,19035,0);
433
434   return bReturn;
435 }
436
437 bool CGUIWindowPVRGuide::OnContextButtonPlay(CFileItem *item, CONTEXT_BUTTON button)
438 {
439   bool bReturn = false;
440
441   if (button == CONTEXT_BUTTON_PLAY_ITEM)
442   {
443     bReturn = PlayEpgItem(item);
444   }
445
446   return bReturn;
447 }
448
449 bool CGUIWindowPVRGuide::OnContextButtonStartRecord(CFileItem *item, CONTEXT_BUTTON button)
450 {
451   bool bReturn = false;
452
453   if (button == CONTEXT_BUTTON_START_RECORD)
454   {
455     StartRecordFile(item);
456     bReturn = true;
457   }
458
459   return bReturn;
460 }
461
462 bool CGUIWindowPVRGuide::OnContextButtonStopRecord(CFileItem *item, CONTEXT_BUTTON button)
463 {
464   bool bReturn = false;
465
466   if (button == CONTEXT_BUTTON_STOP_RECORD)
467   {
468     StopRecordFile(item);
469     bReturn = true;
470   }
471
472   return bReturn;
473 }
474
475 void CGUIWindowPVRGuide::UpdateButtons(void)
476 {
477   if (m_iGuideView == GUIDE_VIEW_CHANNEL)
478     m_parent->SetLabel(m_iControlButton, g_localizeStrings.Get(19222) + ": " + g_localizeStrings.Get(19029));
479   else if (m_iGuideView == GUIDE_VIEW_NOW)
480     m_parent->SetLabel(m_iControlButton, g_localizeStrings.Get(19222) + ": " + g_localizeStrings.Get(19030));
481   else if (m_iGuideView == GUIDE_VIEW_NEXT)
482     m_parent->SetLabel(m_iControlButton, g_localizeStrings.Get(19222) + ": " + g_localizeStrings.Get(19031));
483   else if (m_iGuideView == GUIDE_VIEW_TIMELINE)
484     m_parent->SetLabel(m_iControlButton, g_localizeStrings.Get(19222) + ": " + g_localizeStrings.Get(19032));
485 }