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 <QRegExp>
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 using namespace std::chrono_literals;
39 
40 #define LOC QString("ThemeChooser: ")
41 #define LOC_WARN QString("ThemeChooser, Warning: ")
42 #define LOC_ERR QString("ThemeChooser, Error: ")
43 
47 class ThemeExtractThread : public QRunnable
48 {
49  public:
51  QString srcFile, QString destDir) :
52  m_parent(parent),
53  m_srcFile(std::move(srcFile)),
54  m_destDir(std::move(destDir)) {}
55 
56  void run() override // QRunnable
57  {
58  extractZIP(m_srcFile, m_destDir);
59 
60  auto *me = new MythEvent("THEME_INSTALLED", QStringList(m_srcFile));
61  QCoreApplication::postEvent(m_parent, me);
62  }
63 
64  private:
65  ThemeChooser *m_parent {nullptr};
66  QString m_srcFile;
67  QString m_destDir;
68 };
69 
70 
76  const QString &name) :
77  MythScreenType(parent, name)
78 {
80 
81  StorageGroup sgroup("Themes", gCoreContext->GetHostName());
82  m_userThemeDir = sgroup.GetFirstDir(true);
83 }
84 
86 {
88 }
89 
90 static bool sortThemeNames(const QFileInfo &s1, const QFileInfo &s2)
91 {
92  return s1.fileName().toLower() < s2.fileName().toLower();
93 }
94 
95 
97 {
98  // Load the theme for this screen
99  if (!LoadWindowFromXML("settings-ui.xml", "themechooser", this))
100  return false;
101 
102  bool err = false;
103  UIUtilE::Assign(this, m_themes, "themes", &err);
104 
105  UIUtilW::Assign(this, m_preview, "preview");
106  UIUtilW::Assign(this, m_fullPreviewStateType, "fullpreviewstate");
107 
109  {
110  MythUIGroup *state =
111  dynamic_cast<MythUIGroup*>
112  (m_fullPreviewStateType->GetChild("fullscreen"));
113  if (state)
114  {
116  dynamic_cast<MythUIText*>(state->GetChild("fullscreenname"));
118  dynamic_cast<MythUIImage*>(state->GetChild("fullscreenpreview"));
119  }
120  }
121 
122  if (err)
123  {
124  LOG(VB_GENERAL, LOG_ERR, LOC + "Cannot load screen 'themechooser'");
125  return false;
126  }
127 
129  this, qOverload<MythUIButtonListItem*>(&ThemeChooser::saveAndReload));
132 
133  BuildFocusList();
134 
136 
137  return true;
138 }
139 
141 {
142  SetBusyPopupMessage(tr("Loading Installed Themes"));
143 
144  QStringList themesSeen;
145  QDir themes(m_userThemeDir);
146  themes.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
147  themes.setSorting(QDir::Name | QDir::IgnoreCase);
148 
149  m_infoList = themes.entryInfoList();
150 
151  for (const auto & theme : qAsConst(m_infoList))
152  {
153  if (loadThemeInfo(theme))
154  {
155  themesSeen << theme.fileName();
156  m_themeStatuses[theme.fileName()] = "default";
157  }
158  }
159 
160  themes.setPath(GetThemesParentDir());
161  QFileInfoList sharedThemes = themes.entryInfoList();
162  for (const auto & sharedTheme : qAsConst(sharedThemes))
163  {
164  if ((!themesSeen.contains(sharedTheme.fileName())) &&
165  (loadThemeInfo(sharedTheme)))
166  {
167  m_infoList << sharedTheme;
168  themesSeen << sharedTheme.fileName();
169  m_themeStatuses[sharedTheme.fileName()] = "default";
170  }
171  }
172 
173  // MYTH_SOURCE_VERSION - examples v29-pre-574-g92517f5, v29-Pre, v29.1-21-ge26a33c
174  QString MythVersion(GetMythSourceVersion());
175  QRegExp trunkver("v[0-9]+-pre.*",Qt::CaseInsensitive);
176  QRegExp validver("v[0-9]+.*",Qt::CaseInsensitive);
177 
178  if (!validver.exactMatch(MythVersion))
179  {
180  LOG(VB_GENERAL, LOG_ERR, QString("Invalid MythTV version %1, will use themes from trunk").arg(MythVersion));
181  MythVersion = "trunk";
182  }
183  if (trunkver.exactMatch(MythVersion))
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 
194  MythVersion = MYTH_BINARY_VERSION; // Example: 29.20161017-1
195  // Remove the date part and the rest, eg 29.20161017-1 -> 29
196  MythVersion.replace(QRegExp("\\.[0-9]{8,}.*"), "");
197  LOG(VB_GUI, LOG_INFO, QString("Loading themes for %1").arg(MythVersion));
198  LoadVersion(MythVersion, themesSeen, true);
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  QRegExp subexp("v[0-9]+\\.([0-9]+)-*");
203  // This captures the subversion, i.e. the number after a dot
204  int pos = subexp.indexIn(GetMythSourceVersion());
205  if (pos > -1)
206  {
207  QString subversion;
208  for (int idx = subexp.cap(1).toInt(); idx > 0; --idx)
209  {
210  subversion = MythVersion + "." + QString::number(idx);
211  LOG(VB_GUI, LOG_INFO, QString("Loading themes for %1").arg(subversion));
212  LoadVersion(subversion, themesSeen, false);
213  }
214  }
215  }
216 
217  ResetBusyPopup();
218 
219  std::sort(m_infoList.begin(), m_infoList.end(), sortThemeNames);
220 }
221 
222 void ThemeChooser::LoadVersion(const QString &version,
223  QStringList &themesSeen, bool alert_user)
224 {
225  QString remoteThemesFile = GetConfDir();
226  remoteThemesFile.append("/tmp/themes.zip");
227  QString themeSite = QString("%1/%2")
228  .arg(gCoreContext->GetSetting("ThemeRepositoryURL",
229  "http://themes.mythtv.org/themes/repository")).arg(version);
230  QString destdir = GetCacheDir().append("/themechooser/");
231  QString versiondir = QString("%1/%2").arg(destdir).arg(version);
232  QDir remoteThemesDir(versiondir);
233 
234  int downloadFailures =
235  gCoreContext->GetNumSetting("ThemeInfoDownloadFailures", 0);
236  if (QFile::exists(remoteThemesFile))
237  {
238  QFileInfo finfo(remoteThemesFile);
239  if (finfo.lastModified().toUTC() <
240  MythDate::current().addSecs(-600))
241  {
242  LOG(VB_GUI, LOG_INFO, LOC +
243  QString("%1 is over 10 minutes old, forcing "
244  "remote theme list download").arg(remoteThemesFile));
246  }
247 
248  if (!remoteThemesDir.exists())
250  }
251  else if (downloadFailures < 2) // (and themes.zip does not exist)
252  {
253  LOG(VB_GUI, LOG_INFO, LOC +
254  QString("%1 does not exist, forcing remote theme "
255  "list download").arg(remoteThemesFile));
257  }
258 
260  {
261  QFile test(remoteThemesFile);
262  if (test.open(QIODevice::WriteOnly))
263  test.remove();
264  else
265  {
266  ShowOkPopup(tr("Unable to create '%1'").arg(remoteThemesFile));
267  return;
268  }
269 
270  SetBusyPopupMessage(tr("Refreshing Downloadable Themes Information"));
271 
272  QString url = themeSite;
273  url.append("/themes.zip");
274  if (!removeThemeDir(versiondir))
275  ShowOkPopup(tr("Unable to remove '%1'").arg(versiondir));
276  QDir dir;
277  if (!dir.mkpath(destdir))
278  ShowOkPopup(tr("Unable to create '%1'").arg(destdir));
279  bool result = GetMythDownloadManager()->download(url, remoteThemesFile, true);
280 
281  LOG(VB_GUI, LOG_INFO, LOC +
282  QString("Downloading '%1' to '%2'").arg(url).arg(remoteThemesFile));
283 
284  SetBusyPopupMessage(tr("Extracting Downloadable Themes Information"));
285 
286  if (!result || !extractZIP(remoteThemesFile, destdir))
287  {
288  QFile::remove(remoteThemesFile);
289 
290  downloadFailures++;
291  gCoreContext->SaveSetting("ThemeInfoDownloadFailures",
292  downloadFailures);
293 
294  if (!result)
295  {
296  LOG(VB_GUI, LOG_ERR, LOC +
297  QString("Failed to download '%1'").arg(url));
298  if (alert_user)
299  ShowOkPopup(tr("Failed to download '%1'").arg(url));
300  }
301  else
302  {
303  LOG(VB_GUI, LOG_ERR, LOC +
304  QString("Failed to unzip '%1' to '%2'")
305  .arg(remoteThemesFile).arg(destdir));
306  if (alert_user)
307  ShowOkPopup(tr("Failed to unzip '%1' to '%2'")
308  .arg(remoteThemesFile).arg(destdir));
309  }
310  }
311  else
312  {
313  LOG(VB_GUI, LOG_INFO, LOC +
314  QString("Unzipped '%1' to '%2'")
315  .arg(remoteThemesFile)
316  .arg(destdir));
317  }
318  }
319 
320  QDir themes;
321  themes.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
322  themes.setSorting(QDir::Name | QDir::IgnoreCase);
323 
324  if ((QFile::exists(remoteThemesFile)) &&
325  (remoteThemesDir.exists()))
326  {
327  SetBusyPopupMessage(tr("Loading Downloadable Themes"));
328 
329  LOG(VB_GUI, LOG_INFO, LOC +
330  QString("%1 and %2 exist, using cached remote themes list")
331  .arg(remoteThemesFile).arg(remoteThemesDir.absolutePath()));
332 
333  QString themesPath = remoteThemesDir.absolutePath();
334  themes.setPath(themesPath);
335 
336  QFileInfoList downloadableThemes = themes.entryInfoList();
337  for (const auto & dtheme : qAsConst(downloadableThemes))
338  {
339  QString dirName = dtheme.fileName();
340  QString themeName = dirName;
341  QString remoteDir = themeSite;
342  remoteDir.append("/").append(dirName);
343  QString localDir = themes.absolutePath();
344  localDir.append("/").append(dirName);
345 
346  ThemeInfo remoteTheme(dtheme.absoluteFilePath());
347 
348  if (themesSeen.contains(dirName))
349  {
350  ThemeInfo *localTheme = m_themeNameInfos[dirName];
351 
352  themeName = remoteTheme.GetName();
353 
354  int rmtMaj = remoteTheme.GetMajorVersion();
355  int rmtMin = remoteTheme.GetMinorVersion();
356  int locMaj = localTheme->GetMajorVersion();
357  int locMin = localTheme->GetMinorVersion();
358 
359  if ((rmtMaj > locMaj) ||
360  ((rmtMaj == locMaj) &&
361  (rmtMin > locMin)))
362  {
363  if (loadThemeInfo(dtheme))
364  {
365  LOG(VB_GUI, LOG_DEBUG, LOC +
366  QString("'%1' old version %2.%3, new version %4.%5")
367  .arg(themeName).arg(locMaj).arg(locMin)
368  .arg(rmtMaj).arg(rmtMin));
369 
370  m_infoList << dtheme;
371  m_themeStatuses[themeName] = "updateavailable";
372 
373  QFileInfo finfo(remoteTheme.GetPreviewPath());
375  remoteDir.append("/").append(finfo.fileName()),
376  localDir.append("/").append(finfo.fileName()),
377  nullptr);
378  }
379  }
380  else if ((rmtMaj == locMaj) &&
381  (rmtMin == locMin))
382  {
383  LOG(VB_GUI, LOG_DEBUG, LOC +
384  QString("'%1' up to date (%2.%3)")
385  .arg(themeName).arg(locMaj).arg(locMin));
386 
387  m_themeStatuses[themeName] = "uptodate";
388  }
389  }
390  else
391  {
392  LOG(VB_GUI, LOG_DEBUG, LOC +
393  QString("'%1' (%2.%3) available")
394  .arg(themeName)
395  .arg(remoteTheme.GetMajorVersion())
396  .arg(remoteTheme.GetMinorVersion()));
397 
398  ThemeInfo *tmpTheme = loadThemeInfo(dtheme);
399  if (tmpTheme)
400  {
401  themeName = tmpTheme->GetName();
402  themesSeen << dirName;
403  m_infoList << dtheme;
404  m_themeStatuses[themeName] = "updateavailable";
405 
406  QFileInfo finfo(tmpTheme->GetPreviewPath());
408  remoteDir.append("/").append(finfo.fileName()),
409  localDir.append("/").append(finfo.fileName()),
410  nullptr);
411  }
412  }
413  }
414  }
415 
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 : qAsConst(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.").arg(m_userThemeDir));
485  }
486 }
487 
488 ThemeInfo *ThemeChooser::loadThemeInfo(const QFileInfo &theme)
489 {
490  if (theme.fileName() == "default" || theme.fileName() == "default-wide")
491  return nullptr;
492 
493  ThemeInfo *themeinfo = nullptr;
494  if (theme.exists()) // local directory vs http:// or remote URL
495  themeinfo = new ThemeInfo(theme.absoluteFilePath());
496  else
497  themeinfo = new ThemeInfo(theme.filePath());
498 
499  if (!themeinfo)
500  return nullptr;
501 
502  if (themeinfo->GetName().isEmpty() || ((themeinfo->GetType() & THEME_UI) == 0))
503  {
504  delete themeinfo;
505  return nullptr;
506  }
507 
508  m_themeFileNameInfos[theme.filePath()] = themeinfo;
509  m_themeNameInfos[theme.fileName()] = themeinfo;
510 
511  return themeinfo;
512 }
513 
515 {
516  if (m_popupMenu)
517  return;
518 
519  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
520  QString label = tr("Theme Chooser Menu");
521 
522  m_popupMenu =
523  new MythDialogBox(label, popupStack, "themechoosermenupopup");
524 
526 
527  if (m_popupMenu->Create())
528  popupStack->AddScreen(m_popupMenu);
529  else
530  {
531  delete m_popupMenu;
532  m_popupMenu = nullptr;
533  return;
534  }
535 
536  m_popupMenu->SetReturnEvent(this, "popupmenu");
537 
539  {
541  {
542  m_popupMenu->AddButton(tr("Hide Fullscreen Preview"),
544  }
545  else
546  {
547  m_popupMenu->AddButton(tr("Show Fullscreen Preview"),
549  }
550  }
551 
552  m_popupMenu->AddButton(tr("Refresh Downloadable Themes"),
554 
556  if (current)
557  {
558  auto *info = current->GetData().value<ThemeInfo *>();
559 
560  if (info)
561  {
562  m_popupMenu->AddButton(tr("Select Theme"),
563  qOverload<>(&ThemeChooser::saveAndReload));
564 
565  if (info->GetPreviewPath().startsWith(m_userThemeDir))
566  m_popupMenu->AddButton(tr("Delete Theme"),
568  }
569  }
570 
571  if (gCoreContext->GetBoolSetting("ThemeUpdateNofications", true))
572  {
573  m_popupMenu->AddButton(tr("Disable Theme Update Notifications"),
575  }
576  else
577  {
578  m_popupMenu->AddButton(tr("Enable Theme Update Notifications"),
580  }
581 }
582 
583 void ThemeChooser::popupClosed(const QString& which, int result)
584 {
585  (void)which;
586  (void)result;
587 
588  m_popupMenu = nullptr;
589 }
590 
591 bool ThemeChooser::keyPressEvent(QKeyEvent *event)
592 {
593  if (GetFocusWidget()->keyPressEvent(event))
594  return true;
595 
596  QStringList actions;
597  bool handled = GetMythMainWindow()->TranslateKeyPress("Theme Chooser", event, actions);
598 
599  for (int i = 0; i < actions.size() && !handled; ++i)
600  {
601  QString action = actions[i];
602  handled = true;
603 
604  if (action == "MENU")
605  showPopupMenu();
606  else if (action == "DELETE")
607  removeTheme();
608  else if ((action == "ESCAPE") &&
610  {
612  }
613  else
614  handled = false;
615  }
616 
617  if (!handled && MythScreenType::keyPressEvent(event))
618  handled = true;
619 
620  return handled;
621 }
622 
624 {
626  {
628  {
631 
632  if (m_fullScreenName)
634 
636  m_fullPreviewShowing = false;
637  }
638  else
639  {
641  auto *info = item->GetData().value<ThemeInfo*>();
642  if (info)
643  {
645  {
646  m_fullScreenPreview->SetFilename(info->GetPreviewPath());
648  }
649 
650  if (m_fullScreenName)
651  m_fullScreenName->SetText(info->GetName());
652 
653  m_fullPreviewStateType->DisplayState("fullscreen");
654  m_fullPreviewShowing = true;
655  }
656  }
657  }
658 }
659 
661 {
662  if (gCoreContext->GetBoolSetting("ThemeUpdateNofications", true))
663  gCoreContext->SaveSettingOnHost("ThemeUpdateNofications", "0", "");
664  else
665  gCoreContext->SaveSettingOnHost("ThemeUpdateNofications", "1", "");
666 }
667 
669 {
670  LOG(VB_GUI, LOG_INFO, LOC + "Forcing remote theme list refresh");
672  gCoreContext->SaveSetting("ThemeInfoDownloadFailures", 0);
674 }
675 
677 {
679  if (current)
681 }
682 
684 {
685  auto *info = item->GetData().value<ThemeInfo *>();
686 
687  if (!info)
688  return;
689 
690  if (!info->GetDownloadURL().isEmpty())
691  {
692  QString testFile = m_userThemeDir + "/.test";
693  QFile test(testFile);
694  if (test.open(QIODevice::WriteOnly))
695  test.remove();
696  else
697  {
698  ShowOkPopup(tr("Unable to install theme, %1 themes directory is "
699  "not writable.").arg(m_userThemeDir));
700  return;
701  }
702 
703  QString downloadURL = info->GetDownloadURL();
704  QFileInfo qfile(downloadURL);
705  QString baseName = qfile.fileName();
706 
707  if (!gCoreContext->GetSetting("ThemeDownloadURL").isEmpty())
708  {
709 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
710  QStringList tokens =
711  gCoreContext->GetSetting("ThemeDownloadURL")
712  .split(";", QString::SkipEmptyParts);
713 #else
714  QStringList tokens =
715  gCoreContext->GetSetting("ThemeDownloadURL")
716  .split(";", Qt::SkipEmptyParts);
717 #endif
718  QString origURL = downloadURL;
719  downloadURL.replace(tokens[0], tokens[1]);
720  LOG(VB_FILE, LOG_WARNING, LOC +
721  QString("Theme download URL overridden from %1 to %2.")
722  .arg(origURL).arg(downloadURL));
723  }
724 
725  OpenBusyPopup(tr("Downloading %1 Theme").arg(info->GetName()));
726  m_downloadTheme = info;
727 #if 0
729  "Temp", baseName);
731 #else
732  QString localFile = GetConfDir() + "/tmp/" + baseName;
733  GetMythDownloadManager()->queueDownload(downloadURL, localFile, this);
734  m_downloadFile = localFile;
736 #endif
737  }
738  else
739  {
740  gCoreContext->SaveSetting("Theme", info->GetDirectoryName());
741  GetMythMainWindow()->JumpTo("Reload Theme");
742  }
743 }
744 
746 {
747  auto *info = item->GetData().value<ThemeInfo*>();
748 
749  if (!info)
750  return;
751 
752  QFileInfo preview(info->GetPreviewPath());
753  InfoMap infomap;
754  info->ToMap(infomap);
755  SetTextFromMap(infomap);
756  if (m_preview)
757  {
758  if (preview.exists())
759  {
760  m_preview->SetFilename(info->GetPreviewPath());
761  m_preview->Load();
762  }
763  else
764  m_preview->Reset();
765  }
767  {
769  {
770  if (preview.exists())
771  {
772  m_fullScreenPreview->SetFilename(info->GetPreviewPath());
774  }
775  else
777  }
778 
779  if (m_fullScreenName)
780  m_fullScreenName->SetText(info->GetName());
781  }
782 
783  MythUIStateType *themeLocation =
784  dynamic_cast<MythUIStateType*>(GetChild("themelocation"));
785  if (themeLocation)
786  {
787  if (info->GetDownloadURL().isEmpty())
788  themeLocation->DisplayState("local");
789  else
790  themeLocation->DisplayState("remote");
791  }
792 
793  MythUIStateType *aspectState =
794  dynamic_cast<MythUIStateType*>(GetChild("aspectstate"));
795  if (aspectState)
796  aspectState->DisplayState(info->GetAspect());
797 }
798 
799 void ThemeChooser::updateProgressBar(int bytesReceived,
800  int bytesTotal)
801 {
802  MythUIProgressBar *progressBar =
803  dynamic_cast<MythUIProgressBar *>(GetChild("downloadprogressbar"));
804 
805  if (!progressBar)
806  return;
807 
808  progressBar->SetUsed(bytesReceived);
809  progressBar->SetTotal(bytesTotal);
810 }
811 
813 {
814  if (e->type() == MythEvent::MythEventMessage)
815  {
816  auto *me = dynamic_cast<MythEvent *>(e);
817  if (me == nullptr)
818  return;
819 
820 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
821  QStringList tokens = me->Message().split(" ", QString::SkipEmptyParts);
822 #else
823  QStringList tokens = me->Message().split(" ", Qt::SkipEmptyParts);
824 #endif
825 
826  if (tokens.isEmpty())
827  return;
828 
829  if (tokens[0] == "DOWNLOAD_FILE")
830  {
831  QStringList args = me->ExtraDataList();
832  if ((m_downloadState == dsIdle) ||
833  (tokens.size() != 2) ||
834  (!m_downloadTheme) ||
835  (args[1] != m_downloadFile))
836  return;
837 
838  if (tokens[1] == "UPDATE")
839  {
840  updateProgressBar(args[2].toInt(), args[3].toInt());
841  }
842  else if (tokens[1] == "FINISHED")
843  {
844  bool remoteFileIsLocal = false;
845  int fileSize = args[2].toInt();
846  int errorCode = args[4].toInt();
847 
848  CloseBusyPopup();
849 
850  QFileInfo file(m_downloadFile);
852  (m_downloadFile.startsWith("myth://")))
853  {
854  // The backend download is finished so start the
855  // frontend download
856  if ((errorCode == 0) &&
857  (fileSize > 0))
858  {
860  QString localFile = GetConfDir() + "/tmp/" +
861  file.fileName();
862  file.setFile(localFile);
863 
864  if (file.exists())
865  {
866  remoteFileIsLocal = true;
867  m_downloadFile = localFile;
868  }
869  else
870  {
872  m_downloadFile, localFile, this);
873  OpenBusyPopup(tr("Copying %1 Theme Package")
875  m_downloadFile = localFile;
876  return;
877  }
878  }
879  else
880  {
882  ShowOkPopup(tr("ERROR downloading theme package on master backend."));
883  }
884  }
885 
887  (file.exists()))
888  {
889  // The frontend download is finished
890  if ((errorCode == 0) &&
891  (fileSize > 0))
892  {
894  auto *extractThread =
898  extractThread, "ThemeExtract");
899 
900  if (!remoteFileIsLocal)
902 
903  OpenBusyPopup(tr("Installing %1 Theme")
905  }
906  else
907  {
909  ShowOkPopup(tr("ERROR downloading theme package from master backend."));
910  }
911  }
912  }
913  }
914  else if ((me->Message() == "THEME_INSTALLED") &&
915  (m_downloadTheme) &&
917  {
919  CloseBusyPopup();
920  QStringList args = me->ExtraDataList();
921  QFile::remove(args[0]);
922 
923  QString event = QString("THEME_INSTALLED PATH %1")
924  .arg(m_userThemeDir +
927 
929 
930  // Send a message to ourself so we trigger a reload our next chance
931  auto *me2 = new MythEvent("THEME_RELOAD");
932  qApp->postEvent(this, me2);
933  }
934  else if ((me->Message() == "THEME_RELOAD") &&
935  (m_downloadState == dsIdle))
936  {
937  GetMythMainWindow()->JumpTo("Reload Theme");
938  }
939  }
940 }
941 
943 {
945  if (!current)
946  {
947  ShowOkPopup(tr("Error, no theme selected."));
948  return;
949  }
950 
951  auto *info = current->GetData().value<ThemeInfo *>();
952  if (!info)
953  {
954  ShowOkPopup(tr("Error, unable to find current theme."));
955  return;
956  }
957 
958  if (!info->GetPreviewPath().startsWith(m_userThemeDir))
959  {
960  ShowOkPopup(tr("%1 is not a user-installed theme and can not "
961  "be deleted.").arg(info->GetName()));
962  return;
963  }
964 
965  removeThemeDir(m_userThemeDir + info->GetDirectoryName());
966 
968 }
969 
970 bool ThemeChooser::removeThemeDir(const QString &dirname)
971 {
972  if ((!dirname.startsWith(m_userThemeDir)) &&
973  (!dirname.startsWith(GetMythUI()->GetThemeCacheDir())))
974  return true;
975 
976  QDir dir(dirname);
977 
978  if (!dir.exists())
979  return true;
980 
981  dir.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
982  QFileInfoList list = dir.entryInfoList();
983 
984  for (const auto & fi : qAsConst(list))
985  {
986  if (fi.isFile() && !fi.isSymLink())
987  {
988  if (!QFile::remove(fi.absoluteFilePath()))
989  return false;
990  }
991  else if (fi.isDir() && !fi.isSymLink())
992  {
993  if (!removeThemeDir(fi.absoluteFilePath()))
994  return false;
995  }
996  }
997 
998  return dir.rmdir(dirname);
999 }
1000 
1002 
1004  m_updateTimer(new QTimer(this))
1005 {
1006  QString version = GetMythSourcePath();
1007 
1008  if (!version.isEmpty() && !version.startsWith("fixes/"))
1009  {
1010  // Treat devel branches as master
1011  m_mythVersions << "trunk";
1012  }
1013  else
1014  {
1015  version = MYTH_BINARY_VERSION; // Example: 0.25.20101017-1
1016  version.replace(QRegExp("\\.[0-9]{8,}.*"), "");
1017 
1018  // If a version of the theme for this tag exists, use it...
1019  QRegExp subexp("v[0-9]+.[0-9]+.([0-9]+)-*");
1020  int pos = subexp.indexIn(GetMythSourceVersion());
1021  if (pos > -1)
1022  {
1023  for (int idx = subexp.cap(1).toInt(); idx > 0; --idx)
1024  m_mythVersions << version + "." + QString::number(idx);
1025  }
1027  }
1028 
1031  "remotethemes/themes.zip",
1032  "Temp");
1033 
1034  gCoreContext->SaveSetting("ThemeUpdateStatus", "");
1035 
1037 
1038  if (qEnvironmentVariableIsSet("MYTHTV_DEBUGMDM"))
1039  {
1040  LOG(VB_GENERAL, LOG_INFO, "Checking for theme updates every minute");
1041  m_updateTimer->start(1min);
1042  }
1043  else
1044  {
1045  LOG(VB_GENERAL, LOG_INFO, "Checking for theme updates every hour");
1046  m_updateTimer->start(1h);
1047  }
1048 
1049  // Run once 15 seconds from now
1050  QTimer::singleShot(15s, this, &ThemeUpdateChecker::checkForUpdate);
1051 }
1052 
1054 {
1055  if (m_updateTimer)
1056  {
1057  m_updateTimer->stop();
1058  delete m_updateTimer;
1059  m_updateTimer = nullptr;
1060  }
1061 }
1062 
1064 {
1065  if (GetMythUI()->GetCurrentLocation(false, true) != "mainmenu")
1066  return;
1067 
1068  ThemeInfo *localTheme = nullptr;
1069 
1071  {
1072  QStringList::iterator Iversion;
1073 
1074  for (Iversion = m_mythVersions.begin();
1075  Iversion != m_mythVersions.end(); ++Iversion)
1076  {
1077 
1078  QString remoteThemeDir =
1081  QString("remotethemes/%1/%2")
1082  .arg(*Iversion)
1083  .arg(GetMythUI()->GetThemeName()),
1084  "Temp");
1085 
1086  QString infoXML = remoteThemeDir;
1087  infoXML.append("/themeinfo.xml");
1088 
1089  LOG(VB_GUI, LOG_INFO, QString("ThemeUpdateChecker Loading '%1'")
1090  .arg(infoXML));
1091 
1092  if (RemoteFile::Exists(infoXML))
1093  {
1094  int locMaj = 0;
1095  int locMin = 0;
1096 
1097  auto *remoteTheme = new ThemeInfo(remoteThemeDir);
1098  if (!remoteTheme || remoteTheme->GetType() & THEME_UNKN)
1099  {
1100  LOG(VB_GENERAL, LOG_ERR,
1101  QString("ThemeUpdateChecker::checkForUpdate(): "
1102  "Unable to create ThemeInfo for %1")
1103  .arg(infoXML));
1104  delete remoteTheme;
1105  remoteTheme = nullptr;
1106  return;
1107  }
1108 
1109  if (!localTheme)
1110  {
1111  localTheme = new ThemeInfo(GetMythUI()->GetThemeDir());
1112  if (!localTheme || localTheme->GetType() & THEME_UNKN)
1113  {
1114  LOG(VB_GENERAL, LOG_ERR,
1115  "ThemeUpdateChecker::checkForUpdate(): "
1116  "Unable to create ThemeInfo for current theme");
1117  delete localTheme;
1118  localTheme = nullptr;
1119  return;
1120  }
1121  locMaj = localTheme->GetMajorVersion();
1122  locMin = localTheme->GetMinorVersion();
1123  }
1124 
1125  int rmtMaj = remoteTheme->GetMajorVersion();
1126  int rmtMin = remoteTheme->GetMinorVersion();
1127 
1128  delete remoteTheme;
1129  remoteTheme = nullptr;
1130 
1131  if ((rmtMaj > locMaj) ||
1132  ((rmtMaj == locMaj) &&
1133  (rmtMin > locMin)))
1134  {
1136  QString("%1-%2.%3").arg(GetMythUI()->GetThemeName())
1137  .arg(rmtMaj).arg(rmtMin);
1138 
1139  QString status = gCoreContext->GetSetting
1140  ("ThemeUpdateStatus");
1141  QString currentLocation = GetMythUI()->GetCurrentLocation
1142  (false, true);
1143 
1144  if ((!status.startsWith(m_lastKnownThemeVersion)) &&
1145  (currentLocation == "mainmenu"))
1146  {
1147  m_currentVersion = QString("%1.%2")
1148  .arg(locMaj).arg(locMin);
1149  m_newVersion = QString("%1.%2").arg(rmtMaj).arg(rmtMin);
1150 
1151  gCoreContext->SaveSetting("ThemeUpdateStatus",
1153  + " notified");
1154 
1155  QString message = tr("Version %1 of the %2 theme is now "
1156  "available in the Theme Chooser. "
1157  "The currently installed version "
1158  "is %3.")
1159  .arg(m_newVersion)
1160  .arg(GetMythUI()->GetThemeName())
1161  .arg(m_currentVersion);
1162 
1163  ShowOkPopup(message);
1164  break;
1165  }
1166  }
1167  }
1168  }
1169  }
1170 
1171  delete localTheme;
1172 }
1173 
1174 /* 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:302
build_compdb.args
args
Definition: build_compdb.py:11
e
QDomElement e
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:1420
MythDialogBox::SetReturnEvent
void SetReturnEvent(QObject *retobject, const QString &resultid)
Definition: mythdialogbox.cpp:300
MythEvent::MythEventMessage
static Type MythEventMessage
Definition: mythevent.h:73
MythUIButtonList::GetItemCurrent
MythUIButtonListItem * GetItemCurrent() const
Definition: mythuibuttonlist.cpp:1590
MythScreenType::SetBusyPopupMessage
void SetBusyPopupMessage(const QString &message)
Definition: mythscreentype.cpp:361
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:828
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:56
MythUIButtonListItem::DisplayState
void DisplayState(const QString &state, const QString &name)
Definition: mythuibuttonlist.cpp:3499
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:1442
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:812
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:15
arg
arg(title).arg(filename).arg(doDelete))
ThemeChooser::m_popupMenu
MythDialogBox * m_popupMenu
Definition: themechooser.h:93
ThemeChooser::refreshDownloadableThemes
void refreshDownloadableThemes(void)
Definition: themechooser.cpp:668
ThemeChooser::m_refreshDownloadableThemes
bool m_refreshDownloadableThemes
Definition: themechooser.h:83
MythScreenType::OpenBusyPopup
void OpenBusyPopup(const QString &message="")
Definition: mythscreentype.cpp:336
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:583
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:799
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:47
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:75
MythScreenType::ResetBusyPopup
void ResetBusyPopup(void)
Definition: mythscreentype.cpp:367
MythUIButtonListItem
Definition: mythuibuttonlist.h:27
ThemeInfo::GetName
QString GetName() const
Definition: themeinfo.h:30
ThemeChooser::showPopupMenu
void showPopupMenu(void)
Definition: themechooser.cpp:514
MythScreenType::ReloadInBackground
void ReloadInBackground(void)
Definition: mythscreentype.cpp:330
baseName
QString baseName
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:593
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:781
GetConfDir
QString GetConfDir(void)
Definition: mythdirs.cpp:224
ThemeExtractThread::m_destDir
QString m_destDir
Definition: themechooser.cpp:67
LOC
#define LOC
Definition: themechooser.cpp:40
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:1114
remotefile.h
ThemeChooser::Create
bool Create(void) override
Definition: themechooser.cpp:96
MythUIProgressBar
Progress bar widget.
Definition: mythuiprogressbar.h:12
MythCoreContext::SendSystemEvent
void SendSystemEvent(const QString &msg)
Definition: mythcorecontext.cpp:1554
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:488
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:222
MythUIComposite::SetTextFromMap
virtual void SetTextFromMap(const InfoMap &infoMap)
Definition: mythuicomposite.cpp:9
ThemeUpdateChecker::checkForUpdate
void checkForUpdate(void)
Definition: themechooser.cpp:1063
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:140
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:676
RemoteFile::DeleteFile
static bool DeleteFile(const QString &url)
Definition: remotefile.cpp:418
MythUIButtonListItem::GetData
QVariant GetData()
Definition: mythuibuttonlist.cpp:3580
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:933
GetMythSourcePath
const char * GetMythSourcePath()
Definition: mythcoreutil.cpp:318
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:3281
MythCoreContext::GetBoolSetting
bool GetBoolSetting(const QString &key, bool defaultval=false)
Definition: mythcorecontext.cpp:927
mythburn.themeName
string themeName
Definition: mythburn.py:218
mthreadpool.h
mythuihelper.h
ThemeUpdateChecker::~ThemeUpdateChecker
~ThemeUpdateChecker(void) override
Definition: themechooser.cpp:1053
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:1001
ThemeChooser::toggleFullscreenPreview
void toggleFullscreenPreview(void)
Definition: themechooser.cpp:623
ThemeUpdateChecker::ThemeUpdateChecker
ThemeUpdateChecker(void)
Definition: themechooser.cpp:1003
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:414
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:222
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:3398
dir
QDir dir
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:1174
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:660
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:591
MythMainWindow::GetStack
MythScreenStack * GetStack(const QString &Stackname)
Definition: mythmainwindow.cpp:320
GetMythSourceVersion
const char * GetMythSourceVersion()
Definition: mythcoreutil.cpp:313
ThemeChooser::~ThemeChooser
~ThemeChooser() override
Definition: themechooser.cpp:85
MythCoreContext::GetHostName
QString GetHostName(void)
Definition: mythcorecontext.cpp:859
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:50
MythCoreContext::SaveSetting
void SaveSetting(const QString &key, int newValue)
Definition: mythcorecontext.cpp:902
downloadURL
static bool downloadURL(const QString &url, QByteArray *buffer, QString &finalURL)
Definition: httplivestreambuffer.cpp:98
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:306
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
ThemeChooser::dsIdle
@ dsIdle
Definition: themechooser.h:63
MythUIButtonListItem::SetData
void SetData(QVariant data)
Definition: mythuibuttonlist.cpp:3575
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:557
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:912
ThemeChooser::removeTheme
void removeTheme(void)
Definition: themechooser.cpp:942
RemoteDownloadFile
QString RemoteDownloadFile(const QString &url, const QString &storageGroup, const QString &filename)
Definition: mythcoreutil.cpp:299
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:90
ThemeChooser::m_preview
MythUIImage * m_preview
Definition: themechooser.h:75
MythScreenType::CloseBusyPopup
void CloseBusyPopup(void)
Definition: mythscreentype.cpp:354
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:341
ThemeExtractThread::m_srcFile
QString m_srcFile
Definition: themechooser.cpp:66
MythUIStateType::DisplayState
bool DisplayState(const QString &name)
Definition: mythuistatetype.cpp:84
ThemeChooser::removeThemeDir
bool removeThemeDir(const QString &dirname)
Definition: themechooser.cpp:970
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:919
GetMythDownloadManager
MythDownloadManager * GetMythDownloadManager(void)
Gets the pointer to the MythDownloadManager singleton.
Definition: mythdownloadmanager.cpp:145
ThemeChooser::itemChanged
void itemChanged(MythUIButtonListItem *item)
Definition: themechooser.cpp:745