Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge MythVideo into core.

Most definitely requires a make distclean of both core and plugins.  To be safe, you should also probably remove the libmythvideo.so file from your installed plusings dir ($PREFIX/libs/mythtv/plugins).

Move all the UI portions of mythvideo into the core of MythTV.  The concept of a TV-only media center has become increasingly irrelevant, and this is the first move towards bringing obvious and necessary functionality in to the core.

Part of this work was already done before .24 with the creation of libmythmetadata, which held all the non-UI portions of mythvideo.  Since the DB changes were committed to make sure that all users now have a videometadata table, the only thing that remained was to bring the UI itself into mythfrontend.  This work is now more or less done.  There's a lot of interconnected menu themes, bits, and pieces, but my testing of all menu themes and all obvious video settings, views, and popups seems to indicate that all is working properly.  I'm sure that at least *something* has escaped me, but we'll handle those issues as they arrive.
  • Loading branch information...
commit f09c512b4cc6dc3527d52c4f386fa59058254b07 1 parent c9bebe8
Robert McNamara authored
Showing with 14,142 additions and 40 deletions.
  1. +1 −1  mythtv/libs/libmythmetadata/globals.cpp
  2. +2 −2 mythtv/libs/libmythmetadata/metadatacommon.cpp
  3. +5 −5 mythtv/libs/libmythmetadata/metadatacommon.h
  4. +4 −4 mythtv/libs/libmythmetadata/metadataimagedownload.cpp
  5. +3 −3 mythtv/libs/libmythmetadata/metadataimagedownload.h
  6. +1,231 −0 mythtv/programs/mythfrontend/editvideometadata.cpp
  7. +148 −0 mythtv/programs/mythfrontend/editvideometadata.h
  8. +348 −0 mythtv/programs/mythfrontend/main.cpp
  9. +12 −2 mythtv/programs/mythfrontend/mythfrontend.pro
  10. +4,002 −0 mythtv/programs/mythfrontend/videodlg.cpp
  11. +230 −0 mythtv/programs/mythfrontend/videodlg.h
  12. +541 −0 mythtv/programs/mythfrontend/videofileassoc.cpp
  13. +51 −0 mythtv/programs/mythfrontend/videofileassoc.h
  14. +922 −0 mythtv/programs/mythfrontend/videofilter.cpp
  15. +275 −0 mythtv/programs/mythfrontend/videofilter.h
  16. +313 −0 mythtv/programs/mythfrontend/videoglobalsettings.cpp
  17. +12 −0 mythtv/programs/mythfrontend/videoglobalsettings.h
  18. +1,632 −0 mythtv/programs/mythfrontend/videolist.cpp
  19. +83 −0 mythtv/programs/mythfrontend/videolist.h
  20. +160 −0 mythtv/programs/mythfrontend/videometadatasettings.cpp
  21. +41 −0 mythtv/programs/mythfrontend/videometadatasettings.h
  22. +417 −0 mythtv/programs/mythfrontend/videoplayercommand.cpp
  23. +27 −0 mythtv/programs/mythfrontend/videoplayercommand.h
  24. +190 −0 mythtv/programs/mythfrontend/videoplayersettings.cpp
  25. +44 −0 mythtv/programs/mythfrontend/videoplayersettings.h
  26. +86 −0 mythtv/programs/mythfrontend/videopopups.cpp
  27. +37 −0 mythtv/programs/mythfrontend/videopopups.h
  28. +1 −2  mythtv/themes/DVR/main_settings.xml
  29. +1 −2  mythtv/themes/DVR/util_menu.xml
  30. +31 −0 mythtv/themes/DVR/video_settings.xml
  31. +48 −0 mythtv/themes/DVR/videomenu.xml
  32. +1 −2  mythtv/themes/classic/main_settings.xml
  33. +1 −2  mythtv/themes/classic/mainmenu.xml
  34. +31 −0 mythtv/themes/classic/video_settings.xml
  35. +48 −0 mythtv/themes/classic/videomenu.xml
  36. BIN  mythtv/themes/default-wide/images/mv_browse_background.png
  37. BIN  mythtv/themes/default-wide/images/mv_browse_nocover_large.png
  38. BIN  mythtv/themes/default-wide/images/mv_browse_selector.png
  39. BIN  mythtv/themes/default-wide/images/mv_itemdetail_popup.png
  40. BIN  mythtv/themes/default-wide/images/mv_results_popup.png
  41. +1,603 −0 mythtv/themes/default-wide/video-ui.xml
  42. BIN  mythtv/themes/default/images/md_progress_background.png
  43. BIN  mythtv/themes/default/images/md_rip_banner.png
  44. BIN  mythtv/themes/default/images/mv_browse_background.png
  45. BIN  mythtv/themes/default/images/mv_browse_selector.png
  46. BIN  mythtv/themes/default/images/mv_filerequest.png
  47. BIN  mythtv/themes/default/images/mv_itemdetail_popup.png
  48. BIN  mythtv/themes/default/images/mv_level_high.png
  49. BIN  mythtv/themes/default/images/mv_level_low.png
  50. BIN  mythtv/themes/default/images/mv_level_lowest.png
  51. BIN  mythtv/themes/default/images/mv_level_medium.png
  52. BIN  mythtv/themes/default/images/mv_level_none.png
  53. BIN  mythtv/themes/default/images/mv_results_popup.png
  54. +1,494 −0 mythtv/themes/default/video-ui.xml
  55. +1 −2  mythtv/themes/defaultmenu/library.xml
  56. +0 −1  mythtv/themes/defaultmenu/main_settings.xml
  57. +0 −1  mythtv/themes/defaultmenu/mainmenu.xml
  58. +1 −2  mythtv/themes/defaultmenu/media_settings.xml
  59. +0 −1  mythtv/themes/defaultmenu/optical_menu.xml
  60. +31 −0 mythtv/themes/defaultmenu/video_settings.xml
  61. +0 −1  mythtv/themes/mediacentermenu/advanced.xml
  62. +0 −1  mythtv/themes/mediacentermenu/main_settings.xml
  63. +1 −3 mythtv/themes/mediacentermenu/mainmenu.xml
  64. +1 −2  mythtv/themes/mediacentermenu/media_settings.xml
  65. +0 −1  mythtv/themes/mediacentermenu/optical_menu.xml
  66. +31 −0 mythtv/themes/mediacentermenu/video_settings.xml
