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 m_vecItems->SetPath(GetDirectoryPath());
108 CGUIMediaWindow::OnInitWindow();
111 bool CGUIWindowPVRBase::OnMessage(CGUIMessage& message)
113 switch (message.GetMessage())
115 case GUI_MSG_WINDOW_INIT:
117 m_group = g_PVRManager.GetPlayingGroup(m_bRadio);
118 SetProperty("IsRadio", m_bRadio ? "true" : "");
122 case GUI_MSG_CLICKED:
124 switch (message.GetSenderId())
126 case CONTROL_BTNCHANNELGROUPS:
127 return OpenGroupSelectionDialog();
133 return CGUIMediaWindow::OnMessage(message);
136 void CGUIWindowPVRBase::SetInvalid()
138 VECFILEITEMS items = m_vecItems->GetList();
139 for (VECFILEITEMS::iterator it = items.begin(); it != items.end(); ++it)
141 CGUIMediaWindow::SetInvalid();
144 bool CGUIWindowPVRBase::OpenGroupSelectionDialog(void)
146 CGUIDialogSelect *dialog = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
150 CFileItemList options;
151 g_PVRChannelGroups->Get(m_bRadio)->GetGroupList(&options);
154 dialog->SetHeading(g_localizeStrings.Get(19146));
155 dialog->SetItems(&options);
156 dialog->SetMultiSelection(false);
157 dialog->SetSelected(m_group->GroupName());
160 if (!dialog->IsConfirmed())
163 const CFileItemPtr item = dialog->GetSelectedItem();
167 SetGroup(g_PVRChannelGroups->Get(m_bRadio)->GetByName(item->m_strTitle));
172 CPVRChannelGroupPtr CGUIWindowPVRBase::GetGroup(void)
174 CSingleLock lock(m_critSection);
178 void CGUIWindowPVRBase::SetGroup(CPVRChannelGroupPtr group)
180 CSingleLock lock(m_critSection);
184 if (m_group != group)
187 m_group->UnregisterObserver(this);
189 // we need to register the window to receive changes from the new group
190 m_group->RegisterObserver(this);
191 g_PVRManager.SetPlayingGroup(m_group);
192 Update(GetDirectoryPath());
196 bool CGUIWindowPVRBase::PlayFile(CFileItem *item, bool bPlayMinimized /* = false */)
198 if (item->m_bIsFolder)
203 if (item->GetPath() == g_application.CurrentFile())
205 CGUIMessage msg(GUI_MSG_FULLSCREEN, 0, GetID());
206 g_windowManager.SendMessage(msg);
210 CMediaSettings::Get().SetVideoStartWindowed(bPlayMinimized);
212 if (item->HasPVRRecordingInfoTag())
214 return PlayRecording(item, bPlayMinimized);
218 bool bSwitchSuccessful(false);
220 CPVRChannel *channel = item->HasPVRChannelInfoTag() ? item->GetPVRChannelInfoTag() : NULL;
222 if (channel && g_PVRManager.CheckParentalLock(*channel))
224 /* try a fast switch */
225 if (channel && (g_PVRManager.IsPlayingTV() || g_PVRManager.IsPlayingRadio()) &&
226 (channel->IsRadio() == g_PVRManager.IsPlayingRadio()))
228 if (channel->StreamURL().empty())
229 bSwitchSuccessful = g_application.m_pPlayer->SwitchChannel(*channel);
232 if (!bSwitchSuccessful)
234 CApplicationMessenger::Get().PlayFile(*item, false);
239 if (!bSwitchSuccessful)
241 CStdString channelName = g_localizeStrings.Get(19029); // Channel
243 channelName = channel->ChannelName();
244 CStdString msg = StringUtils::Format(g_localizeStrings.Get(19035).c_str(), channelName.c_str()); // CHANNELNAME could not be played. Check the log for details.
246 CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Error,
247 g_localizeStrings.Get(19166), // PVR information
256 bool CGUIWindowPVRBase::StartRecordFile(const CFileItem &item)
258 if (!item.HasEPGInfoTag())
261 const CEpgInfoTag *tag = item.GetEPGInfoTag();
262 CPVRChannelPtr channel;
264 channel = tag->ChannelTag();
266 if (!channel || !g_PVRManager.CheckParentalLock(*channel))
269 CFileItemPtr timer = g_PVRTimers->GetTimerForEpgTag(&item);
270 if (timer && timer->HasPVRTimerInfoTag())
272 CGUIDialogOK::ShowAndGetInput(19033,19034,0,0);
276 // ask for confirmation before starting a timer
277 CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
280 pDialog->SetHeading(264);
281 pDialog->SetLine(0, tag->PVRChannelName());
282 pDialog->SetLine(1, "");
283 pDialog->SetLine(2, tag->Title());
286 if (!pDialog->IsConfirmed())
289 CPVRTimerInfoTag *newTimer = CPVRTimerInfoTag::CreateFromEpg(*tag);
293 bReturn = g_PVRTimers->AddTimer(*newTimer);
299 bool CGUIWindowPVRBase::StopRecordFile(const CFileItem &item)
301 if (!item.HasEPGInfoTag())
304 const CEpgInfoTag *tag = item.GetEPGInfoTag();
305 if (!tag || !tag->HasPVRChannel())
308 CFileItemPtr timer = g_PVRTimers->GetTimerForEpgTag(&item);
309 if (!timer || !timer->HasPVRTimerInfoTag() || timer->GetPVRTimerInfoTag()->m_bIsRepeating)
312 return g_PVRTimers->DeleteTimer(*timer);
315 bool CGUIWindowPVRBase::PlayRecording(CFileItem *item, bool bPlayMinimized /* = false */)
317 if (!item->HasPVRRecordingInfoTag())
320 CStdString stream = item->GetPVRRecordingInfoTag()->m_strStreamURL;
323 CApplicationMessenger::Get().PlayFile(*item, false);
327 /* Isolate the folder from the filename */
328 size_t found = stream.find_last_of("/");
329 if (found == CStdString::npos)
330 found = stream.find_last_of("\\");
332 if (found != CStdString::npos)
334 /* Check here for asterisk at the begin of the filename */
335 if (stream[found+1] == '*')
337 /* Create a "stack://" url with all files matching the extension */
338 CStdString ext = URIUtils::GetExtension(stream);
339 CStdString dir = stream.substr(0, found).c_str();
342 XFILE::CDirectory::GetDirectory(dir, items);
343 items.Sort(SortByFile, SortOrderAscending);
346 for (int i = 0; i < items.Size(); ++i)
348 if (URIUtils::HasExtension(items[i]->GetPath(), ext))
354 /* If we have a stack change the path of the item to it */
355 XFILE::CStackDirectory dir;
356 CStdString stackPath = dir.ConstructStackPath(items, stack);
357 item->SetPath(stackPath);
362 /* If no asterisk is present play only the given stream URL */
363 item->SetPath(stream);
368 CLog::Log(LOGERROR, "CGUIWindowPVRCommon - %s - can't open recording: no valid filename", __FUNCTION__);
369 CGUIDialogOK::ShowAndGetInput(19033,0,19036,0);
373 CApplicationMessenger::Get().PlayFile(*item, false);
378 void CGUIWindowPVRBase::ShowRecordingInfo(CFileItem *item)
380 CGUIDialogPVRRecordingInfo* pDlgInfo = (CGUIDialogPVRRecordingInfo*)g_windowManager.GetWindow(WINDOW_DIALOG_PVR_RECORDING_INFO);
381 if (item->IsPVRRecording() && pDlgInfo)
383 pDlgInfo->SetRecording(item);
388 void CGUIWindowPVRBase::ShowEPGInfo(CFileItem *item)
390 CFileItem *tag = NULL;
391 bool bHasChannel(false);
395 tag = new CFileItem(*item);
396 if (item->GetEPGInfoTag()->HasPVRChannel())
398 channel = *item->GetEPGInfoTag()->ChannelTag();
402 else if (item->IsPVRChannel())
405 channel = *item->GetPVRChannelInfoTag();
407 if (!item->GetPVRChannelInfoTag()->GetEPGNow(epgnow))
409 CGUIDialogOK::ShowAndGetInput(19033,0,19055,0);
412 tag = new CFileItem(epgnow);
415 CGUIDialogPVRGuideInfo* pDlgInfo = (CGUIDialogPVRGuideInfo*)g_windowManager.GetWindow(WINDOW_DIALOG_PVR_GUIDE_INFO);
416 if (tag && (!bHasChannel || g_PVRManager.CheckParentalLock(channel)) && pDlgInfo)
418 pDlgInfo->SetProgInfo(tag);
425 bool CGUIWindowPVRBase::ActionInputChannelNumber(int input)
427 CStdString strInput = StringUtils::Format("%i", input);
428 if (CGUIDialogNumeric::ShowAndGetNumber(strInput, g_localizeStrings.Get(19103)))
430 int iChannelNumber = atoi(strInput.c_str());
431 if (iChannelNumber >= 0)
434 VECFILEITEMS items = m_vecItems->GetList();
435 for (VECFILEITEMS::iterator it = items.begin(); it != items.end(); ++it)
437 if(((*it)->HasPVRChannelInfoTag() && (*it)->GetPVRChannelInfoTag()->ChannelNumber() == iChannelNumber) ||
438 ((*it)->HasEPGInfoTag() && (*it)->GetEPGInfoTag()->HasPVRChannel() && (*it)->GetEPGInfoTag()->PVRChannelNumber() == iChannelNumber))
440 // different handling for guide grid
441 if ((GetID() == WINDOW_TV_GUIDE || GetID() == WINDOW_RADIO_GUIDE) &&
442 m_viewControl.GetCurrentControl() == GUIDE_VIEW_TIMELINE)
444 CGUIEPGGridContainer* epgGridContainer = (CGUIEPGGridContainer*) GetControl(m_viewControl.GetCurrentControl());
445 epgGridContainer->SetChannel((*(*it)->GetEPGInfoTag()->ChannelTag()));
448 m_viewControl.SetSelectedItem(itemIndex);
459 bool CGUIWindowPVRBase::ActionPlayChannel(CFileItem *item)
461 bool bReturn = false;
463 if (item->GetPath() == "pvr://channels/.add.channel")
465 /* show "add channel" dialog */
466 CGUIDialogOK::ShowAndGetInput(19033,0,19038,0);
472 bReturn = PlayFile(item, CSettings::Get().GetBool("pvrplayback.playminimized"));
478 bool CGUIWindowPVRBase::ActionPlayEpg(CFileItem *item)
480 if (!item || !item->HasEPGInfoTag())
483 CPVRChannelPtr channel;
484 CEpgInfoTag *epgTag = item->GetEPGInfoTag();
485 if (epgTag->HasPVRChannel())
486 channel = epgTag->ChannelTag();
488 if (!channel || !g_PVRManager.CheckParentalLock(*channel))
492 if (epgTag->HasRecording())
493 fileItem = CFileItem(*epgTag->Recording());
495 fileItem = CFileItem(*channel);
497 g_application.SwitchToFullScreen();
498 if (!PlayFile(&fileItem))
500 // CHANNELNAME could not be played. Check the log for details.
501 CStdString msg = StringUtils::Format(g_localizeStrings.Get(19035).c_str(), channel->ChannelName().c_str());
502 CGUIDialogOK::ShowAndGetInput(19033, 0, msg, 0);
509 bool CGUIWindowPVRBase::ActionDeleteChannel(CFileItem *item)
511 CPVRChannel *channel = item->GetPVRChannelInfoTag();
513 /* check if the channel tag is valid */
514 if (!channel || channel->ChannelNumber() <= 0)
517 /* show a confirmation dialog */
518 CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*) g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
521 pDialog->SetHeading(19039);
522 pDialog->SetLine(0, "");
523 pDialog->SetLine(1, channel->ChannelName());
524 pDialog->SetLine(2, "");
527 /* prompt for the user's confirmation */
528 if (!pDialog->IsConfirmed())
531 g_PVRChannelGroups->GetGroupAll(channel->IsRadio())->RemoveFromGroup(*channel);
537 bool CGUIWindowPVRBase::ActionDeleteRecording(CFileItem *item)
539 bool bReturn = false;
541 /* check if the recording tag is valid */
542 CPVRRecording *recTag = (CPVRRecording *) item->GetPVRRecordingInfoTag();
543 if (!recTag || recTag->m_strRecordingId.empty())
546 /* show a confirmation dialog */
547 CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
551 pDialog->SetHeading(122); // Confirm delete
552 pDialog->SetLine(0, item->m_bIsFolder ? 19113 : 19112); // Are you sure?
553 pDialog->SetLine(1, "");
554 pDialog->SetLine(2, item->GetLabel());
555 pDialog->SetChoice(1, 117); // Delete
557 /* prompt for the user's confirmation */
559 if (!pDialog->IsConfirmed())
562 /* delete the recording */
563 if (g_PVRRecordings->Delete(*item))
565 g_PVRManager.TriggerRecordingsUpdate();
572 bool CGUIWindowPVRBase::ActionRecord(CFileItem *item)
574 bool bReturn = false;
576 CEpgInfoTag *epgTag = item->GetEPGInfoTag();
580 CPVRChannelPtr channel = epgTag->ChannelTag();
581 if (!channel || !g_PVRManager.CheckParentalLock(*channel))
584 if (epgTag->Timer() == NULL)
586 /* create a confirmation dialog */
587 CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*) g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
591 pDialog->SetHeading(264);
592 pDialog->SetLine(0, "");
593 pDialog->SetLine(1, epgTag->Title());
594 pDialog->SetLine(2, "");
597 /* prompt for the user's confirmation */
598 if (!pDialog->IsConfirmed())
601 CPVRTimerInfoTag *newTimer = CPVRTimerInfoTag::CreateFromEpg(*epgTag);
604 bReturn = g_PVRTimers->AddTimer(*newTimer);
614 CGUIDialogOK::ShowAndGetInput(19033,19034,0,0);
621 bool CGUIWindowPVRBase::UpdateEpgForChannel(CFileItem *item)
623 CPVRChannel *channel = item->GetPVRChannelInfoTag();
624 CEpg *epg = channel->GetEPG();
632 bool CGUIWindowPVRBase::Update(const std::string &strDirectory, bool updateFilterPath /* = true */)
634 return CGUIMediaWindow::Update(strDirectory, updateFilterPath);
637 void CGUIWindowPVRBase::UpdateButtons(void)
639 CGUIMediaWindow::UpdateButtons();
640 SET_CONTROL_LABEL(CONTROL_BTNCHANNELGROUPS, g_localizeStrings.Get(19141) + ": " + (m_group->GroupType() == PVR_GROUP_TYPE_INTERNAL ? g_localizeStrings.Get(19287) : m_group->GroupName()));