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 
124  this, qOverload<MythUIButtonListItem*>(&ThemeChooser::saveAndReload));
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  // Downloadable themeinfos have thumbnail copies of their preview images
454  if (!themeinfo->GetDownloadURL().isEmpty())
455  thumbnail = thumbnail.append(".thumb.jpg");
456  item->SetImage(thumbnail);
457 
458  if (curTheme == themeinfo->GetDirectoryName())
459  curThemeInfo = themeinfo;
460  }
461  }
462 
464 
465  if (curThemeInfo)
466  m_themes->SetValueByData(QVariant::fromValue(curThemeInfo));
467 
469  if (current)
471 
472  QString testFile = m_userThemeDir + "/.test";
473  QFile test(testFile);
474  if (test.open(QIODevice::WriteOnly))
475  test.remove();
476  else
477  {
478  ShowOkPopup(tr("Error creating test file, %1 themes directory is "
479  "not writable.").arg(m_userThemeDir));
480  }
481 }
482 
483 ThemeInfo *ThemeChooser::loadThemeInfo(const QFileInfo &theme)
484 {
485  if (theme.fileName() == "default" || theme.fileName() == "default-wide")
486  return nullptr;
487 
488  ThemeInfo *themeinfo = nullptr;
489  if (theme.exists()) // local directory vs http:// or remote URL
490  themeinfo = new ThemeInfo(theme.absoluteFilePath());
491  else
492  themeinfo = new ThemeInfo(theme.filePath());
493 
494  if (!themeinfo)
495  return nullptr;
496 
497  if (themeinfo->GetName().isEmpty() || ((themeinfo->GetType() & THEME_UI) == 0))
498  {
499  delete themeinfo;
500  return nullptr;
501  }
502 
503  m_themeFileNameInfos[theme.filePath()] = themeinfo;
504  m_themeNameInfos[theme.fileName()] = themeinfo;
505 
506  return themeinfo;
507 }
508 
510 {
511  if (m_popupMenu)
512  return;
513 
514  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
515  QString label = tr("Theme Chooser Menu");
516 
517  m_popupMenu =
518  new MythDialogBox(label, popupStack, "themechoosermenupopup");
519 
521 
522  if (m_popupMenu->Create())
523  popupStack->AddScreen(m_popupMenu);
524  else
525  {
526  delete m_popupMenu;
527  m_popupMenu = nullptr;
528  return;
529  }
530 
531  m_popupMenu->SetReturnEvent(this, "popupmenu");
532 
534  {
536  {
537  m_popupMenu->AddButton(tr("Hide Fullscreen Preview"),
538  SLOT(toggleFullscreenPreview()));
539  }
540  else
541  {
542  m_popupMenu->AddButton(tr("Show Fullscreen Preview"),
543  SLOT(toggleFullscreenPreview()));
544  }
545  }
546 
547  m_popupMenu->AddButton(tr("Refresh Downloadable Themes"),
548  SLOT(refreshDownloadableThemes()));
549 
551  if (current)
552  {
553  auto *info = current->GetData().value<ThemeInfo *>();
554 
555  if (info)
556  {
557  m_popupMenu->AddButton(tr("Select Theme"),
558  SLOT(saveAndReload()));
559 
560  if (info->GetPreviewPath().startsWith(m_userThemeDir))
561  m_popupMenu->AddButton(tr("Delete Theme"),
562  SLOT(removeTheme()));
563  }
564  }
565 
566  if (gCoreContext->GetBoolSetting("ThemeUpdateNofications", true))
567  {
568  m_popupMenu->AddButton(tr("Disable Theme Update Notifications"),
570  }
571  else
572  {
573  m_popupMenu->AddButton(tr("Enable Theme Update Notifications"),
575  }
576 }
577 
578 void ThemeChooser::popupClosed(const QString& which, int result)
579 {
580  (void)which;
581  (void)result;
582 
583  m_popupMenu = nullptr;
584 }
585 
586 bool ThemeChooser::keyPressEvent(QKeyEvent *event)
587 {
588  if (GetFocusWidget()->keyPressEvent(event))
589  return true;
590 
591  QStringList actions;
592  bool handled = GetMythMainWindow()->TranslateKeyPress("Theme Chooser", event, actions);
593 
594  for (int i = 0; i < actions.size() && !handled; ++i)
595  {
596  QString action = actions[i];
597  handled = true;
598 
599  if (action == "MENU")
600  showPopupMenu();
601  else if (action == "DELETE")
602  removeTheme();
603  else if ((action == "ESCAPE") &&
605  {
607  }
608  else
609  handled = false;
610  }
611 
612  if (!handled && MythScreenType::keyPressEvent(event))
613  handled = true;
614 
615  return handled;
616 }
617 
619 {
621  {
623  {
626 
627  if (m_fullScreenName)
629 
631  m_fullPreviewShowing = false;
632  }
633  else
634  {
636  auto *info = item->GetData().value<ThemeInfo*>();
637  if (info)
638  {
640  {
641  m_fullScreenPreview->SetFilename(info->GetPreviewPath());
643  }
644 
645  if (m_fullScreenName)
646  m_fullScreenName->SetText(info->GetName());
647 
648  m_fullPreviewStateType->DisplayState("fullscreen");
649  m_fullPreviewShowing = true;
650  }
651  }
652  }
653 }
654 
656 {
657  if (gCoreContext->GetBoolSetting("ThemeUpdateNofications", true))
658  gCoreContext->SaveSettingOnHost("ThemeUpdateNofications", "0", "");
659  else
660  gCoreContext->SaveSettingOnHost("ThemeUpdateNofications", "1", "");
661 }
662 
664 {
665  LOG(VB_GUI, LOG_INFO, LOC + "Forcing remote theme list refresh");
667  gCoreContext->SaveSetting("ThemeInfoDownloadFailures", 0);
669 }
670 
672 {
674  if (current)
676 }
677 
679 {
680  auto *info = item->GetData().value<ThemeInfo *>();
681 
682  if (!info)
683  return;
684 
685  if (!info->GetDownloadURL().isEmpty())
686  {
687  QString testFile = m_userThemeDir + "/.test";
688  QFile test(testFile);
689  if (test.open(QIODevice::WriteOnly))
690  test.remove();
691  else
692  {
693  ShowOkPopup(tr("Unable to install theme, %1 themes directory is "
694  "not writable.").arg(m_userThemeDir));
695  return;
696  }
697 
698  QString downloadURL = info->GetDownloadURL();
699  QFileInfo qfile(downloadURL);
700  QString baseName = qfile.fileName();
701 
702  if (!gCoreContext->GetSetting("ThemeDownloadURL").isEmpty())
703  {
704 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
705  QStringList tokens =
706  gCoreContext->GetSetting("ThemeDownloadURL")
707  .split(";", QString::SkipEmptyParts);
708 #else
709  QStringList tokens =
710  gCoreContext->GetSetting("ThemeDownloadURL")
711  .split(";", Qt::SkipEmptyParts);
712 #endif
713  QString origURL = downloadURL;
714  downloadURL.replace(tokens[0], tokens[1]);
715  LOG(VB_FILE, LOG_WARNING, LOC +
716  QString("Theme download URL overridden from %1 to %2.")
717  .arg(origURL).arg(downloadURL));
718  }
719 
720  OpenBusyPopup(tr("Downloading %1 Theme").arg(info->GetName()));
721  m_downloadTheme = info;
722 #if 0
724  "Temp", baseName);
726 #else
727  QString localFile = GetConfDir() + "/tmp/" + baseName;
728  GetMythDownloadManager()->queueDownload(downloadURL, localFile, this);
729  m_downloadFile = localFile;
731 #endif
732  }
733  else
734  {
735  gCoreContext->SaveSetting("Theme", info->GetDirectoryName());
736  GetMythMainWindow()->JumpTo("Reload Theme");
737  }
738 }
739 
741 {
742  auto *info = item->GetData().value<ThemeInfo*>();
743 
744  if (!info)
745  return;
746 
747  QFileInfo preview(info->GetPreviewPath());
748  InfoMap infomap;
749  info->ToMap(infomap);
750  SetTextFromMap(infomap);
751  if (m_preview)
752  {
753  if (preview.exists())
754  {
755  m_preview->SetFilename(info->GetPreviewPath());
756  m_preview->Load();
757  }
758  else
759  m_preview->Reset();
760  }
762  {
764  {
765  if (preview.exists())
766  {
767  m_fullScreenPreview->SetFilename(info->GetPreviewPath());
769  }
770  else
772  }
773 
774  if (m_fullScreenName)
775  m_fullScreenName->SetText(info->GetName());
776  }
777 
778  MythUIStateType *themeLocation =
779  dynamic_cast<MythUIStateType*>(GetChild("themelocation"));
780  if (themeLocation)
781  {
782  if (info->GetDownloadURL().isEmpty())
783  themeLocation->DisplayState("local");
784  else
785  themeLocation->DisplayState("remote");
786  }
787 
788  MythUIStateType *aspectState =
789  dynamic_cast<MythUIStateType*>(GetChild("aspectstate"));
790  if (aspectState)
791  aspectState->DisplayState(info->GetAspect());
792 }
793 
794 void ThemeChooser::updateProgressBar(int bytesReceived,
795  int bytesTotal)
796 {
797  MythUIProgressBar *progressBar =
798  dynamic_cast<MythUIProgressBar *>(GetChild("downloadprogressbar"));
799 
800  if (!progressBar)
801  return;
802 
803  progressBar->SetUsed(bytesReceived);
804  progressBar->SetTotal(bytesTotal);
805 }
806 
808 {
809  if (e->type() == MythEvent::MythEventMessage)
810  {
811  auto *me = dynamic_cast<MythEvent *>(e);
812  if (me == nullptr)
813  return;
814 
815 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
816  QStringList tokens = me->Message().split(" ", QString::SkipEmptyParts);
817 #else
818  QStringList tokens = me->Message().split(" ", Qt::SkipEmptyParts);
819 #endif
820 
821  if (tokens.isEmpty())
822  return;
823 
824  if (tokens[0] == "DOWNLOAD_FILE")
825  {
826  QStringList args = me->ExtraDataList();
827  if ((m_downloadState == dsIdle) ||
828  (tokens.size() != 2) ||
829  (!m_downloadTheme) ||
830  (args[1] != m_downloadFile))
831  return;
832 
833  if (tokens[1] == "UPDATE")
834  {
835  updateProgressBar(args[2].toInt(), args[3].toInt());
836  }
837  else if (tokens[1] == "FINISHED")
838  {
839  bool remoteFileIsLocal = false;
840  int fileSize = args[2].toInt();
841  int errorCode = args[4].toInt();
842 
843  CloseBusyPopup();
844 
845  QFileInfo file(m_downloadFile);
847  (m_downloadFile.startsWith("myth://")))
848  {
849  // The backend download is finished so start the
850  // frontend download
851  if ((errorCode == 0) &&
852  (fileSize > 0))
853  {
855  QString localFile = GetConfDir() + "/tmp/" +
856  file.fileName();
857  file.setFile(localFile);
858 
859  if (file.exists())
860  {
861  remoteFileIsLocal = true;
862  m_downloadFile = localFile;
863  }
864  else
865  {
867  m_downloadFile, localFile, this);
868  OpenBusyPopup(tr("Copying %1 Theme Package")
870  m_downloadFile = localFile;
871  return;
872  }
873  }
874  else
875  {
877  ShowOkPopup(tr("ERROR downloading theme package on master backend."));
878  }
879  }
880 
882  (file.exists()))
883  {
884  // The frontend download is finished
885  if ((errorCode == 0) &&
886  (fileSize > 0))
887  {
889  auto *extractThread =
893  extractThread, "ThemeExtract");
894 
895  if (!remoteFileIsLocal)
897 
898  OpenBusyPopup(tr("Installing %1 Theme")
900  }
901  else
902  {
904  ShowOkPopup(tr("ERROR downloading theme package from master backend."));
905  }
906  }
907  }
908  }
909  else if ((me->Message() == "THEME_INSTALLED") &&
910  (m_downloadTheme) &&
912  {
914  CloseBusyPopup();
915  QStringList args = me->ExtraDataList();
916  QFile::remove(args[0]);
917 
918  QString event = QString("THEME_INSTALLED PATH %1")
919  .arg(m_userThemeDir +
922 
924 
925  // Send a message to ourself so we trigger a reload our next chance
926  auto *me2 = new MythEvent("THEME_RELOAD");
927  qApp->postEvent(this, me2);
928  }
929  else if ((me->Message() == "THEME_RELOAD") &&
930  (m_downloadState == dsIdle))
931  {
932  GetMythMainWindow()->JumpTo("Reload Theme");
933  }
934  }
935 }
936 
938 {
940  if (!current)
941  {
942  ShowOkPopup(tr("Error, no theme selected."));
943  return;
944  }
945 
946  auto *info = current->GetData().value<ThemeInfo *>();
947  if (!info)
948  {
949  ShowOkPopup(tr("Error, unable to find current theme."));
950  return;
951  }
952 
953  if (!info->GetPreviewPath().startsWith(m_userThemeDir))
954  {
955  ShowOkPopup(tr("%1 is not a user-installed theme and can not "
956  "be deleted.").arg(info->GetName()));
957  return;
958  }
959 
960  removeThemeDir(m_userThemeDir + info->GetDirectoryName());
961 
963 }
964 
965 bool ThemeChooser::removeThemeDir(const QString &dirname)
966 {
967  if ((!dirname.startsWith(m_userThemeDir)) &&
968  (!dirname.startsWith(GetMythUI()->GetThemeCacheDir())))
969  return true;
970 
971  QDir dir(dirname);
972 
973  if (!dir.exists())
974  return true;
975 
976  dir.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
977  QFileInfoList list = dir.entryInfoList();
978 
979  for (const auto & fi : qAsConst(list))
980  {
981  if (fi.isFile() && !fi.isSymLink())
982  {
983  if (!QFile::remove(fi.absoluteFilePath()))
984  return false;
985  }
986  else if (fi.isDir() && !fi.isSymLink())
987  {
988  if (!removeThemeDir(fi.absoluteFilePath()))
989  return false;
990  }
991  }
992 
993  return dir.rmdir(dirname);
994 }
995 
997 
999  m_updateTimer(new QTimer(this))
1000 {
1001  QString version = GetMythSourcePath();
1002 
1003  if (!version.isEmpty() && !version.startsWith("fixes/"))
1004  {
1005  // Treat devel branches as master
1006  m_mythVersions << "trunk";
1007  }
1008  else
1009  {
1010  version = MYTH_BINARY_VERSION; // Example: 0.25.20101017-1
1011  version.replace(QRegExp("\\.[0-9]{8,}.*"), "");
1012 
1013  // If a version of the theme for this tag exists, use it...
1014  QRegExp subexp("v[0-9]+.[0-9]+.([0-9]+)-*");
1015  int pos = subexp.indexIn(GetMythSourceVersion());
1016  if (pos > -1)
1017  {
1018  for (int idx = subexp.cap(1).toInt(); idx > 0; --idx)
1019  m_mythVersions << version + "." + QString::number(idx);
1020  }
1022  }
1023 
1026  "remotethemes/themes.zip",
1027  "Temp");
1028 
1029  gCoreContext->SaveSetting("ThemeUpdateStatus", "");
1030 
1032 
1033  if (getenv("MYTHTV_DEBUGMDM"))
1034  {
1035  LOG(VB_GENERAL, LOG_INFO, "Checking for theme updates every minute");
1036  m_updateTimer->start(60 * 1000); // Run once a minute
1037  }
1038  else
1039  {
1040  LOG(VB_GENERAL, LOG_INFO, "Checking for theme updates every hour");
1041  m_updateTimer->start(60 * 60 * 1000); // Run once an hour
1042  }
1043 
1044  // Run once 15 seconds from now
1045  QTimer::singleShot(15 * 1000, this, &ThemeUpdateChecker::checkForUpdate);
1046 }
1047 
1049 {
1050  if (m_updateTimer)
1051  {
1052  m_updateTimer->stop();
1053  delete m_updateTimer;
1054  m_updateTimer = nullptr;
1055  }
1056 }
1057 
1059 {
1060  if (GetMythUI()->GetCurrentLocation(false, true) != "mainmenu")
1061  return;
1062 
1063  ThemeInfo *localTheme = nullptr;
1064 
1066  {
1067  QStringList::iterator Iversion;
1068 
1069  for (Iversion = m_mythVersions.begin();
1070  Iversion != m_mythVersions.end(); ++Iversion)
1071  {
1072 
1073  QString remoteThemeDir =
1076  QString("remotethemes/%1/%2")
1077  .arg(*Iversion)
1078  .arg(GetMythUI()->GetThemeName()),
1079  "Temp");
1080 
1081  QString infoXML = remoteThemeDir;
1082  infoXML.append("/themeinfo.xml");
1083 
1084  LOG(VB_GUI, LOG_INFO, QString("ThemeUpdateChecker Loading '%1'")
1085  .arg(infoXML));
1086 
1087  if (RemoteFile::Exists(infoXML))
1088  {
1089  int locMaj = 0;
1090  int locMin = 0;
1091 
1092  auto *remoteTheme = new ThemeInfo(remoteThemeDir);
1093  if (!remoteTheme || remoteTheme->GetType() & THEME_UNKN)
1094  {
1095  LOG(VB_GENERAL, LOG_ERR,
1096  QString("ThemeUpdateChecker::checkForUpdate(): "
1097  "Unable to create ThemeInfo for %1")
1098  .arg(infoXML));
1099  delete remoteTheme;
1100  remoteTheme = nullptr;
1101  return;
1102  }
1103 
1104  if (!localTheme)
1105  {
1106  localTheme = new ThemeInfo(GetMythUI()->GetThemeDir());
1107  if (!localTheme || localTheme->GetType() & THEME_UNKN)
1108  {
1109  LOG(VB_GENERAL, LOG_ERR,
1110  "ThemeUpdateChecker::checkForUpdate(): "
1111  "Unable to create ThemeInfo for current theme");
1112  delete localTheme;
1113  localTheme = nullptr;
1114  return;
1115  }
1116  locMaj = localTheme->GetMajorVersion();
1117  locMin = localTheme->GetMinorVersion();
1118  }
1119 
1120  int rmtMaj = remoteTheme->GetMajorVersion();
1121  int rmtMin = remoteTheme->GetMinorVersion();
1122 
1123  delete remoteTheme;
1124  remoteTheme = nullptr;
1125 
1126  if ((rmtMaj > locMaj) ||
1127  ((rmtMaj == locMaj) &&
1128  (rmtMin > locMin)))
1129  {
1131  QString("%1-%2.%3").arg(GetMythUI()->GetThemeName())
1132  .arg(rmtMaj).arg(rmtMin);
1133 
1134  QString status = gCoreContext->GetSetting
1135  ("ThemeUpdateStatus");
1136  QString currentLocation = GetMythUI()->GetCurrentLocation
1137  (false, true);
1138 
1139  if ((!status.startsWith(m_lastKnownThemeVersion)) &&
1140  (currentLocation == "mainmenu"))
1141  {
1142  m_currentVersion = QString("%1.%2")
1143  .arg(locMaj).arg(locMin);
1144  m_newVersion = QString("%1.%2").arg(rmtMaj).arg(rmtMin);
1145 
1146  gCoreContext->SaveSetting("ThemeUpdateStatus",
1148  + " notified");
1149 
1150  QString message = tr("Version %1 of the %2 theme is now "
1151  "available in the Theme Chooser. "
1152  "The currently installed version "
1153  "is %3.")
1154  .arg(m_newVersion)
1155  .arg(GetMythUI()->GetThemeName())
1156  .arg(m_currentVersion);
1157 
1158  ShowOkPopup(message);
1159  break;
1160  }
1161  }
1162  }
1163  }
1164  }
1165 
1166  delete localTheme;
1167 }
1168 
1169 /* 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:276
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:824
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:551
ThemeExtractThread::run
void run() override
Definition: themechooser.cpp:51
MythUIButtonListItem::DisplayState
void DisplayState(const QString &state, const QString &name)
Definition: mythuibuttonlist.cpp:3499
MythMainWindow::JumpTo
void JumpTo(const QString &destination, bool pop=true)
Definition: mythmainwindow.cpp:1483
ThemeInfo::GetAspect
QString GetAspect() const
Definition: themeinfo.h:28
RemoteFile::Exists
static bool Exists(const QString &url, struct stat *fileinfo)
Definition: remotefile.cpp:461
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:1139
MythUIType::GetChild
MythUIType * GetChild(const QString &name) const
Get a named child of this UIType.
Definition: mythuitype.cpp:131
mythscreenstack.h
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:17
mythcoreutil.h
ThemeChooser::customEvent
void customEvent(QEvent *e) override
Definition: themechooser.cpp:807
MythDownloadManager::queueDownload
void queueDownload(const QString &url, const QString &dest, QObject *caller, bool reload=false)
Adds a url to the download queue.
Definition: mythdownloadmanager.cpp:393
MythUIProgressBar::SetUsed
void SetUsed(int value)
Definition: mythuiprogressbar.cpp:59
ThemeInfo::GetMinorVersion
int GetMinorVersion() const
Definition: themeinfo.h:37
mythdialogbox.h
MythScreenStack
Definition: mythscreenstack.h:16
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:663
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
MythDialogBox::Closed
void Closed(QString, int)
MythScreenType
Screen in which all other widgets are contained and rendered.
Definition: mythscreentype.h:45
mythuistatetype.h
GetCacheDir
QString GetCacheDir(void)
Returns the base directory for all cached files.
Definition: mythdirs.cpp: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:578
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:794
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:326
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:509
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:777
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
MythUIButtonList::itemClicked
void itemClicked(MythUIButtonListItem *item)
remotefile.h
ThemeChooser::Create
bool Create(void) override
Definition: themechooser.cpp:91
MythUIProgressBar
Progress bar widget.
Definition: mythuiprogressbar.h:13
MythCoreContext::SendSystemEvent
void SendSystemEvent(const QString &msg)
Definition: mythcorecontext.cpp:1550
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:483
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:301
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:1058
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: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:22
storagegroup.h
ThemeChooser::dsExtractingTheme
@ dsExtractingTheme
Definition: themechooser.h:66
ThemeChooser::saveAndReload
void saveAndReload(void)
Definition: themechooser.cpp:671
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:56
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:929
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:923
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:1048
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:997
ThemeChooser::toggleFullscreenPreview
void toggleFullscreenPreview(void)
Definition: themechooser.cpp:618
ThemeUpdateChecker::ThemeUpdateChecker
ThemeUpdateChecker(void)
Definition: themechooser.cpp:998
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: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: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:105
StorageGroup
Definition: storagegroup.h:12
build_compdb.action
action
Definition: build_compdb.py:9
ThemeChooser::toggleThemeUpdateNotifications
static void toggleThemeUpdateNotifications(void)
Definition: themechooser.cpp:655
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:586
GetMythSourceVersion
const char * GetMythSourceVersion()
Definition: mythcoreutil.cpp:313
ThemeChooser::~ThemeChooser
~ThemeChooser() override
Definition: themechooser.cpp:80
MythCoreContext::GetHostName
QString GetHostName(void)
Definition: mythcorecontext.cpp:855
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:898
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:413
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: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:908
ThemeChooser::removeTheme
void removeTheme(void)
Definition: themechooser.cpp:937
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: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:341
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:965
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:915
GetMythDownloadManager
MythDownloadManager * GetMythDownloadManager(void)
Gets the pointer to the MythDownloadManager singleton.
Definition: mythdownloadmanager.cpp:145
ThemeChooser::itemChanged
void itemChanged(MythUIButtonListItem *item)
Definition: themechooser.cpp:740