View
2  mythtv/libs/libmythmetadata/globals.cpp
@@ -27,7 +27,7 @@ const QString JUMP_VIDEO_MANAGER = "Video Manager";
const QString JUMP_VIDEO_BROWSER = "Video Browser";
const QString JUMP_VIDEO_TREE = "Video Listings";
const QString JUMP_VIDEO_GALLERY = "Video Gallery";
-const QString JUMP_VIDEO_DEFAULT = "MythVideo";
+const QString JUMP_VIDEO_DEFAULT = "Video Default";
#ifdef Q_WS_MACX
const QString DEFAULT_VIDEOSTARTUP_DIR = QDir::homePath() + "/Movies";
View
4 mythtv/libs/libmythmetadata/metadatacommon.cpp
@@ -142,7 +142,7 @@ QList<PersonInfo> MetadataLookup::GetPeople(PeopleType type) const
return ret;
}
-ArtworkList MetadataLookup::GetArtwork(ArtworkType type) const
+ArtworkList MetadataLookup::GetArtwork(VideoArtworkType type) const
{
ArtworkList ret;
ret = m_artwork.values(type);
@@ -439,7 +439,7 @@ ArtworkMap ParseArtwork(QDomElement artwork)
if (image.hasAttribute("type"))
{
QString typestring = image.attribute("type");
- ArtworkType type;
+ VideoArtworkType type;
if (typestring.toLower() == "coverart")
type = COVERART;
else if (typestring.toLower() == "fanart")
View
10 mythtv/libs/libmythmetadata/metadatacommon.h
@@ -18,7 +18,7 @@ enum LookupStep {
GETDATA = 1
};
-enum ArtworkType {
+enum VideoArtworkType {
COVERART = 0,
FANART = 1,
BANNER = 2,
@@ -28,7 +28,7 @@ enum ArtworkType {
INSIDECOVER = 6,
CDIMAGE = 7
};
-Q_DECLARE_METATYPE(ArtworkType)
+Q_DECLARE_METATYPE(VideoArtworkType)
struct PersonInfo
{
@@ -71,9 +71,9 @@ enum PeopleType {
typedef QList< ArtworkInfo > ArtworkList;
-typedef QMultiMap< ArtworkType, ArtworkInfo > ArtworkMap;
+typedef QMultiMap< VideoArtworkType, ArtworkInfo > ArtworkMap;
-typedef QMap< ArtworkType, ArtworkInfo > DownloadMap;
+typedef QMap< VideoArtworkType, ArtworkInfo > DownloadMap;
typedef QMultiMap< PeopleType, PersonInfo > PeopleMap;
@@ -223,7 +223,7 @@ class META_PUBLIC MetadataLookup : public QObject
QString GetTrailerURL() const { return m_trailerURL; };
// Artwork
- ArtworkList GetArtwork(ArtworkType type) const;
+ ArtworkList GetArtwork(VideoArtworkType type) const;
DownloadMap GetDownloads() const { return m_downloads; };
private:
View
8 mythtv/libs/libmythmetadata/metadataimagedownload.cpp
@@ -106,7 +106,7 @@ void MetadataImageDownload::run()
for (DownloadMap::iterator i = downloads.begin();
i != downloads.end(); ++i)
{
- ArtworkType type = i.key();
+ VideoArtworkType type = i.key();
ArtworkInfo info = i.value();
QString filename = getDownloadFilename( type, lookup,
info.url );
@@ -295,7 +295,7 @@ QString getDownloadFilename(QString title, QString url)
return outputfile;
}
-QString getDownloadFilename(ArtworkType type, MetadataLookup *lookup,
+QString getDownloadFilename(VideoArtworkType type, MetadataLookup *lookup,
QString url)
{
QString basefilename;
@@ -349,7 +349,7 @@ QString getDownloadFilename(ArtworkType type, MetadataLookup *lookup,
return basefilename;
}
-QString getLocalWritePath(MetadataType metadatatype, ArtworkType type)
+QString getLocalWritePath(MetadataType metadatatype, VideoArtworkType type)
{
QString ret;
@@ -380,7 +380,7 @@ QString getLocalWritePath(MetadataType metadatatype, ArtworkType type)
return ret;
}
-QString getStorageGroupURL(ArtworkType type, QString host)
+QString getStorageGroupURL(VideoArtworkType type, QString host)
{
QString sgroup;
QString ip = gCoreContext->GetSettingOnHost("BackendServerIP", host);
View
6 mythtv/libs/libmythmetadata/metadataimagedownload.h
@@ -67,11 +67,11 @@ class META_PUBLIC MetadataImageDownload : public QThread
};
META_PUBLIC QString getDownloadFilename(QString title, QString url);
-META_PUBLIC QString getDownloadFilename(ArtworkType type, MetadataLookup *lookup,
+META_PUBLIC QString getDownloadFilename(VideoArtworkType type, MetadataLookup *lookup,
QString url);
-META_PUBLIC QString getLocalWritePath(MetadataType metadatatype, ArtworkType type);
-META_PUBLIC QString getStorageGroupURL(ArtworkType type, QString host);
+META_PUBLIC QString getLocalWritePath(MetadataType metadatatype, VideoArtworkType type);
+META_PUBLIC QString getStorageGroupURL(VideoArtworkType type, QString host);
META_PUBLIC void cleanThumbnailCacheDir(void);
View
1,231 mythtv/programs/mythfrontend/editvideometadata.cpp
@@ -0,0 +1,1231 @@
+#include <algorithm>
+
+#include <QImageReader>
+#include <QUrl>
+
+#include <mythcontext.h>
+#include <mythdirs.h>
+
+#include "mythmainwindow.h"
+#include "mythdialogbox.h"
+#include "mythuibuttonlist.h"
+#include "mythuitext.h"
+#include "mythuitextedit.h"
+#include "mythuibutton.h"
+#include "mythuicheckbox.h"
+#include "mythuispinbox.h"
+#include "mythuifilebrowser.h"
+#include "mythuihelper.h"
+#include "mythprogressdialog.h"
+#include "remoteutil.h"
+#include "globals.h"
+#include "dbaccess.h"
+#include "videometadatalistmanager.h"
+#include "videoutils.h"
+
+#include "editvideometadata.h"
+
+EditMetadataDialog::EditMetadataDialog(MythScreenStack *lparent,
+ QString lname, VideoMetadata *source_metadata,
+ const VideoMetadataListManager &cache) : MythScreenType(lparent, lname),
+ m_origMetadata(source_metadata), m_titleEdit(0), m_subtitleEdit(0),
+ m_taglineEdit(0), m_playerEdit(0), m_ratingEdit(0), m_directorEdit(0),
+ m_inetrefEdit(0), m_homepageEdit(0), m_plotEdit(0), m_seasonSpin(0),
+ m_episodeSpin(0), m_yearSpin(0), m_userRatingSpin(0), m_lengthSpin(0),
+ m_categoryList(0), m_levelList(0), m_childList(0), m_browseCheck(0),
+ m_watchedCheck(0), m_coverartButton(0), m_coverartText(0),
+ m_screenshotButton(0), m_screenshotText(0), m_bannerButton(0),
+ m_bannerText(0), m_fanartButton(0), m_fanartText(0),
+ m_trailerButton(0), m_trailerText(0),
+ m_netCoverartButton(0), m_netFanartButton(0), m_netBannerButton(0),
+ m_netScreenshotButton(0), m_coverart(0), m_screenshot(0),
+ m_banner(0), m_fanart(0),
+ m_doneButton(0),
+ cachedChildSelection(0),
+ m_metaCache(cache), m_busyPopup(0)
+{
+ m_query = new MetadataDownload(this);
+ m_imageDownload = new MetadataImageDownload(this);
+ m_workingMetadata = new VideoMetadata(*m_origMetadata);
+
+ m_popupStack = GetMythMainWindow()->GetStack("popup stack");
+}
+
+EditMetadataDialog::~EditMetadataDialog()
+{
+ delete m_workingMetadata;
+}
+
+bool EditMetadataDialog::Create()
+{
+ if (!LoadWindowFromXML("video-ui.xml", "edit_metadata", this))
+ return false;
+
+ bool err = false;
+ UIUtilE::Assign(this, m_titleEdit, "title_edit", &err);
+ UIUtilE::Assign(this, m_subtitleEdit, "subtitle_edit", &err);
+ UIUtilE::Assign(this, m_playerEdit, "player_edit", &err);
+
+ UIUtilE::Assign(this, m_seasonSpin, "season", &err);
+ UIUtilE::Assign(this, m_episodeSpin, "episode", &err);
+
+ UIUtilE::Assign(this, m_coverartText, "coverart_text", &err);
+ UIUtilE::Assign(this, m_screenshotText, "screenshot_text", &err);
+ UIUtilE::Assign(this, m_bannerText, "banner_text", &err);
+ UIUtilE::Assign(this, m_fanartText, "fanart_text", &err);
+ UIUtilE::Assign(this, m_trailerText, "trailer_text", &err);
+
+ UIUtilE::Assign(this, m_categoryList, "category_select", &err);
+ UIUtilE::Assign(this, m_levelList, "level_select", &err);
+ UIUtilE::Assign(this, m_childList, "child_select", &err);
+
+ UIUtilE::Assign(this, m_browseCheck, "browse_check", &err);
+ UIUtilE::Assign(this, m_watchedCheck, "watched_check", &err);
+
+ UIUtilE::Assign(this, m_coverartButton, "coverart_button", &err);
+ UIUtilE::Assign(this, m_bannerButton, "banner_button", &err);
+ UIUtilE::Assign(this, m_fanartButton, "fanart_button", &err);
+ UIUtilE::Assign(this, m_screenshotButton, "screenshot_button", &err);
+ UIUtilE::Assign(this, m_trailerButton, "trailer_button", &err);
+ UIUtilE::Assign(this, m_doneButton, "done_button", &err);
+
+ if (err)
+ {
+ VERBOSE(VB_IMPORTANT, "Cannot load screen 'edit_metadata'");
+ return false;
+ }
+
+ UIUtilW::Assign(this, m_netBannerButton, "net_banner_button");
+ UIUtilW::Assign(this, m_netFanartButton, "net_fanart_button");
+ UIUtilW::Assign(this, m_netScreenshotButton, "net_screenshot_button");
+ UIUtilW::Assign(this, m_netCoverartButton, "net_coverart_button");
+
+ UIUtilW::Assign(this, m_taglineEdit, "tagline_edit");
+ UIUtilW::Assign(this, m_ratingEdit, "rating_edit");
+ UIUtilW::Assign(this, m_directorEdit, "director_edit");
+ UIUtilW::Assign(this, m_inetrefEdit, "inetref_edit");
+ UIUtilW::Assign(this, m_homepageEdit, "homepage_edit");
+ UIUtilW::Assign(this, m_plotEdit, "description_edit");
+ UIUtilW::Assign(this, m_yearSpin, "year_spin");
+ UIUtilW::Assign(this, m_userRatingSpin, "userrating_spin");
+ UIUtilW::Assign(this, m_lengthSpin, "length_spin");
+
+ UIUtilW::Assign(this, m_coverart, "coverart");
+ UIUtilW::Assign(this, m_screenshot, "screenshot");
+ UIUtilW::Assign(this, m_banner, "banner");
+ UIUtilW::Assign(this, m_fanart, "fanart");
+
+ fillWidgets();
+
+ BuildFocusList();
+
+ connect(m_titleEdit, SIGNAL(valueChanged()), SLOT(SetTitle()));
+ m_titleEdit->SetMaxLength(128);
+ connect(m_subtitleEdit, SIGNAL(valueChanged()), SLOT(SetSubtitle()));
+ m_subtitleEdit->SetMaxLength(0);
+ connect(m_playerEdit, SIGNAL(valueChanged()), SLOT(SetPlayer()));
+ if (m_taglineEdit)
+ {
+ connect(m_taglineEdit, SIGNAL(valueChanged()), SLOT(SetTagline()));
+ m_taglineEdit->SetMaxLength(255);
+ }
+ if (m_ratingEdit)
+ {
+ connect(m_ratingEdit, SIGNAL(valueChanged()), SLOT(SetRating()));
+ m_ratingEdit->SetMaxLength(128);
+ }
+ if (m_directorEdit)
+ {
+ connect(m_directorEdit, SIGNAL(valueChanged()), SLOT(SetDirector()));
+ m_directorEdit->SetMaxLength(128);
+ }
+ if (m_inetrefEdit)
+ connect(m_inetrefEdit, SIGNAL(valueChanged()), SLOT(SetInetRef()));
+ if (m_homepageEdit)
+ {
+ connect(m_homepageEdit, SIGNAL(valueChanged()), SLOT(SetHomepage()));
+ m_homepageEdit->SetMaxLength(0);
+ }
+ if (m_plotEdit)
+ {
+ connect(m_plotEdit, SIGNAL(valueChanged()), SLOT(SetPlot()));
+ m_plotEdit->SetMaxLength(0);
+ }
+
+ connect(m_seasonSpin, SIGNAL(LosingFocus()), SLOT(SetSeason()));
+ connect(m_episodeSpin, SIGNAL(LosingFocus()), SLOT(SetEpisode()));
+ if (m_yearSpin)
+ connect(m_yearSpin, SIGNAL(LosingFocus()), SLOT(SetYear()));
+ if (m_userRatingSpin)
+ connect(m_userRatingSpin, SIGNAL(LosingFocus()), SLOT(SetUserRating()));
+ if (m_lengthSpin)
+ connect(m_lengthSpin, SIGNAL(LosingFocus()), SLOT(SetLength()));
+
+ connect(m_doneButton, SIGNAL(Clicked()), SLOT(SaveAndExit()));
+
+ // Find Artwork locally
+ connect(m_coverartButton, SIGNAL(Clicked()), SLOT(FindCoverArt()));
+ connect(m_bannerButton, SIGNAL(Clicked()), SLOT(FindBanner()));
+ connect(m_fanartButton, SIGNAL(Clicked()), SLOT(FindFanart()));
+ connect(m_screenshotButton, SIGNAL(Clicked()), SLOT(FindScreenshot()));
+
+ // Find Artwork on the Internet
+ if (m_netCoverartButton)
+ connect(m_netCoverartButton, SIGNAL(Clicked()), SLOT(FindNetCoverArt()));
+ if (m_netBannerButton)
+ connect(m_netBannerButton, SIGNAL(Clicked()), SLOT(FindNetBanner()));
+ if (m_netFanartButton)
+ connect(m_netFanartButton, SIGNAL(Clicked()), SLOT(FindNetFanart()));
+ if (m_netScreenshotButton)
+ connect(m_netScreenshotButton, SIGNAL(Clicked()), SLOT(FindNetScreenshot()));
+
+ connect(m_trailerButton, SIGNAL(Clicked()), SLOT(FindTrailer()));
+
+ connect(m_browseCheck, SIGNAL(valueChanged()), SLOT(ToggleBrowse()));
+ connect(m_watchedCheck, SIGNAL(valueChanged()), SLOT(ToggleWatched()));
+
+ connect(m_childList, SIGNAL(itemSelected(MythUIButtonListItem*)),
+ SLOT(SetChild(MythUIButtonListItem*)));
+ connect(m_levelList, SIGNAL(itemSelected(MythUIButtonListItem*)),
+ SLOT(SetLevel(MythUIButtonListItem*)));
+ connect(m_categoryList, SIGNAL(itemSelected(MythUIButtonListItem*)),
+ SLOT(SetCategory(MythUIButtonListItem*)));
+ connect(m_categoryList, SIGNAL(itemClicked(MythUIButtonListItem*)),
+ SLOT(NewCategoryPopup()));
+
+ return true;
+}
+
+namespace
+{
+ template <typename T>
+ struct title_sort
+ {
+ bool operator()(const T &lhs, const T &rhs)
+ {
+ return QString::localeAwareCompare(lhs.second, rhs.second) < 0;
+ }
+ };
+
+ QStringList GetSupportedImageExtensionFilter()
+ {
+ QStringList ret;
+
+ QList<QByteArray> exts = QImageReader::supportedImageFormats();
+ for (QList<QByteArray>::iterator p = exts.begin(); p != exts.end(); ++p)
+ {
+ ret.append(QString("*.").append(*p));
+ }
+
+ return ret;
+ }
+
+ void FindImagePopup(const QString &prefix, const QString &prefixAlt,
+ QObject &inst, const QString &returnEvent)
+ {
+ QString fp;
+
+ if (prefix.startsWith("myth://"))
+ fp = prefix;
+ else
+ fp = prefix.isEmpty() ? prefixAlt : prefix;
+
+ MythScreenStack *popupStack =
+ GetMythMainWindow()->GetStack("popup stack");
+
+ MythUIFileBrowser *fb = new MythUIFileBrowser(popupStack, fp);
+ fb->SetNameFilter(GetSupportedImageExtensionFilter());
+ if (fb->Create())
+ {
+ fb->SetReturnEvent(&inst, returnEvent);
+ popupStack->AddScreen(fb);
+ }
+ else
+ delete fb;
+ }
+
+ void FindVideoFilePopup(const QString &prefix, const QString &prefixAlt,
+ QObject &inst, const QString &returnEvent)
+ {
+ QString fp;
+
+ if (prefix.startsWith("myth://"))
+ fp = prefix;
+ else
+ fp = prefix.isEmpty() ? prefixAlt : prefix;
+
+ MythScreenStack *popupStack =
+ GetMythMainWindow()->GetStack("popup stack");
+ QStringList exts;
+
+ const FileAssociations::association_list fa_list =
+ FileAssociations::getFileAssociation().getList();
+ for (FileAssociations::association_list::const_iterator p =
+ fa_list.begin(); p != fa_list.end(); ++p)
+ {
+ exts << QString("*.%1").arg(p->extension.toUpper());
+ }
+
+ MythUIFileBrowser *fb = new MythUIFileBrowser(popupStack, fp);
+ fb->SetNameFilter(exts);
+ if (fb->Create())
+ {
+ fb->SetReturnEvent(&inst, returnEvent);
+ popupStack->AddScreen(fb);
+ }
+ else
+ delete fb;
+ }
+
+ const QString CEID_COVERARTFILE = "coverartfile";
+ const QString CEID_BANNERFILE = "bannerfile";
+ const QString CEID_FANARTFILE = "fanartfile";
+ const QString CEID_SCREENSHOTFILE = "screenshotfile";
+ const QString CEID_TRAILERFILE = "trailerfile";
+ const QString CEID_NEWCATEGORY = "newcategory";
+
+ class ImageSearchResultsDialog : public MythScreenType
+ {
+ Q_OBJECT
+
+ public:
+ ImageSearchResultsDialog(MythScreenStack *lparent,
+ const ArtworkList list, const VideoArtworkType type) :
+ MythScreenType(lparent, "videosearchresultspopup"),
+ m_list(list), m_type(type), m_resultsList(0)
+ {
+ m_imageDownload = new MetadataImageDownload(this);
+ }
+
+ ~ImageSearchResultsDialog()
+ {
+ cleanCacheDir();
+
+ if (m_imageDownload)
+ {
+ delete m_imageDownload;
+ m_imageDownload = NULL;
+ }
+ }
+
+ bool Create()
+ {
+ if (!LoadWindowFromXML("video-ui.xml", "artworksel", this))
+ return false;
+
+ bool err = false;
+ UIUtilE::Assign(this, m_resultsList, "results", &err);
+ if (err)
+ {
+ VERBOSE(VB_IMPORTANT, "Cannot load screen 'moviesel'");
+ return false;
+ }
+
+ for (ArtworkList::const_iterator i = m_list.begin();
+ i != m_list.end(); ++i)
+ {
+ ArtworkInfo info = (*i);
+ MythUIButtonListItem *button =
+ new MythUIButtonListItem(m_resultsList,
+ QString());
+ button->SetText(info.label, "label");
+ button->SetText(info.thumbnail, "thumbnail");
+ button->SetText(info.url, "url");
+ QString width = QString::number(info.width);
+ QString height = QString::number(info.height);
+ button->SetText(width, "width");
+ button->SetText(height, "height");
+ if (info.width > 0 && info.height > 0)
+ button->SetText(QString("%1x%2").arg(width).arg(height),
+ "resolution");
+
+ QString artfile = info.thumbnail;
+
+ if (artfile.isEmpty())
+ artfile = info.url;
+
+ QString dlfile = getDownloadFilename(info.label,
+ artfile);
+
+ if (!artfile.isEmpty())
+ {
+ int pos = m_resultsList->GetItemPos(button);
+
+ if (QFile::exists(dlfile))
+ button->SetImage(dlfile);
+ else
+ m_imageDownload->addThumb(info.label,
+ artfile,
+ qVariantFromValue<uint>(pos));
+ }
+
+ button->SetData(qVariantFromValue<ArtworkInfo>(*i));
+ }
+
+ connect(m_resultsList, SIGNAL(itemClicked(MythUIButtonListItem *)),
+ SLOT(sendResult(MythUIButtonListItem *)));
+
+ BuildFocusList();
+
+ return true;
+ }
+
+ void cleanCacheDir()
+ {
+ QString cache = QString("%1/thumbcache")
+ .arg(GetConfDir());
+ QDir cacheDir(cache);
+ QStringList thumbs = cacheDir.entryList(QDir::Files);
+
+ for (QStringList::const_iterator i = thumbs.end() - 1;
+ i != thumbs.begin() - 1; --i)
+ {
+ QString filename = QString("%1/%2").arg(cache).arg(*i);
+ QFileInfo fi(filename);
+ QDateTime lastmod = fi.lastModified();
+ if (lastmod.addDays(2) < QDateTime::currentDateTime())
+ {
+ VERBOSE(VB_GENERAL|VB_EXTRA, QString("Deleting file %1")
+ .arg(filename));
+ QFile::remove(filename);
+ }
+ }
+ }
+
+ void customEvent(QEvent *event)
+ {
+ if (event->type() == ThumbnailDLEvent::kEventType)
+ {
+ ThumbnailDLEvent *tde = (ThumbnailDLEvent *)event;
+
+ ThumbnailData *data = tde->thumb;
+
+ QString file = data->url;
+ uint pos = qVariantValue<uint>(data->data);
+
+ if (file.isEmpty())
+ return;
+
+ if (!((uint)m_resultsList->GetCount() >= pos))
+ return;
+
+ MythUIButtonListItem *item =
+ m_resultsList->GetItemAt(pos);
+
+ if (item)
+ {
+ item->SetImage(file);
+ }
+ delete data;
+ }
+ }
+
+ signals:
+ void haveResult(ArtworkInfo, VideoArtworkType);
+
+ private:
+ ArtworkList m_list;
+ VideoArtworkType m_type;
+ MythUIButtonList *m_resultsList;
+ MetadataImageDownload *m_imageDownload;
+
+ private slots:
+ void sendResult(MythUIButtonListItem* item)
+ {
+ emit haveResult(qVariantValue<ArtworkInfo>(item->GetData()),
+ m_type);
+ Close();
+ }
+ };
+}
+
+void EditMetadataDialog::createBusyDialog(QString title)
+{
+ if (m_busyPopup)
+ return;
+
+ QString message = title;
+
+ m_busyPopup = new MythUIBusyDialog(message, m_popupStack,
+ "mythvideobusydialog");
+
+ if (m_busyPopup->Create())
+ m_popupStack->AddScreen(m_busyPopup);
+}
+
+void EditMetadataDialog::fillWidgets()
+{
+ m_titleEdit->SetText(m_workingMetadata->GetTitle());
+ m_subtitleEdit->SetText(m_workingMetadata->GetSubtitle());
+
+ m_seasonSpin->SetRange(0,9999,1);
+ m_seasonSpin->SetValue(m_workingMetadata->GetSeason());
+ m_episodeSpin->SetRange(0,999,1);
+ m_episodeSpin->SetValue(m_workingMetadata->GetEpisode());
+ if (m_yearSpin)
+ {
+ m_yearSpin->SetRange(0,9999,1);
+ m_yearSpin->SetValue(m_workingMetadata->GetYear());
+ }
+ if (m_userRatingSpin)
+ {
+ m_userRatingSpin->SetRange(0,10,1);
+ m_userRatingSpin->SetValue(m_workingMetadata->GetUserRating());
+ }
+ if (m_lengthSpin)
+ {
+ m_lengthSpin->SetRange(0,999,1);
+ m_lengthSpin->SetValue(m_workingMetadata->GetLength());
+ }
+
+ MythUIButtonListItem *button =
+ new MythUIButtonListItem(m_categoryList, VIDEO_CATEGORY_UNKNOWN);
+ const VideoCategory::entry_list &vcl =
+ VideoCategory::GetCategory().getList();
+ for (VideoCategory::entry_list::const_iterator p = vcl.begin();
+ p != vcl.end(); ++p)
+ {
+ button = new MythUIButtonListItem(m_categoryList, p->second);
+ button->SetData(p->first);
+ }
+ m_categoryList->SetValueByData(m_workingMetadata->GetCategoryID());
+
+ for (ParentalLevel i = ParentalLevel::plLowest;
+ i <= ParentalLevel::plHigh && i.good(); ++i)
+ {
+ button = new MythUIButtonListItem(m_levelList,
+ QString(tr("Level %1")).arg(i.GetLevel()));
+ button->SetData(i.GetLevel());
+ }
+ m_levelList->SetValueByData(m_workingMetadata->GetShowLevel());
+
+ //
+ // Fill the "always play this video next" option
+ // with all available videos.
+ //
+
+ bool trip_catch = false;
+ QString caught_name = "";
+ int possible_starting_point = 0;
+
+ button = new MythUIButtonListItem(m_childList,tr("None"));
+
+ // TODO: maybe make the title list have the same sort order
+ // as elsewhere.
+ typedef std::vector<std::pair<unsigned int, QString> > title_list;
+ const VideoMetadataListManager::metadata_list &mdl = m_metaCache.getList();
+ title_list tc;
+ tc.reserve(mdl.size());
+ for (VideoMetadataListManager::metadata_list::const_iterator p = mdl.begin();
+ p != mdl.end(); ++p)
+ {
+ tc.push_back(std::make_pair((*p)->GetID(), (*p)->GetTitle()));
+ }
+ std::sort(tc.begin(), tc.end(), title_sort<title_list::value_type>());
+
+ for (title_list::const_iterator p = tc.begin(); p != tc.end(); ++p)
+ {
+ if (trip_catch)
+ {
+ //
+ // Previous loop told us to check if the two
+ // movie names are close enough to try and
+ // set a default starting point.
+ //
+
+ QString target_name = p->second;
+ int length_compare = 0;
+ if (target_name.length() < caught_name.length())
+ {
+ length_compare = target_name.length();
+ }
+ else
+ {
+ length_compare = caught_name.length();
+ }
+
+ QString caught_name_three_quarters =
+ caught_name.left((int)(length_compare * 0.75));
+ QString target_name_three_quarters =
+ target_name.left((int)(length_compare * 0.75));
+
+ if (caught_name_three_quarters == target_name_three_quarters &&
+ m_workingMetadata->GetChildID() == -1 &&
+ !(m_workingMetadata->GetSeason() > 0) &&
+ !(m_workingMetadata->GetEpisode() > 0))
+ {
+ possible_starting_point = p->first;
+ m_workingMetadata->SetChildID(possible_starting_point);
+ }
+ trip_catch = false;
+ }
+
+ if (p->first != m_workingMetadata->GetID())
+ {
+ button = new MythUIButtonListItem(m_childList,p->second);
+ button->SetData(p->first);
+ }
+ else
+ {
+ //
+ // This is the current file. Set a flag so the default
+ // selected child will be set next loop
+ //
+
+ trip_catch = true;
+ caught_name = p->second;
+ }
+ }
+
+ if (m_workingMetadata->GetChildID() > 0)
+ {
+ m_childList->SetValueByData(m_workingMetadata->GetChildID());
+ cachedChildSelection = m_workingMetadata->GetChildID();
+ }
+ else
+ {
+ m_childList->SetValueByData(possible_starting_point);
+ cachedChildSelection = possible_starting_point;
+ }
+
+ if (m_workingMetadata->GetBrowse())
+ m_browseCheck->SetCheckState(MythUIStateType::Full);
+ if (m_workingMetadata->GetWatched())
+ m_watchedCheck->SetCheckState(MythUIStateType::Full);
+ m_coverartText->SetText(m_workingMetadata->GetCoverFile());
+ m_screenshotText->SetText(m_workingMetadata->GetScreenshot());
+ m_bannerText->SetText(m_workingMetadata->GetBanner());
+ m_fanartText->SetText(m_workingMetadata->GetFanart());
+ m_trailerText->SetText(m_workingMetadata->GetTrailer());
+ m_playerEdit->SetText(m_workingMetadata->GetPlayCommand());
+ if (m_taglineEdit)
+ m_taglineEdit->SetText(m_workingMetadata->GetTagline());
+ if (m_ratingEdit)
+ m_ratingEdit->SetText(m_workingMetadata->GetRating());
+ if (m_directorEdit)
+ m_directorEdit->SetText(m_workingMetadata->GetDirector());
+ if (m_inetrefEdit)
+ m_inetrefEdit->SetText(m_workingMetadata->GetInetRef());
+ if (m_homepageEdit)
+ m_homepageEdit->SetText(m_workingMetadata->GetHomepage());
+ if (m_plotEdit)
+ m_plotEdit->SetText(m_workingMetadata->GetPlot());
+
+ if (m_coverart)
+ {
+ if (!m_workingMetadata->GetHost().isEmpty() &&
+ !m_workingMetadata->GetCoverFile().isEmpty() &&
+ !m_workingMetadata->GetCoverFile().startsWith("/"))
+ {
+ m_coverart->SetFilename(generate_file_url("Coverart",
+ m_workingMetadata->GetHost(),
+ m_workingMetadata->GetCoverFile()));
+ }
+ else
+ m_coverart->SetFilename(m_workingMetadata->GetCoverFile());
+
+ if (!m_workingMetadata->GetCoverFile().isEmpty())
+ m_coverart->Load();
+ }
+ if (m_screenshot)
+ {
+ if (!m_workingMetadata->GetHost().isEmpty() &&
+ !m_workingMetadata->GetScreenshot().isEmpty() &&
+ !m_workingMetadata->GetScreenshot().startsWith("/"))
+ {
+ m_screenshot->SetFilename(generate_file_url("Screenshots",
+ m_workingMetadata->GetHost(),
+ m_workingMetadata->GetScreenshot()));
+ }
+ else
+ m_screenshot->SetFilename(m_workingMetadata->GetScreenshot());
+
+ if (!m_workingMetadata->GetScreenshot().isEmpty())
+ m_screenshot->Load();
+ }
+ if (m_banner)
+ {
+ if (!m_workingMetadata->GetHost().isEmpty() &&
+ !m_workingMetadata->GetBanner().isEmpty() &&
+ !m_workingMetadata->GetBanner().startsWith("/"))
+ {
+ m_banner->SetFilename(generate_file_url("Banners",
+ m_workingMetadata->GetHost(),
+ m_workingMetadata->GetBanner()));
+ }
+ else
+ m_banner->SetFilename(m_workingMetadata->GetBanner());
+
+ if (!m_workingMetadata->GetBanner().isEmpty())
+ m_banner->Load();
+ }
+ if (m_fanart)
+ {
+ if (!m_workingMetadata->GetHost().isEmpty() &&
+ !m_workingMetadata->GetFanart().isEmpty() &&
+ !m_workingMetadata->GetFanart().startsWith("/"))
+ {
+ m_fanart->SetFilename(generate_file_url("Fanart",
+ m_workingMetadata->GetHost(),
+ m_workingMetadata->GetFanart()));
+ }
+ else
+ m_fanart->SetFilename(m_workingMetadata->GetFanart());
+
+ if (!m_workingMetadata->GetFanart().isEmpty())
+ m_fanart->Load();
+ }
+}
+
+void EditMetadataDialog::NewCategoryPopup()
+{
+ QString message = tr("Enter new category");
+
+ MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
+
+ MythTextInputDialog *categorydialog =
+ new MythTextInputDialog(popupStack,message);
+
+ if (categorydialog->Create())
+ {
+ categorydialog->SetReturnEvent(this, CEID_NEWCATEGORY);
+ popupStack->AddScreen(categorydialog);
+ }
+
+}
+
+void EditMetadataDialog::AddCategory(QString category)
+{
+ int id = VideoCategory::GetCategory().add(category);
+ m_workingMetadata->SetCategoryID(id);
+ new MythUIButtonListItem(m_categoryList, category, id);
+ m_categoryList->SetValueByData(id);
+}
+
+void EditMetadataDialog::SaveAndExit()
+{
+ *m_origMetadata = *m_workingMetadata;
+ m_origMetadata->UpdateDatabase();
+
+ emit Finished();
+ Close();
+}
+
+void EditMetadataDialog::SetTitle()
+{
+ m_workingMetadata->SetTitle(m_titleEdit->GetText());
+}
+
+void EditMetadataDialog::SetSubtitle()
+{
+ m_workingMetadata->SetSubtitle(m_subtitleEdit->GetText());
+}
+
+void EditMetadataDialog::SetCategory(MythUIButtonListItem *item)
+{
+ m_workingMetadata->SetCategoryID(item->GetData().toInt());
+}
+
+void EditMetadataDialog::SetRating()
+{
+ m_workingMetadata->SetRating(m_ratingEdit->GetText());
+}
+
+void EditMetadataDialog::SetTagline()
+{
+ m_workingMetadata->SetTagline(m_taglineEdit->GetText());
+}
+
+void EditMetadataDialog::SetDirector()
+{
+ m_workingMetadata->SetDirector(m_directorEdit->GetText());
+}
+
+void EditMetadataDialog::SetInetRef()
+{
+ m_workingMetadata->SetInetRef(m_inetrefEdit->GetText());
+}
+
+void EditMetadataDialog::SetHomepage()
+{
+ m_workingMetadata->SetHomepage(m_homepageEdit->GetText());
+}
+
+void EditMetadataDialog::SetPlot()
+{
+ m_workingMetadata->SetPlot(m_plotEdit->GetText());
+}
+
+void EditMetadataDialog::SetSeason()
+{
+ m_workingMetadata->SetSeason(m_seasonSpin->GetIntValue());
+}
+
+void EditMetadataDialog::SetEpisode()
+{
+ m_workingMetadata->SetEpisode(m_episodeSpin->GetIntValue());
+}
+
+void EditMetadataDialog::SetYear()
+{
+ m_workingMetadata->SetYear(m_yearSpin->GetIntValue());
+}
+
+void EditMetadataDialog::SetUserRating()
+{
+ m_workingMetadata->SetUserRating(m_userRatingSpin->GetIntValue());
+}
+
+void EditMetadataDialog::SetLength()
+{
+ m_workingMetadata->SetLength(m_lengthSpin->GetIntValue());
+}
+
+void EditMetadataDialog::SetPlayer()
+{
+ m_workingMetadata->SetPlayCommand(m_playerEdit->GetText());
+}
+
+void EditMetadataDialog::SetLevel(MythUIButtonListItem *item)
+{
+ m_workingMetadata->
+ SetShowLevel(ParentalLevel(item->GetData().toInt()).GetLevel());
+}
+
+void EditMetadataDialog::SetChild(MythUIButtonListItem *item)
+{
+ cachedChildSelection = item->GetData().toInt();
+ m_workingMetadata->SetChildID(cachedChildSelection);
+}
+
+void EditMetadataDialog::ToggleBrowse()
+{
+ m_workingMetadata->
+ SetBrowse(m_browseCheck->GetBooleanCheckState());
+}
+
+void EditMetadataDialog::ToggleWatched()
+{
+ m_workingMetadata->
+ SetWatched(m_watchedCheck->GetBooleanCheckState());
+}
+
+void EditMetadataDialog::FindCoverArt()
+{
+ if (!m_workingMetadata->GetHost().isEmpty())
+ {
+ QString url = generate_file_url("Coverart",
+ m_workingMetadata->GetHost(),
+ "");
+ FindImagePopup(url,"",
+ *this, CEID_COVERARTFILE);
+ }
+ else
+ FindImagePopup(gCoreContext->GetSetting("VideoArtworkDir"),
+ GetConfDir() + "/MythVideo",
+ *this, CEID_COVERARTFILE);
+}
+
+void EditMetadataDialog::OnArtworkSearchDone(MetadataLookup *lookup)
+{
+ if (!lookup)
+ return;
+
+ if (m_busyPopup)
+ {
+ m_busyPopup->Close();
+ m_busyPopup = NULL;
+ }
+
+ VideoArtworkType type = qVariantValue<VideoArtworkType>(lookup->GetData());
+ ArtworkList list = lookup->GetArtwork(type);
+
+ if (list.count() == 0)
+ return;
+
+ MythScreenStack *m_popupStack =
+ GetMythMainWindow()->GetStack("popup stack");
+
+ ImageSearchResultsDialog *resultsdialog =
+ new ImageSearchResultsDialog(m_popupStack, list, type);
+
+ connect(resultsdialog, SIGNAL(haveResult(ArtworkInfo, VideoArtworkType)),
+ SLOT(OnSearchListSelection(ArtworkInfo, VideoArtworkType)));
+
+ if (resultsdialog->Create())
+ m_popupStack->AddScreen(resultsdialog);
+}
+
+void EditMetadataDialog::OnSearchListSelection(ArtworkInfo info, VideoArtworkType type)
+{
+ QString msg = tr("Downloading selected artwork...");
+ createBusyDialog(msg);
+
+ MetadataLookup *lookup = new MetadataLookup();
+ lookup->SetType(VID);
+ lookup->SetHost(m_workingMetadata->GetHost());
+ lookup->SetAutomatic(true);
+ lookup->SetData(qVariantFromValue<VideoArtworkType>(type));
+
+ ArtworkMap downloads;
+ downloads.insert(type, info);
+ lookup->SetDownloads(downloads);
+ lookup->SetAllowOverwrites(true);
+ lookup->SetTitle(m_workingMetadata->GetTitle());
+ lookup->SetSubtitle(m_workingMetadata->GetSubtitle());
+ lookup->SetSeason(m_workingMetadata->GetSeason());
+ lookup->SetEpisode(m_workingMetadata->GetEpisode());
+ lookup->SetInetref(m_workingMetadata->GetInetRef());
+
+ m_imageDownload->addDownloads(lookup);
+}
+
+void EditMetadataDialog::handleDownloadedImages(MetadataLookup *lookup)
+{
+ if (!lookup)
+ return;
+
+ if (m_busyPopup)
+ {
+ m_busyPopup->Close();
+ m_busyPopup = NULL;
+ }
+
+ VideoArtworkType type = qVariantValue<VideoArtworkType>(lookup->GetData());
+ ArtworkMap map = lookup->GetDownloads();
+
+ if (map.count() >= 1)
+ {
+ ArtworkInfo info = map.value(type);
+ QString filename = info.url;
+
+ if (type == COVERART)
+ SetCoverArt(filename);
+ else if (type == FANART)
+ SetFanart(filename);
+ else if (type == BANNER)
+ SetBanner(filename);
+ else if (type == SCREENSHOT)
+ SetScreenshot(filename);
+ }
+}
+
+void EditMetadataDialog::FindNetArt(VideoArtworkType type)
+{
+ QString msg = tr("Searching for available artwork...");
+ createBusyDialog(msg);
+
+ MetadataLookup *lookup = new MetadataLookup();
+ lookup->SetStep(SEARCH);
+ lookup->SetType(VID);
+ lookup->SetAutomatic(true);
+ lookup->SetData(qVariantFromValue<VideoArtworkType>(type));
+
+ lookup->SetTitle(m_workingMetadata->GetTitle());
+ lookup->SetSubtitle(m_workingMetadata->GetSubtitle());
+ lookup->SetSeason(m_workingMetadata->GetSeason());
+ lookup->SetEpisode(m_workingMetadata->GetEpisode());
+ lookup->SetInetref(m_workingMetadata->GetInetRef());
+
+ m_query->addLookup(lookup);
+}
+
+void EditMetadataDialog::FindNetCoverArt()
+{
+ FindNetArt(COVERART);
+}
+
+void EditMetadataDialog::FindNetFanart()
+{
+ FindNetArt(FANART);
+}
+
+void EditMetadataDialog::FindNetBanner()
+{
+ FindNetArt(BANNER);
+}
+
+void EditMetadataDialog::FindNetScreenshot()
+{
+ FindNetArt(SCREENSHOT);
+}
+
+void EditMetadataDialog::SetCoverArt(QString file)
+{
+ if (file.isEmpty())
+ return;
+
+ QString origfile = file;
+
+ if (file.startsWith("myth://"))
+ {
+ QUrl url(file);
+ file = url.path();
+ file = file.right(file.length() - 1);
+ if (!file.endsWith("/"))
+ m_workingMetadata->SetCoverFile(file);
+ else
+ m_workingMetadata->SetCoverFile(QString());
+ }
+ else
+ m_workingMetadata->SetCoverFile(file);
+
+ CheckedSet(m_coverartText, file);
+
+ if (m_coverart)
+ {
+ m_coverart->SetFilename(origfile);
+ m_coverart->Load();
+ }
+}
+
+void EditMetadataDialog::FindBanner()
+{
+ if (!m_workingMetadata->GetHost().isEmpty())
+ {
+ QString url = generate_file_url("Banners",
+ m_workingMetadata->GetHost(),
+ "");
+ FindImagePopup(url,"",
+ *this, CEID_BANNERFILE);
+ }
+ else
+ FindImagePopup(gCoreContext->GetSetting("mythvideo.bannerDir"),
+ GetConfDir() + "/MythVideo/Banners",
+ *this, CEID_BANNERFILE);
+}
+
+void EditMetadataDialog::SetBanner(QString file)
+{
+ if (file.isEmpty())
+ return;
+
+ QString origfile = file;
+
+ if (file.startsWith("myth://"))
+ {
+ QUrl url(file);
+ file = url.path();
+ file = file.right(file.length() - 1);
+ if (!file.endsWith("/"))
+ m_workingMetadata->SetBanner(file);
+ else
+ m_workingMetadata->SetBanner(QString());
+ }
+ else
+ m_workingMetadata->SetBanner(file);
+
+ CheckedSet(m_bannerText, file);
+
+ if (m_banner)
+ {
+ m_banner->SetFilename(origfile);
+ m_banner->Load();
+ }
+}
+
+void EditMetadataDialog::FindFanart()
+{
+ if (!m_workingMetadata->GetHost().isEmpty())
+ {
+ QString url = generate_file_url("Fanart",
+ m_workingMetadata->GetHost(),
+ "");
+ FindImagePopup(url,"",
+ *this, CEID_FANARTFILE);
+ }
+ else
+ FindImagePopup(gCoreContext->GetSetting("mythvideo.fanartDir"),
+ GetConfDir() + "/MythVideo/Fanart",
+ *this, CEID_FANARTFILE);
+}
+
+void EditMetadataDialog::SetFanart(QString file)
+{
+ if (file.isEmpty())
+ return;
+
+ QString origfile = file;
+
+ if (file.startsWith("myth://"))
+ {
+ QUrl url(file);
+ file = url.path();
+ file = file.right(file.length() - 1);
+ if (!file.endsWith("/"))
+ m_workingMetadata->SetFanart(file);
+ else
+ m_workingMetadata->SetFanart(QString());
+ }
+ else
+ m_workingMetadata->SetFanart(file);
+
+ CheckedSet(m_fanartText, file);
+
+ if (m_fanart)
+ {
+ m_fanart->SetFilename(origfile);
+ m_fanart->Load();
+ }
+}
+
+void EditMetadataDialog::FindScreenshot()
+{
+ if (!m_workingMetadata->GetHost().isEmpty())
+ {
+ QString url = generate_file_url("Screenshots",
+ m_workingMetadata->GetHost(),
+ "");
+ FindImagePopup(url,"",
+ *this, CEID_SCREENSHOTFILE);
+ }
+ else
+ FindImagePopup(gCoreContext->GetSetting("mythvideo.screenshotDir"),
+ GetConfDir() + "/MythVideo/Screenshots",
+ *this, CEID_SCREENSHOTFILE);
+}
+
+void EditMetadataDialog::SetScreenshot(QString file)
+{
+ if (file.isEmpty())
+ return;
+
+ QString origfile = file;
+
+ if (file.startsWith("myth://"))
+ {
+ QUrl url(file);
+ file = url.path();
+ file = file.right(file.length() - 1);
+ if (!file.endsWith("/"))
+ m_workingMetadata->SetScreenshot(file);
+ else
+ m_workingMetadata->SetScreenshot(QString());
+ }
+ else
+ m_workingMetadata->SetScreenshot(file);
+
+ CheckedSet(m_screenshotText, file);
+
+ if (m_screenshot)
+ {
+ m_screenshot->SetFilename(origfile);
+ m_screenshot->Load();
+ }
+}
+
+void EditMetadataDialog::FindTrailer()
+{
+ if (!m_workingMetadata->GetHost().isEmpty())
+ {
+ QString url = generate_file_url("Trailers",
+ m_workingMetadata->GetHost(),
+ "");
+ FindVideoFilePopup(url,"",
+ *this, CEID_TRAILERFILE);
+ }
+ else
+ FindVideoFilePopup(gCoreContext->GetSetting("mythvideo.TrailersDir"),
+ GetConfDir() + "/MythVideo/Trailers",
+ *this, CEID_TRAILERFILE);
+}
+
+void EditMetadataDialog::SetTrailer(QString file)
+{
+ if (file.isEmpty())
+ return;
+
+ if (file.startsWith("myth://"))
+ {
+ QUrl url(file);
+ file = url.path();
+ file = file.right(file.length() - 1);
+ if (!file.endsWith("/"))
+ m_workingMetadata->SetTrailer(file);
+ else
+ m_workingMetadata->SetTrailer(QString());
+ }
+ else
+ m_workingMetadata->SetTrailer(file);
+ CheckedSet(m_trailerText, file);
+}
+
+void EditMetadataDialog::customEvent(QEvent *levent)
+{
+ if (levent->type() == DialogCompletionEvent::kEventType)
+ {
+ DialogCompletionEvent *dce = (DialogCompletionEvent*)(levent);
+
+ const QString resultid = dce->GetId();
+
+ if (resultid == CEID_COVERARTFILE)
+ SetCoverArt(dce->GetResultText());
+ else if (resultid == CEID_BANNERFILE)
+ SetBanner(dce->GetResultText());
+ else if (resultid == CEID_FANARTFILE)
+ SetFanart(dce->GetResultText());
+ else if (resultid == CEID_SCREENSHOTFILE)
+ SetScreenshot(dce->GetResultText());
+ else if (resultid == CEID_TRAILERFILE)
+ SetTrailer(dce->GetResultText());
+ else if (resultid == CEID_NEWCATEGORY)
+ AddCategory(dce->GetResultText());
+ }
+ else if (levent->type() == MetadataLookupEvent::kEventType)
+ {
+ MetadataLookupEvent *lue = (MetadataLookupEvent *)levent;
+
+ MetadataLookupList lul = lue->lookupList;
+
+ if (lul.isEmpty())
+ return;
+
+ // There should really only be one result here.
+ // If not, USER ERROR!
+ if (lul.count() == 1)
+ {
+ OnArtworkSearchDone(lul.takeFirst());
+ }
+ else
+ {
+ if (m_busyPopup)
+ {
+ m_busyPopup->Close();
+ m_busyPopup = NULL;
+ }
+ }
+ }
+ else if (levent->type() == MetadataLookupFailure::kEventType)
+ {
+ MetadataLookupFailure *luf = (MetadataLookupFailure *)levent;
+
+ MetadataLookupList lul = luf->lookupList;
+
+ if (m_busyPopup)
+ {
+ m_busyPopup->Close();
+ m_busyPopup = NULL;
+ }
+
+ if (lul.size())
+ {
+ MetadataLookup *lookup = lul.takeFirst();
+ VERBOSE(VB_GENERAL,
+ QString("No results found for %1 %2 %3").arg(lookup->GetTitle())
+ .arg(lookup->GetSeason()).arg(lookup->GetEpisode()));
+ }
+ }
+ else if (levent->type() == ImageDLEvent::kEventType)
+ {
+ ImageDLEvent *ide = (ImageDLEvent *)levent;
+
+ MetadataLookup *lookup = ide->item;
+
+ if (!lookup)
+ return;
+
+ handleDownloadedImages(lookup);
+ }
+}
+
+#include "editvideometadata.moc"
View
148 mythtv/programs/mythfrontend/editvideometadata.h
@@ -0,0 +1,148 @@
+#ifndef EDITVIDEOMETADATA_H_
+#define EDITVIDEOMETADATA_H_
+
+#include "mythscreentype.h"
+#include "metadatacommon.h"
+#include "metadatadownload.h"
+#include "metadataimagedownload.h"
+
+class VideoMetadata;
+class VideoMetadataListManager;
+class MythUIButtonList;
+class MythUIButtonListItem;
+class MythUIText;
+class MythUITextEdit;
+class MythUIButton;
+class MythUISpinBox;
+class MythUICheckBox;
+
+class EditMetadataDialog : public MythScreenType
+{
+ Q_OBJECT
+
+ public:
+ EditMetadataDialog(MythScreenStack *lparent,
+ QString lname,
+ VideoMetadata *source_metadata,
+ const VideoMetadataListManager &cache);
+ ~EditMetadataDialog();
+
+ bool Create();
+ void customEvent(QEvent *levent);
+
+ void fillWidgets();
+
+ protected:
+ void createBusyDialog(QString title);
+
+ signals:
+ void Finished();
+
+ public slots:
+ void SaveAndExit();
+ void SetTitle();
+ void SetSubtitle();
+ void SetTagline();
+ void SetRating();
+ void SetDirector();
+ void SetInetRef();
+ void SetHomepage();
+ void SetPlot();
+ void SetYear();
+ void SetUserRating();
+ void SetLength();
+ void SetCategory(MythUIButtonListItem*);
+ void SetPlayer();
+ void SetSeason();
+ void SetEpisode();
+ void SetLevel(MythUIButtonListItem*);
+ void SetChild(MythUIButtonListItem*);
+ void ToggleBrowse();
+ void ToggleWatched();
+ void FindCoverArt();
+ void FindBanner();
+ void FindFanart();
+ void FindScreenshot();
+ void FindTrailer();
+ void NewCategoryPopup();
+ void AddCategory(QString category);
+ void SetCoverArt(QString file);
+ void SetBanner(QString file);
+ void SetFanart(QString file);
+ void SetScreenshot(QString file);
+ void SetTrailer(QString file);
+ void FindNetArt(VideoArtworkType type);
+ void FindNetCoverArt();
+ void FindNetBanner();
+ void FindNetFanart();
+ void FindNetScreenshot();
+ void OnSearchListSelection(ArtworkInfo info,
+ VideoArtworkType type);
+
+ private:
+ void OnArtworkSearchDone(MetadataLookup *lookup);
+ void handleDownloadedImages(MetadataLookup *lookup);
+
+ VideoMetadata *m_workingMetadata;
+ VideoMetadata *m_origMetadata;
+
+ //
+ // GUI stuff
+ //
+
+ MythUITextEdit *m_titleEdit;
+ MythUITextEdit *m_subtitleEdit;
+ MythUITextEdit *m_taglineEdit;
+ MythUITextEdit *m_playerEdit;
+ MythUITextEdit *m_ratingEdit;
+ MythUITextEdit *m_directorEdit;
+ MythUITextEdit *m_inetrefEdit;
+ MythUITextEdit *m_homepageEdit;
+ MythUITextEdit *m_plotEdit;
+
+ MythUISpinBox *m_seasonSpin;
+ MythUISpinBox *m_episodeSpin;
+ MythUISpinBox *m_yearSpin;
+ MythUISpinBox *m_userRatingSpin;
+ MythUISpinBox *m_lengthSpin;
+ MythUIButtonList *m_categoryList;
+ MythUIButtonList *m_levelList;
+ MythUIButtonList *m_childList;
+ MythUICheckBox *m_browseCheck;
+ MythUICheckBox *m_watchedCheck;
+ MythUIButton *m_coverartButton;
+ MythUIText *m_coverartText;
+ MythUIButton *m_screenshotButton;
+ MythUIText *m_screenshotText;
+ MythUIButton *m_bannerButton;
+ MythUIText *m_bannerText;
+ MythUIButton *m_fanartButton;
+ MythUIText *m_fanartText;
+ MythUIButton *m_trailerButton;
+ MythUIText *m_trailerText;
+ MythUIButton *m_netCoverartButton;
+ MythUIButton *m_netFanartButton;
+ MythUIButton *m_netBannerButton;
+ MythUIButton *m_netScreenshotButton;
+ MythUIImage *m_coverart;
+ MythUIImage *m_screenshot;
+ MythUIImage *m_banner;
+ MythUIImage *m_fanart;
+ MythUIButton *m_doneButton;
+
+ //
+ // Remember video-to-play-next index number when the user is toggling
+ // child videos on and off
+ //
+
+ int cachedChildSelection;
+
+ const VideoMetadataListManager &m_metaCache;
+ MetadataDownload *m_query;
+ MetadataImageDownload *m_imageDownload;
+
+ MythUIBusyDialog *m_busyPopup;
+ MythScreenStack *m_popupStack;
+};
+
+#endif
View
348 mythtv/programs/mythfrontend/main.cpp
@@ -73,6 +73,17 @@ using namespace std;
#include "backendconnectionmanager.h"
#include "themechooser.h"
+// Video
+#include "cleanup.h"
+#include "globals.h"
+#include "videodlg.h"
+#include "videoglobalsettings.h"
+#include "videofileassoc.h"
+#include "videoplayersettings.h"
+#include "videometadatasettings.h"
+#include "videolist.h"
+
+
static ExitPrompter *exitPopup = NULL;
static MythThemedMenu *menu;
@@ -84,6 +95,61 @@ static void handleExit(void);
namespace
{
+ class RunSettingsCompletion : public QObject
+ {
+ Q_OBJECT
+
+ public:
+ static void Create(bool check)
+ {
+ new RunSettingsCompletion(check);
+ }
+
+ private:
+ RunSettingsCompletion(bool check)
+ {
+ if (check)
+ {
+ connect(&m_plcc,
+ SIGNAL(SigResultReady(bool, ParentalLevel::Level)),
+ SLOT(OnPasswordResultReady(bool,
+ ParentalLevel::Level)));
+ m_plcc.Check(ParentalLevel::plMedium, ParentalLevel::plHigh);
+ }
+ else
+ {
+ OnPasswordResultReady(true, ParentalLevel::plHigh);
+ }
+ }
+
+ ~RunSettingsCompletion() {}
+
+ private slots:
+ void OnPasswordResultReady(bool passwordValid,
+ ParentalLevel::Level newLevel)
+ {
+ (void) newLevel;
+
+ if (passwordValid)
+ {
+ VideoGeneralSettings settings;
+ settings.exec();
+ }
+ else
+ {
+ VERBOSE(VB_IMPORTANT,
+ QObject::tr("Aggressive Parental Controls Warning: "
+ "invalid password. An attempt to enter a "
+ "MythVideo settings screen was prevented."));
+ }
+
+ deleteLater();
+ }
+
+ public:
+ ParentalLevelChangeChecker m_plcc;
+ };
+
class BookmarkDialog : MythScreenType
{
public:
@@ -500,6 +566,200 @@ static void showStatus(void)
delete statusbox;
}
+static void RunVideoScreen(VideoDialog::DialogType type, bool fromJump = false)
+{
+ QString message = QObject::tr("Loading videos ...");
+
+ MythScreenStack *popupStack =
+ GetMythMainWindow()->GetStack("popup stack");
+
+ MythUIBusyDialog *busyPopup = new MythUIBusyDialog(message,
+ popupStack, "mythvideobusydialog");
+
+ if (busyPopup->Create())
+ popupStack->AddScreen(busyPopup, false);
+
+ MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
+
+ VideoDialog::VideoListPtr video_list;
+ if (fromJump)
+ {
+ VideoDialog::VideoListDeathDelayPtr &saved =
+ VideoDialog::GetSavedVideoList();
+ if (!saved.isNull())
+ {
+ video_list = saved->GetSaved();
+ }
+ }
+
+ VideoDialog::BrowseType browse = static_cast<VideoDialog::BrowseType>(
+ gCoreContext->GetNumSetting("mythvideo.db_group_type",
+ VideoDialog::BRS_FOLDER));
+
+ if (!video_list)
+ video_list = new VideoList;
+
+ VideoDialog *mythvideo =
+ new VideoDialog(mainStack, "mythvideo", video_list, type, browse);
+
+ if (mythvideo->Create())
+ {
+ busyPopup->Close();
+ mainStack->AddScreen(mythvideo);
+ }
+ else
+ busyPopup->Close();
+}
+
+static void jumpScreenVideoManager() { RunVideoScreen(VideoDialog::DLG_MANAGER, true); }
+static void jumpScreenVideoBrowser() { RunVideoScreen(VideoDialog::DLG_BROWSER, true); }
+static void jumpScreenVideoTree() { RunVideoScreen(VideoDialog::DLG_TREE, true); }
+static void jumpScreenVideoGallery() { RunVideoScreen(VideoDialog::DLG_GALLERY, true); }
+static void jumpScreenVideoDefault() { RunVideoScreen(VideoDialog::DLG_DEFAULT, true); }
+
+QString gDVDdevice;
+
+static void playDisc()
+{
+ //
+ // Get the command string to play a DVD
+ //
+
+ bool isBD = false;
+
+ QString command_string =
+ gCoreContext->GetSetting("mythdvd.DVDPlayerCommand");
+ QString bluray_mountpoint =
+ gCoreContext->GetSetting("BluRayMountpoint", "/media/cdrom");
+ QDir bdtest(bluray_mountpoint + "/BDMV");
+
+ if (bdtest.exists())
+ isBD = true;
+
+ if (isBD)
+ {
+ GetMythUI()->AddCurrentLocation("playdisc");
+
+ QString filename = QString("bd:/%1/").arg(bluray_mountpoint);
+
+ GetMythMainWindow()->HandleMedia("Internal", filename);
+
+ GetMythUI()->RemoveCurrentLocation();
+ }
+ else
+ {
+ QString dvd_device = gDVDdevice;
+
+ if (dvd_device.isEmpty())
+ dvd_device = MediaMonitor::defaultDVDdevice();
+
+ if (dvd_device.isEmpty())
+ return; // User cancelled in the Popup
+
+ GetMythUI()->AddCurrentLocation("playdisc");
+
+ if ((command_string.indexOf("internal", 0, Qt::CaseInsensitive) > -1) ||
+ (command_string.length() < 1))
+ {
+#ifdef Q_OS_MAC
+ // Convert a BSD 'leaf' name into a raw device path
+ QString filename = "dvd://dev/r"; // e.g. 'dvd://dev/rdisk2'
+#elif USING_MINGW
+ QString filename = "dvd:"; // e.g. 'dvd:E\\'
+#else
+ QString filename = "dvd:/"; // e.g. 'dvd://dev/sda'
+#endif
+ filename += dvd_device;
+
+ command_string = "Internal";
+ GetMythMainWindow()->HandleMedia(command_string, filename);
+ GetMythUI()->RemoveCurrentLocation();
+
+ return;
+ }
+ else
+ {
+ if (command_string.contains("%d"))
+ {
+ //
+ // Need to do device substitution
+ //
+ command_string =
+ command_string.replace(QRegExp("%d"), dvd_device);
+ }
+ sendPlaybackStart();
+ myth_system(command_string);
+ sendPlaybackEnd();
+ if (GetMythMainWindow())
+ {
+ GetMythMainWindow()->raise();
+ GetMythMainWindow()->activateWindow();
+ if (GetMythMainWindow()->currentWidget())
+ GetMythMainWindow()->currentWidget()->setFocus();
+ }
+ }
+ GetMythUI()->RemoveCurrentLocation();
+ }
+}
+
+/////////////////////////////////////////////////
+//// Media handlers
+/////////////////////////////////////////////////
+static void handleDVDMedia(MythMediaDevice *dvd)
+{
+ if (!dvd)
+ return;
+
+ QString newDevice = dvd->getDevicePath();
+
+ // Device insertion. Store it for later use
+ if (dvd->isUsable())
+ if (gDVDdevice.length() && gDVDdevice != newDevice)
+ {
+ // Multiple DVD devices. Clear the old one so the user has to
+ // select a disk to play (in MediaMonitor::defaultDVDdevice())
+
+ VERBOSE(VB_MEDIA, "MythVideo: Multiple DVD drives? Forgetting "
+ + gDVDdevice);
+ gDVDdevice.clear();
+ }
+ else
+ {
+ gDVDdevice = newDevice;
+ VERBOSE(VB_MEDIA,
+ "MythVideo: Storing DVD device " + gDVDdevice);
+ }
+ else
+ {
+ // Ejected/unmounted/error.
+
+ if (gDVDdevice.length() && gDVDdevice == newDevice)
+ {
+ VERBOSE(VB_MEDIA,
+ "MythVideo: Forgetting existing DVD " + gDVDdevice);
+ gDVDdevice.clear();
+ }
+
+ return;
+ }
+
+ switch (gCoreContext->GetNumSetting("DVDOnInsertDVD", 1))
+ {
+ case 0 : // Do nothing
+ break;
+ case 1 : // Display menu (mythdvd)*/
+ GetMythMainWindow()->JumpTo("Main Menu");
+ break;
+ case 2 : // play DVD or Blu-ray
+ GetMythMainWindow()->JumpTo("Main Menu");
+ playDisc();
+ break;
+ default:
+ VERBOSE(VB_IMPORTANT, "mythdvd main.o: handleMedia() does not "
+ "know what to do");
+ }
+}
+
static void TVMenuCallback(void *data, QString &selection)
{
(void)data;
@@ -689,6 +949,50 @@ static void TVMenuCallback(void *data, QString &selection)
else
delete msee;
}
+ else if (sel == "video_settings_general")
+ {
+ RunSettingsCompletion::Create(gCoreContext->
+ GetNumSetting("VideoAggressivePC", 0));
+ }
+ else if (sel == "video_settings_player")
+ {
+ MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
+
+ PlayerSettings *ps = new PlayerSettings(mainStack, "player settings");
+
+ if (ps->Create())
+ mainStack->AddScreen(ps);
+ }
+ else if (sel == "video_settings_metadata")
+ {
+ MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
+
+ MetadataSettings *ms = new MetadataSettings(mainStack, "metadata settings");
+
+ if (ms->Create())
+ mainStack->AddScreen(ms);
+ }
+ else if (sel == "video_settings_associations")
+ {
+ MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
+
+ FileAssocDialog *fa = new FileAssocDialog(mainStack, "fa dialog");
+
+ if (fa->Create())
+ mainStack->AddScreen(fa);
+ }
+ if (sel == "manager")
+ RunVideoScreen(VideoDialog::DLG_MANAGER);
+ else if (sel == "browser")
+ RunVideoScreen(VideoDialog::DLG_BROWSER);
+ else if (sel == "listing")
+ RunVideoScreen(VideoDialog::DLG_TREE);
+ else if (sel == "gallery")
+ RunVideoScreen(VideoDialog::DLG_GALLERY);
+ else if (sel == "disc_play")
+ {
+ playDisc();
+ }
else if (sel == "tv_status")
showStatus();
else if (sel == "exiting_app")
@@ -772,6 +1076,9 @@ static void WriteDefaults()
GeneralRecPrioritiesSettings grs;
grs.Load();
grs.Save();
+ VideoGeneralSettings vgs;
+ vgs.Load();
+ vgs.Save();
}
static int internal_play_media(const QString &mrl, const QString &plot,
@@ -977,6 +1284,45 @@ static void InitJumpPoints(void)
REG_JUMP(QT_TRANSLATE_NOOP("MythControls", "Previously Recorded"),
"", "", startPrevious);
+ // Video
+
+ REG_JUMP(JUMP_VIDEO_DEFAULT, QT_TRANSLATE_NOOP("MythControls",
+ "The Video default view"), "", jumpScreenVideoDefault);
+ REG_JUMP(JUMP_VIDEO_MANAGER, QT_TRANSLATE_NOOP("MythControls",
+ "The Video video manager"), "", jumpScreenVideoManager);
+ REG_JUMP(JUMP_VIDEO_BROWSER, QT_TRANSLATE_NOOP("MythControls",
+ "The Video video browser"), "", jumpScreenVideoBrowser);
+ REG_JUMP(JUMP_VIDEO_TREE, QT_TRANSLATE_NOOP("MythControls",
+ "The Video video listings"), "", jumpScreenVideoTree);
+ REG_JUMP(JUMP_VIDEO_GALLERY, QT_TRANSLATE_NOOP("MythControls",
+ "The Video video gallery"), "", jumpScreenVideoGallery);
+ REG_JUMP("Play Disc", QT_TRANSLATE_NOOP("MythControls",
+ "Play an Optical Disc"), "", playDisc);
+
+ REG_KEY("Video","PLAYALT", QT_TRANSLATE_NOOP("MythControls",
+ "Play selected item in alternate player"), "ALT+P");
+ REG_KEY("Video","FILTER", QT_TRANSLATE_NOOP("MythControls",
+ "Open video filter dialog"), "F");
+ REG_KEY("Video","BROWSE", QT_TRANSLATE_NOOP("MythControls",
+ "Change browsable in video manager"), "B");
+ REG_KEY("Video","INCPARENT", QT_TRANSLATE_NOOP("MythControls",
+ "Increase Parental Level"), "],},F11");
+ REG_KEY("Video","DECPARENT", QT_TRANSLATE_NOOP("MythControls",
+ "Decrease Parental Level"), "[,{,F10");
+ REG_KEY("Video","INCSEARCH", QT_TRANSLATE_NOOP("MythControls",
+ "Show Incremental Search Dialog"), "Ctrl+S");
+ REG_KEY("Video","DOWNLOADDATA", QT_TRANSLATE_NOOP("MythControls",
+ "Download metadata for current item"), "W");
+ REG_KEY("Video","ITEMDETAIL", QT_TRANSLATE_NOOP("MythControls",
+ "Display Item Detail Popup"), "");
+ REG_KEY("Video","HOME", QT_TRANSLATE_NOOP("MythControls",
+ "Go to the first video"), "Home");
+ REG_KEY("Video","END", QT_TRANSLATE_NOOP("MythControls",
+ "Go to the last video"), "End");
+ REG_MEDIA_HANDLER(QT_TRANSLATE_NOOP("MythControls",
+ "MythDVD DVD Media Handler"), "", "", handleDVDMedia,
+ MEDIATYPE_DVD, QString::null);
+
REG_JUMPEX(QT_TRANSLATE_NOOP("MythControls", "Toggle Show Widget Borders"),
"", "", setDebugShowBorders, false);
REG_JUMPEX(QT_TRANSLATE_NOOP("MythControls", "Toggle Show Widget Names"),
@@ -1332,4 +1678,6 @@ int main(int argc, char **argv)
return ret;
}
+
+#include "main.moc"
/* vim: set expandtab tabstop=4 shiftwidth=4: */
View
14 mythtv/programs/mythfrontend/mythfrontend.pro
@@ -33,7 +33,12 @@ HEADERS += proglist.h proglist_helpers.h
HEADERS += playbackboxhelper.h viewschedulediff.h
HEADERS += themechooser.h setupwizard_general.h
HEADERS += setupwizard_audio.h setupwizard_video.h
-HEADERS += grabbersettings.h
+HEADERS += grabbersettings.h editvideometadata.h
+HEADERS += videofileassoc.h videometadatasettings.h
+HEADERS += videoplayercommand.h videopopups.h
+HEADERS += videofilter.h videolist.h
+HEADERS += videoplayersettings.h videodlg.h
+HEADERS += videoglobalsettings.h
SOURCES += main.cpp playbackbox.cpp viewscheduled.cpp audiogeneralsettings.cpp
SOURCES += globalsettings.cpp manualschedule.cpp programrecpriority.cpp
@@ -48,7 +53,12 @@ SOURCES += proglist.cpp proglist_helpers.cpp
SOURCES += playbackboxhelper.cpp viewschedulediff.cpp
SOURCES += themechooser.cpp setupwizard_general.cpp
SOURCES += setupwizard_audio.cpp setupwizard_video.cpp
-SOURCES += grabbersettings.cpp
+SOURCES += grabbersettings.cpp editvideometadata.cpp
+SOURCES += videofileassoc.cpp videometadatasettings.cpp
+SOURCES += videoplayercommand.cpp videopopups.cpp
+SOURCES += videofilter.cpp videolist.cpp
+SOURCES += videoplayersettings.cpp videodlg.cpp
+SOURCES += videoglobalsettings.cpp
macx {
mac_bundle {
View
4,002 mythtv/programs/mythfrontend/videodlg.cpp
4,002 additions, 0 deletions not shown
View
230 mythtv/programs/mythfrontend/videodlg.h
@@ -0,0 +1,230 @@
+#ifndef VIDEODLG_H_
+#define VIDEODLG_H_
+
+#include <QPointer>
+#include <QStringList>
+
+#include "mythscreentype.h"
+
+#include "metadatacommon.h"
+#include "parentalcontrols.h"
+#include "quicksp.h"
+
+class MythUIText;
+class MythUIButtonList;
+class MythUIButtonTree;
+class MythUIButtonListItem;
+class MythUIBusyDialog;
+class MythUIImage;
+class MythUIStateType;
+class MythDialogBox;
+class MythGenericTree;
+class MetadataDownload;
+class MetadataImageDownload;
+class VideoMetadata;
+class VideoScanner;
+
+class QUrl;
+
+enum ImageDownloadErrorState { esOK, esError, esTimeout };
+
+class VideoDialog : public MythScreenType
+{
+ Q_OBJECT
+
+ public:
+ enum DialogType { DLG_DEFAULT = 0, DLG_BROWSER = 0x1, DLG_GALLERY = 0x2,
+ DLG_TREE = 0x4, DLG_MANAGER = 0x8, dtLast };
+
+ enum BrowseType { BRS_FOLDER = 0, BRS_GENRE = 0x1, BRS_CATEGORY = 0x2,
+ BRS_YEAR = 0x4, BRS_DIRECTOR = 0x8, BRS_CAST = 0x10,
+ BRS_USERRATING = 0x20, BRS_INSERTDATE = 0x40,
+ BRS_TVMOVIE = 0x80, BRS_STUDIO = 0x100, btLast };
+
+ typedef simple_ref_ptr<class VideoList> VideoListPtr;
+
+ typedef QPointer<class VideoListDeathDelay> VideoListDeathDelayPtr;
+
+ static VideoListDeathDelayPtr &GetSavedVideoList();
+
+ public:
+ VideoDialog(MythScreenStack *lparent, QString lname,
+ VideoListPtr video_list, DialogType type,
+ BrowseType browse);
+ ~VideoDialog();
+
+ bool Create();
+ bool keyPressEvent(QKeyEvent *levent);
+
+ private:
+ void searchStart();
+
+ public slots:
+ void searchComplete(QString string);
+
+ protected slots:
+ void Init(); /// Called after the screen is created by MythScreenStack
+
+ private slots:
+ void UpdatePosition();
+ void UpdateText(MythUIButtonListItem *);
+ void handleSelect(MythUIButtonListItem *);
+ void SetCurrentNode(MythGenericTree *);
+
+ void playVideo();
+ void playVideoAlt();
+ void playFolder();
+ void playVideoWithTrailers();
+ void playTrailer();
+
+ void SwitchTree();
+ void SwitchGallery();
+ void SwitchBrowse();
+ void SwitchManager();
+ void SwitchVideoFolderGroup();
+ void SwitchVideoGenreGroup();
+ void SwitchVideoCategoryGroup();
+ void SwitchVideoYearGroup();
+ void SwitchVideoDirectorGroup();
+ void SwitchVideoStudioGroup();
+ void SwitchVideoCastGroup();
+ void SwitchVideoUserRatingGroup();
+ void SwitchVideoInsertDateGroup();
+ void SwitchVideoTVMovieGroup();
+
+ void EditMetadata();
+ void VideoSearch(MythGenericTree *node = NULL,
+ bool automode = false);
+ void VideoAutoSearch(MythGenericTree *node = NULL);
+ void ResetMetadata();
+ void ToggleWatched();
+ void ToggleProcess();
+ void RemoveVideo();
+ void OnRemoveVideo(bool);
+
+ void VideoMenu();
+ void InfoMenu();
+ void ManageMenu();
+ void PlayMenu();
+ void DisplayMenu();
+ void ViewMenu();
+ void SettingsMenu();
+ void MetadataBrowseMenu();
+
+ void ChangeFilter();
+
+ void ToggleBrowseMode();
+ void ToggleFlatView();
+
+ void ViewPlot();
+ void ShowCastDialog();
+ void ShowHomepage();
+ bool DoItemDetailShow();
+ void ShowPlayerSettings();
+ void ShowExtensionSettings();
+ void ShowMetadataSettings();
+
+ void OnParentalChange(int amount);
+
+ // Called when the underlying data for an item changes
+ void OnVideoSearchListSelection(MetadataLookup *lookup);
+
+ void doVideoScan();
+
+ protected slots:
+ void reloadAllData(bool);
+ void reloadData();
+ void refreshData();
+ void UpdateItem(MythUIButtonListItem *item);
+
+ protected:
+ void customEvent(QEvent *levent);
+
+ virtual MythUIButtonListItem *GetItemCurrent();
+ virtual MythUIButtonListItem *GetItemByMetadata(VideoMetadata *metadata);
+
+ virtual void loadData();
+ void fetchVideos();
+ QString RemoteImageCheck(QString host, QString filename);
+ QString GetCoverImage(MythGenericTree *node);
+ QString GetFirstImage(MythGenericTree *node, QString type,
+ QString gpnode = QString(), int levels = 0);
+ QString GetImageFromFolder(VideoMetadata *metadata);
+ QString GetScreenshot(MythGenericTree *node);
+ QString GetBanner(MythGenericTree *node);
+ QString GetFanart(MythGenericTree *node);
+
+ void handleDownloadedImages(MetadataLookup *lookup);
+
+ VideoMetadata *GetMetadata(MythUIButtonListItem *item);
+
+ void handleDirSelect(MythGenericTree *node);
+ bool goBack();
+ void setParentalLevel(const ParentalLevel::Level &level);
+ void shiftParental(int amount);
+ bool createPopup();
+ void createBusyDialog(QString title);
+ void createOkDialog(QString title);
+
+ void SwitchLayout(DialogType type, BrowseType browse);
+
+ void StartVideoImageSet(MythGenericTree *node, QStringList coverart = QStringList(),
+ QStringList fanart = QStringList(), QStringList banner = QStringList(),
+ QStringList screenshot = QStringList());
+
+ private slots:
+
+ void OnVideoImageSetDone(VideoMetadata *metadata);
+ void OnVideoSearchDone(MetadataLookup *lookup);
+
+ private:
+ MythDialogBox *m_menuPopup;
+ MythUIBusyDialog *m_busyPopup;
+ MythScreenStack *m_popupStack;
+ MythScreenStack *m_mainStack;
+
+ MythUIButtonList *m_videoButtonList;
+ MythUIButtonTree *m_videoButtonTree;
+
+ MythUIText *m_titleText;
+ MythUIText *m_novideoText;
+
+ MythUIText *m_positionText;
+ MythUIText *m_crumbText;
+
+ MythUIImage *m_coverImage;
+ MythUIImage *m_screenshot;
+ MythUIImage *m_banner;
+ MythUIImage *m_fanart;
+
+ MythUIStateType *m_trailerState;
+ MythUIStateType *m_parentalLevelState;
+ MythUIStateType *m_videoLevelState;
+ MythUIStateType *m_userRatingState;
+ MythUIStateType *m_watchedState;
+ MythUIStateType *m_studioState;
+
+ MetadataDownload *m_query;
+ MetadataImageDownload *m_imageDownload;
+
+ class VideoDialogPrivate *m_d;
+};
+
+class VideoListDeathDelay : public QObject
+{
+ Q_OBJECT
+
+ public:
+ VideoListDeathDelay(VideoDialog::VideoListPtr toSave);
+ ~VideoListDeathDelay();
+
+ VideoDialog::VideoListPtr GetSaved();
+
+ private slots:
+ void OnTimeUp();
+
+ private:
+ class VideoListDeathDelayPrivate *m_d;
+};
+
+#endif
View
541 mythtv/programs/mythfrontend/videofileassoc.cpp
@@ -0,0 +1,541 @@
+#include <algorithm>
+#include <vector>
+#include <iterator>
+#include <map>
+
+#include "mythverbose.h"
+#include "mythmainwindow.h"
+#include "mythdialogbox.h"
+#include "mythuibuttonlist.h"
+#include "mythuitextedit.h"
+#include "mythuicheckbox.h"
+#include "mythuibutton.h"
+#include "dbaccess.h"
+#include "videoutils.h"
+
+#include "videofileassoc.h"
+
+namespace
+{
+ template <typename T, typename Inst, typename FuncType>
+ void assign_if_changed_notify(T &oldVal, const T &newVal, Inst *inst,
+ FuncType func)
+ {
+ if (oldVal != newVal)
+ {
+ oldVal = newVal;
+ func(inst);
+ }
+ }
+
+ class FileAssociationWrap
+ {
+ public:
+ enum FA_State {
+ efsNONE,
+ efsDELETE,
+ efsSAVE
+ };
+
+ public:
+ FileAssociationWrap(const QString &new_extension) : m_state(efsSAVE)
+ {
+ m_fa.extension = new_extension;
+ }
+
+ FileAssociationWrap(const FileAssociations::file_association &fa) :
+ m_fa(fa), m_state(efsNONE) {}
+
+ int GetID() const { return m_fa.id; }
+ QString GetExtension() const { return m_fa.extension; }
+ QString GetCommand() const { return m_fa.playcommand; }
+ bool GetDefault() const { return m_fa.use_default; }
+ bool GetIgnore() const { return m_fa.ignore; }
+
+ FA_State GetState() { return m_state; }
+
+ void CommitChanges()
+ {
+ switch (m_state)
+ {
+ case efsDELETE:
+ {
+ FileAssociations::getFileAssociation().remove(m_fa.id);
+ m_fa.id = -1;
+ m_state = efsNONE;
+ break;
+ }
+ case efsSAVE:
+ {
+ if (FileAssociations::getFileAssociation().add(m_fa))
+ {
+ m_state = efsNONE;
+ }
+ break;
+ }
+ case efsNONE:
+ default: {}
+ }
+ }
+
+ void MarkForDeletion()
+ {
+ m_state = efsDELETE;
+ }
+
+ void SetDefault(bool yes_or_no)
+ {
+ assign_if_changed_notify(m_fa.use_default, yes_or_no, this,
+ std::mem_fun(&FileAssociationWrap::SetChanged));
+ }
+
+ void SetIgnore(bool yes_or_no)
+ {
+ assign_if_changed_notify(m_fa.ignore, yes_or_no, this,
+ std::mem_fun(&FileAssociationWrap::SetChanged));
+ }
+
+ void SetCommand(const QString &new_command)
+ {
+ assign_if_changed_notify(m_fa.playcommand, new_command, this,
+ std::mem_fun(&FileAssociationWrap::SetChanged));
+ }
+
+ private:
+ void SetChanged() { m_state = efsSAVE; }
+
+ private:
+ FileAssociations::file_association m_fa;
+ FA_State m_state;
+ };
+
+ class BlockSignalsGuard
+ {
+ public:
+ void Block(QObject *o)
+ {
+ o->blockSignals(true);
+ m_objects.push_back(o);
+ }
+
+ ~BlockSignalsGuard()
+ {
+ for (list_type::iterator p = m_objects.begin();
+ p != m_objects.end(); ++p)
+ {
+ (*p)->blockSignals(false);
+ }
+ }
+
+ private:
+ typedef std::vector<QObject *> list_type;
+
+ private:
+ list_type m_objects;
+ };
+
+ struct UIDToFAPair
+ {
+ typedef unsigned int UID_type;
+
+ UIDToFAPair() : m_uid(0), m_file_assoc(0) {}
+
+ UIDToFAPair(UID_type uid, FileAssociationWrap *assoc) :
+ m_uid(uid), m_file_assoc(assoc) {}
+
+ UID_type m_uid;
+ FileAssociationWrap *m_file_assoc;
+ };
+
+
+ bool operator<(const UIDToFAPair &lhs, const UIDToFAPair &rhs)
+ {
+ if (lhs.m_file_assoc && rhs.m_file_assoc)
+ return QString::localeAwareCompare(lhs.m_file_assoc->GetExtension(),
+ rhs.m_file_assoc->GetExtension()) < 0;
+
+ return rhs.m_file_assoc;
+ }
+}
+
+Q_DECLARE_METATYPE(UIDToFAPair);
+
+////////////////////////////////////////////////////////////////////////
+
+class FileAssocDialogPrivate
+{
+ public:
+ typedef std::vector<UIDToFAPair> UIReadyList_type;
+
+ public:
+ FileAssocDialogPrivate() : m_nextFAID(0), m_selectionOverride(0)
+ {
+ LoadFileAssociations();
+ }
+
+ ~FileAssocDialogPrivate()
+ {
+ for (FA_collection::iterator p = m_fileAssociations.begin();
+ p != m_fileAssociations.end(); ++p)
+ {
+ delete p->second;
+ }
+ }
+
+ void SaveFileAssociations()
+ {
+ for (FA_collection::iterator p = m_fileAssociations.begin();
+ p != m_fileAssociations.end(); ++p)
+ {
+ p->second->CommitChanges();
+ }
+ }
+
+ bool AddExtension(QString newExtension, UIDToFAPair::UID_type &new_id)
+ {
+ if (newExtension.length())
+ {
+ new_id = ++m_nextFAID;
+ m_fileAssociations.insert(FA_collection::value_type(new_id,
+ new FileAssociationWrap(newExtension)));
+ return true;
+ }
+
+ return false;
+ }
+
+ bool DeleteExtension(UIDToFAPair::UID_type uid)
+ {
+ FA_collection::iterator p = m_fileAssociations.find(uid);
+ if (p != m_fileAssociations.end())
+ {
+ p->second->MarkForDeletion();
+
+ return true;
+ }
+
+ return false;
+ }
+
+ // Returns a list sorted by extension
+ UIReadyList_type GetUIReadyList()
+ {
+ UIReadyList_type ret;
+ std::transform(m_fileAssociations.begin(), m_fileAssociations.end(),
+ std::back_inserter(ret), fa_col_ent_2_UIDFAPair());
+ UIReadyList_type::iterator deleted = std::remove_if(ret.begin(),
+ ret.end(), test_fa_state<FileAssociationWrap::efsDELETE>());
+
+ if (deleted != ret.end())
+ ret.erase(deleted, ret.end());
+
+ std::sort(ret.begin(), ret.end());
+
+ return ret;
+ }
+
+ FileAssociationWrap *GetCurrentFA(MythUIButtonList *buttonList)
+ {
+ MythUIButtonListItem *item = buttonList->GetItemCurrent();
+ if (item)
+ {
+ UIDToFAPair key = item->GetData().value<UIDToFAPair>();
+ if (key.m_file_assoc)
+ {
+ return key.m_file_assoc;
+ }
+ }
+
+ return 0;
+ }
+
+ void SetSelectionOverride(UIDToFAPair::UID_type new_sel)
+ {
+ m_selectionOverride = new_sel;
+ }
+
+ UIDToFAPair::UID_type GetSelectionOverride()
+ {
+ return m_selectionOverride;
+ }
+
+ private:
+ typedef std::map<UIDToFAPair::UID_type, FileAssociationWrap *>
+ FA_collection;
+
+ private:
+ struct fa_col_ent_2_UIDFAPair
+ {
+ UIDToFAPair operator()(
+ const FileAssocDialogPrivate::FA_collection::value_type &from)
+ {
+ return UIDToFAPair(from.first, from.second);
+ }
+ };
+
+ template <FileAssociationWrap::FA_State against>
+ struct test_fa_state
+ {
+ bool operator()(const UIDToFAPair &item)
+ {
+ if (item.m_file_assoc && item.m_file_assoc->GetState() == against)
+ return true;
+ return false;
+ }
+ };
+
+ void LoadFileAssociations()
+ {
+ typedef std::vector<UIDToFAPair> tmp_fa_list;
+
+ const FileAssociations::association_list &fa_list =
+ FileAssociations::getFileAssociation().getList();
+ tmp_fa_list tmp_fa;
+ tmp_fa.reserve(fa_list.size());
+
+ for (FileAssociations::association_list::const_iterator p =
+ fa_list.begin(); p != fa_list.end(); ++p)
+ {
+ tmp_fa.push_back(UIDToFAPair(++m_nextFAID,
+ new FileAssociationWrap(*p)));
+ }
+
+ std::random_shuffle(tmp_fa.begin(), tmp_fa.end());
+
+ for (tmp_fa_list::const_iterator p = tmp_fa.begin(); p != tmp_fa.end();
+ ++p)
+ {
+ m_fileAssociations.insert(FA_collection::value_type(p->m_uid,
+ p->m_file_assoc));
+ }
+
+ if (!m_fileAssociations.size())
+ {
+ VERBOSE(VB_IMPORTANT, QString("%1: Couldn't get any filetypes from "
+ "your database.").arg(__FILE__));
+ }
+ }
+
+ private:
+ FA_collection m_fileAssociations;
+ UIDToFAPair::UID_type m_nextFAID;
+ UIDToFAPair::UID_type m_selectionOverride;
+};
+
+////////////////////////////////////////////////////////////////////////
+
+FileAssocDialog::FileAssocDialog(MythScreenStack *screenParent,
+ const QString &lname) :
+ MythScreenType(screenParent, lname), m_commandEdit(0),
+ m_extensionList(0), m_defaultCheck(0), m_ignoreCheck(0), m_doneButton(0),
+ m_newButton(0), m_deleteButton(0), m_private(new FileAssocDialogPrivate)
+{
+}
+
+FileAssocDialog::~FileAssocDialog()
+{
+ delete m_private;
+}
+
+bool FileAssocDialog::Create()
+{
+ if (!LoadWindowFromXML("video-ui.xml", "file_associations", this))
+ return false;
+
+ bool err = false;
+ UIUtilE::Assign(this, m_extensionList, "extension_select", &err);
+ UIUtilE::Assign(this, m_commandEdit, "command", &err);
+ UIUtilE::Assign(this, m_ignoreCheck, "ignore_check", &err);
+ UIUtilE::Assign(this, m_defaultCheck, "default_check", &err);
+
+ UIUtilE::Assign(this, m_doneButton, "done_button", &err);
+ UIUtilE::Assign(this, m_newButton, "new_button", &err);
+ UIUtilE::Assign(this, m_deleteButton, "delete_button", &err);
+
+ if (err)
+ {
+ VERBOSE(VB_IMPORTANT, "Cannot load screen 'file_associations'");
+ return false;
+ }
+
+ connect(m_extensionList, SIGNAL(itemSelected(MythUIButtonListItem *)),
+ SLOT(OnFASelected(MythUIButtonListItem *)));
+ connect(m_commandEdit, SIGNAL(valueChanged()),
+ SLOT(OnPlayerCommandChanged()));
+ connect(m_defaultCheck, SIGNAL(valueChanged()), SLOT(OnUseDefaltChanged()));
+ connect(m_ignoreCheck, SIGNAL(valueChanged()), SLOT(OnIgnoreChanged()));
+
+ connect(m_doneButton, SIGNAL(Clicked()), SLOT(OnDonePressed()));
+ connect(m_newButton, SIGNAL(Clicked()),
+ SLOT(OnNewExtensionPressed()));
+ connect(m_deleteButton, SIGNAL(Clicked()), SLOT(OnDeletePressed()));
+
+ m_extensionList->SetHelpText(tr("Select a file extension from this list "
+ "to modify or delete its settings."));
+ m_commandEdit->SetHelpText(tr("The command to use when playing this kind "
+ "of file. To use MythTV's Internal player, "
+ "use \"Internal\" as the player. For all other "
+ "players, you can use %s to substitute the filename."));
+ m_ignoreCheck->SetHelpText(tr("When checked, this will cause the file extension "
+ "to be ignored in scans of your library."));
+ m_defaultCheck->SetHelpText(tr("When checked, this will cause the global player "