From 89ea0b5a080cdfddbdc78b52c95b40b02ac58df5 Mon Sep 17 00:00:00 2001 From: Kai Sommerfeld Date: Fri, 12 Jan 2018 10:59:05 +0100 Subject: [PATCH 1/2] [PVR][Estuary] Guide window: Add channel group selector. --- .../resources/strings.po | 22 ++- addons/skin.estuary/xml/Includes_PVR.xml | 6 +- addons/skin.estuary/xml/MyPVRGuide.xml | 137 ++++++++++++++---- xbmc/pvr/windows/GUIWindowPVRBase.cpp | 118 ++++++++++++++- xbmc/pvr/windows/GUIWindowPVRBase.h | 10 ++ xbmc/pvr/windows/GUIWindowPVRGuide.cpp | 14 +- xbmc/pvr/windows/GUIWindowPVRGuide.h | 5 +- 7 files changed, 264 insertions(+), 48 deletions(-) diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po index 214e63ca083bc..38f031b7e26c7 100644 --- a/addons/resource.language.en_gb/resources/strings.po +++ b/addons/resource.language.en_gb/resources/strings.po @@ -11074,16 +11074,16 @@ msgctxt "#19296" msgid "No PVR add-on enabled" msgstr "" -#. 'timeline' label used in pvr guide window +#. 'Viewtype' label for vertical channel layout, used in pvr guide window #: addons/skin.estuary/xml/MyPVRGuide.xml msgctxt "#19297" -msgid "Vertical" +msgid "Vertical channels" msgstr "" -#. 'timeline' label used in pvr guide window +#. 'Viewtype' label for horizontal channel layout, used in pvr guide window #: addons/skin.estuary/xml/MyPVRGuide.xml msgctxt "#19298" -msgid "Horizontal" +msgid "Horizontal channels" msgstr "" #. generic "expiration" label used in different places @@ -11093,7 +11093,19 @@ msgctxt "#19299" msgid "Expires" msgstr "" -#empty strings from id 19300 to 19498 +#. 'Viewtype' label for vertical channel layout without channel group selctor, used in pvr guide window +#: addons/skin.estuary/xml/MyPVRGuide.xml +msgctxt "#19300" +msgid "Vertical channels, no group selector" +msgstr "" + +#. 'Viewtype' label for horizontal channel layout without channel group selctor, used in pvr guide window +#: addons/skin.estuary/xml/MyPVRGuide.xml +msgctxt "#19301" +msgid "Horizontal channels, no group selector" +msgstr "" + +#empty strings from id 19302 to 19498 #. label for epg genre value #: xbmc/epg/Epg.cpp diff --git a/addons/skin.estuary/xml/Includes_PVR.xml b/addons/skin.estuary/xml/Includes_PVR.xml index 0f594edfd10b7..d3f5fa6337677 100644 --- a/addons/skin.estuary/xml/Includes_PVR.xml +++ b/addons/skin.estuary/xml/Includes_PVR.xml @@ -257,7 +257,7 @@ 0 - 0 + $PARAM[control_top] 20 340 $PARAM[control_orientation] @@ -267,8 +267,8 @@ 6 9000 60 - 50 - 50 + $PARAM[control_onup_id] + $PARAM[control_id] list $PARAM[progress_texture] diff --git a/addons/skin.estuary/xml/MyPVRGuide.xml b/addons/skin.estuary/xml/MyPVRGuide.xml index 08a7471253832..8f412da98be0b 100644 --- a/addons/skin.estuary/xml/MyPVRGuide.xml +++ b/addons/skin.estuary/xml/MyPVRGuide.xml @@ -2,7 +2,7 @@ 50 background - 50,51 + 50,51,52,53 9000 DefaultBackground @@ -10,7 +10,7 @@ Conditional Guide Timeline - Control.IsVisible(50) | Control.IsVisible(51) + Control.IsVisible(50) | Control.IsVisible(51) | Control.IsVisible(52) | Control.IsVisible(53) OpenClose_Right Visible_Right @@ -23,30 +23,115 @@ 336 dialogs/dialog-bg-nobo.png - - - - - - - - - - - - - - - - - - - - - - - - + + 0 + 0 + 100% + 44 + colors/white50.png + + + 0 + 0 + 100% + 63 + 63 + horizontal + 200 + 3 + Control.IsVisible(50) | Control.IsVisible(51) + + + -140 + 280 + center + center + + grey + + + + + 2 + -148 + 296 + 42 + lists/focus.png + Control.HasFocus(11) + + + -150 + 300 + buttons/thumbnail_focused.png + + + -140 + 280 + center + center + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 diff --git a/xbmc/pvr/windows/GUIWindowPVRBase.cpp b/xbmc/pvr/windows/GUIWindowPVRBase.cpp index c0e92e1ce3e0d..6fb211771a892 100644 --- a/xbmc/pvr/windows/GUIWindowPVRBase.cpp +++ b/xbmc/pvr/windows/GUIWindowPVRBase.cpp @@ -105,9 +105,17 @@ bool CGUIWindowPVRBase::OnAction(const CAction &action) { case ACTION_PREVIOUS_CHANNELGROUP: case ACTION_NEXT_CHANNELGROUP: + { // switch to next or previous group SetChannelGroup(action.GetID() == ACTION_NEXT_CHANNELGROUP ? m_channelGroup->GetNextGroup() : m_channelGroup->GetPreviousGroup()); return true; + } + case ACTION_MOVE_RIGHT: + case ACTION_MOVE_LEFT: + { + if (IsChannelGroupsControlFocused()) + return CGUIMediaWindow::OnAction(action) && ActivateSelectedChannelGroup(); + } } return CGUIMediaWindow::OnAction(action); @@ -133,6 +141,7 @@ void CGUIWindowPVRBase::ClearData() { CSingleLock lock(m_critSection); m_channelGroup.reset(); + m_channelGroups.clear(); } void CGUIWindowPVRBase::OnInitWindow(void) @@ -145,6 +154,9 @@ void CGUIWindowPVRBase::OnInitWindow(void) // mark item as selected by channel path m_viewControl.SetSelectedItem(CServiceBroker::GetPVRManager().GUIActions()->GetSelectedItemPath(m_bRadio)); + + // This has to be done after base class OnInitWindow to restore correct selection + InitChannelGroupsControl(); } else { @@ -171,9 +183,23 @@ bool CGUIWindowPVRBase::OnMessage(CGUIMessage& message) { case CONTROL_BTNCHANNELGROUPS: return OpenChannelGroupSelectionDialog(); + + case CONTROL_LSTCHANNELGROUPS: + { + switch (message.GetParam1()) + { + case ACTION_SELECT_ITEM: + case ACTION_MOUSE_LEFT_CLICK: + { + ActivateSelectedChannelGroup(); + bReturn = true; + break; + } + } + } } + break; } - break; case GUI_MSG_REFRESH_LIST: { @@ -183,6 +209,7 @@ bool CGUIWindowPVRBase::OnMessage(CGUIMessage& message) { // late init InitChannelGroup(); + InitChannelGroupsControl(); RegisterObservers(); HideProgressDialog(); Refresh(true); @@ -197,8 +224,8 @@ bool CGUIWindowPVRBase::OnMessage(CGUIMessage& message) UpdateSelectedItemPath(); } bReturn = true; + break; } - break; case GUI_MSG_NOTIFY_ALL: { @@ -212,8 +239,8 @@ bool CGUIWindowPVRBase::OnMessage(CGUIMessage& message) break; } } + break; } - break; } return bReturn || CGUIMediaWindow::OnMessage(message); @@ -271,6 +298,89 @@ bool CGUIWindowPVRBase::OpenChannelGroupSelectionDialog(void) return true; } +bool CGUIWindowPVRBase::HasChannelGroupsControl() +{ + CGUIControl* control = GetControl(CONTROL_LSTCHANNELGROUPS); + return control && control->IsContainer(); +} + +bool CGUIWindowPVRBase::IsChannelGroupsControlFocused() +{ + CGUIControl* control = GetControl(CONTROL_LSTCHANNELGROUPS); + return control && control->HasFocus(); +} + +void CGUIWindowPVRBase::InitChannelGroupsControl() +{ + if (HasChannelGroupsControl()) + { + const CPVRChannelGroupPtr activeGroup = GetChannelGroup(); + if (activeGroup) + { + m_channelGroups = CServiceBroker::GetPVRManager().ChannelGroups()->Get(m_bRadio)->GetMembers(true); + CFileItemList channelGroupItems; + int iItemIndex = -1; + int iIndex = 0; + for (const auto& group : m_channelGroups) + { + CFileItemPtr item(new CFileItem(group->GetPath(), true)); + item->m_strTitle = group->GroupName(); + item->SetLabel(group->GroupName()); + channelGroupItems.Add(item); + + if (iItemIndex == -1 && *activeGroup == *group) + iItemIndex = iIndex; + else + ++iIndex; + } + + CGUIMessage msg(GUI_MSG_LABEL_BIND, GetID(), CONTROL_LSTCHANNELGROUPS, iItemIndex, 0, &channelGroupItems); + OnMessage(msg); + } + } +} + +bool CGUIWindowPVRBase::SelectActiveChannelGroup() +{ + if (HasChannelGroupsControl()) + { + const CPVRChannelGroupPtr activeGroup = GetChannelGroup(); + if (activeGroup) + { + int iIndex = 0; + for (const auto& group : m_channelGroups) + { + if (*activeGroup == *group) + { + CGUIMessage msg(GUI_MSG_ITEM_SELECT, GetID(), CONTROL_LSTCHANNELGROUPS, iIndex); + OnMessage(msg); + return true; + } + ++iIndex; + } + } + } + return false; +} + +bool CGUIWindowPVRBase::ActivateSelectedChannelGroup() +{ + CGUIMessage msg(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_LSTCHANNELGROUPS); + OnMessage(msg); + + auto it = std::next(m_channelGroups.begin(), msg.GetParam1()); + if (it != m_channelGroups.end()) + { + const CPVRChannelGroupPtr newGroup = *it; + if (*newGroup != *GetChannelGroup()) + { + SetChannelGroup(newGroup); + return true; + } + } + return false; +} + bool CGUIWindowPVRBase::InitChannelGroup() { const CPVRChannelGroupPtr group(CServiceBroker::GetPVRManager().GetPlayingGroup(m_bRadio)); @@ -356,7 +466,9 @@ bool CGUIWindowPVRBase::Update(const std::string &strDirectory, bool updateFilte void CGUIWindowPVRBase::UpdateButtons(void) { CGUIMediaWindow::UpdateButtons(); + SET_CONTROL_LABEL(CONTROL_BTNCHANNELGROUPS, g_localizeStrings.Get(19141) + ": " + m_channelGroup->GroupName()); + SelectActiveChannelGroup(); } void CGUIWindowPVRBase::ShowProgressDialog(const std::string &strText, int iProgress) diff --git a/xbmc/pvr/windows/GUIWindowPVRBase.h b/xbmc/pvr/windows/GUIWindowPVRBase.h index 02c7911ec3966..849c19f075d5f 100644 --- a/xbmc/pvr/windows/GUIWindowPVRBase.h +++ b/xbmc/pvr/windows/GUIWindowPVRBase.h @@ -19,6 +19,8 @@ * */ +#include + #include "utils/Observer.h" #include "windows/GUIMediaWindow.h" @@ -32,6 +34,7 @@ #define CONTROL_BTNSHOWDELETED 7 #define CONTROL_BTNHIDEDISABLEDTIMERS 8 #define CONTROL_BTNSHOWMODE 10 +#define CONTROL_LSTCHANNELGROUPS 11 #define CONTROL_BTNCHANNELGROUPS 28 #define CONTROL_BTNFILTERCHANNELS 31 @@ -112,6 +115,12 @@ namespace PVR private: bool OpenChannelGroupSelectionDialog(void); + bool HasChannelGroupsControl(); + bool IsChannelGroupsControlFocused(); + void InitChannelGroupsControl(); + bool SelectActiveChannelGroup(); + bool ActivateSelectedChannelGroup(); + /*! * @brief Show or update the progress dialog. * @param strText The current status. @@ -125,6 +134,7 @@ namespace PVR void HideProgressDialog(void); CPVRChannelGroupPtr m_channelGroup; + std::vector m_channelGroups; XbmcThreads::EndTime m_refreshTimeout; CGUIDialogProgressBarHandle *m_progressHandle; /*!< progress dialog that is displayed while the pvr manager is loading */ }; diff --git a/xbmc/pvr/windows/GUIWindowPVRGuide.cpp b/xbmc/pvr/windows/GUIWindowPVRGuide.cpp index d20a325c9c04f..f6e4eb41f6faa 100644 --- a/xbmc/pvr/windows/GUIWindowPVRGuide.cpp +++ b/xbmc/pvr/windows/GUIWindowPVRGuide.cpp @@ -18,6 +18,8 @@ * */ +#include + #include "GUIWindowPVRGuide.h" #include "ContextMenuManager.h" @@ -29,15 +31,12 @@ #include "messaging/ApplicationMessenger.h" #include "settings/Settings.h" #include "threads/SingleLock.h" -#include "utils/log.h" #include "view/GUIViewState.h" #include "pvr/PVRGUIActions.h" #include "pvr/PVRManager.h" -#include "pvr/addons/PVRClients.h" #include "pvr/channels/PVRChannelGroupsContainer.h" #include "pvr/epg/EpgContainer.h" -#include "pvr/timers/PVRTimers.h" #include "pvr/windows/GUIEPGGridContainer.h" using namespace PVR; @@ -63,7 +62,7 @@ CGUIEPGGridContainer* CGUIWindowPVRGuideBase::GetGridControl() return dynamic_cast(GetControl(m_viewControl.GetCurrentControl())); } -void CGUIWindowPVRGuideBase::Init() +void CGUIWindowPVRGuideBase::InitEpgGridControl() { CGUIEPGGridContainer *epgGridContainer = GetGridControl(); if (epgGridContainer) @@ -98,7 +97,7 @@ void CGUIWindowPVRGuideBase::OnInitWindow() m_viewControl.SetCurrentView(m_guiState->GetViewAsControl(), false); if (InitChannelGroup()) // no channels -> lazy init - Init(); + InitEpgGridControl(); CGUIWindowPVRBase::OnInitWindow(); } @@ -184,6 +183,7 @@ void CGUIWindowPVRGuideBase::UpdateSelectedItemPath() void CGUIWindowPVRGuideBase::UpdateButtons(void) { CGUIWindowPVRBase::UpdateButtons(); + SET_CONTROL_LABEL(CONTROL_LABEL_HEADER1, g_localizeStrings.Get(19032)); SET_CONTROL_LABEL(CONTROL_LABEL_HEADER2, GetChannelGroup()->GroupName()); } @@ -425,7 +425,7 @@ bool CGUIWindowPVRGuideBase::OnMessage(CGUIMessage& message) CSingleLock lock(m_critSection); m_bRefreshTimelineItems = true; } - Init(); + InitEpgGridControl(); Refresh(true); bReturn = true; @@ -438,7 +438,7 @@ bool CGUIWindowPVRGuideBase::OnMessage(CGUIMessage& message) { // late init InitChannelGroup(); - Init(); + InitEpgGridControl(); break; } case ObservableMessageChannelGroupReset: diff --git a/xbmc/pvr/windows/GUIWindowPVRGuide.h b/xbmc/pvr/windows/GUIWindowPVRGuide.h index 1cfab0f5285d3..c91ad730bc7e6 100644 --- a/xbmc/pvr/windows/GUIWindowPVRGuide.h +++ b/xbmc/pvr/windows/GUIWindowPVRGuide.h @@ -63,11 +63,8 @@ namespace PVR void ClearData() override; private: - void Init(); - CGUIEPGGridContainer* GetGridControl(); - - bool SelectPlayingFile(void); + void InitEpgGridControl(); bool OnContextButtonBegin(); bool OnContextButtonEnd(); From 2250dcc9ad11d1f093f2eeacd70ec7e26dfd9ace Mon Sep 17 00:00:00 2001 From: Kai Sommerfeld Date: Sat, 13 Jan 2018 14:30:53 +0100 Subject: [PATCH 2/2] [PVR] Refactor channel group's path handling. --- xbmc/pvr/channels/PVRChannel.cpp | 5 ++--- xbmc/pvr/channels/PVRChannelGroup.cpp | 5 +++++ xbmc/pvr/channels/PVRChannelGroup.h | 6 ++++++ xbmc/pvr/channels/PVRChannelGroups.cpp | 27 +++++++++++--------------- 4 files changed, 24 insertions(+), 19 deletions(-) diff --git a/xbmc/pvr/channels/PVRChannel.cpp b/xbmc/pvr/channels/PVRChannel.cpp index e0a093953528f..5125d7476254e 100644 --- a/xbmc/pvr/channels/PVRChannel.cpp +++ b/xbmc/pvr/channels/PVRChannel.cpp @@ -407,9 +407,8 @@ void CPVRChannel::UpdatePath(CPVRChannelGroupInternal* group) std::string strFileNameAndPath; CSingleLock lock(m_critSection); - strFileNameAndPath = StringUtils::Format("pvr://channels/%s/%s/%s_%d.pvr", - (m_bIsRadio ? "radio" : "tv"), - group->GroupName().c_str(), + strFileNameAndPath = StringUtils::Format("%s%s_%d.pvr", + group->GetPath(), CServiceBroker::GetPVRManager().Clients()->GetClientAddonId(m_iClientId).c_str(), m_iUniqueId); if (m_strFileNameAndPath != strFileNameAndPath) diff --git a/xbmc/pvr/channels/PVRChannelGroup.cpp b/xbmc/pvr/channels/PVRChannelGroup.cpp index 6468ca041a86f..9163e80248301 100644 --- a/xbmc/pvr/channels/PVRChannelGroup.cpp +++ b/xbmc/pvr/channels/PVRChannelGroup.cpp @@ -204,6 +204,11 @@ bool CPVRChannelGroup::Update(void) return UpdateGroupEntries(PVRChannels_tmp); } +std::string CPVRChannelGroup::GetPath() const +{ + return StringUtils::Format("pvr://channels/%s/%s/", m_bRadio ? "radio" : "tv", GroupName().c_str()); +} + bool CPVRChannelGroup::SetChannelNumber(const CPVRChannelPtr &channel, const CPVRChannelNumber &channelNumber) { bool bReturn(false); diff --git a/xbmc/pvr/channels/PVRChannelGroup.h b/xbmc/pvr/channels/PVRChannelGroup.h index b0210f79a5aa6..65f9897196692 100644 --- a/xbmc/pvr/channels/PVRChannelGroup.h +++ b/xbmc/pvr/channels/PVRChannelGroup.h @@ -117,6 +117,12 @@ namespace PVR */ virtual bool Update(void); + /*! + * @brief Get the path of this group. + * @return the path. + */ + std::string GetPath() const; + /*! * @brief Change the channelnumber of a group. Used by CGUIDialogPVRChannelManager. Call SortByChannelNumber() and Renumber() after all changes are done. * @param channel The channel to change the channel number for. diff --git a/xbmc/pvr/channels/PVRChannelGroups.cpp b/xbmc/pvr/channels/PVRChannelGroups.cpp index e75ae0e809658..7c2bf6db6c3e3 100644 --- a/xbmc/pvr/channels/PVRChannelGroups.cpp +++ b/xbmc/pvr/channels/PVRChannelGroups.cpp @@ -133,25 +133,23 @@ void CPVRChannelGroups::SortGroups() } } -CFileItemPtr CPVRChannelGroups::GetByPath(const std::string &strPath) const +CFileItemPtr CPVRChannelGroups::GetByPath(const std::string &strInPath) const { - // get the filename from curl - CURL url(strPath); - std::string strFileName = url.GetFileName(); - URIUtils::RemoveSlashAtEnd(strFileName); + std::string strPath = strInPath; + URIUtils::RemoveSlashAtEnd(strPath); std::string strCheckPath; - for (std::vector::const_iterator it = m_groups.begin(); it != m_groups.end(); ++it) + for (const auto& group: m_groups) { // check if the path matches - strCheckPath = StringUtils::Format("channels/%s/%s/", (*it)->IsRadio() ? "radio" : "tv", (*it)->GroupName().c_str()); - if (URIUtils::PathHasParent(strFileName, strCheckPath)) + strCheckPath = group->GetPath(); + if (URIUtils::PathHasParent(strPath, strCheckPath)) { - strFileName.erase(0, strCheckPath.length()); - std::vector split(StringUtils::Split(strFileName, '_', 2)); + strPath.erase(0, strCheckPath.size()); + std::vector split(StringUtils::Split(strPath, '_', 2)); if (split.size() == 2) { - CPVRChannelPtr channel((*it)->GetByUniqueID(atoi(split[1].c_str()), CServiceBroker::GetPVRManager().Clients()->GetClientId(split[0]))); + const CPVRChannelPtr channel = group->GetByUniqueID(atoi(split[1].c_str()), CServiceBroker::GetPVRManager().Clients()->GetClientId(split[0])); if (channel) return CFileItemPtr(new CFileItem(channel)); } @@ -159,8 +157,7 @@ CFileItemPtr CPVRChannelGroups::GetByPath(const std::string &strPath) const } // no match - CFileItemPtr retVal(new CFileItem); - return retVal; + return CFileItemPtr(new CFileItem()); } CPVRChannelGroupPtr CPVRChannelGroups::GetById(int iGroupId) const @@ -392,15 +389,13 @@ int CPVRChannelGroups::GetGroupList(CFileItemList* results, bool bExcludeHidden int iReturn(0); CSingleLock lock(m_critSection); - std::string strPath; for (std::vector::const_iterator it = m_groups.begin(); it != m_groups.end(); ++it) { // exclude hidden groups if desired if (bExcludeHidden && (*it)->IsHidden()) continue; - strPath = StringUtils::Format("pvr://channels/%s/%s/", m_bRadio ? "radio" : "tv", (*it)->GroupName().c_str()); - CFileItemPtr group(new CFileItem(strPath, true)); + CFileItemPtr group(new CFileItem((*it)->GetPath(), true)); group->m_strTitle = (*it)->GroupName(); group->SetLabel((*it)->GroupName()); results->Add(group);