summaryrefslogtreecommitdiffstats
path: root/xbmc/pvr/dialogs/GUIDialogPVRChannelManager.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 18:07:22 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 18:07:22 +0000
commitc04dcc2e7d834218ef2d4194331e383402495ae1 (patch)
tree7333e38d10d75386e60f336b80c2443c1166031d /xbmc/pvr/dialogs/GUIDialogPVRChannelManager.cpp
parentInitial commit. (diff)
downloadkodi-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.cpp1076
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);
+ }
+ }
+}