[Windows] Fix driver version detection of AMD RDNA+ GPU on Windows 10
[xbmc.git] / xbmc / pvr / windows / GUIWindowPVRSearch.cpp
blob4a9ad6b10e9cc3f6424c19ad53f5a7e767667d32
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 "GUIWindowPVRSearch.h"
11 #include "FileItem.h"
12 #include "FileItemList.h"
13 #include "ServiceBroker.h"
14 #include "dialogs/GUIDialogBusy.h"
15 #include "dialogs/GUIDialogYesNo.h"
16 #include "guilib/GUIComponent.h"
17 #include "guilib/GUIMessage.h"
18 #include "guilib/GUIWindowManager.h"
19 #include "guilib/LocalizeStrings.h"
20 #include "input/actions/Action.h"
21 #include "input/actions/ActionIDs.h"
22 #include "messaging/helpers/DialogOKHelper.h"
23 #include "pvr/PVRItem.h"
24 #include "pvr/PVRManager.h"
25 #include "pvr/dialogs/GUIDialogPVRGuideSearch.h"
26 #include "pvr/epg/Epg.h"
27 #include "pvr/epg/EpgContainer.h"
28 #include "pvr/epg/EpgInfoTag.h"
29 #include "pvr/epg/EpgSearchFilter.h"
30 #include "pvr/epg/EpgSearchPath.h"
31 #include "pvr/guilib/PVRGUIActionsEPG.h"
32 #include "pvr/guilib/PVRGUIActionsTimers.h"
33 #include "pvr/recordings/PVRRecording.h"
34 #include "threads/IRunnable.h"
35 #include "utils/StringUtils.h"
36 #include "utils/URIUtils.h"
37 #include "utils/Variant.h"
39 #include <algorithm>
40 #include <memory>
41 #include <vector>
43 using namespace PVR;
44 using namespace KODI::MESSAGING;
46 namespace
48 class AsyncSearchAction : private IRunnable
50 public:
51 AsyncSearchAction() = delete;
52 AsyncSearchAction(CFileItemList* items, CPVREpgSearchFilter* filter)
53 : m_items(items), m_filter(filter)
56 bool Execute();
58 private:
59 // IRunnable implementation
60 void Run() override;
62 CFileItemList* m_items;
63 CPVREpgSearchFilter* m_filter;
66 bool AsyncSearchAction::Execute()
68 CGUIDialogBusy::Wait(this, 100, false);
69 return true;
72 void AsyncSearchAction::Run()
74 std::vector<std::shared_ptr<CPVREpgInfoTag>> results =
75 CServiceBroker::GetPVRManager().EpgContainer().GetTags(m_filter->GetEpgSearchData());
76 m_filter->SetEpgSearchDataFiltered();
78 // Tags can still contain false positives, for search criteria that cannot be handled via
79 // database. So, run extended search filters on what we got from the database.
80 for (auto it = results.begin(); it != results.end();)
82 it = results.erase(std::remove_if(results.begin(), results.end(),
83 [this](const std::shared_ptr<CPVREpgInfoTag>& entry) {
84 return !m_filter->FilterEntry(entry);
85 }),
86 results.end());
89 if (m_filter->ShouldRemoveDuplicates())
90 m_filter->RemoveDuplicates(results);
92 m_filter->SetLastExecutedDateTime(CDateTime::GetUTCDateTime());
94 for (const auto& tag : results)
96 m_items->Add(std::make_shared<CFileItem>(tag));
99 } // unnamed namespace
101 CGUIWindowPVRSearchBase::CGUIWindowPVRSearchBase(bool bRadio, int id, const std::string& xmlFile)
102 : CGUIWindowPVRBase(bRadio, id, xmlFile)
106 CGUIWindowPVRSearchBase::~CGUIWindowPVRSearchBase()
110 void CGUIWindowPVRSearchBase::GetContextButtons(int itemNumber, CContextButtons& buttons)
112 if (itemNumber < 0 || itemNumber >= m_vecItems->Size())
113 return;
115 const CPVREpgSearchPath path(m_vecItems->GetPath());
116 const bool bIsSavedSearchesRoot = (path.IsValid() && path.IsSavedSearchesRoot());
117 if (!bIsSavedSearchesRoot)
118 buttons.Add(CONTEXT_BUTTON_CLEAR, 19232); // "Clear search results"
120 CGUIWindowPVRBase::GetContextButtons(itemNumber, buttons);
123 bool CGUIWindowPVRSearchBase::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
125 if (itemNumber < 0 || itemNumber >= m_vecItems->Size())
126 return false;
127 CFileItemPtr pItem = m_vecItems->Get(itemNumber);
129 return OnContextButtonClear(pItem.get(), button) ||
130 CGUIMediaWindow::OnContextButton(itemNumber, button);
133 void CGUIWindowPVRSearchBase::SetItemToSearch(const CFileItem& item)
135 if (item.HasEPGSearchFilter())
137 SetSearchFilter(item.GetEPGSearchFilter());
139 else if (item.IsUsablePVRRecording())
141 SetSearchFilter(std::make_shared<CPVREpgSearchFilter>(m_bRadio));
142 m_searchfilter->SetSearchPhrase(item.GetPVRRecordingInfoTag()->m_strTitle);
144 else
146 SetSearchFilter(std::make_shared<CPVREpgSearchFilter>(m_bRadio));
148 const std::shared_ptr<const CPVREpgInfoTag> epgTag(CPVRItem(item).GetEpgInfoTag());
149 if (epgTag && !CServiceBroker::GetPVRManager().IsParentalLocked(epgTag))
150 m_searchfilter->SetSearchPhrase(epgTag->Title());
153 ExecuteSearch();
156 void CGUIWindowPVRSearchBase::OnPrepareFileItems(CFileItemList& items)
158 if (m_bSearchConfirmed)
160 items.Clear();
163 if (items.IsEmpty())
165 auto item = std::make_shared<CFileItem>(CPVREpgSearchPath::PATH_SEARCH_DIALOG, false);
166 item->SetLabel(g_localizeStrings.Get(
167 m_searchfilter == nullptr ? 19335 : 19336)); // "New search..." / "Edit search..."
168 item->SetLabelPreformatted(true);
169 item->SetSpecialSort(SortSpecialOnTop);
170 item->SetArt("icon", "DefaultPVRSearch.png");
171 items.Add(item);
173 item = std::make_shared<CFileItem>(m_bRadio ? CPVREpgSearchPath::PATH_RADIO_SAVEDSEARCHES
174 : CPVREpgSearchPath::PATH_TV_SAVEDSEARCHES,
175 true);
176 item->SetLabel(g_localizeStrings.Get(19337)); // "Saved searches"
177 item->SetLabelPreformatted(true);
178 item->SetSpecialSort(SortSpecialOnTop);
179 item->SetArt("icon", "DefaultFolder.png");
180 items.Add(item);
183 if (m_bSearchConfirmed)
185 const int itemCount = items.GetObjectCount();
187 AsyncSearchAction(&items, m_searchfilter.get()).Execute();
189 if (items.GetObjectCount() == itemCount)
191 HELPERS::ShowOKDialogText(CVariant{284}, // "No results found"
192 m_searchfilter->GetSearchTerm());
197 bool CGUIWindowPVRSearchBase::OnAction(const CAction& action)
199 if (action.GetID() == ACTION_PARENT_DIR || action.GetID() == ACTION_NAV_BACK)
201 const CPVREpgSearchPath path(m_vecItems->GetPath());
202 if (path.IsValid() && path.IsSavedSearchesRoot())
204 // Go to root dir and show previous search results if any
205 m_bSearchConfirmed = (m_searchfilter != nullptr);
206 GoParentFolder();
207 return true;
210 return CGUIWindowPVRBase::OnAction(action);
213 bool CGUIWindowPVRSearchBase::OnMessage(CGUIMessage& message)
215 if (message.GetMessage() == GUI_MSG_CLICKED)
217 if (message.GetSenderId() == m_viewControl.GetCurrentControl())
219 int iItem = m_viewControl.GetSelectedItem();
220 if (iItem >= 0 && iItem < m_vecItems->Size())
222 CFileItemPtr pItem = m_vecItems->Get(iItem);
224 /* process actions */
225 switch (message.GetParam1())
227 case ACTION_SHOW_INFO:
228 case ACTION_SELECT_ITEM:
229 case ACTION_MOUSE_LEFT_CLICK:
231 const CPVREpgSearchPath path(pItem->GetPath());
232 const bool bIsSavedSearch = (path.IsValid() && path.IsSavedSearch());
233 const bool bIsSavedSearchesRoot = (path.IsValid() && path.IsSavedSearchesRoot());
235 if (message.GetParam1() != ACTION_SHOW_INFO)
237 if (pItem->IsParentFolder())
239 // Go to root dir and show previous search results if any
240 m_bSearchConfirmed = (m_searchfilter != nullptr);
241 break; // handled by base class
244 if (bIsSavedSearchesRoot)
246 // List saved searches
247 m_bSearchConfirmed = false;
248 break; // handled by base class
251 if (bIsSavedSearch)
253 // Execute selected saved search
254 SetSearchFilter(pItem->GetEPGSearchFilter());
255 ExecuteSearch();
256 return true;
260 if (bIsSavedSearch)
262 OpenDialogSearch(*pItem);
264 else if (pItem->GetPath() == CPVREpgSearchPath::PATH_SEARCH_DIALOG)
266 OpenDialogSearch(m_searchfilter);
268 else
270 CServiceBroker::GetPVRManager().Get<PVR::GUI::EPG>().ShowEPGInfo(*pItem);
272 return true;
275 case ACTION_CONTEXT_MENU:
276 case ACTION_MOUSE_RIGHT_CLICK:
277 OnPopupMenu(iItem);
278 return true;
280 case ACTION_RECORD:
281 CServiceBroker::GetPVRManager().Get<PVR::GUI::Timers>().ToggleTimer(*pItem);
282 return true;
287 else if (message.GetMessage() == GUI_MSG_REFRESH_LIST)
289 if (static_cast<PVREvent>(message.GetParam1()) == PVREvent::SavedSearchesInvalidated)
291 Refresh(true);
293 // Refresh triggered by deleted saved search?
294 if (m_searchfilter)
296 const CPVREpgSearchPath path(m_vecItems->GetPath());
297 const bool bIsSavedSearchesRoot = (path.IsValid() && path.IsSavedSearchesRoot());
298 if (bIsSavedSearchesRoot)
300 const std::string filterPath = m_searchfilter->GetPath();
301 bool bFound = false;
302 for (const auto& item : *m_vecItems)
304 const auto filter = item->GetEPGSearchFilter();
305 if (filter && filter->GetPath() == filterPath)
307 bFound = true;
308 break;
311 if (!bFound)
312 SetSearchFilter(nullptr);
317 else if (message.GetMessage() == GUI_MSG_WINDOW_INIT)
319 const CPVREpgSearchPath path(message.GetStringParam(0));
320 if (path.IsValid() && path.IsSavedSearch())
322 const std::shared_ptr<CPVREpgSearchFilter> filter =
323 CServiceBroker::GetPVRManager().EpgContainer().GetSavedSearchById(path.IsRadio(),
324 path.GetId());
325 if (filter)
327 SetSearchFilter(filter);
328 m_bSearchConfirmed = true;
333 return CGUIWindowPVRBase::OnMessage(message);
336 bool CGUIWindowPVRSearchBase::Update(const std::string& strDirectory,
337 bool updateFilterPath /* = true */)
339 if (m_vecItems->GetObjectCount() > 0)
341 const CPVREpgSearchPath path(m_vecItems->GetPath());
342 if (path.IsValid() && path.IsSavedSearchesRoot())
344 const std::string oldPath = m_vecItems->GetPath();
346 const bool bReturn = CGUIWindowPVRBase::Update(strDirectory);
348 if (bReturn && oldPath == m_vecItems->GetPath() && m_vecItems->GetObjectCount() == 0)
350 // Go to parent folder if we're in a subdir and for instance just deleted the last item
351 GoParentFolder();
353 return bReturn;
356 return CGUIWindowPVRBase::Update(strDirectory);
359 void CGUIWindowPVRSearchBase::UpdateButtons()
361 CGUIWindowPVRBase::UpdateButtons();
363 bool bSavedSearchesRoot = false;
364 std::string header;
365 const CPVREpgSearchPath path(m_vecItems->GetPath());
366 if (path.IsValid() && path.IsSavedSearchesRoot())
368 bSavedSearchesRoot = true;
369 header = g_localizeStrings.Get(19337); // "Saved searches"
372 if (header.empty() && m_searchfilter)
374 header = m_searchfilter->GetTitle();
375 if (header.empty())
377 header = m_searchfilter->GetSearchTerm();
378 StringUtils::Trim(header, "\"");
381 SET_CONTROL_LABEL(CONTROL_LABEL_HEADER1, header);
383 if (!bSavedSearchesRoot && m_searchfilter && m_searchfilter->IsChanged())
384 SET_CONTROL_LABEL(CONTROL_LABEL_HEADER2, g_localizeStrings.Get(19342)); // "[not saved]"
385 else if (!bSavedSearchesRoot && m_searchfilter)
386 SET_CONTROL_LABEL(CONTROL_LABEL_HEADER2, g_localizeStrings.Get(19343)); // "[saved]"
387 else
388 SET_CONTROL_LABEL(CONTROL_LABEL_HEADER2, "");
391 bool CGUIWindowPVRSearchBase::OnContextButtonClear(CFileItem* item, CONTEXT_BUTTON button)
393 bool bReturn = false;
395 if (button == CONTEXT_BUTTON_CLEAR)
397 bReturn = true;
399 m_bSearchConfirmed = false;
400 SetSearchFilter(nullptr);
402 Refresh(true);
405 return bReturn;
408 CGUIDialogPVRGuideSearch::Result CGUIWindowPVRSearchBase::OpenDialogSearch(const CFileItem& item)
410 const auto searchFilter = item.GetEPGSearchFilter();
411 if (!searchFilter)
412 return CGUIDialogPVRGuideSearch::Result::CANCEL;
414 return OpenDialogSearch(searchFilter);
417 CGUIDialogPVRGuideSearch::Result CGUIWindowPVRSearchBase::OpenDialogSearch(
418 const std::shared_ptr<CPVREpgSearchFilter>& searchFilter)
420 CGUIDialogPVRGuideSearch* dlgSearch =
421 CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogPVRGuideSearch>(
422 WINDOW_DIALOG_PVR_GUIDE_SEARCH);
424 if (!dlgSearch)
425 return CGUIDialogPVRGuideSearch::Result::CANCEL;
427 const std::shared_ptr<CPVREpgSearchFilter> tmpSearchFilter =
428 searchFilter != nullptr ? std::make_shared<CPVREpgSearchFilter>(*searchFilter)
429 : std::make_shared<CPVREpgSearchFilter>(m_bRadio);
431 dlgSearch->SetFilterData(tmpSearchFilter);
433 /* Open dialog window */
434 dlgSearch->Open();
436 const CGUIDialogPVRGuideSearch::Result result = dlgSearch->GetResult();
437 if (result == CGUIDialogPVRGuideSearch::Result::SEARCH)
439 SetSearchFilter(tmpSearchFilter);
440 ExecuteSearch();
442 else if (result == CGUIDialogPVRGuideSearch::Result::SAVE)
444 CServiceBroker::GetPVRManager().EpgContainer().PersistSavedSearch(*tmpSearchFilter);
445 if (searchFilter)
446 searchFilter->SetDatabaseId(tmpSearchFilter->GetDatabaseId());
448 const CPVREpgSearchPath path(m_vecItems->GetPath());
449 if (path.IsValid() && path.IsSearchRoot())
451 SetSearchFilter(tmpSearchFilter);
452 ExecuteSearch();
456 return result;
459 void CGUIWindowPVRSearchBase::ExecuteSearch()
461 m_bSearchConfirmed = true;
463 const CPVREpgSearchPath path(m_vecItems->GetPath());
464 if (path.IsValid() && path.IsSavedSearchesRoot())
466 GoParentFolder();
468 else if (IsActive())
470 Refresh(true);
473 // Save if not a transient search
474 if (m_searchfilter->GetDatabaseId() != -1)
475 CServiceBroker::GetPVRManager().EpgContainer().UpdateSavedSearchLastExecuted(*m_searchfilter);
478 void CGUIWindowPVRSearchBase::SetSearchFilter(
479 const std::shared_ptr<CPVREpgSearchFilter>& searchFilter)
481 if (m_searchfilter && m_searchfilter->IsChanged() &&
482 (!searchFilter || m_searchfilter->GetPath() != searchFilter->GetPath()))
484 bool bCanceled = false;
485 if (!CGUIDialogYesNo::ShowAndGetInput(CVariant{14117}, // "Warning"
486 CVariant{19341}, // "Save the current search?"
487 CVariant{},
488 CVariant{!m_searchfilter->GetTitle().empty()
489 ? m_searchfilter->GetTitle()
490 : m_searchfilter->GetSearchTerm()},
491 bCanceled, CVariant{107}, // "Yes"
492 CVariant{106}, // "No"
493 CGUIDialogYesNo::NO_TIMEOUT) &&
494 !bCanceled)
496 std::string title = m_searchfilter->GetTitle();
497 if (title.empty())
499 title = m_searchfilter->GetSearchTerm();
500 if (title.empty())
501 title = g_localizeStrings.Get(137); // "Search"
502 else
503 StringUtils::Trim(title, "\"");
505 m_searchfilter->SetTitle(title);
507 CServiceBroker::GetPVRManager().EpgContainer().PersistSavedSearch(*m_searchfilter);
510 m_searchfilter = searchFilter;
513 std::string CGUIWindowPVRTVSearch::GetRootPath() const
515 return CPVREpgSearchPath::PATH_TV_SEARCH;
518 std::string CGUIWindowPVRTVSearch::GetStartFolder(const std::string& dir)
520 return CPVREpgSearchPath::PATH_TV_SEARCH;
523 std::string CGUIWindowPVRTVSearch::GetDirectoryPath()
525 return URIUtils::PathHasParent(m_vecItems->GetPath(), CPVREpgSearchPath::PATH_TV_SEARCH)
526 ? m_vecItems->GetPath()
527 : CPVREpgSearchPath::PATH_TV_SEARCH;
530 std::string CGUIWindowPVRRadioSearch::GetRootPath() const
532 return CPVREpgSearchPath::PATH_RADIO_SEARCH;
535 std::string CGUIWindowPVRRadioSearch::GetStartFolder(const std::string& dir)
537 return CPVREpgSearchPath::PATH_RADIO_SEARCH;
540 std::string CGUIWindowPVRRadioSearch::GetDirectoryPath()
542 return URIUtils::PathHasParent(m_vecItems->GetPath(), CPVREpgSearchPath::PATH_RADIO_SEARCH)
543 ? m_vecItems->GetPath()
544 : CPVREpgSearchPath::PATH_RADIO_SEARCH;