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.
9 #include "GUIDialogPVRGroupManager.h"
12 #include "FileItemList.h"
13 #include "ServiceBroker.h"
14 #include "dialogs/GUIDialogContextMenu.h"
15 #include "dialogs/GUIDialogYesNo.h"
16 #include "guilib/GUIComponent.h"
17 #include "guilib/GUIKeyboardFactory.h"
18 #include "guilib/GUIMessage.h"
19 #include "guilib/GUIRadioButtonControl.h"
20 #include "guilib/GUIWindowManager.h"
21 #include "guilib/LocalizeStrings.h"
22 #include "input/actions/Action.h"
23 #include "input/actions/ActionIDs.h"
24 #include "messaging/helpers//DialogOKHelper.h"
25 #include "pvr/PVRManager.h"
26 #include "pvr/PVRPlaybackState.h"
27 #include "pvr/addons/PVRClient.h"
28 #include "pvr/channels/PVRChannel.h"
29 #include "pvr/channels/PVRChannelGroupMember.h"
30 #include "pvr/channels/PVRChannelGroups.h"
31 #include "pvr/channels/PVRChannelGroupsContainer.h"
32 #include "pvr/filesystem/PVRGUIDirectory.h"
33 #include "settings/Settings.h"
34 #include "settings/SettingsComponent.h"
35 #include "utils/StringUtils.h"
36 #include "utils/Variant.h"
42 using namespace KODI::MESSAGING
;
45 #define CONTROL_LIST_CHANNELS_LEFT 11
46 #define CONTROL_LIST_CHANNELS_RIGHT 12
47 #define CONTROL_LIST_CHANNEL_GROUPS 13
48 #define CONTROL_CURRENT_GROUP_LABEL 20
49 #define CONTROL_UNGROUPED_LABEL 21
50 #define CONTROL_IN_GROUP_LABEL 22
51 #define BUTTON_HIDE_GROUP 25
52 #define BUTTON_NEWGROUP 26
53 #define BUTTON_RENAMEGROUP 27
54 #define BUTTON_DELGROUP 28
56 #define BUTTON_TOGGLE_RADIO_TV 34
57 #define BUTTON_RECREATE_GROUP_THUMB 35
61 constexpr const char* PROPERTY_CLIENT_NAME
= "ClientName";
65 CGUIDialogPVRGroupManager::CGUIDialogPVRGroupManager() :
66 CGUIDialog(WINDOW_DIALOG_PVR_GROUP_MANAGER
, "DialogPVRGroupManager.xml")
68 m_ungroupedChannels
= new CFileItemList
;
69 m_groupMembers
= new CFileItemList
;
70 m_channelGroups
= new CFileItemList
;
75 CGUIDialogPVRGroupManager::~CGUIDialogPVRGroupManager()
77 delete m_ungroupedChannels
;
78 delete m_groupMembers
;
79 delete m_channelGroups
;
82 void CGUIDialogPVRGroupManager::SetRadio(bool bIsRadio
)
84 m_bIsRadio
= bIsRadio
;
85 SetProperty("IsRadio", m_bIsRadio
? "true" : "");
88 bool CGUIDialogPVRGroupManager::PersistChanges()
90 return CServiceBroker::GetPVRManager().ChannelGroups()->Get(m_bIsRadio
)->PersistAll();
93 bool CGUIDialogPVRGroupManager::OnPopupMenu(int itemNumber
)
95 // Currently, the only context menu item is "move".
99 CContextButtons buttons
;
101 if (itemNumber
< 0 || itemNumber
>= m_channelGroups
->Size())
104 const auto item
= m_channelGroups
->Get(itemNumber
);
110 buttons
.Add(CONTEXT_BUTTON_MOVE
, 116); // Move
112 const int choice
= CGUIDialogContextMenu::ShowAndGetChoice(buttons
);
119 return OnContextButton(itemNumber
, choice
);
122 bool CGUIDialogPVRGroupManager::OnContextButton(int itemNumber
, int button
)
124 if (itemNumber
< 0 || itemNumber
>= m_channelGroups
->Size())
127 const auto item
= m_channelGroups
->Get(itemNumber
);
131 if (button
== CONTEXT_BUTTON_MOVE
)
140 bool CGUIDialogPVRGroupManager::ActionButtonOk(const CGUIMessage
& message
)
142 bool bReturn
= false;
143 unsigned int iControl
= message
.GetSenderId();
145 if (iControl
== BUTTON_OK
)
155 bool CGUIDialogPVRGroupManager::ActionButtonNewGroup(const CGUIMessage
& message
)
157 bool bReturn
= false;
158 unsigned int iControl
= message
.GetSenderId();
160 if (iControl
== BUTTON_NEWGROUP
)
162 std::string strGroupName
;
163 if (CGUIKeyboardFactory::ShowAndGetInput(strGroupName
, CVariant
{g_localizeStrings
.Get(19139)}, false))
165 if (!strGroupName
.empty())
167 // add the group if it doesn't already exist
168 auto groups
= CServiceBroker::GetPVRManager().ChannelGroups()->Get(m_bIsRadio
);
169 const auto group
= groups
->AddGroup(strGroupName
);
172 m_selectedGroup
= group
;
173 m_iSelectedChannelGroup
= -1; // recalc index in Update()
184 bool CGUIDialogPVRGroupManager::ActionButtonDeleteGroup(const CGUIMessage
& message
)
186 bool bReturn
= false;
187 unsigned int iControl
= message
.GetSenderId();
189 if (iControl
== BUTTON_DELGROUP
)
191 if (!m_selectedGroup
)
194 CGUIDialogYesNo
* pDialog
= CServiceBroker::GetGUI()->GetWindowManager().GetWindow
<CGUIDialogYesNo
>(WINDOW_DIALOG_YES_NO
);
198 pDialog
->SetHeading(CVariant
{117});
199 pDialog
->SetLine(0, CVariant
{""});
200 pDialog
->SetLine(1, CVariant
{m_selectedGroup
->GroupName()});
201 pDialog
->SetLine(2, CVariant
{""});
204 if (pDialog
->IsConfirmed())
206 ClearSelectedGroupsThumbnail();
207 if (CServiceBroker::GetPVRManager()
210 ->DeleteGroup(m_selectedGroup
))
220 bool CGUIDialogPVRGroupManager::ActionButtonRenameGroup(const CGUIMessage
& message
)
222 bool bReturn
= false;
223 unsigned int iControl
= message
.GetSenderId();
225 if (iControl
== BUTTON_RENAMEGROUP
)
227 if (!m_selectedGroup
)
230 std::string
strGroupName(m_selectedGroup
->GroupName());
231 if (CGUIKeyboardFactory::ShowAndGetInput(strGroupName
, CVariant
{g_localizeStrings
.Get(19139)},
232 true /* allow empty result */))
234 // if an empty string was given we reset the name to the client-supplied name, if available
235 const bool resetName
= strGroupName
.empty() && !m_selectedGroup
->ClientGroupName().empty();
237 strGroupName
= m_selectedGroup
->ClientGroupName();
239 if (!strGroupName
.empty())
241 ClearSelectedGroupsThumbnail();
242 m_selectedGroup
->SetGroupName(strGroupName
, !resetName
);
253 bool CGUIDialogPVRGroupManager::ActionButtonUngroupedChannels(const CGUIMessage
& message
)
255 bool bReturn
= false;
256 unsigned int iControl
= message
.GetSenderId();
258 if (m_viewUngroupedChannels
.HasControl(iControl
)) // list/thumb control
260 m_iSelectedUngroupedChannel
= m_viewUngroupedChannels
.GetSelectedItem();
261 if (m_selectedGroup
->SupportsMemberAdd())
263 const int actionID
= message
.GetParam1();
265 if (actionID
== ACTION_SELECT_ITEM
|| actionID
== ACTION_MOUSE_LEFT_CLICK
)
267 if (m_channelGroups
->GetFolderCount() == 0)
269 HELPERS::ShowOKDialogText(CVariant
{19033}, CVariant
{19137});
271 else if (m_ungroupedChannels
->GetFileCount() > 0)
273 const auto itemChannel
= m_ungroupedChannels
->Get(m_iSelectedUngroupedChannel
);
275 if (m_selectedGroup
->AppendToGroup(itemChannel
->GetPVRChannelGroupMemberInfoTag()))
277 ClearSelectedGroupsThumbnail();
289 bool CGUIDialogPVRGroupManager::ActionButtonGroupMembers(const CGUIMessage
& message
)
291 bool bReturn
= false;
292 unsigned int iControl
= message
.GetSenderId();
294 if (m_viewGroupMembers
.HasControl(iControl
)) // list/thumb control
296 m_iSelectedGroupMember
= m_viewGroupMembers
.GetSelectedItem();
297 if (m_selectedGroup
->SupportsMemberRemove())
299 const int actionID
= message
.GetParam1();
301 if (actionID
== ACTION_SELECT_ITEM
|| actionID
== ACTION_MOUSE_LEFT_CLICK
)
303 if (m_selectedGroup
&& m_groupMembers
->GetFileCount() > 0)
305 const auto itemChannel
= m_groupMembers
->Get(m_iSelectedGroupMember
);
306 m_selectedGroup
->RemoveFromGroup(itemChannel
->GetPVRChannelGroupMemberInfoTag());
307 ClearSelectedGroupsThumbnail();
318 bool CGUIDialogPVRGroupManager::ActionButtonChannelGroups(const CGUIMessage
& message
)
320 bool bReturn
= false;
321 unsigned int iControl
= message
.GetSenderId();
323 if (m_viewChannelGroups
.HasControl(iControl
)) // list/thumb control
327 const int iAction
= message
.GetParam1();
329 if (iAction
== ACTION_SELECT_ITEM
|| iAction
== ACTION_MOUSE_LEFT_CLICK
)
331 m_iSelectedChannelGroup
= m_viewChannelGroups
.GetSelectedItem();
334 else if (iAction
== ACTION_CONTEXT_MENU
|| iAction
== ACTION_MOUSE_RIGHT_CLICK
)
336 m_iSelectedChannelGroup
= m_viewChannelGroups
.GetSelectedItem();
337 OnPopupMenu(m_iSelectedChannelGroup
);
343 const auto item
= m_channelGroups
->Get(m_iSelectedChannelGroup
);
348 m_movingItem
= false;
350 // reset group positions
351 auto* groups
= CServiceBroker::GetPVRManager().ChannelGroups()->Get(m_bIsRadio
);
353 for (auto& groupItem
: *m_channelGroups
)
355 const auto group
= groups
->GetGroupByPath(groupItem
->GetPath());
357 group
->SetPosition(pos
++);
359 groups
->SortGroups();
368 bool CGUIDialogPVRGroupManager::ActionButtonHideGroup(const CGUIMessage
& message
)
370 bool bReturn
= false;
372 if (message
.GetSenderId() == BUTTON_HIDE_GROUP
&& m_selectedGroup
)
374 CGUIRadioButtonControl
* button
= static_cast<CGUIRadioButtonControl
*>(GetControl(message
.GetSenderId()));
377 CServiceBroker::GetPVRManager()
380 ->HideGroup(m_selectedGroup
, button
->IsSelected());
390 bool CGUIDialogPVRGroupManager::ActionButtonToggleRadioTV(const CGUIMessage
& message
)
392 bool bReturn
= false;
394 if (message
.GetSenderId() == BUTTON_TOGGLE_RADIO_TV
)
397 SetRadio(!m_bIsRadio
);
405 bool CGUIDialogPVRGroupManager::ActionButtonRecreateThumbnail(const CGUIMessage
& message
)
407 bool bReturn
= false;
409 if (message
.GetSenderId() == BUTTON_RECREATE_GROUP_THUMB
)
411 m_thumbLoader
.ClearCachedImages(*m_channelGroups
);
419 bool CGUIDialogPVRGroupManager::OnMessageClick(const CGUIMessage
& message
)
421 return ActionButtonOk(message
) ||
422 ActionButtonNewGroup(message
) ||
423 ActionButtonDeleteGroup(message
) ||
424 ActionButtonRenameGroup(message
) ||
425 ActionButtonUngroupedChannels(message
) ||
426 ActionButtonGroupMembers(message
) ||
427 ActionButtonChannelGroups(message
) ||
428 ActionButtonHideGroup(message
) ||
429 ActionButtonToggleRadioTV(message
) ||
430 ActionButtonRecreateThumbnail(message
);
433 bool CGUIDialogPVRGroupManager::OnMessage(CGUIMessage
& message
)
435 unsigned int iMessage
= message
.GetMessage();
439 case GUI_MSG_CLICKED
:
441 OnMessageClick(message
);
446 return CGUIDialog::OnMessage(message
);
449 bool CGUIDialogPVRGroupManager::OnActionMove(const CAction
& action
)
451 bool bReturn
= false;
452 int iActionId
= action
.GetID();
454 if (GetFocusedControlID() == CONTROL_LIST_CHANNEL_GROUPS
)
456 if (iActionId
== ACTION_MOUSE_MOVE
)
458 int iSelected
= m_viewChannelGroups
.GetSelectedItem();
459 if (m_iSelectedChannelGroup
< iSelected
)
461 iActionId
= ACTION_MOVE_DOWN
;
463 else if (m_iSelectedChannelGroup
> iSelected
)
465 iActionId
= ACTION_MOVE_UP
;
473 if (iActionId
== ACTION_MOVE_DOWN
|| iActionId
== ACTION_MOVE_UP
||
474 iActionId
== ACTION_PAGE_DOWN
|| iActionId
== ACTION_PAGE_UP
||
475 iActionId
== ACTION_FIRST_PAGE
|| iActionId
== ACTION_LAST_PAGE
)
477 CGUIDialog::OnAction(action
);
478 int iSelected
= m_viewChannelGroups
.GetSelectedItem();
483 if (iSelected
!= m_iSelectedChannelGroup
)
485 m_iSelectedChannelGroup
= iSelected
;
491 bool moveUp
= iActionId
== ACTION_PAGE_UP
|| iActionId
== ACTION_MOVE_UP
||
492 iActionId
== ACTION_FIRST_PAGE
;
493 unsigned int lines
= moveUp
? std::abs(m_iSelectedChannelGroup
- iSelected
) : 1;
494 bool outOfBounds
= moveUp
? m_iSelectedChannelGroup
<= 0
495 : m_iSelectedChannelGroup
>= m_channelGroups
->Size() - 1;
499 lines
= m_channelGroups
->Size() - 1;
501 for (unsigned int line
= 0; line
< lines
; ++line
)
503 const unsigned int newSelect
=
504 moveUp
? m_iSelectedChannelGroup
- 1 : m_iSelectedChannelGroup
+ 1;
507 m_channelGroups
->Swap(newSelect
, m_iSelectedChannelGroup
);
508 m_iSelectedChannelGroup
= newSelect
;
511 m_viewChannelGroups
.SetItems(*m_channelGroups
);
512 m_viewChannelGroups
.SetSelectedItem(m_iSelectedChannelGroup
);
520 bool CGUIDialogPVRGroupManager::OnAction(const CAction
& action
)
522 return OnActionMove(action
) ||
523 CGUIDialog::OnAction(action
);
526 void CGUIDialogPVRGroupManager::OnInitWindow()
528 CGUIDialog::OnInitWindow();
529 m_iSelectedUngroupedChannel
= 0;
530 m_iSelectedGroupMember
= 0;
531 m_iSelectedChannelGroup
= 0;
532 m_movingItem
= false;
534 // prevent resorting groups if backend group order shall be used
535 const std::shared_ptr
<CSettings
> settings
= CServiceBroker::GetSettingsComponent()->GetSettings();
536 m_allowReorder
= !settings
->GetBool(CSettings::SETTING_PVRMANAGER_BACKENDCHANNELGROUPSORDER
);
541 void CGUIDialogPVRGroupManager::OnDeinitWindow(int nextWindowID
)
544 CGUIDialog::OnDeinitWindow(nextWindowID
);
547 void CGUIDialogPVRGroupManager::OnWindowLoaded()
549 CGUIDialog::OnWindowLoaded();
551 m_viewUngroupedChannels
.Reset();
552 m_viewUngroupedChannels
.SetParentWindow(GetID());
553 m_viewUngroupedChannels
.AddView(GetControl(CONTROL_LIST_CHANNELS_LEFT
));
555 m_viewGroupMembers
.Reset();
556 m_viewGroupMembers
.SetParentWindow(GetID());
557 m_viewGroupMembers
.AddView(GetControl(CONTROL_LIST_CHANNELS_RIGHT
));
559 m_viewChannelGroups
.Reset();
560 m_viewChannelGroups
.SetParentWindow(GetID());
561 m_viewChannelGroups
.AddView(GetControl(CONTROL_LIST_CHANNEL_GROUPS
));
564 void CGUIDialogPVRGroupManager::OnWindowUnload()
566 CGUIDialog::OnWindowUnload();
567 m_viewUngroupedChannels
.Reset();
568 m_viewGroupMembers
.Reset();
569 m_viewChannelGroups
.Reset();
572 void CGUIDialogPVRGroupManager::Update()
574 m_viewUngroupedChannels
.SetCurrentView(CONTROL_LIST_CHANNELS_LEFT
);
575 m_viewGroupMembers
.SetCurrentView(CONTROL_LIST_CHANNELS_RIGHT
);
576 m_viewChannelGroups
.SetCurrentView(CONTROL_LIST_CHANNEL_GROUPS
);
580 // get the groups list
581 CPVRGUIDirectory::GetChannelGroupsDirectory(m_bIsRadio
, false, *m_channelGroups
);
583 for (auto& group
: *m_channelGroups
)
585 const std::shared_ptr
<const CPVRClient
> client
=
586 CServiceBroker::GetPVRManager().GetClient(*group
);
588 group
->SetProperty(PROPERTY_CLIENT_NAME
, client
->GetFullClientName());
591 // Load group thumbnails
592 m_thumbLoader
.Load(*m_channelGroups
);
594 m_viewChannelGroups
.SetItems(*m_channelGroups
);
596 if (m_iSelectedChannelGroup
>= 0)
598 m_viewChannelGroups
.SetSelectedItem(m_iSelectedChannelGroup
);
600 // select a group or select the default group if no group was selected
601 const auto item
= m_channelGroups
->Get(m_viewChannelGroups
.GetSelectedItem());
602 m_selectedGroup
= CServiceBroker::GetPVRManager()
605 ->GetGroupByPath(item
->GetPath());
607 else if (m_selectedGroup
)
609 m_viewChannelGroups
.SetSelectedItem(m_selectedGroup
->GetPath());
610 m_iSelectedChannelGroup
= m_viewChannelGroups
.GetSelectedItem();
615 /* set this group in the pvrmanager, so it becomes the selected group in other dialogs too */
616 CServiceBroker::GetPVRManager().PlaybackState()->SetActiveChannelGroup(m_selectedGroup
);
617 SET_CONTROL_LABEL(CONTROL_CURRENT_GROUP_LABEL
, m_selectedGroup
->GroupName());
618 SET_CONTROL_SELECTED(GetID(), BUTTON_HIDE_GROUP
, m_selectedGroup
->IsHidden());
620 CONTROL_ENABLE_ON_CONDITION(BUTTON_DELGROUP
, m_selectedGroup
->SupportsDelete());
622 SET_CONTROL_LABEL(CONTROL_UNGROUPED_LABEL
, g_localizeStrings
.Get(19219));
624 CONTROL_IN_GROUP_LABEL
,
625 StringUtils::Format("{} {}", g_localizeStrings
.Get(19220), m_selectedGroup
->GroupName()));
627 const std::vector
<std::shared_ptr
<CPVRChannelGroupMember
>> groupMembers
=
628 m_selectedGroup
->GetMembers(CPVRChannelGroup::Include::ONLY_VISIBLE
);
629 for (const auto& groupMember
: groupMembers
)
631 m_groupMembers
->Add(std::make_shared
<CFileItem
>(groupMember
));
634 const auto groups
= CServiceBroker::GetPVRManager().ChannelGroups()->Get(m_bIsRadio
);
635 const auto availableMembers
= groups
->GetMembersAvailableForGroup(m_selectedGroup
);
637 for (const auto& groupMember
: availableMembers
)
639 m_ungroupedChannels
->Add(std::make_shared
<CFileItem
>(groupMember
));
642 m_viewGroupMembers
.SetItems(*m_groupMembers
);
643 m_viewGroupMembers
.SetSelectedItem(m_iSelectedGroupMember
);
645 m_viewUngroupedChannels
.SetItems(*m_ungroupedChannels
);
646 m_viewUngroupedChannels
.SetSelectedItem(m_iSelectedUngroupedChannel
);
650 void CGUIDialogPVRGroupManager::Clear()
652 if (m_thumbLoader
.IsLoading())
653 m_thumbLoader
.StopThread();
655 m_viewUngroupedChannels
.Clear();
656 m_viewGroupMembers
.Clear();
657 m_viewChannelGroups
.Clear();
659 m_ungroupedChannels
->Clear();
660 m_groupMembers
->Clear();
661 m_channelGroups
->Clear();
664 void CGUIDialogPVRGroupManager::ClearSelectedGroupsThumbnail()
666 m_thumbLoader
.ClearCachedImage(*m_channelGroups
->Get(m_iSelectedChannelGroup
));