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