[Windows] Fix driver version detection of AMD RDNA+ GPU on Windows 10
[xbmc.git] / xbmc / pvr / dialogs / GUIDialogPVRChannelManager.cpp
blob8bc352d0ff51d07f183aa3cd2589e66010395f1d
1 /*
2 * Copyright (C) 2012-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "GUIDialogPVRChannelManager.h"
11 #include "FileItem.h"
12 #include "FileItemList.h"
13 #include "GUIPassword.h"
14 #include "ServiceBroker.h"
15 #include "TextureCache.h"
16 #include "dialogs/GUIDialogFileBrowser.h"
17 #include "dialogs/GUIDialogProgress.h"
18 #include "dialogs/GUIDialogSelect.h"
19 #include "dialogs/GUIDialogYesNo.h"
20 #include "guilib/GUIComponent.h"
21 #include "guilib/GUIEditControl.h"
22 #include "guilib/GUIMessage.h"
23 #include "guilib/GUISpinControlEx.h"
24 #include "guilib/GUIWindowManager.h"
25 #include "guilib/LocalizeStrings.h"
26 #include "input/actions/Action.h"
27 #include "input/actions/ActionIDs.h"
28 #include "messaging/helpers/DialogOKHelper.h"
29 #include "profiles/ProfileManager.h"
30 #include "pvr/PVRManager.h"
31 #include "pvr/addons/PVRClient.h"
32 #include "pvr/addons/PVRClients.h"
33 #include "pvr/channels/PVRChannel.h"
34 #include "pvr/channels/PVRChannelGroupMember.h"
35 #include "pvr/channels/PVRChannelGroups.h"
36 #include "pvr/channels/PVRChannelGroupsContainer.h"
37 #include "pvr/dialogs/GUIDialogPVRGroupManager.h"
38 #include "pvr/guilib/PVRGUIActionsParentalControl.h"
39 #include "settings/Settings.h"
40 #include "settings/SettingsComponent.h"
41 #include "storage/MediaManager.h"
42 #include "utils/StringUtils.h"
43 #include "utils/Variant.h"
45 #include <algorithm>
46 #include <memory>
47 #include <string>
48 #include <utility>
49 #include <vector>
51 #define BUTTON_OK 4
52 #define BUTTON_APPLY 5
53 #define BUTTON_CANCEL 6
54 #define RADIOBUTTON_ACTIVE 7
55 #define EDIT_NAME 8
56 #define BUTTON_CHANNEL_LOGO 9
57 #define IMAGE_CHANNEL_LOGO 10
58 #define RADIOBUTTON_USEEPG 12
59 #define SPIN_EPGSOURCE_SELECTION 13
60 #define RADIOBUTTON_PARENTAL_LOCK 14
61 #define CONTROL_LIST_CHANNELS 20
62 #define BUTTON_GROUP_MANAGER 30
63 #define BUTTON_NEW_CHANNEL 31
64 #define BUTTON_RADIO_TV 34
65 #define BUTTON_REFRESH_LOGOS 35
67 namespace
69 constexpr const char* LABEL_CHANNEL_DISABLED = "0";
71 // Note: strings must not be changed; they are part of the public skinning API for this dialog.
72 constexpr const char* PROPERTY_CHANNEL_NUMBER = "Number";
73 constexpr const char* PROPERTY_CHANNEL_ENABLED = "ActiveChannel";
74 constexpr const char* PROPERTY_CHANNEL_USER_SET_HIDDEN = "UserSetHidden";
75 constexpr const char* PROPERTY_CHANNEL_USER_SET_NAME = "UserSetName";
76 constexpr const char* PROPERTY_CHANNEL_LOCKED = "ParentalLocked";
77 constexpr const char* PROPERTY_CHANNEL_ICON = "Icon";
78 constexpr const char* PROPERTY_CHANNEL_CUSTOM_ICON = "UserSetIcon";
79 constexpr const char* PROPERTY_CHANNEL_NAME = "Name";
80 constexpr const char* PROPERTY_CHANNEL_EPG_ENABLED = "UseEPG";
81 constexpr const char* PROPERTY_CHANNEL_EPG_SOURCE = "EPGSource";
82 constexpr const char* PROPERTY_CLIENT_SUPPORTS_SETTINGS = "SupportsSettings";
83 constexpr const char* PROPERTY_CLIENT_NAME = "ClientName";
84 constexpr const char* PROPERTY_ITEM_CHANGED = "Changed";
86 } // namespace
88 using namespace PVR;
89 using namespace KODI::MESSAGING;
91 CGUIDialogPVRChannelManager::CGUIDialogPVRChannelManager() :
92 CGUIDialog(WINDOW_DIALOG_PVR_CHANNEL_MANAGER, "DialogPVRChannelManager.xml"),
93 m_channelItems(new CFileItemList)
95 SetRadio(false);
98 CGUIDialogPVRChannelManager::~CGUIDialogPVRChannelManager()
100 delete m_channelItems;
103 bool CGUIDialogPVRChannelManager::OnActionMove(const CAction& action)
105 bool bReturn(false);
106 int iActionId = action.GetID();
108 if (GetFocusedControlID() == CONTROL_LIST_CHANNELS)
110 if (iActionId == ACTION_MOUSE_MOVE)
112 int iSelected = m_viewControl.GetSelectedItem();
113 if (m_iSelected < iSelected)
115 iActionId = ACTION_MOVE_DOWN;
117 else if (m_iSelected > iSelected)
119 iActionId = ACTION_MOVE_UP;
121 else
123 return bReturn;
127 if (iActionId == ACTION_MOVE_DOWN || iActionId == ACTION_MOVE_UP ||
128 iActionId == ACTION_PAGE_DOWN || iActionId == ACTION_PAGE_UP ||
129 iActionId == ACTION_FIRST_PAGE || iActionId == ACTION_LAST_PAGE)
131 CGUIDialog::OnAction(action);
132 int iSelected = m_viewControl.GetSelectedItem();
134 bReturn = true;
135 if (!m_bMovingMode)
137 if (iSelected != m_iSelected)
139 m_iSelected = iSelected;
140 SetData(m_iSelected);
143 else
145 bool bMoveUp = iActionId == ACTION_PAGE_UP || iActionId == ACTION_MOVE_UP || iActionId == ACTION_FIRST_PAGE;
146 unsigned int iLines = bMoveUp ? abs(m_iSelected - iSelected) : 1;
147 bool bOutOfBounds = bMoveUp ? m_iSelected <= 0 : m_iSelected >= m_channelItems->Size() - 1;
148 if (bOutOfBounds)
150 bMoveUp = !bMoveUp;
151 iLines = m_channelItems->Size() - 1;
153 for (unsigned int iLine = 0; iLine < iLines; ++iLine)
155 unsigned int iNewSelect = bMoveUp ? m_iSelected - 1 : m_iSelected + 1;
157 const CFileItemPtr newItem = m_channelItems->Get(iNewSelect);
158 const std::string number = newItem->GetProperty(PROPERTY_CHANNEL_NUMBER).asString();
159 if (number != LABEL_CHANNEL_DISABLED)
161 // Swap channel numbers
162 const CFileItemPtr item = m_channelItems->Get(m_iSelected);
163 newItem->SetProperty(PROPERTY_CHANNEL_NUMBER,
164 item->GetProperty(PROPERTY_CHANNEL_NUMBER));
165 SetItemChanged(newItem);
166 item->SetProperty(PROPERTY_CHANNEL_NUMBER, number);
167 SetItemChanged(item);
170 // swap items
171 m_channelItems->Swap(iNewSelect, m_iSelected);
172 m_iSelected = iNewSelect;
175 m_viewControl.SetItems(*m_channelItems);
176 m_viewControl.SetSelectedItem(m_iSelected);
181 return bReturn;
184 bool CGUIDialogPVRChannelManager::OnAction(const CAction& action)
186 return OnActionMove(action) ||
187 CGUIDialog::OnAction(action);
190 void CGUIDialogPVRChannelManager::OnInitWindow()
192 CGUIDialog::OnInitWindow();
194 m_iSelected = 0;
195 m_bMovingMode = false;
196 m_bAllowNewChannel = false;
198 EnableChannelOptions(false);
199 CONTROL_DISABLE(BUTTON_APPLY);
201 // prevent resorting channels if backend channel numbers or backend channel order shall be used
202 const std::shared_ptr<CSettings> settings = CServiceBroker::GetSettingsComponent()->GetSettings();
203 m_bAllowRenumber = !settings->GetBool(CSettings::SETTING_PVRMANAGER_USEBACKENDCHANNELNUMBERS);
204 m_bAllowReorder =
205 m_bAllowRenumber && !settings->GetBool(CSettings::SETTING_PVRMANAGER_BACKENDCHANNELORDER);
207 Update();
209 if (m_initialSelection)
211 // set initial selection
212 const std::shared_ptr<const CPVRChannel> channel = m_initialSelection->GetPVRChannelInfoTag();
213 for (int i = 0; i < m_channelItems->Size(); ++i)
215 if (m_channelItems->Get(i)->GetPVRChannelInfoTag() == channel)
217 m_iSelected = i;
218 m_viewControl.SetSelectedItem(m_iSelected);
219 break;
222 m_initialSelection.reset();
224 SetData(m_iSelected);
227 void CGUIDialogPVRChannelManager::OnDeinitWindow(int nextWindowID)
229 Clear();
231 CGUIDialog::OnDeinitWindow(nextWindowID);
234 void CGUIDialogPVRChannelManager::SetRadio(bool bIsRadio)
236 m_bIsRadio = bIsRadio;
237 SetProperty("IsRadio", m_bIsRadio ? "true" : "");
240 void CGUIDialogPVRChannelManager::Open(const std::shared_ptr<CFileItem>& initialSelection)
242 m_initialSelection = initialSelection;
243 CGUIDialog::Open();
246 bool CGUIDialogPVRChannelManager::OnClickListChannels(const CGUIMessage& message)
248 if (!m_bMovingMode)
250 int iAction = message.GetParam1();
251 int iItem = m_viewControl.GetSelectedItem();
253 /* Check file item is in list range and get his pointer */
254 if (iItem < 0 || iItem >= m_channelItems->Size()) return true;
256 /* Process actions */
257 if (iAction == ACTION_SELECT_ITEM || iAction == ACTION_CONTEXT_MENU || iAction == ACTION_MOUSE_RIGHT_CLICK)
259 /* Show Contextmenu */
260 OnPopupMenu(iItem);
262 return true;
265 else
267 CFileItemPtr pItem = m_channelItems->Get(m_iSelected);
268 if (pItem)
270 pItem->Select(false);
271 m_bMovingMode = false;
272 SetItemChanged(pItem);
273 return true;
277 return false;
280 bool CGUIDialogPVRChannelManager::OnClickButtonOK()
282 SaveList();
283 Close();
284 return true;
287 bool CGUIDialogPVRChannelManager::OnClickButtonApply()
289 SaveList();
290 return true;
293 bool CGUIDialogPVRChannelManager::OnClickButtonCancel()
295 Close();
296 return true;
299 bool CGUIDialogPVRChannelManager::OnClickButtonRadioTV()
301 PromptAndSaveList();
303 m_iSelected = 0;
304 m_bMovingMode = false;
305 m_bAllowNewChannel = false;
306 m_bIsRadio = !m_bIsRadio;
307 SetProperty("IsRadio", m_bIsRadio ? "true" : "");
308 Update();
309 return true;
312 bool CGUIDialogPVRChannelManager::OnClickButtonRadioActive()
314 CGUIMessage msg(GUI_MSG_IS_SELECTED, GetID(), RADIOBUTTON_ACTIVE);
315 if (OnMessage(msg))
317 CFileItemPtr pItem = m_channelItems->Get(m_iSelected);
318 if (pItem)
320 const bool selected = (msg.GetParam1() == 1);
321 if (pItem->GetProperty(PROPERTY_CHANNEL_ENABLED).asBoolean() != selected)
323 pItem->SetProperty(PROPERTY_CHANNEL_ENABLED, selected);
324 pItem->SetProperty(PROPERTY_CHANNEL_USER_SET_HIDDEN, true);
325 SetItemChanged(pItem);
326 Renumber();
328 return true;
332 return false;
335 bool CGUIDialogPVRChannelManager::OnClickButtonRadioParentalLocked()
337 CGUIMessage msg(GUI_MSG_IS_SELECTED, GetID(), RADIOBUTTON_PARENTAL_LOCK);
338 if (!OnMessage(msg))
339 return false;
341 bool selected(msg.GetParam1() == 1);
343 // ask for PIN first
344 if (CServiceBroker::GetPVRManager().Get<PVR::GUI::Parental>().CheckParentalPIN() !=
345 ParentalCheckResult::SUCCESS)
346 { // failed - reset to previous
347 SET_CONTROL_SELECTED(GetID(), RADIOBUTTON_PARENTAL_LOCK, !selected);
348 return false;
351 CFileItemPtr pItem = m_channelItems->Get(m_iSelected);
352 if (pItem)
354 if (pItem->GetProperty(PROPERTY_CHANNEL_LOCKED).asBoolean() != selected)
356 pItem->SetProperty(PROPERTY_CHANNEL_LOCKED, selected);
357 SetItemChanged(pItem);
358 Renumber();
360 return true;
363 return false;
366 bool CGUIDialogPVRChannelManager::OnClickButtonEditName()
368 CGUIMessage msg(GUI_MSG_ITEM_SELECTED, GetID(), EDIT_NAME);
369 if (OnMessage(msg))
371 CFileItemPtr pItem = m_channelItems->Get(m_iSelected);
372 if (pItem)
374 const std::string& label = msg.GetLabel();
375 if (pItem->GetProperty(PROPERTY_CHANNEL_NAME).asString() != label)
377 pItem->SetProperty(PROPERTY_CHANNEL_NAME, label);
378 pItem->SetProperty(PROPERTY_CHANNEL_USER_SET_NAME, true);
379 SetItemChanged(pItem);
381 return true;
385 return false;
388 bool CGUIDialogPVRChannelManager::OnClickButtonChannelLogo()
390 CFileItemPtr pItem = m_channelItems->Get(m_iSelected);
391 if (!pItem)
392 return false;
394 const std::shared_ptr<CProfileManager> profileManager = CServiceBroker::GetSettingsComponent()->GetProfileManager();
396 if (profileManager->GetCurrentProfile().canWriteSources() && !g_passwordManager.IsProfileLockUnlocked())
397 return false;
399 // setup our thumb list
400 CFileItemList items;
402 // add the current thumb, if available
403 if (!pItem->GetProperty(PROPERTY_CHANNEL_ICON).asString().empty())
405 CFileItemPtr current(new CFileItem("thumb://Current", false));
406 current->SetArt("thumb", pItem->GetPVRChannelInfoTag()->IconPath());
407 current->SetLabel(g_localizeStrings.Get(19282));
408 items.Add(current);
410 else if (pItem->HasArt("thumb"))
411 { // already have a thumb that the share doesn't know about - must be a local one, so we mayaswell reuse it.
412 CFileItemPtr current(new CFileItem("thumb://Current", false));
413 current->SetArt("thumb", pItem->GetArt("thumb"));
414 current->SetLabel(g_localizeStrings.Get(19282));
415 items.Add(current);
418 // and add a "no thumb" entry as well
419 CFileItemPtr nothumb(new CFileItem("thumb://None", false));
420 nothumb->SetArt("icon", pItem->GetArt("icon"));
421 nothumb->SetLabel(g_localizeStrings.Get(19283));
422 items.Add(nothumb);
424 std::string strThumb;
425 VECSOURCES shares;
426 const std::shared_ptr<CSettings> settings = CServiceBroker::GetSettingsComponent()->GetSettings();
427 if (settings->GetString(CSettings::SETTING_PVRMENU_ICONPATH) != "")
429 CMediaSource share1;
430 share1.strPath = settings->GetString(CSettings::SETTING_PVRMENU_ICONPATH);
431 share1.strName = g_localizeStrings.Get(19066);
432 shares.push_back(share1);
434 CServiceBroker::GetMediaManager().GetLocalDrives(shares);
435 if (!CGUIDialogFileBrowser::ShowAndGetImage(items, shares, g_localizeStrings.Get(19285), strThumb, NULL, 19285))
436 return false;
438 if (strThumb == "thumb://Current")
439 return true;
441 if (strThumb == "thumb://None")
442 strThumb = "";
444 if (pItem->GetProperty(PROPERTY_CHANNEL_ICON).asString() != strThumb)
446 pItem->SetProperty(PROPERTY_CHANNEL_ICON, strThumb);
447 pItem->SetProperty(PROPERTY_CHANNEL_CUSTOM_ICON, true);
448 SetItemChanged(pItem);
451 return true;
454 bool CGUIDialogPVRChannelManager::OnClickButtonUseEPG()
456 CGUIMessage msg(GUI_MSG_IS_SELECTED, GetID(), RADIOBUTTON_USEEPG);
457 if (OnMessage(msg))
459 CFileItemPtr pItem = m_channelItems->Get(m_iSelected);
460 if (pItem)
462 const bool selected = (msg.GetParam1() == 1);
463 if (pItem->GetProperty(PROPERTY_CHANNEL_EPG_ENABLED).asBoolean() != selected)
465 pItem->SetProperty(PROPERTY_CHANNEL_EPG_ENABLED, selected);
466 SetItemChanged(pItem);
468 return true;
472 return false;
475 bool CGUIDialogPVRChannelManager::OnClickEPGSourceSpin()
477 //! @todo Add EPG scraper support
478 return true;
479 // CGUISpinControlEx* pSpin = static_cast<CGUISpinControlEx*>(GetControl(SPIN_EPGSOURCE_SELECTION));
480 // if (pSpin)
481 // {
482 // CFileItemPtr pItem = m_channelItems->Get(m_iSelected);
483 // if (pItem)
484 // {
485 // if (pItem->GetProperty(PROPERTY_CHANNEL_EPG_SOURCE).asInteger() != 0)
486 // {
487 // pItem->SetProperty(PROPERTY_CHANNEL_EPG_SOURCE, static_cast<int>(0));
488 // SetItemChanged(pItem);
489 // }
490 // return true;
491 // }
492 // }
495 bool CGUIDialogPVRChannelManager::OnClickButtonGroupManager()
497 PromptAndSaveList();
499 /* Load group manager dialog */
500 CGUIDialogPVRGroupManager* pDlgInfo = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogPVRGroupManager>(WINDOW_DIALOG_PVR_GROUP_MANAGER);
501 if (!pDlgInfo)
502 return false;
504 pDlgInfo->SetRadio(m_bIsRadio);
506 /* Open dialog window */
507 pDlgInfo->Open();
509 Update();
510 return true;
513 bool CGUIDialogPVRChannelManager::OnClickButtonNewChannel()
515 PromptAndSaveList();
517 int iSelection = 0;
518 if (m_clientsWithSettingsList.size() > 1)
520 CGUIDialogSelect* pDlgSelect = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogSelect>(WINDOW_DIALOG_SELECT);
521 if (!pDlgSelect)
522 return false;
524 pDlgSelect->SetHeading(CVariant{19213}); // Select Client
526 for (const auto& client : m_clientsWithSettingsList)
527 pDlgSelect->Add(client->Name());
528 pDlgSelect->Open();
530 iSelection = pDlgSelect->GetSelectedItem();
533 if (iSelection >= 0 && iSelection < static_cast<int>(m_clientsWithSettingsList.size()))
535 int iClientID = m_clientsWithSettingsList[iSelection]->GetID();
537 std::shared_ptr<CPVRChannel> channel(new CPVRChannel(m_bIsRadio));
538 channel->SetChannelName(g_localizeStrings.Get(19204)); // New channel
539 channel->SetClientID(iClientID);
541 PVR_ERROR ret = PVR_ERROR_UNKNOWN;
542 const std::shared_ptr<CPVRClient> client = CServiceBroker::GetPVRManager().GetClient(iClientID);
543 if (client)
545 channel->SetEPGEnabled(client->GetClientCapabilities().SupportsEPG());
546 ret = client->OpenDialogChannelAdd(channel);
549 if (ret == PVR_ERROR_NO_ERROR)
551 CFileItemList prevChannelItems;
552 prevChannelItems.Assign(*m_channelItems);
554 Update();
556 for (int index = 0; index < m_channelItems->Size(); ++index)
558 if (!prevChannelItems.Contains(m_channelItems->Get(index)->GetPath()))
560 m_iSelected = index;
561 m_viewControl.SetSelectedItem(m_iSelected);
562 SetData(m_iSelected);
563 break;
567 else if (ret == PVR_ERROR_NOT_IMPLEMENTED)
568 HELPERS::ShowOKDialogText(CVariant{19033}, CVariant{19038}); // "Information", "Not supported by the PVR backend."
569 else
570 HELPERS::ShowOKDialogText(CVariant{2103}, CVariant{16029}); // "Add-on error", "Check the log for more information about this message."
572 return true;
575 bool CGUIDialogPVRChannelManager::OnClickButtonRefreshChannelLogos()
577 for (const auto& item : *m_channelItems)
579 const std::string thumb = item->GetArt("thumb");
580 if (!thumb.empty())
582 // clear current cached image
583 CServiceBroker::GetTextureCache()->ClearCachedImage(thumb);
584 item->SetArt("thumb", "");
588 m_iSelected = 0;
589 Update();
591 CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_REFRESH_THUMBS);
592 CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg);
594 return true;
597 bool CGUIDialogPVRChannelManager::OnMessageClick(const CGUIMessage& message)
599 int iControl = message.GetSenderId();
600 switch(iControl)
602 case CONTROL_LIST_CHANNELS:
603 return OnClickListChannels(message);
604 case BUTTON_OK:
605 return OnClickButtonOK();
606 case BUTTON_APPLY:
607 return OnClickButtonApply();
608 case BUTTON_CANCEL:
609 return OnClickButtonCancel();
610 case BUTTON_RADIO_TV:
611 return OnClickButtonRadioTV();
612 case RADIOBUTTON_ACTIVE:
613 return OnClickButtonRadioActive();
614 case RADIOBUTTON_PARENTAL_LOCK:
615 return OnClickButtonRadioParentalLocked();
616 case EDIT_NAME:
617 return OnClickButtonEditName();
618 case BUTTON_CHANNEL_LOGO:
619 return OnClickButtonChannelLogo();
620 case RADIOBUTTON_USEEPG:
621 return OnClickButtonUseEPG();
622 case SPIN_EPGSOURCE_SELECTION:
623 return OnClickEPGSourceSpin();
624 case BUTTON_GROUP_MANAGER:
625 return OnClickButtonGroupManager();
626 case BUTTON_NEW_CHANNEL:
627 return OnClickButtonNewChannel();
628 case BUTTON_REFRESH_LOGOS:
629 return OnClickButtonRefreshChannelLogos();
630 default:
631 return false;
635 bool CGUIDialogPVRChannelManager::OnMessage(CGUIMessage& message)
637 unsigned int iMessage = message.GetMessage();
639 switch (iMessage)
641 case GUI_MSG_CLICKED:
642 return OnMessageClick(message);
645 return CGUIDialog::OnMessage(message);
648 void CGUIDialogPVRChannelManager::OnWindowLoaded()
650 CGUIDialog::OnWindowLoaded();
652 m_viewControl.Reset();
653 m_viewControl.SetParentWindow(GetID());
654 m_viewControl.AddView(GetControl(CONTROL_LIST_CHANNELS));
657 void CGUIDialogPVRChannelManager::OnWindowUnload()
659 CGUIDialog::OnWindowUnload();
660 m_viewControl.Reset();
663 CFileItemPtr CGUIDialogPVRChannelManager::GetCurrentListItem(int offset)
665 return m_channelItems->Get(m_iSelected);
668 bool CGUIDialogPVRChannelManager::OnPopupMenu(int iItem)
670 // popup the context menu
671 // grab our context menu
672 CContextButtons buttons;
674 // mark the item
675 if (iItem >= 0 && iItem < m_channelItems->Size())
676 m_channelItems->Get(iItem)->Select(true);
677 else
678 return false;
680 CFileItemPtr pItem = m_channelItems->Get(iItem);
681 if (!pItem)
682 return false;
684 if (m_bAllowReorder &&
685 pItem->GetProperty(PROPERTY_CHANNEL_NUMBER).asString() != LABEL_CHANNEL_DISABLED)
686 buttons.Add(CONTEXT_BUTTON_MOVE, 116); /* Move channel up or down */
688 if (pItem->GetProperty(PROPERTY_CLIENT_SUPPORTS_SETTINGS).asBoolean())
690 buttons.Add(CONTEXT_BUTTON_SETTINGS, 10004); /* Open add-on channel settings dialog */
691 buttons.Add(CONTEXT_BUTTON_DELETE, 117); /* Delete add-on channel */
694 int choice = CGUIDialogContextMenu::ShowAndGetChoice(buttons);
696 // deselect our item
697 if (iItem >= 0 && iItem < m_channelItems->Size())
698 m_channelItems->Get(iItem)->Select(false);
700 if (choice < 0)
701 return false;
703 return OnContextButton(iItem, (CONTEXT_BUTTON)choice);
706 bool CGUIDialogPVRChannelManager::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
708 /* Check file item is in list range and get his pointer */
709 if (itemNumber < 0 || itemNumber >= m_channelItems->Size()) return false;
711 CFileItemPtr pItem = m_channelItems->Get(itemNumber);
712 if (!pItem)
713 return false;
715 if (button == CONTEXT_BUTTON_MOVE)
717 m_bMovingMode = true;
718 pItem->Select(true);
720 else if (button == CONTEXT_BUTTON_SETTINGS)
722 PromptAndSaveList();
724 const std::shared_ptr<CPVRClient> client = CServiceBroker::GetPVRManager().GetClient(*pItem);
725 PVR_ERROR ret = PVR_ERROR_UNKNOWN;
726 if (client)
727 ret = client->OpenDialogChannelSettings(pItem->GetPVRChannelInfoTag());
729 if (ret == PVR_ERROR_NO_ERROR)
731 Update();
732 SetData(m_iSelected);
734 else if (ret == PVR_ERROR_NOT_IMPLEMENTED)
735 HELPERS::ShowOKDialogText(CVariant{19033}, CVariant{19038}); // "Information", "Not supported by the PVR backend."
736 else
737 HELPERS::ShowOKDialogText(CVariant{2103}, CVariant{16029}); // "Add-on error", "Check the log for more information about this message."
739 else if (button == CONTEXT_BUTTON_DELETE)
741 CGUIDialogYesNo* pDialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogYesNo>(WINDOW_DIALOG_YES_NO);
742 if (!pDialog)
743 return true;
745 pDialog->SetHeading(CVariant{19211}); // Delete channel
746 pDialog->SetText(CVariant{750}); // Are you sure?
747 pDialog->Open();
749 if (pDialog->IsConfirmed())
751 const std::shared_ptr<CPVRClient> client = CServiceBroker::GetPVRManager().GetClient(*pItem);
752 if (client)
754 const std::shared_ptr<const CPVRChannel> channel = pItem->GetPVRChannelInfoTag();
755 PVR_ERROR ret = client->DeleteChannel(channel);
756 if (ret == PVR_ERROR_NO_ERROR)
758 CPVRChannelGroups* groups =
759 CServiceBroker::GetPVRManager().ChannelGroups()->Get(m_bIsRadio);
760 if (groups)
762 groups->UpdateFromClients({});
763 Update();
766 else if (ret == PVR_ERROR_NOT_IMPLEMENTED)
767 HELPERS::ShowOKDialogText(CVariant{19033}, CVariant{19038}); // "Information", "Not supported by the PVR backend."
768 else
769 HELPERS::ShowOKDialogText(CVariant{2103}, CVariant{16029}); // "Add-on error", "Check the log for more information about this message."
773 return true;
776 void CGUIDialogPVRChannelManager::SetData(int iItem)
778 if (iItem < 0 || iItem >= m_channelItems->Size())
780 ClearChannelOptions();
781 EnableChannelOptions(false);
782 return;
785 CFileItemPtr pItem = m_channelItems->Get(iItem);
786 if (!pItem)
787 return;
789 SET_CONTROL_LABEL2(EDIT_NAME, pItem->GetProperty(PROPERTY_CHANNEL_NAME).asString());
790 CGUIMessage msg(GUI_MSG_SET_TYPE, GetID(), EDIT_NAME, CGUIEditControl::INPUT_TYPE_TEXT, 19208);
791 OnMessage(msg);
793 SET_CONTROL_SELECTED(GetID(), RADIOBUTTON_ACTIVE,
794 pItem->GetProperty(PROPERTY_CHANNEL_ENABLED).asBoolean());
795 SET_CONTROL_SELECTED(GetID(), RADIOBUTTON_USEEPG,
796 pItem->GetProperty(PROPERTY_CHANNEL_EPG_ENABLED).asBoolean());
797 SET_CONTROL_SELECTED(GetID(), RADIOBUTTON_PARENTAL_LOCK,
798 pItem->GetProperty(PROPERTY_CHANNEL_LOCKED).asBoolean());
800 EnableChannelOptions(true);
803 void CGUIDialogPVRChannelManager::Update()
805 m_viewControl.SetCurrentView(CONTROL_LIST_CHANNELS);
807 // empty the lists ready for population
808 Clear();
810 std::shared_ptr<CPVRChannelGroup> channels = CServiceBroker::GetPVRManager().ChannelGroups()->GetGroupAll(m_bIsRadio);
812 // No channels available, nothing to do.
813 if (!channels)
814 return;
816 channels->UpdateFromClients({});
818 const std::vector<std::shared_ptr<CPVRChannelGroupMember>> groupMembers = channels->GetMembers();
819 std::shared_ptr<CFileItem> channelFile;
820 for (const auto& member : groupMembers)
822 channelFile = std::make_shared<CFileItem>(member);
823 if (!channelFile)
824 continue;
825 const std::shared_ptr<const CPVRChannel> channel(channelFile->GetPVRChannelInfoTag());
827 channelFile->SetProperty(PROPERTY_CHANNEL_ENABLED, !channel->IsHidden());
828 channelFile->SetProperty(PROPERTY_CHANNEL_USER_SET_HIDDEN, channel->IsUserSetHidden());
829 channelFile->SetProperty(PROPERTY_CHANNEL_USER_SET_NAME, channel->IsUserSetName());
830 channelFile->SetProperty(PROPERTY_CHANNEL_NAME, channel->ChannelName());
831 channelFile->SetProperty(PROPERTY_CHANNEL_EPG_ENABLED, channel->EPGEnabled());
832 channelFile->SetProperty(PROPERTY_CHANNEL_ICON, channel->IconPath());
833 channelFile->SetProperty(PROPERTY_CHANNEL_CUSTOM_ICON, channel->IsUserSetIcon());
834 channelFile->SetProperty(PROPERTY_CHANNEL_EPG_SOURCE, 0);
835 channelFile->SetProperty(PROPERTY_CHANNEL_LOCKED, channel->IsLocked());
836 channelFile->SetProperty(PROPERTY_CHANNEL_NUMBER,
837 member->ChannelNumber().FormattedChannelNumber());
839 const std::shared_ptr<const CPVRClient> client =
840 CServiceBroker::GetPVRManager().GetClient(*channelFile);
841 if (client)
843 channelFile->SetProperty(PROPERTY_CLIENT_NAME, client->GetFullClientName());
844 channelFile->SetProperty(PROPERTY_CLIENT_SUPPORTS_SETTINGS,
845 client->GetClientCapabilities().SupportsChannelSettings());
848 m_channelItems->Add(channelFile);
852 std::vector< std::pair<std::string, int> > labels;
853 labels.emplace_back(g_localizeStrings.Get(19210), 0);
854 //! @todo Add Labels for EPG scrapers here
855 SET_CONTROL_LABELS(SPIN_EPGSOURCE_SELECTION, 0, &labels);
858 m_clientsWithSettingsList = CServiceBroker::GetPVRManager().Clients()->GetClientsSupportingChannelSettings(m_bIsRadio);
859 if (!m_clientsWithSettingsList.empty())
860 m_bAllowNewChannel = true;
862 if (m_bAllowNewChannel)
863 CONTROL_ENABLE(BUTTON_NEW_CHANNEL);
864 else
865 CONTROL_DISABLE(BUTTON_NEW_CHANNEL);
867 Renumber();
868 m_viewControl.SetItems(*m_channelItems);
869 if (m_iSelected >= m_channelItems->Size())
870 m_iSelected = m_channelItems->Size() - 1;
871 m_viewControl.SetSelectedItem(m_iSelected);
872 SetData(m_iSelected);
875 void CGUIDialogPVRChannelManager::Clear()
877 m_viewControl.Clear();
878 m_channelItems->Clear();
880 ClearChannelOptions();
881 EnableChannelOptions(false);
883 CONTROL_DISABLE(BUTTON_APPLY);
886 void CGUIDialogPVRChannelManager::ClearChannelOptions()
888 CONTROL_DESELECT(RADIOBUTTON_ACTIVE);
889 SET_CONTROL_LABEL2(EDIT_NAME, "");
890 SET_CONTROL_FILENAME(BUTTON_CHANNEL_LOGO, "");
891 CONTROL_DESELECT(RADIOBUTTON_USEEPG);
893 std::vector<std::pair<std::string, int>> labels = {{g_localizeStrings.Get(19210), 0}};
894 SET_CONTROL_LABELS(SPIN_EPGSOURCE_SELECTION, 0, &labels);
896 CONTROL_DESELECT(RADIOBUTTON_PARENTAL_LOCK);
899 void CGUIDialogPVRChannelManager::EnableChannelOptions(bool bEnable)
901 if (bEnable)
903 CONTROL_ENABLE(RADIOBUTTON_ACTIVE);
904 CONTROL_ENABLE(EDIT_NAME);
905 CONTROL_ENABLE(BUTTON_CHANNEL_LOGO);
906 CONTROL_ENABLE(IMAGE_CHANNEL_LOGO);
907 CONTROL_ENABLE(RADIOBUTTON_USEEPG);
908 CONTROL_ENABLE(SPIN_EPGSOURCE_SELECTION);
909 CONTROL_ENABLE(RADIOBUTTON_PARENTAL_LOCK);
911 else
913 CONTROL_DISABLE(RADIOBUTTON_ACTIVE);
914 CONTROL_DISABLE(EDIT_NAME);
915 CONTROL_DISABLE(BUTTON_CHANNEL_LOGO);
916 CONTROL_DISABLE(IMAGE_CHANNEL_LOGO);
917 CONTROL_DISABLE(RADIOBUTTON_USEEPG);
918 CONTROL_DISABLE(SPIN_EPGSOURCE_SELECTION);
919 CONTROL_DISABLE(RADIOBUTTON_PARENTAL_LOCK);
923 void CGUIDialogPVRChannelManager::RenameChannel(const CFileItemPtr& pItem)
925 std::string strChannelName = pItem->GetProperty(PROPERTY_CHANNEL_NAME).asString();
926 if (strChannelName != pItem->GetPVRChannelInfoTag()->ChannelName())
928 const std::shared_ptr<CPVRChannel> channel = pItem->GetPVRChannelInfoTag();
929 channel->SetChannelName(strChannelName);
931 const std::shared_ptr<CPVRClient> client = CServiceBroker::GetPVRManager().GetClient(*pItem);
932 if (!client || (client->RenameChannel(channel) != PVR_ERROR_NO_ERROR))
933 HELPERS::ShowOKDialogText(CVariant{2103}, CVariant{16029}); // Add-on error;Check the log file for details.
937 bool CGUIDialogPVRChannelManager::UpdateChannelData(const std::shared_ptr<CFileItem>& pItem,
938 const std::shared_ptr<CPVRChannelGroup>& group)
940 if (!pItem || !group)
941 return false;
943 const auto groupMember = pItem->GetPVRChannelGroupMemberInfoTag();
945 if (pItem->GetProperty(PROPERTY_CHANNEL_ENABLED).asBoolean()) // enabled == not hidden
947 if (m_bAllowRenumber)
949 groupMember->SetChannelNumber(CPVRChannelNumber(
950 static_cast<unsigned int>(pItem->GetProperty(PROPERTY_CHANNEL_NUMBER).asInteger()), 0));
953 // make sure the channel is part of the group
954 group->AppendToGroup(groupMember);
956 else
958 // remove the hidden channel from the group
959 group->RemoveFromGroup(groupMember);
962 const auto channel = groupMember->Channel();
964 channel->SetChannelName(pItem->GetProperty(PROPERTY_CHANNEL_NAME).asString(),
965 pItem->GetProperty(PROPERTY_CHANNEL_USER_SET_NAME).asBoolean());
966 channel->SetHidden(!pItem->GetProperty(PROPERTY_CHANNEL_ENABLED).asBoolean(),
967 pItem->GetProperty(PROPERTY_CHANNEL_USER_SET_HIDDEN).asBoolean());
968 channel->SetLocked(pItem->GetProperty(PROPERTY_CHANNEL_LOCKED).asBoolean());
969 channel->SetIconPath(pItem->GetProperty(PROPERTY_CHANNEL_ICON).asString(),
970 pItem->GetProperty(PROPERTY_CHANNEL_CUSTOM_ICON).asBoolean());
972 //! @todo add other scrapers
973 if (pItem->GetProperty(PROPERTY_CHANNEL_EPG_SOURCE).asInteger() == 0)
974 channel->SetEPGScraper("client");
976 channel->SetEPGEnabled(pItem->GetProperty(PROPERTY_CHANNEL_EPG_ENABLED).asBoolean());
978 return true;
981 void CGUIDialogPVRChannelManager::PromptAndSaveList()
983 if (!HasChangedItems())
984 return;
986 CGUIDialogYesNo* pDialogYesNo =
987 CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogYesNo>(WINDOW_DIALOG_YES_NO);
988 if (pDialogYesNo)
990 pDialogYesNo->SetHeading(CVariant{20052});
991 pDialogYesNo->SetLine(0, CVariant{""});
992 pDialogYesNo->SetLine(1, CVariant{19212});
993 pDialogYesNo->SetLine(2, CVariant{20103});
994 pDialogYesNo->Open();
996 if (pDialogYesNo->IsConfirmed())
997 SaveList();
998 else
999 Update();
1003 void CGUIDialogPVRChannelManager::SaveList()
1005 if (!HasChangedItems())
1006 return;
1008 /* display the progress dialog */
1009 CGUIDialogProgress* pDlgProgress = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogProgress>(WINDOW_DIALOG_PROGRESS);
1010 pDlgProgress->SetHeading(CVariant{190});
1011 pDlgProgress->SetLine(0, CVariant{""});
1012 pDlgProgress->SetLine(1, CVariant{328});
1013 pDlgProgress->SetLine(2, CVariant{""});
1014 pDlgProgress->Open();
1015 pDlgProgress->Progress();
1016 pDlgProgress->SetPercentage(0);
1018 /* persist all channels */
1019 std::shared_ptr<CPVRChannelGroup> group = CServiceBroker::GetPVRManager().ChannelGroups()->GetGroupAll(m_bIsRadio);
1020 if (!group)
1021 return;
1023 for (int iListPtr = 0; iListPtr < m_channelItems->Size(); ++iListPtr)
1025 CFileItemPtr pItem = m_channelItems->Get(iListPtr);
1026 if (pItem && pItem->GetProperty(PROPERTY_ITEM_CHANGED).asBoolean())
1028 if (pItem->GetProperty(PROPERTY_CLIENT_SUPPORTS_SETTINGS).asBoolean())
1029 RenameChannel(pItem);
1031 if (pItem->GetProperty(PROPERTY_CHANNEL_USER_SET_NAME).asBoolean() &&
1032 pItem->GetProperty(PROPERTY_CHANNEL_NAME).asString().empty())
1034 // if the user changes the name manually to an empty string we reset the
1035 // userset name flag and change the name to the name from the client
1036 pItem->SetProperty(PROPERTY_CHANNEL_USER_SET_NAME, false);
1038 const std::string newName = pItem->GetPVRChannelInfoTag()->ClientChannelName();
1039 pItem->SetProperty(PROPERTY_CHANNEL_NAME, newName);
1040 SET_CONTROL_LABEL2(EDIT_NAME, newName);
1043 // Write the changes made in this dialog back to the actual channel instance
1044 if (UpdateChannelData(pItem, group))
1045 pItem->SetProperty(PROPERTY_ITEM_CHANGED, false);
1048 pDlgProgress->SetPercentage(iListPtr * 100 / m_channelItems->Size());
1051 group->SortAndRenumber();
1053 auto channelGroups = CServiceBroker::GetPVRManager().ChannelGroups()->Get(m_bIsRadio);
1054 channelGroups->UpdateChannelNumbersFromAllChannelsGroup();
1055 channelGroups->PersistAll();
1056 pDlgProgress->Close();
1058 CONTROL_DISABLE(BUTTON_APPLY);
1061 bool CGUIDialogPVRChannelManager::HasChangedItems() const
1063 return std::any_of(m_channelItems->cbegin(), m_channelItems->cend(), [](const auto& item) {
1064 return item && item->GetProperty(PROPERTY_ITEM_CHANGED).asBoolean();
1068 namespace
1071 bool IsItemChanged(const std::shared_ptr<CFileItem>& item)
1073 const std::shared_ptr<const CPVRChannelGroupMember> member =
1074 item->GetPVRChannelGroupMemberInfoTag();
1075 const std::shared_ptr<const CPVRChannel> channel = member->Channel();
1077 return item->GetProperty(PROPERTY_CHANNEL_ENABLED).asBoolean() == channel->IsHidden() ||
1078 item->GetProperty(PROPERTY_CHANNEL_USER_SET_HIDDEN).asBoolean() !=
1079 channel->IsUserSetHidden() ||
1080 item->GetProperty(PROPERTY_CHANNEL_USER_SET_NAME).asBoolean() !=
1081 channel->IsUserSetName() ||
1082 item->GetProperty(PROPERTY_CHANNEL_NAME).asString() != channel->ChannelName() ||
1083 item->GetProperty(PROPERTY_CHANNEL_EPG_ENABLED).asBoolean() != channel->EPGEnabled() ||
1084 item->GetProperty(PROPERTY_CHANNEL_ICON).asString() != channel->IconPath() ||
1085 item->GetProperty(PROPERTY_CHANNEL_CUSTOM_ICON).asBoolean() != channel->IsUserSetIcon() ||
1086 item->GetProperty(PROPERTY_CHANNEL_EPG_SOURCE).asInteger() != 0 ||
1087 item->GetProperty(PROPERTY_CHANNEL_LOCKED).asBoolean() != channel->IsLocked() ||
1088 item->GetProperty(PROPERTY_CHANNEL_NUMBER).asString() !=
1089 member->ChannelNumber().FormattedChannelNumber();
1092 } // namespace
1094 void CGUIDialogPVRChannelManager::SetItemChanged(const CFileItemPtr& pItem)
1096 const bool changed = IsItemChanged(pItem);
1097 pItem->SetProperty(PROPERTY_ITEM_CHANGED, changed);
1099 if (changed || HasChangedItems())
1100 CONTROL_ENABLE(BUTTON_APPLY);
1101 else
1102 CONTROL_DISABLE(BUTTON_APPLY);
1105 void CGUIDialogPVRChannelManager::Renumber()
1107 if (!m_bAllowRenumber)
1108 return;
1110 int iNextChannelNumber = 0;
1111 for (const auto& item : *m_channelItems)
1113 const std::string number = item->GetProperty(PROPERTY_CHANNEL_ENABLED).asBoolean()
1114 ? std::to_string(++iNextChannelNumber)
1115 : LABEL_CHANNEL_DISABLED;
1117 if (item->GetProperty(PROPERTY_CHANNEL_NUMBER).asString() != number)
1119 item->SetProperty(PROPERTY_CHANNEL_NUMBER, number);
1120 SetItemChanged(item);