diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 18:07:22 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 18:07:22 +0000 |
commit | c04dcc2e7d834218ef2d4194331e383402495ae1 (patch) | |
tree | 7333e38d10d75386e60f336b80c2443c1166031d /xbmc/pvr/dialogs/GUIDialogPVRChannelManager.cpp | |
parent | Initial commit. (diff) | |
download | kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.tar.xz kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.zip |
Adding upstream version 2:20.4+dfsg.upstream/2%20.4+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'xbmc/pvr/dialogs/GUIDialogPVRChannelManager.cpp')
-rw-r--r-- | xbmc/pvr/dialogs/GUIDialogPVRChannelManager.cpp | 1076 |
1 files changed, 1076 insertions, 0 deletions
diff --git a/xbmc/pvr/dialogs/GUIDialogPVRChannelManager.cpp b/xbmc/pvr/dialogs/GUIDialogPVRChannelManager.cpp new file mode 100644 index 0000000..267b3c6 --- /dev/null +++ b/xbmc/pvr/dialogs/GUIDialogPVRChannelManager.cpp @@ -0,0 +1,1076 @@ +/* + * 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 "GUIDialogPVRChannelManager.h" + +#include "FileItem.h" +#include "GUIPassword.h" +#include "ServiceBroker.h" +#include "TextureCache.h" +#include "dialogs/GUIDialogFileBrowser.h" +#include "dialogs/GUIDialogProgress.h" +#include "dialogs/GUIDialogSelect.h" +#include "dialogs/GUIDialogYesNo.h" +#include "guilib/GUIComponent.h" +#include "guilib/GUIEditControl.h" +#include "guilib/GUIMessage.h" +#include "guilib/GUISpinControlEx.h" +#include "guilib/GUIWindowManager.h" +#include "guilib/LocalizeStrings.h" +#include "input/actions/Action.h" +#include "input/actions/ActionIDs.h" +#include "messaging/helpers/DialogOKHelper.h" +#include "profiles/ProfileManager.h" +#include "pvr/PVRManager.h" +#include "pvr/addons/PVRClient.h" +#include "pvr/addons/PVRClients.h" +#include "pvr/channels/PVRChannel.h" +#include "pvr/channels/PVRChannelGroupMember.h" +#include "pvr/channels/PVRChannelGroups.h" +#include "pvr/channels/PVRChannelGroupsContainer.h" +#include "pvr/dialogs/GUIDialogPVRGroupManager.h" +#include "pvr/guilib/PVRGUIActionsParentalControl.h" +#include "settings/Settings.h" +#include "settings/SettingsComponent.h" +#include "storage/MediaManager.h" +#include "utils/StringUtils.h" +#include "utils/Variant.h" + +#include <algorithm> +#include <memory> +#include <string> +#include <utility> +#include <vector> + +#define BUTTON_OK 4 +#define BUTTON_APPLY 5 +#define BUTTON_CANCEL 6 +#define RADIOBUTTON_ACTIVE 7 +#define EDIT_NAME 8 +#define BUTTON_CHANNEL_LOGO 9 +#define IMAGE_CHANNEL_LOGO 10 +#define RADIOBUTTON_USEEPG 12 +#define SPIN_EPGSOURCE_SELECTION 13 +#define RADIOBUTTON_PARENTAL_LOCK 14 +#define CONTROL_LIST_CHANNELS 20 +#define BUTTON_GROUP_MANAGER 30 +#define BUTTON_NEW_CHANNEL 31 +#define BUTTON_RADIO_TV 34 +#define BUTTON_REFRESH_LOGOS 35 + +namespace +{ +constexpr const char* LABEL_CHANNEL_DISABLED = "0"; + +// Note: strings must not be changed; they are part of the public skinning API for this dialog. +constexpr const char* PROPERTY_CHANNEL_NUMBER = "Number"; +constexpr const char* PROPERTY_CHANNEL_ENABLED = "ActiveChannel"; +constexpr const char* PROPERTY_CHANNEL_USER_SET_HIDDEN = "UserSetHidden"; +constexpr const char* PROPERTY_CHANNEL_LOCKED = "ParentalLocked"; +constexpr const char* PROPERTY_CHANNEL_ICON = "Icon"; +constexpr const char* PROPERTY_CHANNEL_CUSTOM_ICON = "UserSetIcon"; +constexpr const char* PROPERTY_CHANNEL_NAME = "Name"; +constexpr const char* PROPERTY_CHANNEL_EPG_ENABLED = "UseEPG"; +constexpr const char* PROPERTY_CHANNEL_EPG_SOURCE = "EPGSource"; +constexpr const char* PROPERTY_CLIENT_SUPPORTS_SETTINGS = "SupportsSettings"; +constexpr const char* PROPERTY_CLIENT_NAME = "ClientName"; +constexpr const char* PROPERTY_ITEM_CHANGED = "Changed"; + +} // namespace + +using namespace PVR; +using namespace KODI::MESSAGING; + +CGUIDialogPVRChannelManager::CGUIDialogPVRChannelManager() : + CGUIDialog(WINDOW_DIALOG_PVR_CHANNEL_MANAGER, "DialogPVRChannelManager.xml"), + m_channelItems(new CFileItemList) +{ + SetRadio(false); +} + +CGUIDialogPVRChannelManager::~CGUIDialogPVRChannelManager() +{ + delete m_channelItems; +} + +bool CGUIDialogPVRChannelManager::OnActionMove(const CAction& action) +{ + bool bReturn(false); + int iActionId = action.GetID(); + + if (GetFocusedControlID() == CONTROL_LIST_CHANNELS) + { + if (iActionId == ACTION_MOUSE_MOVE) + { + int iSelected = m_viewControl.GetSelectedItem(); + if (m_iSelected < iSelected) + { + iActionId = ACTION_MOVE_DOWN; + } + else if (m_iSelected > iSelected) + { + iActionId = ACTION_MOVE_UP; + } + else + { + return bReturn; + } + } + + if (iActionId == ACTION_MOVE_DOWN || iActionId == ACTION_MOVE_UP || + iActionId == ACTION_PAGE_DOWN || iActionId == ACTION_PAGE_UP || + iActionId == ACTION_FIRST_PAGE || iActionId == ACTION_LAST_PAGE) + { + CGUIDialog::OnAction(action); + int iSelected = m_viewControl.GetSelectedItem(); + + bReturn = true; + if (!m_bMovingMode) + { + if (iSelected != m_iSelected) + { + m_iSelected = iSelected; + SetData(m_iSelected); + } + } + else + { + bool bMoveUp = iActionId == ACTION_PAGE_UP || iActionId == ACTION_MOVE_UP || iActionId == ACTION_FIRST_PAGE; + unsigned int iLines = bMoveUp ? abs(m_iSelected - iSelected) : 1; + bool bOutOfBounds = bMoveUp ? m_iSelected <= 0 : m_iSelected >= m_channelItems->Size() - 1; + if (bOutOfBounds) + { + bMoveUp = !bMoveUp; + iLines = m_channelItems->Size() - 1; + } + for (unsigned int iLine = 0; iLine < iLines; ++iLine) + { + unsigned int iNewSelect = bMoveUp ? m_iSelected - 1 : m_iSelected + 1; + + const CFileItemPtr newItem = m_channelItems->Get(iNewSelect); + const std::string number = newItem->GetProperty(PROPERTY_CHANNEL_NUMBER).asString(); + if (number != LABEL_CHANNEL_DISABLED) + { + // Swap channel numbers + const CFileItemPtr item = m_channelItems->Get(m_iSelected); + newItem->SetProperty(PROPERTY_CHANNEL_NUMBER, + item->GetProperty(PROPERTY_CHANNEL_NUMBER)); + SetItemChanged(newItem); + item->SetProperty(PROPERTY_CHANNEL_NUMBER, number); + SetItemChanged(item); + } + + // swap items + m_channelItems->Swap(iNewSelect, m_iSelected); + m_iSelected = iNewSelect; + } + + m_viewControl.SetItems(*m_channelItems); + m_viewControl.SetSelectedItem(m_iSelected); + } + } + } + + return bReturn; +} + +bool CGUIDialogPVRChannelManager::OnAction(const CAction& action) +{ + return OnActionMove(action) || + CGUIDialog::OnAction(action); +} + +void CGUIDialogPVRChannelManager::OnInitWindow() +{ + CGUIDialog::OnInitWindow(); + + m_iSelected = 0; + m_bMovingMode = false; + m_bAllowNewChannel = false; + + EnableChannelOptions(false); + CONTROL_DISABLE(BUTTON_APPLY); + + // prevent resorting channels if backend channel numbers or backend channel order shall be used + const std::shared_ptr<CSettings> settings = CServiceBroker::GetSettingsComponent()->GetSettings(); + m_bAllowRenumber = !settings->GetBool(CSettings::SETTING_PVRMANAGER_USEBACKENDCHANNELNUMBERS); + m_bAllowReorder = + m_bAllowRenumber && !settings->GetBool(CSettings::SETTING_PVRMANAGER_BACKENDCHANNELORDER); + + Update(); + + if (m_initialSelection) + { + // set initial selection + const std::shared_ptr<CPVRChannel> channel = m_initialSelection->GetPVRChannelInfoTag(); + for (int i = 0; i < m_channelItems->Size(); ++i) + { + if (m_channelItems->Get(i)->GetPVRChannelInfoTag() == channel) + { + m_iSelected = i; + m_viewControl.SetSelectedItem(m_iSelected); + break; + } + } + m_initialSelection.reset(); + } + SetData(m_iSelected); +} + +void CGUIDialogPVRChannelManager::OnDeinitWindow(int nextWindowID) +{ + Clear(); + + CGUIDialog::OnDeinitWindow(nextWindowID); +} + +void CGUIDialogPVRChannelManager::SetRadio(bool bIsRadio) +{ + m_bIsRadio = bIsRadio; + SetProperty("IsRadio", m_bIsRadio ? "true" : ""); +} + +void CGUIDialogPVRChannelManager::Open(const std::shared_ptr<CFileItem>& initialSelection) +{ + m_initialSelection = initialSelection; + CGUIDialog::Open(); +} + +bool CGUIDialogPVRChannelManager::OnClickListChannels(const CGUIMessage& message) +{ + if (!m_bMovingMode) + { + int iAction = message.GetParam1(); + int iItem = m_viewControl.GetSelectedItem(); + + /* Check file item is in list range and get his pointer */ + if (iItem < 0 || iItem >= m_channelItems->Size()) return true; + + /* Process actions */ + if (iAction == ACTION_SELECT_ITEM || iAction == ACTION_CONTEXT_MENU || iAction == ACTION_MOUSE_RIGHT_CLICK) + { + /* Show Contextmenu */ + OnPopupMenu(iItem); + + return true; + } + } + else + { + CFileItemPtr pItem = m_channelItems->Get(m_iSelected); + if (pItem) + { + pItem->Select(false); + m_bMovingMode = false; + SetItemChanged(pItem); + return true; + } + } + + return false; +} + +bool CGUIDialogPVRChannelManager::OnClickButtonOK() +{ + SaveList(); + Close(); + return true; +} + +bool CGUIDialogPVRChannelManager::OnClickButtonApply() +{ + SaveList(); + return true; +} + +bool CGUIDialogPVRChannelManager::OnClickButtonCancel() +{ + Close(); + return true; +} + +bool CGUIDialogPVRChannelManager::OnClickButtonRadioTV() +{ + PromptAndSaveList(); + + m_iSelected = 0; + m_bMovingMode = false; + m_bAllowNewChannel = false; + m_bIsRadio = !m_bIsRadio; + SetProperty("IsRadio", m_bIsRadio ? "true" : ""); + Update(); + return true; +} + +bool CGUIDialogPVRChannelManager::OnClickButtonRadioActive() +{ + CGUIMessage msg(GUI_MSG_IS_SELECTED, GetID(), RADIOBUTTON_ACTIVE); + if (OnMessage(msg)) + { + CFileItemPtr pItem = m_channelItems->Get(m_iSelected); + if (pItem) + { + const bool selected = (msg.GetParam1() == 1); + if (pItem->GetProperty(PROPERTY_CHANNEL_ENABLED).asBoolean() != selected) + { + pItem->SetProperty(PROPERTY_CHANNEL_ENABLED, selected); + pItem->SetProperty(PROPERTY_CHANNEL_USER_SET_HIDDEN, true); + SetItemChanged(pItem); + Renumber(); + } + return true; + } + } + + return false; +} + +bool CGUIDialogPVRChannelManager::OnClickButtonRadioParentalLocked() +{ + CGUIMessage msg(GUI_MSG_IS_SELECTED, GetID(), RADIOBUTTON_PARENTAL_LOCK); + if (!OnMessage(msg)) + return false; + + bool selected(msg.GetParam1() == 1); + + // ask for PIN first + if (CServiceBroker::GetPVRManager().Get<PVR::GUI::Parental>().CheckParentalPIN() != + ParentalCheckResult::SUCCESS) + { // failed - reset to previous + SET_CONTROL_SELECTED(GetID(), RADIOBUTTON_PARENTAL_LOCK, !selected); + return false; + } + + CFileItemPtr pItem = m_channelItems->Get(m_iSelected); + if (pItem) + { + if (pItem->GetProperty(PROPERTY_CHANNEL_LOCKED).asBoolean() != selected) + { + pItem->SetProperty(PROPERTY_CHANNEL_LOCKED, selected); + SetItemChanged(pItem); + Renumber(); + } + return true; + } + + return false; +} + +bool CGUIDialogPVRChannelManager::OnClickButtonEditName() +{ + CGUIMessage msg(GUI_MSG_ITEM_SELECTED, GetID(), EDIT_NAME); + if (OnMessage(msg)) + { + CFileItemPtr pItem = m_channelItems->Get(m_iSelected); + if (pItem) + { + if (pItem->GetProperty(PROPERTY_CHANNEL_NAME).asString() != msg.GetLabel()) + { + pItem->SetProperty(PROPERTY_CHANNEL_NAME, msg.GetLabel()); + SetItemChanged(pItem); + } + return true; + } + } + + return false; +} + +bool CGUIDialogPVRChannelManager::OnClickButtonChannelLogo() +{ + CFileItemPtr pItem = m_channelItems->Get(m_iSelected); + if (!pItem) + return false; + + const std::shared_ptr<CProfileManager> profileManager = CServiceBroker::GetSettingsComponent()->GetProfileManager(); + + if (profileManager->GetCurrentProfile().canWriteSources() && !g_passwordManager.IsProfileLockUnlocked()) + return false; + + // setup our thumb list + CFileItemList items; + + // add the current thumb, if available + if (!pItem->GetProperty(PROPERTY_CHANNEL_ICON).asString().empty()) + { + CFileItemPtr current(new CFileItem("thumb://Current", false)); + current->SetArt("thumb", pItem->GetPVRChannelInfoTag()->IconPath()); + current->SetLabel(g_localizeStrings.Get(19282)); + items.Add(current); + } + else if (pItem->HasArt("thumb")) + { // already have a thumb that the share doesn't know about - must be a local one, so we mayaswell reuse it. + CFileItemPtr current(new CFileItem("thumb://Current", false)); + current->SetArt("thumb", pItem->GetArt("thumb")); + current->SetLabel(g_localizeStrings.Get(19282)); + items.Add(current); + } + + // and add a "no thumb" entry as well + CFileItemPtr nothumb(new CFileItem("thumb://None", false)); + nothumb->SetArt("icon", pItem->GetArt("icon")); + nothumb->SetLabel(g_localizeStrings.Get(19283)); + items.Add(nothumb); + + std::string strThumb; + VECSOURCES shares; + const std::shared_ptr<CSettings> settings = CServiceBroker::GetSettingsComponent()->GetSettings(); + if (settings->GetString(CSettings::SETTING_PVRMENU_ICONPATH) != "") + { + CMediaSource share1; + share1.strPath = settings->GetString(CSettings::SETTING_PVRMENU_ICONPATH); + share1.strName = g_localizeStrings.Get(19066); + shares.push_back(share1); + } + CServiceBroker::GetMediaManager().GetLocalDrives(shares); + if (!CGUIDialogFileBrowser::ShowAndGetImage(items, shares, g_localizeStrings.Get(19285), strThumb, NULL, 19285)) + return false; + + if (strThumb == "thumb://Current") + return true; + + if (strThumb == "thumb://None") + strThumb = ""; + + if (pItem->GetProperty(PROPERTY_CHANNEL_ICON).asString() != strThumb) + { + pItem->SetProperty(PROPERTY_CHANNEL_ICON, strThumb); + pItem->SetProperty(PROPERTY_CHANNEL_CUSTOM_ICON, true); + SetItemChanged(pItem); + } + + return true; +} + +bool CGUIDialogPVRChannelManager::OnClickButtonUseEPG() +{ + CGUIMessage msg(GUI_MSG_IS_SELECTED, GetID(), RADIOBUTTON_USEEPG); + if (OnMessage(msg)) + { + CFileItemPtr pItem = m_channelItems->Get(m_iSelected); + if (pItem) + { + const bool selected = (msg.GetParam1() == 1); + if (pItem->GetProperty(PROPERTY_CHANNEL_EPG_ENABLED).asBoolean() != selected) + { + pItem->SetProperty(PROPERTY_CHANNEL_EPG_ENABLED, selected); + SetItemChanged(pItem); + } + return true; + } + } + + return false; +} + +bool CGUIDialogPVRChannelManager::OnClickEPGSourceSpin() +{ + //! @todo Add EPG scraper support + return true; + // CGUISpinControlEx* pSpin = static_cast<CGUISpinControlEx*>(GetControl(SPIN_EPGSOURCE_SELECTION)); + // if (pSpin) + // { + // CFileItemPtr pItem = m_channelItems->Get(m_iSelected); + // if (pItem) + // { + // if (pItem->GetProperty(PROPERTY_CHANNEL_EPG_SOURCE).asInteger() != 0) + // { + // pItem->SetProperty(PROPERTY_CHANNEL_EPG_SOURCE, static_cast<int>(0)); + // SetItemChanged(pItem); + // } + // return true; + // } + // } +} + +bool CGUIDialogPVRChannelManager::OnClickButtonGroupManager() +{ + PromptAndSaveList(); + + /* Load group manager dialog */ + CGUIDialogPVRGroupManager* pDlgInfo = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogPVRGroupManager>(WINDOW_DIALOG_PVR_GROUP_MANAGER); + if (!pDlgInfo) + return false; + + pDlgInfo->SetRadio(m_bIsRadio); + + /* Open dialog window */ + pDlgInfo->Open(); + + Update(); + return true; +} + +bool CGUIDialogPVRChannelManager::OnClickButtonNewChannel() +{ + PromptAndSaveList(); + + int iSelection = 0; + if (m_clientsWithSettingsList.size() > 1) + { + CGUIDialogSelect* pDlgSelect = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogSelect>(WINDOW_DIALOG_SELECT); + if (!pDlgSelect) + return false; + + pDlgSelect->SetHeading(CVariant{19213}); // Select Client + + for (const auto& client : m_clientsWithSettingsList) + pDlgSelect->Add(client->Name()); + pDlgSelect->Open(); + + iSelection = pDlgSelect->GetSelectedItem(); + } + + if (iSelection >= 0 && iSelection < static_cast<int>(m_clientsWithSettingsList.size())) + { + int iClientID = m_clientsWithSettingsList[iSelection]->GetID(); + + std::shared_ptr<CPVRChannel> channel(new CPVRChannel(m_bIsRadio)); + channel->SetChannelName(g_localizeStrings.Get(19204)); // New channel + channel->SetClientID(iClientID); + + PVR_ERROR ret = PVR_ERROR_UNKNOWN; + const std::shared_ptr<CPVRClient> client = CServiceBroker::GetPVRManager().GetClient(iClientID); + if (client) + { + channel->SetEPGEnabled(client->GetClientCapabilities().SupportsEPG()); + ret = client->OpenDialogChannelAdd(channel); + } + + if (ret == PVR_ERROR_NO_ERROR) + { + CFileItemList prevChannelItems; + prevChannelItems.Assign(*m_channelItems); + + Update(); + + for (int index = 0; index < m_channelItems->Size(); ++index) + { + if (!prevChannelItems.Contains(m_channelItems->Get(index)->GetPath())) + { + m_iSelected = index; + m_viewControl.SetSelectedItem(m_iSelected); + SetData(m_iSelected); + break; + } + } + } + else if (ret == PVR_ERROR_NOT_IMPLEMENTED) + HELPERS::ShowOKDialogText(CVariant{19033}, CVariant{19038}); // "Information", "Not supported by the PVR backend." + else + HELPERS::ShowOKDialogText(CVariant{2103}, CVariant{16029}); // "Add-on error", "Check the log for more information about this message." + } + return true; +} + +bool CGUIDialogPVRChannelManager::OnClickButtonRefreshChannelLogos() +{ + for (const auto& item : *m_channelItems) + { + const std::string thumb = item->GetArt("thumb"); + if (!thumb.empty()) + { + // clear current cached image + CServiceBroker::GetTextureCache()->ClearCachedImage(thumb); + item->SetArt("thumb", ""); + } + } + + m_iSelected = 0; + Update(); + + CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_REFRESH_THUMBS); + CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg); + + return true; +} + +bool CGUIDialogPVRChannelManager::OnMessageClick(const CGUIMessage& message) +{ + int iControl = message.GetSenderId(); + switch(iControl) + { + case CONTROL_LIST_CHANNELS: + return OnClickListChannels(message); + case BUTTON_OK: + return OnClickButtonOK(); + case BUTTON_APPLY: + return OnClickButtonApply(); + case BUTTON_CANCEL: + return OnClickButtonCancel(); + case BUTTON_RADIO_TV: + return OnClickButtonRadioTV(); + case RADIOBUTTON_ACTIVE: + return OnClickButtonRadioActive(); + case RADIOBUTTON_PARENTAL_LOCK: + return OnClickButtonRadioParentalLocked(); + case EDIT_NAME: + return OnClickButtonEditName(); + case BUTTON_CHANNEL_LOGO: + return OnClickButtonChannelLogo(); + case RADIOBUTTON_USEEPG: + return OnClickButtonUseEPG(); + case SPIN_EPGSOURCE_SELECTION: + return OnClickEPGSourceSpin(); + case BUTTON_GROUP_MANAGER: + return OnClickButtonGroupManager(); + case BUTTON_NEW_CHANNEL: + return OnClickButtonNewChannel(); + case BUTTON_REFRESH_LOGOS: + return OnClickButtonRefreshChannelLogos(); + default: + return false; + } +} + +bool CGUIDialogPVRChannelManager::OnMessage(CGUIMessage& message) +{ + unsigned int iMessage = message.GetMessage(); + + switch (iMessage) + { + case GUI_MSG_CLICKED: + return OnMessageClick(message); + } + + return CGUIDialog::OnMessage(message); +} + +void CGUIDialogPVRChannelManager::OnWindowLoaded() +{ + CGUIDialog::OnWindowLoaded(); + + m_viewControl.Reset(); + m_viewControl.SetParentWindow(GetID()); + m_viewControl.AddView(GetControl(CONTROL_LIST_CHANNELS)); +} + +void CGUIDialogPVRChannelManager::OnWindowUnload() +{ + CGUIDialog::OnWindowUnload(); + m_viewControl.Reset(); +} + +CFileItemPtr CGUIDialogPVRChannelManager::GetCurrentListItem(int offset) +{ + return m_channelItems->Get(m_iSelected); +} + +bool CGUIDialogPVRChannelManager::OnPopupMenu(int iItem) +{ + // popup the context menu + // grab our context menu + CContextButtons buttons; + + // mark the item + if (iItem >= 0 && iItem < m_channelItems->Size()) + m_channelItems->Get(iItem)->Select(true); + else + return false; + + CFileItemPtr pItem = m_channelItems->Get(iItem); + if (!pItem) + return false; + + if (m_bAllowReorder && + pItem->GetProperty(PROPERTY_CHANNEL_NUMBER).asString() != LABEL_CHANNEL_DISABLED) + buttons.Add(CONTEXT_BUTTON_MOVE, 116); /* Move channel up or down */ + + if (pItem->GetProperty(PROPERTY_CLIENT_SUPPORTS_SETTINGS).asBoolean()) + { + buttons.Add(CONTEXT_BUTTON_SETTINGS, 10004); /* Open add-on channel settings dialog */ + buttons.Add(CONTEXT_BUTTON_DELETE, 117); /* Delete add-on channel */ + } + + int choice = CGUIDialogContextMenu::ShowAndGetChoice(buttons); + + // deselect our item + if (iItem >= 0 && iItem < m_channelItems->Size()) + m_channelItems->Get(iItem)->Select(false); + + if (choice < 0) + return false; + + return OnContextButton(iItem, (CONTEXT_BUTTON)choice); +} + +bool CGUIDialogPVRChannelManager::OnContextButton(int itemNumber, CONTEXT_BUTTON button) +{ + /* Check file item is in list range and get his pointer */ + if (itemNumber < 0 || itemNumber >= m_channelItems->Size()) return false; + + CFileItemPtr pItem = m_channelItems->Get(itemNumber); + if (!pItem) + return false; + + if (button == CONTEXT_BUTTON_MOVE) + { + m_bMovingMode = true; + pItem->Select(true); + } + else if (button == CONTEXT_BUTTON_SETTINGS) + { + PromptAndSaveList(); + + const std::shared_ptr<CPVRClient> client = CServiceBroker::GetPVRManager().GetClient(*pItem); + PVR_ERROR ret = PVR_ERROR_UNKNOWN; + if (client) + ret = client->OpenDialogChannelSettings(pItem->GetPVRChannelInfoTag()); + + if (ret == PVR_ERROR_NO_ERROR) + { + Update(); + SetData(m_iSelected); + } + else if (ret == PVR_ERROR_NOT_IMPLEMENTED) + HELPERS::ShowOKDialogText(CVariant{19033}, CVariant{19038}); // "Information", "Not supported by the PVR backend." + else + HELPERS::ShowOKDialogText(CVariant{2103}, CVariant{16029}); // "Add-on error", "Check the log for more information about this message." + } + else if (button == CONTEXT_BUTTON_DELETE) + { + CGUIDialogYesNo* pDialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogYesNo>(WINDOW_DIALOG_YES_NO); + if (!pDialog) + return true; + + pDialog->SetHeading(CVariant{19211}); // Delete channel + pDialog->SetText(CVariant{750}); // Are you sure? + pDialog->Open(); + + if (pDialog->IsConfirmed()) + { + const std::shared_ptr<CPVRClient> client = CServiceBroker::GetPVRManager().GetClient(*pItem); + if (client) + { + const std::shared_ptr<CPVRChannel> channel = pItem->GetPVRChannelInfoTag(); + PVR_ERROR ret = client->DeleteChannel(channel); + if (ret == PVR_ERROR_NO_ERROR) + { + CPVRChannelGroups* groups = + CServiceBroker::GetPVRManager().ChannelGroups()->Get(m_bIsRadio); + if (groups) + { + groups->UpdateFromClients({}); + Update(); + } + } + else if (ret == PVR_ERROR_NOT_IMPLEMENTED) + HELPERS::ShowOKDialogText(CVariant{19033}, CVariant{19038}); // "Information", "Not supported by the PVR backend." + else + HELPERS::ShowOKDialogText(CVariant{2103}, CVariant{16029}); // "Add-on error", "Check the log for more information about this message." + } + } + } + return true; +} + +void CGUIDialogPVRChannelManager::SetData(int iItem) +{ + if (iItem < 0 || iItem >= m_channelItems->Size()) + { + ClearChannelOptions(); + EnableChannelOptions(false); + return; + } + + CFileItemPtr pItem = m_channelItems->Get(iItem); + if (!pItem) + return; + + SET_CONTROL_LABEL2(EDIT_NAME, pItem->GetProperty(PROPERTY_CHANNEL_NAME).asString()); + CGUIMessage msg(GUI_MSG_SET_TYPE, GetID(), EDIT_NAME, CGUIEditControl::INPUT_TYPE_TEXT, 19208); + OnMessage(msg); + + SET_CONTROL_SELECTED(GetID(), RADIOBUTTON_ACTIVE, + pItem->GetProperty(PROPERTY_CHANNEL_ENABLED).asBoolean()); + SET_CONTROL_SELECTED(GetID(), RADIOBUTTON_USEEPG, + pItem->GetProperty(PROPERTY_CHANNEL_EPG_ENABLED).asBoolean()); + SET_CONTROL_SELECTED(GetID(), RADIOBUTTON_PARENTAL_LOCK, + pItem->GetProperty(PROPERTY_CHANNEL_LOCKED).asBoolean()); + + EnableChannelOptions(true); +} + +void CGUIDialogPVRChannelManager::Update() +{ + m_viewControl.SetCurrentView(CONTROL_LIST_CHANNELS); + + // empty the lists ready for population + Clear(); + + std::shared_ptr<CPVRChannelGroup> channels = CServiceBroker::GetPVRManager().ChannelGroups()->GetGroupAll(m_bIsRadio); + + // No channels available, nothing to do. + if (!channels) + return; + + channels->UpdateFromClients({}); + + const std::vector<std::shared_ptr<CPVRChannelGroupMember>> groupMembers = channels->GetMembers(); + std::shared_ptr<CFileItem> channelFile; + for (const auto& member : groupMembers) + { + channelFile = std::make_shared<CFileItem>(member); + if (!channelFile) + continue; + const std::shared_ptr<CPVRChannel> channel(channelFile->GetPVRChannelInfoTag()); + + channelFile->SetProperty(PROPERTY_CHANNEL_ENABLED, !channel->IsHidden()); + channelFile->SetProperty(PROPERTY_CHANNEL_USER_SET_HIDDEN, channel->IsUserSetHidden()); + channelFile->SetProperty(PROPERTY_CHANNEL_NAME, channel->ChannelName()); + channelFile->SetProperty(PROPERTY_CHANNEL_EPG_ENABLED, channel->EPGEnabled()); + channelFile->SetProperty(PROPERTY_CHANNEL_ICON, channel->ClientIconPath()); + channelFile->SetProperty(PROPERTY_CHANNEL_CUSTOM_ICON, channel->IsUserSetIcon()); + channelFile->SetProperty(PROPERTY_CHANNEL_EPG_SOURCE, 0); + channelFile->SetProperty(PROPERTY_CHANNEL_LOCKED, channel->IsLocked()); + channelFile->SetProperty(PROPERTY_CHANNEL_NUMBER, + member->ChannelNumber().FormattedChannelNumber()); + + const std::shared_ptr<CPVRClient> client = CServiceBroker::GetPVRManager().GetClient(*channelFile); + if (client) + { + channelFile->SetProperty(PROPERTY_CLIENT_NAME, client->GetFriendlyName()); + channelFile->SetProperty(PROPERTY_CLIENT_SUPPORTS_SETTINGS, + client->GetClientCapabilities().SupportsChannelSettings()); + } + + m_channelItems->Add(channelFile); + } + + { + std::vector< std::pair<std::string, int> > labels; + labels.emplace_back(g_localizeStrings.Get(19210), 0); + //! @todo Add Labels for EPG scrapers here + SET_CONTROL_LABELS(SPIN_EPGSOURCE_SELECTION, 0, &labels); + } + + m_clientsWithSettingsList = CServiceBroker::GetPVRManager().Clients()->GetClientsSupportingChannelSettings(m_bIsRadio); + if (!m_clientsWithSettingsList.empty()) + m_bAllowNewChannel = true; + + if (m_bAllowNewChannel) + CONTROL_ENABLE(BUTTON_NEW_CHANNEL); + else + CONTROL_DISABLE(BUTTON_NEW_CHANNEL); + + Renumber(); + m_viewControl.SetItems(*m_channelItems); + if (m_iSelected >= m_channelItems->Size()) + m_iSelected = m_channelItems->Size() - 1; + m_viewControl.SetSelectedItem(m_iSelected); + SetData(m_iSelected); +} + +void CGUIDialogPVRChannelManager::Clear() +{ + m_viewControl.Clear(); + m_channelItems->Clear(); + + ClearChannelOptions(); + EnableChannelOptions(false); + + CONTROL_DISABLE(BUTTON_APPLY); +} + +void CGUIDialogPVRChannelManager::ClearChannelOptions() +{ + CONTROL_DESELECT(RADIOBUTTON_ACTIVE); + SET_CONTROL_LABEL2(EDIT_NAME, ""); + SET_CONTROL_FILENAME(BUTTON_CHANNEL_LOGO, ""); + CONTROL_DESELECT(RADIOBUTTON_USEEPG); + + std::vector<std::pair<std::string, int>> labels = {{g_localizeStrings.Get(19210), 0}}; + SET_CONTROL_LABELS(SPIN_EPGSOURCE_SELECTION, 0, &labels); + + CONTROL_DESELECT(RADIOBUTTON_PARENTAL_LOCK); +} + +void CGUIDialogPVRChannelManager::EnableChannelOptions(bool bEnable) +{ + if (bEnable) + { + CONTROL_ENABLE(RADIOBUTTON_ACTIVE); + CONTROL_ENABLE(EDIT_NAME); + CONTROL_ENABLE(BUTTON_CHANNEL_LOGO); + CONTROL_ENABLE(IMAGE_CHANNEL_LOGO); + CONTROL_ENABLE(RADIOBUTTON_USEEPG); + CONTROL_ENABLE(SPIN_EPGSOURCE_SELECTION); + CONTROL_ENABLE(RADIOBUTTON_PARENTAL_LOCK); + } + else + { + CONTROL_DISABLE(RADIOBUTTON_ACTIVE); + CONTROL_DISABLE(EDIT_NAME); + CONTROL_DISABLE(BUTTON_CHANNEL_LOGO); + CONTROL_DISABLE(IMAGE_CHANNEL_LOGO); + CONTROL_DISABLE(RADIOBUTTON_USEEPG); + CONTROL_DISABLE(SPIN_EPGSOURCE_SELECTION); + CONTROL_DISABLE(RADIOBUTTON_PARENTAL_LOCK); + } +} + +void CGUIDialogPVRChannelManager::RenameChannel(const CFileItemPtr& pItem) +{ + std::string strChannelName = pItem->GetProperty(PROPERTY_CHANNEL_NAME).asString(); + if (strChannelName != pItem->GetPVRChannelInfoTag()->ChannelName()) + { + std::shared_ptr<CPVRChannel> channel = pItem->GetPVRChannelInfoTag(); + channel->SetChannelName(strChannelName); + + const std::shared_ptr<CPVRClient> client = CServiceBroker::GetPVRManager().GetClient(*pItem); + if (!client || (client->RenameChannel(channel) != PVR_ERROR_NO_ERROR)) + HELPERS::ShowOKDialogText(CVariant{2103}, CVariant{16029}); // Add-on error;Check the log file for details. + } +} + +bool CGUIDialogPVRChannelManager::PersistChannel(const CFileItemPtr& pItem, + const std::shared_ptr<CPVRChannelGroup>& group) +{ + if (!pItem || !group) + return false; + + return group->UpdateChannel( + pItem->GetPVRChannelInfoTag()->StorageId(), + pItem->GetProperty(PROPERTY_CHANNEL_NAME).asString(), + pItem->GetProperty(PROPERTY_CHANNEL_ICON).asString(), + static_cast<int>(pItem->GetProperty(PROPERTY_CHANNEL_EPG_SOURCE).asInteger()), + m_bAllowRenumber ? pItem->GetProperty(PROPERTY_CHANNEL_NUMBER).asInteger() : 0, + !pItem->GetProperty(PROPERTY_CHANNEL_ENABLED).asBoolean(), // hidden + pItem->GetProperty(PROPERTY_CHANNEL_EPG_ENABLED).asBoolean(), + pItem->GetProperty(PROPERTY_CHANNEL_LOCKED).asBoolean(), + pItem->GetProperty(PROPERTY_CHANNEL_CUSTOM_ICON).asBoolean(), + pItem->GetProperty(PROPERTY_CHANNEL_USER_SET_HIDDEN).asBoolean()); +} + +void CGUIDialogPVRChannelManager::PromptAndSaveList() +{ + if (!HasChangedItems()) + return; + + CGUIDialogYesNo* pDialogYesNo = + CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogYesNo>(WINDOW_DIALOG_YES_NO); + if (pDialogYesNo) + { + pDialogYesNo->SetHeading(CVariant{20052}); + pDialogYesNo->SetLine(0, CVariant{""}); + pDialogYesNo->SetLine(1, CVariant{19212}); + pDialogYesNo->SetLine(2, CVariant{20103}); + pDialogYesNo->Open(); + + if (pDialogYesNo->IsConfirmed()) + SaveList(); + else + Update(); + } +} + +void CGUIDialogPVRChannelManager::SaveList() +{ + if (!HasChangedItems()) + return; + + /* display the progress dialog */ + CGUIDialogProgress* pDlgProgress = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogProgress>(WINDOW_DIALOG_PROGRESS); + pDlgProgress->SetHeading(CVariant{190}); + pDlgProgress->SetLine(0, CVariant{""}); + pDlgProgress->SetLine(1, CVariant{328}); + pDlgProgress->SetLine(2, CVariant{""}); + pDlgProgress->Open(); + pDlgProgress->Progress(); + pDlgProgress->SetPercentage(0); + + /* persist all channels */ + std::shared_ptr<CPVRChannelGroup> group = CServiceBroker::GetPVRManager().ChannelGroups()->GetGroupAll(m_bIsRadio); + if (!group) + return; + + for (int iListPtr = 0; iListPtr < m_channelItems->Size(); ++iListPtr) + { + CFileItemPtr pItem = m_channelItems->Get(iListPtr); + if (pItem && pItem->GetProperty(PROPERTY_ITEM_CHANGED).asBoolean()) + { + if (pItem->GetProperty(PROPERTY_CLIENT_SUPPORTS_SETTINGS).asBoolean()) + RenameChannel(pItem); + + if (PersistChannel(pItem, group)) + pItem->SetProperty(PROPERTY_ITEM_CHANGED, false); + } + + pDlgProgress->SetPercentage(iListPtr * 100 / m_channelItems->Size()); + } + + group->SortAndRenumber(); + + auto channelGroups = CServiceBroker::GetPVRManager().ChannelGroups()->Get(m_bIsRadio); + channelGroups->UpdateChannelNumbersFromAllChannelsGroup(); + channelGroups->PersistAll(); + pDlgProgress->Close(); + + CONTROL_DISABLE(BUTTON_APPLY); +} + +bool CGUIDialogPVRChannelManager::HasChangedItems() const +{ + return std::any_of(m_channelItems->cbegin(), m_channelItems->cend(), [](const auto& item) { + return item && item->GetProperty(PROPERTY_ITEM_CHANGED).asBoolean(); + }); +} + +namespace +{ + +bool IsItemChanged(const std::shared_ptr<CFileItem>& item) +{ + const std::shared_ptr<CPVRChannelGroupMember> member = item->GetPVRChannelGroupMemberInfoTag(); + const std::shared_ptr<CPVRChannel> channel = member->Channel(); + + return item->GetProperty(PROPERTY_CHANNEL_ENABLED).asBoolean() == channel->IsHidden() || + item->GetProperty(PROPERTY_CHANNEL_USER_SET_HIDDEN).asBoolean() != + channel->IsUserSetHidden() || + item->GetProperty(PROPERTY_CHANNEL_NAME).asString() != channel->ChannelName() || + item->GetProperty(PROPERTY_CHANNEL_EPG_ENABLED).asBoolean() != channel->EPGEnabled() || + item->GetProperty(PROPERTY_CHANNEL_ICON).asString() != channel->ClientIconPath() || + item->GetProperty(PROPERTY_CHANNEL_CUSTOM_ICON).asBoolean() != channel->IsUserSetIcon() || + item->GetProperty(PROPERTY_CHANNEL_EPG_SOURCE).asInteger() != 0 || + item->GetProperty(PROPERTY_CHANNEL_LOCKED).asBoolean() != channel->IsLocked() || + item->GetProperty(PROPERTY_CHANNEL_NUMBER).asString() != + member->ChannelNumber().FormattedChannelNumber(); +} + +} // namespace + +void CGUIDialogPVRChannelManager::SetItemChanged(const CFileItemPtr& pItem) +{ + const bool changed = IsItemChanged(pItem); + pItem->SetProperty(PROPERTY_ITEM_CHANGED, changed); + + if (changed || HasChangedItems()) + CONTROL_ENABLE(BUTTON_APPLY); + else + CONTROL_DISABLE(BUTTON_APPLY); +} + +void CGUIDialogPVRChannelManager::Renumber() +{ + if (!m_bAllowRenumber) + return; + + int iNextChannelNumber = 0; + for (const auto& item : *m_channelItems) + { + const std::string number = item->GetProperty(PROPERTY_CHANNEL_ENABLED).asBoolean() + ? std::to_string(++iNextChannelNumber) + : LABEL_CHANNEL_DISABLED; + + if (item->GetProperty(PROPERTY_CHANNEL_NUMBER).asString() != number) + { + item->SetProperty(PROPERTY_CHANNEL_NUMBER, number); + SetItemChanged(item); + } + } +} |