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 "GUIDialogPVRTimerSettings.h"
11 #include "ServiceBroker.h"
12 #include "dialogs/GUIDialogNumeric.h"
13 #include "guilib/GUIMessage.h"
14 #include "guilib/LocalizeStrings.h"
15 #include "messaging/helpers/DialogOKHelper.h"
16 #include "pvr/PVRConstants.h" // PVR_CLIENT_INVALID_UID
17 #include "pvr/PVRManager.h"
18 #include "pvr/addons/PVRClient.h"
19 #include "pvr/addons/PVRClients.h"
20 #include "pvr/channels/PVRChannel.h"
21 #include "pvr/channels/PVRChannelGroup.h"
22 #include "pvr/channels/PVRChannelGroupMember.h"
23 #include "pvr/channels/PVRChannelGroupsContainer.h"
24 #include "pvr/epg/EpgInfoTag.h"
25 #include "pvr/settings/PVRCustomTimerSettings.h"
26 #include "pvr/timers/PVRTimerInfoTag.h"
27 #include "pvr/timers/PVRTimerType.h"
28 #include "settings/SettingUtils.h"
29 #include "settings/dialogs/GUIDialogSettingsBase.h"
30 #include "settings/lib/Setting.h"
31 #include "settings/lib/SettingsManager.h"
32 #include "settings/windows/GUIControlSettings.h"
33 #include "utils/StringUtils.h"
34 #include "utils/Variant.h"
35 #include "utils/log.h"
45 using namespace KODI::MESSAGING
;
47 #define SETTING_TMR_TYPE "timer.type"
48 #define SETTING_TMR_ACTIVE "timer.active"
49 #define SETTING_TMR_NAME "timer.name"
50 #define SETTING_TMR_EPGSEARCH "timer.epgsearch"
51 #define SETTING_TMR_FULLTEXT "timer.fulltext"
52 #define SETTING_TMR_CHANNEL "timer.channel"
53 #define SETTING_TMR_START_ANYTIME "timer.startanytime"
54 #define SETTING_TMR_END_ANYTIME "timer.endanytime"
55 #define SETTING_TMR_START_DAY "timer.startday"
56 #define SETTING_TMR_END_DAY "timer.endday"
57 #define SETTING_TMR_BEGIN "timer.begin"
58 #define SETTING_TMR_END "timer.end"
59 #define SETTING_TMR_WEEKDAYS "timer.weekdays"
60 #define SETTING_TMR_FIRST_DAY "timer.firstday"
61 #define SETTING_TMR_NEW_EPISODES "timer.newepisodes"
62 #define SETTING_TMR_BEGIN_PRE "timer.startmargin"
63 #define SETTING_TMR_END_POST "timer.endmargin"
64 #define SETTING_TMR_PRIORITY "timer.priority"
65 #define SETTING_TMR_LIFETIME "timer.lifetime"
66 #define SETTING_TMR_MAX_REC "timer.maxrecordings"
67 #define SETTING_TMR_DIR "timer.directory"
68 #define SETTING_TMR_REC_GROUP "timer.recgroup"
70 #define TYPE_DEP_VISIBI_COND_ID_POSTFIX "visibi.typedep"
71 #define TYPE_DEP_ENABLE_COND_ID_POSTFIX "enable.typedep"
72 #define CHANNEL_DEP_VISIBI_COND_ID_POSTFIX "visibi.channeldep"
73 #define START_ANYTIME_DEP_VISIBI_COND_ID_POSTFIX "visibi.startanytimedep"
74 #define END_ANYTIME_DEP_VISIBI_COND_ID_POSTFIX "visibi.endanytimedep"
76 CGUIDialogPVRTimerSettings::CGUIDialogPVRTimerSettings()
77 : CGUIDialogSettingsManualBase(WINDOW_DIALOG_PVR_TIMER_SETTING
, "DialogSettings.xml"),
78 m_iWeekdays(PVR_WEEKDAY_NONE
)
80 m_loadType
= LOAD_EVERY_TIME
;
83 CGUIDialogPVRTimerSettings::~CGUIDialogPVRTimerSettings() = default;
85 bool CGUIDialogPVRTimerSettings::CanBeActivated() const
89 CLog::LogF(LOGERROR
, "No timer info tag");
95 void CGUIDialogPVRTimerSettings::SetTimer(const std::shared_ptr
<CPVRTimerInfoTag
>& timer
)
99 CLog::LogF(LOGERROR
, "No timer given");
103 m_timerInfoTag
= timer
;
105 // Copy data we need from tag. Do not modify the tag itself until Save()!
106 m_timerType
= m_timerInfoTag
->GetTimerType();
107 m_bIsRadio
= m_timerInfoTag
->m_bIsRadio
;
108 m_bIsNewTimer
= m_timerInfoTag
->m_iClientIndex
== PVR_TIMER_NO_CLIENT_INDEX
;
109 m_bTimerActive
= m_bIsNewTimer
|| !m_timerType
->SupportsEnableDisable() ||
110 !(m_timerInfoTag
->m_state
== PVR_TIMER_STATE_DISABLED
);
112 m_bIsNewTimer
|| !m_timerType
->SupportsStartAnyTime() || m_timerInfoTag
->m_bStartAnyTime
;
114 m_bIsNewTimer
|| !m_timerType
->SupportsEndAnyTime() || m_timerInfoTag
->m_bEndAnyTime
;
115 m_strTitle
= m_timerInfoTag
->m_strTitle
;
117 m_startLocalTime
= m_timerInfoTag
->StartAsLocalTime();
118 m_endLocalTime
= m_timerInfoTag
->EndAsLocalTime();
120 m_timerStartTimeStr
= m_startLocalTime
.GetAsLocalizedTime("", false);
121 m_timerEndTimeStr
= m_endLocalTime
.GetAsLocalizedTime("", false);
122 m_firstDayLocalTime
= m_timerInfoTag
->FirstDayAsLocalTime();
124 m_strEpgSearchString
= m_timerInfoTag
->m_strEpgSearchString
;
125 if (!m_bIsNewTimer
&& m_strEpgSearchString
.empty())
126 m_strEpgSearchString
= m_strTitle
;
128 m_bFullTextEpgSearch
= m_timerInfoTag
->m_bFullTextEpgSearch
;
130 m_iWeekdays
= m_timerInfoTag
->m_iWeekdays
;
131 if ((m_bIsNewTimer
|| !m_timerType
->SupportsWeekdays()) && m_iWeekdays
== PVR_WEEKDAY_NONE
)
132 m_iWeekdays
= PVR_WEEKDAY_ALLDAYS
;
134 m_iPreventDupEpisodes
= m_timerInfoTag
->m_iPreventDupEpisodes
;
135 m_iMarginStart
= m_timerInfoTag
->m_iMarginStart
;
136 m_iMarginEnd
= m_timerInfoTag
->m_iMarginEnd
;
137 m_iPriority
= m_timerInfoTag
->m_iPriority
;
138 m_iLifetime
= m_timerInfoTag
->m_iLifetime
;
139 m_iMaxRecordings
= m_timerInfoTag
->m_iMaxRecordings
;
141 if (m_bIsNewTimer
&& m_timerInfoTag
->m_strDirectory
.empty() &&
142 m_timerType
->SupportsRecordingFolders())
143 m_strDirectory
= m_strTitle
;
145 m_strDirectory
= m_timerInfoTag
->m_strDirectory
;
147 m_iRecordingGroup
= m_timerInfoTag
->m_iRecordingGroup
;
149 InitializeChannelsList();
150 InitializeTypesList();
152 m_customTimerSettings
= std::make_unique
<CPVRCustomTimerSettings
>(
153 *m_timerType
, m_timerInfoTag
->m_customProps
, m_typeEntries
);
156 m_channel
= ChannelDescriptor();
158 if (m_timerInfoTag
->m_iClientChannelUid
== PVR_CHANNEL_INVALID_UID
)
160 if (m_timerType
->SupportsAnyChannel())
162 // Select first matching "Any channel" entry.
163 const auto it
= std::find_if(m_channelEntries
.cbegin(), m_channelEntries
.cend(),
164 [this](const auto& channel
) {
165 return channel
.second
.channelUid
== PVR_CHANNEL_INVALID_UID
&&
166 channel
.second
.clientId
== m_timerInfoTag
->m_iClientId
;
169 if (it
!= m_channelEntries
.cend())
171 m_channel
= (*it
).second
;
175 CLog::LogF(LOGERROR
, "Unable to map PVR_CHANNEL_INVALID_UID to channel entry!");
178 else if (m_bIsNewTimer
)
180 // Select first matching regular (not "Any channel") entry.
181 const auto it
= std::find_if(m_channelEntries
.cbegin(), m_channelEntries
.cend(),
182 [this](const auto& channel
) {
183 return channel
.second
.channelUid
!= PVR_CHANNEL_INVALID_UID
&&
184 channel
.second
.clientId
== m_timerInfoTag
->m_iClientId
;
187 if (it
!= m_channelEntries
.cend())
189 m_channel
= (*it
).second
;
193 CLog::LogF(LOGERROR
, "Unable to map PVR_CHANNEL_INVALID_UID to channel entry!");
199 // Find matching channel entry
200 const auto it
= std::find_if(
201 m_channelEntries
.cbegin(), m_channelEntries
.cend(), [this](const auto& channel
) {
202 return channel
.second
.channelUid
== m_timerInfoTag
->m_iClientChannelUid
&&
203 channel
.second
.clientId
== m_timerInfoTag
->m_iClientId
;
206 if (it
!= m_channelEntries
.cend())
208 m_channel
= (*it
).second
;
212 CLog::LogF(LOGERROR
, "Unable to map channel uid to channel entry!");
217 void CGUIDialogPVRTimerSettings::SetupView()
219 CGUIDialogSettingsManualBase::SetupView();
221 SET_CONTROL_HIDDEN(CONTROL_SETTINGS_CUSTOM_BUTTON
);
222 SET_CONTROL_LABEL(CONTROL_SETTINGS_OKAY_BUTTON
, 186);
223 SET_CONTROL_LABEL(CONTROL_SETTINGS_CANCEL_BUTTON
, 222);
227 void CGUIDialogPVRTimerSettings::InitializeSettings()
229 CGUIDialogSettingsManualBase::InitializeSettings();
231 const std::shared_ptr
<CSettingCategory
> category
= AddCategory("pvrtimersettings", -1);
232 if (category
== NULL
)
234 CLog::LogF(LOGERROR
, "Unable to add settings category");
238 const std::shared_ptr
<CSettingGroup
> group
= AddGroup(category
);
241 CLog::LogF(LOGERROR
, "Unable to add settings group");
245 std::shared_ptr
<CSetting
> setting
= NULL
;
248 bool useDetails
= false;
249 bool foundClientSupportingTimers
= false;
251 const CPVRClientMap clients
= CServiceBroker::GetPVRManager().Clients()->GetCreatedClients();
252 for (const auto& client
: clients
)
254 if (client
.second
->GetClientCapabilities().SupportsTimers())
256 if (foundClientSupportingTimers
)
258 // found second client supporting timers, use detailed timer type list layout
262 foundClientSupportingTimers
= true;
266 setting
= AddList(group
, SETTING_TMR_TYPE
, 803, SettingLevel::Basic
, 0, TypesFiller
, 803, true,
268 AddTypeDependentEnableCondition(setting
, SETTING_TMR_TYPE
);
270 // Timer enabled/disabled
271 setting
= AddToggle(group
, SETTING_TMR_ACTIVE
, 305, SettingLevel::Basic
, m_bTimerActive
);
272 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_ACTIVE
);
273 AddTypeDependentEnableCondition(setting
, SETTING_TMR_ACTIVE
);
277 AddEdit(group
, SETTING_TMR_NAME
, 19075, SettingLevel::Basic
, m_strTitle
, true, false, 19097);
278 AddTypeDependentEnableCondition(setting
, SETTING_TMR_NAME
);
280 // epg search string (only for epg-based timer rules)
281 setting
= AddEdit(group
, SETTING_TMR_EPGSEARCH
, 804, SettingLevel::Basic
, m_strEpgSearchString
,
283 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_EPGSEARCH
);
284 AddTypeDependentEnableCondition(setting
, SETTING_TMR_EPGSEARCH
);
286 // epg fulltext search (only for epg-based timer rules)
287 setting
= AddToggle(group
, SETTING_TMR_FULLTEXT
, 806, SettingLevel::Basic
, m_bFullTextEpgSearch
);
288 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_FULLTEXT
);
289 AddTypeDependentEnableCondition(setting
, SETTING_TMR_FULLTEXT
);
293 AddList(group
, SETTING_TMR_CHANNEL
, 19078, SettingLevel::Basic
, 0, ChannelsFiller
, 19078);
294 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_CHANNEL
);
295 AddTypeDependentEnableCondition(setting
, SETTING_TMR_CHANNEL
);
297 // Days of week (only for timer rules)
298 std::vector
<int> weekdaysPreselect
;
299 if (m_iWeekdays
& PVR_WEEKDAY_MONDAY
)
300 weekdaysPreselect
.push_back(PVR_WEEKDAY_MONDAY
);
301 if (m_iWeekdays
& PVR_WEEKDAY_TUESDAY
)
302 weekdaysPreselect
.push_back(PVR_WEEKDAY_TUESDAY
);
303 if (m_iWeekdays
& PVR_WEEKDAY_WEDNESDAY
)
304 weekdaysPreselect
.push_back(PVR_WEEKDAY_WEDNESDAY
);
305 if (m_iWeekdays
& PVR_WEEKDAY_THURSDAY
)
306 weekdaysPreselect
.push_back(PVR_WEEKDAY_THURSDAY
);
307 if (m_iWeekdays
& PVR_WEEKDAY_FRIDAY
)
308 weekdaysPreselect
.push_back(PVR_WEEKDAY_FRIDAY
);
309 if (m_iWeekdays
& PVR_WEEKDAY_SATURDAY
)
310 weekdaysPreselect
.push_back(PVR_WEEKDAY_SATURDAY
);
311 if (m_iWeekdays
& PVR_WEEKDAY_SUNDAY
)
312 weekdaysPreselect
.push_back(PVR_WEEKDAY_SUNDAY
);
314 setting
= AddList(group
, SETTING_TMR_WEEKDAYS
, 19079, SettingLevel::Basic
, weekdaysPreselect
,
315 WeekdaysFiller
, 19079, 1, -1, true, -1, WeekdaysValueFormatter
);
316 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_WEEKDAYS
);
317 AddTypeDependentEnableCondition(setting
, SETTING_TMR_WEEKDAYS
);
319 // "Start any time" (only for timer rules)
320 setting
= AddToggle(group
, SETTING_TMR_START_ANYTIME
, 810, SettingLevel::Basic
, m_bStartAnyTime
);
321 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_START_ANYTIME
);
322 AddTypeDependentEnableCondition(setting
, SETTING_TMR_START_ANYTIME
);
324 // Start day (day + month + year only, no hours, minutes)
325 setting
= AddSpinner(group
, SETTING_TMR_START_DAY
, 19128, SettingLevel::Basic
,
326 GetDateAsIndex(m_startLocalTime
), DaysFiller
);
327 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_START_DAY
);
328 AddTypeDependentEnableCondition(setting
, SETTING_TMR_START_DAY
);
329 AddStartAnytimeDependentVisibilityCondition(setting
, SETTING_TMR_START_DAY
);
331 // Start time (hours + minutes only, no day, month, year)
332 setting
= AddButton(group
, SETTING_TMR_BEGIN
, 19126, SettingLevel::Basic
);
333 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_BEGIN
);
334 AddTypeDependentEnableCondition(setting
, SETTING_TMR_BEGIN
);
335 AddStartAnytimeDependentVisibilityCondition(setting
, SETTING_TMR_BEGIN
);
337 // "End any time" (only for timer rules)
338 setting
= AddToggle(group
, SETTING_TMR_END_ANYTIME
, 817, SettingLevel::Basic
, m_bEndAnyTime
);
339 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_END_ANYTIME
);
340 AddTypeDependentEnableCondition(setting
, SETTING_TMR_END_ANYTIME
);
342 // End day (day + month + year only, no hours, minutes)
343 setting
= AddSpinner(group
, SETTING_TMR_END_DAY
, 19129, SettingLevel::Basic
,
344 GetDateAsIndex(m_endLocalTime
), DaysFiller
);
345 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_END_DAY
);
346 AddTypeDependentEnableCondition(setting
, SETTING_TMR_END_DAY
);
347 AddEndAnytimeDependentVisibilityCondition(setting
, SETTING_TMR_END_DAY
);
349 // End time (hours + minutes only, no day, month, year)
350 setting
= AddButton(group
, SETTING_TMR_END
, 19127, SettingLevel::Basic
);
351 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_END
);
352 AddTypeDependentEnableCondition(setting
, SETTING_TMR_END
);
353 AddEndAnytimeDependentVisibilityCondition(setting
, SETTING_TMR_END
);
355 // First day (only for timer rules)
356 setting
= AddSpinner(group
, SETTING_TMR_FIRST_DAY
, 19084, SettingLevel::Basic
,
357 GetDateAsIndex(m_firstDayLocalTime
), DaysFiller
);
358 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_FIRST_DAY
);
359 AddTypeDependentEnableCondition(setting
, SETTING_TMR_FIRST_DAY
);
361 // "Prevent duplicate episodes" (only for timer rules)
362 setting
= AddList(group
, SETTING_TMR_NEW_EPISODES
, 812, SettingLevel::Basic
,
363 m_iPreventDupEpisodes
, DupEpisodesFiller
, 812);
364 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_NEW_EPISODES
);
365 AddTypeDependentEnableCondition(setting
, SETTING_TMR_NEW_EPISODES
);
367 // Pre and post record time
368 setting
= AddList(group
, SETTING_TMR_BEGIN_PRE
, 813, SettingLevel::Basic
, m_iMarginStart
,
369 MarginTimeFiller
, 813);
370 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_BEGIN_PRE
);
371 AddTypeDependentEnableCondition(setting
, SETTING_TMR_BEGIN_PRE
);
373 setting
= AddList(group
, SETTING_TMR_END_POST
, 814, SettingLevel::Basic
, m_iMarginEnd
,
374 MarginTimeFiller
, 814);
375 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_END_POST
);
376 AddTypeDependentEnableCondition(setting
, SETTING_TMR_END_POST
);
379 setting
= AddList(group
, SETTING_TMR_PRIORITY
, 19082, SettingLevel::Basic
, m_iPriority
,
380 PrioritiesFiller
, 19082);
381 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_PRIORITY
);
382 AddTypeDependentEnableCondition(setting
, SETTING_TMR_PRIORITY
);
385 setting
= AddList(group
, SETTING_TMR_LIFETIME
, 19083, SettingLevel::Basic
, m_iLifetime
,
386 LifetimesFiller
, 19083);
387 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_LIFETIME
);
388 AddTypeDependentEnableCondition(setting
, SETTING_TMR_LIFETIME
);
391 setting
= AddList(group
, SETTING_TMR_MAX_REC
, 818, SettingLevel::Basic
, m_iMaxRecordings
,
392 MaxRecordingsFiller
, 818);
393 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_MAX_REC
);
394 AddTypeDependentEnableCondition(setting
, SETTING_TMR_MAX_REC
);
397 setting
= AddEdit(group
, SETTING_TMR_DIR
, 19076, SettingLevel::Basic
, m_strDirectory
, true, false,
399 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_DIR
);
400 AddTypeDependentEnableCondition(setting
, SETTING_TMR_DIR
);
403 setting
= AddList(group
, SETTING_TMR_REC_GROUP
, 811, SettingLevel::Basic
, m_iRecordingGroup
,
404 RecordingGroupFiller
, 811);
405 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_REC_GROUP
);
406 AddTypeDependentEnableCondition(setting
, SETTING_TMR_REC_GROUP
);
408 // Add-on supplied custom settings
409 m_customTimerSettings
->AddSettings(*this, group
);
412 void CGUIDialogPVRTimerSettings::AddMultiIntSetting(const std::shared_ptr
<CSettingGroup
>& group
,
413 const std::string
& settingName
,
416 const std::shared_ptr
<CSetting
> setting
{AddList(group
, settingName
, 16028, SettingLevel::Basic
,
417 settingValue
, CustomIntSettingDefinitionsFiller
,
419 AddTypeDependentVisibilityCondition(setting
, settingName
);
420 AddTypeDependentEnableCondition(setting
, settingName
);
423 void CGUIDialogPVRTimerSettings::AddSingleIntSetting(const std::shared_ptr
<CSettingGroup
>& group
,
424 const std::string
& settingName
,
430 const std::shared_ptr
<CSetting
> setting
{AddEdit(group
, settingName
, 16028, SettingLevel::Basic
,
431 settingValue
, minValue
, step
, maxValue
)};
432 AddTypeDependentVisibilityCondition(setting
, settingName
);
433 AddTypeDependentEnableCondition(setting
, settingName
);
436 void CGUIDialogPVRTimerSettings::AddMultiStringSetting(const std::shared_ptr
<CSettingGroup
>& group
,
437 const std::string
& settingName
,
438 const std::string
& settingValue
)
440 const std::shared_ptr
<CSetting
> setting
{AddList(group
, settingName
, 16028, SettingLevel::Basic
,
442 CustomStringSettingDefinitionsFiller
, 16028)};
443 AddTypeDependentVisibilityCondition(setting
, settingName
);
444 AddTypeDependentEnableCondition(setting
, settingName
);
447 void CGUIDialogPVRTimerSettings::AddSingleStringSetting(const std::shared_ptr
<CSettingGroup
>& group
,
448 const std::string
& settingName
,
449 const std::string
& settingValue
,
450 bool allowEmptyValue
)
452 const std::shared_ptr
<CSetting
> setting
{
453 AddEdit(group
, settingName
, 16028, SettingLevel::Basic
, settingValue
, allowEmptyValue
)};
454 AddTypeDependentVisibilityCondition(setting
, settingName
);
455 AddTypeDependentEnableCondition(setting
, settingName
);
458 int CGUIDialogPVRTimerSettings::GetWeekdaysFromSetting(const SettingConstPtr
& setting
)
460 std::shared_ptr
<const CSettingList
> settingList
=
461 std::static_pointer_cast
<const CSettingList
>(setting
);
462 if (settingList
->GetElementType() != SettingType::Integer
)
464 CLog::LogF(LOGERROR
, "Wrong weekdays element type");
468 std::vector
<CVariant
> list
= CSettingUtils::GetList(settingList
);
469 for (const auto& value
: list
)
471 if (!value
.isInteger())
473 CLog::LogF(LOGERROR
, "Wrong weekdays value type");
476 weekdays
+= static_cast<int>(value
.asInteger());
482 void CGUIDialogPVRTimerSettings::OnSettingChanged(const std::shared_ptr
<const CSetting
>& setting
)
486 CLog::LogF(LOGERROR
, "No setting");
490 CGUIDialogSettingsManualBase::OnSettingChanged(setting
);
492 const std::string
& settingId
= setting
->GetId();
494 if (settingId
== SETTING_TMR_TYPE
)
496 int idx
= std::static_pointer_cast
<const CSettingInt
>(setting
)->GetValue();
497 const auto it
= m_typeEntries
.find(idx
);
498 if (it
!= m_typeEntries
.end())
500 m_timerType
= it
->second
;
501 m_customTimerSettings
->SetTimerType(*m_timerType
);
503 // reset certain settings to the defaults of the new timer type
505 if (m_timerType
->SupportsPriority())
506 m_iPriority
= m_timerType
->GetPriorityDefault();
508 if (m_timerType
->SupportsLifetime())
509 m_iLifetime
= m_timerType
->GetLifetimeDefault();
511 if (m_timerType
->SupportsMaxRecordings())
512 m_iMaxRecordings
= m_timerType
->GetMaxRecordingsDefault();
514 if (m_timerType
->SupportsRecordingGroup())
515 m_iRecordingGroup
= m_timerType
->GetRecordingGroupDefault();
517 if (m_timerType
->SupportsRecordOnlyNewEpisodes())
518 m_iPreventDupEpisodes
= m_timerType
->GetPreventDuplicateEpisodesDefault();
520 if (m_timerType
->IsTimerRule() && (m_iWeekdays
== PVR_WEEKDAY_ALLDAYS
))
521 SetButtonLabels(); // update "Any day" vs. "Every day"
525 CLog::LogF(LOGERROR
, "Unable to get 'type' value");
528 else if (settingId
== SETTING_TMR_ACTIVE
)
530 m_bTimerActive
= std::static_pointer_cast
<const CSettingBool
>(setting
)->GetValue();
532 else if (settingId
== SETTING_TMR_NAME
)
534 m_strTitle
= std::static_pointer_cast
<const CSettingString
>(setting
)->GetValue();
536 else if (settingId
== SETTING_TMR_EPGSEARCH
)
538 m_strEpgSearchString
= std::static_pointer_cast
<const CSettingString
>(setting
)->GetValue();
540 else if (settingId
== SETTING_TMR_FULLTEXT
)
542 m_bFullTextEpgSearch
= std::static_pointer_cast
<const CSettingBool
>(setting
)->GetValue();
544 else if (settingId
== SETTING_TMR_CHANNEL
)
546 int idx
= std::static_pointer_cast
<const CSettingInt
>(setting
)->GetValue();
547 const auto it
= m_channelEntries
.find(idx
);
548 if (it
!= m_channelEntries
.end())
550 m_channel
= it
->second
;
554 CLog::LogF(LOGERROR
, "Unable to get 'type' value");
557 else if (settingId
== SETTING_TMR_WEEKDAYS
)
559 m_iWeekdays
= GetWeekdaysFromSetting(setting
);
561 else if (settingId
== SETTING_TMR_START_ANYTIME
)
563 m_bStartAnyTime
= std::static_pointer_cast
<const CSettingBool
>(setting
)->GetValue();
565 else if (settingId
== SETTING_TMR_END_ANYTIME
)
567 m_bEndAnyTime
= std::static_pointer_cast
<const CSettingBool
>(setting
)->GetValue();
569 else if (settingId
== SETTING_TMR_START_DAY
)
571 SetDateFromIndex(m_startLocalTime
,
572 std::static_pointer_cast
<const CSettingInt
>(setting
)->GetValue());
574 else if (settingId
== SETTING_TMR_END_DAY
)
576 SetDateFromIndex(m_endLocalTime
,
577 std::static_pointer_cast
<const CSettingInt
>(setting
)->GetValue());
579 else if (settingId
== SETTING_TMR_FIRST_DAY
)
581 SetDateFromIndex(m_firstDayLocalTime
,
582 std::static_pointer_cast
<const CSettingInt
>(setting
)->GetValue());
584 else if (settingId
== SETTING_TMR_NEW_EPISODES
)
586 m_iPreventDupEpisodes
= std::static_pointer_cast
<const CSettingInt
>(setting
)->GetValue();
588 else if (settingId
== SETTING_TMR_BEGIN_PRE
)
590 m_iMarginStart
= std::static_pointer_cast
<const CSettingInt
>(setting
)->GetValue();
592 else if (settingId
== SETTING_TMR_END_POST
)
594 m_iMarginEnd
= std::static_pointer_cast
<const CSettingInt
>(setting
)->GetValue();
596 else if (settingId
== SETTING_TMR_PRIORITY
)
598 m_iPriority
= std::static_pointer_cast
<const CSettingInt
>(setting
)->GetValue();
600 else if (settingId
== SETTING_TMR_LIFETIME
)
602 m_iLifetime
= std::static_pointer_cast
<const CSettingInt
>(setting
)->GetValue();
604 else if (settingId
== SETTING_TMR_MAX_REC
)
606 m_iMaxRecordings
= std::static_pointer_cast
<const CSettingInt
>(setting
)->GetValue();
608 else if (settingId
== SETTING_TMR_DIR
)
610 m_strDirectory
= std::static_pointer_cast
<const CSettingString
>(setting
)->GetValue();
612 else if (settingId
== SETTING_TMR_REC_GROUP
)
614 m_iRecordingGroup
= std::static_pointer_cast
<const CSettingInt
>(setting
)->GetValue();
616 else if (m_customTimerSettings
->IsCustomIntSetting(settingId
))
618 m_customTimerSettings
->UpdateIntProperty(setting
);
620 else if (m_customTimerSettings
->IsCustomStringSetting(settingId
))
622 m_customTimerSettings
->UpdateStringProperty(setting
);
626 void CGUIDialogPVRTimerSettings::OnSettingAction(const std::shared_ptr
<const CSetting
>& setting
)
630 CLog::LogF(LOGERROR
, "No setting");
634 CGUIDialogSettingsManualBase::OnSettingAction(setting
);
636 const std::string
& settingId
= setting
->GetId();
637 if (settingId
== SETTING_TMR_BEGIN
)
639 KODI::TIME::SystemTime timerStartTime
;
640 m_startLocalTime
.GetAsSystemTime(timerStartTime
);
641 if (CGUIDialogNumeric::ShowAndGetTime(timerStartTime
, g_localizeStrings
.Get(14066)))
643 SetTimeFromSystemTime(m_startLocalTime
, timerStartTime
);
644 m_timerStartTimeStr
= m_startLocalTime
.GetAsLocalizedTime("", false);
648 else if (settingId
== SETTING_TMR_END
)
650 KODI::TIME::SystemTime timerEndTime
;
651 m_endLocalTime
.GetAsSystemTime(timerEndTime
);
652 if (CGUIDialogNumeric::ShowAndGetTime(timerEndTime
, g_localizeStrings
.Get(14066)))
654 SetTimeFromSystemTime(m_endLocalTime
, timerEndTime
);
655 m_timerEndTimeStr
= m_endLocalTime
.GetAsLocalizedTime("", false);
661 bool CGUIDialogPVRTimerSettings::Validate()
663 // @todo: Timer rules may have no date (time-only), so we can't check those for now.
664 // We need to extend the api with additional attributes to properly fix this
665 if (m_timerType
->IsTimerRule())
668 bool bStartAnyTime
= m_bStartAnyTime
;
669 bool bEndAnyTime
= m_bEndAnyTime
;
671 if (!m_timerType
->SupportsStartAnyTime() ||
672 !m_timerType
->IsEpgBased()) // Start anytime toggle is not displayed
673 bStartAnyTime
= false; // Assume start time change needs checking for
675 if (!m_timerType
->SupportsEndAnyTime() ||
676 !m_timerType
->IsEpgBased()) // End anytime toggle is not displayed
677 bEndAnyTime
= false; // Assume end time change needs checking for
679 // Begin and end time
680 if (!bStartAnyTime
&& !bEndAnyTime
)
682 if (m_timerType
->SupportsStartTime() && m_timerType
->SupportsEndTime() &&
683 m_endLocalTime
< m_startLocalTime
)
685 HELPERS::ShowOKDialogText(CVariant
{19065}, // "Timer settings"
686 CVariant
{19072}); // In order to add/update a timer
694 std::string
CGUIDialogPVRTimerSettings::GetSettingsLabel(const std::shared_ptr
<ISetting
>& setting
)
696 // Special handling for add-on supplied custom settings.
697 const std::string label
{m_customTimerSettings
->GetSettingsLabel(setting
->GetId())};
701 return CGUIDialogSettingsManualBase::GetSettingsLabel(setting
);
704 bool CGUIDialogPVRTimerSettings::Save()
710 m_timerInfoTag
->SetTimerType(m_timerType
);
712 // Timer active/inactive
713 m_timerInfoTag
->m_state
= m_bTimerActive
? PVR_TIMER_STATE_SCHEDULED
: PVR_TIMER_STATE_DISABLED
;
716 m_timerInfoTag
->m_strTitle
= m_strTitle
;
718 // epg search string (only for epg-based timer rules)
719 m_timerInfoTag
->m_strEpgSearchString
= m_strEpgSearchString
;
721 // epg fulltext search, instead of just title match. (only for epg-based timer rules)
722 m_timerInfoTag
->m_bFullTextEpgSearch
= m_bFullTextEpgSearch
;
725 m_timerInfoTag
->m_iClientChannelUid
= m_channel
.channelUid
;
726 m_timerInfoTag
->m_iClientId
= m_channel
.clientId
;
727 m_timerInfoTag
->m_bIsRadio
= m_bIsRadio
;
728 m_timerInfoTag
->UpdateChannel();
730 if (!m_timerType
->SupportsStartAnyTime() ||
731 !m_timerType
->IsEpgBased()) // Start anytime toggle is not displayed
732 m_bStartAnyTime
= false; // Assume start time change needs checking for
733 m_timerInfoTag
->m_bStartAnyTime
= m_bStartAnyTime
;
735 if (!m_timerType
->SupportsEndAnyTime() ||
736 !m_timerType
->IsEpgBased()) // End anytime toggle is not displayed
737 m_bEndAnyTime
= false; // Assume end time change needs checking for
738 m_timerInfoTag
->m_bEndAnyTime
= m_bEndAnyTime
;
740 // Begin and end time
741 if (!m_bStartAnyTime
&& !m_bEndAnyTime
)
743 if (m_timerType
->SupportsStartTime() && // has start clock entry
744 m_timerType
->SupportsEndTime() && // and end clock entry
745 m_timerType
->IsTimerRule()) // but no associated start/end day spinners
747 if (m_endLocalTime
< m_startLocalTime
) // And the end clock is earlier than the start clock
749 CLog::LogFC(LOGDEBUG
, LOGPVR
, "End before start, adding a day.");
750 m_endLocalTime
+= CDateTimeSpan(1, 0, 0, 0);
751 if (m_endLocalTime
< m_startLocalTime
)
753 CLog::Log(LOGWARNING
,
754 "Timer settings dialog: End before start. Setting end time to start time.");
755 m_endLocalTime
= m_startLocalTime
;
758 else if (m_endLocalTime
>
759 (m_startLocalTime
+ CDateTimeSpan(1, 0, 0, 0))) // Or the duration is more than a day
761 CLog::LogFC(LOGDEBUG
, LOGPVR
, "End > 1 day after start, removing a day.");
762 m_endLocalTime
-= CDateTimeSpan(1, 0, 0, 0);
763 if (m_endLocalTime
> (m_startLocalTime
+ CDateTimeSpan(1, 0, 0, 0)))
767 "Timer settings dialog: End > 1 day after start. Setting end time to start time.");
768 m_endLocalTime
= m_startLocalTime
;
772 else if (m_endLocalTime
< m_startLocalTime
)
774 // this case will fail validation so this can't be reached.
776 m_timerInfoTag
->SetStartFromLocalTime(m_startLocalTime
);
777 m_timerInfoTag
->SetEndFromLocalTime(m_endLocalTime
);
779 else if (!m_bStartAnyTime
)
780 m_timerInfoTag
->SetStartFromLocalTime(m_startLocalTime
);
781 else if (!m_bEndAnyTime
)
782 m_timerInfoTag
->SetEndFromLocalTime(m_endLocalTime
);
784 // Days of week (only for timer rules)
785 if (m_timerType
->IsTimerRule())
786 m_timerInfoTag
->m_iWeekdays
= m_iWeekdays
;
788 m_timerInfoTag
->m_iWeekdays
= PVR_WEEKDAY_NONE
;
790 // First day (only for timer rules)
791 m_timerInfoTag
->SetFirstDayFromLocalTime(m_firstDayLocalTime
);
793 // "New episodes only" (only for timer rules)
794 m_timerInfoTag
->m_iPreventDupEpisodes
= m_iPreventDupEpisodes
;
796 // Pre and post record time
797 m_timerInfoTag
->m_iMarginStart
= m_iMarginStart
;
798 m_timerInfoTag
->m_iMarginEnd
= m_iMarginEnd
;
801 m_timerInfoTag
->m_iPriority
= m_iPriority
;
804 m_timerInfoTag
->m_iLifetime
= m_iLifetime
;
807 m_timerInfoTag
->m_iMaxRecordings
= m_iMaxRecordings
;
810 m_timerInfoTag
->m_strDirectory
= m_strDirectory
;
813 m_timerInfoTag
->m_iRecordingGroup
= m_iRecordingGroup
;
816 m_timerInfoTag
->m_customProps
= m_customTimerSettings
->GetProperties();
818 // Set the timer's title to the channel name if it's empty or 'New Timer'
819 if (m_strTitle
.empty() || m_strTitle
== g_localizeStrings
.Get(19056))
821 const std::string channelName
= m_timerInfoTag
->ChannelName();
822 if (!channelName
.empty())
823 m_timerInfoTag
->m_strTitle
= channelName
;
827 m_timerInfoTag
->UpdateSummary();
832 void CGUIDialogPVRTimerSettings::SetButtonLabels()
835 BaseSettingControlPtr settingControl
= GetSettingControl(SETTING_TMR_BEGIN
);
836 if (settingControl
!= NULL
&& settingControl
->GetControl() != NULL
)
838 SET_CONTROL_LABEL2(settingControl
->GetID(), m_timerStartTimeStr
);
842 settingControl
= GetSettingControl(SETTING_TMR_END
);
843 if (settingControl
!= NULL
&& settingControl
->GetControl() != NULL
)
845 SET_CONTROL_LABEL2(settingControl
->GetID(), m_timerEndTimeStr
);
849 void CGUIDialogPVRTimerSettings::AddCondition(const std::shared_ptr
<CSetting
>& setting
,
850 const std::string
& identifier
,
851 SettingConditionCheck condition
,
852 SettingDependencyType depType
,
853 const std::string
& settingId
)
855 GetSettingsManager()->AddDynamicCondition(identifier
, condition
, this);
856 CSettingDependency
dep(depType
, GetSettingsManager());
857 dep
.And()->Add(std::make_shared
<CSettingDependencyCondition
>(identifier
, "true", settingId
, false,
858 GetSettingsManager()));
859 SettingDependencies
deps(setting
->GetDependencies());
861 setting
->SetDependencies(deps
);
864 int CGUIDialogPVRTimerSettings::GetDateAsIndex(const CDateTime
& datetime
)
866 const CDateTime
date(datetime
.GetYear(), datetime
.GetMonth(), datetime
.GetDay(), 0, 0, 0);
869 return static_cast<int>(t
);
872 void CGUIDialogPVRTimerSettings::SetDateFromIndex(CDateTime
& datetime
, int date
)
874 const CDateTime
newDate(static_cast<time_t>(date
));
875 datetime
.SetDateTime(newDate
.GetYear(), newDate
.GetMonth(), newDate
.GetDay(), datetime
.GetHour(),
876 datetime
.GetMinute(), datetime
.GetSecond());
879 void CGUIDialogPVRTimerSettings::SetTimeFromSystemTime(CDateTime
& datetime
,
880 const KODI::TIME::SystemTime
& time
)
882 const CDateTime
newTime(time
);
883 datetime
.SetDateTime(datetime
.GetYear(), datetime
.GetMonth(), datetime
.GetDay(),
884 newTime
.GetHour(), newTime
.GetMinute(), newTime
.GetSecond());
887 void CGUIDialogPVRTimerSettings::InitializeTypesList()
889 m_typeEntries
.clear();
891 // If timer is read-only or was created by a timer rule, only add current type, for information. Type can't be changed.
892 if (m_timerType
->IsReadOnly() || m_timerInfoTag
->HasParent())
894 m_typeEntries
.insert(std::make_pair(0, m_timerType
));
898 bool bFoundThisType(false);
900 const std::vector
<std::shared_ptr
<CPVRTimerType
>> types(CPVRTimerType::GetAllTypes());
901 for (const auto& type
: types
)
903 // Type definition prohibits created of new instances.
904 // But the dialog can act as a viewer for these types.
905 if (type
->ForbidsNewInstances())
908 // Read-only timers cannot be created using this dialog.
909 // But the dialog can act as a viewer for read-only types.
910 if (type
->IsReadOnly())
913 // Drop TimerTypes that require EPGInfo, if none is populated
914 if (type
->RequiresEpgTagOnCreate() && !m_timerInfoTag
->GetEpgInfoTag())
917 // Drop TimerTypes without 'Series' EPG attributes if none are set
918 if (type
->RequiresEpgSeriesOnCreate())
920 const std::shared_ptr
<const CPVREpgInfoTag
> epgTag(m_timerInfoTag
->GetEpgInfoTag());
921 if (epgTag
&& !epgTag
->IsSeries())
925 // Drop TimerTypes which need series link if none is set
926 if (type
->RequiresEpgSeriesLinkOnCreate())
928 const std::shared_ptr
<const CPVREpgInfoTag
> epgTag(m_timerInfoTag
->GetEpgInfoTag());
929 if (!epgTag
|| epgTag
->SeriesLink().empty())
933 // Drop TimerTypes that forbid EPGInfo, if it is populated
934 if (type
->ForbidsEpgTagOnCreate() && m_timerInfoTag
->GetEpgInfoTag())
937 // Drop TimerTypes that aren't rules and cannot be recorded
938 if (!type
->IsTimerRule())
940 const std::shared_ptr
<const CPVREpgInfoTag
> epgTag(m_timerInfoTag
->GetEpgInfoTag());
941 bool bCanRecord
= epgTag
? epgTag
->IsRecordable()
942 : m_timerInfoTag
->EndAsLocalTime() > CDateTime::GetCurrentDateTime();
947 if (!bFoundThisType
&& *type
== *m_timerType
)
948 bFoundThisType
= true;
950 m_typeEntries
.insert(std::make_pair(idx
++, type
));
954 m_typeEntries
.insert(std::make_pair(idx
++, m_timerType
));
957 void CGUIDialogPVRTimerSettings::InitializeChannelsList()
959 m_channelEntries
.clear();
963 // Add special "any channel" entries - one for every client (used for epg-based timer rules),
964 // and for reminder rules another one representing any channel from any client.
965 const CPVRClientMap clients
= CServiceBroker::GetPVRManager().Clients()->GetCreatedClients();
966 if (clients
.size() > 1)
967 m_channelEntries
.insert(
968 {index
++, ChannelDescriptor(PVR_CHANNEL_INVALID_UID
, PVR_CLIENT_INVALID_UID
,
969 // Any channel from any client
970 g_localizeStrings
.Get(854))});
972 for (const auto& client
: clients
)
974 m_channelEntries
.insert(
975 {index
, ChannelDescriptor(PVR_CHANNEL_INVALID_UID
, client
.second
->GetID(),
978 ? g_localizeStrings
.Get(809)
979 // Any channel from client "X"
980 : StringUtils::Format(g_localizeStrings
.Get(853),
981 client
.second
->GetFullClientName()))});
985 // Add regular channels
986 const std::shared_ptr
<const CPVRChannelGroup
> allGroup
=
987 CServiceBroker::GetPVRManager().ChannelGroups()->GetGroupAll(m_bIsRadio
);
988 const std::vector
<std::shared_ptr
<CPVRChannelGroupMember
>> groupMembers
=
989 allGroup
->GetMembers(CPVRChannelGroup::Include::ONLY_VISIBLE
);
990 for (const auto& groupMember
: groupMembers
)
992 const std::shared_ptr
<const CPVRChannel
> channel
= groupMember
->Channel();
993 const std::string channelDescription
= StringUtils::Format(
994 "{} {}", groupMember
->ChannelNumber().FormattedChannelNumber(), channel
->ChannelName());
995 m_channelEntries
.insert(
996 {index
, ChannelDescriptor(channel
->UniqueID(), channel
->ClientID(), channelDescription
)});
1001 void CGUIDialogPVRTimerSettings::TypesFiller(const SettingConstPtr
& setting
,
1002 std::vector
<IntegerSettingOption
>& list
,
1006 CGUIDialogPVRTimerSettings
* pThis
= static_cast<CGUIDialogPVRTimerSettings
*>(data
);
1012 static const std::vector
<std::pair
<std::string
, CVariant
>> reminderTimerProps
{
1013 std::make_pair("PVR.IsRemindingTimer", CVariant
{true})};
1014 static const std::vector
<std::pair
<std::string
, CVariant
>> recordingTimerProps
{
1015 std::make_pair("PVR.IsRecordingTimer", CVariant
{true})};
1017 const auto clients
= CServiceBroker::GetPVRManager().Clients();
1019 bool foundCurrent(false);
1020 for (const auto& typeEntry
: pThis
->m_typeEntries
)
1022 std::string clientName
;
1024 const auto client
= clients
->GetCreatedClient(typeEntry
.second
->GetClientId());
1026 clientName
= client
->GetFullClientName();
1028 list
.emplace_back(typeEntry
.second
->GetDescription(), clientName
, typeEntry
.first
,
1029 typeEntry
.second
->IsReminder() ? reminderTimerProps
: recordingTimerProps
);
1031 if (!foundCurrent
&& (*(pThis
->m_timerType
) == *(typeEntry
.second
)))
1033 current
= typeEntry
.first
;
1034 foundCurrent
= true;
1039 CLog::LogF(LOGERROR
, "No dialog");
1042 void CGUIDialogPVRTimerSettings::ChannelsFiller(const SettingConstPtr
& setting
,
1043 std::vector
<IntegerSettingOption
>& list
,
1047 CGUIDialogPVRTimerSettings
* pThis
= static_cast<CGUIDialogPVRTimerSettings
*>(data
);
1053 bool foundCurrent(false);
1054 for (const auto& channelEntry
: pThis
->m_channelEntries
)
1056 // Only include channels for the currently selected timer type or all channels if type is client-independent.
1057 if (pThis
->m_timerType
->GetClientId() == PVR_CLIENT_INVALID_UID
|| // client-independent
1058 pThis
->m_timerType
->GetClientId() == channelEntry
.second
.clientId
)
1060 // Do not add "any channel" entry if not supported by selected timer type.
1061 if (channelEntry
.second
.channelUid
== PVR_CHANNEL_INVALID_UID
&&
1062 !pThis
->m_timerType
->SupportsAnyChannel())
1065 // Do not add "any channel from any client" entry for reminder rules.
1066 if (channelEntry
.second
.channelUid
== PVR_CHANNEL_INVALID_UID
&&
1067 channelEntry
.second
.clientId
== PVR_CLIENT_INVALID_UID
&&
1068 !pThis
->m_timerType
->IsReminder() && !pThis
->m_timerType
->IsTimerRule())
1071 list
.emplace_back(channelEntry
.second
.description
, channelEntry
.first
);
1074 if (!foundCurrent
&& (pThis
->m_channel
== channelEntry
.second
))
1076 current
= channelEntry
.first
;
1077 foundCurrent
= true;
1083 // Verify m_channel is still valid. Update if not.
1084 if (std::find_if(list
.cbegin(), list
.cend(),
1085 [¤t
](const auto& channel
)
1086 { return channel
.value
== current
; }) == list
.cend())
1088 // Set m_channel and current to first valid channel in list
1089 const int first
{list
.front().value
};
1091 std::find_if(pThis
->m_channelEntries
.cbegin(), pThis
->m_channelEntries
.cend(),
1092 [first
](const auto& channel
) { return channel
.first
== first
; });
1094 if (it
!= pThis
->m_channelEntries
.cend())
1096 current
= (*it
).first
;
1097 pThis
->m_channel
= (*it
).second
;
1101 CLog::LogF(LOGERROR
, "Unable to find channel to select");
1107 CLog::LogF(LOGERROR
, "No dialog");
1110 void CGUIDialogPVRTimerSettings::DaysFiller(const SettingConstPtr
& setting
,
1111 std::vector
<IntegerSettingOption
>& list
,
1115 CGUIDialogPVRTimerSettings
* pThis
= static_cast<CGUIDialogPVRTimerSettings
*>(data
);
1121 // Data range: "today" until "yesterday next year"
1122 const CDateTime
now(CDateTime::GetCurrentDateTime());
1123 CDateTime
time(now
.GetYear(), now
.GetMonth(), now
.GetDay(), 0, 0, 0);
1124 const CDateTime
yesterdayPlusOneYear(CDateTime(time
.GetYear() + 1, time
.GetMonth(),
1125 time
.GetDay(), time
.GetHour(), time
.GetMinute(),
1127 CDateTimeSpan(1, 0, 0, 0));
1129 CDateTime oldCDateTime
;
1130 if (setting
->GetId() == SETTING_TMR_FIRST_DAY
)
1131 oldCDateTime
= pThis
->m_timerInfoTag
->FirstDayAsLocalTime();
1132 else if (setting
->GetId() == SETTING_TMR_START_DAY
)
1133 oldCDateTime
= pThis
->m_timerInfoTag
->StartAsLocalTime();
1135 oldCDateTime
= pThis
->m_timerInfoTag
->EndAsLocalTime();
1136 const CDateTime
oldCDate(oldCDateTime
.GetYear(), oldCDateTime
.GetMonth(), oldCDateTime
.GetDay(),
1139 if ((oldCDate
< time
) || (oldCDate
> yesterdayPlusOneYear
))
1140 list
.emplace_back(oldCDate
.GetAsLocalizedDate(true /*long date*/), GetDateAsIndex(oldCDate
));
1142 while (time
<= yesterdayPlusOneYear
)
1144 list
.emplace_back(time
.GetAsLocalizedDate(true /*long date*/), GetDateAsIndex(time
));
1145 time
+= CDateTimeSpan(1, 0, 0, 0);
1148 if (setting
->GetId() == SETTING_TMR_FIRST_DAY
)
1149 current
= GetDateAsIndex(pThis
->m_firstDayLocalTime
);
1150 else if (setting
->GetId() == SETTING_TMR_START_DAY
)
1151 current
= GetDateAsIndex(pThis
->m_startLocalTime
);
1153 current
= GetDateAsIndex(pThis
->m_endLocalTime
);
1156 CLog::LogF(LOGERROR
, "No dialog");
1159 void CGUIDialogPVRTimerSettings::DupEpisodesFiller(const SettingConstPtr
& setting
,
1160 std::vector
<IntegerSettingOption
>& list
,
1164 CGUIDialogPVRTimerSettings
* pThis
= static_cast<CGUIDialogPVRTimerSettings
*>(data
);
1169 const std::vector
<SettingIntValue
>& values
{
1170 pThis
->m_timerType
->GetPreventDuplicateEpisodesValues()};
1171 std::transform(values
.cbegin(), values
.cend(), std::back_inserter(list
), [](const auto& value
) {
1172 return IntegerSettingOption(value
.first
, value
.second
);
1175 current
= pThis
->m_iPreventDupEpisodes
;
1178 CLog::LogF(LOGERROR
, "No dialog");
1181 void CGUIDialogPVRTimerSettings::WeekdaysFiller(const SettingConstPtr
& setting
,
1182 std::vector
<IntegerSettingOption
>& list
,
1186 CGUIDialogPVRTimerSettings
* pThis
= static_cast<CGUIDialogPVRTimerSettings
*>(data
);
1190 list
.emplace_back(g_localizeStrings
.Get(831), PVR_WEEKDAY_MONDAY
); // "Mondays"
1191 list
.emplace_back(g_localizeStrings
.Get(832), PVR_WEEKDAY_TUESDAY
); // "Tuesdays"
1192 list
.emplace_back(g_localizeStrings
.Get(833), PVR_WEEKDAY_WEDNESDAY
); // "Wednesdays"
1193 list
.emplace_back(g_localizeStrings
.Get(834), PVR_WEEKDAY_THURSDAY
); // "Thursdays"
1194 list
.emplace_back(g_localizeStrings
.Get(835), PVR_WEEKDAY_FRIDAY
); // "Fridays"
1195 list
.emplace_back(g_localizeStrings
.Get(836), PVR_WEEKDAY_SATURDAY
); // "Saturdays"
1196 list
.emplace_back(g_localizeStrings
.Get(837), PVR_WEEKDAY_SUNDAY
); // "Sundays"
1198 current
= pThis
->m_iWeekdays
;
1201 CLog::LogF(LOGERROR
, "No dialog");
1204 void CGUIDialogPVRTimerSettings::PrioritiesFiller(const SettingConstPtr
& setting
,
1205 std::vector
<IntegerSettingOption
>& list
,
1209 CGUIDialogPVRTimerSettings
* pThis
= static_cast<CGUIDialogPVRTimerSettings
*>(data
);
1214 const std::vector
<SettingIntValue
>& values
{pThis
->m_timerType
->GetPriorityValues()};
1215 std::transform(values
.cbegin(), values
.cend(), std::back_inserter(list
), [](const auto& value
) {
1216 return IntegerSettingOption(value
.first
, value
.second
);
1219 current
= pThis
->m_iPriority
;
1221 auto it
= list
.begin();
1222 while (it
!= list
.end())
1224 if (it
->value
== current
)
1225 break; // value already in list
1230 if (it
== list
.end())
1232 // PVR backend supplied value is not in the list of predefined values. Insert it.
1233 list
.insert(it
, IntegerSettingOption(std::to_string(current
), current
));
1237 CLog::LogF(LOGERROR
, "No dialog");
1240 void CGUIDialogPVRTimerSettings::LifetimesFiller(const SettingConstPtr
& setting
,
1241 std::vector
<IntegerSettingOption
>& list
,
1245 CGUIDialogPVRTimerSettings
* pThis
= static_cast<CGUIDialogPVRTimerSettings
*>(data
);
1250 const std::vector
<SettingIntValue
>& values
{pThis
->m_timerType
->GetLifetimeValues()};
1251 std::transform(values
.cbegin(), values
.cend(), std::back_inserter(list
), [](const auto& value
) {
1252 return IntegerSettingOption(value
.first
, value
.second
);
1255 current
= pThis
->m_iLifetime
;
1257 auto it
= list
.begin();
1258 while (it
!= list
.end())
1260 if (it
->value
== current
)
1261 break; // value already in list
1266 if (it
== list
.end())
1268 // PVR backend supplied value is not in the list of predefined values. Insert it.
1269 list
.insert(it
, IntegerSettingOption(
1270 StringUtils::Format(g_localizeStrings
.Get(17999), current
) /* {} days */,
1275 CLog::LogF(LOGERROR
, "No dialog");
1278 void CGUIDialogPVRTimerSettings::MaxRecordingsFiller(const SettingConstPtr
& setting
,
1279 std::vector
<IntegerSettingOption
>& list
,
1283 CGUIDialogPVRTimerSettings
* pThis
= static_cast<CGUIDialogPVRTimerSettings
*>(data
);
1288 const std::vector
<SettingIntValue
>& values
{pThis
->m_timerType
->GetMaxRecordingsValues()};
1289 std::transform(values
.cbegin(), values
.cend(), std::back_inserter(list
), [](const auto& value
) {
1290 return IntegerSettingOption(value
.first
, value
.second
);
1293 current
= pThis
->m_iMaxRecordings
;
1295 auto it
= list
.begin();
1296 while (it
!= list
.end())
1298 if (it
->value
== current
)
1299 break; // value already in list
1304 if (it
== list
.end())
1306 // PVR backend supplied value is not in the list of predefined values. Insert it.
1307 list
.insert(it
, IntegerSettingOption(std::to_string(current
), current
));
1311 CLog::LogF(LOGERROR
, "No dialog");
1314 void CGUIDialogPVRTimerSettings::RecordingGroupFiller(const SettingConstPtr
& setting
,
1315 std::vector
<IntegerSettingOption
>& list
,
1319 CGUIDialogPVRTimerSettings
* pThis
= static_cast<CGUIDialogPVRTimerSettings
*>(data
);
1324 const std::vector
<SettingIntValue
>& values
{pThis
->m_timerType
->GetRecordingGroupValues()};
1325 std::transform(values
.cbegin(), values
.cend(), std::back_inserter(list
), [](const auto& value
) {
1326 return IntegerSettingOption(value
.first
, value
.second
);
1329 current
= pThis
->m_iRecordingGroup
;
1332 CLog::LogF(LOGERROR
, "No dialog");
1335 void CGUIDialogPVRTimerSettings::MarginTimeFiller(const SettingConstPtr
& setting
,
1336 std::vector
<IntegerSettingOption
>& list
,
1340 CGUIDialogPVRTimerSettings
* pThis
= static_cast<CGUIDialogPVRTimerSettings
*>(data
);
1345 // Get global settings values
1346 CPVRSettings::MarginTimeFiller(setting
, list
, current
, data
);
1348 if (setting
->GetId() == SETTING_TMR_BEGIN_PRE
)
1349 current
= pThis
->m_iMarginStart
;
1351 current
= pThis
->m_iMarginEnd
;
1353 bool bInsertValue
= true;
1354 auto it
= list
.begin();
1355 while (it
!= list
.end())
1357 if (it
->value
== current
)
1359 bInsertValue
= false;
1360 break; // value already in list
1363 if (it
->value
> current
)
1371 // PVR backend supplied value is not in the list of predefined values. Insert it.
1372 list
.insert(it
, IntegerSettingOption(
1373 StringUtils::Format(g_localizeStrings
.Get(14044), current
) /* {} min */,
1378 CLog::LogF(LOGERROR
, "No dialog");
1381 void CGUIDialogPVRTimerSettings::CustomIntSettingDefinitionsFiller(
1382 const std::shared_ptr
<const CSetting
>& setting
,
1383 std::vector
<IntegerSettingOption
>& list
,
1387 CGUIDialogPVRTimerSettings
* pThis
= static_cast<CGUIDialogPVRTimerSettings
*>(data
);
1392 const std::string settingId
{setting
->GetId()};
1393 if (pThis
->m_customTimerSettings
->IsCustomIntSetting(settingId
))
1394 pThis
->m_customTimerSettings
->IntSettingDefinitionsFiller(settingId
, list
, current
);
1397 CLog::LogF(LOGERROR
, "No dialog");
1400 void CGUIDialogPVRTimerSettings::CustomStringSettingDefinitionsFiller(
1401 const std::shared_ptr
<const CSetting
>& setting
,
1402 std::vector
<StringSettingOption
>& list
,
1403 std::string
& current
,
1406 CGUIDialogPVRTimerSettings
* pThis
= static_cast<CGUIDialogPVRTimerSettings
*>(data
);
1411 const std::string settingId
{setting
->GetId()};
1412 if (pThis
->m_customTimerSettings
->IsCustomStringSetting(settingId
))
1413 pThis
->m_customTimerSettings
->StringSettingDefinitionsFiller(settingId
, list
, current
);
1416 CLog::LogF(LOGERROR
, "No dialog");
1419 std::string
CGUIDialogPVRTimerSettings::WeekdaysValueFormatter(const SettingConstPtr
& setting
)
1421 return CPVRTimerInfoTag::GetWeekdaysString(GetWeekdaysFromSetting(setting
), true, true);
1424 void CGUIDialogPVRTimerSettings::AddTypeDependentEnableCondition(
1425 const std::shared_ptr
<CSetting
>& setting
, const std::string
& identifier
)
1427 // Enable setting depending on read-only attribute of the selected timer type
1428 std::string
id(identifier
);
1429 id
.append(TYPE_DEP_ENABLE_COND_ID_POSTFIX
);
1430 AddCondition(setting
, id
, TypeReadOnlyCondition
, SettingDependencyType::Enable
, SETTING_TMR_TYPE
);
1433 bool CGUIDialogPVRTimerSettings::TypeReadOnlyCondition(const std::string
& condition
,
1434 const std::string
& value
,
1435 const SettingConstPtr
& setting
,
1438 if (setting
== NULL
)
1441 CGUIDialogPVRTimerSettings
* pThis
= static_cast<CGUIDialogPVRTimerSettings
*>(data
);
1444 CLog::LogF(LOGERROR
, "No dialog");
1448 if (!StringUtils::EqualsNoCase(value
, "true"))
1451 std::string
cond(condition
);
1452 cond
.erase(cond
.find(TYPE_DEP_ENABLE_COND_ID_POSTFIX
));
1454 // If only one type is available, disable type selector.
1455 if (pThis
->m_typeEntries
.size() == 1)
1457 if (cond
== SETTING_TMR_TYPE
)
1461 // For existing one time epg-based timers, disable editing of epg-filled data.
1462 if (!pThis
->m_bIsNewTimer
&& pThis
->m_timerType
->IsEpgBasedOnetime())
1464 if ((cond
== SETTING_TMR_NAME
) || (cond
== SETTING_TMR_CHANNEL
) ||
1465 (cond
== SETTING_TMR_START_DAY
) || (cond
== SETTING_TMR_END_DAY
) ||
1466 (cond
== SETTING_TMR_BEGIN
) || (cond
== SETTING_TMR_END
))
1470 /* Always enable enable/disable, if supported by the timer type. */
1471 if (pThis
->m_timerType
->SupportsEnableDisable() && !pThis
->m_timerInfoTag
->IsBroken())
1473 if (cond
== SETTING_TMR_ACTIVE
)
1477 /* Handle recordings in progress. */
1478 if (pThis
->m_timerInfoTag
->State() == PVR_TIMER_STATE_RECORDING
)
1480 if (cond
== SETTING_TMR_TYPE
|| cond
== SETTING_TMR_CHANNEL
|| cond
== SETTING_TMR_BEGIN_PRE
||
1481 cond
== SETTING_TMR_START_DAY
|| cond
== SETTING_TMR_BEGIN
||
1482 cond
== SETTING_TMR_PRIORITY
|| cond
== SETTING_TMR_DIR
)
1486 if (pThis
->m_customTimerSettings
->IsCustomSetting(cond
))
1488 return !pThis
->m_customTimerSettings
->IsSettingReadonlyForTimerState(
1489 cond
, pThis
->m_timerInfoTag
->State());
1492 // Let the PVR client decide...
1493 int idx
= std::static_pointer_cast
<const CSettingInt
>(setting
)->GetValue();
1494 const auto entry
= pThis
->m_typeEntries
.find(idx
);
1495 if (entry
!= pThis
->m_typeEntries
.end())
1496 return !entry
->second
->IsReadOnly();
1498 CLog::LogF(LOGERROR
, "No type entry");
1503 void CGUIDialogPVRTimerSettings::AddTypeDependentVisibilityCondition(
1504 const std::shared_ptr
<CSetting
>& setting
, const std::string
& identifier
)
1506 // Show or hide setting depending on attributes of the selected timer type
1507 std::string
id(identifier
);
1508 id
.append(TYPE_DEP_VISIBI_COND_ID_POSTFIX
);
1509 AddCondition(setting
, id
, TypeSupportsCondition
, SettingDependencyType::Visible
,
1513 bool CGUIDialogPVRTimerSettings::TypeSupportsCondition(const std::string
& condition
,
1514 const std::string
& value
,
1515 const SettingConstPtr
& setting
,
1518 if (setting
== NULL
)
1521 CGUIDialogPVRTimerSettings
* pThis
= static_cast<CGUIDialogPVRTimerSettings
*>(data
);
1524 CLog::LogF(LOGERROR
, "No dialog");
1528 if (!StringUtils::EqualsNoCase(value
, "true"))
1531 int idx
= std::static_pointer_cast
<const CSettingInt
>(setting
)->GetValue();
1532 const auto entry
= pThis
->m_typeEntries
.find(idx
);
1533 if (entry
!= pThis
->m_typeEntries
.end())
1535 std::string
cond(condition
);
1536 cond
.erase(cond
.find(TYPE_DEP_VISIBI_COND_ID_POSTFIX
));
1538 if (cond
== SETTING_TMR_EPGSEARCH
)
1539 return entry
->second
->SupportsEpgTitleMatch() || entry
->second
->SupportsEpgFulltextMatch();
1540 else if (cond
== SETTING_TMR_FULLTEXT
)
1541 return entry
->second
->SupportsEpgFulltextMatch();
1542 else if (cond
== SETTING_TMR_ACTIVE
)
1543 return entry
->second
->SupportsEnableDisable();
1544 else if (cond
== SETTING_TMR_CHANNEL
)
1545 return entry
->second
->SupportsChannels();
1546 else if (cond
== SETTING_TMR_START_ANYTIME
)
1547 return entry
->second
->SupportsStartAnyTime() && entry
->second
->IsEpgBased();
1548 else if (cond
== SETTING_TMR_END_ANYTIME
)
1549 return entry
->second
->SupportsEndAnyTime() && entry
->second
->IsEpgBased();
1550 else if (cond
== SETTING_TMR_START_DAY
)
1551 return entry
->second
->SupportsStartTime() && entry
->second
->IsOnetime();
1552 else if (cond
== SETTING_TMR_END_DAY
)
1553 return entry
->second
->SupportsEndTime() && entry
->second
->IsOnetime();
1554 else if (cond
== SETTING_TMR_BEGIN
)
1555 return entry
->second
->SupportsStartTime();
1556 else if (cond
== SETTING_TMR_END
)
1557 return entry
->second
->SupportsEndTime();
1558 else if (cond
== SETTING_TMR_WEEKDAYS
)
1559 return entry
->second
->SupportsWeekdays();
1560 else if (cond
== SETTING_TMR_FIRST_DAY
)
1561 return entry
->second
->SupportsFirstDay();
1562 else if (cond
== SETTING_TMR_NEW_EPISODES
)
1563 return entry
->second
->SupportsRecordOnlyNewEpisodes();
1564 else if (cond
== SETTING_TMR_BEGIN_PRE
)
1565 return entry
->second
->SupportsStartMargin();
1566 else if (cond
== SETTING_TMR_END_POST
)
1567 return entry
->second
->SupportsEndMargin();
1568 else if (cond
== SETTING_TMR_PRIORITY
)
1569 return entry
->second
->SupportsPriority();
1570 else if (cond
== SETTING_TMR_LIFETIME
)
1571 return entry
->second
->SupportsLifetime();
1572 else if (cond
== SETTING_TMR_MAX_REC
)
1573 return entry
->second
->SupportsMaxRecordings();
1574 else if (cond
== SETTING_TMR_DIR
)
1575 return entry
->second
->SupportsRecordingFolders();
1576 else if (cond
== SETTING_TMR_REC_GROUP
)
1577 return entry
->second
->SupportsRecordingGroup();
1578 else if (pThis
->m_customTimerSettings
->IsCustomSetting(cond
))
1579 return pThis
->m_customTimerSettings
->IsSettingSupportedForTimerType(cond
, *entry
->second
);
1581 CLog::LogF(LOGERROR
, "Unknown condition");
1585 CLog::LogF(LOGERROR
, "No type entry");
1590 void CGUIDialogPVRTimerSettings::AddStartAnytimeDependentVisibilityCondition(
1591 const std::shared_ptr
<CSetting
>& setting
, const std::string
& identifier
)
1593 // Show or hide setting depending on value of setting "any time"
1594 std::string
id(identifier
);
1595 id
.append(START_ANYTIME_DEP_VISIBI_COND_ID_POSTFIX
);
1596 AddCondition(setting
, id
, StartAnytimeSetCondition
, SettingDependencyType::Visible
,
1597 SETTING_TMR_START_ANYTIME
);
1600 bool CGUIDialogPVRTimerSettings::StartAnytimeSetCondition(const std::string
& condition
,
1601 const std::string
& value
,
1602 const SettingConstPtr
& setting
,
1605 if (setting
== NULL
)
1608 CGUIDialogPVRTimerSettings
* pThis
= static_cast<CGUIDialogPVRTimerSettings
*>(data
);
1611 CLog::LogF(LOGERROR
, "No dialog");
1615 if (!StringUtils::EqualsNoCase(value
, "true"))
1618 // "any time" setting is only relevant for epg-based timers.
1619 if (!pThis
->m_timerType
->IsEpgBased())
1622 // If 'Start anytime' option isn't supported, don't hide start time
1623 if (!pThis
->m_timerType
->SupportsStartAnyTime())
1626 std::string
cond(condition
);
1627 cond
.erase(cond
.find(START_ANYTIME_DEP_VISIBI_COND_ID_POSTFIX
));
1629 if ((cond
== SETTING_TMR_START_DAY
) || (cond
== SETTING_TMR_BEGIN
))
1631 bool bAnytime
= std::static_pointer_cast
<const CSettingBool
>(setting
)->GetValue();
1637 void CGUIDialogPVRTimerSettings::AddEndAnytimeDependentVisibilityCondition(
1638 const std::shared_ptr
<CSetting
>& setting
, const std::string
& identifier
)
1640 // Show or hide setting depending on value of setting "any time"
1641 std::string
id(identifier
);
1642 id
.append(END_ANYTIME_DEP_VISIBI_COND_ID_POSTFIX
);
1643 AddCondition(setting
, id
, EndAnytimeSetCondition
, SettingDependencyType::Visible
,
1644 SETTING_TMR_END_ANYTIME
);
1647 bool CGUIDialogPVRTimerSettings::EndAnytimeSetCondition(const std::string
& condition
,
1648 const std::string
& value
,
1649 const SettingConstPtr
& setting
,
1652 if (setting
== NULL
)
1655 CGUIDialogPVRTimerSettings
* pThis
= static_cast<CGUIDialogPVRTimerSettings
*>(data
);
1658 CLog::LogF(LOGERROR
, "No dialog");
1662 if (!StringUtils::EqualsNoCase(value
, "true"))
1665 // "any time" setting is only relevant for epg-based timers.
1666 if (!pThis
->m_timerType
->IsEpgBased())
1669 // If 'End anytime' option isn't supported, don't hide end time
1670 if (!pThis
->m_timerType
->SupportsEndAnyTime())
1673 std::string
cond(condition
);
1674 cond
.erase(cond
.find(END_ANYTIME_DEP_VISIBI_COND_ID_POSTFIX
));
1676 if ((cond
== SETTING_TMR_END_DAY
) || (cond
== SETTING_TMR_END
))
1678 bool bAnytime
= std::static_pointer_cast
<const CSettingBool
>(setting
)->GetValue();