MythTV  master
themechooser.cpp
Go to the documentation of this file.
1 // C++ headers
2 #include <chrono>
3 
4 // Qt headers
5 #include <QCoreApplication>
6 #include <QRegularExpression>
7 #include <QRunnable>
8 
9 // MythTV headers
12 #include "libmythbase/mythdate.h"
15 #include "libmythbase/mythversion.h"
17 #include "libmythbase/remotefile.h"
18 #include "libmythbase/remoteutil.h"
20 #include "libmythbase/unziputil.h" // for extractZIP
26 #include "libmythui/mythuigroup.h"
27 #include "libmythui/mythuihelper.h"
28 #include "libmythui/mythuiimage.h"
31 #include "libmythui/mythuitext.h"
32 
33 // Theme Chooser headers
34 #include "themechooser.h"
35 
36 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 2)
37 #define capturedView capturedRef
38 #endif
39 
40 #define LOC QString("ThemeChooser: ")
41 #define LOC_WARN QString("ThemeChooser, Warning: ")
42 #define LOC_ERR QString("ThemeChooser, Error: ")
43 
44 static const QRegularExpression kVersionDateRE{"\\.[0-9]{8,}.*"};
45 
49 class ThemeExtractThread : public QRunnable
50 {
51 public:
53  QString srcFile, QString destDir) : m_parent(parent),
54  m_srcFile(std::move(srcFile)),
55  m_destDir(std::move(destDir)) {}
56 
57  void run() override // QRunnable
58  {
60 
61  auto *me = new MythEvent("THEME_INSTALLED", QStringList(m_srcFile));
62  QCoreApplication::postEvent(m_parent, me);
63  }
64 
65 private:
67  QString m_srcFile;
68  QString m_destDir;
69 };
70 
76  const QString &name) : MythScreenType(parent, name)
77 {
79 
80  StorageGroup sgroup("Themes", gCoreContext->GetHostName());
81  m_userThemeDir = sgroup.GetFirstDir(true);
82 }
83 
85 {
87 }
88 
89 static bool sortThemeNames(const QFileInfo &s1, const QFileInfo &s2)
90 {
91  return s1.fileName().toLower() < s2.fileName().toLower();
92 }
93 
95 {
96  // Load the theme for this screen
97  if (!LoadWindowFromXML("settings-ui.xml", "themechooser", this))
98  return false;
99 
100  bool err = false;
101  UIUtilE::Assign(this, m_themes, "themes", &err);
102 
103  UIUtilW::Assign(this, m_preview, "preview");
104  UIUtilW::Assign(this, m_fullPreviewStateType, "fullpreviewstate");
105 
107  {
108  MythUIGroup *state =
109  dynamic_cast<MythUIGroup *>(m_fullPreviewStateType->GetChild("fullscreen"));
110  if (state)
111  {
113  dynamic_cast<MythUIText *>(state->GetChild("fullscreenname"));
115  dynamic_cast<MythUIImage *>(state->GetChild("fullscreenpreview"));
116  }
117  }
118 
119  if (err)
120  {
121  LOG(VB_GENERAL, LOG_ERR, LOC + "Cannot load screen 'themechooser'");
122  return false;
123  }
124 
126  this, qOverload<MythUIButtonListItem *>(&ThemeChooser::saveAndReload));
129 
130  BuildFocusList();
131 
133 
134  return true;
135 }
136 
138 {
139  SetBusyPopupMessage(tr("Loading Installed Themes"));
140 
141  QStringList themesSeen;
142  QDir themes(m_userThemeDir);
143  themes.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
144  themes.setSorting(QDir::Name | QDir::IgnoreCase);
145 
146  m_infoList = themes.entryInfoList();
147 
148  for (const auto &theme : std::as_const(m_infoList))
149  {
150  if (loadThemeInfo(theme))
151  {
152  themesSeen << theme.fileName();
153  m_themeStatuses[theme.fileName()] = "default";
154  }
155  }
156 
157  themes.setPath(GetThemesParentDir());
158  QFileInfoList sharedThemes = themes.entryInfoList();
159  for (const auto &sharedTheme : std::as_const(sharedThemes))
160  {
161  if ((!themesSeen.contains(sharedTheme.fileName())) &&
162  (loadThemeInfo(sharedTheme)))
163  {
164  m_infoList << sharedTheme;
165  themesSeen << sharedTheme.fileName();
166  m_themeStatuses[sharedTheme.fileName()] = "default";
167  }
168  }
169 
170  // MYTH_SOURCE_VERSION - examples v29-pre-574-g92517f5, v29-Pre, v29.1-21-ge26a33c
171  QString MythVersion(GetMythSourceVersion());
172  static const QRegularExpression trunkver{"\\Av[0-9]+-pre.*\\z", QRegularExpression::CaseInsensitiveOption};
173  static const QRegularExpression validver{
174  "\\Av[0-9]+.*\\z", QRegularExpression::CaseInsensitiveOption};
175 
176  auto match = validver.match(MythVersion);
177  if (!match.hasMatch())
178  {
179  LOG(VB_GENERAL, LOG_ERR, QString("Invalid MythTV version %1, will use themes from trunk").arg(MythVersion));
180  MythVersion = "trunk";
181  }
182  match = trunkver.match(MythVersion);
183  if (match.hasMatch())
184  MythVersion = "trunk";
185 
186  if (MythVersion == "trunk")
187  {
188  LoadVersion(MythVersion, themesSeen, true);
189  LOG(VB_GUI, LOG_INFO, QString("Loading themes for %1").arg(MythVersion));
190  }
191  else
192  {
193  MythVersion = MYTH_BINARY_VERSION; // Example: 29.20161017-1
194  // Remove the date part and the rest, eg 29.20161017-1 -> 29
195  MythVersion.remove(kVersionDateRE);
196  LOG(VB_GUI, LOG_INFO, QString("Loading themes for %1").arg(MythVersion));
197  if (LoadVersion(MythVersion, themesSeen, true))
198  {
199 
200  // If a version of the theme for this tag exists, use it...
201  // MYTH_SOURCE_VERSION - examples v29-pre-574-g92517f5, v29-Pre, v29.1-21-ge26a33c
202  static const QRegularExpression subexp{"v[0-9]+\\.([0-9]+)-*", QRegularExpression::CaseInsensitiveOption};
203  // This captures the subversion, i.e. the number after a dot
204  match = subexp.match(GetMythSourceVersion());
205  if (match.hasMatch())
206  {
207  QString subversion;
208  LOG(VB_GUI, LOG_INFO, QString("Loading version %1").arg(match.capturedView(1).toInt()));
209  for (int idx = match.capturedView(1).toInt(); idx > 0; --idx)
210  {
211  subversion = MythVersion + "." + QString::number(idx);
212  LOG(VB_GUI, LOG_INFO, QString("Loading themes for %1").arg(subversion));
213  LoadVersion(subversion, themesSeen, false);
214  }
215  }
216  else
217  {
218  LOG(VB_GENERAL, LOG_WARNING, QString("Failed to match theme for %1").arg(GetMythSourceVersion()));
219  }
220 
221  ResetBusyPopup();
222 
223  std::sort(m_infoList.begin(), m_infoList.end(), sortThemeNames);
224  }
225  else
226  {
227 
228  LOG(VB_GENERAL, LOG_INFO, QString("Failed to load themes for %1, trying trunk").arg(MythVersion));
229  MythVersion = "trunk";
230  if (!LoadVersion(MythVersion, themesSeen, true))
231  {
232  LOG(VB_GENERAL, LOG_WARNING, QString("Failed to load themes for %1").arg(MythVersion));
233  }
234  }
235  }
236 }
237 
238 bool ThemeChooser::LoadVersion(const QString &version,
239  QStringList &themesSeen, bool alert_user)
240 {
241  QString remoteThemesFile = GetConfDir();
242  remoteThemesFile.append("/tmp/themes.zip");
243  QString themeSite = QString("%1/%2")
244  .arg(gCoreContext->GetSetting("ThemeRepositoryURL",
245  "http://themes.mythtv.org/themes/repository"),
246  version);
247  QString destdir = GetCacheDir().append("/themechooser");
248  QString versiondir = QString("%1/%2").arg(destdir, version);
249  QDir remoteThemesDir(versiondir);
250 
251  int downloadFailures =
252  gCoreContext->GetNumSetting("ThemeInfoDownloadFailures", 0);
253  if (QFile::exists(remoteThemesFile))
254  {
255  QFileInfo finfo(remoteThemesFile);
256  if (finfo.lastModified().toUTC() <
257  MythDate::current().addSecs(-600))
258  {
259  LOG(VB_GUI, LOG_INFO, LOC + QString("%1 is over 10 minutes old, forcing "
260  "remote theme list download")
261  .arg(remoteThemesFile));
263  }
264 
265  if (!remoteThemesDir.exists())
266  {
268  }
269  }
270  else if (downloadFailures < 2) // (and themes.zip does not exist)
271  {
272  LOG(VB_GUI, LOG_INFO, LOC + QString("%1 does not exist, forcing remote theme "
273  "list download")
274  .arg(remoteThemesFile));
276  }
277 
279  {
280  QFile test(remoteThemesFile);
281  if (test.open(QIODevice::WriteOnly))
282  test.remove();
283  else
284  {
285  ShowOkPopup(tr("Unable to create '%1'").arg(remoteThemesFile));
286  return false;
287  }
288 
289  SetBusyPopupMessage(tr("Refreshing Downloadable Themes Information"));
290 
291  QString url = themeSite;
292  url.append("/themes.zip");
293  if (!removeThemeDir(versiondir))
294  ShowOkPopup(tr("Unable to remove '%1'").arg(versiondir));
295  QDir dir;
296  if (!dir.mkpath(destdir))
297  ShowOkPopup(tr("Unable to create '%1'").arg(destdir));
298  bool result = GetMythDownloadManager()->download(url, remoteThemesFile, true);
299 
300  LOG(VB_GUI, LOG_INFO, LOC + QString("Downloading '%1' to '%2'").arg(url, remoteThemesFile));
301 
302  SetBusyPopupMessage(tr("Extracting Downloadable Themes Information"));
303 
304  if (!result || !extractZIP(remoteThemesFile, destdir))
305  {
306  QFile::remove(remoteThemesFile);
307 
308  downloadFailures++;
309  gCoreContext->SaveSetting("ThemeInfoDownloadFailures",
310  downloadFailures);
311 
312  if (!result)
313  {
314  LOG(VB_GUI, LOG_ERR, LOC + QString("Failed to download '%1'").arg(url));
315  if (alert_user)
316  ShowOkPopup(tr("Failed to download '%1'").arg(url));
317  }
318  else
319  {
320  LOG(VB_GUI, LOG_ERR, LOC + QString("Failed to unzip '%1' to '%2'").arg(remoteThemesFile, destdir));
321  if (alert_user)
322  ShowOkPopup(tr("Failed to unzip '%1' to '%2'")
323  .arg(remoteThemesFile, destdir));
324  }
325  return false;
326  }
327  LOG(VB_GUI, LOG_INFO, LOC + QString("Unzipped '%1' to '%2'").arg(remoteThemesFile, destdir));
328  }
329 
330  QDir themes;
331  themes.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
332  themes.setSorting(QDir::Name | QDir::IgnoreCase);
333 
334  if ((QFile::exists(remoteThemesFile)) &&
335  (remoteThemesDir.exists()))
336  {
337  SetBusyPopupMessage(tr("Loading Downloadable Themes"));
338 
339  LOG(VB_GUI, LOG_INFO, LOC + QString("%1 and %2 exist, using cached remote themes list").arg(remoteThemesFile, remoteThemesDir.absolutePath()));
340 
341  QString themesPath = remoteThemesDir.absolutePath();
342  themes.setPath(themesPath);
343 
344  QFileInfoList downloadableThemes = themes.entryInfoList();
345  for (const auto &dtheme : std::as_const(downloadableThemes))
346  {
347  QString dirName = dtheme.fileName();
348  QString themeName = dirName;
349  QString remoteDir = themeSite;
350  remoteDir.append("/").append(dirName);
351  QString localDir = themes.absolutePath();
352  localDir.append("/").append(dirName);
353 
354  ThemeInfo remoteTheme(dtheme.absoluteFilePath());
355 
356  if (themesSeen.contains(dirName))
357  {
358  ThemeInfo *localTheme = m_themeNameInfos[dirName];
359 
360  themeName = remoteTheme.GetName();
361 
362  int rmtMaj = remoteTheme.GetMajorVersion();
363  int rmtMin = remoteTheme.GetMinorVersion();
364  int locMaj = localTheme->GetMajorVersion();
365  int locMin = localTheme->GetMinorVersion();
366 
367  if ((rmtMaj > locMaj) ||
368  ((rmtMaj == locMaj) &&
369  (rmtMin > locMin)))
370  {
371  if (loadThemeInfo(dtheme))
372  {
373  LOG(VB_GUI, LOG_DEBUG, LOC + QString("'%1' old version %2.%3, new version %4.%5").arg(themeName).arg(locMaj).arg(locMin).arg(rmtMaj).arg(rmtMin));
374 
375  m_infoList << dtheme;
376  m_themeStatuses[themeName] = "updateavailable";
377 
378  QFileInfo finfo(remoteTheme.GetPreviewPath());
380  remoteDir.append("/").append(finfo.fileName()),
381  localDir.append("/").append(finfo.fileName()),
382  nullptr);
383  }
384  }
385  else if ((rmtMaj == locMaj) &&
386  (rmtMin == locMin))
387  {
388  LOG(VB_GUI, LOG_DEBUG, LOC + QString("'%1' up to date (%2.%3)").arg(themeName).arg(locMaj).arg(locMin));
389 
390  m_themeStatuses[themeName] = "uptodate";
391  }
392  }
393  else
394  {
395  LOG(VB_GUI, LOG_DEBUG, LOC + QString("'%1' (%2.%3) available").arg(themeName).arg(remoteTheme.GetMajorVersion()).arg(remoteTheme.GetMinorVersion()));
396 
397  ThemeInfo *tmpTheme = loadThemeInfo(dtheme);
398  if (tmpTheme)
399  {
400  themeName = tmpTheme->GetName();
401  themesSeen << dirName;
402  m_infoList << dtheme;
403  m_themeStatuses[themeName] = "updateavailable";
404 
405  QFileInfo finfo(tmpTheme->GetPreviewPath());
407  remoteDir.append("/").append(finfo.fileName()),
408  localDir.append("/").append(finfo.fileName()),
409  nullptr);
410  }
411  }
412  }
413  return true;
414  }
415  return false;
416 }
417 
419 {
420  QString curTheme = gCoreContext->GetSetting("Theme");
421  ThemeInfo *themeinfo = nullptr;
422  ThemeInfo *curThemeInfo = nullptr;
423  MythUIButtonListItem *item = nullptr;
424 
425  m_themes->Reset();
426  for (const auto &theme : std::as_const(m_infoList))
427  {
428  if (!m_themeFileNameInfos.contains(theme.filePath()))
429  continue;
430 
431  themeinfo = m_themeFileNameInfos[theme.filePath()];
432  if (!themeinfo)
433  continue;
434 
435  QString buttonText = QString("%1 %2.%3")
436  .arg(themeinfo->GetName())
437  .arg(themeinfo->GetMajorVersion())
438  .arg(themeinfo->GetMinorVersion());
439 
440  item = new MythUIButtonListItem(m_themes, buttonText);
441  if (item)
442  {
443  if (themeinfo->GetDownloadURL().isEmpty())
444  item->DisplayState("local", "themelocation");
445  else
446  item->DisplayState("remote", "themelocation");
447 
448  item->DisplayState(themeinfo->GetAspect(), "aspectstate");
449 
450  item->DisplayState(m_themeStatuses[themeinfo->GetName()],
451  "themestatus");
452  InfoMap infomap;
453  themeinfo->ToMap(infomap);
454  item->SetTextFromMap(infomap);
455  item->SetData(QVariant::fromValue(themeinfo));
456 
457  QString thumbnail = themeinfo->GetPreviewPath();
458  // Downloadable themeinfos have thumbnail copies of their preview images
459  if (!themeinfo->GetDownloadURL().isEmpty())
460  thumbnail = thumbnail.append(".thumb.jpg");
461  item->SetImage(thumbnail);
462 
463  if (curTheme == themeinfo->GetDirectoryName())
464  curThemeInfo = themeinfo;
465  }
466  }
467 
469 
470  if (curThemeInfo)
471  m_themes->SetValueByData(QVariant::fromValue(curThemeInfo));
472 
474  if (current)
476 
477  QString testFile = m_userThemeDir + "/.test";
478  QFile test(testFile);
479  if (test.open(QIODevice::WriteOnly))
480  test.remove();
481  else
482  {
483  ShowOkPopup(tr("Error creating test file, %1 themes directory is "
484  "not writable.")
485  .arg(m_userThemeDir));
486  }
487 }
488 
489 ThemeInfo *ThemeChooser::loadThemeInfo(const QFileInfo &theme)
490 {
491  if (theme.fileName() == "default" || theme.fileName() == "default-wide")
492  return nullptr;
493 
494  ThemeInfo *themeinfo = nullptr;
495  if (theme.exists()) // local directory vs http:// or remote URL
496  themeinfo = new ThemeInfo(theme.absoluteFilePath());
497  else
498  themeinfo = new ThemeInfo(theme.filePath());
499 
500  if (!themeinfo)
501  return nullptr;
502 
503  if (themeinfo->GetName().isEmpty() || ((themeinfo->GetType() & THEME_UI) == 0))
504  {
505  delete themeinfo;
506  return nullptr;
507  }
508 
509  m_themeFileNameInfos[theme.filePath()] = themeinfo;
510  m_themeNameInfos[theme.fileName()] = themeinfo;
511 
512  return themeinfo;
513 }
514 
516 {
517  if (m_popupMenu)
518  return;
519 
520  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
521  QString label = tr("Theme Chooser Menu");
522 
523  m_popupMenu =
524  new MythDialogBox(label, popupStack, "themechoosermenupopup");
525 
527 
528  if (m_popupMenu->Create())
529  popupStack->AddScreen(m_popupMenu);
530  else
531  {
532  delete m_popupMenu;
533  m_popupMenu = nullptr;
534  return;
535  }
536 
537  m_popupMenu->SetReturnEvent(this, "popupmenu");
538 
540  {
542  {
543  m_popupMenu->AddButton(tr("Hide Fullscreen Preview"),
545  }
546  else
547  {
548  m_popupMenu->AddButton(tr("Show Fullscreen Preview"),
550  }
551  }
552 
553  m_popupMenu->AddButton(tr("Refresh Downloadable Themes"),
555 
557  if (current)
558  {
559  auto *info = current->GetData().value<ThemeInfo *>();
560 
561  if (info)
562  {
563  m_popupMenu->AddButton(tr("Select Theme"),
564  qOverload<>(&ThemeChooser::saveAndReload));
565 
566  if (info->GetPreviewPath().startsWith(m_userThemeDir))
567  m_popupMenu->AddButton(tr("Delete Theme"),
569  }
570  }
571 
572  if (gCoreContext->GetBoolSetting("ThemeUpdateNofications", true))
573  {
574  m_popupMenu->AddButton(tr("Disable Theme Update Notifications"),
576  }
577  else
578  {
579  m_popupMenu->AddButton(tr("Enable Theme Update Notifications"),
581  }
582 }
583 
584 void ThemeChooser::popupClosed([[maybe_unused]] const QString &which,
585  [[maybe_unused]] int result)
586 {
587  m_popupMenu = nullptr;
588 }
589 
590 bool ThemeChooser::keyPressEvent(QKeyEvent *event)
591 {
592  if (GetFocusWidget()->keyPressEvent(event))
593  return true;
594 
595  QStringList actions;
596  bool handled = GetMythMainWindow()->TranslateKeyPress("Theme Chooser", event, actions);
597 
598  for (int i = 0; i < actions.size() && !handled; ++i)
599  {
600  const QString& action = actions[i];
601  handled = true;
602 
603  if (action == "MENU")
604  showPopupMenu();
605  else if (action == "DELETE")
606  removeTheme();
607  else if ((action == "ESCAPE") &&
609  {
611  }
612  else
613  {
614  handled = false;
615  }
616  }
617 
618  if (!handled && MythScreenType::keyPressEvent(event))
619  handled = true;
620 
621  return handled;
622 }
623 
625 {
627  {
629  {
632 
633  if (m_fullScreenName)
635 
637  m_fullPreviewShowing = false;
638  }
639  else
640  {
642  auto *info = item->GetData().value<ThemeInfo *>();
643  if (info)
644  {
646  {
647  m_fullScreenPreview->SetFilename(info->GetPreviewPath());
649  }
650 
651  if (m_fullScreenName)
652  m_fullScreenName->SetText(info->GetName());
653 
654  m_fullPreviewStateType->DisplayState("fullscreen");
655  m_fullPreviewShowing = true;
656  }
657  }
658  }
659 }
660 
662 {
663  if (gCoreContext->GetBoolSetting("ThemeUpdateNofications", true))
664  gCoreContext->SaveSettingOnHost("ThemeUpdateNofications", "0", "");
665  else
666  gCoreContext->SaveSettingOnHost("ThemeUpdateNofications", "1", "");
667 }
668 
670 {
671  LOG(VB_GUI, LOG_INFO, LOC + "Forcing remote theme list refresh");
673  gCoreContext->SaveSetting("ThemeInfoDownloadFailures", 0);
675 }
676 
678 {
680  if (current)
682 }
683 
685 {
686  auto *info = item->GetData().value<ThemeInfo *>();
687 
688  if (!info)
689  return;
690 
691  if (!info->GetDownloadURL().isEmpty())
692  {
693  QString testFile = m_userThemeDir + "/.test";
694  QFile test(testFile);
695  if (test.open(QIODevice::WriteOnly))
696  test.remove();
697  else
698  {
699  ShowOkPopup(tr("Unable to install theme, %1 themes directory is "
700  "not writable.")
701  .arg(m_userThemeDir));
702  return;
703  }
704 
705  QString downloadURL = info->GetDownloadURL();
706  LOG(VB_FILE, LOG_INFO, QString("Download url is %1").arg(downloadURL));
707  QFileInfo qfile(downloadURL);
708  QString baseName = qfile.fileName();
709 
710  if (!gCoreContext->GetSetting("ThemeDownloadURL").isEmpty())
711  {
712 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
713  QStringList tokens =
714  gCoreContext->GetSetting("ThemeDownloadURL")
715  .split(";", QString::SkipEmptyParts);
716 #else
717  QStringList tokens =
718  gCoreContext->GetSetting("ThemeDownloadURL")
719  .split(";", Qt::SkipEmptyParts);
720 #endif
721  QString origURL = downloadURL;
722  downloadURL.replace(tokens[0], tokens[1]);
723  LOG(VB_FILE, LOG_WARNING, LOC + QString("Theme download URL overridden from %1 to %2.").arg(origURL, downloadURL));
724  }
725 
726  OpenBusyPopup(tr("Downloading %1 Theme").arg(info->GetName()));
728 #if 0
730  "Temp", baseName);
732 #else
733  QString localFile = GetConfDir() + "/tmp/" + baseName;
734  GetMythDownloadManager()->queueDownload(downloadURL, localFile, this);
735  m_downloadFile = localFile;
737 #endif
738  }
739  else
740  {
741  gCoreContext->SaveSetting("Theme", info->GetDirectoryName());
742  GetMythMainWindow()->JumpTo("Reload Theme");
743  }
744 }
745 
747 {
748  auto *info = item->GetData().value<ThemeInfo *>();
749 
750  if (!info)
751  return;
752 
753  QFileInfo preview(info->GetPreviewPath());
754  InfoMap infomap;
755  info->ToMap(infomap);
756  SetTextFromMap(infomap);
757  if (m_preview)
758  {
759  if (preview.exists())
760  {
761  m_preview->SetFilename(info->GetPreviewPath());
762  m_preview->Load();
763  }
764  else
765  {
766  m_preview->Reset();
767  }
768  }
770  {
772  {
773  if (preview.exists())
774  {
775  m_fullScreenPreview->SetFilename(info->GetPreviewPath());
777  }
778  else
779  {
781  }
782  }
783 
784  if (m_fullScreenName)
785  m_fullScreenName->SetText(info->GetName());
786  }
787 
788  MythUIStateType *themeLocation =
789  dynamic_cast<MythUIStateType *>(GetChild("themelocation"));
790  if (themeLocation)
791  {
792  if (info->GetDownloadURL().isEmpty())
793  themeLocation->DisplayState("local");
794  else
795  themeLocation->DisplayState("remote");
796  }
797 
798  MythUIStateType *aspectState =
799  dynamic_cast<MythUIStateType *>(GetChild("aspectstate"));
800  if (aspectState)
801  aspectState->DisplayState(info->GetAspect());
802 }
803 
804 void ThemeChooser::updateProgressBar(int bytesReceived,
805  int bytesTotal)
806 {
807  MythUIProgressBar *progressBar =
808  dynamic_cast<MythUIProgressBar *>(GetChild("downloadprogressbar"));
809 
810  if (!progressBar)
811  return;
812 
813  progressBar->SetUsed(bytesReceived);
814  progressBar->SetTotal(bytesTotal);
815 }
816 
818 {
819  if (e->type() == MythEvent::kMythEventMessage)
820  {
821  auto *me = dynamic_cast<MythEvent *>(e);
822  if (me == nullptr)
823  return;
824 
825 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
826  QStringList tokens = me->Message().split(" ", QString::SkipEmptyParts);
827 #else
828  QStringList tokens = me->Message().split(" ", Qt::SkipEmptyParts);
829 #endif
830 
831  if (tokens.isEmpty())
832  return;
833 
834  if (tokens[0] == "DOWNLOAD_FILE")
835  {
836  QStringList args = me->ExtraDataList();
837  if ((m_downloadState == dsIdle) ||
838  (tokens.size() != 2) ||
839  (!m_downloadTheme) ||
840  (args[1] != m_downloadFile))
841  return;
842 
843  if (tokens[1] == "UPDATE")
844  {
845  updateProgressBar(args[2].toInt(), args[3].toInt());
846  }
847  else if (tokens[1] == "FINISHED")
848  {
849  bool remoteFileIsLocal = false;
850  int fileSize = args[2].toInt();
851  int errorCode = args[4].toInt();
852 
853  CloseBusyPopup();
854 
855  QFileInfo file(m_downloadFile);
857  (m_downloadFile.startsWith("myth://")))
858  {
859  // The backend download is finished so start the
860  // frontend download
861  LOG(VB_FILE, LOG_INFO, QString("Download done MBE %1 %2").arg(errorCode).arg(fileSize));
862  if ((errorCode == 0) &&
863  (fileSize > 0))
864  {
866  QString localFile = GetConfDir() + "/tmp/" +
867  file.fileName();
868  file.setFile(localFile);
869 
870  if (file.exists())
871  {
872  remoteFileIsLocal = true;
873  m_downloadFile = localFile;
874  }
875  else
876  {
878  m_downloadFile, localFile, this);
879  OpenBusyPopup(tr("Copying %1 Theme Package")
880  .arg(m_downloadTheme->GetName()));
881  m_downloadFile = localFile;
882  return;
883  }
884  }
885  else
886  {
888  ShowOkPopup(tr("ERROR downloading theme package on master backend."));
889  }
890  }
891 
893  (file.exists()))
894  {
895  // The frontend download is finished
896  LOG(VB_FILE, LOG_INFO, QString("Download done MFE %1 %2").arg(errorCode).arg(fileSize));
897  // moved error is ok
898  if ((errorCode == 0) &&
899  (fileSize > 0))
900  {
902  auto *extractThread =
906  extractThread, "ThemeExtract");
907 
908  if (!remoteFileIsLocal)
910 
911  OpenBusyPopup(tr("Installing %1 Theme")
912  .arg(m_downloadTheme->GetName()));
913  }
914  else
915  {
917  ShowOkPopup(tr("ERROR downloading theme package from frontend."));
918  }
919  }
920  }
921  }
922  else if ((me->Message() == "THEME_INSTALLED") &&
923  (m_downloadTheme) &&
925  {
927  CloseBusyPopup();
928  QStringList args = me->ExtraDataList();
929 
930  if (!args.isEmpty() && !args[0].isEmpty())
931  QFile::remove(args[0]);
932 
933  QString event = QString("THEME_INSTALLED PATH %1")
934  .arg(m_userThemeDir +
937 
939 
940  // Send a message to ourself so we trigger a reload our next chance
941  auto *me2 = new MythEvent("THEME_RELOAD");
942  qApp->postEvent(this, me2);
943  }
944  else if ((me->Message() == "THEME_RELOAD") &&
945  (m_downloadState == dsIdle))
946  {
947  GetMythMainWindow()->JumpTo("Reload Theme");
948  }
949  }
950 }
951 
953 {
955  if (!current)
956  {
957  ShowOkPopup(tr("Error, no theme selected."));
958  return;
959  }
960 
961  auto *info = current->GetData().value<ThemeInfo *>();
962  if (!info)
963  {
964  ShowOkPopup(tr("Error, unable to find current theme."));
965  return;
966  }
967 
968  if (!info->GetPreviewPath().startsWith(m_userThemeDir))
969  {
970  ShowOkPopup(tr("%1 is not a user-installed theme and can not "
971  "be deleted.")
972  .arg(info->GetName()));
973  return;
974  }
975 
976  removeThemeDir(m_userThemeDir + info->GetDirectoryName());
977 
979 }
980 
981 bool ThemeChooser::removeThemeDir(const QString &dirname)
982 {
983  if ((!dirname.startsWith(m_userThemeDir)) &&
984  (!dirname.startsWith(GetMythUI()->GetThemeCacheDir())))
985  return true;
986 
987  QDir dir(dirname);
988 
989  if (!dir.exists())
990  return true;
991 
992  dir.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
993  QFileInfoList list = dir.entryInfoList();
994 
995  for (const auto &fi : std::as_const(list))
996  {
997  if (fi.isFile() && !fi.isSymLink())
998  {
999  if (!QFile::remove(fi.absoluteFilePath()))
1000  return false;
1001  }
1002  else if (fi.isDir() && !fi.isSymLink())
1003  {
1004  if (!removeThemeDir(fi.absoluteFilePath()))
1005  return false;
1006  }
1007  }
1008 
1009  return dir.rmdir(dirname);
1010 }
1011 
1013 
1014 ThemeUpdateChecker::ThemeUpdateChecker(void) : m_updateTimer(new QTimer(this))
1015 {
1016  QString version = GetMythSourcePath();
1017 
1018  if (!version.isEmpty() && !version.startsWith("fixes/"))
1019  {
1020  // Treat devel branches as master
1021  m_mythVersions << "trunk";
1022  }
1023  else
1024  {
1025  version = MYTH_BINARY_VERSION; // Example: 0.25.20101017-1
1026  version.remove(kVersionDateRE);
1027 
1028  // If a version of the theme for this tag exists, use it...
1029  static const QRegularExpression subexp{"v[0-9]+\\.([0-9]+)-*", QRegularExpression::CaseInsensitiveOption};
1030  auto match = subexp.match(GetMythSourceVersion());
1031  if (match.hasMatch())
1032  {
1033  for (int idx = match.capturedView(1).toInt(); idx > 0; --idx)
1034  m_mythVersions << version + "." + QString::number(idx);
1035  }
1037  }
1038 
1041  "remotethemes/themes.zip",
1042  "Temp");
1043 
1044  gCoreContext->SaveSetting("ThemeUpdateStatus", "");
1045 
1047 
1048  if (qEnvironmentVariableIsSet("MYTHTV_DEBUGMDM"))
1049  {
1050  LOG(VB_GENERAL, LOG_INFO, "Checking for theme updates every minute");
1051  m_updateTimer->start(1min);
1052  }
1053  else
1054  {
1055  LOG(VB_GENERAL, LOG_INFO, "Checking for theme updates every hour");
1056  m_updateTimer->start(1h);
1057  }
1058 
1059  // Run once 15 seconds from now
1060  QTimer::singleShot(15s, this, &ThemeUpdateChecker::checkForUpdate);
1061 }
1062 
1064 {
1065  if (m_updateTimer)
1066  {
1067  m_updateTimer->stop();
1068  delete m_updateTimer;
1069  m_updateTimer = nullptr;
1070  }
1071 }
1072 
1074 {
1075  if (GetMythUI()->GetCurrentLocation(false, true) != "mainmenu")
1076  return;
1077 
1078  ThemeInfo *localTheme = nullptr;
1079 
1081  {
1082  QStringList::iterator Iversion;
1083 
1084  for (Iversion = m_mythVersions.begin();
1085  Iversion != m_mythVersions.end(); ++Iversion)
1086  {
1087 
1088  QString remoteThemeDir =
1091  QString("remotethemes/%1/%2")
1092  .arg(*Iversion,
1093  GetMythUI()->GetThemeName()),
1094  "Temp");
1095 
1096  QString infoXML = remoteThemeDir;
1097  infoXML.append("/themeinfo.xml");
1098 
1099  LOG(VB_GUI, LOG_INFO, QString("ThemeUpdateChecker Loading '%1'").arg(infoXML));
1100 
1101  if (RemoteFile::Exists(infoXML))
1102  {
1103  int locMaj = 0;
1104  int locMin = 0;
1105 
1106  auto *remoteTheme = new ThemeInfo(remoteThemeDir);
1107  if (!remoteTheme || remoteTheme->GetType() & THEME_UNKN)
1108  {
1109  LOG(VB_GENERAL, LOG_ERR,
1110  QString("ThemeUpdateChecker::checkForUpdate(): "
1111  "Unable to create ThemeInfo for %1")
1112  .arg(infoXML));
1113  delete remoteTheme;
1114  remoteTheme = nullptr;
1115  return;
1116  }
1117 
1118  if (!localTheme)
1119  {
1120  localTheme = new ThemeInfo(GetMythUI()->GetThemeDir());
1121  if (!localTheme || localTheme->GetType() & THEME_UNKN)
1122  {
1123  LOG(VB_GENERAL, LOG_ERR,
1124  "ThemeUpdateChecker::checkForUpdate(): "
1125  "Unable to create ThemeInfo for current theme");
1126  delete localTheme;
1127  localTheme = nullptr;
1128  return;
1129  }
1130  locMaj = localTheme->GetMajorVersion();
1131  locMin = localTheme->GetMinorVersion();
1132  }
1133 
1134  int rmtMaj = remoteTheme->GetMajorVersion();
1135  int rmtMin = remoteTheme->GetMinorVersion();
1136 
1137  delete remoteTheme;
1138  remoteTheme = nullptr;
1139 
1140  if ((rmtMaj > locMaj) ||
1141  ((rmtMaj == locMaj) &&
1142  (rmtMin > locMin)))
1143  {
1145  QString("%1-%2.%3").arg(GetMythUI()->GetThemeName()).arg(rmtMaj).arg(rmtMin);
1146 
1147  QString status = gCoreContext->GetSetting("ThemeUpdateStatus");
1148  QString currentLocation = GetMythUI()->GetCurrentLocation(false, true);
1149 
1150  if ((!status.startsWith(m_lastKnownThemeVersion)) &&
1151  (currentLocation == "mainmenu"))
1152  {
1153  m_currentVersion = QString("%1.%2")
1154  .arg(locMaj)
1155  .arg(locMin);
1156  m_newVersion = QString("%1.%2").arg(rmtMaj).arg(rmtMin);
1157 
1158  gCoreContext->SaveSetting("ThemeUpdateStatus",
1159  m_lastKnownThemeVersion + " notified");
1160 
1161  QString message = tr("Version %1 of the %2 theme is now "
1162  "available in the Theme Chooser. "
1163  "The currently installed version "
1164  "is %3.")
1165  .arg(m_newVersion,
1166  GetMythUI()->GetThemeName(),
1168 
1169  ShowOkPopup(message);
1170  break;
1171  }
1172  }
1173  }
1174  }
1175  }
1176 
1177  delete localTheme;
1178 }
1179 
1180 /* vim: set expandtab tabstop=4 shiftwidth=4: */
GetThemesParentDir
QString GetThemesParentDir(void)
Definition: mythdirs.cpp:257
MythScreenType::LoadInBackground
void LoadInBackground(const QString &message="")
Definition: mythscreentype.cpp:283
build_compdb.args
args
Definition: build_compdb.py:11
ThemeChooser::dsExtractingTheme
@ dsExtractingTheme
Definition: themechooser.h:66
MythDialogBox::SetReturnEvent
void SetReturnEvent(QObject *retobject, const QString &resultid)
Definition: mythdialogbox.cpp:303
extractZIP
bool extractZIP(QString zipFile, const QString &outDir)
Definition: unziputil.cpp:17
MythUIButtonList::GetItemCurrent
MythUIButtonListItem * GetItemCurrent() const
Definition: mythuibuttonlist.cpp:1614
MythScreenType::SetBusyPopupMessage
void SetBusyPopupMessage(const QString &message)
Definition: mythscreentype.cpp:342
hardwareprofile.smolt.timeout
float timeout
Definition: smolt.py:102
ThemeChooser::m_themeNameInfos
QMap< QString, ThemeInfo * > m_themeNameInfos
Definition: themechooser.h:86
MythCoreContext::GetMasterHostName
QString GetMasterHostName(void)
Definition: mythcorecontext.cpp:811
ThemeUpdateChecker::m_lastKnownThemeVersion
QString m_lastKnownThemeVersion
Definition: themechooser.h:113
MythUIButtonList::SetValueByData
void SetValueByData(const QVariant &data)
Definition: mythuibuttonlist.cpp:1566
ThemeChooser
View and select installed themes.
Definition: themechooser.h:27
mythuitext.h
ThemeChooser::m_themes
MythUIButtonList * m_themes
Definition: themechooser.h:74
mythuiprogressbar.h
kVersionDateRE
static const QRegularExpression kVersionDateRE
Definition: themechooser.cpp:44
MythEvent::kMythEventMessage
static const Type kMythEventMessage
Definition: mythevent.h:79
unziputil.h
MythUIImage
Image widget, displays a single image or multiple images in sequence.
Definition: mythuiimage.h:97
MythUIText::Reset
void Reset(void) override
Reset the widget to it's original state, should not reset changes made by the theme.
Definition: mythuitext.cpp:65
ThemeExtractThread::run
void run() override
Definition: themechooser.cpp:57
MythUIButtonListItem::DisplayState
void DisplayState(const QString &state, const QString &name)
Definition: mythuibuttonlist.cpp:3613
ThemeInfo::GetAspect
QString GetAspect() const
Definition: themeinfo.h:27
ThemeChooser::dsDownloadingOnBackend
@ dsDownloadingOnBackend
Definition: themechooser.h:64
RemoteFile::Exists
static bool Exists(const QString &url, struct stat *fileinfo)
Definition: remotefile.cpp:460
MythUIType::GetChild
MythUIType * GetChild(const QString &name) const
Get a named child of this UIType.
Definition: mythuitype.cpp:138
mythscreenstack.h
MythMainWindow::JumpTo
void JumpTo(const QString &Destination, bool Pop=true)
Definition: mythmainwindow.cpp:1457
MythUIImage::Load
bool Load(bool allowLoadInBackground=true, bool forceStat=false)
Load the image(s), wraps ImageLoader::LoadImage()
Definition: mythuiimage.cpp:971
MythUIButtonList::itemSelected
void itemSelected(MythUIButtonListItem *item)
MythEvent
This class is used as a container for messages.
Definition: mythevent.h:16
ThemeChooser::customEvent
void customEvent(QEvent *e) override
Definition: themechooser.cpp:817
GetMythSourceVersion
const char * GetMythSourceVersion()
Definition: mythversion.cpp:5
MythDownloadManager::queueDownload
void queueDownload(const QString &url, const QString &dest, QObject *caller, bool reload=false)
Adds a url to the download queue.
Definition: mythdownloadmanager.cpp:393
MythUIProgressBar::SetUsed
void SetUsed(int value)
Definition: mythuiprogressbar.cpp:72
xbmcvfs.exists
bool exists(str path)
Definition: xbmcvfs.py:51
ThemeInfo::GetMinorVersion
int GetMinorVersion() const
Definition: themeinfo.h:36
mythdialogbox.h
MythScreenStack
Definition: mythscreenstack.h:16
ThemeChooser::m_popupMenu
MythDialogBox * m_popupMenu
Definition: themechooser.h:93
ThemeChooser::dsDownloadingOnFrontend
@ dsDownloadingOnFrontend
Definition: themechooser.h:65
ThemeChooser::refreshDownloadableThemes
void refreshDownloadableThemes(void)
Definition: themechooser.cpp:669
ThemeChooser::m_refreshDownloadableThemes
bool m_refreshDownloadableThemes
Definition: themechooser.h:83
MythScreenType::OpenBusyPopup
void OpenBusyPopup(const QString &message="")
Definition: mythscreentype.cpp:317
MythUIGroup
Create a group of widgets.
Definition: mythuigroup.h:11
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MythDialogBox::Closed
void Closed(QString, int)
MythScreenType
Screen in which all other widgets are contained and rendered.
Definition: mythscreentype.h:45
mythuistatetype.h
GetCacheDir
QString GetCacheDir(void)
Returns the base directory for all cached files.
Definition: mythdirs.cpp:266
ThemeUpdateChecker::m_newVersion
QString m_newVersion
Definition: themechooser.h:115
MythUIStateType::Reset
void Reset(void) override
Reset the widget to it's original state, should not reset changes made by the theme.
Definition: mythuistatetype.cpp:197
mythsystemevent.h
build_compdb.file
file
Definition: build_compdb.py:55
ThemeChooser::popupClosed
void popupClosed(const QString &which, int result)
Definition: themechooser.cpp:584
MythUIImage::Reset
void Reset(void) override
Reset the image back to the default defined in the theme.
Definition: mythuiimage.cpp:644
ThemeUpdateChecker::m_updateTimer
QTimer * m_updateTimer
Definition: themechooser.h:110
ThemeChooser::updateProgressBar
void updateProgressBar(int bytesReceived, int bytesTotal)
Definition: themechooser.cpp:804
ThemeInfo::GetDownloadURL
QString GetDownloadURL() const
Definition: themeinfo.h:38
remoteutil.h
mythuibuttonlist.h
mythuiimage.h
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:14
MythEvent::Message
const QString & Message() const
Definition: mythevent.h:65
ThemeUpdateChecker::m_mythVersions
QStringList m_mythVersions
Definition: themechooser.h:111
MythScreenType::GetFocusWidget
MythUIType * GetFocusWidget(void) const
Definition: mythscreentype.cpp:110
ThemeExtractThread
Definition: themechooser.cpp:49
programtypes.h
InfoMap
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
MythObservable::addListener
void addListener(QObject *listener)
Add a listener to the observable.
Definition: mythobservable.cpp:38
ThemeChooser::ThemeChooser
ThemeChooser(MythScreenStack *parent, const QString &name="ThemeChooser")
Creates a new ThemeChooser Screen.
Definition: themechooser.cpp:75
MythScreenType::ResetBusyPopup
void ResetBusyPopup(void)
Definition: mythscreentype.cpp:348
ThemeChooser::LoadVersion
bool LoadVersion(const QString &version, QStringList &themesSeen, bool alert_user)
Definition: themechooser.cpp:238
MythUIButtonListItem
Definition: mythuibuttonlist.h:41
ThemeInfo::GetName
QString GetName() const
Definition: themeinfo.h:29
ThemeChooser::showPopupMenu
void showPopupMenu(void)
Definition: themechooser.cpp:515
MythScreenType::ReloadInBackground
void ReloadInBackground(void)
Definition: mythscreentype.cpp:311
mythdate.h
MythUIProgressBar::SetTotal
void SetTotal(int value)
Definition: mythuiprogressbar.cpp:78
mythlogging.h
MythCoreContext::GenMythURL
static QString GenMythURL(const QString &host=QString(), int port=0, QString path=QString(), const QString &storageGroup=QString())
Definition: mythcorecontext.cpp:764
GetConfDir
QString GetConfDir(void)
Definition: mythdirs.cpp:256
ThemeExtractThread::m_destDir
QString m_destDir
Definition: themechooser.cpp:68
LOC
#define LOC
Definition: themechooser.cpp:40
THEME_UNKN
@ THEME_UNKN
Definition: themeinfo.h:14
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
remotefile.h
ThemeChooser::Create
bool Create(void) override
Definition: themechooser.cpp:94
MythUIProgressBar
Progress bar widget.
Definition: mythuiprogressbar.h:12
MythCoreContext::SendSystemEvent
void SendSystemEvent(const QString &msg)
Definition: mythcorecontext.cpp:1552
MythScreenType::SetFocusWidget
bool SetFocusWidget(MythUIType *widget=nullptr)
Definition: mythscreentype.cpp:115
MythDialogBox::AddButton
void AddButton(const QString &title)
Definition: mythdialogbox.h:198
MythDialogBox
Basic menu dialog, message and a list of options.
Definition: mythdialogbox.h:166
ThemeChooser::loadThemeInfo
ThemeInfo * loadThemeInfo(const QFileInfo &theme)
Definition: themechooser.cpp:489
MythDialogBox::Create
bool Create(void) override
Definition: mythdialogbox.cpp:127
ThemeChooser::m_downloadTheme
ThemeInfo * m_downloadTheme
Definition: themechooser.h:89
MythScreenType::BuildFocusList
void BuildFocusList(void)
Definition: mythscreentype.cpp:203
MythUIComposite::SetTextFromMap
virtual void SetTextFromMap(const InfoMap &infoMap)
Definition: mythuicomposite.cpp:9
ThemeUpdateChecker::checkForUpdate
void checkForUpdate(void)
Definition: themechooser.cpp:1073
ThemeChooser::Load
void Load(void) override
Load data which will ultimately be displayed on-screen or used to determine what appears on-screen (S...
Definition: themechooser.cpp:137
MythDownloadManager::download
bool download(const QString &url, const QString &dest, bool reload=false)
Downloads a URL to a file in blocking mode.
Definition: mythdownloadmanager.cpp:430
ThemeInfo::GetPreviewPath
QString GetPreviewPath() const
Definition: themeinfo.h:33
StorageGroup::GetFirstDir
QString GetFirstDir(bool appendSlash=false) const
Definition: storagegroup.cpp:189
ThemeInfo
Definition: themeinfo.h:20
storagegroup.h
ThemeChooser::saveAndReload
void saveAndReload(void)
Definition: themechooser.cpp:677
RemoteFile::DeleteFile
static bool DeleteFile(const QString &url)
Definition: remotefile.cpp:417
MythUIButtonListItem::GetData
QVariant GetData()
Definition: mythuibuttonlist.cpp:3715
MythUILocation::GetCurrentLocation
QString GetCurrentLocation(bool FullPath=false, bool MainStackOnly=true)
Definition: mythuilocation.cpp:20
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:55
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:916
ThemeChooser::m_userThemeDir
QString m_userThemeDir
Definition: themechooser.h:84
UIUtilDisp::Assign
static bool Assign(ContainerType *container, UIType *&item, const QString &name, bool *err=nullptr)
Definition: mythuiutils.h:27
mythuigroup.h
GetMythSourcePath
const char * GetMythSourcePath()
Definition: mythversion.cpp:10
MythUIButtonListItem::SetTextFromMap
void SetTextFromMap(const InfoMap &infoMap, const QString &state="")
Definition: mythuibuttonlist.cpp:3338
MythCoreContext::GetBoolSetting
bool GetBoolSetting(const QString &key, bool defaultval=false)
Definition: mythcorecontext.cpp:910
ThemeExtractThread::m_parent
ThemeChooser * m_parent
Definition: themechooser.cpp:66
mythburn.themeName
string themeName
Definition: mythburn.py:218
mthreadpool.h
mythuihelper.h
ThemeUpdateChecker::~ThemeUpdateChecker
~ThemeUpdateChecker(void) override
Definition: themechooser.cpp:1063
MythCoreContext::GetMasterServerPort
static int GetMasterServerPort(void)
Returns the Master Backend control port If no master server port has been defined in the database,...
Definition: mythcorecontext.cpp:984
ThemeChooser::toggleFullscreenPreview
void toggleFullscreenPreview(void)
Definition: themechooser.cpp:624
ThemeUpdateChecker::ThemeUpdateChecker
ThemeUpdateChecker(void)
Definition: themechooser.cpp:1014
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:401
ThemeInfo::GetType
int GetType() const
Definition: themeinfo.h:34
themechooser.h
ThemeChooser::m_fullPreviewShowing
bool m_fullPreviewShowing
Definition: themechooser.h:77
ThemeChooser::m_downloadState
DownloadState m_downloadState
Definition: themechooser.h:91
ThemeChooser::m_themeStatuses
QMap< QString, QString > m_themeStatuses
Definition: themechooser.h:88
THEME_UI
@ THEME_UI
Definition: themeinfo.h:15
mythcorecontext.h
ThemeChooser::m_themeFileNameInfos
QMap< QString, ThemeInfo * > m_themeFileNameInfos
Definition: themechooser.h:87
XMLParseBase::LoadWindowFromXML
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
Definition: xmlparsebase.cpp:687
MythUIButtonListItem::SetImage
void SetImage(MythImage *image, const QString &name="")
Sets an image directly, should only be used in special circumstances since it bypasses the cache.
Definition: mythuibuttonlist.cpp:3479
ThemeUpdateChecker::m_currentVersion
QString m_currentVersion
Definition: themechooser.h:114
MythUIText::SetText
virtual void SetText(const QString &text)
Definition: mythuitext.cpp:115
ThemeChooser::m_fullScreenName
MythUIText * m_fullScreenName
Definition: themechooser.h:79
ThemeInfo::GetMajorVersion
int GetMajorVersion() const
Definition: themeinfo.h:35
ThemeChooser::m_fullScreenPreview
MythUIImage * m_fullScreenPreview
Definition: themechooser.h:80
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
StorageGroup
Definition: storagegroup.h:11
build_compdb.action
action
Definition: build_compdb.py:9
ThemeChooser::toggleThemeUpdateNotifications
static void toggleThemeUpdateNotifications(void)
Definition: themechooser.cpp:661
ThemeChooser::m_fullPreviewStateType
MythUIStateType * m_fullPreviewStateType
Definition: themechooser.h:78
ThemeUpdateChecker::m_infoPackage
QString m_infoPackage
Definition: themechooser.h:112
ThemeChooser::keyPressEvent
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
Definition: themechooser.cpp:590
MythMainWindow::GetStack
MythScreenStack * GetStack(const QString &Stackname)
Definition: mythmainwindow.cpp:322
RemoteDownloadFile
QString RemoteDownloadFile(const QString &url, const QString &storageGroup, const QString &filename)
Definition: remoteutil.cpp:609
ThemeChooser::~ThemeChooser
~ThemeChooser() override
Definition: themechooser.cpp:84
MythCoreContext::GetHostName
QString GetHostName(void)
Definition: mythcorecontext.cpp:842
ThemeExtractThread::ThemeExtractThread
ThemeExtractThread(ThemeChooser *parent, QString srcFile, QString destDir)
Definition: themechooser.cpp:52
azlyrics.info
dictionary info
Definition: azlyrics.py:7
ThemeChooser::dsIdle
@ dsIdle
Definition: themechooser.h:63
MythCoreContext::SaveSetting
void SaveSetting(const QString &key, int newValue)
Definition: mythcorecontext.cpp:885
downloadURL
static bool downloadURL(const QString &url, QByteArray *buffer, QString &finalURL)
Definition: httplivestreambuffer.cpp:94
ThemeChooser::m_downloadFile
QString m_downloadFile
Definition: themechooser.h:90
MythUIImage::SetFilename
void SetFilename(const QString &filename)
Must be followed by a call to Load() to load the image.
Definition: mythuiimage.cpp:677
mythdownloadmanager.h
GetMythUI
MythUIHelper * GetMythUI()
Definition: mythuihelper.cpp:66
ThemeChooser::m_infoList
QFileInfoList m_infoList
Definition: themechooser.h:82
MThreadPool::globalInstance
static MThreadPool * globalInstance(void)
Definition: mthreadpool.cpp:307
mythmainwindow.h
ThemeChooser::Init
void Init(void) override
Used after calling Load() to assign data to widgets and other UI initilisation which is prohibited in...
Definition: themechooser.cpp:418
MythUIButtonListItem::SetData
void SetData(QVariant data)
Definition: mythuibuttonlist.cpp:3710
MythScreenStack::AddScreen
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Definition: mythscreenstack.cpp:52
ShowOkPopup
MythConfirmationDialog * ShowOkPopup(const QString &message, bool showCancel)
Non-blocking version of MythPopupBox::showOkPopup()
Definition: mythdialogbox.cpp:566
nv_python_libs.bbciplayer.bbciplayer_api.version
string version
Definition: bbciplayer_api.py:77
MythCoreContext::SaveSettingOnHost
bool SaveSettingOnHost(const QString &key, const QString &newValue, const QString &host)
Definition: mythcorecontext.cpp:895
ThemeChooser::removeTheme
void removeTheme(void)
Definition: themechooser.cpp:952
ThemeInfo::GetDirectoryName
QString GetDirectoryName() const
Definition: themeinfo.cpp:252
ThemeInfo::ToMap
void ToMap(InfoMap &infoMap) const
Definition: themeinfo.cpp:261
MythObservable::removeListener
void removeListener(QObject *listener)
Remove a listener to the observable.
Definition: mythobservable.cpp:55
sortThemeNames
static bool sortThemeNames(const QFileInfo &s1, const QFileInfo &s2)
Definition: themechooser.cpp:89
ThemeChooser::m_preview
MythUIImage * m_preview
Definition: themechooser.h:75
MythScreenType::CloseBusyPopup
void CloseBusyPopup(void)
Definition: mythscreentype.cpp:335
MythUIStateType
This widget is used for grouping other widgets for display when a particular named state is called....
Definition: mythuistatetype.h:22
MThreadPool::start
void start(QRunnable *runnable, const QString &debugName, int priority=0)
Definition: mthreadpool.cpp:342
ThemeExtractThread::m_srcFile
QString m_srcFile
Definition: themechooser.cpp:67
MythUIStateType::DisplayState
bool DisplayState(const QString &name)
Definition: mythuistatetype.cpp:84
ThemeChooser::removeThemeDir
bool removeThemeDir(const QString &dirname)
Definition: themechooser.cpp:981
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:902
GetMythDownloadManager
MythDownloadManager * GetMythDownloadManager(void)
Gets the pointer to the MythDownloadManager singleton.
Definition: mythdownloadmanager.cpp:145
ThemeChooser::itemChanged
void itemChanged(MythUIButtonListItem *item)
Definition: themechooser.cpp:746