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