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 "GUIDialogPVRGuideSearch.h"
11 #include "ServiceBroker.h"
12 #include "guilib/GUIEditControl.h"
13 #include "guilib/GUIKeyboardFactory.h"
14 #include "guilib/GUIMessage.h"
15 #include "guilib/LocalizeStrings.h"
16 #include "pvr/PVRManager.h"
17 #include "pvr/channels/PVRChannel.h"
18 #include "pvr/channels/PVRChannelGroupMember.h"
19 #include "pvr/channels/PVRChannelGroups.h"
20 #include "pvr/channels/PVRChannelGroupsContainer.h"
21 #include "pvr/epg/EpgContainer.h"
22 #include "pvr/epg/EpgSearchFilter.h"
23 #include "utils/StringUtils.h"
31 #define CONTROL_EDIT_SEARCH 9
32 #define CONTROL_BTN_INC_DESC 10
33 #define CONTROL_BTN_CASE_SENS 11
34 #define CONTROL_SPIN_MIN_DURATION 12
35 #define CONTROL_SPIN_MAX_DURATION 13
36 #define CONTROL_EDIT_START_DATE 14
37 #define CONTROL_EDIT_STOP_DATE 15
38 #define CONTROL_EDIT_START_TIME 16
39 #define CONTROL_EDIT_STOP_TIME 17
40 #define CONTROL_SPIN_GENRE 18
41 #define CONTROL_SPIN_NO_REPEATS 19
42 #define CONTROL_BTN_UNK_GENRE 20
43 #define CONTROL_SPIN_GROUPS 21
44 #define CONTROL_BTN_FTA_ONLY 22
45 #define CONTROL_SPIN_CHANNELS 23
46 #define CONTROL_BTN_IGNORE_TMR 24
47 #define CONTROL_BTN_CANCEL 25
48 #define CONTROL_BTN_SEARCH 26
49 #define CONTROL_BTN_IGNORE_REC 27
50 #define CONTROL_BTN_DEFAULTS 28
51 static constexpr int CONTROL_BTN_SAVE
= 29;
52 static constexpr int CONTROL_BTN_IGNORE_FINISHED
= 30;
53 static constexpr int CONTROL_BTN_IGNORE_FUTURE
= 31;
54 static constexpr int CONTROL_BTN_START_ANY_TIME
= 32;
55 static constexpr int CONTROL_BTN_END_ANY_TIME
= 33;
57 CGUIDialogPVRGuideSearch::CGUIDialogPVRGuideSearch()
58 : CGUIDialog(WINDOW_DIALOG_PVR_GUIDE_SEARCH
, "DialogPVRGuideSearch.xml")
62 void CGUIDialogPVRGuideSearch::SetFilterData(
63 const std::shared_ptr
<CPVREpgSearchFilter
>& searchFilter
)
65 m_searchFilter
= searchFilter
;
68 void CGUIDialogPVRGuideSearch::UpdateChannelSpin()
70 int iChannelGroup
= GetSpinValue(CONTROL_SPIN_GROUPS
);
72 std::vector
< std::pair
<std::string
, int> > labels
;
73 if (m_searchFilter
->IsRadio())
74 labels
.emplace_back(g_localizeStrings
.Get(19216), EPG_SEARCH_UNSET
); // All radio channels
76 labels
.emplace_back(g_localizeStrings
.Get(19217), EPG_SEARCH_UNSET
); // All TV channels
78 std::shared_ptr
<CPVRChannelGroup
> group
;
79 if (iChannelGroup
!= EPG_SEARCH_UNSET
)
80 group
= CServiceBroker::GetPVRManager().ChannelGroups()->GetByIdFromAll(iChannelGroup
);
83 group
= CServiceBroker::GetPVRManager().ChannelGroups()->GetGroupAll(m_searchFilter
->IsRadio());
85 m_channelsMap
.clear();
86 const std::vector
<std::shared_ptr
<CPVRChannelGroupMember
>> groupMembers
=
87 group
->GetMembers(CPVRChannelGroup::Include::ONLY_VISIBLE
);
89 int iSelectedChannel
= EPG_SEARCH_UNSET
;
90 for (const auto& groupMember
: groupMembers
)
92 labels
.emplace_back(groupMember
->Channel()->ChannelName(), iIndex
);
93 m_channelsMap
.insert(std::make_pair(iIndex
, groupMember
));
95 if (iSelectedChannel
== EPG_SEARCH_UNSET
&&
96 groupMember
->ChannelUID() == m_searchFilter
->GetChannelUID() &&
97 groupMember
->ChannelClientID() == m_searchFilter
->GetClientID())
98 iSelectedChannel
= iIndex
;
103 SET_CONTROL_LABELS(CONTROL_SPIN_CHANNELS
, iSelectedChannel
, &labels
);
106 void CGUIDialogPVRGuideSearch::UpdateGroupsSpin()
108 std::vector
<std::pair
<std::string
, int>> labels
;
109 const std::vector
<std::shared_ptr
<CPVRChannelGroup
>> groups
=
110 CServiceBroker::GetPVRManager().ChannelGroups()->Get(m_searchFilter
->IsRadio())->GetMembers();
111 int selectedGroup
= EPG_SEARCH_UNSET
;
112 for (const auto& group
: groups
)
114 labels
.emplace_back(group
->GroupName(), group
->GroupID());
116 if (selectedGroup
== EPG_SEARCH_UNSET
&&
117 group
->GroupID() == m_searchFilter
->GetChannelGroupID())
118 selectedGroup
= group
->GroupID();
121 SET_CONTROL_LABELS(CONTROL_SPIN_GROUPS
, selectedGroup
, &labels
);
124 void CGUIDialogPVRGuideSearch::UpdateGenreSpin()
126 std::vector
< std::pair
<std::string
, int> > labels
;
127 labels
.emplace_back(g_localizeStrings
.Get(593), EPG_SEARCH_UNSET
);
128 labels
.emplace_back(g_localizeStrings
.Get(19500), EPG_EVENT_CONTENTMASK_MOVIEDRAMA
);
129 labels
.emplace_back(g_localizeStrings
.Get(19516), EPG_EVENT_CONTENTMASK_NEWSCURRENTAFFAIRS
);
130 labels
.emplace_back(g_localizeStrings
.Get(19532), EPG_EVENT_CONTENTMASK_SHOW
);
131 labels
.emplace_back(g_localizeStrings
.Get(19548), EPG_EVENT_CONTENTMASK_SPORTS
);
132 labels
.emplace_back(g_localizeStrings
.Get(19564), EPG_EVENT_CONTENTMASK_CHILDRENYOUTH
);
133 labels
.emplace_back(g_localizeStrings
.Get(19580), EPG_EVENT_CONTENTMASK_MUSICBALLETDANCE
);
134 labels
.emplace_back(g_localizeStrings
.Get(19596), EPG_EVENT_CONTENTMASK_ARTSCULTURE
);
135 labels
.emplace_back(g_localizeStrings
.Get(19612), EPG_EVENT_CONTENTMASK_SOCIALPOLITICALECONOMICS
);
136 labels
.emplace_back(g_localizeStrings
.Get(19628), EPG_EVENT_CONTENTMASK_EDUCATIONALSCIENCE
);
137 labels
.emplace_back(g_localizeStrings
.Get(19644), EPG_EVENT_CONTENTMASK_LEISUREHOBBIES
);
138 labels
.emplace_back(g_localizeStrings
.Get(19660), EPG_EVENT_CONTENTMASK_SPECIAL
);
139 labels
.emplace_back(g_localizeStrings
.Get(19499), EPG_EVENT_CONTENTMASK_USERDEFINED
);
141 SET_CONTROL_LABELS(CONTROL_SPIN_GENRE
, m_searchFilter
->GetGenreType(), &labels
);
144 void CGUIDialogPVRGuideSearch::UpdateDurationSpin()
146 /* minimum duration */
147 std::vector
< std::pair
<std::string
, int> > labels
;
149 labels
.emplace_back("-", EPG_SEARCH_UNSET
);
150 for (int i
= 1; i
< 12*60/5; ++i
)
151 labels
.emplace_back(StringUtils::Format(g_localizeStrings
.Get(14044), i
* 5), i
* 5);
153 SET_CONTROL_LABELS(CONTROL_SPIN_MIN_DURATION
, m_searchFilter
->GetMinimumDuration(), &labels
);
155 /* maximum duration */
158 labels
.emplace_back("-", EPG_SEARCH_UNSET
);
159 for (int i
= 1; i
< 12*60/5; ++i
)
160 labels
.emplace_back(StringUtils::Format(g_localizeStrings
.Get(14044), i
* 5), i
* 5);
162 SET_CONTROL_LABELS(CONTROL_SPIN_MAX_DURATION
, m_searchFilter
->GetMaximumDuration(), &labels
);
165 bool CGUIDialogPVRGuideSearch::OnMessage(CGUIMessage
& message
)
167 CGUIDialog::OnMessage(message
);
169 switch (message
.GetMessage())
171 case GUI_MSG_CLICKED
:
173 int iControl
= message
.GetSenderId();
174 if (iControl
== CONTROL_BTN_SEARCH
)
176 // Read data from controls, update m_searchfilter accordingly
177 UpdateSearchFilter();
179 m_result
= Result::SEARCH
;
183 else if (iControl
== CONTROL_BTN_CANCEL
)
185 m_result
= Result::CANCEL
;
189 else if (iControl
== CONTROL_BTN_DEFAULTS
)
193 m_searchFilter
->Reset();
198 else if (iControl
== CONTROL_BTN_SAVE
)
200 // Read data from controls, update m_searchfilter accordingly
201 UpdateSearchFilter();
203 std::string title
= m_searchFilter
->GetTitle();
206 title
= m_searchFilter
->GetSearchTerm();
208 title
= g_localizeStrings
.Get(137); // "Search"
210 StringUtils::Trim(title
, "\"");
212 if (!CGUIKeyboardFactory::ShowAndGetInput(
213 title
, CVariant
{g_localizeStrings
.Get(528)}, // "Enter title"
218 m_searchFilter
->SetTitle(title
);
221 m_result
= Result::SAVE
;
225 else if (iControl
== CONTROL_SPIN_GROUPS
)
230 else if (iControl
== CONTROL_BTN_START_ANY_TIME
|| iControl
== CONTROL_BTN_END_ANY_TIME
)
232 UpdateSearchFilter();
243 void CGUIDialogPVRGuideSearch::OnInitWindow()
245 CGUIDialog::OnInitWindow();
247 m_result
= Result::CANCEL
;
250 void CGUIDialogPVRGuideSearch::OnWindowLoaded()
253 return CGUIDialog::OnWindowLoaded();
256 CDateTime
CGUIDialogPVRGuideSearch::ReadDateTime(const std::string
& strDate
, const std::string
& strTime
) const
259 int iHours
, iMinutes
;
260 sscanf(strTime
.c_str(), "%d:%d", &iHours
, &iMinutes
);
261 dateTime
.SetFromDBDate(strDate
);
262 dateTime
.SetDateTime(dateTime
.GetYear(), dateTime
.GetMonth(), dateTime
.GetDay(), iHours
, iMinutes
, 0);
263 return dateTime
.GetAsUTCDateTime();
266 bool CGUIDialogPVRGuideSearch::IsRadioSelected(int controlID
)
268 CGUIMessage
msg(GUI_MSG_IS_SELECTED
, GetID(), controlID
);
270 return (msg
.GetParam1() == 1);
273 int CGUIDialogPVRGuideSearch::GetSpinValue(int controlID
)
275 CGUIMessage
msg(GUI_MSG_ITEM_SELECTED
, GetID(), controlID
);
277 return msg
.GetParam1();
280 std::string
CGUIDialogPVRGuideSearch::GetEditValue(int controlID
)
282 CGUIMessage
msg(GUI_MSG_ITEM_SELECTED
, GetID(), controlID
);
284 return msg
.GetLabel();
287 void CGUIDialogPVRGuideSearch::UpdateSearchFilter()
292 m_searchFilter
->SetSearchTerm(GetEditValue(CONTROL_EDIT_SEARCH
));
294 m_searchFilter
->SetSearchInDescription(IsRadioSelected(CONTROL_BTN_INC_DESC
));
295 m_searchFilter
->SetCaseSensitive(IsRadioSelected(CONTROL_BTN_CASE_SENS
));
296 m_searchFilter
->SetFreeToAirOnly(IsRadioSelected(CONTROL_BTN_FTA_ONLY
));
297 m_searchFilter
->SetIncludeUnknownGenres(IsRadioSelected(CONTROL_BTN_UNK_GENRE
));
298 m_searchFilter
->SetIgnorePresentRecordings(IsRadioSelected(CONTROL_BTN_IGNORE_REC
));
299 m_searchFilter
->SetIgnorePresentTimers(IsRadioSelected(CONTROL_BTN_IGNORE_TMR
));
300 m_searchFilter
->SetRemoveDuplicates(IsRadioSelected(CONTROL_SPIN_NO_REPEATS
));
301 m_searchFilter
->SetIgnoreFinishedBroadcasts(IsRadioSelected(CONTROL_BTN_IGNORE_FINISHED
));
302 m_searchFilter
->SetIgnoreFutureBroadcasts(IsRadioSelected(CONTROL_BTN_IGNORE_FUTURE
));
303 m_searchFilter
->SetGenreType(GetSpinValue(CONTROL_SPIN_GENRE
));
304 m_searchFilter
->SetMinimumDuration(GetSpinValue(CONTROL_SPIN_MIN_DURATION
));
305 m_searchFilter
->SetMaximumDuration(GetSpinValue(CONTROL_SPIN_MAX_DURATION
));
307 auto it
= m_channelsMap
.find(GetSpinValue(CONTROL_SPIN_CHANNELS
));
308 m_searchFilter
->SetClientID(it
== m_channelsMap
.end() ? PVR_CLIENT_INVALID_UID
309 : (*it
).second
->ChannelClientID());
310 m_searchFilter
->SetChannelUID(it
== m_channelsMap
.end() ? -1 : (*it
).second
->ChannelUID());
311 m_searchFilter
->SetChannelGroupID(GetSpinValue(CONTROL_SPIN_GROUPS
));
313 const CDateTime start
=
314 ReadDateTime(GetEditValue(CONTROL_EDIT_START_DATE
), GetEditValue(CONTROL_EDIT_START_TIME
));
315 if (start
!= m_startDateTime
)
317 m_searchFilter
->SetStartDateTime(start
);
318 m_startDateTime
= start
;
320 const CDateTime end
=
321 ReadDateTime(GetEditValue(CONTROL_EDIT_STOP_DATE
), GetEditValue(CONTROL_EDIT_STOP_TIME
));
322 if (end
!= m_endDateTime
)
324 m_searchFilter
->SetEndDateTime(end
);
328 m_searchFilter
->SetStartAnyTime(IsRadioSelected(CONTROL_BTN_START_ANY_TIME
));
329 m_searchFilter
->SetEndAnyTime(IsRadioSelected(CONTROL_BTN_END_ANY_TIME
));
332 void CGUIDialogPVRGuideSearch::Update()
337 SET_CONTROL_LABEL2(CONTROL_EDIT_SEARCH
, m_searchFilter
->GetSearchTerm());
339 CGUIMessage
msg(GUI_MSG_SET_TYPE
, GetID(), CONTROL_EDIT_SEARCH
, CGUIEditControl::INPUT_TYPE_TEXT
, 16017);
343 SET_CONTROL_SELECTED(GetID(), CONTROL_BTN_CASE_SENS
, m_searchFilter
->IsCaseSensitive());
344 SET_CONTROL_SELECTED(GetID(), CONTROL_BTN_INC_DESC
, m_searchFilter
->ShouldSearchInDescription());
345 SET_CONTROL_SELECTED(GetID(), CONTROL_BTN_FTA_ONLY
, m_searchFilter
->IsFreeToAirOnly());
346 SET_CONTROL_SELECTED(GetID(), CONTROL_BTN_UNK_GENRE
, m_searchFilter
->ShouldIncludeUnknownGenres());
347 SET_CONTROL_SELECTED(GetID(), CONTROL_BTN_IGNORE_REC
, m_searchFilter
->ShouldIgnorePresentRecordings());
348 SET_CONTROL_SELECTED(GetID(), CONTROL_BTN_IGNORE_TMR
, m_searchFilter
->ShouldIgnorePresentTimers());
349 SET_CONTROL_SELECTED(GetID(), CONTROL_SPIN_NO_REPEATS
, m_searchFilter
->ShouldRemoveDuplicates());
350 SET_CONTROL_SELECTED(GetID(), CONTROL_BTN_IGNORE_FINISHED
,
351 m_searchFilter
->ShouldIgnoreFinishedBroadcasts());
352 SET_CONTROL_SELECTED(GetID(), CONTROL_BTN_IGNORE_FUTURE
,
353 m_searchFilter
->ShouldIgnoreFutureBroadcasts());
354 SET_CONTROL_SELECTED(GetID(), CONTROL_BTN_START_ANY_TIME
, m_searchFilter
->IsStartAnyTime());
355 SET_CONTROL_SELECTED(GetID(), CONTROL_BTN_END_ANY_TIME
, m_searchFilter
->IsEndAnyTime());
356 CONTROL_ENABLE_ON_CONDITION(CONTROL_EDIT_START_TIME
, !m_searchFilter
->IsStartAnyTime());
357 CONTROL_ENABLE_ON_CONDITION(CONTROL_EDIT_STOP_TIME
, !m_searchFilter
->IsEndAnyTime());
359 // Set start/end datetime fields
360 m_startDateTime
= m_searchFilter
->GetStartDateTime();
361 m_endDateTime
= m_searchFilter
->GetEndDateTime();
362 if (!m_startDateTime
.IsValid() || !m_endDateTime
.IsValid())
364 const auto dates
= CServiceBroker::GetPVRManager().EpgContainer().GetFirstAndLastEPGDate();
365 if (!m_startDateTime
.IsValid())
366 m_startDateTime
= dates
.first
;
367 if (!m_endDateTime
.IsValid())
368 m_endDateTime
= dates
.second
;
371 if (!m_startDateTime
.IsValid())
372 m_startDateTime
= CDateTime::GetUTCDateTime();
374 if (!m_endDateTime
.IsValid())
375 m_endDateTime
= m_startDateTime
+ CDateTimeSpan(10, 0, 0, 0); // default to start + 10 days
377 CDateTime startLocal
;
378 startLocal
.SetFromUTCDateTime(m_startDateTime
);
380 endLocal
.SetFromUTCDateTime(m_endDateTime
);
382 SET_CONTROL_LABEL2(CONTROL_EDIT_START_TIME
, startLocal
.GetAsLocalizedTime("", false));
384 CGUIMessage
msg(GUI_MSG_SET_TYPE
, GetID(), CONTROL_EDIT_START_TIME
, CGUIEditControl::INPUT_TYPE_TIME
, 14066);
387 SET_CONTROL_LABEL2(CONTROL_EDIT_STOP_TIME
, endLocal
.GetAsLocalizedTime("", false));
389 CGUIMessage
msg(GUI_MSG_SET_TYPE
, GetID(), CONTROL_EDIT_STOP_TIME
, CGUIEditControl::INPUT_TYPE_TIME
, 14066);
392 SET_CONTROL_LABEL2(CONTROL_EDIT_START_DATE
, startLocal
.GetAsDBDate());
394 CGUIMessage
msg(GUI_MSG_SET_TYPE
, GetID(), CONTROL_EDIT_START_DATE
, CGUIEditControl::INPUT_TYPE_DATE
, 14067);
397 SET_CONTROL_LABEL2(CONTROL_EDIT_STOP_DATE
, endLocal
.GetAsDBDate());
399 CGUIMessage
msg(GUI_MSG_SET_TYPE
, GetID(), CONTROL_EDIT_STOP_DATE
, CGUIEditControl::INPUT_TYPE_DATE
, 14067);
403 UpdateDurationSpin();