2 * Copyright (C) 2012-2013 Team XBMC
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)
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.
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/>.
21 #include "GUIWindowPVRGuide.h"
23 #include "Application.h"
24 #include "dialogs/GUIDialogOK.h"
25 #include "guilib/GUIWindowManager.h"
26 #include "guilib/Key.h"
27 #include "pvr/PVRManager.h"
28 #include "pvr/channels/PVRChannelGroupsContainer.h"
29 #include "epg/EpgContainer.h"
30 #include "pvr/windows/GUIWindowPVR.h"
31 #include "settings/AdvancedSettings.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"
41 CGUIWindowPVRGuide::CGUIWindowPVRGuide(CGUIWindowPVR *parent) :
42 CGUIWindowPVRCommon(parent, PVR_WINDOW_EPG, CONTROL_BTNGUIDE, CONTROL_LIST_GUIDE_NOW_NEXT),
44 m_iGuideView(CSettings::Get().GetInt("epg.defaultguideview"))
46 m_cachedTimeline = new CFileItemList;
47 m_cachedChannelGroup = CPVRChannelGroupPtr(new CPVRChannelGroup);
50 CGUIWindowPVRGuide::~CGUIWindowPVRGuide(void)
52 delete m_cachedTimeline;
55 void CGUIWindowPVRGuide::UnregisterObservers(void)
57 g_EpgContainer.UnregisterObserver(this);
60 void CGUIWindowPVRGuide::ResetObservers(void)
62 g_EpgContainer.RegisterObserver(this);
65 void CGUIWindowPVRGuide::Notify(const Observable &obs, const ObservableMessage msg)
67 if (msg == ObservableMessageEpg || msg == ObservableMessageEpgContainer)
69 m_bUpdateRequired = true;
71 /* update the current window if the EPG timeline view is visible */
72 if (IsFocused() && m_iGuideView == GUIDE_VIEW_TIMELINE)
75 else if (msg == ObservableMessageEpgActiveItem)
77 if (IsVisible() && m_iGuideView != GUIDE_VIEW_TIMELINE)
80 m_bUpdateRequired = true;
84 void CGUIWindowPVRGuide::GetContextButtons(int itemNumber, CContextButtons &buttons) const
86 if (itemNumber < 0 || itemNumber >= m_parent->m_vecItems->Size())
88 CFileItemPtr pItem = m_parent->m_vecItems->Get(itemNumber);
90 CFileItemPtr timer = g_PVRTimers->GetTimerForEpgTag(pItem.get());
91 if (timer && timer->HasPVRTimerInfoTag())
93 if (timer->GetPVRTimerInfoTag()->IsRecording())
94 buttons.Add(CONTEXT_BUTTON_STOP_RECORD, 19059); /* stop recording */
96 buttons.Add(CONTEXT_BUTTON_STOP_RECORD, 19060); /* delete timer */
98 else if (pItem->GetEPGInfoTag()->EndAsLocalTime() > CDateTime::GetCurrentDateTime())
100 if (pItem->GetEPGInfoTag()->StartAsLocalTime() < CDateTime::GetCurrentDateTime())
101 buttons.Add(CONTEXT_BUTTON_START_RECORD, 264); /* record */
103 buttons.Add(CONTEXT_BUTTON_START_RECORD, 19061); /* add timer */
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)
111 buttons.Add(CONTEXT_BUTTON_BEGIN, 19063); /* go to begin */
112 buttons.Add(CONTEXT_BUTTON_NOW, 19070); /* go to now */
113 buttons.Add(CONTEXT_BUTTON_END, 19064); /* go to end */
115 if (pItem->GetEPGInfoTag()->HasPVRChannel() &&
116 g_PVRClients->HasMenuHooks(pItem->GetEPGInfoTag()->ChannelTag()->ClientID(), PVR_MENUHOOK_EPG))
117 buttons.Add(CONTEXT_BUTTON_MENU_HOOKS, 19195); /* PVR client specific action */
121 bool CGUIWindowPVRGuide::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
123 if (itemNumber < 0 || itemNumber >= (int) m_parent->m_vecItems->Size())
125 CFileItemPtr pItem = m_parent->m_vecItems->Get(itemNumber);
127 return OnContextButtonPlay(pItem.get(), button) ||
128 OnContextButtonInfo(pItem.get(), button) ||
129 OnContextButtonStartRecord(pItem.get(), button) ||
130 OnContextButtonStopRecord(pItem.get(), button) ||
131 OnContextButtonBegin(pItem.get(), button) ||
132 OnContextButtonEnd(pItem.get(), button) ||
133 OnContextButtonNow(pItem.get(), button) ||
134 CGUIWindowPVRCommon::OnContextButton(itemNumber, button);
137 void CGUIWindowPVRGuide::UpdateViewChannel(bool bUpdateSelectedFile)
139 CPVRChannelPtr CurrentChannel;
140 bool bGotCurrentChannel = g_PVRManager.GetCurrentChannel(CurrentChannel);
142 m_parent->m_guideGrid = NULL;
143 m_parent->m_viewControl.SetCurrentView(CONTROL_LIST_GUIDE_CHANNEL);
145 m_parent->SetLabel(m_iControlButton, g_localizeStrings.Get(19222) + ": " + g_localizeStrings.Get(19029));
146 if (bGotCurrentChannel && CurrentChannel.get())
147 m_parent->SetLabel(CONTROL_LABELGROUP, CurrentChannel->ChannelName().c_str());
149 if ((!bGotCurrentChannel || g_PVRManager.GetCurrentEpg(*m_parent->m_vecItems) == 0) && CurrentChannel.get())
152 item.reset(new CFileItem("pvr://guide/" + CurrentChannel->ChannelName() + "/empty.epg", false));
153 item->SetLabel(g_localizeStrings.Get(19028));
154 item->SetLabelPreformated(true);
155 m_parent->m_vecItems->Add(item);
157 m_parent->m_viewControl.SetItems(*m_parent->m_vecItems);
160 void CGUIWindowPVRGuide::UpdateViewNow(bool bUpdateSelectedFile)
162 CPVRChannelPtr CurrentChannel;
163 bool bGotCurrentChannel = g_PVRManager.GetCurrentChannel(CurrentChannel);
164 bool bRadio = bGotCurrentChannel ? CurrentChannel->IsRadio() : false;
166 m_parent->m_guideGrid = NULL;
167 m_parent->m_viewControl.SetCurrentView(CONTROL_LIST_GUIDE_NOW_NEXT);
169 m_parent->SetLabel(m_iControlButton, g_localizeStrings.Get(19222) + ": " + g_localizeStrings.Get(19030));
170 m_parent->SetLabel(CONTROL_LABELGROUP, g_localizeStrings.Get(19030));
172 int iEpgItems = g_PVRManager.GetPlayingGroup(bRadio)->GetEPGNow(*m_parent->m_vecItems);
173 if (iEpgItems == 0 && bRadio)
174 // if we didn't get any events for radio, get tv instead
175 iEpgItems = g_PVRManager.GetPlayingGroup(false)->GetEPGNow(*m_parent->m_vecItems);
180 item.reset(new CFileItem("pvr://guide/now/empty.epg", false));
181 item->SetLabel(g_localizeStrings.Get(19028));
182 item->SetLabelPreformated(true);
183 m_parent->m_vecItems->Add(item);
185 m_parent->m_viewControl.SetItems(*m_parent->m_vecItems);
188 void CGUIWindowPVRGuide::UpdateViewNext(bool bUpdateSelectedFile)
190 CPVRChannelPtr CurrentChannel;
191 bool bGotCurrentChannel = g_PVRManager.GetCurrentChannel(CurrentChannel);
192 bool bRadio = bGotCurrentChannel ? CurrentChannel->IsRadio() : false;
194 m_parent->m_guideGrid = NULL;
195 m_parent->m_viewControl.SetCurrentView(CONTROL_LIST_GUIDE_NOW_NEXT);
197 m_parent->SetLabel(m_iControlButton, g_localizeStrings.Get(19222) + ": " + g_localizeStrings.Get(19031));
198 m_parent->SetLabel(CONTROL_LABELGROUP, g_localizeStrings.Get(19031));
200 int iEpgItems = g_PVRManager.GetPlayingGroup(bRadio)->GetEPGNext(*m_parent->m_vecItems);
201 if (iEpgItems == 0 && bRadio)
202 // if we didn't get any events for radio, get tv instead
203 iEpgItems = g_PVRManager.GetPlayingGroup(false)->GetEPGNext(*m_parent->m_vecItems);
208 item.reset(new CFileItem("pvr://guide/next/empty.epg", false));
209 item->SetLabel(g_localizeStrings.Get(19028));
210 item->SetLabelPreformated(true);
211 m_parent->m_vecItems->Add(item);
213 m_parent->m_viewControl.SetItems(*m_parent->m_vecItems);
216 void CGUIWindowPVRGuide::UpdateViewTimeline(bool bUpdateSelectedFile)
218 m_parent->m_guideGrid = (CGUIEPGGridContainer*) m_parent->GetControl(CONTROL_LIST_TIMELINE);
219 if (!m_parent->m_guideGrid)
222 CPVRChannelPtr CurrentChannel;
223 bool bGotCurrentChannel = g_PVRManager.GetCurrentChannel(CurrentChannel);
224 bool bRadio = bGotCurrentChannel ? CurrentChannel->IsRadio() : false;
226 if (m_bUpdateRequired || m_cachedTimeline->IsEmpty() ||
227 *m_cachedChannelGroup != *g_PVRManager.GetPlayingGroup(bRadio))
229 m_bUpdateRequired = false;
231 m_cachedTimeline->Clear();
232 m_cachedChannelGroup = g_PVRManager.GetPlayingGroup(bRadio);
234 if (m_cachedChannelGroup->GetEPGAll(*m_cachedTimeline) == 0 && bRadio)
236 // if we didn't get any events for radio, get tv instead
237 m_cachedChannelGroup = g_PVRManager.GetPlayingGroup(false);
238 m_cachedChannelGroup->GetEPGAll(*m_cachedTimeline);
242 m_parent->m_vecItems->RemoveDiscCache(m_parent->GetID());
243 m_parent->m_vecItems->Assign(*m_cachedTimeline, false);
245 CDateTime startDate(m_cachedChannelGroup->GetFirstEPGDate());
246 CDateTime endDate(m_cachedChannelGroup->GetLastEPGDate());
247 CDateTime currentDate = CDateTime::GetCurrentDateTime().GetAsUTCDateTime();
249 if (!startDate.IsValid())
250 startDate = currentDate;
252 if (!endDate.IsValid() || endDate < startDate)
255 // limit start to linger time
256 CDateTime maxPastDate = currentDate - CDateTimeSpan(0, 0, g_advancedSettings.m_iEpgLingerTime, 0);
257 if(startDate < maxPastDate)
258 startDate = maxPastDate;
260 m_parent->m_guideGrid->SetStartEnd(startDate, endDate);
262 m_parent->SetLabel(m_iControlButton, g_localizeStrings.Get(19222) + ": " + g_localizeStrings.Get(19032));
263 m_parent->SetLabel(CONTROL_LABELGROUP, g_localizeStrings.Get(19032));
264 m_parent->m_viewControl.SetCurrentView(CONTROL_LIST_TIMELINE, true);
266 if (bUpdateSelectedFile)
270 bool CGUIWindowPVRGuide::SelectPlayingFile(void)
272 if (m_iGuideView == GUIDE_VIEW_TIMELINE)
274 if (m_parent->m_guideGrid && g_PVRManager.IsPlaying())
275 m_parent->m_guideGrid->SetChannel(g_application.CurrentFile());
281 void CGUIWindowPVRGuide::UpdateData(bool bUpdateSelectedFile /* = true */)
283 CSingleLock lock(m_critSection);
284 CLog::Log(LOGDEBUG, "CGUIWindowPVRGuide - %s - update window '%s'. set view to %d", __FUNCTION__, GetName(), m_iControlList);
286 /* lock the graphics context while updating */
287 CSingleLock graphicsLock(g_graphicsContext);
288 m_parent->m_viewControl.Clear();
289 m_parent->m_vecItems->Clear();
291 if (m_iGuideView == GUIDE_VIEW_CHANNEL)
292 UpdateViewChannel(bUpdateSelectedFile);
293 else if (m_iGuideView == GUIDE_VIEW_NOW)
294 UpdateViewNow(bUpdateSelectedFile);
295 else if (m_iGuideView == GUIDE_VIEW_NEXT)
296 UpdateViewNext(bUpdateSelectedFile);
297 else if (m_iGuideView == GUIDE_VIEW_TIMELINE)
298 UpdateViewTimeline(bUpdateSelectedFile);
300 m_bUpdateRequired = false;
301 m_parent->SetLabel(CONTROL_LABELHEADER, g_localizeStrings.Get(19222));
305 bool CGUIWindowPVRGuide::IsSelectedButton(CGUIMessage &message) const
307 unsigned int iControl = message.GetSenderId();
308 return (iControl == CONTROL_BTNGUIDE ||
309 iControl == CONTROL_BTNGUIDE_CHANNEL ||
310 iControl == CONTROL_BTNGUIDE_NOW ||
311 iControl == CONTROL_BTNGUIDE_NEXT ||
312 iControl == CONTROL_BTNGUIDE_TIMELINE);
315 bool CGUIWindowPVRGuide::IsSelectedList(CGUIMessage &message) const
317 return ((message.GetSenderId() == CONTROL_LIST_TIMELINE && m_iGuideView == GUIDE_VIEW_TIMELINE) ||
318 (message.GetSenderId() == CONTROL_LIST_GUIDE_CHANNEL && m_iGuideView == GUIDE_VIEW_CHANNEL) ||
319 (message.GetSenderId() == CONTROL_LIST_GUIDE_NOW_NEXT && (m_iGuideView == GUIDE_VIEW_NOW || m_iGuideView == GUIDE_VIEW_NEXT)));
322 bool CGUIWindowPVRGuide::OnClickButton(CGUIMessage &message)
324 bool bReturn = false;
326 if (IsSelectedButton(message))
328 unsigned int iControl = message.GetSenderId();
331 if (iControl == CONTROL_BTNGUIDE)
333 if (++m_iGuideView > GUIDE_VIEW_TIMELINE)
334 m_iGuideView = GUIDE_VIEW_CHANNEL;
336 else if (iControl == CONTROL_BTNGUIDE_CHANNEL)
337 m_iGuideView = GUIDE_VIEW_CHANNEL;
338 else if (iControl == CONTROL_BTNGUIDE_NOW)
339 m_iGuideView = GUIDE_VIEW_NOW;
340 else if (iControl == CONTROL_BTNGUIDE_NEXT)
341 m_iGuideView = GUIDE_VIEW_NEXT;
342 else if (iControl == CONTROL_BTNGUIDE_TIMELINE)
343 m_iGuideView = GUIDE_VIEW_TIMELINE;
354 bool CGUIWindowPVRGuide::OnClickList(CGUIMessage &message)
356 bool bReturn = false;
358 if (IsSelectedList(message))
360 int iAction = message.GetParam1();
361 int iItem = m_parent->m_viewControl.GetSelectedItem();
363 /* get the fileitem pointer */
364 if (iItem < 0 || iItem >= (int) m_parent->m_vecItems->Size())
366 CFileItemPtr pItem = m_parent->m_vecItems->Get(iItem);
368 /* process actions */
371 case ACTION_SELECT_ITEM:
372 case ACTION_MOUSE_LEFT_CLICK:
373 if (!g_advancedSettings.m_bPVRShowEpgInfoOnEpgItemSelect && pItem->GetEPGInfoTag()->IsActive())
374 ActionPlayEpg(pItem.get());
376 ShowEPGInfo(pItem.get());
378 case ACTION_SHOW_INFO:
379 ShowEPGInfo(pItem.get());
382 ActionPlayEpg(pItem.get());
385 ActionRecord(pItem.get());
387 case ACTION_CONTEXT_MENU:
388 case ACTION_MOUSE_RIGHT_CLICK:
389 m_parent->OnPopupMenu(iItem);
400 bool CGUIWindowPVRGuide::OnContextButtonBegin(CFileItem *item, CONTEXT_BUTTON button)
402 bool bReturn = false;
404 if (button == CONTEXT_BUTTON_BEGIN)
406 CGUIWindowPVR *pWindow = (CGUIWindowPVR *) g_windowManager.GetWindow(WINDOW_PVR);
408 pWindow->m_guideGrid->GoToBegin();
415 bool CGUIWindowPVRGuide::OnContextButtonEnd(CFileItem *item, CONTEXT_BUTTON button)
417 bool bReturn = false;
419 if (button == CONTEXT_BUTTON_END)
421 CGUIWindowPVR *pWindow = (CGUIWindowPVR *) g_windowManager.GetWindow(WINDOW_PVR);
423 pWindow->m_guideGrid->GoToEnd();
430 bool CGUIWindowPVRGuide::OnContextButtonNow(CFileItem *item, CONTEXT_BUTTON button)
432 bool bReturn = false;
434 if (button == CONTEXT_BUTTON_NOW)
436 CGUIWindowPVR *pWindow = (CGUIWindowPVR *) g_windowManager.GetWindow(WINDOW_PVR);
438 pWindow->m_guideGrid->GoToNow();
445 bool CGUIWindowPVRGuide::OnContextButtonInfo(CFileItem *item, CONTEXT_BUTTON button)
447 bool bReturn = false;
449 if (button == CONTEXT_BUTTON_INFO)
458 bool CGUIWindowPVRGuide::PlayEpgItem(CFileItem *item)
460 CPVRChannelPtr channel;
461 if (item && item->HasEPGInfoTag() && item->GetEPGInfoTag()->HasPVRChannel())
462 channel = item->GetEPGInfoTag()->ChannelTag();
464 if (!channel || !g_PVRManager.CheckParentalLock(*channel))
467 CLog::Log(LOGDEBUG, "play channel '%s'", channel->ChannelName().c_str());
468 CFileItem channelItem = CFileItem(*channel);
469 g_application.SwitchToFullScreen();
470 bool bReturn = PlayFile(&channelItem);
473 CStdString msg = StringUtils::Format(g_localizeStrings.Get(19035).c_str(), channel->ChannelName().c_str()); // CHANNELNAME could not be played. Check the log for details.
474 CGUIDialogOK::ShowAndGetInput(19033, 0, msg, 0);
480 bool CGUIWindowPVRGuide::OnContextButtonPlay(CFileItem *item, CONTEXT_BUTTON button)
482 bool bReturn = false;
484 if (button == CONTEXT_BUTTON_PLAY_ITEM)
486 bReturn = PlayEpgItem(item);
492 bool CGUIWindowPVRGuide::OnContextButtonStartRecord(CFileItem *item, CONTEXT_BUTTON button)
494 bool bReturn = false;
496 if (button == CONTEXT_BUTTON_START_RECORD)
498 StartRecordFile(item);
505 bool CGUIWindowPVRGuide::OnContextButtonStopRecord(CFileItem *item, CONTEXT_BUTTON button)
507 bool bReturn = false;
509 if (button == CONTEXT_BUTTON_STOP_RECORD)
511 StopRecordFile(item);
518 void CGUIWindowPVRGuide::UpdateButtons(void)
520 if (m_iGuideView == GUIDE_VIEW_CHANNEL)
521 m_parent->SetLabel(m_iControlButton, g_localizeStrings.Get(19222) + ": " + g_localizeStrings.Get(19029));
522 else if (m_iGuideView == GUIDE_VIEW_NOW)
523 m_parent->SetLabel(m_iControlButton, g_localizeStrings.Get(19222) + ": " + g_localizeStrings.Get(19030));
524 else if (m_iGuideView == GUIDE_VIEW_NEXT)
525 m_parent->SetLabel(m_iControlButton, g_localizeStrings.Get(19222) + ": " + g_localizeStrings.Get(19031));
526 else if (m_iGuideView == GUIDE_VIEW_TIMELINE)
527 m_parent->SetLabel(m_iControlButton, g_localizeStrings.Get(19222) + ": " + g_localizeStrings.Get(19032));
530 void CGUIWindowPVRGuide::SettingOptionsEpgGuideViewFiller(const CSetting *setting, std::vector< std::pair<std::string, int> > &list, int ¤t)
532 list.push_back(make_pair(g_localizeStrings.Get(19029), PVR::GUIDE_VIEW_CHANNEL));
533 list.push_back(make_pair(g_localizeStrings.Get(19030), PVR::GUIDE_VIEW_NOW));
534 list.push_back(make_pair(g_localizeStrings.Get(19031), PVR::GUIDE_VIEW_NEXT));
535 list.push_back(make_pair(g_localizeStrings.Get(19032), PVR::GUIDE_VIEW_TIMELINE));