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/PVRManager.h"
17 #include "pvr/addons/PVRClient.h"
18 #include "pvr/addons/PVRClients.h"
19 #include "pvr/channels/PVRChannel.h"
20 #include "pvr/channels/PVRChannelGroup.h"
21 #include "pvr/channels/PVRChannelGroupMember.h"
22 #include "pvr/channels/PVRChannelGroupsContainer.h"
23 #include "pvr/epg/EpgInfoTag.h"
24 #include "pvr/timers/PVRTimerInfoTag.h"
25 #include "pvr/timers/PVRTimerType.h"
26 #include "settings/SettingUtils.h"
27 #include "settings/dialogs/GUIDialogSettingsBase.h"
28 #include "settings/lib/Setting.h"
29 #include "settings/lib/SettingsManager.h"
30 #include "settings/windows/GUIControlSettings.h"
31 #include "utils/StringUtils.h"
32 #include "utils/Variant.h"
33 #include "utils/log.h"
43 using namespace KODI::MESSAGING
;
45 #define SETTING_TMR_TYPE "timer.type"
46 #define SETTING_TMR_ACTIVE "timer.active"
47 #define SETTING_TMR_NAME "timer.name"
48 #define SETTING_TMR_EPGSEARCH "timer.epgsearch"
49 #define SETTING_TMR_FULLTEXT "timer.fulltext"
50 #define SETTING_TMR_CHANNEL "timer.channel"
51 #define SETTING_TMR_START_ANYTIME "timer.startanytime"
52 #define SETTING_TMR_END_ANYTIME "timer.endanytime"
53 #define SETTING_TMR_START_DAY "timer.startday"
54 #define SETTING_TMR_END_DAY "timer.endday"
55 #define SETTING_TMR_BEGIN "timer.begin"
56 #define SETTING_TMR_END "timer.end"
57 #define SETTING_TMR_WEEKDAYS "timer.weekdays"
58 #define SETTING_TMR_FIRST_DAY "timer.firstday"
59 #define SETTING_TMR_NEW_EPISODES "timer.newepisodes"
60 #define SETTING_TMR_BEGIN_PRE "timer.startmargin"
61 #define SETTING_TMR_END_POST "timer.endmargin"
62 #define SETTING_TMR_PRIORITY "timer.priority"
63 #define SETTING_TMR_LIFETIME "timer.lifetime"
64 #define SETTING_TMR_MAX_REC "timer.maxrecordings"
65 #define SETTING_TMR_DIR "timer.directory"
66 #define SETTING_TMR_REC_GROUP "timer.recgroup"
68 #define TYPE_DEP_VISIBI_COND_ID_POSTFIX "visibi.typedep"
69 #define TYPE_DEP_ENABLE_COND_ID_POSTFIX "enable.typedep"
70 #define CHANNEL_DEP_VISIBI_COND_ID_POSTFIX "visibi.channeldep"
71 #define START_ANYTIME_DEP_VISIBI_COND_ID_POSTFIX "visibi.startanytimedep"
72 #define END_ANYTIME_DEP_VISIBI_COND_ID_POSTFIX "visibi.endanytimedep"
74 CGUIDialogPVRTimerSettings::CGUIDialogPVRTimerSettings()
75 : CGUIDialogSettingsManualBase(WINDOW_DIALOG_PVR_TIMER_SETTING
, "DialogSettings.xml"),
76 m_iWeekdays(PVR_WEEKDAY_NONE
)
78 m_loadType
= LOAD_EVERY_TIME
;
81 CGUIDialogPVRTimerSettings::~CGUIDialogPVRTimerSettings() = default;
83 bool CGUIDialogPVRTimerSettings::CanBeActivated() const
87 CLog::LogF(LOGERROR
, "No timer info tag");
93 void CGUIDialogPVRTimerSettings::SetTimer(const std::shared_ptr
<CPVRTimerInfoTag
>& timer
)
97 CLog::LogF(LOGERROR
, "No timer given");
101 m_timerInfoTag
= timer
;
103 // Copy data we need from tag. Do not modify the tag itself until Save()!
104 m_timerType
= m_timerInfoTag
->GetTimerType();
105 m_bIsRadio
= m_timerInfoTag
->m_bIsRadio
;
106 m_bIsNewTimer
= m_timerInfoTag
->m_iClientIndex
== PVR_TIMER_NO_CLIENT_INDEX
;
107 m_bTimerActive
= m_bIsNewTimer
|| !m_timerType
->SupportsEnableDisable() ||
108 !(m_timerInfoTag
->m_state
== PVR_TIMER_STATE_DISABLED
);
110 m_bIsNewTimer
|| !m_timerType
->SupportsStartAnyTime() || m_timerInfoTag
->m_bStartAnyTime
;
112 m_bIsNewTimer
|| !m_timerType
->SupportsEndAnyTime() || m_timerInfoTag
->m_bEndAnyTime
;
113 m_strTitle
= m_timerInfoTag
->m_strTitle
;
115 m_startLocalTime
= m_timerInfoTag
->StartAsLocalTime();
116 m_endLocalTime
= m_timerInfoTag
->EndAsLocalTime();
118 m_timerStartTimeStr
= m_startLocalTime
.GetAsLocalizedTime("", false);
119 m_timerEndTimeStr
= m_endLocalTime
.GetAsLocalizedTime("", false);
120 m_firstDayLocalTime
= m_timerInfoTag
->FirstDayAsLocalTime();
122 m_strEpgSearchString
= m_timerInfoTag
->m_strEpgSearchString
;
123 if ((m_bIsNewTimer
|| !m_timerType
->SupportsEpgTitleMatch()) && m_strEpgSearchString
.empty())
124 m_strEpgSearchString
= m_strTitle
;
126 m_bFullTextEpgSearch
= m_timerInfoTag
->m_bFullTextEpgSearch
;
128 m_iWeekdays
= m_timerInfoTag
->m_iWeekdays
;
129 if ((m_bIsNewTimer
|| !m_timerType
->SupportsWeekdays()) && m_iWeekdays
== PVR_WEEKDAY_NONE
)
130 m_iWeekdays
= PVR_WEEKDAY_ALLDAYS
;
132 m_iPreventDupEpisodes
= m_timerInfoTag
->m_iPreventDupEpisodes
;
133 m_iMarginStart
= m_timerInfoTag
->m_iMarginStart
;
134 m_iMarginEnd
= m_timerInfoTag
->m_iMarginEnd
;
135 m_iPriority
= m_timerInfoTag
->m_iPriority
;
136 m_iLifetime
= m_timerInfoTag
->m_iLifetime
;
137 m_iMaxRecordings
= m_timerInfoTag
->m_iMaxRecordings
;
139 if (m_bIsNewTimer
&& m_timerInfoTag
->m_strDirectory
.empty() &&
140 m_timerType
->SupportsRecordingFolders())
141 m_strDirectory
= m_strTitle
;
143 m_strDirectory
= m_timerInfoTag
->m_strDirectory
;
145 m_iRecordingGroup
= m_timerInfoTag
->m_iRecordingGroup
;
147 InitializeChannelsList();
148 InitializeTypesList();
151 m_channel
= ChannelDescriptor();
153 if (m_timerInfoTag
->m_iClientChannelUid
== PVR_CHANNEL_INVALID_UID
)
155 if (m_timerType
->SupportsAnyChannel())
157 // Select first matching "Any channel" entry.
158 const auto it
= std::find_if(m_channelEntries
.cbegin(), m_channelEntries
.cend(),
159 [this](const auto& channel
) {
160 return channel
.second
.channelUid
== PVR_CHANNEL_INVALID_UID
&&
161 channel
.second
.clientId
== m_timerInfoTag
->m_iClientId
;
164 if (it
!= m_channelEntries
.cend())
166 m_channel
= (*it
).second
;
170 CLog::LogF(LOGERROR
, "Unable to map PVR_CHANNEL_INVALID_UID to channel entry!");
173 else if (m_bIsNewTimer
)
175 // Select first matching regular (not "Any channel") entry.
176 const auto it
= std::find_if(m_channelEntries
.cbegin(), m_channelEntries
.cend(),
177 [this](const auto& channel
) {
178 return channel
.second
.channelUid
!= PVR_CHANNEL_INVALID_UID
&&
179 channel
.second
.clientId
== m_timerInfoTag
->m_iClientId
;
182 if (it
!= m_channelEntries
.cend())
184 m_channel
= (*it
).second
;
188 CLog::LogF(LOGERROR
, "Unable to map PVR_CHANNEL_INVALID_UID to channel entry!");
194 // Find matching channel entry
195 const auto it
= std::find_if(
196 m_channelEntries
.cbegin(), m_channelEntries
.cend(), [this](const auto& channel
) {
197 return channel
.second
.channelUid
== m_timerInfoTag
->m_iClientChannelUid
&&
198 channel
.second
.clientId
== m_timerInfoTag
->m_iClientId
;
201 if (it
!= m_channelEntries
.cend())
203 m_channel
= (*it
).second
;
207 CLog::LogF(LOGERROR
, "Unable to map channel uid to channel entry!");
212 void CGUIDialogPVRTimerSettings::SetupView()
214 CGUIDialogSettingsManualBase::SetupView();
216 SET_CONTROL_HIDDEN(CONTROL_SETTINGS_CUSTOM_BUTTON
);
217 SET_CONTROL_LABEL(CONTROL_SETTINGS_OKAY_BUTTON
, 186);
218 SET_CONTROL_LABEL(CONTROL_SETTINGS_CANCEL_BUTTON
, 222);
222 void CGUIDialogPVRTimerSettings::InitializeSettings()
224 CGUIDialogSettingsManualBase::InitializeSettings();
226 const std::shared_ptr
<CSettingCategory
> category
= AddCategory("pvrtimersettings", -1);
227 if (category
== NULL
)
229 CLog::LogF(LOGERROR
, "Unable to add settings category");
233 const std::shared_ptr
<CSettingGroup
> group
= AddGroup(category
);
236 CLog::LogF(LOGERROR
, "Unable to add settings group");
240 std::shared_ptr
<CSetting
> setting
= NULL
;
243 bool useDetails
= false;
244 bool foundClientSupportingTimers
= false;
246 const CPVRClientMap clients
= CServiceBroker::GetPVRManager().Clients()->GetCreatedClients();
247 for (const auto& client
: clients
)
249 if (client
.second
->GetClientCapabilities().SupportsTimers())
251 if (foundClientSupportingTimers
)
253 // found second client supporting timers, use detailed timer type list layout
257 foundClientSupportingTimers
= true;
261 setting
= AddList(group
, SETTING_TMR_TYPE
, 803, SettingLevel::Basic
, 0, TypesFiller
, 803, true,
263 AddTypeDependentEnableCondition(setting
, SETTING_TMR_TYPE
);
265 // Timer enabled/disabled
266 setting
= AddToggle(group
, SETTING_TMR_ACTIVE
, 305, SettingLevel::Basic
, m_bTimerActive
);
267 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_ACTIVE
);
268 AddTypeDependentEnableCondition(setting
, SETTING_TMR_ACTIVE
);
272 AddEdit(group
, SETTING_TMR_NAME
, 19075, SettingLevel::Basic
, m_strTitle
, true, false, 19097);
273 AddTypeDependentEnableCondition(setting
, SETTING_TMR_NAME
);
275 // epg search string (only for epg-based timer rules)
276 setting
= AddEdit(group
, SETTING_TMR_EPGSEARCH
, 804, SettingLevel::Basic
, m_strEpgSearchString
,
278 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_EPGSEARCH
);
279 AddTypeDependentEnableCondition(setting
, SETTING_TMR_EPGSEARCH
);
281 // epg fulltext search (only for epg-based timer rules)
282 setting
= AddToggle(group
, SETTING_TMR_FULLTEXT
, 806, SettingLevel::Basic
, m_bFullTextEpgSearch
);
283 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_FULLTEXT
);
284 AddTypeDependentEnableCondition(setting
, SETTING_TMR_FULLTEXT
);
288 AddList(group
, SETTING_TMR_CHANNEL
, 19078, SettingLevel::Basic
, 0, ChannelsFiller
, 19078);
289 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_CHANNEL
);
290 AddTypeDependentEnableCondition(setting
, SETTING_TMR_CHANNEL
);
292 // Days of week (only for timer rules)
293 std::vector
<int> weekdaysPreselect
;
294 if (m_iWeekdays
& PVR_WEEKDAY_MONDAY
)
295 weekdaysPreselect
.push_back(PVR_WEEKDAY_MONDAY
);
296 if (m_iWeekdays
& PVR_WEEKDAY_TUESDAY
)
297 weekdaysPreselect
.push_back(PVR_WEEKDAY_TUESDAY
);
298 if (m_iWeekdays
& PVR_WEEKDAY_WEDNESDAY
)
299 weekdaysPreselect
.push_back(PVR_WEEKDAY_WEDNESDAY
);
300 if (m_iWeekdays
& PVR_WEEKDAY_THURSDAY
)
301 weekdaysPreselect
.push_back(PVR_WEEKDAY_THURSDAY
);
302 if (m_iWeekdays
& PVR_WEEKDAY_FRIDAY
)
303 weekdaysPreselect
.push_back(PVR_WEEKDAY_FRIDAY
);
304 if (m_iWeekdays
& PVR_WEEKDAY_SATURDAY
)
305 weekdaysPreselect
.push_back(PVR_WEEKDAY_SATURDAY
);
306 if (m_iWeekdays
& PVR_WEEKDAY_SUNDAY
)
307 weekdaysPreselect
.push_back(PVR_WEEKDAY_SUNDAY
);
309 setting
= AddList(group
, SETTING_TMR_WEEKDAYS
, 19079, SettingLevel::Basic
, weekdaysPreselect
,
310 WeekdaysFiller
, 19079, 1, -1, true, -1, WeekdaysValueFormatter
);
311 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_WEEKDAYS
);
312 AddTypeDependentEnableCondition(setting
, SETTING_TMR_WEEKDAYS
);
314 // "Start any time" (only for timer rules)
315 setting
= AddToggle(group
, SETTING_TMR_START_ANYTIME
, 810, SettingLevel::Basic
, m_bStartAnyTime
);
316 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_START_ANYTIME
);
317 AddTypeDependentEnableCondition(setting
, SETTING_TMR_START_ANYTIME
);
319 // Start day (day + month + year only, no hours, minutes)
320 setting
= AddSpinner(group
, SETTING_TMR_START_DAY
, 19128, SettingLevel::Basic
,
321 GetDateAsIndex(m_startLocalTime
), DaysFiller
);
322 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_START_DAY
);
323 AddTypeDependentEnableCondition(setting
, SETTING_TMR_START_DAY
);
324 AddStartAnytimeDependentVisibilityCondition(setting
, SETTING_TMR_START_DAY
);
326 // Start time (hours + minutes only, no day, month, year)
327 setting
= AddButton(group
, SETTING_TMR_BEGIN
, 19126, SettingLevel::Basic
);
328 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_BEGIN
);
329 AddTypeDependentEnableCondition(setting
, SETTING_TMR_BEGIN
);
330 AddStartAnytimeDependentVisibilityCondition(setting
, SETTING_TMR_BEGIN
);
332 // "End any time" (only for timer rules)
333 setting
= AddToggle(group
, SETTING_TMR_END_ANYTIME
, 817, SettingLevel::Basic
, m_bEndAnyTime
);
334 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_END_ANYTIME
);
335 AddTypeDependentEnableCondition(setting
, SETTING_TMR_END_ANYTIME
);
337 // End day (day + month + year only, no hours, minutes)
338 setting
= AddSpinner(group
, SETTING_TMR_END_DAY
, 19129, SettingLevel::Basic
,
339 GetDateAsIndex(m_endLocalTime
), DaysFiller
);
340 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_END_DAY
);
341 AddTypeDependentEnableCondition(setting
, SETTING_TMR_END_DAY
);
342 AddEndAnytimeDependentVisibilityCondition(setting
, SETTING_TMR_END_DAY
);
344 // End time (hours + minutes only, no day, month, year)
345 setting
= AddButton(group
, SETTING_TMR_END
, 19127, SettingLevel::Basic
);
346 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_END
);
347 AddTypeDependentEnableCondition(setting
, SETTING_TMR_END
);
348 AddEndAnytimeDependentVisibilityCondition(setting
, SETTING_TMR_END
);
350 // First day (only for timer rules)
351 setting
= AddSpinner(group
, SETTING_TMR_FIRST_DAY
, 19084, SettingLevel::Basic
,
352 GetDateAsIndex(m_firstDayLocalTime
), DaysFiller
);
353 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_FIRST_DAY
);
354 AddTypeDependentEnableCondition(setting
, SETTING_TMR_FIRST_DAY
);
356 // "Prevent duplicate episodes" (only for timer rules)
357 setting
= AddList(group
, SETTING_TMR_NEW_EPISODES
, 812, SettingLevel::Basic
,
358 m_iPreventDupEpisodes
, DupEpisodesFiller
, 812);
359 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_NEW_EPISODES
);
360 AddTypeDependentEnableCondition(setting
, SETTING_TMR_NEW_EPISODES
);
362 // Pre and post record time
363 setting
= AddList(group
, SETTING_TMR_BEGIN_PRE
, 813, SettingLevel::Basic
, m_iMarginStart
,
364 MarginTimeFiller
, 813);
365 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_BEGIN_PRE
);
366 AddTypeDependentEnableCondition(setting
, SETTING_TMR_BEGIN_PRE
);
368 setting
= AddList(group
, SETTING_TMR_END_POST
, 814, SettingLevel::Basic
, m_iMarginEnd
,
369 MarginTimeFiller
, 814);
370 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_END_POST
);
371 AddTypeDependentEnableCondition(setting
, SETTING_TMR_END_POST
);
374 setting
= AddList(group
, SETTING_TMR_PRIORITY
, 19082, SettingLevel::Basic
, m_iPriority
,
375 PrioritiesFiller
, 19082);
376 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_PRIORITY
);
377 AddTypeDependentEnableCondition(setting
, SETTING_TMR_PRIORITY
);
380 setting
= AddList(group
, SETTING_TMR_LIFETIME
, 19083, SettingLevel::Basic
, m_iLifetime
,
381 LifetimesFiller
, 19083);
382 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_LIFETIME
);
383 AddTypeDependentEnableCondition(setting
, SETTING_TMR_LIFETIME
);
386 setting
= AddList(group
, SETTING_TMR_MAX_REC
, 818, SettingLevel::Basic
, m_iMaxRecordings
,
387 MaxRecordingsFiller
, 818);
388 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_MAX_REC
);
389 AddTypeDependentEnableCondition(setting
, SETTING_TMR_MAX_REC
);
392 setting
= AddEdit(group
, SETTING_TMR_DIR
, 19076, SettingLevel::Basic
, m_strDirectory
, true, false,
394 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_DIR
);
395 AddTypeDependentEnableCondition(setting
, SETTING_TMR_DIR
);
398 setting
= AddList(group
, SETTING_TMR_REC_GROUP
, 811, SettingLevel::Basic
, m_iRecordingGroup
,
399 RecordingGroupFiller
, 811);
400 AddTypeDependentVisibilityCondition(setting
, SETTING_TMR_REC_GROUP
);
401 AddTypeDependentEnableCondition(setting
, SETTING_TMR_REC_GROUP
);
404 int CGUIDialogPVRTimerSettings::GetWeekdaysFromSetting(const SettingConstPtr
& setting
)
406 std::shared_ptr
<const CSettingList
> settingList
=
407 std::static_pointer_cast
<const CSettingList
>(setting
);
408 if (settingList
->GetElementType() != SettingType::Integer
)
410 CLog::LogF(LOGERROR
, "Wrong weekdays element type");
414 std::vector
<CVariant
> list
= CSettingUtils::GetList(settingList
);
415 for (const auto& value
: list
)
417 if (!value
.isInteger())
419 CLog::LogF(LOGERROR
, "Wrong weekdays value type");
422 weekdays
+= static_cast<int>(value
.asInteger());
428 void CGUIDialogPVRTimerSettings::OnSettingChanged(const std::shared_ptr
<const CSetting
>& setting
)
432 CLog::LogF(LOGERROR
, "No setting");
436 CGUIDialogSettingsManualBase::OnSettingChanged(setting
);
438 const std::string
& settingId
= setting
->GetId();
440 if (settingId
== SETTING_TMR_TYPE
)
442 int idx
= std::static_pointer_cast
<const CSettingInt
>(setting
)->GetValue();
443 const auto it
= m_typeEntries
.find(idx
);
444 if (it
!= m_typeEntries
.end())
446 m_timerType
= it
->second
;
448 // reset certain settings to the defaults of the new timer type
450 if (m_timerType
->SupportsPriority())
451 m_iPriority
= m_timerType
->GetPriorityDefault();
453 if (m_timerType
->SupportsLifetime())
454 m_iLifetime
= m_timerType
->GetLifetimeDefault();
456 if (m_timerType
->SupportsMaxRecordings())
457 m_iMaxRecordings
= m_timerType
->GetMaxRecordingsDefault();
459 if (m_timerType
->SupportsRecordingGroup())
460 m_iRecordingGroup
= m_timerType
->GetRecordingGroupDefault();
462 if (m_timerType
->SupportsRecordOnlyNewEpisodes())
463 m_iPreventDupEpisodes
= m_timerType
->GetPreventDuplicateEpisodesDefault();
465 if (m_timerType
->IsTimerRule() && (m_iWeekdays
== PVR_WEEKDAY_ALLDAYS
))
466 SetButtonLabels(); // update "Any day" vs. "Every day"
470 CLog::LogF(LOGERROR
, "Unable to get 'type' value");
473 else if (settingId
== SETTING_TMR_ACTIVE
)
475 m_bTimerActive
= std::static_pointer_cast
<const CSettingBool
>(setting
)->GetValue();
477 else if (settingId
== SETTING_TMR_NAME
)
479 m_strTitle
= std::static_pointer_cast
<const CSettingString
>(setting
)->GetValue();
481 else if (settingId
== SETTING_TMR_EPGSEARCH
)
483 m_strEpgSearchString
= std::static_pointer_cast
<const CSettingString
>(setting
)->GetValue();
485 else if (settingId
== SETTING_TMR_FULLTEXT
)
487 m_bFullTextEpgSearch
= std::static_pointer_cast
<const CSettingBool
>(setting
)->GetValue();
489 else if (settingId
== SETTING_TMR_CHANNEL
)
491 int idx
= std::static_pointer_cast
<const CSettingInt
>(setting
)->GetValue();
492 const auto it
= m_channelEntries
.find(idx
);
493 if (it
!= m_channelEntries
.end())
495 m_channel
= it
->second
;
499 CLog::LogF(LOGERROR
, "Unable to get 'type' value");
502 else if (settingId
== SETTING_TMR_WEEKDAYS
)
504 m_iWeekdays
= GetWeekdaysFromSetting(setting
);
506 else if (settingId
== SETTING_TMR_START_ANYTIME
)
508 m_bStartAnyTime
= std::static_pointer_cast
<const CSettingBool
>(setting
)->GetValue();
510 else if (settingId
== SETTING_TMR_END_ANYTIME
)
512 m_bEndAnyTime
= std::static_pointer_cast
<const CSettingBool
>(setting
)->GetValue();
514 else if (settingId
== SETTING_TMR_START_DAY
)
516 SetDateFromIndex(m_startLocalTime
,
517 std::static_pointer_cast
<const CSettingInt
>(setting
)->GetValue());
519 else if (settingId
== SETTING_TMR_END_DAY
)
521 SetDateFromIndex(m_endLocalTime
,
522 std::static_pointer_cast
<const CSettingInt
>(setting
)->GetValue());
524 else if (settingId
== SETTING_TMR_FIRST_DAY
)
526 SetDateFromIndex(m_firstDayLocalTime
,
527 std::static_pointer_cast
<const CSettingInt
>(setting
)->GetValue());
529 else if (settingId
== SETTING_TMR_NEW_EPISODES
)
531 m_iPreventDupEpisodes
= std::static_pointer_cast
<const CSettingInt
>(setting
)->GetValue();
533 else if (settingId
== SETTING_TMR_BEGIN_PRE
)
535 m_iMarginStart
= std::static_pointer_cast
<const CSettingInt
>(setting
)->GetValue();
537 else if (settingId
== SETTING_TMR_END_POST
)
539 m_iMarginEnd
= std::static_pointer_cast
<const CSettingInt
>(setting
)->GetValue();
541 else if (settingId
== SETTING_TMR_PRIORITY
)
543 m_iPriority
= std::static_pointer_cast
<const CSettingInt
>(setting
)->GetValue();
545 else if (settingId
== SETTING_TMR_LIFETIME
)
547 m_iLifetime
= std::static_pointer_cast
<const CSettingInt
>(setting
)->GetValue();
549 else if (settingId
== SETTING_TMR_MAX_REC
)
551 m_iMaxRecordings
= std::static_pointer_cast
<const CSettingInt
>(setting
)->GetValue();
553 else if (settingId
== SETTING_TMR_DIR
)
555 m_strDirectory
= std::static_pointer_cast
<const CSettingString
>(setting
)->GetValue();
557 else if (settingId
== SETTING_TMR_REC_GROUP
)
559 m_iRecordingGroup
= std::static_pointer_cast
<const CSettingInt
>(setting
)->GetValue();
563 void CGUIDialogPVRTimerSettings::OnSettingAction(const std::shared_ptr
<const CSetting
>& setting
)
567 CLog::LogF(LOGERROR
, "No setting");
571 CGUIDialogSettingsManualBase::OnSettingAction(setting
);
573 const std::string
& settingId
= setting
->GetId();
574 if (settingId
== SETTING_TMR_BEGIN
)
576 KODI::TIME::SystemTime timerStartTime
;
577 m_startLocalTime
.GetAsSystemTime(timerStartTime
);
578 if (CGUIDialogNumeric::ShowAndGetTime(timerStartTime
, g_localizeStrings
.Get(14066)))
580 SetTimeFromSystemTime(m_startLocalTime
, timerStartTime
);
581 m_timerStartTimeStr
= m_startLocalTime
.GetAsLocalizedTime("", false);
585 else if (settingId
== SETTING_TMR_END
)
587 KODI::TIME::SystemTime timerEndTime
;
588 m_endLocalTime
.GetAsSystemTime(timerEndTime
);
589 if (CGUIDialogNumeric::ShowAndGetTime(timerEndTime
, g_localizeStrings
.Get(14066)))
591 SetTimeFromSystemTime(m_endLocalTime
, timerEndTime
);
592 m_timerEndTimeStr
= m_endLocalTime
.GetAsLocalizedTime("", false);
598 bool CGUIDialogPVRTimerSettings::Validate()
600 // @todo: Timer rules may have no date (time-only), so we can't check those for now.
601 // We need to extend the api with additional attributes to properly fix this
602 if (m_timerType
->IsTimerRule())
605 bool bStartAnyTime
= m_bStartAnyTime
;
606 bool bEndAnyTime
= m_bEndAnyTime
;
608 if (!m_timerType
->SupportsStartAnyTime() ||
609 !m_timerType
->IsEpgBased()) // Start anytime toggle is not displayed
610 bStartAnyTime
= false; // Assume start time change needs checking for
612 if (!m_timerType
->SupportsEndAnyTime() ||
613 !m_timerType
->IsEpgBased()) // End anytime toggle is not displayed
614 bEndAnyTime
= false; // Assume end time change needs checking for
616 // Begin and end time
617 if (!bStartAnyTime
&& !bEndAnyTime
)
619 if (m_timerType
->SupportsStartTime() && m_timerType
->SupportsEndTime() &&
620 m_endLocalTime
< m_startLocalTime
)
622 HELPERS::ShowOKDialogText(CVariant
{19065}, // "Timer settings"
623 CVariant
{19072}); // In order to add/update a timer
631 bool CGUIDialogPVRTimerSettings::Save()
637 m_timerInfoTag
->SetTimerType(m_timerType
);
639 // Timer active/inactive
640 m_timerInfoTag
->m_state
= m_bTimerActive
? PVR_TIMER_STATE_SCHEDULED
: PVR_TIMER_STATE_DISABLED
;
643 m_timerInfoTag
->m_strTitle
= m_strTitle
;
645 // epg search string (only for epg-based timer rules)
646 m_timerInfoTag
->m_strEpgSearchString
= m_strEpgSearchString
;
648 // epg fulltext search, instead of just title match. (only for epg-based timer rules)
649 m_timerInfoTag
->m_bFullTextEpgSearch
= m_bFullTextEpgSearch
;
652 m_timerInfoTag
->m_iClientChannelUid
= m_channel
.channelUid
;
653 m_timerInfoTag
->m_iClientId
= m_channel
.clientId
;
654 m_timerInfoTag
->m_bIsRadio
= m_bIsRadio
;
655 m_timerInfoTag
->UpdateChannel();
657 if (!m_timerType
->SupportsStartAnyTime() ||
658 !m_timerType
->IsEpgBased()) // Start anytime toggle is not displayed
659 m_bStartAnyTime
= false; // Assume start time change needs checking for
660 m_timerInfoTag
->m_bStartAnyTime
= m_bStartAnyTime
;
662 if (!m_timerType
->SupportsEndAnyTime() ||
663 !m_timerType
->IsEpgBased()) // End anytime toggle is not displayed
664 m_bEndAnyTime
= false; // Assume end time change needs checking for
665 m_timerInfoTag
->m_bEndAnyTime
= m_bEndAnyTime
;
667 // Begin and end time
668 if (!m_bStartAnyTime
&& !m_bEndAnyTime
)
670 if (m_timerType
->SupportsStartTime() && // has start clock entry
671 m_timerType
->SupportsEndTime() && // and end clock entry
672 m_timerType
->IsTimerRule()) // but no associated start/end day spinners
674 if (m_endLocalTime
< m_startLocalTime
) // And the end clock is earlier than the start clock
676 CLog::LogFC(LOGDEBUG
, LOGPVR
, "End before start, adding a day.");
677 m_endLocalTime
+= CDateTimeSpan(1, 0, 0, 0);
678 if (m_endLocalTime
< m_startLocalTime
)
680 CLog::Log(LOGWARNING
,
681 "Timer settings dialog: End before start. Setting end time to start time.");
682 m_endLocalTime
= m_startLocalTime
;
685 else if (m_endLocalTime
>
686 (m_startLocalTime
+ CDateTimeSpan(1, 0, 0, 0))) // Or the duration is more than a day
688 CLog::LogFC(LOGDEBUG
, LOGPVR
, "End > 1 day after start, removing a day.");
689 m_endLocalTime
-= CDateTimeSpan(1, 0, 0, 0);
690 if (m_endLocalTime
> (m_startLocalTime
+ CDateTimeSpan(1, 0, 0, 0)))
694 "Timer settings dialog: End > 1 day after start. Setting end time to start time.");
695 m_endLocalTime
= m_startLocalTime
;
699 else if (m_endLocalTime
< m_startLocalTime
)
701 // this case will fail validation so this can't be reached.
703 m_timerInfoTag
->SetStartFromLocalTime(m_startLocalTime
);
704 m_timerInfoTag
->SetEndFromLocalTime(m_endLocalTime
);
706 else if (!m_bStartAnyTime
)
707 m_timerInfoTag
->SetStartFromLocalTime(m_startLocalTime
);
708 else if (!m_bEndAnyTime
)
709 m_timerInfoTag
->SetEndFromLocalTime(m_endLocalTime
);
711 // Days of week (only for timer rules)
712 if (m_timerType
->IsTimerRule())
713 m_timerInfoTag
->m_iWeekdays
= m_iWeekdays
;
715 m_timerInfoTag
->m_iWeekdays
= PVR_WEEKDAY_NONE
;
717 // First day (only for timer rules)
718 m_timerInfoTag
->SetFirstDayFromLocalTime(m_firstDayLocalTime
);
720 // "New episodes only" (only for timer rules)
721 m_timerInfoTag
->m_iPreventDupEpisodes
= m_iPreventDupEpisodes
;
723 // Pre and post record time
724 m_timerInfoTag
->m_iMarginStart
= m_iMarginStart
;
725 m_timerInfoTag
->m_iMarginEnd
= m_iMarginEnd
;
728 m_timerInfoTag
->m_iPriority
= m_iPriority
;
731 m_timerInfoTag
->m_iLifetime
= m_iLifetime
;
734 m_timerInfoTag
->m_iMaxRecordings
= m_iMaxRecordings
;
737 m_timerInfoTag
->m_strDirectory
= m_strDirectory
;
740 m_timerInfoTag
->m_iRecordingGroup
= m_iRecordingGroup
;
742 // Set the timer's title to the channel name if it's empty or 'New Timer'
743 if (m_strTitle
.empty() || m_strTitle
== g_localizeStrings
.Get(19056))
745 const std::string channelName
= m_timerInfoTag
->ChannelName();
746 if (!channelName
.empty())
747 m_timerInfoTag
->m_strTitle
= channelName
;
751 m_timerInfoTag
->UpdateSummary();
756 void CGUIDialogPVRTimerSettings::SetButtonLabels()
759 BaseSettingControlPtr settingControl
= GetSettingControl(SETTING_TMR_BEGIN
);
760 if (settingControl
!= NULL
&& settingControl
->GetControl() != NULL
)
762 SET_CONTROL_LABEL2(settingControl
->GetID(), m_timerStartTimeStr
);
766 settingControl
= GetSettingControl(SETTING_TMR_END
);
767 if (settingControl
!= NULL
&& settingControl
->GetControl() != NULL
)
769 SET_CONTROL_LABEL2(settingControl
->GetID(), m_timerEndTimeStr
);
773 void CGUIDialogPVRTimerSettings::AddCondition(const std::shared_ptr
<CSetting
>& setting
,
774 const std::string
& identifier
,
775 SettingConditionCheck condition
,
776 SettingDependencyType depType
,
777 const std::string
& settingId
)
779 GetSettingsManager()->AddDynamicCondition(identifier
, condition
, this);
780 CSettingDependency
dep(depType
, GetSettingsManager());
781 dep
.And()->Add(std::make_shared
<CSettingDependencyCondition
>(identifier
, "true", settingId
, false,
782 GetSettingsManager()));
783 SettingDependencies
deps(setting
->GetDependencies());
785 setting
->SetDependencies(deps
);
788 int CGUIDialogPVRTimerSettings::GetDateAsIndex(const CDateTime
& datetime
)
790 const CDateTime
date(datetime
.GetYear(), datetime
.GetMonth(), datetime
.GetDay(), 0, 0, 0);
793 return static_cast<int>(t
);
796 void CGUIDialogPVRTimerSettings::SetDateFromIndex(CDateTime
& datetime
, int date
)
798 const CDateTime
newDate(static_cast<time_t>(date
));
799 datetime
.SetDateTime(newDate
.GetYear(), newDate
.GetMonth(), newDate
.GetDay(), datetime
.GetHour(),
800 datetime
.GetMinute(), datetime
.GetSecond());
803 void CGUIDialogPVRTimerSettings::SetTimeFromSystemTime(CDateTime
& datetime
,
804 const KODI::TIME::SystemTime
& time
)
806 const CDateTime
newTime(time
);
807 datetime
.SetDateTime(datetime
.GetYear(), datetime
.GetMonth(), datetime
.GetDay(),
808 newTime
.GetHour(), newTime
.GetMinute(), newTime
.GetSecond());
811 void CGUIDialogPVRTimerSettings::InitializeTypesList()
813 m_typeEntries
.clear();
815 // If timer is read-only or was created by a timer rule, only add current type, for information. Type can't be changed.
816 if (m_timerType
->IsReadOnly() || m_timerInfoTag
->HasParent())
818 m_typeEntries
.insert(std::make_pair(0, m_timerType
));
822 bool bFoundThisType(false);
824 const std::vector
<std::shared_ptr
<CPVRTimerType
>> types(CPVRTimerType::GetAllTypes());
825 for (const auto& type
: types
)
827 // Type definition prohibits created of new instances.
828 // But the dialog can act as a viewer for these types.
829 if (type
->ForbidsNewInstances())
832 // Read-only timers cannot be created using this dialog.
833 // But the dialog can act as a viewer for read-only types.
834 if (type
->IsReadOnly())
837 // Drop TimerTypes that require EPGInfo, if none is populated
838 if (type
->RequiresEpgTagOnCreate() && !m_timerInfoTag
->GetEpgInfoTag())
841 // Drop TimerTypes without 'Series' EPG attributes if none are set
842 if (type
->RequiresEpgSeriesOnCreate())
844 const std::shared_ptr
<const CPVREpgInfoTag
> epgTag(m_timerInfoTag
->GetEpgInfoTag());
845 if (epgTag
&& !epgTag
->IsSeries())
849 // Drop TimerTypes which need series link if none is set
850 if (type
->RequiresEpgSeriesLinkOnCreate())
852 const std::shared_ptr
<const CPVREpgInfoTag
> epgTag(m_timerInfoTag
->GetEpgInfoTag());
853 if (!epgTag
|| epgTag
->SeriesLink().empty())
857 // Drop TimerTypes that forbid EPGInfo, if it is populated
858 if (type
->ForbidsEpgTagOnCreate() && m_timerInfoTag
->GetEpgInfoTag())
861 // Drop TimerTypes that aren't rules and cannot be recorded
862 if (!type
->IsTimerRule())
864 const std::shared_ptr
<const CPVREpgInfoTag
> epgTag(m_timerInfoTag
->GetEpgInfoTag());
865 bool bCanRecord
= epgTag
? epgTag
->IsRecordable()
866 : m_timerInfoTag
->EndAsLocalTime() > CDateTime::GetCurrentDateTime();
871 if (!bFoundThisType
&& *type
== *m_timerType
)
872 bFoundThisType
= true;
874 m_typeEntries
.insert(std::make_pair(idx
++, type
));
878 m_typeEntries
.insert(std::make_pair(idx
++, m_timerType
));
881 void CGUIDialogPVRTimerSettings::InitializeChannelsList()
883 m_channelEntries
.clear();
887 // Add special "any channel" entries - one for every client (used for epg-based timer rules).
888 const CPVRClientMap clients
= CServiceBroker::GetPVRManager().Clients()->GetCreatedClients();
889 for (const auto& client
: clients
)
891 m_channelEntries
.insert(
892 {index
, ChannelDescriptor(PVR_CHANNEL_INVALID_UID
, client
.second
->GetID(),
895 ? g_localizeStrings
.Get(809)
896 // Any channel from client "X"
897 : StringUtils::Format(g_localizeStrings
.Get(853),
898 client
.second
->GetFullClientName()))});
902 // Add regular channels
903 const std::shared_ptr
<const CPVRChannelGroup
> allGroup
=
904 CServiceBroker::GetPVRManager().ChannelGroups()->GetGroupAll(m_bIsRadio
);
905 const std::vector
<std::shared_ptr
<CPVRChannelGroupMember
>> groupMembers
=
906 allGroup
->GetMembers(CPVRChannelGroup::Include::ONLY_VISIBLE
);
907 for (const auto& groupMember
: groupMembers
)
909 const std::shared_ptr
<const CPVRChannel
> channel
= groupMember
->Channel();
910 const std::string channelDescription
= StringUtils::Format(
911 "{} {}", groupMember
->ChannelNumber().FormattedChannelNumber(), channel
->ChannelName());
912 m_channelEntries
.insert(
913 {index
, ChannelDescriptor(channel
->UniqueID(), channel
->ClientID(), channelDescription
)});
918 void CGUIDialogPVRTimerSettings::TypesFiller(const SettingConstPtr
& setting
,
919 std::vector
<IntegerSettingOption
>& list
,
923 CGUIDialogPVRTimerSettings
* pThis
= static_cast<CGUIDialogPVRTimerSettings
*>(data
);
929 static const std::vector
<std::pair
<std::string
, CVariant
>> reminderTimerProps
{
930 std::make_pair("PVR.IsRemindingTimer", CVariant
{true})};
931 static const std::vector
<std::pair
<std::string
, CVariant
>> recordingTimerProps
{
932 std::make_pair("PVR.IsRecordingTimer", CVariant
{true})};
934 const auto clients
= CServiceBroker::GetPVRManager().Clients();
936 bool foundCurrent(false);
937 for (const auto& typeEntry
: pThis
->m_typeEntries
)
939 std::string clientName
;
941 const auto client
= clients
->GetCreatedClient(typeEntry
.second
->GetClientId());
943 clientName
= client
->GetFullClientName();
945 list
.emplace_back(typeEntry
.second
->GetDescription(), clientName
, typeEntry
.first
,
946 typeEntry
.second
->IsReminder() ? reminderTimerProps
: recordingTimerProps
);
948 if (!foundCurrent
&& (*(pThis
->m_timerType
) == *(typeEntry
.second
)))
950 current
= typeEntry
.first
;
956 CLog::LogF(LOGERROR
, "No dialog");
959 void CGUIDialogPVRTimerSettings::ChannelsFiller(const SettingConstPtr
& setting
,
960 std::vector
<IntegerSettingOption
>& list
,
964 CGUIDialogPVRTimerSettings
* pThis
= static_cast<CGUIDialogPVRTimerSettings
*>(data
);
970 bool foundCurrent(false);
971 for (const auto& channelEntry
: pThis
->m_channelEntries
)
973 // Only include channels for the currently selected timer type or all channels if type is client-independent.
974 if (pThis
->m_timerType
->GetClientId() == -1 || // client-independent
975 pThis
->m_timerType
->GetClientId() == channelEntry
.second
.clientId
)
977 // Do not add "any channel" entry if not supported by selected timer type.
978 if (channelEntry
.second
.channelUid
== PVR_CHANNEL_INVALID_UID
&&
979 !pThis
->m_timerType
->SupportsAnyChannel())
982 list
.emplace_back(channelEntry
.second
.description
, channelEntry
.first
);
985 if (!foundCurrent
&& (pThis
->m_channel
== channelEntry
.second
))
987 current
= channelEntry
.first
;
994 // Verify m_channel is still valid. Update if not.
995 if (std::find_if(list
.cbegin(), list
.cend(),
996 [¤t
](const auto& channel
)
997 { return channel
.value
== current
; }) == list
.cend())
999 // Set m_channel and current to first valid channel in list
1000 const int first
{list
.front().value
};
1002 std::find_if(pThis
->m_channelEntries
.cbegin(), pThis
->m_channelEntries
.cend(),
1003 [first
](const auto& channel
) { return channel
.first
== first
; });
1005 if (it
!= pThis
->m_channelEntries
.cend())
1007 current
= (*it
).first
;
1008 pThis
->m_channel
= (*it
).second
;
1012 CLog::LogF(LOGERROR
, "Unable to find channel to select");
1018 CLog::LogF(LOGERROR
, "No dialog");
1021 void CGUIDialogPVRTimerSettings::DaysFiller(const SettingConstPtr
& setting
,
1022 std::vector
<IntegerSettingOption
>& list
,
1026 CGUIDialogPVRTimerSettings
* pThis
= static_cast<CGUIDialogPVRTimerSettings
*>(data
);
1032 // Data range: "today" until "yesterday next year"
1033 const CDateTime
now(CDateTime::GetCurrentDateTime());
1034 CDateTime
time(now
.GetYear(), now
.GetMonth(), now
.GetDay(), 0, 0, 0);
1035 const CDateTime
yesterdayPlusOneYear(CDateTime(time
.GetYear() + 1, time
.GetMonth(),
1036 time
.GetDay(), time
.GetHour(), time
.GetMinute(),
1038 CDateTimeSpan(1, 0, 0, 0));
1040 CDateTime oldCDateTime
;
1041 if (setting
->GetId() == SETTING_TMR_FIRST_DAY
)
1042 oldCDateTime
= pThis
->m_timerInfoTag
->FirstDayAsLocalTime();
1043 else if (setting
->GetId() == SETTING_TMR_START_DAY
)
1044 oldCDateTime
= pThis
->m_timerInfoTag
->StartAsLocalTime();
1046 oldCDateTime
= pThis
->m_timerInfoTag
->EndAsLocalTime();
1047 const CDateTime
oldCDate(oldCDateTime
.GetYear(), oldCDateTime
.GetMonth(), oldCDateTime
.GetDay(),
1050 if ((oldCDate
< time
) || (oldCDate
> yesterdayPlusOneYear
))
1051 list
.emplace_back(oldCDate
.GetAsLocalizedDate(true /*long date*/), GetDateAsIndex(oldCDate
));
1053 while (time
<= yesterdayPlusOneYear
)
1055 list
.emplace_back(time
.GetAsLocalizedDate(true /*long date*/), GetDateAsIndex(time
));
1056 time
+= CDateTimeSpan(1, 0, 0, 0);
1059 if (setting
->GetId() == SETTING_TMR_FIRST_DAY
)
1060 current
= GetDateAsIndex(pThis
->m_firstDayLocalTime
);
1061 else if (setting
->GetId() == SETTING_TMR_START_DAY
)
1062 current
= GetDateAsIndex(pThis
->m_startLocalTime
);
1064 current
= GetDateAsIndex(pThis
->m_endLocalTime
);
1067 CLog::LogF(LOGERROR
, "No dialog");
1070 void CGUIDialogPVRTimerSettings::DupEpisodesFiller(const SettingConstPtr
& setting
,
1071 std::vector
<IntegerSettingOption
>& list
,
1075 CGUIDialogPVRTimerSettings
* pThis
= static_cast<CGUIDialogPVRTimerSettings
*>(data
);
1080 std::vector
<std::pair
<std::string
, int>> values
;
1081 pThis
->m_timerType
->GetPreventDuplicateEpisodesValues(values
);
1082 std::transform(values
.cbegin(), values
.cend(), std::back_inserter(list
), [](const auto& value
) {
1083 return IntegerSettingOption(value
.first
, value
.second
);
1086 current
= pThis
->m_iPreventDupEpisodes
;
1089 CLog::LogF(LOGERROR
, "No dialog");
1092 void CGUIDialogPVRTimerSettings::WeekdaysFiller(const SettingConstPtr
& setting
,
1093 std::vector
<IntegerSettingOption
>& list
,
1097 CGUIDialogPVRTimerSettings
* pThis
= static_cast<CGUIDialogPVRTimerSettings
*>(data
);
1101 list
.emplace_back(g_localizeStrings
.Get(831), PVR_WEEKDAY_MONDAY
); // "Mondays"
1102 list
.emplace_back(g_localizeStrings
.Get(832), PVR_WEEKDAY_TUESDAY
); // "Tuesdays"
1103 list
.emplace_back(g_localizeStrings
.Get(833), PVR_WEEKDAY_WEDNESDAY
); // "Wednesdays"
1104 list
.emplace_back(g_localizeStrings
.Get(834), PVR_WEEKDAY_THURSDAY
); // "Thursdays"
1105 list
.emplace_back(g_localizeStrings
.Get(835), PVR_WEEKDAY_FRIDAY
); // "Fridays"
1106 list
.emplace_back(g_localizeStrings
.Get(836), PVR_WEEKDAY_SATURDAY
); // "Saturdays"
1107 list
.emplace_back(g_localizeStrings
.Get(837), PVR_WEEKDAY_SUNDAY
); // "Sundays"
1109 current
= pThis
->m_iWeekdays
;
1112 CLog::LogF(LOGERROR
, "No dialog");
1115 void CGUIDialogPVRTimerSettings::PrioritiesFiller(const SettingConstPtr
& setting
,
1116 std::vector
<IntegerSettingOption
>& list
,
1120 CGUIDialogPVRTimerSettings
* pThis
= static_cast<CGUIDialogPVRTimerSettings
*>(data
);
1125 std::vector
<std::pair
<std::string
, int>> values
;
1126 pThis
->m_timerType
->GetPriorityValues(values
);
1127 std::transform(values
.cbegin(), values
.cend(), std::back_inserter(list
), [](const auto& value
) {
1128 return IntegerSettingOption(value
.first
, value
.second
);
1131 current
= pThis
->m_iPriority
;
1133 auto it
= list
.begin();
1134 while (it
!= list
.end())
1136 if (it
->value
== current
)
1137 break; // value already in list
1142 if (it
== list
.end())
1144 // PVR backend supplied value is not in the list of predefined values. Insert it.
1145 list
.insert(it
, IntegerSettingOption(std::to_string(current
), current
));
1149 CLog::LogF(LOGERROR
, "No dialog");
1152 void CGUIDialogPVRTimerSettings::LifetimesFiller(const SettingConstPtr
& setting
,
1153 std::vector
<IntegerSettingOption
>& list
,
1157 CGUIDialogPVRTimerSettings
* pThis
= static_cast<CGUIDialogPVRTimerSettings
*>(data
);
1162 std::vector
<std::pair
<std::string
, int>> values
;
1163 pThis
->m_timerType
->GetLifetimeValues(values
);
1164 std::transform(values
.cbegin(), values
.cend(), std::back_inserter(list
), [](const auto& value
) {
1165 return IntegerSettingOption(value
.first
, value
.second
);
1168 current
= pThis
->m_iLifetime
;
1170 auto it
= list
.begin();
1171 while (it
!= list
.end())
1173 if (it
->value
== current
)
1174 break; // value already in list
1179 if (it
== list
.end())
1181 // PVR backend supplied value is not in the list of predefined values. Insert it.
1182 list
.insert(it
, IntegerSettingOption(
1183 StringUtils::Format(g_localizeStrings
.Get(17999), current
) /* {} days */,
1188 CLog::LogF(LOGERROR
, "No dialog");
1191 void CGUIDialogPVRTimerSettings::MaxRecordingsFiller(const SettingConstPtr
& setting
,
1192 std::vector
<IntegerSettingOption
>& list
,
1196 CGUIDialogPVRTimerSettings
* pThis
= static_cast<CGUIDialogPVRTimerSettings
*>(data
);
1201 std::vector
<std::pair
<std::string
, int>> values
;
1202 pThis
->m_timerType
->GetMaxRecordingsValues(values
);
1203 std::transform(values
.cbegin(), values
.cend(), std::back_inserter(list
), [](const auto& value
) {
1204 return IntegerSettingOption(value
.first
, value
.second
);
1207 current
= pThis
->m_iMaxRecordings
;
1209 auto it
= list
.begin();
1210 while (it
!= list
.end())
1212 if (it
->value
== current
)
1213 break; // value already in list
1218 if (it
== list
.end())
1220 // PVR backend supplied value is not in the list of predefined values. Insert it.
1221 list
.insert(it
, IntegerSettingOption(std::to_string(current
), current
));
1225 CLog::LogF(LOGERROR
, "No dialog");
1228 void CGUIDialogPVRTimerSettings::RecordingGroupFiller(const SettingConstPtr
& setting
,
1229 std::vector
<IntegerSettingOption
>& list
,
1233 CGUIDialogPVRTimerSettings
* pThis
= static_cast<CGUIDialogPVRTimerSettings
*>(data
);
1238 std::vector
<std::pair
<std::string
, int>> values
;
1239 pThis
->m_timerType
->GetRecordingGroupValues(values
);
1240 std::transform(values
.cbegin(), values
.cend(), std::back_inserter(list
), [](const auto& value
) {
1241 return IntegerSettingOption(value
.first
, value
.second
);
1244 current
= pThis
->m_iRecordingGroup
;
1247 CLog::LogF(LOGERROR
, "No dialog");
1250 void CGUIDialogPVRTimerSettings::MarginTimeFiller(const SettingConstPtr
& setting
,
1251 std::vector
<IntegerSettingOption
>& list
,
1255 CGUIDialogPVRTimerSettings
* pThis
= static_cast<CGUIDialogPVRTimerSettings
*>(data
);
1260 // Get global settings values
1261 CPVRSettings::MarginTimeFiller(setting
, list
, current
, data
);
1263 if (setting
->GetId() == SETTING_TMR_BEGIN_PRE
)
1264 current
= pThis
->m_iMarginStart
;
1266 current
= pThis
->m_iMarginEnd
;
1268 bool bInsertValue
= true;
1269 auto it
= list
.begin();
1270 while (it
!= list
.end())
1272 if (it
->value
== current
)
1274 bInsertValue
= false;
1275 break; // value already in list
1278 if (it
->value
> current
)
1286 // PVR backend supplied value is not in the list of predefined values. Insert it.
1287 list
.insert(it
, IntegerSettingOption(
1288 StringUtils::Format(g_localizeStrings
.Get(14044), current
) /* {} min */,
1293 CLog::LogF(LOGERROR
, "No dialog");
1296 std::string
CGUIDialogPVRTimerSettings::WeekdaysValueFormatter(const SettingConstPtr
& setting
)
1298 return CPVRTimerInfoTag::GetWeekdaysString(GetWeekdaysFromSetting(setting
), true, true);
1301 void CGUIDialogPVRTimerSettings::AddTypeDependentEnableCondition(
1302 const std::shared_ptr
<CSetting
>& setting
, const std::string
& identifier
)
1304 // Enable setting depending on read-only attribute of the selected timer type
1305 std::string
id(identifier
);
1306 id
.append(TYPE_DEP_ENABLE_COND_ID_POSTFIX
);
1307 AddCondition(setting
, id
, TypeReadOnlyCondition
, SettingDependencyType::Enable
, SETTING_TMR_TYPE
);
1310 bool CGUIDialogPVRTimerSettings::TypeReadOnlyCondition(const std::string
& condition
,
1311 const std::string
& value
,
1312 const SettingConstPtr
& setting
,
1315 if (setting
== NULL
)
1318 CGUIDialogPVRTimerSettings
* pThis
= static_cast<CGUIDialogPVRTimerSettings
*>(data
);
1321 CLog::LogF(LOGERROR
, "No dialog");
1325 if (!StringUtils::EqualsNoCase(value
, "true"))
1328 std::string
cond(condition
);
1329 cond
.erase(cond
.find(TYPE_DEP_ENABLE_COND_ID_POSTFIX
));
1331 // If only one type is available, disable type selector.
1332 if (pThis
->m_typeEntries
.size() == 1)
1334 if (cond
== SETTING_TMR_TYPE
)
1338 // For existing one time epg-based timers, disable editing of epg-filled data.
1339 if (!pThis
->m_bIsNewTimer
&& pThis
->m_timerType
->IsEpgBasedOnetime())
1341 if ((cond
== SETTING_TMR_NAME
) || (cond
== SETTING_TMR_CHANNEL
) ||
1342 (cond
== SETTING_TMR_START_DAY
) || (cond
== SETTING_TMR_END_DAY
) ||
1343 (cond
== SETTING_TMR_BEGIN
) || (cond
== SETTING_TMR_END
))
1347 /* Always enable enable/disable, if supported by the timer type. */
1348 if (pThis
->m_timerType
->SupportsEnableDisable() && !pThis
->m_timerInfoTag
->IsBroken())
1350 if (cond
== SETTING_TMR_ACTIVE
)
1354 // Let the PVR client decide...
1355 int idx
= std::static_pointer_cast
<const CSettingInt
>(setting
)->GetValue();
1356 const auto entry
= pThis
->m_typeEntries
.find(idx
);
1357 if (entry
!= pThis
->m_typeEntries
.end())
1358 return !entry
->second
->IsReadOnly();
1360 CLog::LogF(LOGERROR
, "No type entry");
1365 void CGUIDialogPVRTimerSettings::AddTypeDependentVisibilityCondition(
1366 const std::shared_ptr
<CSetting
>& setting
, const std::string
& identifier
)
1368 // Show or hide setting depending on attributes of the selected timer type
1369 std::string
id(identifier
);
1370 id
.append(TYPE_DEP_VISIBI_COND_ID_POSTFIX
);
1371 AddCondition(setting
, id
, TypeSupportsCondition
, SettingDependencyType::Visible
,
1375 bool CGUIDialogPVRTimerSettings::TypeSupportsCondition(const std::string
& condition
,
1376 const std::string
& value
,
1377 const SettingConstPtr
& setting
,
1380 if (setting
== NULL
)
1383 CGUIDialogPVRTimerSettings
* pThis
= static_cast<CGUIDialogPVRTimerSettings
*>(data
);
1386 CLog::LogF(LOGERROR
, "No dialog");
1390 if (!StringUtils::EqualsNoCase(value
, "true"))
1393 int idx
= std::static_pointer_cast
<const CSettingInt
>(setting
)->GetValue();
1394 const auto entry
= pThis
->m_typeEntries
.find(idx
);
1395 if (entry
!= pThis
->m_typeEntries
.end())
1397 std::string
cond(condition
);
1398 cond
.erase(cond
.find(TYPE_DEP_VISIBI_COND_ID_POSTFIX
));
1400 if (cond
== SETTING_TMR_EPGSEARCH
)
1401 return entry
->second
->SupportsEpgTitleMatch() || entry
->second
->SupportsEpgFulltextMatch();
1402 else if (cond
== SETTING_TMR_FULLTEXT
)
1403 return entry
->second
->SupportsEpgFulltextMatch();
1404 else if (cond
== SETTING_TMR_ACTIVE
)
1405 return entry
->second
->SupportsEnableDisable();
1406 else if (cond
== SETTING_TMR_CHANNEL
)
1407 return entry
->second
->SupportsChannels();
1408 else if (cond
== SETTING_TMR_START_ANYTIME
)
1409 return entry
->second
->SupportsStartAnyTime() && entry
->second
->IsEpgBased();
1410 else if (cond
== SETTING_TMR_END_ANYTIME
)
1411 return entry
->second
->SupportsEndAnyTime() && entry
->second
->IsEpgBased();
1412 else if (cond
== SETTING_TMR_START_DAY
)
1413 return entry
->second
->SupportsStartTime() && entry
->second
->IsOnetime();
1414 else if (cond
== SETTING_TMR_END_DAY
)
1415 return entry
->second
->SupportsEndTime() && entry
->second
->IsOnetime();
1416 else if (cond
== SETTING_TMR_BEGIN
)
1417 return entry
->second
->SupportsStartTime();
1418 else if (cond
== SETTING_TMR_END
)
1419 return entry
->second
->SupportsEndTime();
1420 else if (cond
== SETTING_TMR_WEEKDAYS
)
1421 return entry
->second
->SupportsWeekdays();
1422 else if (cond
== SETTING_TMR_FIRST_DAY
)
1423 return entry
->second
->SupportsFirstDay();
1424 else if (cond
== SETTING_TMR_NEW_EPISODES
)
1425 return entry
->second
->SupportsRecordOnlyNewEpisodes();
1426 else if (cond
== SETTING_TMR_BEGIN_PRE
)
1427 return entry
->second
->SupportsStartMargin();
1428 else if (cond
== SETTING_TMR_END_POST
)
1429 return entry
->second
->SupportsEndMargin();
1430 else if (cond
== SETTING_TMR_PRIORITY
)
1431 return entry
->second
->SupportsPriority();
1432 else if (cond
== SETTING_TMR_LIFETIME
)
1433 return entry
->second
->SupportsLifetime();
1434 else if (cond
== SETTING_TMR_MAX_REC
)
1435 return entry
->second
->SupportsMaxRecordings();
1436 else if (cond
== SETTING_TMR_DIR
)
1437 return entry
->second
->SupportsRecordingFolders();
1438 else if (cond
== SETTING_TMR_REC_GROUP
)
1439 return entry
->second
->SupportsRecordingGroup();
1441 CLog::LogF(LOGERROR
, "Unknown condition");
1445 CLog::LogF(LOGERROR
, "No type entry");
1450 void CGUIDialogPVRTimerSettings::AddStartAnytimeDependentVisibilityCondition(
1451 const std::shared_ptr
<CSetting
>& setting
, const std::string
& identifier
)
1453 // Show or hide setting depending on value of setting "any time"
1454 std::string
id(identifier
);
1455 id
.append(START_ANYTIME_DEP_VISIBI_COND_ID_POSTFIX
);
1456 AddCondition(setting
, id
, StartAnytimeSetCondition
, SettingDependencyType::Visible
,
1457 SETTING_TMR_START_ANYTIME
);
1460 bool CGUIDialogPVRTimerSettings::StartAnytimeSetCondition(const std::string
& condition
,
1461 const std::string
& value
,
1462 const SettingConstPtr
& setting
,
1465 if (setting
== NULL
)
1468 CGUIDialogPVRTimerSettings
* pThis
= static_cast<CGUIDialogPVRTimerSettings
*>(data
);
1471 CLog::LogF(LOGERROR
, "No dialog");
1475 if (!StringUtils::EqualsNoCase(value
, "true"))
1478 // "any time" setting is only relevant for epg-based timers.
1479 if (!pThis
->m_timerType
->IsEpgBased())
1482 // If 'Start anytime' option isn't supported, don't hide start time
1483 if (!pThis
->m_timerType
->SupportsStartAnyTime())
1486 std::string
cond(condition
);
1487 cond
.erase(cond
.find(START_ANYTIME_DEP_VISIBI_COND_ID_POSTFIX
));
1489 if ((cond
== SETTING_TMR_START_DAY
) || (cond
== SETTING_TMR_BEGIN
))
1491 bool bAnytime
= std::static_pointer_cast
<const CSettingBool
>(setting
)->GetValue();
1497 void CGUIDialogPVRTimerSettings::AddEndAnytimeDependentVisibilityCondition(
1498 const std::shared_ptr
<CSetting
>& setting
, const std::string
& identifier
)
1500 // Show or hide setting depending on value of setting "any time"
1501 std::string
id(identifier
);
1502 id
.append(END_ANYTIME_DEP_VISIBI_COND_ID_POSTFIX
);
1503 AddCondition(setting
, id
, EndAnytimeSetCondition
, SettingDependencyType::Visible
,
1504 SETTING_TMR_END_ANYTIME
);
1507 bool CGUIDialogPVRTimerSettings::EndAnytimeSetCondition(const std::string
& condition
,
1508 const std::string
& value
,
1509 const SettingConstPtr
& setting
,
1512 if (setting
== NULL
)
1515 CGUIDialogPVRTimerSettings
* pThis
= static_cast<CGUIDialogPVRTimerSettings
*>(data
);
1518 CLog::LogF(LOGERROR
, "No dialog");
1522 if (!StringUtils::EqualsNoCase(value
, "true"))
1525 // "any time" setting is only relevant for epg-based timers.
1526 if (!pThis
->m_timerType
->IsEpgBased())
1529 // If 'End anytime' option isn't supported, don't hide end time
1530 if (!pThis
->m_timerType
->SupportsEndAnyTime())
1533 std::string
cond(condition
);
1534 cond
.erase(cond
.find(END_ANYTIME_DEP_VISIBI_COND_ID_POSTFIX
));
1536 if ((cond
== SETTING_TMR_END_DAY
) || (cond
== SETTING_TMR_END
))
1538 bool bAnytime
= std::static_pointer_cast
<const CSettingBool
>(setting
)->GetValue();