MythTV master
weatherSetup.cpp
Go to the documentation of this file.
1// QT headers
2#include <QApplication>
3#include <QSqlError>
4#include <QVariant>
5#include <algorithm>
6
7// MythTV headers
12
13// MythWeather headers
14#include "sourceManager.h"
15#include "weatherScreen.h"
16#include "weatherSetup.h"
17#include "weatherSource.h"
18
20{
21 // Load the theme for this screen
22 bool foundtheme = LoadWindowFromXML("weather-ui.xml", "global-setup", this);
23 if (!foundtheme)
24 return false;
25
26 m_timeoutSpinbox = dynamic_cast<MythUISpinBox *> (GetChild("timeout_spinbox"));
27
28 m_backgroundCheckbox = dynamic_cast<MythUICheckBox *> (GetChild("backgroundcheck"));
29 m_finishButton = dynamic_cast<MythUIButton *> (GetChild("finishbutton"));
30
32 {
33 LOG(VB_GENERAL, LOG_ERR, "Theme is missing required elements.");
34 return false;
35 }
36
38
39 m_finishButton->SetText(tr("Finish"));
41
42 loadData();
43
44 return true;
45}
46
48{
49 int setting = gCoreContext->GetNumSetting("weatherbackgroundfetch", 0);
50 if (setting == 1)
52
53 m_timeout = gCoreContext->GetNumSetting("weatherTimeout", 10);
54 m_timeoutSpinbox->SetRange(5, 120, 5);
56}
57
59{
61 gCoreContext->SaveSetting("weatherTimeout", timeout);
62
63 int checkstate = 0;
65 checkstate = 1;
66 gCoreContext->SaveSetting("weatherbackgroundfetch", checkstate);
67 Close();
68}
69
71
72ScreenSetup::ScreenSetup(MythScreenStack *parent, const QString &name,
73 SourceManager *srcman)
74 : MythScreenType(parent, name),
75 m_sourceManager(srcman ? srcman : new SourceManager()),
76 m_createdSrcMan(srcman == nullptr)
77{
80}
81
83{
85 delete m_sourceManager;
86 m_sourceManager = nullptr;
87
88 // Deallocate the ScreenListInfo objects created for the inactive screen list.
89 for (int i=0; i < m_inactiveList->GetCount(); i++)
90 {
92 if (item->GetData().isValid())
93 delete item->GetData().value<ScreenListInfo *>();
94 }
95
96 // Deallocate the ScreenListInfo objects created for the active screen list.
97 for (int i=0; i < m_activeList->GetCount(); i++)
98 {
100 if (item->GetData().isValid())
101 delete item->GetData().value<ScreenListInfo *>();
102 }
103}
104
106{
107 // Load the theme for this screen
108 bool foundtheme = LoadWindowFromXML("weather-ui.xml", "screen-setup", this);
109 if (!foundtheme)
110 return false;
111
112 m_helpText = dynamic_cast<MythUIText *> (GetChild("helptxt"));
113
114 m_activeList = dynamic_cast<MythUIButtonList *> (GetChild("activelist"));
115 m_inactiveList = dynamic_cast<MythUIButtonList *> (GetChild("inactivelist"));
116
117 m_finishButton = dynamic_cast<MythUIButton *> (GetChild("finishbutton"));
118
119 MythUIText *activeheader = dynamic_cast<MythUIText *> (GetChild("activehdr"));
120 if (activeheader)
121 activeheader->SetText(tr("Active Screens"));
122
123 MythUIText *inactiveheader = dynamic_cast<MythUIText *> (GetChild("inactivehdr"));
124 if (inactiveheader)
125 inactiveheader->SetText(tr("Inactive Screens"));
126
128 {
129 LOG(VB_GENERAL, LOG_ERR, "Theme is missing required elements.");
130 return false;
131 }
132
134
143
145
146 m_finishButton->SetText(tr("Finish"));
148
149 loadData();
150
151 return true;
152}
153
154bool ScreenSetup::keyPressEvent(QKeyEvent *event)
155{
157 return true;
158
159 QStringList actions;
160 bool handled = GetMythMainWindow()->TranslateKeyPress("Weather", event, actions);
161
162 for (int i = 0; i < actions.size() && !handled; i++)
163 {
164 const QString& action = actions[i];
165 handled = true;
166
167 if (action == "DELETE")
168 {
170 deleteScreen();
171 }
172 else
173 {
174 handled = false;
175 }
176 }
177
178 if (!handled && MythScreenType::keyPressEvent(event))
179 handled = true;
180
181 return handled;
182}
183
185{
186 MythUIType *list = GetFocusWidget();
187 QString text;
188 if (!list)
189 return;
190
191 if (list == m_inactiveList)
192 {
193
195 if (!item)
196 return;
197
198 auto *si = item->GetData().value<ScreenListInfo *>();
199 if (!si)
200 return;
201
202 QStringList sources = si->m_sources;
203
204 text = tr("Add desired screen to the Active Screens list "
205 "by pressing SELECT.") + "\n";
206 text += si->m_title + "\n";
207 text += QString("%1: %2").arg(tr("Sources"), sources.join(", "));
208 }
209 else if (list == m_activeList)
210 {
212 if (!item)
213 return;
214
215 auto *si = item->GetData().value<ScreenListInfo *>();
216 if (!si)
217 return;
218
219 text += si->m_title + "\n";
220 if (si->m_hasUnits)
221 {
222 text += tr("Units: ");
223 text += (ENG_UNITS == si->m_units) ?
224 tr("English Units") : tr("SI Units");
225 text += " ";
226 }
227 if (!si->m_multiLoc && !si->m_types.empty())
228 {
229 TypeListInfo ti = *si->m_types.begin();
230 text += tr("Location: ");
231 text += (ti.m_location.isEmpty()) ? tr("Not Defined") : ti.m_location;
232 text += "\n";
233 text += tr("Source: " );
234 text += (ti.m_src) ? ti.m_src->name : tr("Not Defined");
235 text += "\n";
236 }
237 text += "\n" + tr("Press SELECT to ");
238 if (!si->m_multiLoc)
239 text += tr("change location; ");
240 if (si->m_hasUnits)
241 text += tr("change units; ");
242 text += tr("move screen up or down; or remove screen.");
243 }
244
245 m_helpText->SetText(text);
246}
247
249{
250 QStringList types;
251
252 ScreenListMap screenListMap = loadScreens();
253
254 // Fill the inactive screen button list.
255 ScreenListMap::const_iterator i = screenListMap.constBegin();
256 while (i != screenListMap.constEnd())
257 {
258 ScreenListInfo *si = &screenListMap[i.key()];
259 types = si->m_dataTypes;
260 si->m_units = ENG_UNITS;
261
262 QStringList type_strs;
263 for (const QString& type : std::as_const(types))
264 {
265 TypeListInfo ti(type);
266 si->m_types.insert(type, ti);
267 type_strs << type;
268 }
269
270 QList<ScriptInfo *> scriptList;
271 // Only add a screen to the list if we have a source
272 // available to satisfy the requirements.
273 if (m_sourceManager->findPossibleSources(type_strs, scriptList))
274 {
275 for (const auto *script : std::as_const(scriptList))
276 si->m_sources.append(script->name);
277 auto *item = new MythUIButtonListItem(m_inactiveList, si->m_title);
278 item->SetData(QVariant::fromValue(new ScreenListInfo(*si)));
279 }
280
281 ++i;
282 }
283
284 QMap<long, ScreenListInfo*> active_screens;
285
287 QString query = "SELECT weatherscreens.container, weatherscreens.units, "
288 "weatherdatalayout.dataitem, weatherdatalayout.location, "
289 "weathersourcesettings.source_name, weatherscreens.draworder "
290 "FROM weatherscreens, weatherdatalayout, weathersourcesettings "
291 "WHERE weatherscreens.hostname = :HOST "
292 "AND weatherscreens.screen_id = weatherdatalayout.weatherscreens_screen_id "
293 "AND weathersourcesettings.sourceid = weatherdatalayout.weathersourcesettings_sourceid "
294 "ORDER BY weatherscreens.draworder;";
295 db.prepare(query);
296 db.bindValue(":HOST", gCoreContext->GetHostName());
297 if (!db.exec())
298 {
299 LOG(VB_GENERAL, LOG_ERR, db.lastError().text());
300 return;
301 }
302
303 // Fill the active screen button list.
304 while (db.next())
305 {
306 QString name = db.value(0).toString();
307 units_t units = db.value(1).toUInt();
308 QString dataitem = db.value(2).toString();
309 QString location = db.value(3).toString();
310 QString src = db.value(4).toString();
311 uint draworder = db.value(5).toUInt();
312
313 types = screenListMap[name].m_dataTypes;
314
315 TypeListInfo ti(dataitem, location,
317
318 if (!active_screens.contains(draworder))
319 {
320 auto *si = new ScreenListInfo(screenListMap[name]);
321 // Clear types first as we will re-insert the values from the database
322 si->m_types.clear();
323 si->m_units = units;
324
325 auto *item = new MythUIButtonListItem(m_activeList, si->m_title);
326
327 // Only insert types meant for this screen
328 for (const auto & type : std::as_const(types))
329 {
330 if (type == dataitem)
331 si->m_types.insert(dataitem, ti);
332 }
333
334 item->SetData(QVariant::fromValue(si));
335 active_screens.insert(draworder, si);
336 }
337 else
338 {
339 ScreenListInfo *si = active_screens[draworder];
340 for (const auto & type : std::as_const(types))
341 {
342 if (type == dataitem)
343 {
344 si->m_types.insert(dataitem, ti);
345 }
346 }
347 }
348 }
349}
350
352{
353 // check if all active screens have sources/locations defined
354 QStringList notDefined;
355
356 for (int i=0; i < m_activeList->GetCount(); i++)
357 {
359 auto *si = item->GetData().value<ScreenListInfo *>();
360 for (const auto & type : std::as_const(si->m_types))
361 {
362 if (type.m_src)
363 continue;
364
365 notDefined << type.m_name;
366 LOG(VB_GENERAL, LOG_ERR, QString("Not defined %1").arg(type.m_name));
367 }
368 }
369
370 if (!notDefined.empty())
371 {
372 LOG(VB_GENERAL, LOG_ERR, "A Selected screen has data items with no "
373 "sources defined.");
374 return;
375 }
376
379 QString query = "DELETE FROM weatherscreens WHERE hostname=:HOST";
380 db.prepare(query);
381 db.bindValue(":HOST", gCoreContext->GetHostName());
382 if (!db.exec())
383 MythDB::DBError("ScreenSetup::saveData - delete weatherscreens", db);
384
385 query = "INSERT into weatherscreens (draworder, container, units, hostname) "
386 "VALUES (:DRAW, :CONT, :UNITS, :HOST);";
387 db.prepare(query);
388
389 int draworder = 0;
390 for (int i=0; i < m_activeList->GetCount(); i++)
391 {
393 auto *si = item->GetData().value<ScreenListInfo *>();
394 db.bindValue(":DRAW", draworder);
395 db.bindValue(":CONT", si->m_name);
396 db.bindValue(":UNITS", si->m_units);
397 db.bindValue(":HOST", gCoreContext->GetHostName());
398 if (db.exec())
399 {
400 // TODO see comment in dbcheck.cpp for way to improve
401 QString query2 = "SELECT screen_id FROM weatherscreens "
402 "WHERE draworder = :DRAW AND hostname = :HOST;";
403 db2.prepare(query2);
404 db2.bindValue(":DRAW", draworder);
405 db2.bindValue(":HOST", gCoreContext->GetHostName());
406 if (!db2.exec() || !db2.next())
407 {
408 LOG(VB_GENERAL, LOG_ERR, db2.executedQuery());
409 LOG(VB_GENERAL, LOG_ERR, db2.lastError().text());
410 return;
411 }
412
413 int screen_id = db2.value(0).toInt();
414
415 query2 = "INSERT INTO weatherdatalayout (location, dataitem, "
416 "weatherscreens_screen_id, weathersourcesettings_sourceid) "
417 "VALUES (:LOC, :ITEM, :SCREENID, :SRCID);";
418 db2.prepare(query2);
419 for (const auto & type : std::as_const(si->m_types))
420 {
421 db2.bindValue(":LOC", type.m_location);
422 db2.bindValue(":ITEM", type.m_name);
423 db2.bindValue(":SCREENID", screen_id);
424 db2.bindValue(":SRCID", type.m_src->id);
425 if (!db2.exec())
426 {
427 LOG(VB_GENERAL, LOG_ERR, db2.executedQuery());
428 LOG(VB_GENERAL, LOG_ERR, db2.lastError().text());
429 return;
430 }
431 }
432 }
433 else
434 {
435 LOG(VB_GENERAL, LOG_ERR, db.executedQuery());
436 LOG(VB_GENERAL, LOG_ERR, db.lastError().text());
437 return;
438 }
439
440 ++draworder;
441 }
442
443 Close();
444}
445
447{
448 if (!selected)
449 return;
450
452 {
453 auto *si = selected->GetData().value<ScreenListInfo *>();
454
455 QString label = tr("Manipulate Screen");
456
457 MythScreenStack *popupStack =
458 GetMythMainWindow()->GetStack("popup stack");
459
460 auto *menuPopup = new MythDialogBox(label, popupStack,
461 "screensetupmenupopup");
462
463 if (menuPopup->Create())
464 {
465 popupStack->AddScreen(menuPopup);
466
467 menuPopup->SetReturnEvent(this, "options");
468
469 menuPopup->AddButtonV(tr("Move Up"), QVariant::fromValue(selected));
470 menuPopup->AddButtonV(tr("Move Down"), QVariant::fromValue(selected));
471 menuPopup->AddButtonV(tr("Remove"), QVariant::fromValue(selected));
472 menuPopup->AddButtonV(tr("Change Location"), QVariant::fromValue(selected));
473 if (si->m_hasUnits)
474 menuPopup->AddButtonV(tr("Change Units"), QVariant::fromValue(selected));
475 menuPopup->AddButtonV(tr("Cancel"), QVariant::fromValue(selected));
476 }
477 else
478 {
479 delete menuPopup;
480 }
481
482 }
483 else if (GetFocusWidget() == m_inactiveList)
484 {
485 auto *si = selected->GetData().value<ScreenListInfo *>();
486 QStringList type_strs;
487
489 // NOLINTNEXTLINE(modernize-loop-convert)
490 for (auto it = si->m_types.begin(); it != si->m_types.end(); ++it)
491 {
492 types.insert(it.key(), *it);
493 type_strs << it.key();
494 }
495 bool hasUnits = si->m_hasUnits;
496
497 QList<ScriptInfo *> tmp;
498 if (m_sourceManager->findPossibleSources(type_strs, tmp))
499 {
500 if (!m_inactiveList->GetCount())
501 {
502 //m_inactiveList->SetActive(false);
504 }
505 if (hasUnits)
506 showUnitsPopup(selected->GetText(), si);
507 else
509 }
510 else
511 {
512 LOG(VB_GENERAL, LOG_ERR, "Screen cannot be used, not all required "
513 "data is supplied by existing sources");
514 }
515 }
516}
517
519{
520 MythScreenStack *mainStack =
522
523 auto *locdialog = new LocationDialog(mainStack, "locationdialog",
524 this, si, m_sourceManager);
525
526 if (locdialog->Create())
527 mainStack->AddScreen(locdialog);
528 else
529 delete locdialog;
530}
531
532void ScreenSetup::showUnitsPopup(const QString &name, ScreenListInfo *si)
533{
534 if (!si)
535 return;
536
537 QString label = QString("%1 %2").arg(name, tr("Change Units"));
538
539 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
540
541 auto *menuPopup = new MythDialogBox(label, popupStack, "weatherunitspopup");
542
543 if (menuPopup->Create())
544 {
545 popupStack->AddScreen(menuPopup);
546
547 menuPopup->SetReturnEvent(this, "units");
548
549 menuPopup->AddButtonV(tr("English Units"), QVariant::fromValue(si));
550 menuPopup->AddButtonV(tr("SI Units"), QVariant::fromValue(si));
551 }
552 else
553 {
554 delete menuPopup;
555 }
556}
557
559{
561 if (item)
562 {
563 if (item->GetData().isValid())
564 delete item->GetData().value<ScreenListInfo *>();
565
566 delete item;
567 }
568
569 if (!m_activeList->GetCount())
570 {
571 NextPrevWidgetFocus(false);
572 m_activeList->SetEnabled(false);
573 }
574}
575
576void ScreenSetup::customEvent(QEvent *event)
577{
578 if (event->type() == DialogCompletionEvent::kEventType)
579 {
580 auto *dce = dynamic_cast<DialogCompletionEvent*>(event);
581 if (dce == nullptr)
582 return;
583
584 QString resultid = dce->GetId();
585 int buttonnum = dce->GetResult();
586
587 if (resultid == "options")
588 {
589 if (buttonnum > -1)
590 {
591 auto *item = dce->GetData().value<MythUIButtonListItem *>();
592 auto *si = item->GetData().value<ScreenListInfo *>();
593
594 if (buttonnum == 0)
595 {
596 m_activeList->MoveItemUpDown(item, true);
597 }
598 else if (buttonnum == 1)
599 {
600 m_activeList->MoveItemUpDown(item, false);
601 }
602 else if (buttonnum == 2)
603 {
604 deleteScreen();
605 }
606 else if (buttonnum == 3)
607 {
608 si->m_updating = true;
610 }
611 else if (si->m_hasUnits && buttonnum == 4)
612 {
613 si->m_updating = true;
614 showUnitsPopup(item->GetText(), si);
616 }
617 }
618 }
619 else if (resultid == "units")
620 {
621 if (buttonnum > -1)
622 {
623 auto *si = dce->GetData().value<ScreenListInfo *>();
624
625 if (buttonnum == 0)
626 {
627 si->m_units = ENG_UNITS;
628 }
629 else if (buttonnum == 1)
630 {
631 si->m_units = SI_UNITS;
632 }
633
635
636 if (si->m_updating)
637 si->m_updating = false;
638 else
640 }
641 }
642 else if (resultid == "location")
643 {
644 auto *si = dce->GetData().value<ScreenListInfo *>();
645
646 auto emptyloc = [](const auto & type)
647 { return type.m_location.isEmpty(); };
648 if (std::ranges::any_of(std::as_const(si->m_types), emptyloc))
649 return;
650
651 if (si->m_updating)
652 {
653 si->m_updating = false;
655 if (item)
656 item->SetData(QVariant::fromValue(si));
657 }
658 else
659 {
660 auto *item = new MythUIButtonListItem(m_activeList, si->m_title);
661 item->SetData(QVariant::fromValue(si));
662 }
663
664 if (m_activeList->GetCount())
666 }
667 }
668}
669
671
673{
674 for (int i=0; i < m_sourceList->GetCount(); i++)
675 {
677 if (item->GetData().isValid())
678 delete item->GetData().value<SourceListInfo *>();
679 }
680}
681
683{
684 // Load the theme for this screen
685 bool foundtheme = LoadWindowFromXML("weather-ui.xml", "source-setup", this);
686 if (!foundtheme)
687 return false;
688
689 m_sourceList = dynamic_cast<MythUIButtonList *> (GetChild("srclist"));
690 m_updateSpinbox = dynamic_cast<MythUISpinBox *> (GetChild("update_spinbox"));
691 m_retrieveSpinbox = dynamic_cast<MythUISpinBox *> (GetChild("retrieve_spinbox"));
692 m_finishButton = dynamic_cast<MythUIButton *> (GetChild("finishbutton"));
693 m_sourceText = dynamic_cast<MythUIText *> (GetChild("srcinfo"));
694
697 {
698 LOG(VB_GENERAL, LOG_ERR, "Theme is missing required elements.");
699 return false;
700 }
701
704
706 this, qOverload<MythUIButtonListItem *>(&SourceSetup::sourceListItemSelected));
707#if 0
709 this, qOverload<>(&SourceSetup::sourceListItemSelected));
710#endif
711
712 // 12 Hour max interval
713 m_updateSpinbox->SetRange(10, 720, 10);
716
717 // 2 Minute retrieval timeout max
718 m_retrieveSpinbox->SetRange(10, 120, 5);
721
722 m_finishButton->SetText(tr("Finish"));
724
725 loadData();
726
727 return true;
728}
729
731{
733 QString query =
734 "SELECT DISTINCT sourceid, source_name, update_timeout, retrieve_timeout, "
735 "author, email, version FROM weathersourcesettings, weatherdatalayout "
736 "WHERE weathersourcesettings.sourceid = weatherdatalayout.weathersourcesettings_sourceid "
737 "AND hostname=:HOST;";
738 db.prepare(query);
739 db.bindValue(":HOST", gCoreContext->GetHostName());
740 if (!db.exec())
741 {
742 LOG(VB_GENERAL, LOG_ERR, db.lastError().text());
743 return false;
744 }
745
746 if (!db.size())
747 {
748 return false;
749 }
750
751 while (db.next())
752 {
753 auto *si = new SourceListInfo;
754 si->id = db.value(0).toUInt();
755 si->name = db.value(1).toString();
756 si->update_timeout = std::chrono::minutes(db.value(2).toUInt() / 60);
757 si->retrieve_timeout = std::chrono::seconds(db.value(3).toUInt());
758 si->author = db.value(4).toString();
759 si->email = db.value(5).toString();
760 si->version = db.value(6).toString();
761
762 new MythUIButtonListItem(m_sourceList, si->name, QVariant::fromValue(si));
763 }
764
765 return true;
766}
767
769{
771
772 if (curritem)
773 {
774 auto *si = curritem->GetData().value<SourceListInfo *>();
775 si->update_timeout = m_updateSpinbox->GetDuration<std::chrono::minutes>();
776 si->retrieve_timeout = m_retrieveSpinbox->GetDuration<std::chrono::seconds>();
777 }
778
780 QString query = "UPDATE weathersourcesettings "
781 "SET update_timeout = :UPDATE, retrieve_timeout = :RETRIEVE "
782 "WHERE sourceid = :ID;";
783 db.prepare(query);
784
785 for (int i=0; i < m_sourceList->GetCount(); i++)
786 {
788 auto *si = item->GetData().value<SourceListInfo *>();
789 db.bindValue(":ID", si->id);
790 db.bindValue(":UPDATE", (int)duration_cast<std::chrono::seconds>(si->update_timeout).count());
791 db.bindValue(":RETRIEVE", (int)si->retrieve_timeout.count());
792 if (!db.exec())
793 {
794 LOG(VB_GENERAL, LOG_ERR, db.lastError().text());
795 return;
796 }
797 }
798
799 Close();
800}
801
803{
805 {
806 auto *si = m_sourceList->GetItemCurrent()->GetData().value<SourceListInfo *>();
807 si->update_timeout = m_updateSpinbox->GetDuration<std::chrono::minutes>();
808 }
809}
810
812{
814 {
815 auto *si = m_sourceList->GetItemCurrent()->GetData().value<SourceListInfo *>();
816 si->retrieve_timeout = m_retrieveSpinbox->GetDuration<std::chrono::seconds>();
817 }
818}
819
821{
822 if (!item)
824
825 if (!item)
826 return;
827
828 auto *si = item->GetData().value<SourceListInfo *>();
829 if (!si)
830 return;
831
832 m_updateSpinbox->SetDuration<std::chrono::minutes>(si->update_timeout);
833 m_retrieveSpinbox->SetDuration<std::chrono::seconds>(si->retrieve_timeout);
834 QString txt = tr("Author: ");
835 txt += si->author;
836 txt += "\n" + tr("Email: ") + si->email;
837 txt += "\n" + tr("Version: ") + si->version;
838 m_sourceText->SetText(txt);
839}
840
842
844 MythScreenType *retScreen, ScreenListInfo *si,
845 SourceManager *srcman)
846 : MythScreenType(parent, name),
847 m_screenListInfo(new ScreenListInfo(*si)), m_sourceManager(srcman),
848 m_retScreen(retScreen)
849{
850 for (const auto & type : std::as_const(si->m_types))
851 m_types << type.m_name;
852}
853
855{
857 clearResults();
858
859 delete m_screenListInfo;
860}
861
863{
864 // Load the theme for this screen
865 bool foundtheme = LoadWindowFromXML("weather-ui.xml", "setup-location", this);
866 if (!foundtheme)
867 return false;
868
869 m_sourceText = dynamic_cast<MythUIText *> (GetChild("source"));
870 m_resultsText = dynamic_cast<MythUIText *> (GetChild("numresults"));
871 m_locationEdit = dynamic_cast<MythUITextEdit *> (GetChild("loc-edit"));
872 m_locationList = dynamic_cast<MythUIButtonList *> (GetChild("results"));
873 m_searchButton = dynamic_cast<MythUIButton *> (GetChild("searchbtn"));
874
875
877 || !m_searchButton)
878 {
879 LOG(VB_GENERAL, LOG_ERR, "Theme is missing required elements.");
880 return false;
881 }
882
885
887 m_searchButton->SetText(tr("Search"));
892
893 return true;
894}
895
897{
898 QString busymessage = tr("Searching...");
899
900 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
901
902 auto *busyPopup = new MythUIBusyDialog(busymessage, popupStack,
903 "mythweatherbusydialog");
904
905 if (busyPopup->Create())
906 {
907 popupStack->AddScreen(busyPopup, false);
908 }
909 else
910 {
911 delete busyPopup;
912 busyPopup = nullptr;
913 }
914
915
916 QHash<ScriptInfo *, QStringList> result_cache;
917 int numresults = 0;
918 clearResults();
919
920 QString searchingresults = tr("Searching... Results: %1");
921
922 m_resultsText->SetText(searchingresults.arg(0));
923 QCoreApplication::processEvents();
924
925 QList<ScriptInfo *> sources;
926 // if a screen makes it this far, theres at least one source for it
928 QString search = m_locationEdit->GetText();
929 for (auto *si : std::as_const(sources))
930 {
931 if (!result_cache.contains(si))
932 {
933 QStringList results = m_sourceManager->getLocationList(si, search);
934 result_cache[si] = results;
935 numresults += results.size();
936 m_resultsText->SetText(searchingresults.arg(numresults));
937 QCoreApplication::processEvents();
938 }
939 }
940
941 for (auto it = result_cache.begin(); it != result_cache.end(); ++it)
942 {
943 ScriptInfo *si = it.key();
944 QStringList results = it.value();
945 QString name = si->name;
946 QStringList::iterator rit;
947 for (rit = results.begin(); rit != results.end(); ++rit)
948 {
949 QStringList tmp = (*rit).split("::");
950 if (tmp.size() < 2)
951 {
952 LOG(VB_GENERAL, LOG_WARNING,
953 QString("Invalid line in Location Search reponse "
954 "from %1: %2").arg(name, *rit));
955 continue;
956 }
957 QString resultstring = QString("%1 (%2)").arg(tmp[1], name);
958 auto *item = new MythUIButtonListItem(m_locationList, resultstring);
959 auto *ri = new ResultListInfo;
960 ri->idstr = tmp[0];
961 ri->src = si;
962 item->SetData(QVariant::fromValue(ri));
963 QCoreApplication::processEvents();
964 }
965 }
966
967 if (busyPopup)
968 {
969 busyPopup->Close();
970 busyPopup = nullptr;
971 }
972
973 m_resultsText->SetText(tr("Search Complete. Results: %1").arg(numresults));
974 if (numresults)
976}
977
979{
980 for (int i=0; i < m_locationList->GetCount(); i++)
981 {
983 if (item->GetData().isValid())
984 delete item->GetData().value<ResultListInfo *>();
985 }
986
988}
989
991{
992 auto *ri = item->GetData().value<ResultListInfo *>();
993 if (ri)
994 m_sourceText->SetText(tr("Source: %1").arg(ri->src->name));
995}
996
998{
999 auto *ri = item->GetData().value<ResultListInfo *>();
1000 if (ri)
1001 {
1002 // NOLINTNEXTLINE(modernize-loop-convert)
1003 for (auto it = m_screenListInfo->m_types.begin();
1004 it != m_screenListInfo->m_types.end(); ++it)
1005 {
1006 (*it).m_location = ri->idstr;
1007 (*it).m_src = ri->src;
1008 }
1009 }
1010
1011 auto *dce = new DialogCompletionEvent("location", 0, "",
1012 QVariant::fromValue(new ScreenListInfo(*m_screenListInfo)));
1013 QApplication::postEvent(m_retScreen, dce);
1014
1015 Close();
1016}
Event dispatched from MythUI modal dialogs to a listening class containing a result of some form.
Definition: mythdialogbox.h:41
static const Type kEventType
Definition: mythdialogbox.h:56
void saveData(void)
bool Create(void) override
void loadData(void)
MythUICheckBox * m_backgroundCheckbox
Definition: weatherSetup.h:57
MythUISpinBox * m_timeoutSpinbox
Definition: weatherSetup.h:58
MythUIButton * m_finishButton
Definition: weatherSetup.h:60
ScreenListInfo * m_screenListInfo
Definition: weatherSetup.h:160
SourceManager * m_sourceManager
Definition: weatherSetup.h:161
MythUIText * m_sourceText
Definition: weatherSetup.h:169
LocationDialog(MythScreenStack *parent, const QString &name, MythScreenType *retScreen, ScreenListInfo *si, SourceManager *srcman)
MythUITextEdit * m_locationEdit
Definition: weatherSetup.h:166
MythUIButtonList * m_locationList
Definition: weatherSetup.h:165
bool Create(void) override
~LocationDialog() override
void itemClicked(MythUIButtonListItem *item)
QStringList m_types
Definition: weatherSetup.h:159
MythUIButton * m_searchButton
Definition: weatherSetup.h:167
void doSearch(void)
MythScreenType * m_retScreen
Definition: weatherSetup.h:163
void itemSelected(MythUIButtonListItem *item)
MythUIText * m_resultsText
Definition: weatherSetup.h:168
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:128
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:838
QString executedQuery(void) const
Definition: mythdbcon.h:205
QSqlError lastError(void) const
Definition: mythdbcon.h:213
QVariant value(int i) const
Definition: mythdbcon.h:204
int size(void) const
Definition: mythdbcon.h:214
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:619
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:889
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:813
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:551
QString GetHostName(void)
void SaveSetting(const QString &key, int newValue)
int GetNumSetting(const QString &key, int defaultval=0)
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:225
Basic menu dialog, message and a list of options.
MythScreenStack * GetMainStack()
bool TranslateKeyPress(const QString &Context, QKeyEvent *Event, QStringList &Actions, bool AllowJumps=true)
Get a list of actions for a keypress in the given context.
MythScreenStack * GetStack(const QString &Stackname)
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Screen in which all other widgets are contained and rendered.
virtual bool NextPrevWidgetFocus(bool up_or_down)
void BuildFocusList(void)
MythUIType * GetFocusWidget(void) const
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
bool SetFocusWidget(MythUIType *widget=nullptr)
virtual void Close()
void SetData(QVariant data)
QString GetText(const QString &name="") const
List widget, displays list items in a variety of themeable arrangements and can trigger signals when ...
bool MoveItemUpDown(MythUIButtonListItem *item, bool up)
MythUIButtonListItem * GetItemCurrent() const
void Reset() override
Reset the widget to it's original state, should not reset changes made by the theme.
void itemClicked(MythUIButtonListItem *item)
MythUIButtonListItem * GetItemAt(int pos) const
void itemSelected(MythUIButtonListItem *item)
A single button widget.
Definition: mythuibutton.h:22
void SetText(const QString &msg)
void Clicked()
A checkbox widget supporting three check states - on,off,half and two conditions - selected and unsel...
void SetCheckState(MythUIStateType::StateType state)
MythUIStateType::StateType GetCheckState() const
A widget for offering a range of numerical values where only the the bounding values and interval are...
Definition: mythuispinbox.h:19
void SetRange(int low, int high, int step, uint pageMultiple=5)
Set the lower and upper bounds of the spinbox, the interval and page amount.
void SetValue(int val) override
Definition: mythuispinbox.h:28
void SetDuration(T val)
Definition: mythuispinbox.h:45
int GetIntValue(void) const override
Definition: mythuispinbox.h:35
A text entry and edit widget.
QString GetText(void) const
All purpose text widget, displays a text string.
Definition: mythuitext.h:29
virtual void SetText(const QString &text)
Definition: mythuitext.cpp:115
The base class on which all widgets and screens are based.
Definition: mythuitype.h:97
void TakingFocus(void)
void SetEnabled(bool enable)
MythUIType * GetChild(const QString &name) const
Get a named child of this UIType.
Definition: mythuitype.cpp:130
void LosingFocus(void)
TypeListMap m_types
Definition: weatherUtils.h:56
QStringList m_sources
Definition: weatherUtils.h:59
QString m_title
Definition: weatherUtils.h:55
QStringList m_dataTypes
Definition: weatherUtils.h:57
units_t m_units
Definition: weatherUtils.h:60
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
MythUIButtonList * m_activeList
Definition: weatherSetup.h:92
void customEvent(QEvent *event) override
void loadData(void)
void saveData(void)
MythUIText * m_helpText
Definition: weatherSetup.h:91
MythUIButtonList * m_inactiveList
Definition: weatherSetup.h:93
~ScreenSetup() override
bool Create(void) override
SourceManager * m_sourceManager
Definition: weatherSetup.h:89
bool m_createdSrcMan
Definition: weatherSetup.h:90
MythUIButton * m_finishButton
Definition: weatherSetup.h:94
void doLocationDialog(ScreenListInfo *si)
void updateHelpText(void)
void doListSelect(MythUIButtonListItem *selected)
ScreenSetup(MythScreenStack *parent, const QString &name, SourceManager *srcman)
void deleteScreen(void)
void showUnitsPopup(const QString &name, ScreenListInfo *si)
QString name
Definition: weatherSource.h:24
bool findPossibleSources(QStringList types, QList< ScriptInfo * > &sources)
QStringList getLocationList(ScriptInfo *si, const QString &str)
ScriptInfo * getSourceByName(const QString &name)
void updateSpinboxUpdate(void)
MythUISpinBox * m_retrieveSpinbox
Definition: weatherSetup.h:121
MythUIText * m_sourceText
Definition: weatherSetup.h:124
void retrieveSpinboxUpdate(void)
MythUISpinBox * m_updateSpinbox
Definition: weatherSetup.h:120
void sourceListItemSelected(MythUIButtonListItem *item)
bool loadData(void)
bool Create(void) override
void saveData(void)
MythUIButtonList * m_sourceList
Definition: weatherSetup.h:122
~SourceSetup() override
MythUIButton * m_finishButton
Definition: weatherSetup.h:123
QString m_location
Definition: weatherUtils.h:43
ScriptInfo * m_src
Definition: weatherUtils.h:44
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
unsigned int uint
Definition: compat.h:60
static const struct wl_interface * types[]
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MythMainWindow * GetMythMainWindow(void)
std::chrono::seconds retrieve_timeout
Definition: weatherSetup.h:30
std::chrono::minutes update_timeout
Definition: weatherSetup.h:29
ScreenListMap loadScreens()
static constexpr uint8_t ENG_UNITS
Definition: weatherUtils.h:19
static constexpr uint8_t SI_UNITS
Definition: weatherUtils.h:18
QMap< QString, ScreenListInfo > ScreenListMap
Definition: weatherUtils.h:68
QMultiHash< QString, TypeListInfo > TypeListMap
Definition: weatherUtils.h:46
unsigned char units_t
Definition: weatherUtils.h:25