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  for (int x = 0; x < scriptList.size(); x++)
280  {
281  ScriptInfo *script = scriptList.at(x);
282  si->m_sources.append(script->name);
283  }
284  auto *item = new MythUIButtonListItem(m_inactiveList, si->m_title);
285  item->SetData(qVariantFromValue(new ScreenListInfo(*si)));
286  }
287 
288  ++i;
289  }
290 
291  QMap<long, ScreenListInfo*> active_screens;
292 
294  QString query = "SELECT weatherscreens.container, weatherscreens.units, "
295  "weatherdatalayout.dataitem, weatherdatalayout.location, "
296  "weathersourcesettings.source_name, weatherscreens.draworder "
297  "FROM weatherscreens, weatherdatalayout, weathersourcesettings "
298  "WHERE weatherscreens.hostname = :HOST "
299  "AND weatherscreens.screen_id = weatherdatalayout.weatherscreens_screen_id "
300  "AND weathersourcesettings.sourceid = weatherdatalayout.weathersourcesettings_sourceid "
301  "ORDER BY weatherscreens.draworder;";
302  db.prepare(query);
303  db.bindValue(":HOST", gCoreContext->GetHostName());
304  if (!db.exec())
305  {
306  LOG(VB_GENERAL, LOG_ERR, db.lastError().text());
307  return;
308  }
309 
310  // Fill the active screen button list.
311  while (db.next())
312  {
313  QString name = db.value(0).toString();
314  units_t units = db.value(1).toUInt();
315  QString dataitem = db.value(2).toString();
316  QString location = db.value(3).toString();
317  QString src = db.value(4).toString();
318  uint draworder = db.value(5).toUInt();
319 
320  types = screenListMap[name].m_dataTypes;
321 
322  TypeListInfo ti(dataitem, location,
324 
325  if (active_screens.find(draworder) == active_screens.end())
326  {
327  auto *si = new ScreenListInfo(screenListMap[name]);
328  // Clear types first as we will re-insert the values from the database
329  si->m_types.clear();
330  si->m_units = units;
331 
332  auto *item = new MythUIButtonListItem(m_activeList, si->m_title);
333 
334  // Only insert types meant for this screen
335  for (QStringList::Iterator type_i = types.begin();
336  type_i != types.end(); ++type_i )
337  {
338  if (*type_i == dataitem)
339  si->m_types.insert(dataitem, ti);
340  }
341 
342  item->SetData(qVariantFromValue(si));
343  active_screens.insert(draworder, si);
344  }
345  else
346  {
347  ScreenListInfo *si = active_screens[draworder];
348  for (QStringList::Iterator type_i = types.begin();
349  type_i != types.end(); ++type_i )
350  {
351  if (*type_i == dataitem)
352  {
353  si->m_types.insert(dataitem, ti);
354  }
355  }
356  }
357  }
358 }
359 
361 {
362  // check if all active screens have sources/locations defined
363  QStringList notDefined;
364 
365  for (int i=0; i < m_activeList->GetCount(); i++)
366  {
368  auto *si = item->GetData().value<ScreenListInfo *>();
369  TypeListMap::iterator it = si->m_types.begin();
370  for (; it != si->m_types.end(); ++it)
371  {
372  if ((*it).m_src)
373  continue;
374 
375  notDefined << (*it).m_name;
376  LOG(VB_GENERAL, LOG_ERR, QString("Not defined %1").arg((*it).m_name));
377  }
378  }
379 
380  if (!notDefined.empty())
381  {
382  LOG(VB_GENERAL, LOG_ERR, "A Selected screen has data items with no "
383  "sources defined.");
384  return;
385  }
386 
389  QString query = "DELETE FROM weatherscreens WHERE hostname=:HOST";
390  db.prepare(query);
391  db.bindValue(":HOST", gCoreContext->GetHostName());
392  if (!db.exec())
393  MythDB::DBError("ScreenSetup::saveData - delete weatherscreens", db);
394 
395  query = "INSERT into weatherscreens (draworder, container, units, hostname) "
396  "VALUES (:DRAW, :CONT, :UNITS, :HOST);";
397  db.prepare(query);
398 
399  int draworder = 0;
400  for (int i=0; i < m_activeList->GetCount(); i++)
401  {
403  auto *si = item->GetData().value<ScreenListInfo *>();
404  db.bindValue(":DRAW", draworder);
405  db.bindValue(":CONT", si->m_name);
406  db.bindValue(":UNITS", si->m_units);
407  db.bindValue(":HOST", gCoreContext->GetHostName());
408  if (db.exec())
409  {
410  // TODO see comment in dbcheck.cpp for way to improve
411  QString query2 = "SELECT screen_id FROM weatherscreens "
412  "WHERE draworder = :DRAW AND hostname = :HOST;";
413  db2.prepare(query2);
414  db2.bindValue(":DRAW", draworder);
415  db2.bindValue(":HOST", gCoreContext->GetHostName());
416  if (!db2.exec() || !db2.next())
417  {
418  LOG(VB_GENERAL, LOG_ERR, db2.executedQuery());
419  LOG(VB_GENERAL, LOG_ERR, db2.lastError().text());
420  return;
421  }
422 
423  int screen_id = db2.value(0).toInt();
424 
425  query2 = "INSERT INTO weatherdatalayout (location, dataitem, "
426  "weatherscreens_screen_id, weathersourcesettings_sourceid) "
427  "VALUES (:LOC, :ITEM, :SCREENID, :SRCID);";
428  db2.prepare(query2);
429  TypeListMap::iterator it = si->m_types.begin();
430  for (; it != si->m_types.end(); ++it)
431  {
432  db2.bindValue(":LOC", (*it).m_location);
433  db2.bindValue(":ITEM", (*it).m_name);
434  db2.bindValue(":SCREENID", screen_id);
435  db2.bindValue(":SRCID", (*it).m_src->id);
436  if (!db2.exec())
437  {
438  LOG(VB_GENERAL, LOG_ERR, db2.executedQuery());
439  LOG(VB_GENERAL, LOG_ERR, db2.lastError().text());
440  return;
441  }
442  }
443  }
444  else
445  {
446  LOG(VB_GENERAL, LOG_ERR, db.executedQuery());
447  LOG(VB_GENERAL, LOG_ERR, db.lastError().text());
448  return;
449  }
450 
451  ++draworder;
452  }
453 
454  Close();
455 }
456 
458 {
459  if (!selected)
460  return;
461 
462  QString txt = selected->GetText();
463  if (GetFocusWidget() == m_activeList)
464  {
465  auto *si = selected->GetData().value<ScreenListInfo *>();
466 
467  QString label = tr("Manipulate Screen");
468 
469  MythScreenStack *popupStack =
470  GetMythMainWindow()->GetStack("popup stack");
471 
472  auto *menuPopup = new MythDialogBox(label, popupStack,
473  "screensetupmenupopup");
474 
475  if (menuPopup->Create())
476  {
477  popupStack->AddScreen(menuPopup);
478 
479  menuPopup->SetReturnEvent(this, "options");
480 
481  menuPopup->AddButton(tr("Move Up"), qVariantFromValue(selected));
482  menuPopup->AddButton(tr("Move Down"), qVariantFromValue(selected));
483  menuPopup->AddButton(tr("Remove"), qVariantFromValue(selected));
484  menuPopup->AddButton(tr("Change Location"), qVariantFromValue(selected));
485  if (si->m_hasUnits)
486  menuPopup->AddButton(tr("Change Units"), qVariantFromValue(selected));
487  menuPopup->AddButton(tr("Cancel"), qVariantFromValue(selected));
488  }
489  else
490  {
491  delete menuPopup;
492  }
493 
494  }
495  else if (GetFocusWidget() == m_inactiveList)
496  {
497  auto *si = selected->GetData().value<ScreenListInfo *>();
498  QStringList type_strs;
499 
500  TypeListMap::iterator it = si->m_types.begin();
501  TypeListMap types;
502  for (; it != si->m_types.end(); ++it)
503  {
504  types.insert(it.key(), *it);
505  type_strs << it.key();
506  }
507  bool hasUnits = si->m_hasUnits;
508 
509  QList<ScriptInfo *> tmp;
510  if (m_sourceManager->findPossibleSources(type_strs, tmp))
511  {
512  if (!m_inactiveList->GetCount())
513  {
514  //m_inactiveList->SetActive(false);
515  NextPrevWidgetFocus(true);
516  }
517  if (hasUnits)
518  showUnitsPopup(selected->GetText(), si);
519  else
520  doLocationDialog(si);
521  }
522  else
523  LOG(VB_GENERAL, LOG_ERR, "Screen cannot be used, not all required "
524  "data is supplied by existing sources");
525  }
526 }
527 
529 {
530  MythScreenStack *mainStack =
532 
533  auto *locdialog = new LocationDialog(mainStack, "locationdialog",
534  this, si, m_sourceManager);
535 
536  if (locdialog->Create())
537  mainStack->AddScreen(locdialog);
538  else
539  delete locdialog;
540 }
541 
542 void ScreenSetup::showUnitsPopup(const QString &name, ScreenListInfo *si)
543 {
544  if (!si)
545  return;
546 
547  QString label = QString("%1 %2").arg(name).arg(tr("Change Units"));
548 
549  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
550 
551  auto *menuPopup = new MythDialogBox(label, popupStack, "weatherunitspopup");
552 
553  if (menuPopup->Create())
554  {
555  popupStack->AddScreen(menuPopup);
556 
557  menuPopup->SetReturnEvent(this, "units");
558 
559  menuPopup->AddButton(tr("English Units"), qVariantFromValue(si));
560  menuPopup->AddButton(tr("SI Units"), qVariantFromValue(si));
561  }
562  else
563  {
564  delete menuPopup;
565  }
566 }
567 
569 {
571  if (item)
572  {
573  if (item->GetData().isValid())
574  delete item->GetData().value<ScreenListInfo *>();
575 
576  delete item;
577  }
578 
579  if (!m_activeList->GetCount())
580  {
581  NextPrevWidgetFocus(false);
582  m_activeList->SetEnabled(false);
583  }
584 }
585 
586 void ScreenSetup::customEvent(QEvent *event)
587 {
588  if (event->type() == DialogCompletionEvent::kEventType)
589  {
590  auto dce = dynamic_cast<DialogCompletionEvent*>(event);
591  if (dce == nullptr)
592  return;
593 
594  QString resultid = dce->GetId();
595  int buttonnum = dce->GetResult();
596 
597  if (resultid == "options")
598  {
599  if (buttonnum > -1)
600  {
601  auto *item = dce->GetData().value<MythUIButtonListItem *>();
602  auto *si = item->GetData().value<ScreenListInfo *>();
603 
604  if (buttonnum == 0)
605  {
606  m_activeList->MoveItemUpDown(item, true);
607  }
608  else if (buttonnum == 1)
609  {
610  m_activeList->MoveItemUpDown(item, false);
611  }
612  else if (buttonnum == 2)
613  {
614  deleteScreen();
615  }
616  else if (buttonnum == 3)
617  {
618  si->m_updating = true;
619  doLocationDialog(si);
620  }
621  else if (si->m_hasUnits && buttonnum == 4)
622  {
623  si->m_updating = true;
624  showUnitsPopup(item->GetText(), si);
625  updateHelpText();
626  }
627  }
628  }
629  else if (resultid == "units")
630  {
631  if (buttonnum > -1)
632  {
633  auto *si = dce->GetData().value<ScreenListInfo *>();
634 
635  if (buttonnum == 0)
636  {
637  si->m_units = ENG_UNITS;
638  }
639  else if (buttonnum == 1)
640  {
641  si->m_units = SI_UNITS;
642  }
643 
644  updateHelpText();
645 
646  if (si->m_updating)
647  si->m_updating = false;
648  else
649  doLocationDialog(si);
650  }
651  }
652  else if (resultid == "location")
653  {
654  auto *si = dce->GetData().value<ScreenListInfo *>();
655 
656  TypeListMap::iterator it = si->m_types.begin();
657  for (; it != si->m_types.end(); ++it)
658  {
659  if ((*it).m_location.isEmpty())
660  return;
661  }
662 
663  if (si->m_updating)
664  {
665  si->m_updating = false;
667  if (item)
668  item->SetData(qVariantFromValue(si));
669  }
670  else
671  {
672  auto *item = new MythUIButtonListItem(m_activeList, si->m_title);
673  item->SetData(qVariantFromValue(si));
674  }
675 
676  if (m_activeList->GetCount())
677  m_activeList->SetEnabled(true);
678  }
679  }
680 }
681 
683 
684 SourceSetup::SourceSetup(MythScreenStack *parent, const QString &name)
685  : MythScreenType(parent, name)
686 {
687  m_sourceList = nullptr;
689  m_finishButton = nullptr;
690  m_sourceText = nullptr;
691 }
692 
694 {
695  for (int i=0; i < m_sourceList->GetCount(); i++)
696  {
698  if (item->GetData().isValid())
699  delete item->GetData().value<SourceListInfo *>();
700  }
701 }
702 
704 {
705  // Load the theme for this screen
706  bool foundtheme = LoadWindowFromXML("weather-ui.xml", "source-setup", this);
707  if (!foundtheme)
708  return false;
709 
710  m_sourceList = dynamic_cast<MythUIButtonList *> (GetChild("srclist"));
711  m_updateSpinbox = dynamic_cast<MythUISpinBox *> (GetChild("update_spinbox"));
712  m_retrieveSpinbox = dynamic_cast<MythUISpinBox *> (GetChild("retrieve_spinbox"));
713  m_finishButton = dynamic_cast<MythUIButton *> (GetChild("finishbutton"));
714  m_sourceText = dynamic_cast<MythUIText *> (GetChild("srcinfo"));
715 
718  {
719  LOG(VB_GENERAL, LOG_ERR, "Theme is missing required elements.");
720  return false;
721  }
722 
723  BuildFocusList();
725 
726  connect(m_sourceList, SIGNAL(itemSelected(MythUIButtonListItem *)),
728 #if 0
729  connect(m_sourceList, SIGNAL(TakingFocus()),
730  this, SLOT(sourceListItemSelected()));
731 #endif
732 
733  // 12 Hour max interval
734  m_updateSpinbox->SetRange(10, 720, 10);
735  connect(m_updateSpinbox, SIGNAL(LosingFocus()),
736  SLOT(updateSpinboxUpdate()));
737 
738  // 2 Minute retrieval timeout max
739  m_retrieveSpinbox->SetRange(10, 120, 5);
740  connect(m_retrieveSpinbox, SIGNAL(LosingFocus()),
741  SLOT(retrieveSpinboxUpdate()));
742 
743  m_finishButton->SetText(tr("Finish"));
744  connect(m_finishButton, SIGNAL(Clicked()), SLOT(saveData()));
745 
746  loadData();
747 
748  return true;
749 }
750 
752 {
754  QString query =
755  "SELECT DISTINCT sourceid, source_name, update_timeout, retrieve_timeout, "
756  "author, email, version FROM weathersourcesettings, weatherdatalayout "
757  "WHERE weathersourcesettings.sourceid = weatherdatalayout.weathersourcesettings_sourceid "
758  "AND hostname=:HOST;";
759  db.prepare(query);
760  db.bindValue(":HOST", gCoreContext->GetHostName());
761  if (!db.exec())
762  {
763  LOG(VB_GENERAL, LOG_ERR, db.lastError().text());
764  return false;
765  }
766 
767  if (!db.size())
768  {
769  return false;
770  }
771 
772  while (db.next())
773  {
774  auto *si = new SourceListInfo;
775  si->id = db.value(0).toUInt();
776  si->name = db.value(1).toString();
777  si->update_timeout = db.value(2).toUInt() / 60;
778  si->retrieve_timeout = db.value(3).toUInt();
779  si->author = db.value(4).toString();
780  si->email = db.value(5).toString();
781  si->version = db.value(6).toString();
782 
783  new MythUIButtonListItem(m_sourceList, si->name, qVariantFromValue(si));
784  }
785 
786  return true;
787 }
788 
790 {
792 
793  if (curritem)
794  {
795  auto *si = curritem->GetData().value<SourceListInfo *>();
797  si->retrieve_timeout = m_retrieveSpinbox->GetIntValue();
798  }
799 
801  QString query = "UPDATE weathersourcesettings "
802  "SET update_timeout = :UPDATE, retrieve_timeout = :RETRIEVE "
803  "WHERE sourceid = :ID;";
804  db.prepare(query);
805 
806  for (int i=0; i < m_sourceList->GetCount(); i++)
807  {
809  auto *si = item->GetData().value<SourceListInfo *>();
810  db.bindValue(":ID", si->id);
811  db.bindValue(":UPDATE", si->update_timeout * 60);
812  db.bindValue(":RETRIEVE", si->retrieve_timeout);
813  if (!db.exec())
814  {
815  LOG(VB_GENERAL, LOG_ERR, db.lastError().text());
816  return;
817  }
818  }
819 
820  Close();
821 }
822 
824 {
826  {
827  auto *si = m_sourceList->GetItemCurrent()->GetData().value<SourceListInfo *>();
829  }
830 }
831 
833 {
835  {
836  auto *si = m_sourceList->GetItemCurrent()->GetData().value<SourceListInfo *>();
838  }
839 }
840 
842 {
843  if (!item)
844  item = m_sourceList->GetItemCurrent();
845 
846  if (!item)
847  return;
848 
849  auto *si = item->GetData().value<SourceListInfo *>();
850  if (!si)
851  return;
852 
853  m_updateSpinbox->SetValue(si->update_timeout);
854  m_retrieveSpinbox->SetValue(si->retrieve_timeout);
855  QString txt = tr("Author: ");
856  txt += si->author;
857  txt += "\n" + tr("Email: ") + si->email;
858  txt += "\n" + tr("Version: ") + si->version;
859  m_sourceText->SetText(txt);
860 }
861 
863 
864 LocationDialog::LocationDialog(MythScreenStack *parent, const QString &name,
865  MythScreenType *retScreen, ScreenListInfo *si,
866  SourceManager *srcman)
867  : MythScreenType(parent, name),
868  m_screenListInfo(new ScreenListInfo(*si)), m_sourceManager(srcman),
869  m_retScreen(retScreen), m_locationList(nullptr),
870  m_locationEdit(nullptr),m_searchButton(nullptr),
871  m_resultsText(nullptr), m_sourceText(nullptr)
872 {
873  TypeListMap::iterator it = si->m_types.begin();
874  for (; it != si->m_types.end(); ++it)
875  m_types << (*it).m_name;
876 }
877 
879 {
880  if(m_locationList)
881  clearResults();
882 
883  delete m_screenListInfo;
884 }
885 
887 {
888  // Load the theme for this screen
889  bool foundtheme = LoadWindowFromXML("weather-ui.xml", "setup-location", this);
890  if (!foundtheme)
891  return false;
892 
893  m_sourceText = dynamic_cast<MythUIText *> (GetChild("source"));
894  m_resultsText = dynamic_cast<MythUIText *> (GetChild("numresults"));
895  m_locationEdit = dynamic_cast<MythUITextEdit *> (GetChild("loc-edit"));
896  m_locationList = dynamic_cast<MythUIButtonList *> (GetChild("results"));
897  m_searchButton = dynamic_cast<MythUIButton *> (GetChild("searchbtn"));
898 
899 
901  || !m_searchButton)
902  {
903  LOG(VB_GENERAL, LOG_ERR, "Theme is missing required elements.");
904  return false;
905  }
906 
907  BuildFocusList();
909 
910  connect(m_searchButton, SIGNAL(Clicked()), this, SLOT(doSearch()));
911  m_searchButton->SetText(tr("Search"));
913  this, SLOT(itemSelected(MythUIButtonListItem *)));
914  connect(m_locationList, SIGNAL(itemClicked(MythUIButtonListItem *)),
915  this, SLOT(itemClicked(MythUIButtonListItem *)));
916 
917  return true;
918 }
919 
921 {
922  QString busymessage = tr("Searching...");
923 
924  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
925 
926  auto *busyPopup = new MythUIBusyDialog(busymessage, popupStack,
927  "mythweatherbusydialog");
928 
929  if (busyPopup->Create())
930  {
931  popupStack->AddScreen(busyPopup, false);
932  }
933  else
934  {
935  delete busyPopup;
936  busyPopup = nullptr;
937  }
938 
939 
940  QMap<ScriptInfo *, QStringList> result_cache;
941  int numresults = 0;
942  clearResults();
943 
944  QString searchingresults = tr("Searching... Results: %1");
945 
946  m_resultsText->SetText(searchingresults.arg(0));
947  qApp->processEvents();
948 
949  QList<ScriptInfo *> sources;
950  // if a screen makes it this far, theres at least one source for it
952  QString search = m_locationEdit->GetText();
953  for (int x = 0; x < sources.size(); x++)
954  {
955  ScriptInfo *si = sources.at(x);
956  if (!result_cache.contains(si))
957  {
958  QStringList results = m_sourceManager->getLocationList(si, search);
959  result_cache[si] = results;
960  numresults += results.size();
961  m_resultsText->SetText(searchingresults.arg(numresults));
962  qApp->processEvents();
963  }
964  }
965 
966  QMap<ScriptInfo *, QStringList>::iterator it;
967  for (it = result_cache.begin(); it != result_cache.end(); ++it)
968  {
969  ScriptInfo *si = it.key();
970  QStringList results = it.value();
971  QString name = si->name;
972  QStringList::iterator rit;
973  for (rit = results.begin(); rit != results.end(); ++rit)
974  {
975  QStringList tmp = (*rit).split("::");
976  if (tmp.size() < 2)
977  {
978  LOG(VB_GENERAL, LOG_WARNING,
979  QString("Invalid line in Location Search reponse "
980  "from %1: %2")
981  .arg(name).arg(*rit));
982  continue;
983  }
984  QString resultstring = QString("%1 (%2)").arg(tmp[1]).arg(name);
985  auto *item = new MythUIButtonListItem(m_locationList, resultstring);
986  auto *ri = new ResultListInfo;
987  ri->idstr = tmp[0];
988  ri->src = si;
989  item->SetData(qVariantFromValue(ri));
990  qApp->processEvents();
991  }
992  }
993 
994  if (busyPopup)
995  {
996  busyPopup->Close();
997  busyPopup = nullptr;
998  }
999 
1000  m_resultsText->SetText(tr("Search Complete. Results: %1").arg(numresults));
1001  if (numresults)
1003 }
1004 
1006 {
1007  for (int i=0; i < m_locationList->GetCount(); i++)
1008  {
1010  if (item->GetData().isValid())
1011  delete item->GetData().value<ResultListInfo *>();
1012  }
1013 
1014  m_locationList->Reset();
1015 }
1016 
1018 {
1019  auto *ri = item->GetData().value<ResultListInfo *>();
1020  if (ri)
1021  m_sourceText->SetText(tr("Source: %1").arg(ri->src->name));
1022 }
1023 
1025 {
1026  auto *ri = item->GetData().value<ResultListInfo *>();
1027  if (ri)
1028  {
1029  TypeListMap::iterator it = m_screenListInfo->m_types.begin();
1030  for (; it != m_screenListInfo->m_types.end(); ++it)
1031  {
1032  (*it).m_location = ri->idstr;
1033  (*it).m_src = ri->src;
1034  }
1035  }
1036 
1037  auto *dce = new DialogCompletionEvent("location", 0, "",
1038  qVariantFromValue(new ScreenListInfo(*m_screenListInfo)));
1039  QApplication::postEvent(m_retScreen, dce);
1040 
1041  Close();
1042 }
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:782
MythUIButtonList * m_sourceList
Definition: weatherSetup.h:120
void doListSelect(MythUIButtonListItem *selected)
MythUIButton * m_searchButton
Definition: weatherSetup.h:165
MythUIButton * m_finishButton
Definition: weatherSetup.h:121
QStringList m_sources
Definition: weatherUtils.h:70
TypeListMap m_types
Definition: weatherUtils.h:67
#define ENG_UNITS
Definition: weatherUtils.h:16
MythUISpinBox * m_timeoutSpinbox
Definition: weatherSetup.h:59
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:863
MythUIStateType::StateType GetCheckState() const
void saveData(void)
SourceManager * m_sourceManager
Definition: weatherSetup.h:159
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:96
QString name
Definition: weatherSource.h:21
All purpose text widget, displays a text string.
Definition: mythuitext.h:28
ScreenListInfo * m_screenListInfo
Definition: weatherSetup.h:158
void SetData(QVariant data)
void SaveSetting(const QString &key, int newValue)
SourceManager * m_sourceManager
Definition: weatherSetup.h:91
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)
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 doSearch(void)
MythUIButtonListItem * GetItemAt(int pos) const
MythUICheckBox * m_backgroundCheckbox
Definition: weatherSetup.h:58
MythUISpinBox * m_retrieveSpinbox
Definition: weatherSetup.h:119
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:161
static Type kEventType
Definition: mythdialogbox.h:50
bool Create(void) override
int GetIntValue(void) const override
Definition: mythuispinbox.h:33
MythUIButton * m_finishButton
Definition: weatherSetup.h:62
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:167
MythUISpinBox * m_updateSpinbox
Definition: weatherSetup.h:118
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:164
bool findPossibleSources(QStringList types, QList< ScriptInfo * > &sources)
unsigned int uint
Definition: compat.h:140
MythUIText * m_resultsText
Definition: weatherSetup.h:166
static MSqlQueryInfo InitCon(ConnectionReuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:535
QMultiHash< QString, TypeListInfo > TypeListMap
Definition: weatherUtils.h:44
bool m_createdSrcMan
Definition: weatherSetup.h:92
void customEvent(QEvent *) override
bool Create(void) override
SourceSetup(MythScreenStack *parent, const QString &name)
MythUIButtonList * m_locationList
Definition: weatherSetup.h:163
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:71
QStringList m_dataTypes
Definition: weatherUtils.h:68
int GetNumSetting(const QString &key, int defaultval=0)
void sourceListItemSelected(MythUIButtonListItem *item=nullptr)
MythUIText * m_helpText
Definition: weatherSetup.h:93
MythUIButtonList * m_inactiveList
Definition: weatherSetup.h:95
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:807
bool keyPressEvent(QKeyEvent *) override
Key event handler.
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
void deleteScreen(void)
unsigned char units_t
Definition: weatherUtils.h:22
ScreenListMap loadScreens()
void retrieveSpinboxUpdate(void)
ScriptInfo * getSourceByName(const QString &name)
void SetCheckState(MythUIStateType::StateType state)
bool keyPressEvent(QKeyEvent *) override
Key event handler.
QString executedQuery(void) const
Definition: mythdbcon.h:199
bool SetFocusWidget(MythUIType *widget=nullptr)
QString m_location
Definition: weatherUtils.h:41
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:603
QString m_title
Definition: weatherUtils.h:66
QStringList m_types
Definition: weatherSetup.h:157
MythUIText * m_sourceText
Definition: weatherSetup.h:122
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:94
void saveData(void)
QMap< QString, ScreenListInfo > ScreenListMap
Definition: weatherUtils.h:79
#define SI_UNITS
Definition: weatherUtils.h:15
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:37
MythUIType * GetChild(const QString &name) const
Get a named child of this UIType.
Definition: mythuitype.cpp:132
void loadData(void)
QStringList getLocationList(ScriptInfo *si, const QString &str)
QString GetText(void) const
MythUIButtonListItem * GetItemCurrent() const
ScriptInfo * m_src
Definition: weatherUtils.h:42