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