From c04dcc2e7d834218ef2d4194331e383402495ae1 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 10 Apr 2024 20:07:22 +0200 Subject: Adding upstream version 2:20.4+dfsg. Signed-off-by: Daniel Baumann --- xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.cpp | 1513 ++++++++++++++++++++++++ 1 file changed, 1513 insertions(+) create mode 100644 xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.cpp (limited to 'xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.cpp') diff --git a/xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.cpp b/xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.cpp new file mode 100644 index 0000000..f786627 --- /dev/null +++ b/xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.cpp @@ -0,0 +1,1513 @@ +/* + * 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 "GUIDialogPVRTimerSettings.h" + +#include "ServiceBroker.h" +#include "dialogs/GUIDialogNumeric.h" +#include "guilib/GUIMessage.h" +#include "guilib/LocalizeStrings.h" +#include "messaging/helpers/DialogOKHelper.h" +#include "pvr/PVRManager.h" +#include "pvr/addons/PVRClient.h" +#include "pvr/addons/PVRClients.h" +#include "pvr/channels/PVRChannel.h" +#include "pvr/channels/PVRChannelGroup.h" +#include "pvr/channels/PVRChannelGroupMember.h" +#include "pvr/channels/PVRChannelGroupsContainer.h" +#include "pvr/epg/EpgInfoTag.h" +#include "pvr/timers/PVRTimerInfoTag.h" +#include "pvr/timers/PVRTimerType.h" +#include "settings/SettingUtils.h" +#include "settings/dialogs/GUIDialogSettingsBase.h" +#include "settings/lib/Setting.h" +#include "settings/lib/SettingsManager.h" +#include "settings/windows/GUIControlSettings.h" +#include "utils/StringUtils.h" +#include "utils/Variant.h" +#include "utils/log.h" + +#include +#include +#include +#include +#include +#include + +using namespace PVR; +using namespace KODI::MESSAGING; + +#define SETTING_TMR_TYPE "timer.type" +#define SETTING_TMR_ACTIVE "timer.active" +#define SETTING_TMR_NAME "timer.name" +#define SETTING_TMR_EPGSEARCH "timer.epgsearch" +#define SETTING_TMR_FULLTEXT "timer.fulltext" +#define SETTING_TMR_CHANNEL "timer.channel" +#define SETTING_TMR_START_ANYTIME "timer.startanytime" +#define SETTING_TMR_END_ANYTIME "timer.endanytime" +#define SETTING_TMR_START_DAY "timer.startday" +#define SETTING_TMR_END_DAY "timer.endday" +#define SETTING_TMR_BEGIN "timer.begin" +#define SETTING_TMR_END "timer.end" +#define SETTING_TMR_WEEKDAYS "timer.weekdays" +#define SETTING_TMR_FIRST_DAY "timer.firstday" +#define SETTING_TMR_NEW_EPISODES "timer.newepisodes" +#define SETTING_TMR_BEGIN_PRE "timer.startmargin" +#define SETTING_TMR_END_POST "timer.endmargin" +#define SETTING_TMR_PRIORITY "timer.priority" +#define SETTING_TMR_LIFETIME "timer.lifetime" +#define SETTING_TMR_MAX_REC "timer.maxrecordings" +#define SETTING_TMR_DIR "timer.directory" +#define SETTING_TMR_REC_GROUP "timer.recgroup" + +#define TYPE_DEP_VISIBI_COND_ID_POSTFIX "visibi.typedep" +#define TYPE_DEP_ENABLE_COND_ID_POSTFIX "enable.typedep" +#define CHANNEL_DEP_VISIBI_COND_ID_POSTFIX "visibi.channeldep" +#define START_ANYTIME_DEP_VISIBI_COND_ID_POSTFIX "visibi.startanytimedep" +#define END_ANYTIME_DEP_VISIBI_COND_ID_POSTFIX "visibi.endanytimedep" + +CGUIDialogPVRTimerSettings::CGUIDialogPVRTimerSettings() + : CGUIDialogSettingsManualBase(WINDOW_DIALOG_PVR_TIMER_SETTING, "DialogSettings.xml"), + m_iWeekdays(PVR_WEEKDAY_NONE) +{ + m_loadType = LOAD_EVERY_TIME; +} + +CGUIDialogPVRTimerSettings::~CGUIDialogPVRTimerSettings() = default; + +bool CGUIDialogPVRTimerSettings::CanBeActivated() const +{ + if (!m_timerInfoTag) + { + CLog::LogF(LOGERROR, "No timer info tag"); + return false; + } + return true; +} + +void CGUIDialogPVRTimerSettings::SetTimer(const std::shared_ptr& timer) +{ + if (!timer) + { + CLog::LogF(LOGERROR, "No timer given"); + return; + } + + m_timerInfoTag = timer; + + // Copy data we need from tag. Do not modify the tag itself until Save()! + m_timerType = m_timerInfoTag->GetTimerType(); + m_bIsRadio = m_timerInfoTag->m_bIsRadio; + m_bIsNewTimer = m_timerInfoTag->m_iClientIndex == PVR_TIMER_NO_CLIENT_INDEX; + m_bTimerActive = m_bIsNewTimer || !m_timerType->SupportsEnableDisable() || + !(m_timerInfoTag->m_state == PVR_TIMER_STATE_DISABLED); + m_bStartAnyTime = + m_bIsNewTimer || !m_timerType->SupportsStartAnyTime() || m_timerInfoTag->m_bStartAnyTime; + m_bEndAnyTime = + m_bIsNewTimer || !m_timerType->SupportsEndAnyTime() || m_timerInfoTag->m_bEndAnyTime; + m_strTitle = m_timerInfoTag->m_strTitle; + + m_startLocalTime = m_timerInfoTag->StartAsLocalTime(); + m_endLocalTime = m_timerInfoTag->EndAsLocalTime(); + + m_timerStartTimeStr = m_startLocalTime.GetAsLocalizedTime("", false); + m_timerEndTimeStr = m_endLocalTime.GetAsLocalizedTime("", false); + m_firstDayLocalTime = m_timerInfoTag->FirstDayAsLocalTime(); + + m_strEpgSearchString = m_timerInfoTag->m_strEpgSearchString; + if ((m_bIsNewTimer || !m_timerType->SupportsEpgTitleMatch()) && m_strEpgSearchString.empty()) + m_strEpgSearchString = m_strTitle; + + m_bFullTextEpgSearch = m_timerInfoTag->m_bFullTextEpgSearch; + + m_iWeekdays = m_timerInfoTag->m_iWeekdays; + if ((m_bIsNewTimer || !m_timerType->SupportsWeekdays()) && m_iWeekdays == PVR_WEEKDAY_NONE) + m_iWeekdays = PVR_WEEKDAY_ALLDAYS; + + m_iPreventDupEpisodes = m_timerInfoTag->m_iPreventDupEpisodes; + m_iMarginStart = m_timerInfoTag->m_iMarginStart; + m_iMarginEnd = m_timerInfoTag->m_iMarginEnd; + m_iPriority = m_timerInfoTag->m_iPriority; + m_iLifetime = m_timerInfoTag->m_iLifetime; + m_iMaxRecordings = m_timerInfoTag->m_iMaxRecordings; + + if (m_bIsNewTimer && m_timerInfoTag->m_strDirectory.empty() && + m_timerType->SupportsRecordingFolders()) + m_strDirectory = m_strTitle; + else + m_strDirectory = m_timerInfoTag->m_strDirectory; + + m_iRecordingGroup = m_timerInfoTag->m_iRecordingGroup; + + InitializeChannelsList(); + InitializeTypesList(); + + // Channel + m_channel = ChannelDescriptor(); + + if (m_timerInfoTag->m_iClientChannelUid == PVR_CHANNEL_INVALID_UID) + { + if (m_timerType->SupportsAnyChannel()) + { + // Select first matching "Any channel" entry. + const auto it = std::find_if(m_channelEntries.cbegin(), m_channelEntries.cend(), + [this](const auto& channel) { + return channel.second.channelUid == PVR_CHANNEL_INVALID_UID && + channel.second.clientId == m_timerInfoTag->m_iClientId; + }); + + if (it != m_channelEntries.cend()) + { + m_channel = (*it).second; + } + else + { + CLog::LogF(LOGERROR, "Unable to map PVR_CHANNEL_INVALID_UID to channel entry!"); + } + } + else if (m_bIsNewTimer) + { + // Select first matching regular (not "Any channel") entry. + const auto it = std::find_if(m_channelEntries.cbegin(), m_channelEntries.cend(), + [this](const auto& channel) { + return channel.second.channelUid != PVR_CHANNEL_INVALID_UID && + channel.second.clientId == m_timerInfoTag->m_iClientId; + }); + + if (it != m_channelEntries.cend()) + { + m_channel = (*it).second; + } + else + { + CLog::LogF(LOGERROR, "Unable to map PVR_CHANNEL_INVALID_UID to channel entry!"); + } + } + } + else + { + // Find matching channel entry + const auto it = std::find_if( + m_channelEntries.cbegin(), m_channelEntries.cend(), [this](const auto& channel) { + return channel.second.channelUid == m_timerInfoTag->m_iClientChannelUid && + channel.second.clientId == m_timerInfoTag->m_iClientId; + }); + + if (it != m_channelEntries.cend()) + { + m_channel = (*it).second; + } + else + { + CLog::LogF(LOGERROR, "Unable to map channel uid to channel entry!"); + } + } +} + +void CGUIDialogPVRTimerSettings::SetupView() +{ + CGUIDialogSettingsManualBase::SetupView(); + SetHeading(19065); + SET_CONTROL_HIDDEN(CONTROL_SETTINGS_CUSTOM_BUTTON); + SET_CONTROL_LABEL(CONTROL_SETTINGS_OKAY_BUTTON, 186); + SET_CONTROL_LABEL(CONTROL_SETTINGS_CANCEL_BUTTON, 222); + SetButtonLabels(); +} + +void CGUIDialogPVRTimerSettings::InitializeSettings() +{ + CGUIDialogSettingsManualBase::InitializeSettings(); + + const std::shared_ptr category = AddCategory("pvrtimersettings", -1); + if (category == NULL) + { + CLog::LogF(LOGERROR, "Unable to add settings category"); + return; + } + + const std::shared_ptr group = AddGroup(category); + if (group == NULL) + { + CLog::LogF(LOGERROR, "Unable to add settings group"); + return; + } + + std::shared_ptr setting = NULL; + + // Timer type + bool useDetails = false; + bool foundClientSupportingTimers = false; + + const CPVRClientMap clients = CServiceBroker::GetPVRManager().Clients()->GetCreatedClients(); + for (const auto& client : clients) + { + if (client.second->GetClientCapabilities().SupportsTimers()) + { + if (foundClientSupportingTimers) + { + // found second client supporting timers, use detailed timer type list layout + useDetails = true; + break; + } + foundClientSupportingTimers = true; + } + } + + setting = AddList(group, SETTING_TMR_TYPE, 803, SettingLevel::Basic, 0, TypesFiller, 803, true, + -1, useDetails); + AddTypeDependentEnableCondition(setting, SETTING_TMR_TYPE); + + // Timer enabled/disabled + setting = AddToggle(group, SETTING_TMR_ACTIVE, 305, SettingLevel::Basic, m_bTimerActive); + AddTypeDependentVisibilityCondition(setting, SETTING_TMR_ACTIVE); + AddTypeDependentEnableCondition(setting, SETTING_TMR_ACTIVE); + + // Name + setting = + AddEdit(group, SETTING_TMR_NAME, 19075, SettingLevel::Basic, m_strTitle, true, false, 19097); + AddTypeDependentEnableCondition(setting, SETTING_TMR_NAME); + + // epg search string (only for epg-based timer rules) + setting = AddEdit(group, SETTING_TMR_EPGSEARCH, 804, SettingLevel::Basic, m_strEpgSearchString, + true, false, 805); + AddTypeDependentVisibilityCondition(setting, SETTING_TMR_EPGSEARCH); + AddTypeDependentEnableCondition(setting, SETTING_TMR_EPGSEARCH); + + // epg fulltext search (only for epg-based timer rules) + setting = AddToggle(group, SETTING_TMR_FULLTEXT, 806, SettingLevel::Basic, m_bFullTextEpgSearch); + AddTypeDependentVisibilityCondition(setting, SETTING_TMR_FULLTEXT); + AddTypeDependentEnableCondition(setting, SETTING_TMR_FULLTEXT); + + // Channel + setting = + AddList(group, SETTING_TMR_CHANNEL, 19078, SettingLevel::Basic, 0, ChannelsFiller, 19078); + AddTypeDependentVisibilityCondition(setting, SETTING_TMR_CHANNEL); + AddTypeDependentEnableCondition(setting, SETTING_TMR_CHANNEL); + + // Days of week (only for timer rules) + std::vector weekdaysPreselect; + if (m_iWeekdays & PVR_WEEKDAY_MONDAY) + weekdaysPreselect.push_back(PVR_WEEKDAY_MONDAY); + if (m_iWeekdays & PVR_WEEKDAY_TUESDAY) + weekdaysPreselect.push_back(PVR_WEEKDAY_TUESDAY); + if (m_iWeekdays & PVR_WEEKDAY_WEDNESDAY) + weekdaysPreselect.push_back(PVR_WEEKDAY_WEDNESDAY); + if (m_iWeekdays & PVR_WEEKDAY_THURSDAY) + weekdaysPreselect.push_back(PVR_WEEKDAY_THURSDAY); + if (m_iWeekdays & PVR_WEEKDAY_FRIDAY) + weekdaysPreselect.push_back(PVR_WEEKDAY_FRIDAY); + if (m_iWeekdays & PVR_WEEKDAY_SATURDAY) + weekdaysPreselect.push_back(PVR_WEEKDAY_SATURDAY); + if (m_iWeekdays & PVR_WEEKDAY_SUNDAY) + weekdaysPreselect.push_back(PVR_WEEKDAY_SUNDAY); + + setting = AddList(group, SETTING_TMR_WEEKDAYS, 19079, SettingLevel::Basic, weekdaysPreselect, + WeekdaysFiller, 19079, 1, -1, true, -1, WeekdaysValueFormatter); + AddTypeDependentVisibilityCondition(setting, SETTING_TMR_WEEKDAYS); + AddTypeDependentEnableCondition(setting, SETTING_TMR_WEEKDAYS); + + // "Start any time" (only for timer rules) + setting = AddToggle(group, SETTING_TMR_START_ANYTIME, 810, SettingLevel::Basic, m_bStartAnyTime); + AddTypeDependentVisibilityCondition(setting, SETTING_TMR_START_ANYTIME); + AddTypeDependentEnableCondition(setting, SETTING_TMR_START_ANYTIME); + + // Start day (day + month + year only, no hours, minutes) + setting = AddSpinner(group, SETTING_TMR_START_DAY, 19128, SettingLevel::Basic, + GetDateAsIndex(m_startLocalTime), DaysFiller); + AddTypeDependentVisibilityCondition(setting, SETTING_TMR_START_DAY); + AddTypeDependentEnableCondition(setting, SETTING_TMR_START_DAY); + AddStartAnytimeDependentVisibilityCondition(setting, SETTING_TMR_START_DAY); + + // Start time (hours + minutes only, no day, month, year) + setting = AddButton(group, SETTING_TMR_BEGIN, 19126, SettingLevel::Basic); + AddTypeDependentVisibilityCondition(setting, SETTING_TMR_BEGIN); + AddTypeDependentEnableCondition(setting, SETTING_TMR_BEGIN); + AddStartAnytimeDependentVisibilityCondition(setting, SETTING_TMR_BEGIN); + + // "End any time" (only for timer rules) + setting = AddToggle(group, SETTING_TMR_END_ANYTIME, 817, SettingLevel::Basic, m_bEndAnyTime); + AddTypeDependentVisibilityCondition(setting, SETTING_TMR_END_ANYTIME); + AddTypeDependentEnableCondition(setting, SETTING_TMR_END_ANYTIME); + + // End day (day + month + year only, no hours, minutes) + setting = AddSpinner(group, SETTING_TMR_END_DAY, 19129, SettingLevel::Basic, + GetDateAsIndex(m_endLocalTime), DaysFiller); + AddTypeDependentVisibilityCondition(setting, SETTING_TMR_END_DAY); + AddTypeDependentEnableCondition(setting, SETTING_TMR_END_DAY); + AddEndAnytimeDependentVisibilityCondition(setting, SETTING_TMR_END_DAY); + + // End time (hours + minutes only, no day, month, year) + setting = AddButton(group, SETTING_TMR_END, 19127, SettingLevel::Basic); + AddTypeDependentVisibilityCondition(setting, SETTING_TMR_END); + AddTypeDependentEnableCondition(setting, SETTING_TMR_END); + AddEndAnytimeDependentVisibilityCondition(setting, SETTING_TMR_END); + + // First day (only for timer rules) + setting = AddSpinner(group, SETTING_TMR_FIRST_DAY, 19084, SettingLevel::Basic, + GetDateAsIndex(m_firstDayLocalTime), DaysFiller); + AddTypeDependentVisibilityCondition(setting, SETTING_TMR_FIRST_DAY); + AddTypeDependentEnableCondition(setting, SETTING_TMR_FIRST_DAY); + + // "Prevent duplicate episodes" (only for timer rules) + setting = AddList(group, SETTING_TMR_NEW_EPISODES, 812, SettingLevel::Basic, + m_iPreventDupEpisodes, DupEpisodesFiller, 812); + AddTypeDependentVisibilityCondition(setting, SETTING_TMR_NEW_EPISODES); + AddTypeDependentEnableCondition(setting, SETTING_TMR_NEW_EPISODES); + + // Pre and post record time + setting = AddList(group, SETTING_TMR_BEGIN_PRE, 813, SettingLevel::Basic, m_iMarginStart, + MarginTimeFiller, 813); + AddTypeDependentVisibilityCondition(setting, SETTING_TMR_BEGIN_PRE); + AddTypeDependentEnableCondition(setting, SETTING_TMR_BEGIN_PRE); + + setting = AddList(group, SETTING_TMR_END_POST, 814, SettingLevel::Basic, m_iMarginEnd, + MarginTimeFiller, 814); + AddTypeDependentVisibilityCondition(setting, SETTING_TMR_END_POST); + AddTypeDependentEnableCondition(setting, SETTING_TMR_END_POST); + + // Priority + setting = AddList(group, SETTING_TMR_PRIORITY, 19082, SettingLevel::Basic, m_iPriority, + PrioritiesFiller, 19082); + AddTypeDependentVisibilityCondition(setting, SETTING_TMR_PRIORITY); + AddTypeDependentEnableCondition(setting, SETTING_TMR_PRIORITY); + + // Lifetime + setting = AddList(group, SETTING_TMR_LIFETIME, 19083, SettingLevel::Basic, m_iLifetime, + LifetimesFiller, 19083); + AddTypeDependentVisibilityCondition(setting, SETTING_TMR_LIFETIME); + AddTypeDependentEnableCondition(setting, SETTING_TMR_LIFETIME); + + // MaxRecordings + setting = AddList(group, SETTING_TMR_MAX_REC, 818, SettingLevel::Basic, m_iMaxRecordings, + MaxRecordingsFiller, 818); + AddTypeDependentVisibilityCondition(setting, SETTING_TMR_MAX_REC); + AddTypeDependentEnableCondition(setting, SETTING_TMR_MAX_REC); + + // Recording folder + setting = AddEdit(group, SETTING_TMR_DIR, 19076, SettingLevel::Basic, m_strDirectory, true, false, + 19104); + AddTypeDependentVisibilityCondition(setting, SETTING_TMR_DIR); + AddTypeDependentEnableCondition(setting, SETTING_TMR_DIR); + + // Recording group + setting = AddList(group, SETTING_TMR_REC_GROUP, 811, SettingLevel::Basic, m_iRecordingGroup, + RecordingGroupFiller, 811); + AddTypeDependentVisibilityCondition(setting, SETTING_TMR_REC_GROUP); + AddTypeDependentEnableCondition(setting, SETTING_TMR_REC_GROUP); +} + +int CGUIDialogPVRTimerSettings::GetWeekdaysFromSetting(const SettingConstPtr& setting) +{ + std::shared_ptr settingList = + std::static_pointer_cast(setting); + if (settingList->GetElementType() != SettingType::Integer) + { + CLog::LogF(LOGERROR, "Wrong weekdays element type"); + return 0; + } + int weekdays = 0; + std::vector list = CSettingUtils::GetList(settingList); + for (const auto& value : list) + { + if (!value.isInteger()) + { + CLog::LogF(LOGERROR, "Wrong weekdays value type"); + return 0; + } + weekdays += static_cast(value.asInteger()); + } + + return weekdays; +} + +void CGUIDialogPVRTimerSettings::OnSettingChanged(const std::shared_ptr& setting) +{ + if (setting == NULL) + { + CLog::LogF(LOGERROR, "No setting"); + return; + } + + CGUIDialogSettingsManualBase::OnSettingChanged(setting); + + const std::string& settingId = setting->GetId(); + + if (settingId == SETTING_TMR_TYPE) + { + int idx = std::static_pointer_cast(setting)->GetValue(); + const auto it = m_typeEntries.find(idx); + if (it != m_typeEntries.end()) + { + m_timerType = it->second; + + // reset certain settings to the defaults of the new timer type + + if (m_timerType->SupportsPriority()) + m_iPriority = m_timerType->GetPriorityDefault(); + + if (m_timerType->SupportsLifetime()) + m_iLifetime = m_timerType->GetLifetimeDefault(); + + if (m_timerType->SupportsMaxRecordings()) + m_iMaxRecordings = m_timerType->GetMaxRecordingsDefault(); + + if (m_timerType->SupportsRecordingGroup()) + m_iRecordingGroup = m_timerType->GetRecordingGroupDefault(); + + if (m_timerType->SupportsRecordOnlyNewEpisodes()) + m_iPreventDupEpisodes = m_timerType->GetPreventDuplicateEpisodesDefault(); + + if (m_timerType->IsTimerRule() && (m_iWeekdays == PVR_WEEKDAY_ALLDAYS)) + SetButtonLabels(); // update "Any day" vs. "Every day" + } + else + { + CLog::LogF(LOGERROR, "Unable to get 'type' value"); + } + } + else if (settingId == SETTING_TMR_ACTIVE) + { + m_bTimerActive = std::static_pointer_cast(setting)->GetValue(); + } + else if (settingId == SETTING_TMR_NAME) + { + m_strTitle = std::static_pointer_cast(setting)->GetValue(); + } + else if (settingId == SETTING_TMR_EPGSEARCH) + { + m_strEpgSearchString = std::static_pointer_cast(setting)->GetValue(); + } + else if (settingId == SETTING_TMR_FULLTEXT) + { + m_bFullTextEpgSearch = std::static_pointer_cast(setting)->GetValue(); + } + else if (settingId == SETTING_TMR_CHANNEL) + { + int idx = std::static_pointer_cast(setting)->GetValue(); + const auto it = m_channelEntries.find(idx); + if (it != m_channelEntries.end()) + { + m_channel = it->second; + } + else + { + CLog::LogF(LOGERROR, "Unable to get 'type' value"); + } + } + else if (settingId == SETTING_TMR_WEEKDAYS) + { + m_iWeekdays = GetWeekdaysFromSetting(setting); + } + else if (settingId == SETTING_TMR_START_ANYTIME) + { + m_bStartAnyTime = std::static_pointer_cast(setting)->GetValue(); + } + else if (settingId == SETTING_TMR_END_ANYTIME) + { + m_bEndAnyTime = std::static_pointer_cast(setting)->GetValue(); + } + else if (settingId == SETTING_TMR_START_DAY) + { + SetDateFromIndex(m_startLocalTime, + std::static_pointer_cast(setting)->GetValue()); + } + else if (settingId == SETTING_TMR_END_DAY) + { + SetDateFromIndex(m_endLocalTime, + std::static_pointer_cast(setting)->GetValue()); + } + else if (settingId == SETTING_TMR_FIRST_DAY) + { + SetDateFromIndex(m_firstDayLocalTime, + std::static_pointer_cast(setting)->GetValue()); + } + else if (settingId == SETTING_TMR_NEW_EPISODES) + { + m_iPreventDupEpisodes = std::static_pointer_cast(setting)->GetValue(); + } + else if (settingId == SETTING_TMR_BEGIN_PRE) + { + m_iMarginStart = std::static_pointer_cast(setting)->GetValue(); + } + else if (settingId == SETTING_TMR_END_POST) + { + m_iMarginEnd = std::static_pointer_cast(setting)->GetValue(); + } + else if (settingId == SETTING_TMR_PRIORITY) + { + m_iPriority = std::static_pointer_cast(setting)->GetValue(); + } + else if (settingId == SETTING_TMR_LIFETIME) + { + m_iLifetime = std::static_pointer_cast(setting)->GetValue(); + } + else if (settingId == SETTING_TMR_MAX_REC) + { + m_iMaxRecordings = std::static_pointer_cast(setting)->GetValue(); + } + else if (settingId == SETTING_TMR_DIR) + { + m_strDirectory = std::static_pointer_cast(setting)->GetValue(); + } + else if (settingId == SETTING_TMR_REC_GROUP) + { + m_iRecordingGroup = std::static_pointer_cast(setting)->GetValue(); + } +} + +void CGUIDialogPVRTimerSettings::OnSettingAction(const std::shared_ptr& setting) +{ + if (setting == NULL) + { + CLog::LogF(LOGERROR, "No setting"); + return; + } + + CGUIDialogSettingsManualBase::OnSettingAction(setting); + + const std::string& settingId = setting->GetId(); + if (settingId == SETTING_TMR_BEGIN) + { + KODI::TIME::SystemTime timerStartTime; + m_startLocalTime.GetAsSystemTime(timerStartTime); + if (CGUIDialogNumeric::ShowAndGetTime(timerStartTime, g_localizeStrings.Get(14066))) + { + SetTimeFromSystemTime(m_startLocalTime, timerStartTime); + m_timerStartTimeStr = m_startLocalTime.GetAsLocalizedTime("", false); + SetButtonLabels(); + } + } + else if (settingId == SETTING_TMR_END) + { + KODI::TIME::SystemTime timerEndTime; + m_endLocalTime.GetAsSystemTime(timerEndTime); + if (CGUIDialogNumeric::ShowAndGetTime(timerEndTime, g_localizeStrings.Get(14066))) + { + SetTimeFromSystemTime(m_endLocalTime, timerEndTime); + m_timerEndTimeStr = m_endLocalTime.GetAsLocalizedTime("", false); + SetButtonLabels(); + } + } +} + +bool CGUIDialogPVRTimerSettings::Validate() +{ + // @todo: Timer rules may have no date (time-only), so we can't check those for now. + // We need to extend the api with additional attributes to properly fix this + if (m_timerType->IsTimerRule()) + return true; + + bool bStartAnyTime = m_bStartAnyTime; + bool bEndAnyTime = m_bEndAnyTime; + + if (!m_timerType->SupportsStartAnyTime() || + !m_timerType->IsEpgBased()) // Start anytime toggle is not displayed + bStartAnyTime = false; // Assume start time change needs checking for + + if (!m_timerType->SupportsEndAnyTime() || + !m_timerType->IsEpgBased()) // End anytime toggle is not displayed + bEndAnyTime = false; // Assume end time change needs checking for + + // Begin and end time + if (!bStartAnyTime && !bEndAnyTime) + { + if (m_timerType->SupportsStartTime() && m_timerType->SupportsEndTime() && + m_endLocalTime < m_startLocalTime) + { + HELPERS::ShowOKDialogText(CVariant{19065}, // "Timer settings" + CVariant{19072}); // In order to add/update a timer + return false; + } + } + + return true; +} + +bool CGUIDialogPVRTimerSettings::Save() +{ + if (!Validate()) + return false; + + // Timer type + m_timerInfoTag->SetTimerType(m_timerType); + + // Timer active/inactive + m_timerInfoTag->m_state = m_bTimerActive ? PVR_TIMER_STATE_SCHEDULED : PVR_TIMER_STATE_DISABLED; + + // Name + m_timerInfoTag->m_strTitle = m_strTitle; + + // epg search string (only for epg-based timer rules) + m_timerInfoTag->m_strEpgSearchString = m_strEpgSearchString; + + // epg fulltext search, instead of just title match. (only for epg-based timer rules) + m_timerInfoTag->m_bFullTextEpgSearch = m_bFullTextEpgSearch; + + // Channel + m_timerInfoTag->m_iClientChannelUid = m_channel.channelUid; + m_timerInfoTag->m_iClientId = m_channel.clientId; + m_timerInfoTag->m_bIsRadio = m_bIsRadio; + m_timerInfoTag->UpdateChannel(); + + if (!m_timerType->SupportsStartAnyTime() || + !m_timerType->IsEpgBased()) // Start anytime toggle is not displayed + m_bStartAnyTime = false; // Assume start time change needs checking for + m_timerInfoTag->m_bStartAnyTime = m_bStartAnyTime; + + if (!m_timerType->SupportsEndAnyTime() || + !m_timerType->IsEpgBased()) // End anytime toggle is not displayed + m_bEndAnyTime = false; // Assume end time change needs checking for + m_timerInfoTag->m_bEndAnyTime = m_bEndAnyTime; + + // Begin and end time + if (!m_bStartAnyTime && !m_bEndAnyTime) + { + if (m_timerType->SupportsStartTime() && // has start clock entry + m_timerType->SupportsEndTime() && // and end clock entry + m_timerType->IsTimerRule()) // but no associated start/end day spinners + { + if (m_endLocalTime < m_startLocalTime) // And the end clock is earlier than the start clock + { + CLog::LogFC(LOGDEBUG, LOGPVR, "End before start, adding a day."); + m_endLocalTime += CDateTimeSpan(1, 0, 0, 0); + if (m_endLocalTime < m_startLocalTime) + { + CLog::Log(LOGWARNING, + "Timer settings dialog: End before start. Setting end time to start time."); + m_endLocalTime = m_startLocalTime; + } + } + else if (m_endLocalTime > + (m_startLocalTime + CDateTimeSpan(1, 0, 0, 0))) // Or the duration is more than a day + { + CLog::LogFC(LOGDEBUG, LOGPVR, "End > 1 day after start, removing a day."); + m_endLocalTime -= CDateTimeSpan(1, 0, 0, 0); + if (m_endLocalTime > (m_startLocalTime + CDateTimeSpan(1, 0, 0, 0))) + { + CLog::Log( + LOGWARNING, + "Timer settings dialog: End > 1 day after start. Setting end time to start time."); + m_endLocalTime = m_startLocalTime; + } + } + } + else if (m_endLocalTime < m_startLocalTime) + { + // this case will fail validation so this can't be reached. + } + m_timerInfoTag->SetStartFromLocalTime(m_startLocalTime); + m_timerInfoTag->SetEndFromLocalTime(m_endLocalTime); + } + else if (!m_bStartAnyTime) + m_timerInfoTag->SetStartFromLocalTime(m_startLocalTime); + else if (!m_bEndAnyTime) + m_timerInfoTag->SetEndFromLocalTime(m_endLocalTime); + + // Days of week (only for timer rules) + if (m_timerType->IsTimerRule()) + m_timerInfoTag->m_iWeekdays = m_iWeekdays; + else + m_timerInfoTag->m_iWeekdays = PVR_WEEKDAY_NONE; + + // First day (only for timer rules) + m_timerInfoTag->SetFirstDayFromLocalTime(m_firstDayLocalTime); + + // "New episodes only" (only for timer rules) + m_timerInfoTag->m_iPreventDupEpisodes = m_iPreventDupEpisodes; + + // Pre and post record time + m_timerInfoTag->m_iMarginStart = m_iMarginStart; + m_timerInfoTag->m_iMarginEnd = m_iMarginEnd; + + // Priority + m_timerInfoTag->m_iPriority = m_iPriority; + + // Lifetime + m_timerInfoTag->m_iLifetime = m_iLifetime; + + // MaxRecordings + m_timerInfoTag->m_iMaxRecordings = m_iMaxRecordings; + + // Recording folder + m_timerInfoTag->m_strDirectory = m_strDirectory; + + // Recording group + m_timerInfoTag->m_iRecordingGroup = m_iRecordingGroup; + + // Set the timer's title to the channel name if it's empty or 'New Timer' + if (m_strTitle.empty() || m_strTitle == g_localizeStrings.Get(19056)) + { + const std::string channelName = m_timerInfoTag->ChannelName(); + if (!channelName.empty()) + m_timerInfoTag->m_strTitle = channelName; + } + + // Update summary + m_timerInfoTag->UpdateSummary(); + + return true; +} + +void CGUIDialogPVRTimerSettings::SetButtonLabels() +{ + // timer start time + BaseSettingControlPtr settingControl = GetSettingControl(SETTING_TMR_BEGIN); + if (settingControl != NULL && settingControl->GetControl() != NULL) + { + SET_CONTROL_LABEL2(settingControl->GetID(), m_timerStartTimeStr); + } + + // timer end time + settingControl = GetSettingControl(SETTING_TMR_END); + if (settingControl != NULL && settingControl->GetControl() != NULL) + { + SET_CONTROL_LABEL2(settingControl->GetID(), m_timerEndTimeStr); + } +} + +void CGUIDialogPVRTimerSettings::AddCondition(const std::shared_ptr& setting, + const std::string& identifier, + SettingConditionCheck condition, + SettingDependencyType depType, + const std::string& settingId) +{ + GetSettingsManager()->AddDynamicCondition(identifier, condition, this); + CSettingDependency dep(depType, GetSettingsManager()); + dep.And()->Add(CSettingDependencyConditionPtr( + new CSettingDependencyCondition(identifier, "true", settingId, false, GetSettingsManager()))); + SettingDependencies deps(setting->GetDependencies()); + deps.push_back(dep); + setting->SetDependencies(deps); +} + +int CGUIDialogPVRTimerSettings::GetDateAsIndex(const CDateTime& datetime) +{ + const CDateTime date(datetime.GetYear(), datetime.GetMonth(), datetime.GetDay(), 0, 0, 0); + time_t t(0); + date.GetAsTime(t); + return static_cast(t); +} + +void CGUIDialogPVRTimerSettings::SetDateFromIndex(CDateTime& datetime, int date) +{ + const CDateTime newDate(static_cast(date)); + datetime.SetDateTime(newDate.GetYear(), newDate.GetMonth(), newDate.GetDay(), datetime.GetHour(), + datetime.GetMinute(), datetime.GetSecond()); +} + +void CGUIDialogPVRTimerSettings::SetTimeFromSystemTime(CDateTime& datetime, + const KODI::TIME::SystemTime& time) +{ + const CDateTime newTime(time); + datetime.SetDateTime(datetime.GetYear(), datetime.GetMonth(), datetime.GetDay(), + newTime.GetHour(), newTime.GetMinute(), newTime.GetSecond()); +} + +void CGUIDialogPVRTimerSettings::InitializeTypesList() +{ + m_typeEntries.clear(); + + // If timer is read-only or was created by a timer rule, only add current type, for information. Type can't be changed. + if (m_timerType->IsReadOnly() || m_timerInfoTag->HasParent()) + { + m_typeEntries.insert(std::make_pair(0, m_timerType)); + return; + } + + bool bFoundThisType(false); + int idx(0); + const std::vector> types(CPVRTimerType::GetAllTypes()); + for (const auto& type : types) + { + // Type definition prohibits created of new instances. + // But the dialog can act as a viewer for these types. + if (type->ForbidsNewInstances()) + continue; + + // Read-only timers cannot be created using this dialog. + // But the dialog can act as a viewer for read-only types. + if (type->IsReadOnly()) + continue; + + // Drop TimerTypes that require EPGInfo, if none is populated + if (type->RequiresEpgTagOnCreate() && !m_timerInfoTag->GetEpgInfoTag()) + continue; + + // Drop TimerTypes without 'Series' EPG attributes if none are set + if (type->RequiresEpgSeriesOnCreate()) + { + const std::shared_ptr epgTag(m_timerInfoTag->GetEpgInfoTag()); + if (epgTag && !epgTag->IsSeries()) + continue; + } + + // Drop TimerTypes which need series link if none is set + if (type->RequiresEpgSeriesLinkOnCreate()) + { + const std::shared_ptr epgTag(m_timerInfoTag->GetEpgInfoTag()); + if (!epgTag || epgTag->SeriesLink().empty()) + continue; + } + + // Drop TimerTypes that forbid EPGInfo, if it is populated + if (type->ForbidsEpgTagOnCreate() && m_timerInfoTag->GetEpgInfoTag()) + continue; + + // Drop TimerTypes that aren't rules and cannot be recorded + if (!type->IsTimerRule()) + { + const std::shared_ptr epgTag(m_timerInfoTag->GetEpgInfoTag()); + bool bCanRecord = epgTag ? epgTag->IsRecordable() + : m_timerInfoTag->EndAsLocalTime() > CDateTime::GetCurrentDateTime(); + if (!bCanRecord) + continue; + } + + if (!bFoundThisType && *type == *m_timerType) + bFoundThisType = true; + + m_typeEntries.insert(std::make_pair(idx++, type)); + } + + if (!bFoundThisType) + m_typeEntries.insert(std::make_pair(idx++, m_timerType)); +} + +void CGUIDialogPVRTimerSettings::InitializeChannelsList() +{ + m_channelEntries.clear(); + + int index = 0; + + // Add special "any channel" entries - one for every client (used for epg-based timer rules). + const CPVRClientMap clients = CServiceBroker::GetPVRManager().Clients()->GetCreatedClients(); + for (const auto& client : clients) + { + m_channelEntries.insert( + {index, ChannelDescriptor(PVR_CHANNEL_INVALID_UID, client.second->GetID(), + g_localizeStrings.Get(809))}); // "Any channel" + ++index; + } + + // Add regular channels + const std::shared_ptr allGroup = + CServiceBroker::GetPVRManager().ChannelGroups()->GetGroupAll(m_bIsRadio); + const std::vector> groupMembers = + allGroup->GetMembers(CPVRChannelGroup::Include::ONLY_VISIBLE); + for (const auto& groupMember : groupMembers) + { + const std::shared_ptr channel = groupMember->Channel(); + const std::string channelDescription = StringUtils::Format( + "{} {}", groupMember->ChannelNumber().FormattedChannelNumber(), channel->ChannelName()); + m_channelEntries.insert( + {index, ChannelDescriptor(channel->UniqueID(), channel->ClientID(), channelDescription)}); + ++index; + } +} + +void CGUIDialogPVRTimerSettings::TypesFiller(const SettingConstPtr& setting, + std::vector& list, + int& current, + void* data) +{ + CGUIDialogPVRTimerSettings* pThis = static_cast(data); + if (pThis) + { + list.clear(); + current = 0; + + static const std::vector> reminderTimerProps{ + std::make_pair("PVR.IsRemindingTimer", CVariant{true})}; + static const std::vector> recordingTimerProps{ + std::make_pair("PVR.IsRecordingTimer", CVariant{true})}; + + const auto clients = CServiceBroker::GetPVRManager().Clients(); + + bool foundCurrent(false); + for (const auto& typeEntry : pThis->m_typeEntries) + { + std::string clientName; + + const auto client = clients->GetCreatedClient(typeEntry.second->GetClientId()); + if (client) + clientName = client->GetFriendlyName(); + + list.emplace_back(typeEntry.second->GetDescription(), clientName, typeEntry.first, + typeEntry.second->IsReminder() ? reminderTimerProps : recordingTimerProps); + + if (!foundCurrent && (*(pThis->m_timerType) == *(typeEntry.second))) + { + current = typeEntry.first; + foundCurrent = true; + } + } + } + else + CLog::LogF(LOGERROR, "No dialog"); +} + +void CGUIDialogPVRTimerSettings::ChannelsFiller(const SettingConstPtr& setting, + std::vector& list, + int& current, + void* data) +{ + CGUIDialogPVRTimerSettings* pThis = static_cast(data); + if (pThis) + { + list.clear(); + current = 0; + + bool foundCurrent(false); + for (const auto& channelEntry : pThis->m_channelEntries) + { + // Only include channels for the currently selected timer type or all channels if type is client-independent. + if (pThis->m_timerType->GetClientId() == -1 || // client-independent + pThis->m_timerType->GetClientId() == channelEntry.second.clientId) + { + // Do not add "any channel" entry if not supported by selected timer type. + if (channelEntry.second.channelUid == PVR_CHANNEL_INVALID_UID && + !pThis->m_timerType->SupportsAnyChannel()) + continue; + + list.emplace_back( + IntegerSettingOption(channelEntry.second.description, channelEntry.first)); + } + + if (!foundCurrent && (pThis->m_channel == channelEntry.second)) + { + current = channelEntry.first; + foundCurrent = true; + } + } + } + else + CLog::LogF(LOGERROR, "No dialog"); +} + +void CGUIDialogPVRTimerSettings::DaysFiller(const SettingConstPtr& setting, + std::vector& list, + int& current, + void* data) +{ + CGUIDialogPVRTimerSettings* pThis = static_cast(data); + if (pThis) + { + list.clear(); + current = 0; + + // Data range: "today" until "yesterday next year" + const CDateTime now(CDateTime::GetCurrentDateTime()); + CDateTime time(now.GetYear(), now.GetMonth(), now.GetDay(), 0, 0, 0); + const CDateTime yesterdayPlusOneYear(CDateTime(time.GetYear() + 1, time.GetMonth(), + time.GetDay(), time.GetHour(), time.GetMinute(), + time.GetSecond()) - + CDateTimeSpan(1, 0, 0, 0)); + + CDateTime oldCDateTime; + if (setting->GetId() == SETTING_TMR_FIRST_DAY) + oldCDateTime = pThis->m_timerInfoTag->FirstDayAsLocalTime(); + else if (setting->GetId() == SETTING_TMR_START_DAY) + oldCDateTime = pThis->m_timerInfoTag->StartAsLocalTime(); + else + oldCDateTime = pThis->m_timerInfoTag->EndAsLocalTime(); + const CDateTime oldCDate(oldCDateTime.GetYear(), oldCDateTime.GetMonth(), oldCDateTime.GetDay(), + 0, 0, 0); + + if ((oldCDate < time) || (oldCDate > yesterdayPlusOneYear)) + list.emplace_back(oldCDate.GetAsLocalizedDate(true /*long date*/), GetDateAsIndex(oldCDate)); + + while (time <= yesterdayPlusOneYear) + { + list.emplace_back(time.GetAsLocalizedDate(true /*long date*/), GetDateAsIndex(time)); + time += CDateTimeSpan(1, 0, 0, 0); + } + + if (setting->GetId() == SETTING_TMR_FIRST_DAY) + current = GetDateAsIndex(pThis->m_firstDayLocalTime); + else if (setting->GetId() == SETTING_TMR_START_DAY) + current = GetDateAsIndex(pThis->m_startLocalTime); + else + current = GetDateAsIndex(pThis->m_endLocalTime); + } + else + CLog::LogF(LOGERROR, "No dialog"); +} + +void CGUIDialogPVRTimerSettings::DupEpisodesFiller(const SettingConstPtr& setting, + std::vector& list, + int& current, + void* data) +{ + CGUIDialogPVRTimerSettings* pThis = static_cast(data); + if (pThis) + { + list.clear(); + + std::vector> values; + pThis->m_timerType->GetPreventDuplicateEpisodesValues(values); + std::transform(values.cbegin(), values.cend(), std::back_inserter(list), [](const auto& value) { + return IntegerSettingOption(value.first, value.second); + }); + + current = pThis->m_iPreventDupEpisodes; + } + else + CLog::LogF(LOGERROR, "No dialog"); +} + +void CGUIDialogPVRTimerSettings::WeekdaysFiller(const SettingConstPtr& setting, + std::vector& list, + int& current, + void* data) +{ + CGUIDialogPVRTimerSettings* pThis = static_cast(data); + if (pThis) + { + list.clear(); + list.emplace_back(g_localizeStrings.Get(831), PVR_WEEKDAY_MONDAY); // "Mondays" + list.emplace_back(g_localizeStrings.Get(832), PVR_WEEKDAY_TUESDAY); // "Tuesdays" + list.emplace_back(g_localizeStrings.Get(833), PVR_WEEKDAY_WEDNESDAY); // "Wednesdays" + list.emplace_back(g_localizeStrings.Get(834), PVR_WEEKDAY_THURSDAY); // "Thursdays" + list.emplace_back(g_localizeStrings.Get(835), PVR_WEEKDAY_FRIDAY); // "Fridays" + list.emplace_back(g_localizeStrings.Get(836), PVR_WEEKDAY_SATURDAY); // "Saturdays" + list.emplace_back(g_localizeStrings.Get(837), PVR_WEEKDAY_SUNDAY); // "Sundays" + + current = pThis->m_iWeekdays; + } + else + CLog::LogF(LOGERROR, "No dialog"); +} + +void CGUIDialogPVRTimerSettings::PrioritiesFiller(const SettingConstPtr& setting, + std::vector& list, + int& current, + void* data) +{ + CGUIDialogPVRTimerSettings* pThis = static_cast(data); + if (pThis) + { + list.clear(); + + std::vector> values; + pThis->m_timerType->GetPriorityValues(values); + std::transform(values.cbegin(), values.cend(), std::back_inserter(list), [](const auto& value) { + return IntegerSettingOption(value.first, value.second); + }); + + current = pThis->m_iPriority; + + auto it = list.begin(); + while (it != list.end()) + { + if (it->value == current) + break; // value already in list + + ++it; + } + + if (it == list.end()) + { + // PVR backend supplied value is not in the list of predefined values. Insert it. + list.insert(it, IntegerSettingOption(std::to_string(current), current)); + } + } + else + CLog::LogF(LOGERROR, "No dialog"); +} + +void CGUIDialogPVRTimerSettings::LifetimesFiller(const SettingConstPtr& setting, + std::vector& list, + int& current, + void* data) +{ + CGUIDialogPVRTimerSettings* pThis = static_cast(data); + if (pThis) + { + list.clear(); + + std::vector> values; + pThis->m_timerType->GetLifetimeValues(values); + std::transform(values.cbegin(), values.cend(), std::back_inserter(list), [](const auto& value) { + return IntegerSettingOption(value.first, value.second); + }); + + current = pThis->m_iLifetime; + + auto it = list.begin(); + while (it != list.end()) + { + if (it->value == current) + break; // value already in list + + ++it; + } + + if (it == list.end()) + { + // PVR backend supplied value is not in the list of predefined values. Insert it. + list.insert(it, IntegerSettingOption( + StringUtils::Format(g_localizeStrings.Get(17999), current) /* {} days */, + current)); + } + } + else + CLog::LogF(LOGERROR, "No dialog"); +} + +void CGUIDialogPVRTimerSettings::MaxRecordingsFiller(const SettingConstPtr& setting, + std::vector& list, + int& current, + void* data) +{ + CGUIDialogPVRTimerSettings* pThis = static_cast(data); + if (pThis) + { + list.clear(); + + std::vector> values; + pThis->m_timerType->GetMaxRecordingsValues(values); + std::transform(values.cbegin(), values.cend(), std::back_inserter(list), [](const auto& value) { + return IntegerSettingOption(value.first, value.second); + }); + + current = pThis->m_iMaxRecordings; + + auto it = list.begin(); + while (it != list.end()) + { + if (it->value == current) + break; // value already in list + + ++it; + } + + if (it == list.end()) + { + // PVR backend supplied value is not in the list of predefined values. Insert it. + list.insert(it, IntegerSettingOption(std::to_string(current), current)); + } + } + else + CLog::LogF(LOGERROR, "No dialog"); +} + +void CGUIDialogPVRTimerSettings::RecordingGroupFiller(const SettingConstPtr& setting, + std::vector& list, + int& current, + void* data) +{ + CGUIDialogPVRTimerSettings* pThis = static_cast(data); + if (pThis) + { + list.clear(); + + std::vector> values; + pThis->m_timerType->GetRecordingGroupValues(values); + std::transform(values.cbegin(), values.cend(), std::back_inserter(list), [](const auto& value) { + return IntegerSettingOption(value.first, value.second); + }); + + current = pThis->m_iRecordingGroup; + } + else + CLog::LogF(LOGERROR, "No dialog"); +} + +void CGUIDialogPVRTimerSettings::MarginTimeFiller(const SettingConstPtr& setting, + std::vector& list, + int& current, + void* data) +{ + CGUIDialogPVRTimerSettings* pThis = static_cast(data); + if (pThis) + { + list.clear(); + + // Get global settings values + CPVRSettings::MarginTimeFiller(setting, list, current, data); + + if (setting->GetId() == SETTING_TMR_BEGIN_PRE) + current = pThis->m_iMarginStart; + else + current = pThis->m_iMarginEnd; + + bool bInsertValue = true; + auto it = list.begin(); + while (it != list.end()) + { + if (it->value == current) + { + bInsertValue = false; + break; // value already in list + } + + if (it->value > current) + break; + + ++it; + } + + if (bInsertValue) + { + // PVR backend supplied value is not in the list of predefined values. Insert it. + list.insert(it, IntegerSettingOption( + StringUtils::Format(g_localizeStrings.Get(14044), current) /* {} min */, + current)); + } + } + else + CLog::LogF(LOGERROR, "No dialog"); +} + +std::string CGUIDialogPVRTimerSettings::WeekdaysValueFormatter(const SettingConstPtr& setting) +{ + return CPVRTimerInfoTag::GetWeekdaysString(GetWeekdaysFromSetting(setting), true, true); +} + +void CGUIDialogPVRTimerSettings::AddTypeDependentEnableCondition( + const std::shared_ptr& setting, const std::string& identifier) +{ + // Enable setting depending on read-only attribute of the selected timer type + std::string id(identifier); + id.append(TYPE_DEP_ENABLE_COND_ID_POSTFIX); + AddCondition(setting, id, TypeReadOnlyCondition, SettingDependencyType::Enable, SETTING_TMR_TYPE); +} + +bool CGUIDialogPVRTimerSettings::TypeReadOnlyCondition(const std::string& condition, + const std::string& value, + const SettingConstPtr& setting, + void* data) +{ + if (setting == NULL) + return false; + + CGUIDialogPVRTimerSettings* pThis = static_cast(data); + if (pThis == NULL) + { + CLog::LogF(LOGERROR, "No dialog"); + return false; + } + + if (!StringUtils::EqualsNoCase(value, "true")) + return false; + + std::string cond(condition); + cond.erase(cond.find(TYPE_DEP_ENABLE_COND_ID_POSTFIX)); + + // If only one type is available, disable type selector. + if (pThis->m_typeEntries.size() == 1) + { + if (cond == SETTING_TMR_TYPE) + return false; + } + + // For existing one time epg-based timers, disable editing of epg-filled data. + if (!pThis->m_bIsNewTimer && pThis->m_timerType->IsEpgBasedOnetime()) + { + if ((cond == SETTING_TMR_NAME) || (cond == SETTING_TMR_CHANNEL) || + (cond == SETTING_TMR_START_DAY) || (cond == SETTING_TMR_END_DAY) || + (cond == SETTING_TMR_BEGIN) || (cond == SETTING_TMR_END)) + return false; + } + + /* Always enable enable/disable, if supported by the timer type. */ + if (pThis->m_timerType->SupportsEnableDisable() && !pThis->m_timerInfoTag->IsBroken()) + { + if (cond == SETTING_TMR_ACTIVE) + return true; + } + + // Let the PVR client decide... + int idx = std::static_pointer_cast(setting)->GetValue(); + const auto entry = pThis->m_typeEntries.find(idx); + if (entry != pThis->m_typeEntries.end()) + return !entry->second->IsReadOnly(); + else + CLog::LogF(LOGERROR, "No type entry"); + + return false; +} + +void CGUIDialogPVRTimerSettings::AddTypeDependentVisibilityCondition( + const std::shared_ptr& setting, const std::string& identifier) +{ + // Show or hide setting depending on attributes of the selected timer type + std::string id(identifier); + id.append(TYPE_DEP_VISIBI_COND_ID_POSTFIX); + AddCondition(setting, id, TypeSupportsCondition, SettingDependencyType::Visible, + SETTING_TMR_TYPE); +} + +bool CGUIDialogPVRTimerSettings::TypeSupportsCondition(const std::string& condition, + const std::string& value, + const SettingConstPtr& setting, + void* data) +{ + if (setting == NULL) + return false; + + CGUIDialogPVRTimerSettings* pThis = static_cast(data); + if (pThis == NULL) + { + CLog::LogF(LOGERROR, "No dialog"); + return false; + } + + if (!StringUtils::EqualsNoCase(value, "true")) + return false; + + int idx = std::static_pointer_cast(setting)->GetValue(); + const auto entry = pThis->m_typeEntries.find(idx); + if (entry != pThis->m_typeEntries.end()) + { + std::string cond(condition); + cond.erase(cond.find(TYPE_DEP_VISIBI_COND_ID_POSTFIX)); + + if (cond == SETTING_TMR_EPGSEARCH) + return entry->second->SupportsEpgTitleMatch() || entry->second->SupportsEpgFulltextMatch(); + else if (cond == SETTING_TMR_FULLTEXT) + return entry->second->SupportsEpgFulltextMatch(); + else if (cond == SETTING_TMR_ACTIVE) + return entry->second->SupportsEnableDisable(); + else if (cond == SETTING_TMR_CHANNEL) + return entry->second->SupportsChannels(); + else if (cond == SETTING_TMR_START_ANYTIME) + return entry->second->SupportsStartAnyTime() && entry->second->IsEpgBased(); + else if (cond == SETTING_TMR_END_ANYTIME) + return entry->second->SupportsEndAnyTime() && entry->second->IsEpgBased(); + else if (cond == SETTING_TMR_START_DAY) + return entry->second->SupportsStartTime() && entry->second->IsOnetime(); + else if (cond == SETTING_TMR_END_DAY) + return entry->second->SupportsEndTime() && entry->second->IsOnetime(); + else if (cond == SETTING_TMR_BEGIN) + return entry->second->SupportsStartTime(); + else if (cond == SETTING_TMR_END) + return entry->second->SupportsEndTime(); + else if (cond == SETTING_TMR_WEEKDAYS) + return entry->second->SupportsWeekdays(); + else if (cond == SETTING_TMR_FIRST_DAY) + return entry->second->SupportsFirstDay(); + else if (cond == SETTING_TMR_NEW_EPISODES) + return entry->second->SupportsRecordOnlyNewEpisodes(); + else if (cond == SETTING_TMR_BEGIN_PRE) + return entry->second->SupportsStartMargin(); + else if (cond == SETTING_TMR_END_POST) + return entry->second->SupportsEndMargin(); + else if (cond == SETTING_TMR_PRIORITY) + return entry->second->SupportsPriority(); + else if (cond == SETTING_TMR_LIFETIME) + return entry->second->SupportsLifetime(); + else if (cond == SETTING_TMR_MAX_REC) + return entry->second->SupportsMaxRecordings(); + else if (cond == SETTING_TMR_DIR) + return entry->second->SupportsRecordingFolders(); + else if (cond == SETTING_TMR_REC_GROUP) + return entry->second->SupportsRecordingGroup(); + else + CLog::LogF(LOGERROR, "Unknown condition"); + } + else + { + CLog::LogF(LOGERROR, "No type entry"); + } + return false; +} + +void CGUIDialogPVRTimerSettings::AddStartAnytimeDependentVisibilityCondition( + const std::shared_ptr& setting, const std::string& identifier) +{ + // Show or hide setting depending on value of setting "any time" + std::string id(identifier); + id.append(START_ANYTIME_DEP_VISIBI_COND_ID_POSTFIX); + AddCondition(setting, id, StartAnytimeSetCondition, SettingDependencyType::Visible, + SETTING_TMR_START_ANYTIME); +} + +bool CGUIDialogPVRTimerSettings::StartAnytimeSetCondition(const std::string& condition, + const std::string& value, + const SettingConstPtr& setting, + void* data) +{ + if (setting == NULL) + return false; + + CGUIDialogPVRTimerSettings* pThis = static_cast(data); + if (pThis == NULL) + { + CLog::LogF(LOGERROR, "No dialog"); + return false; + } + + if (!StringUtils::EqualsNoCase(value, "true")) + return false; + + // "any time" setting is only relevant for epg-based timers. + if (!pThis->m_timerType->IsEpgBased()) + return true; + + // If 'Start anytime' option isn't supported, don't hide start time + if (!pThis->m_timerType->SupportsStartAnyTime()) + return true; + + std::string cond(condition); + cond.erase(cond.find(START_ANYTIME_DEP_VISIBI_COND_ID_POSTFIX)); + + if ((cond == SETTING_TMR_START_DAY) || (cond == SETTING_TMR_BEGIN)) + { + bool bAnytime = std::static_pointer_cast(setting)->GetValue(); + return !bAnytime; + } + return false; +} + +void CGUIDialogPVRTimerSettings::AddEndAnytimeDependentVisibilityCondition( + const std::shared_ptr& setting, const std::string& identifier) +{ + // Show or hide setting depending on value of setting "any time" + std::string id(identifier); + id.append(END_ANYTIME_DEP_VISIBI_COND_ID_POSTFIX); + AddCondition(setting, id, EndAnytimeSetCondition, SettingDependencyType::Visible, + SETTING_TMR_END_ANYTIME); +} + +bool CGUIDialogPVRTimerSettings::EndAnytimeSetCondition(const std::string& condition, + const std::string& value, + const SettingConstPtr& setting, + void* data) +{ + if (setting == NULL) + return false; + + CGUIDialogPVRTimerSettings* pThis = static_cast(data); + if (pThis == NULL) + { + CLog::LogF(LOGERROR, "No dialog"); + return false; + } + + if (!StringUtils::EqualsNoCase(value, "true")) + return false; + + // "any time" setting is only relevant for epg-based timers. + if (!pThis->m_timerType->IsEpgBased()) + return true; + + // If 'End anytime' option isn't supported, don't hide end time + if (!pThis->m_timerType->SupportsEndAnyTime()) + return true; + + std::string cond(condition); + cond.erase(cond.find(END_ANYTIME_DEP_VISIBI_COND_ID_POSTFIX)); + + if ((cond == SETTING_TMR_END_DAY) || (cond == SETTING_TMR_END)) + { + bool bAnytime = std::static_pointer_cast(setting)->GetValue(); + return !bAnytime; + } + return false; +} -- cgit v1.2.3