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