/* * Copyright (C) 2012-2018 Team Kodi * This file is part of Kodi - https://kodi.tv * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSES/README.md for more information. */ #include "GUIWindowPVRChannels.h" #include "FileItem.h" #include "GUIInfoManager.h" #include "ServiceBroker.h" #include "dialogs/GUIDialogContextMenu.h" #include "dialogs/GUIDialogKaiToast.h" #include "dialogs/GUIDialogYesNo.h" #include "guilib/GUIComponent.h" #include "guilib/GUIKeyboardFactory.h" #include "guilib/GUIMessage.h" #include "guilib/GUIRadioButtonControl.h" #include "guilib/GUIWindowManager.h" #include "guilib/LocalizeStrings.h" #include "input/Key.h" #include "input/actions/Action.h" #include "pvr/PVRManager.h" #include "pvr/channels/PVRChannel.h" #include "pvr/channels/PVRChannelGroup.h" #include "pvr/channels/PVRChannelGroupMember.h" #include "pvr/channels/PVRChannelGroupsContainer.h" #include "pvr/channels/PVRChannelsPath.h" #include "pvr/dialogs/GUIDialogPVRChannelManager.h" #include "pvr/dialogs/GUIDialogPVRGroupManager.h" #include "pvr/epg/Epg.h" #include "pvr/epg/EpgContainer.h" #include "pvr/guilib/PVRGUIActionsChannels.h" #include "pvr/guilib/PVRGUIActionsEPG.h" #include "pvr/guilib/PVRGUIActionsPlayback.h" #include "utils/StringUtils.h" #include "utils/Variant.h" #include #include using namespace PVR; CGUIWindowPVRChannelsBase::CGUIWindowPVRChannelsBase(bool bRadio, int id, const std::string& xmlFile) : CGUIWindowPVRBase(bRadio, id, xmlFile), m_bShowHiddenChannels(false) { CServiceBroker::GetPVRManager().Get().RegisterChannelNumberInputHandler(this); } CGUIWindowPVRChannelsBase::~CGUIWindowPVRChannelsBase() { CServiceBroker::GetPVRManager().Get().DeregisterChannelNumberInputHandler( this); } std::string CGUIWindowPVRChannelsBase::GetRootPath() const { //! @todo Would it make sense to change GetRootPath() declaration in CGUIMediaWindow //! to be non-const to get rid of the const_cast's here? CGUIWindowPVRChannelsBase* pThis = const_cast(this); if (pThis->InitChannelGroup()) return pThis->GetDirectoryPath(); return CGUIWindowPVRBase::GetRootPath(); } void CGUIWindowPVRChannelsBase::GetContextButtons(int itemNumber, CContextButtons& buttons) { // Add parent buttons before the Manage button CGUIWindowPVRBase::GetContextButtons(itemNumber, buttons); buttons.Add(CONTEXT_BUTTON_EDIT, 16106); /* Manage... */ } bool CGUIWindowPVRChannelsBase::OnContextButton(int itemNumber, CONTEXT_BUTTON button) { if (itemNumber < 0 || itemNumber >= m_vecItems->Size()) return false; return OnContextButtonManage(m_vecItems->Get(itemNumber), button) || CGUIMediaWindow::OnContextButton(itemNumber, button); } bool CGUIWindowPVRChannelsBase::Update(const std::string& strDirectory, bool updateFilterPath /* = true */) { bool bReturn = CGUIWindowPVRBase::Update(strDirectory); if (bReturn) { std::unique_lock lock(m_critSection); /* empty list for hidden channels */ if (m_vecItems->GetObjectCount() == 0 && m_bShowHiddenChannels) { /* show the visible channels instead */ m_bShowHiddenChannels = false; lock.unlock(); Update(GetDirectoryPath()); } } return bReturn; } void CGUIWindowPVRChannelsBase::UpdateButtons() { CGUIRadioButtonControl* btnShowHidden = static_cast(GetControl(CONTROL_BTNSHOWHIDDEN)); if (btnShowHidden) { btnShowHidden->SetVisible(CServiceBroker::GetPVRManager() .ChannelGroups() ->GetGroupAll(m_bRadio) ->GetNumHiddenChannels() > 0); btnShowHidden->SetSelected(m_bShowHiddenChannels); } CGUIWindowPVRBase::UpdateButtons(); SET_CONTROL_LABEL(CONTROL_LABEL_HEADER1, m_bShowHiddenChannels ? g_localizeStrings.Get(19022) : GetChannelGroup()->GroupName()); } bool CGUIWindowPVRChannelsBase::OnAction(const CAction& action) { switch (action.GetID()) { case REMOTE_0: case REMOTE_1: case REMOTE_2: case REMOTE_3: case REMOTE_4: case REMOTE_5: case REMOTE_6: case REMOTE_7: case REMOTE_8: case REMOTE_9: AppendChannelNumberCharacter(static_cast(action.GetID() - REMOTE_0) + '0'); return true; case ACTION_CHANNEL_NUMBER_SEP: AppendChannelNumberCharacter(CPVRChannelNumber::SEPARATOR); return true; } return CGUIWindowPVRBase::OnAction(action); } bool CGUIWindowPVRChannelsBase::OnMessage(CGUIMessage& message) { bool bReturn = false; switch (message.GetMessage()) { case GUI_MSG_WINDOW_INIT: { const CPVRChannelsPath path(message.GetStringParam(0)); if (path.IsValid() && path.IsChannelGroup()) { // if a path to a channel group is given we must init // that group instead of last played/selected group m_channelGroupPath = message.GetStringParam(0); } break; } case GUI_MSG_CLICKED: if (message.GetSenderId() == m_viewControl.GetCurrentControl()) { if (message.GetParam1() == ACTION_SELECT_ITEM || message.GetParam1() == ACTION_MOUSE_LEFT_CLICK) { // If direct channel number input is active, select the entered channel. if (CServiceBroker::GetPVRManager() .Get() .GetChannelNumberInputHandler() .CheckInputAndExecuteAction()) { bReturn = true; break; } } int iItem = m_viewControl.GetSelectedItem(); if (iItem >= 0 && iItem < m_vecItems->Size()) { bReturn = true; switch (message.GetParam1()) { case ACTION_SELECT_ITEM: case ACTION_MOUSE_LEFT_CLICK: case ACTION_PLAYER_PLAY: CServiceBroker::GetPVRManager().Get().SwitchToChannel( *(m_vecItems->Get(iItem)), true); break; case ACTION_SHOW_INFO: CServiceBroker::GetPVRManager().Get().ShowEPGInfo( *(m_vecItems->Get(iItem))); break; case ACTION_DELETE_ITEM: CServiceBroker::GetPVRManager().Get().HideChannel( *(m_vecItems->Get(iItem))); break; case ACTION_CONTEXT_MENU: case ACTION_MOUSE_RIGHT_CLICK: OnPopupMenu(iItem); break; default: bReturn = false; break; } } } else if (message.GetSenderId() == CONTROL_BTNSHOWHIDDEN) { CGUIRadioButtonControl* radioButton = static_cast(GetControl(CONTROL_BTNSHOWHIDDEN)); if (radioButton) { m_bShowHiddenChannels = radioButton->IsSelected(); Update(GetDirectoryPath()); } bReturn = true; } else if (message.GetSenderId() == CONTROL_BTNFILTERCHANNELS) { std::string filter = GetProperty("filter").asString(); CGUIKeyboardFactory::ShowAndGetFilter(filter, false); OnFilterItems(filter); UpdateButtons(); bReturn = true; } break; case GUI_MSG_REFRESH_LIST: { switch (static_cast(message.GetParam1())) { case PVREvent::ChannelGroup: case PVREvent::CurrentItem: case PVREvent::Epg: case PVREvent::EpgActiveItem: case PVREvent::EpgContainer: case PVREvent::RecordingsInvalidated: case PVREvent::Timers: SetInvalid(); break; case PVREvent::ChannelGroupInvalidated: Refresh(true); break; default: break; } break; } } return bReturn || CGUIWindowPVRBase::OnMessage(message); } bool CGUIWindowPVRChannelsBase::OnContextButtonManage(const CFileItemPtr& item, CONTEXT_BUTTON button) { bool bReturn = false; if (button == CONTEXT_BUTTON_EDIT) { // Create context sub menu CContextButtons buttons; buttons.Add(CONTEXT_BUTTON_GROUP_MANAGER, 19048); buttons.Add(CONTEXT_BUTTON_CHANNEL_MANAGER, 19199); buttons.Add(CONTEXT_BUTTON_UPDATE_EPG, 19251); // Get the response int choice = CGUIDialogContextMenu::ShowAndGetChoice(buttons); if (choice >= 0) { switch (static_cast(choice)) { case CONTEXT_BUTTON_GROUP_MANAGER: ShowGroupManager(); break; case CONTEXT_BUTTON_CHANNEL_MANAGER: ShowChannelManager(); break; case CONTEXT_BUTTON_UPDATE_EPG: UpdateEpg(item); break; default: break; } // Refresh the list in case anything was changed Refresh(true); } bReturn = true; } return bReturn; } void CGUIWindowPVRChannelsBase::UpdateEpg(const CFileItemPtr& item) { const std::shared_ptr channel(item->GetPVRChannelInfoTag()); if (!CGUIDialogYesNo::ShowAndGetInput( CVariant{19251}, // "Update guide information" CVariant{19252}, // "Schedule guide update for this channel?" CVariant{""}, CVariant{channel->ChannelName()})) return; const std::shared_ptr epg = channel->GetEPG(); if (epg) { epg->ForceUpdate(); const std::string strMessage = StringUtils::Format("{}: '{}'", g_localizeStrings.Get(19253), // "Guide update scheduled for channel" channel->ChannelName()); CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info, g_localizeStrings.Get(19166), // "PVR information" strMessage); } else { const std::string strMessage = StringUtils::Format("{}: '{}'", g_localizeStrings.Get(19254), // "Guide update failed for channel" channel->ChannelName()); CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Error, g_localizeStrings.Get(19166), // "PVR information" strMessage); } } void CGUIWindowPVRChannelsBase::ShowChannelManager() { CGUIDialogPVRChannelManager* dialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow( WINDOW_DIALOG_PVR_CHANNEL_MANAGER); if (!dialog) return; dialog->SetRadio(m_bRadio); const int iItem = m_viewControl.GetSelectedItem(); dialog->Open(iItem >= 0 && iItem < m_vecItems->Size() ? m_vecItems->Get(iItem) : nullptr); } void CGUIWindowPVRChannelsBase::ShowGroupManager() { /* Load group manager dialog */ CGUIDialogPVRGroupManager* pDlgInfo = CServiceBroker::GetGUI()->GetWindowManager().GetWindow( WINDOW_DIALOG_PVR_GROUP_MANAGER); if (!pDlgInfo) return; pDlgInfo->SetRadio(m_bRadio); pDlgInfo->Open(); } void CGUIWindowPVRChannelsBase::OnInputDone() { const CPVRChannelNumber channelNumber = GetChannelNumber(); if (channelNumber.IsValid()) { int itemIndex = 0; for (const CFileItemPtr& channel : *m_vecItems) { if (channel->GetPVRChannelGroupMemberInfoTag()->ChannelNumber() == channelNumber) { m_viewControl.SetSelectedItem(itemIndex); return; } ++itemIndex; } } } void CGUIWindowPVRChannelsBase::GetChannelNumbers(std::vector& channelNumbers) { const std::shared_ptr group = GetChannelGroup(); if (group) group->GetChannelNumbers(channelNumbers); } CGUIWindowPVRTVChannels::CGUIWindowPVRTVChannels() : CGUIWindowPVRChannelsBase(false, WINDOW_TV_CHANNELS, "MyPVRChannels.xml") { } std::string CGUIWindowPVRTVChannels::GetDirectoryPath() { return CPVRChannelsPath(false, m_bShowHiddenChannels, GetChannelGroup()->GroupName()); } CGUIWindowPVRRadioChannels::CGUIWindowPVRRadioChannels() : CGUIWindowPVRChannelsBase(true, WINDOW_RADIO_CHANNELS, "MyPVRChannels.xml") { } std::string CGUIWindowPVRRadioChannels::GetDirectoryPath() { return CPVRChannelsPath(true, m_bShowHiddenChannels, GetChannelGroup()->GroupName()); }