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(), 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 bool CGUIWindowPVRBase::OpenGroupSelectionDialog(void)
136 CGUIDialogSelect *dialog = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
140 CFileItemList options;
141 g_PVRChannelGroups->Get(m_bRadio)->GetGroupList(&options);
144 dialog->SetHeading(g_localizeStrings.Get(19146));
145 dialog->SetItems(&options);
146 dialog->SetMultiSelection(false);
147 dialog->SetSelected(m_group->GroupName());
150 if (!dialog->IsConfirmed())
153 const CFileItemPtr item = dialog->GetSelectedItem();
157 SetGroup(g_PVRChannelGroups->Get(m_bRadio)->GetByName(item->m_strTitle));
162 CPVRChannelGroupPtr CGUIWindowPVRBase::GetGroup(void)
164 CSingleLock lock(m_critSection);
168 void CGUIWindowPVRBase::SetGroup(CPVRChannelGroupPtr group)
170 CSingleLock lock(m_critSection);
174 if (m_group != group)
177 m_group->UnregisterObserver(this);
179 // we need to register the window to receive changes from the new group
180 m_group->RegisterObserver(this);
181 g_PVRManager.SetPlayingGroup(m_group);
186 bool CGUIWindowPVRBase::PlayFile(CFileItem *item, bool bPlayMinimized /* = false */)
188 if (item->m_bIsFolder)
193 if (item->GetPath() == g_application.CurrentFile())
195 CGUIMessage msg(GUI_MSG_FULLSCREEN, 0, GetID());
196 g_windowManager.SendMessage(msg);
200 CMediaSettings::Get().SetVideoStartWindowed(bPlayMinimized);
202 if (item->HasPVRRecordingInfoTag())
204 return PlayRecording(item, bPlayMinimized);
208 bool bSwitchSuccessful(false);
210 CPVRChannel *channel = item->HasPVRChannelInfoTag() ? item->GetPVRChannelInfoTag() : NULL;
212 if (channel && g_PVRManager.CheckParentalLock(*channel))
214 /* try a fast switch */
215 if (channel && (g_PVRManager.IsPlayingTV() || g_PVRManager.IsPlayingRadio()) &&
216 (channel->IsRadio() == g_PVRManager.IsPlayingRadio()))
218 if (channel->StreamURL().empty())
219 bSwitchSuccessful = g_application.m_pPlayer->SwitchChannel(*channel);
222 if (!bSwitchSuccessful)
224 CApplicationMessenger::Get().PlayFile(*item, false);
229 if (!bSwitchSuccessful)
231 CStdString channelName = g_localizeStrings.Get(19029); // Channel
233 channelName = channel->ChannelName();
234 CStdString msg = StringUtils::Format(g_localizeStrings.Get(19035).c_str(), channelName.c_str()); // CHANNELNAME could not be played. Check the log for details.
236 CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Error,
237 g_localizeStrings.Get(19166), // PVR information
246 bool CGUIWindowPVRBase::StartRecordFile(const CFileItem &item)
248 if (!item.HasEPGInfoTag())
251 const CEpgInfoTag *tag = item.GetEPGInfoTag();
252 CPVRChannelPtr channel;
254 channel = tag->ChannelTag();
256 if (!channel || !g_PVRManager.CheckParentalLock(*channel))
259 CFileItemPtr timer = g_PVRTimers->GetTimerForEpgTag(&item);
260 if (timer && timer->HasPVRTimerInfoTag())
262 CGUIDialogOK::ShowAndGetInput(19033,19034,0,0);
266 // ask for confirmation before starting a timer
267 CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
270 pDialog->SetHeading(264);
271 pDialog->SetLine(0, tag->PVRChannelName());
272 pDialog->SetLine(1, "");
273 pDialog->SetLine(2, tag->Title());
276 if (!pDialog->IsConfirmed())
279 CPVRTimerInfoTag *newTimer = CPVRTimerInfoTag::CreateFromEpg(*tag);
283 bReturn = g_PVRTimers->AddTimer(*newTimer);
289 bool CGUIWindowPVRBase::StopRecordFile(const CFileItem &item)
291 if (!item.HasEPGInfoTag())
294 const CEpgInfoTag *tag = item.GetEPGInfoTag();
295 if (!tag || !tag->HasPVRChannel())
298 CFileItemPtr timer = g_PVRTimers->GetTimerForEpgTag(&item);
299 if (!timer || !timer->HasPVRTimerInfoTag() || timer->GetPVRTimerInfoTag()->m_bIsRepeating)
302 return g_PVRTimers->DeleteTimer(*timer);
305 bool CGUIWindowPVRBase::PlayRecording(CFileItem *item, bool bPlayMinimized /* = false */)
307 if (!item->HasPVRRecordingInfoTag())
310 CStdString stream = item->GetPVRRecordingInfoTag()->m_strStreamURL;
313 CApplicationMessenger::Get().PlayFile(*item, false);
317 /* Isolate the folder from the filename */
318 size_t found = stream.find_last_of("/");
319 if (found == CStdString::npos)
320 found = stream.find_last_of("\\");
322 if (found != CStdString::npos)
324 /* Check here for asterisk at the begin of the filename */
325 if (stream[found+1] == '*')
327 /* Create a "stack://" url with all files matching the extension */
328 CStdString ext = URIUtils::GetExtension(stream);
329 CStdString dir = stream.substr(0, found).c_str();
332 XFILE::CDirectory::GetDirectory(dir, items);
333 items.Sort(SortByFile, SortOrderAscending);
336 for (int i = 0; i < items.Size(); ++i)
338 if (URIUtils::HasExtension(items[i]->GetPath(), ext))
344 /* If we have a stack change the path of the item to it */
345 XFILE::CStackDirectory dir;
346 CStdString stackPath = dir.ConstructStackPath(items, stack);
347 item->SetPath(stackPath);
352 /* If no asterisk is present play only the given stream URL */
353 item->SetPath(stream);
358 CLog::Log(LOGERROR, "CGUIWindowPVRCommon - %s - can't open recording: no valid filename", __FUNCTION__);
359 CGUIDialogOK::ShowAndGetInput(19033,0,19036,0);
363 CApplicationMessenger::Get().PlayFile(*item, false);
368 void CGUIWindowPVRBase::ShowRecordingInfo(CFileItem *item)
370 CGUIDialogPVRRecordingInfo* pDlgInfo = (CGUIDialogPVRRecordingInfo*)g_windowManager.GetWindow(WINDOW_DIALOG_PVR_RECORDING_INFO);
371 if (item->IsPVRRecording() && pDlgInfo)
373 pDlgInfo->SetRecording(item);
378 void CGUIWindowPVRBase::ShowEPGInfo(CFileItem *item)
380 CFileItem *tag = NULL;
381 bool bHasChannel(false);
385 tag = new CFileItem(*item);
386 if (item->GetEPGInfoTag()->HasPVRChannel())
388 channel = *item->GetEPGInfoTag()->ChannelTag();
392 else if (item->IsPVRChannel())
395 channel = *item->GetPVRChannelInfoTag();
397 if (!item->GetPVRChannelInfoTag()->GetEPGNow(epgnow))
399 CGUIDialogOK::ShowAndGetInput(19033,0,19055,0);
402 tag = new CFileItem(epgnow);
405 CGUIDialogPVRGuideInfo* pDlgInfo = (CGUIDialogPVRGuideInfo*)g_windowManager.GetWindow(WINDOW_DIALOG_PVR_GUIDE_INFO);
406 if (tag && (!bHasChannel || g_PVRManager.CheckParentalLock(channel)) && pDlgInfo)
408 pDlgInfo->SetProgInfo(tag);
415 bool CGUIWindowPVRBase::ActionInputChannelNumber(int input)
417 CStdString strInput = StringUtils::Format("%i", input);
418 if (CGUIDialogNumeric::ShowAndGetNumber(strInput, g_localizeStrings.Get(19103)))
420 int iChannelNumber = atoi(strInput.c_str());
421 if (iChannelNumber >= 0)
424 VECFILEITEMS items = m_vecItems->GetList();
425 for (VECFILEITEMS::iterator it = items.begin(); it != items.end(); ++it)
427 if(((*it)->HasPVRChannelInfoTag() && (*it)->GetPVRChannelInfoTag()->ChannelNumber() == iChannelNumber) ||
428 ((*it)->HasEPGInfoTag() && (*it)->GetEPGInfoTag()->HasPVRChannel() && (*it)->GetEPGInfoTag()->PVRChannelNumber() == iChannelNumber))
430 // different handling for guide grid
431 if ((GetID() == WINDOW_TV_GUIDE || GetID() == WINDOW_RADIO_GUIDE) &&
432 m_viewControl.GetCurrentControl() == GUIDE_VIEW_TIMELINE)
434 CGUIEPGGridContainer* epgGridContainer = (CGUIEPGGridContainer*) GetControl(m_viewControl.GetCurrentControl());
435 epgGridContainer->SetChannel((*(*it)->GetEPGInfoTag()->ChannelTag()));
438 m_viewControl.SetSelectedItem(itemIndex);
449 bool CGUIWindowPVRBase::ActionPlayChannel(CFileItem *item)
451 bool bReturn = false;
453 if (item->GetPath() == "pvr://channels/.add.channel")
455 /* show "add channel" dialog */
456 CGUIDialogOK::ShowAndGetInput(19033,0,19038,0);
462 bReturn = PlayFile(item, CSettings::Get().GetBool("pvrplayback.playminimized"));
468 bool CGUIWindowPVRBase::ActionPlayEpg(CFileItem *item)
470 if (!item || !item->HasEPGInfoTag())
473 CPVRChannelPtr channel;
474 CEpgInfoTag *epgTag = item->GetEPGInfoTag();
475 if (epgTag->HasPVRChannel())
476 channel = epgTag->ChannelTag();
478 if (!channel || !g_PVRManager.CheckParentalLock(*channel))
482 if (epgTag->HasRecording())
483 fileItem = CFileItem(*epgTag->Recording());
485 fileItem = CFileItem(*channel);
487 g_application.SwitchToFullScreen();
488 if (!PlayFile(&fileItem))
490 // CHANNELNAME could not be played. Check the log for details.
491 CStdString msg = StringUtils::Format(g_localizeStrings.Get(19035).c_str(), channel->ChannelName().c_str());
492 CGUIDialogOK::ShowAndGetInput(19033, 0, msg, 0);
499 bool CGUIWindowPVRBase::ActionDeleteChannel(CFileItem *item)
501 CPVRChannel *channel = item->GetPVRChannelInfoTag();
503 /* check if the channel tag is valid */
504 if (!channel || channel->ChannelNumber() <= 0)
507 /* show a confirmation dialog */
508 CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*) g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
511 pDialog->SetHeading(19039);
512 pDialog->SetLine(0, "");
513 pDialog->SetLine(1, channel->ChannelName());
514 pDialog->SetLine(2, "");
517 /* prompt for the user's confirmation */
518 if (!pDialog->IsConfirmed())
521 g_PVRChannelGroups->GetGroupAll(channel->IsRadio())->RemoveFromGroup(*channel);
527 bool CGUIWindowPVRBase::ActionDeleteRecording(CFileItem *item)
529 bool bReturn = false;
531 /* check if the recording tag is valid */
532 CPVRRecording *recTag = (CPVRRecording *) item->GetPVRRecordingInfoTag();
533 if (!recTag || recTag->m_strRecordingId.empty())
536 /* show a confirmation dialog */
537 CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
541 pDialog->SetHeading(122); // Confirm delete
542 pDialog->SetLine(0, item->m_bIsFolder ? 19113 : 19112); // Are you sure?
543 pDialog->SetLine(1, "");
544 pDialog->SetLine(2, item->GetLabel());
545 pDialog->SetChoice(1, 117); // Delete
547 /* prompt for the user's confirmation */
549 if (!pDialog->IsConfirmed())
552 /* delete the recording */
553 if (g_PVRRecordings->Delete(*item))
555 g_PVRManager.TriggerRecordingsUpdate();
562 bool CGUIWindowPVRBase::ActionRecord(CFileItem *item)
564 bool bReturn = false;
566 CEpgInfoTag *epgTag = item->GetEPGInfoTag();
570 CPVRChannelPtr channel = epgTag->ChannelTag();
571 if (!channel || !g_PVRManager.CheckParentalLock(*channel))
574 if (epgTag->Timer() == NULL)
576 /* create a confirmation dialog */
577 CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*) g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
581 pDialog->SetHeading(264);
582 pDialog->SetLine(0, "");
583 pDialog->SetLine(1, epgTag->Title());
584 pDialog->SetLine(2, "");
587 /* prompt for the user's confirmation */
588 if (!pDialog->IsConfirmed())
591 CPVRTimerInfoTag *newTimer = CPVRTimerInfoTag::CreateFromEpg(*epgTag);
594 bReturn = g_PVRTimers->AddTimer(*newTimer);
604 CGUIDialogOK::ShowAndGetInput(19033,19034,0,0);
611 bool CGUIWindowPVRBase::UpdateEpgForChannel(CFileItem *item)
613 CPVRChannel *channel = item->GetPVRChannelInfoTag();
614 CEpg *epg = channel->GetEPG();
622 bool CGUIWindowPVRBase::Update(const std::string &strDirectory, bool updateFilterPath /* = true */)
624 return CGUIMediaWindow::Update(strDirectory, updateFilterPath);
627 void CGUIWindowPVRBase::UpdateButtons(void)
629 CGUIMediaWindow::UpdateButtons();
630 SET_CONTROL_LABEL(CONTROL_BTNCHANNELGROUPS, g_localizeStrings.Get(19141) + ": " + (m_group->GroupType() == PVR_GROUP_TYPE_INTERNAL ? g_localizeStrings.Get(19287) : m_group->GroupName()));