[Windows] Fix driver version detection of AMD RDNA+ GPU on Windows 10
[xbmc.git] / xbmc / pvr / dialogs / GUIDialogPVRTimerSettings.cpp
blob9ff3dbb6b22c3af239eef3503defa235f7b161e7
1 /*
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.
7 */
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"
35 #include <algorithm>
36 #include <iterator>
37 #include <memory>
38 #include <string>
39 #include <utility>
40 #include <vector>
42 using namespace PVR;
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
85 if (!m_timerInfoTag)
87 CLog::LogF(LOGERROR, "No timer info tag");
88 return false;
90 return true;
93 void CGUIDialogPVRTimerSettings::SetTimer(const std::shared_ptr<CPVRTimerInfoTag>& timer)
95 if (!timer)
97 CLog::LogF(LOGERROR, "No timer given");
98 return;
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);
109 m_bStartAnyTime =
110 m_bIsNewTimer || !m_timerType->SupportsStartAnyTime() || m_timerInfoTag->m_bStartAnyTime;
111 m_bEndAnyTime =
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;
142 else
143 m_strDirectory = m_timerInfoTag->m_strDirectory;
145 m_iRecordingGroup = m_timerInfoTag->m_iRecordingGroup;
147 InitializeChannelsList();
148 InitializeTypesList();
150 // Channel
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;
168 else
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;
186 else
188 CLog::LogF(LOGERROR, "Unable to map PVR_CHANNEL_INVALID_UID to channel entry!");
192 else
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;
205 else
207 CLog::LogF(LOGERROR, "Unable to map channel uid to channel entry!");
212 void CGUIDialogPVRTimerSettings::SetupView()
214 CGUIDialogSettingsManualBase::SetupView();
215 SetHeading(19065);
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);
219 SetButtonLabels();
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");
230 return;
233 const std::shared_ptr<CSettingGroup> group = AddGroup(category);
234 if (group == NULL)
236 CLog::LogF(LOGERROR, "Unable to add settings group");
237 return;
240 std::shared_ptr<CSetting> setting = NULL;
242 // Timer type
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
254 useDetails = true;
255 break;
257 foundClientSupportingTimers = true;
261 setting = AddList(group, SETTING_TMR_TYPE, 803, SettingLevel::Basic, 0, TypesFiller, 803, true,
262 -1, useDetails);
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);
270 // Name
271 setting =
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,
277 true, false, 805);
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);
286 // Channel
287 setting =
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);
373 // Priority
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);
379 // Lifetime
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);
385 // MaxRecordings
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);
391 // Recording folder
392 setting = AddEdit(group, SETTING_TMR_DIR, 19076, SettingLevel::Basic, m_strDirectory, true, false,
393 19104);
394 AddTypeDependentVisibilityCondition(setting, SETTING_TMR_DIR);
395 AddTypeDependentEnableCondition(setting, SETTING_TMR_DIR);
397 // Recording group
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");
411 return 0;
413 int weekdays = 0;
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");
420 return 0;
422 weekdays += static_cast<int>(value.asInteger());
425 return weekdays;
428 void CGUIDialogPVRTimerSettings::OnSettingChanged(const std::shared_ptr<const CSetting>& setting)
430 if (setting == NULL)
432 CLog::LogF(LOGERROR, "No setting");
433 return;
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"
468 else
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;
497 else
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)
565 if (setting == NULL)
567 CLog::LogF(LOGERROR, "No setting");
568 return;
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);
582 SetButtonLabels();
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);
593 SetButtonLabels();
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())
603 return true;
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
624 return false;
628 return true;
631 bool CGUIDialogPVRTimerSettings::Save()
633 if (!Validate())
634 return false;
636 // Timer type
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;
642 // Name
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;
651 // Channel
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)))
692 CLog::Log(
693 LOGWARNING,
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;
714 else
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;
727 // Priority
728 m_timerInfoTag->m_iPriority = m_iPriority;
730 // Lifetime
731 m_timerInfoTag->m_iLifetime = m_iLifetime;
733 // MaxRecordings
734 m_timerInfoTag->m_iMaxRecordings = m_iMaxRecordings;
736 // Recording folder
737 m_timerInfoTag->m_strDirectory = m_strDirectory;
739 // Recording group
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;
750 // Update summary
751 m_timerInfoTag->UpdateSummary();
753 return true;
756 void CGUIDialogPVRTimerSettings::SetButtonLabels()
758 // timer start time
759 BaseSettingControlPtr settingControl = GetSettingControl(SETTING_TMR_BEGIN);
760 if (settingControl != NULL && settingControl->GetControl() != NULL)
762 SET_CONTROL_LABEL2(settingControl->GetID(), m_timerStartTimeStr);
765 // timer end time
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());
784 deps.push_back(dep);
785 setting->SetDependencies(deps);
788 int CGUIDialogPVRTimerSettings::GetDateAsIndex(const CDateTime& datetime)
790 const CDateTime date(datetime.GetYear(), datetime.GetMonth(), datetime.GetDay(), 0, 0, 0);
791 time_t t(0);
792 date.GetAsTime(t);
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));
819 return;
822 bool bFoundThisType(false);
823 int idx(0);
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())
830 continue;
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())
835 continue;
837 // Drop TimerTypes that require EPGInfo, if none is populated
838 if (type->RequiresEpgTagOnCreate() && !m_timerInfoTag->GetEpgInfoTag())
839 continue;
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())
846 continue;
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())
854 continue;
857 // Drop TimerTypes that forbid EPGInfo, if it is populated
858 if (type->ForbidsEpgTagOnCreate() && m_timerInfoTag->GetEpgInfoTag())
859 continue;
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();
867 if (!bCanRecord)
868 continue;
871 if (!bFoundThisType && *type == *m_timerType)
872 bFoundThisType = true;
874 m_typeEntries.insert(std::make_pair(idx++, type));
877 if (!bFoundThisType)
878 m_typeEntries.insert(std::make_pair(idx++, m_timerType));
881 void CGUIDialogPVRTimerSettings::InitializeChannelsList()
883 m_channelEntries.clear();
885 int index = 0;
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(),
893 clients.size() == 1
894 // Any channel
895 ? g_localizeStrings.Get(809)
896 // Any channel from client "X"
897 : StringUtils::Format(g_localizeStrings.Get(853),
898 client.second->GetFullClientName()))});
899 ++index;
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)});
914 ++index;
918 void CGUIDialogPVRTimerSettings::TypesFiller(const SettingConstPtr& setting,
919 std::vector<IntegerSettingOption>& list,
920 int& current,
921 void* data)
923 CGUIDialogPVRTimerSettings* pThis = static_cast<CGUIDialogPVRTimerSettings*>(data);
924 if (pThis)
926 list.clear();
927 current = 0;
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());
942 if (client)
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;
951 foundCurrent = true;
955 else
956 CLog::LogF(LOGERROR, "No dialog");
959 void CGUIDialogPVRTimerSettings::ChannelsFiller(const SettingConstPtr& setting,
960 std::vector<IntegerSettingOption>& list,
961 int& current,
962 void* data)
964 CGUIDialogPVRTimerSettings* pThis = static_cast<CGUIDialogPVRTimerSettings*>(data);
965 if (pThis)
967 list.clear();
968 current = 0;
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())
980 continue;
982 list.emplace_back(channelEntry.second.description, channelEntry.first);
985 if (!foundCurrent && (pThis->m_channel == channelEntry.second))
987 current = channelEntry.first;
988 foundCurrent = true;
992 if (foundCurrent)
994 // Verify m_channel is still valid. Update if not.
995 if (std::find_if(list.cbegin(), list.cend(),
996 [&current](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};
1001 const auto it =
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;
1010 else
1012 CLog::LogF(LOGERROR, "Unable to find channel to select");
1017 else
1018 CLog::LogF(LOGERROR, "No dialog");
1021 void CGUIDialogPVRTimerSettings::DaysFiller(const SettingConstPtr& setting,
1022 std::vector<IntegerSettingOption>& list,
1023 int& current,
1024 void* data)
1026 CGUIDialogPVRTimerSettings* pThis = static_cast<CGUIDialogPVRTimerSettings*>(data);
1027 if (pThis)
1029 list.clear();
1030 current = 0;
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(),
1037 time.GetSecond()) -
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();
1045 else
1046 oldCDateTime = pThis->m_timerInfoTag->EndAsLocalTime();
1047 const CDateTime oldCDate(oldCDateTime.GetYear(), oldCDateTime.GetMonth(), oldCDateTime.GetDay(),
1048 0, 0, 0);
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);
1063 else
1064 current = GetDateAsIndex(pThis->m_endLocalTime);
1066 else
1067 CLog::LogF(LOGERROR, "No dialog");
1070 void CGUIDialogPVRTimerSettings::DupEpisodesFiller(const SettingConstPtr& setting,
1071 std::vector<IntegerSettingOption>& list,
1072 int& current,
1073 void* data)
1075 CGUIDialogPVRTimerSettings* pThis = static_cast<CGUIDialogPVRTimerSettings*>(data);
1076 if (pThis)
1078 list.clear();
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;
1088 else
1089 CLog::LogF(LOGERROR, "No dialog");
1092 void CGUIDialogPVRTimerSettings::WeekdaysFiller(const SettingConstPtr& setting,
1093 std::vector<IntegerSettingOption>& list,
1094 int& current,
1095 void* data)
1097 CGUIDialogPVRTimerSettings* pThis = static_cast<CGUIDialogPVRTimerSettings*>(data);
1098 if (pThis)
1100 list.clear();
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;
1111 else
1112 CLog::LogF(LOGERROR, "No dialog");
1115 void CGUIDialogPVRTimerSettings::PrioritiesFiller(const SettingConstPtr& setting,
1116 std::vector<IntegerSettingOption>& list,
1117 int& current,
1118 void* data)
1120 CGUIDialogPVRTimerSettings* pThis = static_cast<CGUIDialogPVRTimerSettings*>(data);
1121 if (pThis)
1123 list.clear();
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
1139 ++it;
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));
1148 else
1149 CLog::LogF(LOGERROR, "No dialog");
1152 void CGUIDialogPVRTimerSettings::LifetimesFiller(const SettingConstPtr& setting,
1153 std::vector<IntegerSettingOption>& list,
1154 int& current,
1155 void* data)
1157 CGUIDialogPVRTimerSettings* pThis = static_cast<CGUIDialogPVRTimerSettings*>(data);
1158 if (pThis)
1160 list.clear();
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
1176 ++it;
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 */,
1184 current));
1187 else
1188 CLog::LogF(LOGERROR, "No dialog");
1191 void CGUIDialogPVRTimerSettings::MaxRecordingsFiller(const SettingConstPtr& setting,
1192 std::vector<IntegerSettingOption>& list,
1193 int& current,
1194 void* data)
1196 CGUIDialogPVRTimerSettings* pThis = static_cast<CGUIDialogPVRTimerSettings*>(data);
1197 if (pThis)
1199 list.clear();
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
1215 ++it;
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));
1224 else
1225 CLog::LogF(LOGERROR, "No dialog");
1228 void CGUIDialogPVRTimerSettings::RecordingGroupFiller(const SettingConstPtr& setting,
1229 std::vector<IntegerSettingOption>& list,
1230 int& current,
1231 void* data)
1233 CGUIDialogPVRTimerSettings* pThis = static_cast<CGUIDialogPVRTimerSettings*>(data);
1234 if (pThis)
1236 list.clear();
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;
1246 else
1247 CLog::LogF(LOGERROR, "No dialog");
1250 void CGUIDialogPVRTimerSettings::MarginTimeFiller(const SettingConstPtr& setting,
1251 std::vector<IntegerSettingOption>& list,
1252 int& current,
1253 void* data)
1255 CGUIDialogPVRTimerSettings* pThis = static_cast<CGUIDialogPVRTimerSettings*>(data);
1256 if (pThis)
1258 list.clear();
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;
1265 else
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)
1279 break;
1281 ++it;
1284 if (bInsertValue)
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 */,
1289 current));
1292 else
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,
1313 void* data)
1315 if (setting == NULL)
1316 return false;
1318 CGUIDialogPVRTimerSettings* pThis = static_cast<CGUIDialogPVRTimerSettings*>(data);
1319 if (pThis == NULL)
1321 CLog::LogF(LOGERROR, "No dialog");
1322 return false;
1325 if (!StringUtils::EqualsNoCase(value, "true"))
1326 return false;
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)
1335 return false;
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))
1344 return false;
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)
1351 return true;
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();
1359 else
1360 CLog::LogF(LOGERROR, "No type entry");
1362 return false;
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,
1372 SETTING_TMR_TYPE);
1375 bool CGUIDialogPVRTimerSettings::TypeSupportsCondition(const std::string& condition,
1376 const std::string& value,
1377 const SettingConstPtr& setting,
1378 void* data)
1380 if (setting == NULL)
1381 return false;
1383 CGUIDialogPVRTimerSettings* pThis = static_cast<CGUIDialogPVRTimerSettings*>(data);
1384 if (pThis == NULL)
1386 CLog::LogF(LOGERROR, "No dialog");
1387 return false;
1390 if (!StringUtils::EqualsNoCase(value, "true"))
1391 return false;
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();
1440 else
1441 CLog::LogF(LOGERROR, "Unknown condition");
1443 else
1445 CLog::LogF(LOGERROR, "No type entry");
1447 return false;
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,
1463 void* data)
1465 if (setting == NULL)
1466 return false;
1468 CGUIDialogPVRTimerSettings* pThis = static_cast<CGUIDialogPVRTimerSettings*>(data);
1469 if (pThis == NULL)
1471 CLog::LogF(LOGERROR, "No dialog");
1472 return false;
1475 if (!StringUtils::EqualsNoCase(value, "true"))
1476 return false;
1478 // "any time" setting is only relevant for epg-based timers.
1479 if (!pThis->m_timerType->IsEpgBased())
1480 return true;
1482 // If 'Start anytime' option isn't supported, don't hide start time
1483 if (!pThis->m_timerType->SupportsStartAnyTime())
1484 return true;
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();
1492 return !bAnytime;
1494 return false;
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,
1510 void* data)
1512 if (setting == NULL)
1513 return false;
1515 CGUIDialogPVRTimerSettings* pThis = static_cast<CGUIDialogPVRTimerSettings*>(data);
1516 if (pThis == NULL)
1518 CLog::LogF(LOGERROR, "No dialog");
1519 return false;
1522 if (!StringUtils::EqualsNoCase(value, "true"))
1523 return false;
1525 // "any time" setting is only relevant for epg-based timers.
1526 if (!pThis->m_timerType->IsEpgBased())
1527 return true;
1529 // If 'End anytime' option isn't supported, don't hide end time
1530 if (!pThis->m_timerType->SupportsEndAnyTime())
1531 return true;
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();
1539 return !bAnytime;
1541 return false;