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