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 "GUIWindowPVRBase.h"
23 #include "Application.h"
24 #include "ApplicationMessenger.h"
25 #include "dialogs/GUIDialogNumeric.h"
26 #include "dialogs/GUIDialogKaiToast.h"
27 #include "dialogs/GUIDialogOK.h"
28 #include "dialogs/GUIDialogYesNo.h"
29 #include "filesystem/StackDirectory.h"
30 #include "guilib/Key.h"
31 #include "guilib/GUIMessage.h"
32 #include "guilib/GUIWindowManager.h"
33 #include "dialogs/GUIDialogKaiToast.h"
34 #include "dialogs/GUIDialogSelect.h"
35 #include "pvr/PVRManager.h"
36 #include "pvr/addons/PVRClients.h"
37 #include "pvr/dialogs/GUIDialogPVRGuideInfo.h"
38 #include "pvr/dialogs/GUIDialogPVRRecordingInfo.h"
39 #include "pvr/timers/PVRTimers.h"
41 #include "epg/GUIEPGGridContainer.h"
42 #include "settings/MediaSettings.h"
43 #include "settings/Settings.h"
44 #include "threads/SingleLock.h"
45 #include "utils/StringUtils.h"
46 #include "utils/Observer.h"
52 CGUIWindowPVRBase::CGUIWindowPVRBase(bool bRadio, int id, const std::string &xmlFile) :
53 CGUIMediaWindow(id, xmlFile.c_str()),
58 CGUIWindowPVRBase::~CGUIWindowPVRBase(void)
62 void CGUIWindowPVRBase::Notify(const Observable &obs, const ObservableMessage msg)
64 CGUIMessage m(GUI_MSG_REFRESH_LIST, GetID(), 0, msg);
65 CApplicationMessenger::Get().SendGUIMessage(m);
68 bool CGUIWindowPVRBase::OnAction(const CAction &action)
70 switch (action.GetID())
72 case ACTION_PREVIOUS_CHANNELGROUP:
73 case ACTION_NEXT_CHANNELGROUP:
74 // switch to next or previous group
75 SetGroup(ACTION_NEXT_CHANNELGROUP ? m_group->GetNextGroup() : m_group->GetPreviousGroup());
79 return CGUIMediaWindow::OnAction(action);
82 bool CGUIWindowPVRBase::OnBack(int actionID)
84 if (actionID == ACTION_NAV_BACK)
86 // don't call CGUIMediaWindow as it will attempt to go to the parent folder which we don't want.
87 if (GetPreviousWindow() != WINDOW_FULLSCREEN_LIVETV)
88 g_windowManager.ActivateWindow(WINDOW_HOME);
90 return CGUIWindow::OnBack(actionID);
92 return CGUIMediaWindow::OnBack(actionID);
95 void CGUIWindowPVRBase::OnInitWindow(void)
97 if (!g_PVRManager.IsStarted() || !g_PVRClients->HasConnectedClients())
99 g_windowManager.PreviousWindow();
100 CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Warning,
101 g_localizeStrings.Get(19045),
102 g_localizeStrings.Get(19044));
106 CGUIMediaWindow::OnInitWindow();
109 bool CGUIWindowPVRBase::OnMessage(CGUIMessage& message)
111 switch (message.GetMessage())
113 case GUI_MSG_WINDOW_INIT:
115 m_group = g_PVRManager.GetPlayingGroup(m_bRadio);
116 SetProperty("IsRadio", m_bRadio ? "true" : "");
120 case GUI_MSG_CLICKED:
122 switch (message.GetSenderId())
124 case CONTROL_BTNCHANNELGROUPS:
125 return OpenGroupSelectionDialog();
131 return CGUIMediaWindow::OnMessage(message);
134 void CGUIWindowPVRBase::SetInvalid()
136 VECFILEITEMS items = m_vecItems->GetList();
137 for (VECFILEITEMS::iterator it = items.begin(); it != items.end(); ++it)
139 CGUIMediaWindow::SetInvalid();
142 bool CGUIWindowPVRBase::OpenGroupSelectionDialog(void)
144 CGUIDialogSelect *dialog = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
148 CFileItemList options;
149 g_PVRChannelGroups->Get(m_bRadio)->GetGroupList(&options);
152 dialog->SetHeading(g_localizeStrings.Get(19146));
153 dialog->SetItems(&options);
154 dialog->SetMultiSelection(false);
155 dialog->SetSelected(m_group->GroupName());
158 if (!dialog->IsConfirmed())
161 const CFileItemPtr item = dialog->GetSelectedItem();
165 SetGroup(g_PVRChannelGroups->Get(m_bRadio)->GetByName(item->m_strTitle));
170 CPVRChannelGroupPtr CGUIWindowPVRBase::GetGroup(void)
172 CSingleLock lock(m_critSection);
176 void CGUIWindowPVRBase::SetGroup(CPVRChannelGroupPtr group)
178 CSingleLock lock(m_critSection);
182 if (m_group != group)
185 m_group->UnregisterObserver(this);
187 // we need to register the window to receive changes from the new group
188 m_group->RegisterObserver(this);
189 g_PVRManager.SetPlayingGroup(m_group);
194 bool CGUIWindowPVRBase::PlayFile(CFileItem *item, bool bPlayMinimized /* = false */)
196 if (item->m_bIsFolder)
201 if (item->GetPath() == g_application.CurrentFile())
203 CGUIMessage msg(GUI_MSG_FULLSCREEN, 0, GetID());
204 g_windowManager.SendMessage(msg);
208 CMediaSettings::Get().SetVideoStartWindowed(bPlayMinimized);
210 if (item->HasPVRRecordingInfoTag())
212 return PlayRecording(item, bPlayMinimized);
216 bool bSwitchSuccessful(false);
218 CPVRChannel *channel = item->HasPVRChannelInfoTag() ? item->GetPVRChannelInfoTag() : NULL;
220 if (channel && g_PVRManager.CheckParentalLock(*channel))
222 /* try a fast switch */
223 if (channel && (g_PVRManager.IsPlayingTV() || g_PVRManager.IsPlayingRadio()) &&
224 (channel->IsRadio() == g_PVRManager.IsPlayingRadio()))
226 if (channel->StreamURL().empty())
227 bSwitchSuccessful = g_application.m_pPlayer->SwitchChannel(*channel);
230 if (!bSwitchSuccessful)
232 CApplicationMessenger::Get().PlayFile(*item, false);
237 if (!bSwitchSuccessful)
239 CStdString channelName = g_localizeStrings.Get(19029); // Channel
241 channelName = channel->ChannelName();
242 CStdString msg = StringUtils::Format(g_localizeStrings.Get(19035).c_str(), channelName.c_str()); // CHANNELNAME could not be played. Check the log for details.
244 CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Error,
245 g_localizeStrings.Get(19166), // PVR information
254 bool CGUIWindowPVRBase::StartRecordFile(const CFileItem &item)
256 if (!item.HasEPGInfoTag())
259 const CEpgInfoTag *tag = item.GetEPGInfoTag();
260 CPVRChannelPtr channel;
262 channel = tag->ChannelTag();
264 if (!channel || !g_PVRManager.CheckParentalLock(*channel))
267 CFileItemPtr timer = g_PVRTimers->GetTimerForEpgTag(&item);
268 if (timer && timer->HasPVRTimerInfoTag())
270 CGUIDialogOK::ShowAndGetInput(19033,19034,0,0);
274 // ask for confirmation before starting a timer
275 CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
278 pDialog->SetHeading(264);
279 pDialog->SetLine(0, tag->PVRChannelName());
280 pDialog->SetLine(1, "");
281 pDialog->SetLine(2, tag->Title());
284 if (!pDialog->IsConfirmed())
287 CPVRTimerInfoTag *newTimer = CPVRTimerInfoTag::CreateFromEpg(*tag);
291 bReturn = g_PVRTimers->AddTimer(*newTimer);
297 bool CGUIWindowPVRBase::StopRecordFile(const CFileItem &item)
299 if (!item.HasEPGInfoTag())
302 const CEpgInfoTag *tag = item.GetEPGInfoTag();
303 if (!tag || !tag->HasPVRChannel())
306 CFileItemPtr timer = g_PVRTimers->GetTimerForEpgTag(&item);
307 if (!timer || !timer->HasPVRTimerInfoTag() || timer->GetPVRTimerInfoTag()->m_bIsRepeating)
310 return g_PVRTimers->DeleteTimer(*timer);
313 bool CGUIWindowPVRBase::PlayRecording(CFileItem *item, bool bPlayMinimized /* = false */)
315 if (!item->HasPVRRecordingInfoTag())
318 CStdString stream = item->GetPVRRecordingInfoTag()->m_strStreamURL;
321 CApplicationMessenger::Get().PlayFile(*item, false);
325 /* Isolate the folder from the filename */
326 size_t found = stream.find_last_of("/");
327 if (found == CStdString::npos)
328 found = stream.find_last_of("\\");
330 if (found != CStdString::npos)
332 /* Check here for asterisk at the begin of the filename */
333 if (stream[found+1] == '*')
335 /* Create a "stack://" url with all files matching the extension */
336 CStdString ext = URIUtils::GetExtension(stream);
337 CStdString dir = stream.substr(0, found).c_str();
340 XFILE::CDirectory::GetDirectory(dir, items);
341 items.Sort(SortByFile, SortOrderAscending);
344 for (int i = 0; i < items.Size(); ++i)
346 if (URIUtils::HasExtension(items[i]->GetPath(), ext))
352 /* If we have a stack change the path of the item to it */
353 XFILE::CStackDirectory dir;
354 CStdString stackPath = dir.ConstructStackPath(items, stack);
355 item->SetPath(stackPath);
360 /* If no asterisk is present play only the given stream URL */
361 item->SetPath(stream);
366 CLog::Log(LOGERROR, "CGUIWindowPVRCommon - %s - can't open recording: no valid filename", __FUNCTION__);
367 CGUIDialogOK::ShowAndGetInput(19033,0,19036,0);
371 CApplicationMessenger::Get().PlayFile(*item, false);
376 void CGUIWindowPVRBase::ShowRecordingInfo(CFileItem *item)
378 CGUIDialogPVRRecordingInfo* pDlgInfo = (CGUIDialogPVRRecordingInfo*)g_windowManager.GetWindow(WINDOW_DIALOG_PVR_RECORDING_INFO);
379 if (item->IsPVRRecording() && pDlgInfo)
381 pDlgInfo->SetRecording(item);
386 void CGUIWindowPVRBase::ShowEPGInfo(CFileItem *item)
388 CFileItem *tag = NULL;
389 bool bHasChannel(false);
393 tag = new CFileItem(*item);
394 if (item->GetEPGInfoTag()->HasPVRChannel())
396 channel = *item->GetEPGInfoTag()->ChannelTag();
400 else if (item->IsPVRChannel())
403 channel = *item->GetPVRChannelInfoTag();
405 if (!item->GetPVRChannelInfoTag()->GetEPGNow(epgnow))
407 CGUIDialogOK::ShowAndGetInput(19033,0,19055,0);
410 tag = new CFileItem(epgnow);
413 CGUIDialogPVRGuideInfo* pDlgInfo = (CGUIDialogPVRGuideInfo*)g_windowManager.GetWindow(WINDOW_DIALOG_PVR_GUIDE_INFO);
414 if (tag && (!bHasChannel || g_PVRManager.CheckParentalLock(channel)) && pDlgInfo)
416 pDlgInfo->SetProgInfo(tag);
423 bool CGUIWindowPVRBase::ActionInputChannelNumber(int input)
425 CStdString strInput = StringUtils::Format("%i", input);
426 if (CGUIDialogNumeric::ShowAndGetNumber(strInput, g_localizeStrings.Get(19103)))
428 int iChannelNumber = atoi(strInput.c_str());
429 if (iChannelNumber >= 0)
432 VECFILEITEMS items = m_vecItems->GetList();
433 for (VECFILEITEMS::iterator it = items.begin(); it != items.end(); ++it)
435 if(((*it)->HasPVRChannelInfoTag() && (*it)->GetPVRChannelInfoTag()->ChannelNumber() == iChannelNumber) ||
436 ((*it)->HasEPGInfoTag() && (*it)->GetEPGInfoTag()->HasPVRChannel() && (*it)->GetEPGInfoTag()->PVRChannelNumber() == iChannelNumber))
438 // different handling for guide grid
439 if ((GetID() == WINDOW_TV_GUIDE || GetID() == WINDOW_RADIO_GUIDE) &&
440 m_viewControl.GetCurrentControl() == GUIDE_VIEW_TIMELINE)
442 CGUIEPGGridContainer* epgGridContainer = (CGUIEPGGridContainer*) GetControl(m_viewControl.GetCurrentControl());
443 epgGridContainer->SetChannel((*(*it)->GetEPGInfoTag()->ChannelTag()));
446 m_viewControl.SetSelectedItem(itemIndex);
457 bool CGUIWindowPVRBase::ActionPlayChannel(CFileItem *item)
459 bool bReturn = false;
461 if (item->GetPath() == "pvr://channels/.add.channel")
463 /* show "add channel" dialog */
464 CGUIDialogOK::ShowAndGetInput(19033,0,19038,0);
470 bReturn = PlayFile(item, CSettings::Get().GetBool("pvrplayback.playminimized"));
476 bool CGUIWindowPVRBase::ActionPlayEpg(CFileItem *item)
478 if (!item || !item->HasEPGInfoTag())
481 CPVRChannelPtr channel;
482 CEpgInfoTag *epgTag = item->GetEPGInfoTag();
483 if (epgTag->HasPVRChannel())
484 channel = epgTag->ChannelTag();
486 if (!channel || !g_PVRManager.CheckParentalLock(*channel))
490 if (epgTag->HasRecording())
491 fileItem = CFileItem(*epgTag->Recording());
493 fileItem = CFileItem(*channel);
495 g_application.SwitchToFullScreen();
496 if (!PlayFile(&fileItem))
498 // CHANNELNAME could not be played. Check the log for details.
499 CStdString msg = StringUtils::Format(g_localizeStrings.Get(19035).c_str(), channel->ChannelName().c_str());
500 CGUIDialogOK::ShowAndGetInput(19033, 0, msg, 0);
507 bool CGUIWindowPVRBase::ActionDeleteChannel(CFileItem *item)
509 CPVRChannel *channel = item->GetPVRChannelInfoTag();
511 /* check if the channel tag is valid */
512 if (!channel || channel->ChannelNumber() <= 0)
515 /* show a confirmation dialog */
516 CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*) g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
519 pDialog->SetHeading(19039);
520 pDialog->SetLine(0, "");
521 pDialog->SetLine(1, channel->ChannelName());
522 pDialog->SetLine(2, "");
525 /* prompt for the user's confirmation */
526 if (!pDialog->IsConfirmed())
529 g_PVRChannelGroups->GetGroupAll(channel->IsRadio())->RemoveFromGroup(*channel);
535 bool CGUIWindowPVRBase::ActionDeleteRecording(CFileItem *item)
537 bool bReturn = false;
539 /* check if the recording tag is valid */
540 CPVRRecording *recTag = (CPVRRecording *) item->GetPVRRecordingInfoTag();
541 if (!recTag || recTag->m_strRecordingId.empty())
544 /* show a confirmation dialog */
545 CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
549 pDialog->SetHeading(122); // Confirm delete
550 pDialog->SetLine(0, item->m_bIsFolder ? 19113 : 19112); // Are you sure?
551 pDialog->SetLine(1, "");
552 pDialog->SetLine(2, item->GetLabel());
553 pDialog->SetChoice(1, 117); // Delete
555 /* prompt for the user's confirmation */
557 if (!pDialog->IsConfirmed())
560 /* delete the recording */
561 if (g_PVRRecordings->Delete(*item))
563 g_PVRManager.TriggerRecordingsUpdate();
570 bool CGUIWindowPVRBase::ActionRecord(CFileItem *item)
572 bool bReturn = false;
574 CEpgInfoTag *epgTag = item->GetEPGInfoTag();
578 CPVRChannelPtr channel = epgTag->ChannelTag();
579 if (!channel || !g_PVRManager.CheckParentalLock(*channel))
582 if (epgTag->Timer() == NULL)
584 /* create a confirmation dialog */
585 CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*) g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
589 pDialog->SetHeading(264);
590 pDialog->SetLine(0, "");
591 pDialog->SetLine(1, epgTag->Title());
592 pDialog->SetLine(2, "");
595 /* prompt for the user's confirmation */
596 if (!pDialog->IsConfirmed())
599 CPVRTimerInfoTag *newTimer = CPVRTimerInfoTag::CreateFromEpg(*epgTag);
602 bReturn = g_PVRTimers->AddTimer(*newTimer);
612 CGUIDialogOK::ShowAndGetInput(19033,19034,0,0);
619 bool CGUIWindowPVRBase::UpdateEpgForChannel(CFileItem *item)
621 CPVRChannel *channel = item->GetPVRChannelInfoTag();
622 CEpg *epg = channel->GetEPG();
630 bool CGUIWindowPVRBase::Update(const std::string &strDirectory, bool updateFilterPath /* = true */)
632 return CGUIMediaWindow::Update(strDirectory, updateFilterPath);
635 void CGUIWindowPVRBase::UpdateButtons(void)
637 CGUIMediaWindow::UpdateButtons();
638 SET_CONTROL_LABEL(CONTROL_BTNCHANNELGROUPS, g_localizeStrings.Get(19141) + ": " + (m_group->GroupType() == PVR_GROUP_TYPE_INTERNAL ? g_localizeStrings.Get(19287) : m_group->GroupName()));