MythTV  0.26-pre
videodlg.cpp
Go to the documentation of this file.
00001 #include <set>
00002 #include <map>
00003 
00004 #include <QApplication>
00005 #include <QTimer>
00006 #include <QList>
00007 #include <QFile>
00008 #include <QFileInfo>
00009 #include <QDir>
00010 #include <QUrl>
00011 
00012 #include "mythcontext.h"
00013 #include "compat.h"
00014 #include "mythdirs.h"
00015 
00016 #include "mythuihelper.h"
00017 #include "mythprogressdialog.h"
00018 #include "mythuitext.h"
00019 #include "mythuibutton.h"
00020 #include "mythuibuttonlist.h"
00021 #include "mythuibuttontree.h"
00022 #include "mythuiimage.h"
00023 #include "mythuistatetype.h"
00024 #include "mythuimetadataresults.h"
00025 #include "mythdialogbox.h"
00026 #include "mythgenerictree.h"
00027 #include "mythsystem.h"
00028 #include "remotefile.h"
00029 #include "remoteutil.h"
00030 #include "storagegroup.h"
00031 
00032 #include "videoscan.h"
00033 #include "globals.h"
00034 #include "videometadatalistmanager.h"
00035 #include "parentalcontrols.h"
00036 #include "videoutils.h"
00037 #include "dbaccess.h"
00038 #include "dirscan.h"
00039 #include "metadatafactory.h"
00040 #include "videofilter.h"
00041 #include "editvideometadata.h"
00042 #include "videopopups.h"
00043 #include "videolist.h"
00044 #include "videoplayercommand.h"
00045 #include "videodlg.h"
00046 #include "videofileassoc.h"
00047 #include "videoplayersettings.h"
00048 #include "videometadatasettings.h"
00049 
00050 namespace
00051 {
00052     bool IsValidDialogType(int num)
00053     {
00054         for (int i = 1; i <= VideoDialog::dtLast - 1; i <<= 1)
00055             if (num == i) return true;
00056         return false;
00057     }
00058 
00059     class ParentalLevelNotifyContainer : public QObject
00060     {
00061         Q_OBJECT
00062 
00063       signals:
00064         void SigLevelChanged();
00065 
00066       public:
00067         ParentalLevelNotifyContainer(QObject *lparent = 0) :
00068             QObject(lparent), m_level(ParentalLevel::plNone)
00069         {
00070             connect(&m_levelCheck,
00071                     SIGNAL(SigResultReady(bool, ParentalLevel::Level)),
00072                     SLOT(OnResultReady(bool, ParentalLevel::Level)));
00073         }
00074 
00075         const ParentalLevel &GetLevel() const { return m_level; }
00076 
00077         void SetLevel(ParentalLevel level)
00078         {
00079             m_levelCheck.Check(m_level.GetLevel(), level.GetLevel());
00080         }
00081 
00082       private slots:
00083         void OnResultReady(bool passwordValid, ParentalLevel::Level newLevel)
00084         {
00085             ParentalLevel lastLevel = m_level;
00086             if (passwordValid)
00087             {
00088                 m_level = newLevel;
00089             }
00090 
00091             if (m_level.GetLevel() == ParentalLevel::plNone)
00092             {
00093                 m_level = ParentalLevel(ParentalLevel::plLowest);
00094             }
00095 
00096             if (lastLevel != m_level)
00097             {
00098                 emit SigLevelChanged();
00099             }
00100         }
00101 
00102       private:
00103         ParentalLevel m_level;
00104         ParentalLevelChangeChecker m_levelCheck;
00105     };
00106 
00107     MythGenericTree *GetNodePtrFromButton(MythUIButtonListItem *item)
00108     {
00109         if (item)
00110             return item->GetData().value<MythGenericTree *>();
00111 
00112         return NULL;
00113     }
00114 
00115     VideoMetadata *GetMetadataPtrFromNode(MythGenericTree *node)
00116     {
00117         if (node)
00118             return node->GetData().value<TreeNodeData>().GetMetadata();
00119 
00120         return NULL;
00121     }
00122 
00123     bool GetLocalVideoImage(const QString &video_uid, const QString &filename,
00124                              const QStringList &in_dirs, QString &image,
00125                              QString title, int season,
00126                              const QString host, QString sgroup,
00127                              int episode = 0, bool isScreenshot = false)
00128     {
00129         QStringList search_dirs(in_dirs);
00130         QFileInfo qfi(filename);
00131         search_dirs += qfi.absolutePath();
00132         if (title.contains("/"))
00133             title.replace("/", "-");
00134 
00135         const QString base_name = qfi.completeBaseName();
00136         QList<QByteArray> image_types = QImageReader::supportedImageFormats();
00137 
00138         typedef std::set<QString> image_type_list;
00139         image_type_list image_exts;
00140 
00141         QString suffix;
00142 
00143         if (sgroup == "Coverart")
00144             suffix = "coverart";
00145         if (sgroup == "Fanart")
00146             suffix = "fanart";
00147         if (sgroup == "Screenshots")
00148             suffix = "screenshot";
00149         if (sgroup == "Banners")
00150             suffix = "banner";
00151 
00152         for (QList<QByteArray>::const_iterator it = image_types.begin();
00153                 it != image_types.end(); ++it)
00154         {
00155             image_exts.insert(QString(*it).toLower());
00156         }
00157 
00158         if (!host.isEmpty())
00159         {
00160             QStringList hostFiles;
00161 
00162             RemoteGetFileList(host, "", &hostFiles, sgroup, true);
00163             const QString hntm("%2.%3");
00164 
00165             for (image_type_list::const_iterator ext = image_exts.begin();
00166                     ext != image_exts.end(); ++ext)
00167             {
00168                 QStringList sfn;
00169                 if (episode > 0 || season > 0)
00170                 {
00171                     if (isScreenshot)
00172                         sfn += hntm.arg(QString("%1 Season %2x%3_%4")
00173                                  .arg(title).arg(QString::number(season))
00174                                  .arg(QString::number(episode))
00175                                  .arg(suffix))
00176                                  .arg(*ext);
00177                     else
00178                         sfn += hntm.arg(QString("%1 Season %2_%3")
00179                                  .arg(title).arg(QString::number(season))
00180                                  .arg(suffix))
00181                                  .arg(*ext);
00182 
00183                 }
00184                 else
00185                 {
00186                 sfn += hntm.arg(base_name + "_%1").arg(suffix).arg(*ext);
00187                 sfn += hntm.arg(video_uid + "_%1").arg(suffix).arg(*ext);
00188                 }
00189 
00190                 for (QStringList::const_iterator i = sfn.begin();
00191                         i != sfn.end(); ++i)
00192                 {
00193                     if (hostFiles.contains(*i))
00194                     {
00195                         image = *i;
00196                         return true;
00197                     }
00198                 }
00199             }
00200         }
00201 
00202         const QString fntm("%1/%2.%3");
00203 
00204         for (QStringList::const_iterator dir = search_dirs.begin();
00205                 dir != search_dirs.end(); ++dir)
00206         {
00207             if (!(*dir).length()) continue;
00208 
00209             for (image_type_list::const_iterator ext = image_exts.begin();
00210                     ext != image_exts.end(); ++ext)
00211             {
00212                 QStringList sfn;
00213                 if (season > 0 || episode > 0)
00214                 {
00215                     if (isScreenshot)
00216                         sfn += fntm.arg(*dir).arg(QString("%1 Season %2x%3_%4")
00217                                  .arg(title).arg(QString::number(season))
00218                                  .arg(QString::number(episode))
00219                                  .arg(suffix))
00220                                  .arg(*ext);
00221                     else if (!isScreenshot)
00222                         sfn += fntm.arg(*dir).arg(QString("%1 Season %2_%3")
00223                                  .arg(title).arg(QString::number(season))
00224                                  .arg(suffix))
00225                                  .arg(*ext);
00226 
00227                 }
00228                 if (!isScreenshot)
00229                 {
00230                 sfn += fntm.arg(*dir).arg(QString(base_name + "_%1")
00231                     .arg(suffix)).arg(*ext);
00232                 sfn += fntm.arg(*dir).arg(QString(video_uid + "_%1")
00233                     .arg(suffix)).arg(*ext);
00234                 }
00235 
00236                 for (QStringList::const_iterator i = sfn.begin();
00237                         i != sfn.end(); ++i)
00238                 {
00239                     if (QFile::exists(*i))
00240                     {
00241                         image = *i;
00242                         return true;
00243                     }
00244                 }
00245             }
00246         }
00247 
00248         return false;
00249     }
00250 
00251     void PlayVideo(const QString &filename,
00252             const VideoMetadataListManager &video_list, bool useAltPlayer = false)
00253     {
00254         const int WATCHED_WATERMARK = 10000; // Less than this and the chain of
00255                                              // videos will not be followed when
00256                                              // playing.
00257 
00258         VideoMetadataListManager::VideoMetadataPtr item = video_list.byFilename(filename);
00259 
00260         if (!item) return;
00261 
00262         QTime playing_time;
00263 
00264         do
00265         {
00266             playing_time.start();
00267 
00268             if (useAltPlayer)
00269                 VideoPlayerCommand::AltPlayerFor(item.get()).Play();
00270             else
00271                 VideoPlayerCommand::PlayerFor(item.get()).Play();
00272 
00273             if (item->GetChildID() > 0 && video_list.byID(item->GetChildID()))
00274                     item = video_list.byID(item->GetChildID());
00275             else
00276                 break;
00277         }
00278         while (item && playing_time.elapsed() > WATCHED_WATERMARK);
00279     }
00280 
00281     class FanartLoader: public QObject
00282     {
00283         Q_OBJECT
00284 
00285       public:
00286         FanartLoader() : itemsPast(0)
00287         {
00288             connect(&m_fanartTimer, SIGNAL(timeout()), SLOT(fanartLoad()));
00289         }
00290 
00291        ~FanartLoader()
00292         {
00293             m_fanartTimer.stop();
00294             m_fanartTimer.disconnect(this);
00295         }
00296 
00297         void LoadImage(const QString &filename, MythUIImage *image)
00298         {
00299             bool wasActive = m_fanartTimer.isActive();
00300             if (filename.isEmpty())
00301             {
00302                 if (wasActive)
00303                     m_fanartTimer.stop();
00304 
00305                 image->Reset();
00306                 itemsPast++;
00307             }
00308             else
00309             {
00310                 QMutexLocker locker(&m_fanartLock);
00311                 m_fanart = image;
00312                 if (filename != m_fanart->GetFilename())
00313                 {
00314                     if (wasActive)
00315                         m_fanartTimer.stop();
00316 
00317                     if (itemsPast > 2)
00318                         m_fanart->Reset();
00319 
00320                     m_fanart->SetFilename(filename);
00321                     m_fanartTimer.setSingleShot(true);
00322                     m_fanartTimer.start(300);
00323 
00324                     if (wasActive)
00325                         itemsPast++;
00326                     else
00327                         itemsPast = 0;
00328                 }
00329                 else
00330                     itemsPast = 0;
00331             }
00332         }
00333 
00334       protected slots:
00335         void fanartLoad(void)
00336         {
00337             QMutexLocker locker(&m_fanartLock);
00338             m_fanart->Load();
00339         }
00340 
00341       private:
00342         int             itemsPast;
00343         QMutex          m_fanartLock;
00344         MythUIImage    *m_fanart;
00345         QTimer          m_fanartTimer;
00346     };
00347 
00348     FanartLoader fanartLoader;
00349 
00350     struct CopyMetadataDestination
00351     {
00352         virtual void handleText(const QString &name, const QString &value) = 0;
00353         virtual void handleState(const QString &name, const QString &value) = 0;
00354         virtual void handleImage(const QString &name,
00355                 const QString &filename) = 0;
00356     };
00357 
00358     class ScreenCopyDest : public CopyMetadataDestination
00359     {
00360       public:
00361         ScreenCopyDest(MythScreenType *screen) : m_screen(screen) {}
00362 
00363         void handleText(const QString &name, const QString &value)
00364         {
00365             CheckedSet(m_screen, name, value);
00366         }
00367 
00368         void handleState(const QString &name, const QString &value)
00369         {
00370             handleText(name, value);
00371         }
00372 
00373         void handleImage(const QString &name, const QString &filename)
00374         {
00375             MythUIImage *image = NULL;
00376             UIUtilW::Assign(m_screen, image, name);
00377             if (image)
00378             {
00379                 if (name != "fanart")
00380                 {
00381                     if (!filename.isEmpty())
00382                     {
00383                         image->SetFilename(filename);
00384                         image->Load();
00385                     }
00386                     else
00387                         image->Reset();
00388                 }
00389                 else
00390                 {
00391                     fanartLoader.LoadImage(filename, image);
00392                 }
00393             }
00394         }
00395 
00396       private:
00397         MythScreenType *m_screen;
00398     };
00399 
00400     class MythUIButtonListItemCopyDest : public CopyMetadataDestination
00401     {
00402       public:
00403         MythUIButtonListItemCopyDest(MythUIButtonListItem *item) :
00404             m_item(item) {}
00405 
00406         void handleText(const QString &name, const QString &value)
00407         {
00408             m_item->SetText(value, name);
00409         }
00410 
00411         void handleState(const QString &name, const QString &value)
00412         {
00413             m_item->DisplayState(value, name);
00414         }
00415 
00416         void handleImage(const QString &name, const QString &filename)
00417         {
00418             (void) name;
00419             (void) filename;
00420         }
00421 
00422       private:
00423         MythUIButtonListItem *m_item;
00424     };
00425 
00426     void CopyMetadataToUI(const VideoMetadata *metadata,
00427             CopyMetadataDestination &dest)
00428     {
00429         typedef std::map<QString, QString> valuelist;
00430         valuelist tmp;
00431 
00432         if (metadata)
00433         {
00434             QString coverfile;
00435             if ((metadata->IsHostSet()
00436                 && !metadata->GetCoverFile().startsWith("/"))
00437                 && !metadata->GetCoverFile().isEmpty()
00438                 && !IsDefaultCoverFile(metadata->GetCoverFile()))
00439             {
00440                 coverfile = generate_file_url("Coverart", metadata->GetHost(),
00441                         metadata->GetCoverFile());
00442             }
00443             else
00444             {
00445                 coverfile = metadata->GetCoverFile();
00446             }
00447 
00448             if (!IsDefaultCoverFile(coverfile))
00449                 tmp["coverart"] = coverfile;
00450 
00451             tmp["coverfile"] = coverfile;
00452 
00453             QString screenshotfile;
00454             if (metadata->IsHostSet() && !metadata->GetScreenshot().startsWith("/")
00455                 && !metadata->GetScreenshot().isEmpty())
00456             {
00457                 screenshotfile = generate_file_url("Screenshots",
00458                         metadata->GetHost(), metadata->GetScreenshot());
00459             }
00460             else
00461             {
00462                 screenshotfile = metadata->GetScreenshot();
00463             }
00464 
00465             if (!IsDefaultScreenshot(screenshotfile))
00466                 tmp["screenshot"] = screenshotfile;
00467 
00468             tmp["screenshotfile"] = screenshotfile;
00469 
00470             QString bannerfile;
00471             if (metadata->IsHostSet() && !metadata->GetBanner().startsWith("/")
00472                 && !metadata->GetBanner().isEmpty())
00473             {
00474                 bannerfile = generate_file_url("Banners", metadata->GetHost(),
00475                         metadata->GetBanner());
00476             }
00477             else
00478             {
00479                 bannerfile = metadata->GetBanner();
00480             }
00481 
00482             if (!IsDefaultBanner(bannerfile))
00483                 tmp["banner"] = bannerfile;
00484 
00485             tmp["bannerfile"] = bannerfile;
00486 
00487             QString fanartfile;
00488             if (metadata->IsHostSet() && !metadata->GetFanart().startsWith("/")
00489                 && !metadata->GetFanart().isEmpty())
00490             {
00491                 fanartfile = generate_file_url("Fanart", metadata->GetHost(),
00492                         metadata->GetFanart());
00493             }
00494             else
00495             {
00496                 fanartfile = metadata->GetFanart();
00497             }
00498 
00499             if (!IsDefaultFanart(fanartfile))
00500                 tmp["fanart"] = fanartfile;
00501 
00502             tmp["fanartfile"] = fanartfile;
00503 
00504             tmp["trailerstate"] = TrailerToState(metadata->GetTrailer());
00505             tmp["studiostate"] = metadata->GetStudio();
00506             tmp["userratingstate"] =
00507                     QString::number((int)(metadata->GetUserRating()));
00508             tmp["watchedstate"] = WatchedToState(metadata->GetWatched());
00509 
00510             tmp["videolevel"] = ParentalLevelToState(metadata->GetShowLevel());
00511         }
00512 
00513         struct helper
00514         {
00515             helper(valuelist &values, CopyMetadataDestination &d) :
00516                 m_vallist(values), m_dest(d) {}
00517 
00518             void handleImage(const QString &name)
00519             {
00520                 m_dest.handleImage(name, m_vallist[name]);
00521             }
00522 
00523             void handleState(const QString &name)
00524             {
00525                 m_dest.handleState(name, m_vallist[name]);
00526             }
00527           private:
00528             valuelist &m_vallist;
00529             CopyMetadataDestination &m_dest;
00530         };
00531 
00532         helper h(tmp, dest);
00533 
00534         h.handleImage("coverart");
00535         h.handleImage("screenshot");
00536         h.handleImage("banner");
00537         h.handleImage("fanart");
00538 
00539         h.handleState("trailerstate");
00540         h.handleState("userratingstate");
00541         h.handleState("watchedstate");
00542         h.handleState("videolevel");
00543     }
00544 }
00545 
00546 class ItemDetailPopup : public MythScreenType
00547 {
00548     Q_OBJECT
00549 
00550   public:
00551     static bool Exists()
00552     {
00553         // TODO: Add ability to theme loader to do this a better way.
00554         return LoadWindowFromXML("video-ui.xml", WINDOW_NAME, NULL);
00555     }
00556 
00557   public:
00558     ItemDetailPopup(MythScreenStack *lparent, VideoMetadata *metadata,
00559             const VideoMetadataListManager &listManager) :
00560         MythScreenType(lparent, WINDOW_NAME), m_metadata(metadata),
00561         m_listManager(listManager), m_playButton(NULL), m_doneButton(NULL)
00562     {
00563     }
00564 
00565     bool Create()
00566     {
00567         if (!LoadWindowFromXML("video-ui.xml", WINDOW_NAME, this))
00568             return false;
00569 
00570         UIUtilW::Assign(this, m_playButton, "play_button");
00571         UIUtilW::Assign(this, m_doneButton, "done_button");
00572 
00573         if (m_playButton)
00574             connect(m_playButton, SIGNAL(Clicked()), SLOT(OnPlay()));
00575 
00576         if (m_doneButton)
00577             connect(m_doneButton, SIGNAL(Clicked()), SLOT(OnDone()));
00578 
00579         BuildFocusList();
00580 
00581         if (m_playButton || m_doneButton)
00582             SetFocusWidget(m_playButton ? m_playButton : m_doneButton);
00583 
00584         MetadataMap metadataMap;
00585         m_metadata->toMap(metadataMap);
00586         SetTextFromMap(metadataMap);
00587 
00588         ScreenCopyDest dest(this);
00589         CopyMetadataToUI(m_metadata, dest);
00590 
00591         return true;
00592     }
00593 
00594   private slots:
00595     void OnPlay()
00596     {
00597         PlayVideo(m_metadata->GetFilename(), m_listManager);
00598     }
00599 
00600     void OnDone()
00601     {
00602         // TODO: Close() can do horrible things, this will pop
00603         // our screen, delete us, and return here.
00604         Close();
00605     }
00606 
00607   private:
00608     bool OnKeyAction(const QStringList &actions)
00609     {
00610         bool handled = false;
00611         for (QStringList::const_iterator key = actions.begin();
00612                 key != actions.end(); ++key)
00613         {
00614             handled = true;
00615             if (*key == "SELECT" || *key == "PLAYBACK")
00616                 OnPlay();
00617             else
00618                 handled = false;
00619         }
00620 
00621         return handled;
00622     }
00623 
00624   protected:
00625     bool keyPressEvent(QKeyEvent *levent)
00626     {
00627         if (!MythScreenType::keyPressEvent(levent))
00628         {
00629             QStringList actions;
00630             bool handled = GetMythMainWindow()->TranslateKeyPress("Video",
00631                            levent, actions);
00632 
00633             if (!handled && !OnKeyAction(actions))
00634             {
00635                 handled = GetMythMainWindow()->TranslateKeyPress("TV Frontend",
00636                         levent, actions);
00637                 OnKeyAction(actions);
00638             }
00639         }
00640 
00641         return true;
00642     }
00643 
00644   private:
00645     static const char * const WINDOW_NAME;
00646     VideoMetadata *m_metadata;
00647     const VideoMetadataListManager &m_listManager;
00648 
00649     MythUIButton *m_playButton;
00650     MythUIButton *m_doneButton;
00651 };
00652 
00653 const char * const ItemDetailPopup::WINDOW_NAME = "itemdetailpopup";
00654 
00655 class VideoDialogPrivate
00656 {
00657   private:
00658     typedef std::list<std::pair<QString, ParentalLevel::Level> >
00659             parental_level_map;
00660 
00661     struct rating_to_pl_less :
00662         public std::binary_function<parental_level_map::value_type,
00663                                     parental_level_map::value_type, bool>
00664     {
00665         bool operator()(const parental_level_map::value_type &lhs,
00666                     const parental_level_map::value_type &rhs) const
00667         {
00668             return lhs.first.length() < rhs.first.length();
00669         }
00670     };
00671 
00672     typedef VideoDialog::VideoListPtr VideoListPtr;
00673 
00674   public:
00675     VideoDialogPrivate(VideoListPtr videoList, VideoDialog::DialogType type,
00676                        VideoDialog::BrowseType browse) :
00677         m_switchingLayout(false), m_firstLoadPass(true),
00678         m_rememberPosition(false), m_videoList(videoList), m_rootNode(0),
00679         m_currentNode(0), m_treeLoaded(false), m_isFlatList(false),
00680         m_type(type), m_browse(browse), m_scanner(0)
00681     {
00682         if (gCoreContext->GetNumSetting("mythvideo.ParentalLevelFromRating", 0))
00683         {
00684             for (ParentalLevel sl(ParentalLevel::plLowest);
00685                 sl.GetLevel() <= ParentalLevel::plHigh && sl.good(); ++sl)
00686             {
00687                 QString ratingstring =
00688                         gCoreContext->GetSetting(QString("mythvideo.AutoR2PL%1")
00689                                 .arg(sl.GetLevel()));
00690                 QStringList ratings =
00691                         ratingstring.split(':', QString::SkipEmptyParts);
00692 
00693                 for (QStringList::const_iterator p = ratings.begin();
00694                     p != ratings.end(); ++p)
00695                 {
00696                     m_rating_to_pl.push_back(
00697                         parental_level_map::value_type(*p, sl.GetLevel()));
00698                 }
00699             }
00700             m_rating_to_pl.sort(std::not2(rating_to_pl_less()));
00701         }
00702 
00703         m_rememberPosition =
00704                 gCoreContext->GetNumSetting("mythvideo.VideoTreeRemember", 0);
00705 
00706         m_isFileBrowser = gCoreContext->GetNumSetting("VideoDialogNoDB", 0);
00707         m_groupType = gCoreContext->GetNumSetting("mythvideo.db_group_type", 0);
00708 
00709         m_altPlayerEnabled =
00710                     gCoreContext->GetNumSetting("mythvideo.EnableAlternatePlayer");
00711 
00712         m_autoMeta = gCoreContext->GetNumSetting("mythvideo.AutoMetaDataScan", 1);
00713 
00714         m_artDir = gCoreContext->GetSetting("VideoArtworkDir");
00715         m_sshotDir = gCoreContext->GetSetting("mythvideo.screenshotDir");
00716         m_fanDir = gCoreContext->GetSetting("mythvideo.fanartDir");
00717         m_banDir = gCoreContext->GetSetting("mythvideo.bannerDir");
00718     }
00719 
00720     ~VideoDialogPrivate()
00721     {
00722         delete m_scanner;
00723 
00724         if (m_rememberPosition && m_lastTreeNodePath.length())
00725         {
00726             gCoreContext->SaveSetting("mythvideo.VideoTreeLastActive",
00727                     m_lastTreeNodePath);
00728         }
00729     }
00730 
00731     void AutomaticParentalAdjustment(VideoMetadata *metadata)
00732     {
00733         if (metadata && !m_rating_to_pl.empty())
00734         {
00735             QString rating = metadata->GetRating();
00736             for (parental_level_map::const_iterator p = m_rating_to_pl.begin();
00737                     !rating.isEmpty() && p != m_rating_to_pl.end(); ++p)
00738             {
00739                 if (rating.indexOf(p->first) != -1)
00740                 {
00741                     metadata->SetShowLevel(p->second);
00742                     break;
00743                 }
00744             }
00745         }
00746     }
00747 
00748     void DelayVideoListDestruction(VideoListPtr videoList)
00749     {
00750         m_savedPtr = new VideoListDeathDelay(videoList);
00751     }
00752 
00753   public:
00754     ParentalLevelNotifyContainer m_parentalLevel;
00755     bool m_switchingLayout;
00756 
00757     static VideoDialog::VideoListDeathDelayPtr m_savedPtr;
00758 
00759     bool m_firstLoadPass;
00760 
00761     bool m_rememberPosition;
00762 
00763     VideoListPtr m_videoList;
00764 
00765     MythGenericTree *m_rootNode;
00766     MythGenericTree *m_currentNode;
00767 
00768     bool m_treeLoaded;
00769 
00770     bool m_isFileBrowser;
00771     int  m_groupType;
00772     bool m_isFlatList;
00773     bool m_altPlayerEnabled;
00774     VideoDialog::DialogType m_type;
00775     VideoDialog::BrowseType m_browse;
00776 
00777     bool m_autoMeta;
00778 
00779     QString m_artDir;
00780     QString m_sshotDir;
00781     QString m_fanDir;
00782     QString m_banDir;
00783     VideoScanner *m_scanner;
00784 
00785     QString m_lastTreeNodePath;
00786 
00787   private:
00788     parental_level_map m_rating_to_pl;
00789 };
00790 
00791 VideoDialog::VideoListDeathDelayPtr VideoDialogPrivate::m_savedPtr;
00792 
00793 class VideoListDeathDelayPrivate
00794 {
00795   public:
00796     VideoListDeathDelayPrivate(VideoDialog::VideoListPtr toSave) :
00797         m_savedList(toSave)
00798     {
00799     }
00800 
00801     VideoDialog::VideoListPtr GetSaved()
00802     {
00803         return m_savedList;
00804     }
00805 
00806   private:
00807     VideoDialog::VideoListPtr m_savedList;
00808 };
00809 
00810 VideoListDeathDelay::VideoListDeathDelay(VideoDialog::VideoListPtr toSave) :
00811     QObject(qApp)
00812 {
00813     m_d = new VideoListDeathDelayPrivate(toSave);
00814     QTimer::singleShot(3000, this, SLOT(OnTimeUp()));
00815 }
00816 
00817 VideoListDeathDelay::~VideoListDeathDelay()
00818 {
00819     delete m_d;
00820 }
00821 
00822 VideoDialog::VideoListPtr VideoListDeathDelay::GetSaved()
00823 {
00824     return m_d->GetSaved();
00825 }
00826 
00827 void VideoListDeathDelay::OnTimeUp()
00828 {
00829     deleteLater();
00830 }
00831 
00832 VideoDialog::VideoListDeathDelayPtr &VideoDialog::GetSavedVideoList()
00833 {
00834     return VideoDialogPrivate::m_savedPtr;
00835 }
00836 
00837 VideoDialog::VideoDialog(MythScreenStack *lparent, QString lname,
00838         VideoListPtr video_list, DialogType type, BrowseType browse) :
00839     MythScreenType(lparent, lname), m_menuPopup(0), m_busyPopup(0),
00840     m_videoButtonList(0), m_videoButtonTree(0), m_titleText(0),
00841     m_novideoText(0), m_positionText(0), m_crumbText(0), m_coverImage(0),
00842     m_screenshot(0), m_banner(0), m_fanart(0), m_trailerState(0),
00843     m_parentalLevelState(0), m_watchedState(0), m_studioState(0)
00844 {
00845     m_metadataFactory = new MetadataFactory(this);
00846 
00847     m_d = new VideoDialogPrivate(video_list, type, browse);
00848 
00849     m_popupStack = GetMythMainWindow()->GetStack("popup stack");
00850     m_mainStack = GetMythMainWindow()->GetMainStack();
00851 
00852     m_d->m_videoList->setCurrentVideoFilter(VideoFilterSettings(true,
00853                     lname));
00854 
00855     m_d->m_parentalLevel.SetLevel(ParentalLevel(gCoreContext->
00856                     GetNumSetting("VideoDefaultParentalLevel",
00857                             ParentalLevel::plLowest)));
00858     
00859     StorageGroup::ClearGroupToUseCache();
00860 }
00861 
00862 VideoDialog::~VideoDialog()
00863 {
00864     if (!m_d->m_switchingLayout)
00865         m_d->DelayVideoListDestruction(m_d->m_videoList);
00866 
00867     SavePosition();
00868 
00869     delete m_d;
00870 }
00871 
00872 void VideoDialog::SavePosition(void)
00873 {
00874     m_d->m_lastTreeNodePath = "";
00875 
00876     if (m_d->m_type == DLG_TREE)
00877     {
00878         MythGenericTree *node = m_videoButtonTree->GetCurrentNode();
00879         if (node)
00880             m_d->m_lastTreeNodePath = node->getRouteByString().join("\n");
00881     }
00882     else if (m_d->m_type == DLG_BROWSER || m_d->m_type == DLG_GALLERY)
00883     {
00884         MythUIButtonListItem *item = m_videoButtonList->GetItemCurrent();
00885         if (item)
00886         {
00887             MythGenericTree *node = GetNodePtrFromButton(item);
00888             if (node)
00889                  m_d->m_lastTreeNodePath = node->getRouteByString().join("\n");
00890         }
00891     }
00892 
00893     gCoreContext->SaveSetting("mythvideo.VideoTreeLastActive", m_d->m_lastTreeNodePath);
00894 }
00895 
00896 bool VideoDialog::Create()
00897 {
00898     if (m_d->m_type == DLG_DEFAULT)
00899     {
00900         m_d->m_type = static_cast<DialogType>(
00901                 gCoreContext->GetNumSetting("Default MythVideo View", DLG_GALLERY));
00902         m_d->m_browse = static_cast<BrowseType>(
00903                 gCoreContext->GetNumSetting("mythvideo.db_group_type", BRS_FOLDER));
00904     }
00905 
00906     if (!IsValidDialogType(m_d->m_type))
00907     {
00908         m_d->m_type = DLG_GALLERY;
00909     }
00910 
00911     QString windowName = "videogallery";
00912     int flatlistDefault = 0;
00913 
00914     switch (m_d->m_type)
00915     {
00916         case DLG_BROWSER:
00917             windowName = "browser";
00918             flatlistDefault = 1;
00919             break;
00920         case DLG_GALLERY:
00921             windowName = "gallery";
00922             break;
00923         case DLG_TREE:
00924             windowName = "tree";
00925             break;
00926         case DLG_MANAGER:
00927             m_d->m_isFlatList =
00928                     gCoreContext->GetNumSetting("mythvideo.db_folder_view", 1);
00929             windowName = "manager";
00930             flatlistDefault = 1;
00931             break;
00932         case DLG_DEFAULT:
00933         default:
00934             break;
00935     }
00936 
00937     switch (m_d->m_browse)
00938     {
00939         case BRS_GENRE:
00940             m_d->m_groupType = BRS_GENRE;
00941             break;
00942         case BRS_CATEGORY:
00943             m_d->m_groupType = BRS_CATEGORY;
00944             break;
00945         case BRS_YEAR:
00946             m_d->m_groupType = BRS_YEAR;
00947             break;
00948         case BRS_DIRECTOR:
00949             m_d->m_groupType = BRS_DIRECTOR;
00950             break;
00951         case BRS_STUDIO:
00952             m_d->m_groupType = BRS_STUDIO;
00953             break;
00954         case BRS_CAST:
00955             m_d->m_groupType = BRS_CAST;
00956             break;
00957         case BRS_USERRATING:
00958             m_d->m_groupType = BRS_USERRATING;
00959             break;
00960         case BRS_INSERTDATE:
00961             m_d->m_groupType = BRS_INSERTDATE;
00962             break;
00963         case BRS_TVMOVIE:
00964             m_d->m_groupType = BRS_TVMOVIE;
00965             break;
00966         case BRS_FOLDER:
00967         default:
00968             m_d->m_groupType = BRS_FOLDER;
00969             break;
00970     }
00971 
00972     m_d->m_isFlatList =
00973             gCoreContext->GetNumSetting(QString("mythvideo.folder_view_%1")
00974                     .arg(m_d->m_type), flatlistDefault);
00975 
00976     if (!LoadWindowFromXML("video-ui.xml", windowName, this))
00977         return false;
00978 
00979     bool err = false;
00980     if (m_d->m_type == DLG_TREE)
00981         UIUtilE::Assign(this, m_videoButtonTree, "videos", &err);
00982     else
00983         UIUtilE::Assign(this, m_videoButtonList, "videos", &err);
00984 
00985     UIUtilW::Assign(this, m_titleText, "title");
00986     UIUtilW::Assign(this, m_novideoText, "novideos");
00987     UIUtilW::Assign(this, m_positionText, "position");
00988     UIUtilW::Assign(this, m_crumbText, "breadcrumbs");
00989 
00990     UIUtilW::Assign(this, m_coverImage, "coverart");
00991     UIUtilW::Assign(this, m_screenshot, "screenshot");
00992     UIUtilW::Assign(this, m_banner, "banner");
00993     UIUtilW::Assign(this, m_fanart, "fanart");
00994 
00995     UIUtilW::Assign(this, m_trailerState, "trailerstate");
00996     UIUtilW::Assign(this, m_parentalLevelState, "parentallevel");
00997     UIUtilW::Assign(this, m_watchedState, "watchedstate");
00998     UIUtilW::Assign(this, m_studioState, "studiostate");
00999 
01000     if (err)
01001     {
01002         LOG(VB_GENERAL, LOG_ERR, "Cannot load screen '" + windowName + "'");
01003         return false;
01004     }
01005 
01006     CheckedSet(m_trailerState, "None");
01007     CheckedSet(m_parentalLevelState, "None");
01008     CheckedSet(m_watchedState, "None");
01009     CheckedSet(m_studioState, "None");
01010 
01011     BuildFocusList();
01012 
01013     if (m_d->m_type == DLG_TREE)
01014     {
01015         SetFocusWidget(m_videoButtonTree);
01016 
01017         connect(m_videoButtonTree, SIGNAL(itemClicked(MythUIButtonListItem *)),
01018                 SLOT(handleSelect(MythUIButtonListItem *)));
01019         connect(m_videoButtonTree, SIGNAL(itemSelected(MythUIButtonListItem *)),
01020                 SLOT(UpdateText(MythUIButtonListItem *)));
01021         connect(m_videoButtonTree, SIGNAL(nodeChanged(MythGenericTree *)),
01022                 SLOT(SetCurrentNode(MythGenericTree *)));
01023     }
01024     else
01025     {
01026         SetFocusWidget(m_videoButtonList);
01027 
01028         connect(m_videoButtonList, SIGNAL(itemClicked(MythUIButtonListItem *)),
01029                 SLOT(handleSelect(MythUIButtonListItem *)));
01030         connect(m_videoButtonList, SIGNAL(itemSelected(MythUIButtonListItem *)),
01031                 SLOT(UpdateText(MythUIButtonListItem *)));
01032     }
01033 
01034     return true;
01035 }
01036 
01037 void VideoDialog::Init()
01038 {
01039     connect(&m_d->m_parentalLevel, SIGNAL(SigLevelChanged()),
01040             SLOT(reloadData()));
01041 }
01042 
01043 void VideoDialog::Load()
01044 {
01045     reloadData();
01046     // We only want to prompt once, on startup, hence this is done in Load()
01047     if (m_d->m_rootNode->childCount() == 1 &&
01048         m_d->m_rootNode->getChildAt(0)->getInt() == kNoFilesFound)
01049         PromptToScan();
01050 }
01051 
01056 void VideoDialog::refreshData()
01057 {
01058     fetchVideos();
01059     loadData();
01060 
01061     CheckedSet(m_parentalLevelState,
01062             ParentalLevelToState(m_d->m_parentalLevel.GetLevel()));
01063 
01064     bool noFiles = (m_d->m_rootNode->childCount() == 1 &&
01065                     m_d->m_rootNode->getChildAt(0)->getInt() == kNoFilesFound);
01066 
01067     if (m_novideoText)
01068         m_novideoText->SetVisible(noFiles);
01069 }
01070 
01071 void VideoDialog::scanFinished(bool dbChanged)
01072 {
01073     delete m_d->m_scanner;
01074     m_d->m_scanner = 0;
01075 
01076     if (dbChanged)
01077         m_d->m_videoList->InvalidateCache();
01078 
01079     m_d->m_currentNode = NULL;
01080     reloadData();
01081 
01082     if (m_d->m_autoMeta)
01083         VideoAutoSearch();
01084 
01085     if (m_d->m_rootNode->childCount() == 1 &&
01086         m_d->m_rootNode->getChildAt(0)->getInt() == kNoFilesFound)
01087     {
01088         QString message = tr("The video scan found no files, have you "
01089                              "configured a video storage group?");
01090         ShowOkPopup(message);
01091     }
01092 }
01093 
01098 void VideoDialog::reloadData()
01099 {
01100     m_d->m_treeLoaded = false;
01101     refreshData();
01102 }
01103 
01108 void VideoDialog::loadData()
01109 {
01110     if (m_d->m_type == DLG_TREE)
01111     {
01112         m_videoButtonTree->AssignTree(m_d->m_rootNode);
01113 
01114         if (m_d->m_firstLoadPass)
01115         {
01116             m_d->m_firstLoadPass = false;
01117 
01118             if (m_d->m_rememberPosition)
01119             {
01120                 QStringList route =
01121                         gCoreContext->GetSetting("mythvideo.VideoTreeLastActive",
01122                                 "").split("\n");
01123                 m_videoButtonTree->SetNodeByString(route);
01124             }
01125         }
01126     }
01127     else
01128     {
01129         m_videoButtonList->Reset();
01130 
01131         if (!m_d->m_treeLoaded)
01132             return;
01133 
01134         if (!m_d->m_currentNode)
01135             SetCurrentNode(m_d->m_rootNode);
01136 
01137         if (!m_d->m_currentNode)
01138             return;
01139 
01140         MythGenericTree *selectedNode = m_d->m_currentNode->getSelectedChild();
01141 
01142         // restore the last saved position in the video tree if this is the first
01143         // time this method is called and the option is set in the database
01144         if (m_d->m_firstLoadPass)
01145         {
01146             if (m_d->m_rememberPosition)
01147             {
01148                 QStringList lastTreeNodePath = gCoreContext->GetSetting("mythvideo.VideoTreeLastActive", "").split("\n");
01149 
01150                 if (m_d->m_type == DLG_GALLERY || m_d->m_type == DLG_BROWSER)
01151                 {
01152                     if (!lastTreeNodePath.isEmpty())
01153                     {
01154                         MythGenericTree *node;
01155 
01156                         // go through the path list and set the current node
01157                         for (int i = 0; i < lastTreeNodePath.size(); i++)
01158                         {
01159                             node = m_d->m_currentNode->getChildByName(lastTreeNodePath.at(i));
01160                             if (node != NULL)
01161                             {
01162                                 // check if the node name is the same as the currently selected
01163                                 // one in the saved tree list. if yes then we are on the right
01164                                 // way down the video tree to find the last saved position
01165                                 if (node->getString().compare(lastTreeNodePath.at(i)) == 0)
01166                                 {
01167                                     // set the folder as the new node so we can travel further down
01168                                     // dont do this if its the last part of the saved video path tree
01169                                     if (node->getInt() == kSubFolder &&
01170                                         node->childCount() > 1 &&
01171                                         i < lastTreeNodePath.size()-1)
01172                                     {
01173                                         SetCurrentNode(node);
01174                                     }
01175                                     // in the last run the selectedNode will be the last
01176                                     // entry of the saved tree node.
01177                                     if (lastTreeNodePath.at(i) == lastTreeNodePath.last())
01178                                         selectedNode = node;
01179                                 }
01180                             }
01181                         }
01182                         m_d->m_firstLoadPass = false;
01183                     }
01184                 }
01185             }
01186         }
01187 
01188         typedef QList<MythGenericTree *> MGTreeChildList;
01189         MGTreeChildList *lchildren = m_d->m_currentNode->getAllChildren();
01190 
01191         for (MGTreeChildList::const_iterator p = lchildren->begin();
01192                 p != lchildren->end(); ++p)
01193         {
01194             if (*p != NULL)
01195             {
01196                 MythUIButtonListItem *item =
01197                         new MythUIButtonListItem(m_videoButtonList, QString(), 0,
01198                                 true, MythUIButtonListItem::NotChecked);
01199 
01200                 item->SetData(qVariantFromValue(*p));
01201 
01202                 UpdateItem(item);
01203 
01204                 if (*p == selectedNode)
01205                     m_videoButtonList->SetItemCurrent(item);
01206             }
01207         }
01208     }
01209 
01210     UpdatePosition();
01211 }
01212 
01217 void VideoDialog::UpdateItem(MythUIButtonListItem *item)
01218 {
01219     if (!item)
01220         return;
01221 
01222     MythGenericTree *node = GetNodePtrFromButton(item);
01223 
01224     VideoMetadata *metadata = GetMetadata(item);
01225 
01226     if (metadata)
01227     {
01228         MetadataMap metadataMap;
01229         metadata->toMap(metadataMap);
01230         item->SetTextFromMap(metadataMap);
01231     }
01232 
01233     MythUIButtonListItemCopyDest dest(item);
01234     CopyMetadataToUI(metadata, dest);
01235 
01236     MythGenericTree *parent = node->getParent();
01237 
01238     if (parent && metadata && ((QString::compare(parent->getString(),
01239                             metadata->GetTitle(), Qt::CaseInsensitive) == 0) ||
01240                             parent->getString().startsWith(tr("Season"), Qt::CaseInsensitive)))
01241         item->SetText(metadata->GetSubtitle());
01242     else if (metadata && !metadata->GetSubtitle().isEmpty())
01243         item->SetText(QString("%1: %2").arg(metadata->GetTitle()).arg(metadata->GetSubtitle()));
01244     else
01245         item->SetText(metadata ? metadata->GetTitle() : node->getString());
01246 
01247     QString coverimage = GetCoverImage(node);
01248     QString screenshot = GetScreenshot(node);
01249     QString banner     = GetBanner(node);
01250     QString fanart     = GetFanart(node);
01251 
01252     if (!screenshot.isEmpty() && parent && metadata &&
01253         ((QString::compare(parent->getString(),
01254                             metadata->GetTitle(), Qt::CaseInsensitive) == 0) ||
01255             parent->getString().startsWith(tr("Season"), Qt::CaseInsensitive)))
01256     {
01257         item->SetImage(screenshot);
01258     }
01259     else
01260     {
01261         if (coverimage.isEmpty())
01262             coverimage = GetFirstImage(node, "Coverart");
01263         item->SetImage(coverimage);
01264     }
01265 
01266     int nodeInt = node->getInt();
01267 
01268     if (coverimage.isEmpty() && nodeInt == kSubFolder)
01269         coverimage = GetFirstImage(node, "Coverart");
01270 
01271     item->SetImage(coverimage, "coverart");
01272 
01273     if (screenshot.isEmpty() && nodeInt == kSubFolder)
01274         screenshot = GetFirstImage(node, "Screenshots");
01275 
01276     item->SetImage(screenshot, "screenshot");
01277 
01278     if (banner.isEmpty() && nodeInt == kSubFolder)
01279         banner = GetFirstImage(node, "Banners");
01280 
01281     item->SetImage(banner, "banner");
01282 
01283     if (fanart.isEmpty() && nodeInt == kSubFolder)
01284         fanart = GetFirstImage(node, "Fanart");
01285 
01286     item->SetImage(fanart, "fanart");
01287 
01288     if (nodeInt == kSubFolder)
01289     {
01290         item->SetText(QString("%1").arg(node->visibleChildCount()), "childcount");
01291         item->DisplayState("subfolder", "nodetype");
01292         item->SetText(node->getString(), "title");
01293         item->SetText(node->getString());
01294     }
01295     else if (nodeInt == kUpFolder)
01296     {
01297         item->DisplayState("upfolder", "nodetype");
01298         item->SetText(node->getString(), "title");
01299         item->SetText(node->getString());
01300     }
01301 
01302     if (item == GetItemCurrent())
01303         UpdateText(item);
01304 }
01305 
01310 void VideoDialog::fetchVideos()
01311 {
01312     MythGenericTree *oldroot = m_d->m_rootNode;
01313     if (!m_d->m_treeLoaded)
01314     {
01315         m_d->m_rootNode = m_d->m_videoList->buildVideoList(m_d->m_isFileBrowser,
01316                 m_d->m_isFlatList, m_d->m_groupType,
01317                 m_d->m_parentalLevel.GetLevel(), true);
01318     }
01319     else
01320     {
01321         m_d->m_videoList->refreshList(m_d->m_isFileBrowser,
01322                 m_d->m_parentalLevel.GetLevel(),
01323                 m_d->m_isFlatList, m_d->m_groupType);
01324         m_d->m_rootNode = m_d->m_videoList->GetTreeRoot();
01325     }
01326 
01327     m_d->m_treeLoaded = true;
01328 
01329     m_d->m_rootNode->setOrderingIndex(kNodeSort);
01330 
01331     // Move a node down if there is a single directory item here...
01332     if (m_d->m_rootNode->childCount() == 1)
01333     {
01334         MythGenericTree *node = m_d->m_rootNode->getChildAt(0);
01335         if (node->getInt() == kSubFolder && node->childCount() > 1)
01336             m_d->m_rootNode = node;
01337         else if (node->getInt() == kUpFolder)
01338             m_d->m_treeLoaded = false;
01339     }
01340     else if (m_d->m_rootNode->childCount() == 0)
01341         m_d->m_treeLoaded = false;
01342 
01343     if (!m_d->m_currentNode || m_d->m_rootNode != oldroot)
01344         SetCurrentNode(m_d->m_rootNode);
01345 }
01346 
01351 QString VideoDialog::RemoteImageCheck(QString host, QString filename)
01352 {
01353     QString result = "";
01354 #if 0
01355     LOG(VB_GENERAL, LOG_DEBUG, QString("RemoteImageCheck(%1)").arg(filename));
01356 #endif
01357 
01358     QStringList dirs = GetVideoDirsByHost(host);
01359 
01360     if (!dirs.isEmpty())
01361     {
01362         for (QStringList::const_iterator iter = dirs.begin();
01363              iter != dirs.end(); ++iter)
01364         {
01365             QUrl sgurl = *iter;
01366             QString path = sgurl.path();
01367 
01368             QString fname = QString("%1/%2").arg(path).arg(filename);
01369 
01370             QStringList list( QString("QUERY_SG_FILEQUERY") );
01371             list << host;
01372             list << "Videos";
01373             list << fname;
01374 
01375             bool ok = gCoreContext->SendReceiveStringList(list);
01376 
01377             if (!ok || list.at(0).startsWith("SLAVE UNREACHABLE"))
01378             {
01379                 LOG(VB_GENERAL, LOG_WARNING,
01380                     QString("Backend : %1 currently Unreachable. Skipping "
01381                             "this one.") .arg(host));
01382                 break;
01383             }
01384 
01385             if ((!list.isEmpty()) && (list.at(0) == fname))
01386                 result = generate_file_url("Videos", host, filename);
01387 
01388             if (!result.isEmpty())
01389             {
01390 #if 0
01391                 LOG(VB_GENERAL, LOG_DEBUG,
01392                     QString("RemoteImageCheck(%1) res :%2: :%3:")
01393                         .arg(fname).arg(result).arg(*iter));
01394 #endif
01395                 break;
01396             }
01397 
01398         }
01399     }
01400 
01401     return result;
01402 }
01403 
01408 QString VideoDialog::GetImageFromFolder(VideoMetadata *metadata)
01409 {
01410     QString icon_file;
01411     QString host = metadata->GetHost();
01412     QFileInfo fullpath(metadata->GetFilename());
01413     QDir dir = fullpath.dir();
01414     QString prefix = QDir::cleanPath(dir.path());
01415 
01416     QString filename = QString("%1/folder").arg(prefix);
01417 
01418     QStringList test_files;
01419     test_files.append(filename + ".png");
01420     test_files.append(filename + ".jpg");
01421     test_files.append(filename + ".gif");
01422     bool foundCover;
01423 
01424     for (QStringList::const_iterator tfp = test_files.begin();
01425             tfp != test_files.end(); ++tfp)
01426     {
01427         QString imagePath = *tfp;
01428         foundCover = false;
01429         if (!host.isEmpty())
01430         {
01431             // Strip out any extra /'s
01432             imagePath.replace("//", "/");
01433             prefix.replace("//","/");
01434             imagePath = imagePath.right(imagePath.length() - (prefix.length() + 1));
01435             QString tmpCover = RemoteImageCheck(host, imagePath);
01436 
01437             if (!tmpCover.isEmpty())
01438             {
01439                 foundCover = true;
01440                 imagePath = tmpCover;
01441             }
01442         }
01443         else
01444             foundCover = QFile::exists(imagePath);
01445 
01446         if (foundCover)
01447         {
01448             icon_file = imagePath;
01449             return icon_file;
01450         }
01451     }
01452 
01453     // If we found nothing, load something that matches the title.
01454     // If that fails, load anything we find.
01455     if (icon_file.isEmpty())
01456     {
01457         QStringList imageTypes;
01458         imageTypes.append(metadata->GetTitle() + ".png");
01459         imageTypes.append(metadata->GetTitle() + ".jpg");
01460         imageTypes.append(metadata->GetTitle() + ".gif");
01461         imageTypes.append("*.png");
01462         imageTypes.append("*.jpg");
01463         imageTypes.append("*.gif");
01464 
01465         QStringList fList;
01466 
01467         if (!host.isEmpty())
01468         {
01469             // TODO: This can likely get a little cleaner
01470 
01471             QStringList dirs = GetVideoDirsByHost(host);
01472 
01473             if (!dirs.isEmpty())
01474             {
01475                 for (QStringList::const_iterator iter = dirs.begin();
01476                      iter != dirs.end(); ++iter)
01477                 {
01478                     QUrl sgurl = *iter;
01479                     QString path = sgurl.path();
01480 
01481                     QString subdir = prefix;
01482 
01483                     path = path + "/" + subdir;
01484                     QStringList tmpList;
01485                     bool ok = RemoteGetFileList(host, path, &tmpList, "Videos");
01486 
01487                     if (ok)
01488                     {
01489                         for (QStringList::const_iterator pattern = imageTypes.begin();
01490                              pattern != imageTypes.end(); ++pattern)
01491                         {
01492                             QRegExp rx(*pattern);
01493                             rx.setPatternSyntax(QRegExp::Wildcard);
01494                             QStringList matches = tmpList.filter(rx);
01495                             if (!matches.isEmpty())
01496                             {
01497                                 fList.clear();
01498                                 fList.append(subdir + "/" + matches.at(0).split("::").at(1));
01499                                 break;
01500                             }
01501                         }
01502 
01503                         break;
01504                     }
01505                 }
01506             }
01507         }
01508         else
01509         {
01510             QDir vidDir(prefix);
01511             vidDir.setNameFilters(imageTypes);
01512             fList = vidDir.entryList();
01513         }
01514 
01515         if (!fList.isEmpty())
01516         {
01517             if (host.isEmpty())
01518                 icon_file = QString("%1/%2")
01519                                 .arg(prefix)
01520                                 .arg(fList.at(0));
01521             else
01522                 icon_file = generate_file_url("Videos", host, fList.at(0));
01523         }
01524     }
01525 
01526     if (!icon_file.isEmpty())
01527         LOG(VB_GENERAL, LOG_DEBUG, QString("Found Image : %1 :")
01528                 .arg(icon_file));
01529     else
01530         LOG(VB_GENERAL, LOG_DEBUG, QString("Could not find cover Image : %1 ")
01531                 .arg(prefix));
01532 
01533     if (IsDefaultCoverFile(icon_file))
01534         icon_file.clear();
01535 
01536     return icon_file;
01537 }
01538 
01543 QString VideoDialog::GetCoverImage(MythGenericTree *node)
01544 {
01545     int nodeInt = node->getInt();
01546 
01547     QString icon_file;
01548 
01549     if (nodeInt  == kSubFolder)  // subdirectory
01550     {
01551         // load folder icon
01552         QString folder_path = node->GetData().value<TreeNodeData>().GetPath();
01553         QString host = node->GetData().value<TreeNodeData>().GetHost();
01554         QString prefix = node->GetData().value<TreeNodeData>().GetPrefix();
01555 
01556         if (folder_path.startsWith("myth://"))
01557             folder_path = folder_path.right(folder_path.length()
01558                                 - folder_path.lastIndexOf("//") - 1);
01559 
01560         QString filename = QString("%1/folder").arg(folder_path);
01561 
01562 #if 0
01563         LOG(VB_GENERAL, LOG_DEBUG,
01564             QString("GetCoverImage host : %1  prefix : %2 file : %3")
01565                 .arg(host).arg(prefix).arg(filename));
01566 #endif
01567 
01568         QStringList test_files;
01569         test_files.append(filename + ".png");
01570         test_files.append(filename + ".jpg");
01571         test_files.append(filename + ".gif");
01572         bool foundCover;
01573 
01574         for (QStringList::const_iterator tfp = test_files.begin();
01575                 tfp != test_files.end(); ++tfp)
01576         {
01577             QString imagePath = *tfp;
01578 #if 0
01579             LOG(VB_GENERAL, LOG_DEBUG, QString("Cover check :%1 : ").arg(*tfp));
01580 #endif
01581 
01582             foundCover = false;
01583             if (!host.isEmpty())
01584             {
01585                 // Strip out any extra /'s
01586                 imagePath.replace("//", "/");
01587                 prefix.replace("//","/");
01588                 imagePath = imagePath.right(imagePath.length() - (prefix.length() + 1));
01589                 QString tmpCover = RemoteImageCheck(host, imagePath);
01590 
01591                 if (!tmpCover.isEmpty())
01592                 {
01593                     foundCover = true;
01594                     imagePath = tmpCover;
01595                 }
01596             }
01597             else
01598                 foundCover = QFile::exists(imagePath);
01599 
01600             if (foundCover)
01601             {
01602                 icon_file = imagePath;
01603                 break;
01604             }
01605         }
01606 
01607         // If we found nothing, load the first image we find
01608         if (icon_file.isEmpty())
01609         {
01610             QStringList imageTypes;
01611             imageTypes.append("*.png");
01612             imageTypes.append("*.jpg");
01613             imageTypes.append("*.gif");
01614 
01615             QStringList fList;
01616 
01617             if (!host.isEmpty())
01618             {
01619                 // TODO: This can likely get a little cleaner
01620 
01621                 QStringList dirs = GetVideoDirsByHost(host);
01622 
01623                 if (!dirs.isEmpty())
01624                 {
01625                     for (QStringList::const_iterator iter = dirs.begin();
01626                          iter != dirs.end(); ++iter)
01627                     {
01628                         QUrl sgurl = *iter;
01629                         QString path = sgurl.path();
01630 
01631                         QString subdir = folder_path.right(folder_path.length() - (prefix.length() + 2));
01632 
01633                         path = path + "/" + subdir;
01634 
01635                         QStringList tmpList;
01636                         bool ok = RemoteGetFileList(host, path, &tmpList, "Videos");
01637 
01638                         if (ok)
01639                         {
01640                             for (QStringList::const_iterator pattern = imageTypes.begin();
01641                                  pattern != imageTypes.end(); ++pattern)
01642                             {
01643                                 QRegExp rx(*pattern);
01644                                 rx.setPatternSyntax(QRegExp::Wildcard);
01645                                 QStringList matches = tmpList.filter(rx);
01646                                 if (!matches.isEmpty())
01647                                 {
01648                                     fList.clear();
01649                                     fList.append(subdir + "/" + matches.at(0).split("::").at(1));
01650                                     break;
01651                                 }
01652                             }
01653 
01654                             break;
01655                         }
01656                     }
01657                 }
01658 
01659             }
01660             else
01661             {
01662                 QDir vidDir(folder_path);
01663                 vidDir.setNameFilters(imageTypes);
01664                 fList = vidDir.entryList();
01665             }
01666 
01667             // Take the Coverfile for the first valid node in the dir, if it exists.
01668             if (icon_file.isEmpty())
01669             {
01670                 int list_count = node->visibleChildCount();
01671                 if (list_count > 0)
01672                 {
01673                     for (int i = 0; i < list_count; i++)
01674                     {
01675                         MythGenericTree *subnode = node->getVisibleChildAt(i);
01676                         if (subnode)
01677                         {
01678                             VideoMetadata *metadata = GetMetadataPtrFromNode(subnode);
01679                             if (metadata)
01680                             {
01681                                 if (!metadata->GetHost().isEmpty() &&
01682                                     !metadata->GetCoverFile().startsWith("/"))
01683                                 {
01684                                     QString test_file = generate_file_url("Coverart",
01685                                                 metadata->GetHost(), metadata->GetCoverFile());
01686                                     if (!test_file.endsWith("/") && !test_file.isEmpty() &&
01687                                         !IsDefaultCoverFile(test_file))
01688                                     {
01689                                         icon_file = test_file;
01690                                         break;
01691                                     }
01692                                 }
01693                                 else
01694                                 {
01695                                     QString test_file = metadata->GetCoverFile();
01696                                     if (!test_file.isEmpty() &&
01697                                         !IsDefaultCoverFile(test_file))
01698                                     {
01699                                         icon_file = test_file;
01700                                         break;
01701                                     }
01702                                 }
01703                             }
01704                         }
01705                     }
01706                 }
01707             }
01708 
01709             if (!fList.isEmpty())
01710             {
01711                 if (host.isEmpty())
01712                     icon_file = QString("%1/%2")
01713                                     .arg(folder_path)
01714                                     .arg(fList.at(0));
01715                 else
01716                     icon_file = generate_file_url("Videos", host, fList.at(0));
01717             }
01718         }
01719 
01720         if (!icon_file.isEmpty())
01721             LOG(VB_GENERAL, LOG_DEBUG, QString("Found Image : %1 :")
01722                     .arg(icon_file));
01723         else
01724             LOG(VB_GENERAL, LOG_DEBUG,
01725                 QString("Could not find folder cover Image : %1 ")
01726                     .arg(folder_path));
01727     }
01728     else
01729     {
01730         const VideoMetadata *metadata = GetMetadataPtrFromNode(node);
01731 
01732         if (metadata)
01733         {
01734             if (metadata->IsHostSet() &&
01735                 !metadata->GetCoverFile().startsWith("/") &&
01736                 !IsDefaultCoverFile(metadata->GetCoverFile()))
01737             {
01738                 icon_file = generate_file_url("Coverart", metadata->GetHost(),
01739                         metadata->GetCoverFile());
01740             }
01741             else
01742             {
01743                 icon_file = metadata->GetCoverFile();
01744             }
01745         }
01746     }
01747 
01748     if (IsDefaultCoverFile(icon_file))
01749         icon_file.clear();
01750 
01751     return icon_file;
01752 }
01753 
01765 QString VideoDialog::GetFirstImage(MythGenericTree *node, QString type,
01766                                    QString gpnode, int levels)
01767 {
01768     if (!node || type.isEmpty())
01769         return QString();
01770 
01771     QString icon_file;
01772 
01773     int list_count = node->visibleChildCount();
01774     if (list_count > 0)
01775     {
01776         QList<MythGenericTree *> subDirs;
01777         int maxRecurse = 1;
01778 
01779         for (int i = 0; i < list_count; i++)
01780         {
01781             MythGenericTree *subnode = node->getVisibleChildAt(i);
01782             if (subnode)
01783             {
01784                 if (subnode->childCount() > 0)
01785                     subDirs << subnode;
01786 
01787                 VideoMetadata *metadata = GetMetadataPtrFromNode(subnode);
01788                 if (metadata)
01789                 {
01790                     QString test_file;
01791                     QString host = metadata->GetHost();
01792                     QString title = metadata->GetTitle();
01793 
01794                     if (type == "Coverart" && !host.isEmpty() &&
01795                         !metadata->GetCoverFile().startsWith("/"))
01796                     {
01797                         test_file = generate_file_url("Coverart",
01798                                     host, metadata->GetCoverFile());
01799                     }
01800                     else if (type == "Coverart")
01801                         test_file = metadata->GetCoverFile();
01802 
01803                     if (!test_file.endsWith("/") && !test_file.isEmpty() &&
01804                         !IsDefaultCoverFile(test_file) && (gpnode.isEmpty() ||
01805                         (QString::compare(gpnode, title, Qt::CaseInsensitive) == 0)))
01806                     {
01807                         icon_file = test_file;
01808                         break;
01809                     }
01810 
01811                     if (type == "Fanart" && !host.isEmpty() &&
01812                         !metadata->GetFanart().startsWith("/"))
01813                     {
01814                         test_file = generate_file_url("Fanart",
01815                                     host, metadata->GetFanart());
01816                     }
01817                     else if (type == "Fanart")
01818                         test_file = metadata->GetFanart();
01819 
01820                     if (!test_file.endsWith("/") && !test_file.isEmpty() &&
01821                         test_file != VIDEO_FANART_DEFAULT && (gpnode.isEmpty() ||
01822                         (QString::compare(gpnode, title, Qt::CaseInsensitive) == 0)))
01823                     {
01824                         icon_file = test_file;
01825                         break;
01826                     }
01827 
01828                     if (type == "Banners" && !host.isEmpty() &&
01829                         !metadata->GetBanner().startsWith("/"))
01830                     {
01831                         test_file = generate_file_url("Banners",
01832                                     host, metadata->GetBanner());
01833                     }
01834                     else if (type == "Banners")
01835                         test_file = metadata->GetBanner();
01836 
01837                     if (!test_file.endsWith("/") && !test_file.isEmpty() &&
01838                         test_file != VIDEO_BANNER_DEFAULT && (gpnode.isEmpty() ||
01839                         (QString::compare(gpnode, title, Qt::CaseInsensitive) == 0)))
01840                     {
01841                         icon_file = test_file;
01842                         break;
01843                     }
01844 
01845                     if (type == "Screenshots" && !host.isEmpty() &&
01846                         !metadata->GetScreenshot().startsWith("/"))
01847                     {
01848                         test_file = generate_file_url("Screenshots",
01849                                     host, metadata->GetScreenshot());
01850                     }
01851                     else if (type == "Screenshots")
01852                         test_file = metadata->GetScreenshot();
01853 
01854                     if (!test_file.endsWith("/") && !test_file.isEmpty() &&
01855                        test_file != VIDEO_SCREENSHOT_DEFAULT && (gpnode.isEmpty() ||
01856                        (QString::compare(gpnode, title, Qt::CaseInsensitive) == 0)))
01857                     {
01858                         icon_file = test_file;
01859                         break;
01860                     }
01861                 }
01862             }
01863         }
01864         if (icon_file.isEmpty() && !subDirs.isEmpty())
01865         {
01866             QString test_file;
01867             int subDirCount = subDirs.count();
01868             for (int i = 0; i < subDirCount; i ++)
01869             {
01870                 if (levels < maxRecurse)
01871                 {
01872                     test_file = GetFirstImage(subDirs[i], type,
01873                                      node->getString(), levels + 1);
01874                     if (!test_file.isEmpty())
01875                     {
01876                         icon_file = test_file;
01877                         break;
01878                     }
01879                 }
01880             }
01881         }
01882     }
01883     return icon_file;
01884 }
01885 
01890 QString VideoDialog::GetScreenshot(MythGenericTree *node)
01891 {
01892     const int nodeInt = node->getInt();
01893 
01894     QString icon_file;
01895 
01896     if (nodeInt  == kSubFolder || nodeInt == kUpFolder)  // subdirectory
01897     {
01898         icon_file = VIDEO_SCREENSHOT_DEFAULT;
01899     }
01900     else
01901     {
01902         const VideoMetadata *metadata = GetMetadataPtrFromNode(node);
01903 
01904         if (metadata)
01905         {
01906             if (metadata->IsHostSet() &&
01907                     !metadata->GetScreenshot().startsWith("/") &&
01908                     !metadata->GetScreenshot().isEmpty())
01909             {
01910                 icon_file = generate_file_url("Screenshots", metadata->GetHost(),
01911                         metadata->GetScreenshot());
01912             }
01913             else
01914             {
01915                 icon_file = metadata->GetScreenshot();
01916             }
01917         }
01918     }
01919 
01920     if (IsDefaultScreenshot(icon_file))
01921         icon_file.clear();
01922 
01923     return icon_file;
01924 }
01925 
01930 QString VideoDialog::GetBanner(MythGenericTree *node)
01931 {
01932     const int nodeInt = node->getInt();
01933 
01934     if (nodeInt == kSubFolder || nodeInt == kUpFolder)
01935         return QString();
01936 
01937     QString icon_file;
01938     const VideoMetadata *metadata = GetMetadataPtrFromNode(node);
01939 
01940     if (metadata)
01941     {
01942         if (metadata->IsHostSet() &&
01943                !metadata->GetBanner().startsWith("/") &&
01944                !metadata->GetBanner().isEmpty())
01945         {
01946             icon_file = generate_file_url("Banners", metadata->GetHost(),
01947                     metadata->GetBanner());
01948         }
01949         else
01950         {
01951             icon_file = metadata->GetBanner();
01952         }
01953 
01954         if (IsDefaultBanner(icon_file))
01955             icon_file.clear();
01956     }
01957 
01958     return icon_file;
01959 }
01960 
01965 QString VideoDialog::GetFanart(MythGenericTree *node)
01966 {
01967     const int nodeInt = node->getInt();
01968 
01969     if (nodeInt  == kSubFolder || nodeInt == kUpFolder)  // subdirectory
01970         return QString();
01971 
01972     QString icon_file;
01973     const VideoMetadata *metadata = GetMetadataPtrFromNode(node);
01974 
01975     if (metadata)
01976     {
01977         if (metadata->IsHostSet() &&
01978                 !metadata->GetFanart().startsWith("/") &&
01979                 !metadata->GetFanart().isEmpty())
01980         {
01981             icon_file = generate_file_url("Fanart", metadata->GetHost(),
01982                     metadata->GetFanart());
01983         }
01984         else
01985         {
01986             icon_file = metadata->GetFanart();
01987         }
01988 
01989         if (IsDefaultFanart(icon_file))
01990             icon_file.clear();
01991     }
01992 
01993     return icon_file;
01994 }
01995 
02000 bool VideoDialog::keyPressEvent(QKeyEvent *levent)
02001 {
02002     if (GetFocusWidget()->keyPressEvent(levent))
02003         return true;
02004 
02005     bool handled = false;
02006     QStringList actions;
02007     handled = GetMythMainWindow()->TranslateKeyPress("Video", levent, actions);
02008 
02009     for (int i = 0; i < actions.size() && !handled; i++)
02010     {
02011         QString action = actions[i];
02012         handled = true;
02013 
02014         if (action == "INFO")
02015         {
02016             MythUIButtonListItem *item = GetItemCurrent();
02017             MythGenericTree *node = GetNodePtrFromButton(item);
02018             if (!m_menuPopup && node->getInt() != kUpFolder)
02019                 VideoMenu();
02020         }
02021         else if (action == "INCPARENT")
02022             shiftParental(1);
02023         else if (action == "DECPARENT")
02024             shiftParental(-1);
02025         else if (action == "1" || action == "2" ||
02026                  action == "3" || action == "4")
02027             setParentalLevel((ParentalLevel::Level)action.toInt());
02028         else if (action == "FILTER")
02029             ChangeFilter();
02030         else if (action == "MENU")
02031         {
02032             if (!m_menuPopup)
02033                 DisplayMenu();
02034         }
02035         else if (action == "PLAYALT")
02036         {
02037             if (!m_menuPopup && GetMetadata(GetItemCurrent()) &&
02038                 m_d->m_altPlayerEnabled)
02039                 playVideoAlt();
02040         }
02041         else if (action == "DOWNLOADDATA")
02042         {
02043             if (!m_menuPopup && GetMetadata(GetItemCurrent()))
02044                 VideoSearch();
02045         }
02046         else if (action == "INCSEARCH")
02047             searchStart();
02048         else if (action == "ITEMDETAIL")
02049             DoItemDetailShow();
02050         else if (action == "DELETE")
02051         {
02052             if (!m_menuPopup && GetMetadata(GetItemCurrent()))
02053                 RemoveVideo();
02054         }
02055         else if (action == "EDIT" && !m_menuPopup)
02056             EditMetadata();
02057         else if (action == "ESCAPE")
02058         {
02059             if (m_d->m_type != DLG_TREE
02060                     && !GetMythMainWindow()->IsExitingToMain()
02061                     && m_d->m_currentNode != m_d->m_rootNode)
02062                 handled = goBack();
02063             else
02064                 handled = false;
02065         }
02066         else
02067             handled = false;
02068     }
02069 
02070     if (!handled)
02071     {
02072         handled = GetMythMainWindow()->TranslateKeyPress("TV Frontend", levent,
02073                                                          actions);
02074 
02075         for (int i = 0; i < actions.size() && !handled; i++)
02076         {
02077             QString action = actions[i];
02078             if (action == "PLAYBACK")
02079             {
02080                 handled = true;
02081                 playVideo();
02082             }
02083         }
02084     }
02085 
02086     if (!handled && MythScreenType::keyPressEvent(levent))
02087         handled = true;
02088 
02089     return handled;
02090 }
02091 
02096 void VideoDialog::createBusyDialog(QString title)
02097 {
02098     if (m_busyPopup)
02099         return;
02100 
02101     QString message = title;
02102 
02103     m_busyPopup = new MythUIBusyDialog(message, m_popupStack,
02104             "mythvideobusydialog");
02105 
02106     if (m_busyPopup->Create())
02107         m_popupStack->AddScreen(m_busyPopup);
02108 }
02109 
02114 void VideoDialog::createOkDialog(QString title)
02115 {
02116     QString message = title;
02117 
02118     MythConfirmationDialog *okPopup =
02119             new MythConfirmationDialog(m_popupStack, message, false);
02120 
02121     if (okPopup->Create())
02122         m_popupStack->AddScreen(okPopup);
02123 }
02124 
02129 void VideoDialog::searchComplete(QString string)
02130 {
02131     LOG(VB_GENERAL, LOG_DEBUG, QString("Jumping to: %1").arg(string));
02132 
02133     MythGenericTree *parent = m_d->m_currentNode->getParent();
02134     QStringList childList;
02135     QList<MythGenericTree*>::iterator it;
02136     QList<MythGenericTree*> *children;
02137     QMap<int, QString> idTitle;
02138 
02139     if (parent && m_d->m_type == DLG_TREE)
02140         children = parent->getAllChildren();
02141     else
02142         children = m_d->m_currentNode->getAllChildren();
02143 
02144     for (it = children->begin(); it != children->end(); ++it)
02145     {
02146         MythGenericTree *child = *it;
02147         QString title = child->getString();
02148         int id = child->getPosition();
02149         idTitle.insert(id, title);
02150     }
02151 
02152     if (m_d->m_type == DLG_TREE)
02153     {
02154         MythGenericTree *parent = m_videoButtonTree->GetCurrentNode()->getParent();
02155         MythGenericTree *new_node = parent->getChildAt(idTitle.key(string));
02156         if (new_node)
02157         {
02158             m_videoButtonTree->SetCurrentNode(new_node);
02159             m_videoButtonTree->SetActive(true);
02160         }
02161     }
02162     else
02163         m_videoButtonList->SetItemCurrent(idTitle.key(string));
02164 }
02165 
02170 void VideoDialog::searchStart(void)
02171 {
02172     MythGenericTree *parent = m_d->m_currentNode->getParent();
02173 
02174     QStringList childList;
02175     QList<MythGenericTree*>::iterator it;
02176     QList<MythGenericTree*> *children;
02177     if (parent && m_d->m_type == DLG_TREE)
02178         children = parent->getAllChildren();
02179     else
02180         children = m_d->m_currentNode->getAllChildren();
02181 
02182     for (it = children->begin(); it != children->end(); ++it)
02183     {
02184         MythGenericTree *child = *it;
02185         childList << child->getString();
02186     }
02187 
02188     MythScreenStack *popupStack =
02189         GetMythMainWindow()->GetStack("popup stack");
02190     MythUISearchDialog *searchDialog = new MythUISearchDialog(popupStack,
02191         tr("Video Search"), childList, false, "");
02192 
02193     if (searchDialog->Create())
02194     {
02195         connect(searchDialog, SIGNAL(haveResult(QString)),
02196                 SLOT(searchComplete(QString)));
02197 
02198         popupStack->AddScreen(searchDialog);
02199     }
02200     else
02201         delete searchDialog;
02202 }
02203 
02208 bool VideoDialog::goBack()
02209 {
02210     bool handled = false;
02211 
02212     if (m_d->m_currentNode != m_d->m_rootNode)
02213     {
02214         MythGenericTree *lparent = m_d->m_currentNode->getParent();
02215         if (lparent)
02216         {
02217             SetCurrentNode(lparent);
02218 
02219             handled = true;
02220         }
02221     }
02222 
02223     loadData();
02224 
02225     return handled;
02226 }
02227 
02232 void VideoDialog::SetCurrentNode(MythGenericTree *node)
02233 {
02234     if (!node)
02235         return;
02236 
02237     m_d->m_currentNode = node;
02238 }
02239 
02244 void VideoDialog::UpdatePosition()
02245 {
02246     MythUIButtonListItem *ci = GetItemCurrent();
02247     MythUIButtonList *currentList = ci ? ci->parent() : 0;
02248 
02249     if (!currentList)
02250         return;
02251 
02252     CheckedSet(m_positionText, QString(tr("%1 of %2"))
02253             .arg(currentList->GetCurrentPos() + 1)
02254             .arg(currentList->GetCount()));
02255 }
02256 
02261 void VideoDialog::UpdateText(MythUIButtonListItem *item)
02262 {
02263     if (!item)
02264         return;
02265 
02266     MythUIButtonList *currentList = item->parent();
02267 
02268     if (!currentList)
02269         return;
02270 
02271     VideoMetadata *metadata = GetMetadata(item);
02272 
02273     MythGenericTree *node = GetNodePtrFromButton(item);
02274 
02275     if (!node)
02276         return;
02277 
02278     if (metadata)
02279     {
02280         MetadataMap metadataMap;
02281         metadata->toMap(metadataMap);
02282         SetTextFromMap(metadataMap);
02283     }
02284     else
02285     {
02286         MetadataMap metadataMap;
02287         ClearMap(metadataMap);
02288         SetTextFromMap(metadataMap);
02289     }
02290 
02291     ScreenCopyDest dest(this);
02292     CopyMetadataToUI(metadata, dest);
02293 
02294     if (node->getInt() == kSubFolder && !metadata)
02295     {
02296         QString cover = GetFirstImage(node, "Coverart");
02297         QString fanart = GetFirstImage(node, "Fanart");
02298         QString banner = GetFirstImage(node, "Banners");
02299         QString screenshot = GetFirstImage(node, "Screenshots");
02300         CheckedSet(m_coverImage, cover);
02301         CheckedSet(m_fanart, fanart);
02302         CheckedSet(m_banner, banner);
02303         CheckedSet(m_screenshot, screenshot);
02304     }
02305 
02306     if (!metadata)
02307         CheckedSet(m_titleText, item->GetText());
02308     UpdatePosition();
02309 
02310     if (m_d->m_currentNode)
02311     {
02312         CheckedSet(m_crumbText, m_d->m_currentNode->getRouteByString().join(" > "));
02313         CheckedSet(this, "foldername", m_d->m_currentNode->getString());
02314     }
02315 
02316     if (node && node->getInt() == kSubFolder)
02317         CheckedSet(this, "childcount",
02318                    QString("%1").arg(node->visibleChildCount()));
02319 
02320     if (node)
02321         node->becomeSelectedChild();
02322 }
02323 
02328 void VideoDialog::VideoMenu()
02329 {
02330     VideoMetadata *metadata = GetMetadata(GetItemCurrent());
02331     QString label;
02332 
02333     if (metadata)
02334     {
02335         if (!metadata->GetSubtitle().isEmpty())
02336             label = tr("Video Options\n%1\n%2").arg(metadata->GetTitle())
02337                                            .arg(metadata->GetSubtitle());
02338         else
02339             label = tr("Video Options\n%1").arg(metadata->GetTitle());
02340     }
02341     else
02342         label = tr("Video Options");
02343 
02344     MythMenu *menu = new MythMenu(label, this, "actions");
02345 
02346     MythUIButtonListItem *item = GetItemCurrent();
02347     MythGenericTree *node = GetNodePtrFromButton(item);
02348     if (metadata)
02349     {
02350         if (!metadata->GetTrailer().isEmpty() ||
02351                 gCoreContext->GetNumSetting("mythvideo.TrailersRandomEnabled", 0) ||
02352                 m_d->m_altPlayerEnabled)
02353             menu->AddItem(tr("Play..."), NULL, CreatePlayMenu());
02354         else
02355             menu->AddItem(tr("Play"), SLOT(playVideo()));
02356         if (metadata->GetWatched())
02357             menu->AddItem(tr("Mark as Unwatched"), SLOT(ToggleWatched()));
02358         else
02359             menu->AddItem(tr("Mark as Watched"), SLOT(ToggleWatched()));
02360         menu->AddItem(tr("Video Info"), NULL, CreateInfoMenu());
02361         menu->AddItem(tr("Change Video Details"), NULL, CreateManageMenu());
02362         menu->AddItem(tr("Delete"), SLOT(RemoveVideo()));
02363     }
02364     else if (node && node->getInt() != kUpFolder)
02365     {
02366         menu->AddItem(tr("Play Folder"), SLOT(playFolder()));
02367     }
02368 
02369 
02370     m_menuPopup = new MythDialogBox(menu, m_popupStack, "videomenupopup");
02371 
02372     if (m_menuPopup->Create())
02373         m_popupStack->AddScreen(m_menuPopup);
02374     else
02375         delete m_menuPopup;
02376 }
02377 
02383 MythMenu* VideoDialog::CreatePlayMenu()
02384 {
02385     VideoMetadata *metadata = GetMetadata(GetItemCurrent());
02386     QString label;
02387 
02388     if (metadata)
02389         label = tr("Playback Options\n%1").arg(metadata->GetTitle());
02390     else
02391         return NULL;
02392 
02393     MythMenu *menu = new MythMenu(label, this, "actions");
02394 
02395     menu->AddItem(tr("Play"), SLOT(playVideo()));
02396 
02397     if (m_d->m_altPlayerEnabled)
02398     {
02399         menu->AddItem(tr("Play in Alternate Player"), SLOT(playVideoAlt()));
02400     }
02401 
02402     if (gCoreContext->GetNumSetting("mythvideo.TrailersRandomEnabled", 0))
02403     {
02404          menu->AddItem(tr("Play With Trailers"), SLOT(playVideoWithTrailers()));
02405     }
02406 
02407     QString trailerFile = metadata->GetTrailer();
02408     if (QFile::exists(trailerFile) ||
02409         (!metadata->GetHost().isEmpty() && !trailerFile.isEmpty()))
02410     {
02411         menu->AddItem(tr("Play Trailer"), SLOT(playTrailer()));
02412     }
02413 
02414     return menu;
02415 }
02416 
02421 void VideoDialog::DisplayMenu()
02422 {
02423     QString label = tr("Video Display Menu");
02424 
02425     MythMenu *menu = new MythMenu(label, this, "display");
02426 
02427     menu->AddItem(tr("Scan For Changes"), SLOT(doVideoScan()));
02428     menu->AddItem(tr("Retrieve All Details"), SLOT(VideoAutoSearch()));
02429     menu->AddItem(tr("Filter Display"), SLOT(ChangeFilter()));
02430     menu->AddItem(tr("Browse By..."), NULL, CreateMetadataBrowseMenu());
02431     menu->AddItem(tr("Change View"), NULL, CreateViewMenu());
02432     menu->AddItem(tr("Settings"), NULL, CreateSettingsMenu());
02433 
02434     m_menuPopup = new MythDialogBox(menu, m_popupStack, "videomenupopup");
02435 
02436     if (m_menuPopup->Create())
02437         m_popupStack->AddScreen(m_menuPopup);
02438     else
02439         delete m_menuPopup;
02440 }
02441 
02446 MythMenu* VideoDialog::CreateViewMenu()
02447 {
02448     QString label = tr("Change View");
02449 
02450     MythMenu *menu = new MythMenu(label, this, "view");
02451 
02452     if (!(m_d->m_type & DLG_BROWSER))
02453         menu->AddItem(tr("Switch to Browse View"), SLOT(SwitchBrowse()));
02454 
02455     if (!(m_d->m_type & DLG_GALLERY))
02456         menu->AddItem(tr("Switch to Gallery View"), SLOT(SwitchGallery()));
02457 
02458     if (!(m_d->m_type & DLG_TREE))
02459         menu->AddItem(tr("Switch to List View"), SLOT(SwitchTree()));
02460 
02461     if (!(m_d->m_type & DLG_MANAGER))
02462         menu->AddItem(tr("Switch to Manage View"), SLOT(SwitchManager()));
02463 
02464     if (m_d->m_isFlatList)
02465         menu->AddItem(tr("Show Directory Structure"), SLOT(ToggleFlatView()));
02466     else
02467         menu->AddItem(tr("Hide Directory Structure"), SLOT(ToggleFlatView()));
02468 
02469     if (m_d->m_isFileBrowser)
02470         menu->AddItem(tr("Browse Library (recommended)"), SLOT(ToggleBrowseMode()));
02471     else
02472         menu->AddItem(tr("Browse Filesystem (slow)"), SLOT(ToggleBrowseMode()));
02473 
02474 
02475     return menu;
02476 }
02477 
02482 MythMenu* VideoDialog::CreateSettingsMenu()
02483 {
02484     QString label = tr("Video Settings");
02485 
02486     MythMenu *menu = new MythMenu(label, this, "settings");
02487 
02488     menu->AddItem(tr("Player Settings"), SLOT(ShowPlayerSettings()));
02489     menu->AddItem(tr("Metadata Settings"), SLOT(ShowMetadataSettings()));
02490     menu->AddItem(tr("File Type Settings"), SLOT(ShowExtensionSettings()));
02491 
02492     return menu;
02493 }
02494 
02499 void VideoDialog::ShowPlayerSettings()
02500 {
02501     PlayerSettings *ps = new PlayerSettings(m_mainStack, "player settings");
02502 
02503     if (ps->Create())
02504         m_mainStack->AddScreen(ps);
02505     else
02506         delete ps;
02507 }
02508 
02513 void VideoDialog::ShowMetadataSettings()
02514 {
02515     MetadataSettings *ms = new MetadataSettings(m_mainStack, "metadata settings");
02516 
02517     if (ms->Create())
02518         m_mainStack->AddScreen(ms);
02519     else
02520         delete ms;
02521 }
02522 
02527 void VideoDialog::ShowExtensionSettings()
02528 {
02529     FileAssocDialog *fa = new FileAssocDialog(m_mainStack, "fa dialog");
02530 
02531     if (fa->Create())
02532         m_mainStack->AddScreen(fa);
02533     else
02534         delete fa;
02535 }
02536 
02541 MythMenu* VideoDialog::CreateMetadataBrowseMenu()
02542 {
02543     QString label = tr("Browse By");
02544 
02545     MythMenu *menu = new MythMenu(label, this, "metadata");
02546 
02547     if (m_d->m_groupType != BRS_CAST)
02548         menu->AddItem(tr("Cast"), SLOT(SwitchVideoCastGroup()));
02549 
02550     if (m_d->m_groupType != BRS_CATEGORY)
02551         menu->AddItem(tr("Category"), SLOT(SwitchVideoCategoryGroup()));
02552 
02553     if (m_d->m_groupType != BRS_INSERTDATE)
02554         menu->AddItem(tr("Date Added"), SLOT(SwitchVideoInsertDateGroup()));
02555 
02556     if (m_d->m_groupType != BRS_DIRECTOR)
02557         menu->AddItem(tr("Director"), SLOT(SwitchVideoDirectorGroup()));
02558 
02559     if (m_d->m_groupType != BRS_STUDIO)
02560         menu->AddItem(tr("Studio"), SLOT(SwitchVideoStudioGroup()));
02561 
02562     if (m_d->m_groupType != BRS_FOLDER)
02563         menu->AddItem(tr("Folder"), SLOT(SwitchVideoFolderGroup()));
02564 
02565     if (m_d->m_groupType != BRS_GENRE)
02566         menu->AddItem(tr("Genre"), SLOT(SwitchVideoGenreGroup()));
02567 
02568     if (m_d->m_groupType != BRS_TVMOVIE)
02569         menu->AddItem(tr("TV/Movies"),SLOT(SwitchVideoTVMovieGroup()));
02570 
02571     if (m_d->m_groupType != BRS_USERRATING)
02572         menu->AddItem(tr("User Rating"), SLOT(SwitchVideoUserRatingGroup()));
02573 
02574     if (m_d->m_groupType != BRS_YEAR)
02575         menu->AddItem(tr("Year"), SLOT(SwitchVideoYearGroup()));
02576 
02577     return menu;
02578 }
02579 
02584 MythMenu *VideoDialog::CreateInfoMenu()
02585 {
02586     QString label = tr("Video Info");
02587 
02588     MythMenu *menu = new MythMenu(label, this, "info");
02589 
02590     if (ItemDetailPopup::Exists())
02591         menu->AddItem(tr("View Details"), SLOT(DoItemDetailShow()));
02592 
02593     menu->AddItem(tr("View Full Plot"), SLOT(ViewPlot()));
02594 
02595     VideoMetadata *metadata = GetMetadata(GetItemCurrent());
02596     if (metadata)
02597     {
02598         if (!metadata->GetCast().empty())
02599             menu->AddItem(tr("View Cast"), SLOT(ShowCastDialog()));
02600         if (!metadata->GetHomepage().isEmpty())
02601             menu->AddItem(tr("View Homepage"), SLOT(ShowHomepage()));
02602     }
02603 
02604     return menu;
02605 }
02606 
02611 MythMenu *VideoDialog::CreateManageMenu()
02612 {
02613     QString label = tr("Manage Video Details");
02614 
02615     MythMenu *menu = new MythMenu(label, this, "manage");
02616 
02617     VideoMetadata *metadata = GetMetadata(GetItemCurrent());
02618 
02619     menu->AddItem(tr("Edit Details"), SLOT(EditMetadata()));
02620     menu->AddItem(tr("Retrieve Details"), SLOT(VideoSearch()));
02621     if (metadata->GetProcessed())
02622         menu->AddItem(tr("Allow Updates"), SLOT(ToggleProcess()));
02623     else
02624         menu->AddItem(tr("Disable Updates"), SLOT(ToggleProcess()));
02625     menu->AddItem(tr("Reset Details"), SLOT(ResetMetadata()));
02626 
02627     return menu;
02628 }
02629 
02630 void VideoDialog::ToggleProcess()
02631 {
02632     VideoMetadata *metadata = GetMetadata(GetItemCurrent());
02633     if (metadata)
02634     {
02635         metadata->SetProcessed(!metadata->GetProcessed());
02636         metadata->UpdateDatabase();
02637 
02638         refreshData();
02639     }
02640 }
02641 
02646 void VideoDialog::ToggleBrowseMode()
02647 {
02648     m_d->m_isFileBrowser = !m_d->m_isFileBrowser;
02649     gCoreContext->SaveSetting("VideoDialogNoDB",
02650             QString("%1").arg((int)m_d->m_isFileBrowser));
02651     reloadData();
02652 }
02653 
02658 void VideoDialog::ToggleFlatView()
02659 {
02660     m_d->m_isFlatList = !m_d->m_isFlatList;
02661     gCoreContext->SaveSetting(QString("mythvideo.folder_view_%1").arg(m_d->m_type),
02662                          QString("%1").arg((int)m_d->m_isFlatList));
02663     // TODO: This forces a complete tree rebuild, this is SLOW and shouldn't
02664     // be necessary since MythGenericTree can do a flat view without a rebuild,
02665     // I just don't want to re-write VideoList just now
02666     reloadData();
02667 }
02668 
02673 void VideoDialog::handleDirSelect(MythGenericTree *node)
02674 {
02675     SetCurrentNode(node);
02676     loadData();
02677 }
02678 
02683 void VideoDialog::handleDynamicDirSelect(MythGenericTree *node)
02684 {
02685     QStringList route = node->getRouteByString();
02686     if (m_d->m_videoList && m_d->m_videoList->refreshNode(node))
02687         reloadData();
02688     m_videoButtonTree->SetNodeByString(route);
02689 }
02690 
02695 void VideoDialog::handleSelect(MythUIButtonListItem *item)
02696 {
02697     MythGenericTree *node = GetNodePtrFromButton(item);
02698     int nodeInt = node->getInt();
02699 
02700     switch (nodeInt)
02701     {
02702         case kDynamicSubFolder:
02703             handleDynamicDirSelect(node);
02704             break;
02705         case kSubFolder:
02706             handleDirSelect(node);
02707             break;
02708         case kUpFolder:
02709             goBack();
02710             break;
02711         default:
02712         {
02713             bool doPlay = true;
02714             if (m_d->m_type == DLG_GALLERY)
02715             {
02716                 doPlay = !DoItemDetailShow();
02717             }
02718 
02719             if (doPlay)
02720                 playVideo();
02721         }
02722     };
02723 }
02724 
02729 void VideoDialog::SwitchTree()
02730 {
02731     SwitchLayout(DLG_TREE, m_d->m_browse);
02732 }
02733 
02738 void VideoDialog::SwitchGallery()
02739 {
02740     SwitchLayout(DLG_GALLERY, m_d->m_browse);
02741 }
02742 
02747 void VideoDialog::SwitchBrowse()
02748 {
02749     SwitchLayout(DLG_BROWSER, m_d->m_browse);
02750 }
02751 
02756 void VideoDialog::SwitchManager()
02757 {
02758     SwitchLayout(DLG_MANAGER, m_d->m_browse);
02759 }
02760 
02765 void VideoDialog::SwitchVideoFolderGroup()
02766 {
02767     SwitchLayout(m_d->m_type, BRS_FOLDER);
02768 }
02769 
02774 void VideoDialog::SwitchVideoGenreGroup()
02775 {
02776     SwitchLayout(m_d->m_type, BRS_GENRE);
02777 }
02778 
02783 void VideoDialog::SwitchVideoCategoryGroup()
02784 {
02785    SwitchLayout(m_d->m_type, BRS_CATEGORY);
02786 }
02787 
02792 void VideoDialog::SwitchVideoYearGroup()
02793 {
02794    SwitchLayout(m_d->m_type, BRS_YEAR);
02795 }
02796 
02801 void VideoDialog::SwitchVideoDirectorGroup()
02802 {
02803    SwitchLayout(m_d->m_type, BRS_DIRECTOR);
02804 }
02805 
02810 void VideoDialog::SwitchVideoStudioGroup()
02811 {
02812    SwitchLayout(m_d->m_type, BRS_STUDIO);
02813 }
02814 
02819 void VideoDialog::SwitchVideoCastGroup()
02820 {
02821    SwitchLayout(m_d->m_type, BRS_CAST);
02822 }
02823 
02828 void VideoDialog::SwitchVideoUserRatingGroup()
02829 {
02830    SwitchLayout(m_d->m_type, BRS_USERRATING);
02831 }
02832 
02837 void VideoDialog::SwitchVideoInsertDateGroup()
02838 {
02839    SwitchLayout(m_d->m_type, BRS_INSERTDATE);
02840 }
02841 
02846 void VideoDialog::SwitchVideoTVMovieGroup()
02847 {
02848    SwitchLayout(m_d->m_type, BRS_TVMOVIE);
02849 }
02850 
02855 void VideoDialog::SwitchLayout(DialogType type, BrowseType browse)
02856 {
02857     m_d->m_switchingLayout = true;
02858 
02859     // save current position so it can be restored after the switch
02860     SavePosition();
02861 
02862     VideoDialog *mythvideo =
02863             new VideoDialog(GetMythMainWindow()->GetMainStack(), "mythvideo",
02864                     m_d->m_videoList, type, browse);
02865 
02866     if (mythvideo->Create())
02867     {
02868         gCoreContext->SaveSetting("Default MythVideo View", type);
02869         gCoreContext->SaveSetting("mythvideo.db_group_type", browse);
02870         MythScreenStack *screenStack = GetScreenStack();
02871         screenStack->AddScreen(mythvideo);
02872         screenStack->PopScreen(this, false, false);
02873         deleteLater();
02874     }
02875     else
02876     {
02877         ShowOkPopup(tr("An error occurred when switching views."));
02878     }
02879 }
02880 
02885 void VideoDialog::ViewPlot()
02886 {
02887     VideoMetadata *metadata = GetMetadata(GetItemCurrent());
02888 
02889     PlotDialog *plotdialog = new PlotDialog(m_popupStack, metadata);
02890 
02891     if (plotdialog->Create())
02892         m_popupStack->AddScreen(plotdialog);
02893 }
02894 
02899 bool VideoDialog::DoItemDetailShow()
02900 {
02901     VideoMetadata *metadata = GetMetadata(GetItemCurrent());
02902 
02903     if (metadata)
02904     {
02905         MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
02906         ItemDetailPopup *idp = new ItemDetailPopup(mainStack, metadata,
02907                 m_d->m_videoList->getListCache());
02908 
02909         if (idp->Create())
02910         {
02911             mainStack->AddScreen(idp);
02912             return true;
02913         }
02914     }
02915 
02916     return false;
02917 }
02918 
02923 void VideoDialog::ShowCastDialog()
02924 {
02925     VideoMetadata *metadata = GetMetadata(GetItemCurrent());
02926 
02927     CastDialog *castdialog = new CastDialog(m_popupStack, metadata);
02928 
02929     if (castdialog->Create())
02930         m_popupStack->AddScreen(castdialog);
02931 }
02932 
02933 void VideoDialog::ShowHomepage()
02934 {
02935     VideoMetadata *metadata = GetMetadata(GetItemCurrent());
02936 
02937     if (!metadata)
02938         return;
02939 
02940     QString url = metadata->GetHomepage();
02941 
02942     if (url.isEmpty())
02943         return;
02944 
02945     QString browser = gCoreContext->GetSetting("WebBrowserCommand", "");
02946     QString zoom = gCoreContext->GetSetting("WebBrowserZoomLevel", "1.0");
02947 
02948     if (browser.isEmpty())
02949     {
02950         ShowOkPopup(tr("No browser command set! MythVideo needs MythBrowser "
02951                        "installed to display the homepage."));
02952         return;
02953     }
02954 
02955     if (browser.toLower() == "internal")
02956     {
02957         GetMythMainWindow()->HandleMedia("WebBrowser", url);
02958         return;
02959     }
02960     else
02961     {
02962         QString cmd = browser;
02963         cmd.replace("%ZOOM%", zoom);
02964         cmd.replace("%URL%", url);
02965         cmd.replace('\'', "%27");
02966         cmd.replace("&","\\&");
02967         cmd.replace(";","\\;");
02968 
02969         GetMythMainWindow()->AllowInput(false);
02970         myth_system(cmd, kMSDontDisableDrawing);
02971         GetMythMainWindow()->AllowInput(true);
02972         return;
02973     }
02974 }
02975 
02980 void VideoDialog::playVideo()
02981 {
02982     VideoMetadata *metadata = GetMetadata(GetItemCurrent());
02983     if (metadata)
02984         PlayVideo(metadata->GetFilename(), m_d->m_videoList->getListCache());
02985 }
02986 
02991 void VideoDialog::playVideoAlt()
02992 {
02993     VideoMetadata *metadata = GetMetadata(GetItemCurrent());
02994     if (metadata)
02995         PlayVideo(metadata->GetFilename(),
02996                   m_d->m_videoList->getListCache(), true);
02997 }
02998 
03003 void VideoDialog::playFolder()
03004 {
03005     const int WATCHED_WATERMARK = 10000; // Play less then this milisec and the chain of
03006                                          // videos will not be followed when
03007                                          // playing.
03008     QTime playing_time;
03009 
03010     MythUIButtonListItem *item = GetItemCurrent();
03011     MythGenericTree *node = GetNodePtrFromButton(item);
03012     int list_count;
03013 
03014     if (node && !(node->getInt() >= 0))
03015         list_count = node->childCount();
03016     else
03017         return;
03018 
03019     if (list_count > 0)
03020     {
03021         bool video_started = false;
03022         int i = 0;
03023         while (i < list_count &&
03024                (!video_started || playing_time.elapsed() > WATCHED_WATERMARK))
03025         {
03026             MythGenericTree *subnode = node->getChildAt(i);
03027             if (subnode)
03028             {
03029                 VideoMetadata *metadata = GetMetadataPtrFromNode(subnode);
03030                 if (metadata)
03031                 {
03032                     playing_time.start();
03033                     video_started = true;
03034                     PlayVideo(metadata->GetFilename(),
03035                               m_d->m_videoList->getListCache());
03036                 }
03037             }
03038             i++;
03039         }
03040     }
03041 }
03042 
03043 namespace
03044 {
03045     struct SimpleCollect : public DirectoryHandler
03046     {
03047         SimpleCollect(QStringList &fileList) : m_fileList(fileList) {}
03048 
03049         DirectoryHandler *newDir(const QString &dirName,
03050                 const QString &fqDirName)
03051         {
03052             (void) dirName;
03053             (void) fqDirName;
03054             return this;
03055         }
03056 
03057         void handleFile(const QString &fileName, const QString &fqFileName,
03058                 const QString &extension, const QString &host)
03059         {
03060             (void) fileName;
03061             (void) extension;
03062             (void) host;
03063             m_fileList.push_back(fqFileName);
03064         }
03065 
03066       private:
03067         QStringList &m_fileList;
03068     };
03069 
03070     QStringList GetTrailersInDirectory(const QString &startDir)
03071     {
03072         FileAssociations::ext_ignore_list extensions;
03073         FileAssociations::getFileAssociation()
03074                 .getExtensionIgnoreList(extensions);
03075         QStringList ret;
03076         SimpleCollect sc(ret);
03077 
03078         (void) ScanVideoDirectory(startDir, &sc, extensions, false);
03079         return ret;
03080     }
03081 }
03082 
03087 void VideoDialog::playVideoWithTrailers()
03088 {
03089     VideoMetadata *metadata = GetMetadata(GetItemCurrent());
03090     if (!metadata) return;
03091 
03092     QStringList trailers = GetTrailersInDirectory(gCoreContext->
03093             GetSetting("mythvideo.TrailersDir"));
03094 
03095     if (trailers.isEmpty())
03096         return;
03097 
03098     const int trailersToPlay =
03099             gCoreContext->GetNumSetting("mythvideo.TrailersRandomCount");
03100 
03101     int i = 0;
03102     while (!trailers.isEmpty() && i < trailersToPlay)
03103     {
03104         ++i;
03105         QString trailer = trailers.takeAt(random() % trailers.size());
03106 
03107         LOG(VB_GENERAL, LOG_DEBUG,
03108             QString("Random trailer to play will be: %1").arg(trailer));
03109 
03110         VideoPlayerCommand::PlayerFor(trailer).Play();
03111     }
03112 
03113     PlayVideo(metadata->GetFilename(), m_d->m_videoList->getListCache());
03114 }
03115 
03120 void VideoDialog::playTrailer()
03121 {
03122     VideoMetadata *metadata = GetMetadata(GetItemCurrent());
03123     if (!metadata) return;
03124     QString url;
03125 
03126     if (metadata->IsHostSet() && !metadata->GetTrailer().startsWith("/"))
03127         url = generate_file_url("Trailers", metadata->GetHost(),
03128                         metadata->GetTrailer());
03129     else
03130         url = metadata->GetTrailer();
03131 
03132     VideoPlayerCommand::PlayerFor(url).Play();
03133 }
03134 
03139 void VideoDialog::setParentalLevel(const ParentalLevel::Level &level)
03140 {
03141     m_d->m_parentalLevel.SetLevel(level);
03142 }
03143 
03148 void VideoDialog::shiftParental(int amount)
03149 {
03150     setParentalLevel(ParentalLevel(m_d->m_parentalLevel.GetLevel()
03151                     .GetLevel() + amount).GetLevel());
03152 }
03153 
03158 void VideoDialog::ChangeFilter()
03159 {
03160     MythScreenStack *mainStack = GetScreenStack();
03161 
03162     VideoFilterDialog *filterdialog = new VideoFilterDialog(mainStack,
03163             "videodialogfilters", m_d->m_videoList.get());
03164 
03165     if (filterdialog->Create())
03166         mainStack->AddScreen(filterdialog);
03167 
03168     connect(filterdialog, SIGNAL(filterChanged()), SLOT(reloadData()));
03169 }
03170 
03175 VideoMetadata *VideoDialog::GetMetadata(MythUIButtonListItem *item)
03176 {
03177     VideoMetadata *metadata = NULL;
03178 
03179     if (item)
03180     {
03181         MythGenericTree *node = GetNodePtrFromButton(item);
03182         if (node)
03183         {
03184             int nodeInt = node->getInt();
03185 
03186             if (nodeInt >= 0)
03187                 metadata = GetMetadataPtrFromNode(node);
03188         }
03189     }
03190 
03191     return metadata;
03192 }
03193 
03194 void VideoDialog::customEvent(QEvent *levent)
03195 {
03196     if (levent->type() == MetadataFactoryMultiResult::kEventType)
03197     {
03198         MetadataFactoryMultiResult *mfmr = dynamic_cast<MetadataFactoryMultiResult*>(levent);
03199 
03200         if (!mfmr)
03201             return;
03202 
03203         MetadataLookupList list = mfmr->results;
03204 
03205         if (m_busyPopup)
03206         {
03207             m_busyPopup->Close();
03208             m_busyPopup = NULL;
03209         }
03210 
03211         if (list.count() > 1)
03212         {
03213             MetadataResultsDialog *resultsdialog =
03214                   new MetadataResultsDialog(m_popupStack, list);
03215 
03216             connect(resultsdialog, SIGNAL(haveResult(MetadataLookup*)),
03217                     SLOT(OnVideoSearchListSelection(MetadataLookup*)),
03218                     Qt::QueuedConnection);
03219 
03220             if (resultsdialog->Create())
03221                 m_popupStack->AddScreen(resultsdialog);
03222         }
03223     }
03224     else if (levent->type() == MetadataFactorySingleResult::kEventType)
03225     {
03226         MetadataFactorySingleResult *mfsr = dynamic_cast<MetadataFactorySingleResult*>(levent);
03227 
03228         if (!mfsr)
03229             return;
03230 
03231         MetadataLookup *lookup = mfsr->result;
03232 
03233         if (!lookup)
03234             return;
03235 
03236         OnVideoSearchDone(lookup);
03237     }
03238     else if (levent->type() == MetadataFactoryNoResult::kEventType)
03239     {
03240         MetadataFactoryNoResult *mfnr = dynamic_cast<MetadataFactoryNoResult*>(levent);
03241 
03242         if (!mfnr)
03243             return;
03244 
03245         MetadataLookup *lookup = mfnr->result;
03246 
03247         if (!lookup)
03248             return;
03249 
03250         if (m_busyPopup)
03251         {
03252             m_busyPopup->Close();
03253             m_busyPopup = NULL;
03254         }
03255 
03256         VideoMetadata *metadata =
03257             qVariantValue<VideoMetadata *>(lookup->GetData());
03258         if (metadata)
03259         {
03260             metadata->SetProcessed(true);
03261             metadata->UpdateDatabase();
03262         }
03263         LOG(VB_GENERAL, LOG_INFO,
03264             QString("No results found for %1 %2 %3").arg(lookup->GetTitle())
03265                 .arg(lookup->GetSeason()).arg(lookup->GetEpisode()));
03266     }
03267     else if (levent->type() == DialogCompletionEvent::kEventType)
03268     {
03269         DialogCompletionEvent *dce = static_cast<DialogCompletionEvent *>(levent);
03270         QString id = dce->GetId();
03271 
03272         if (id == "scanprompt")
03273         {
03274             int result = dce->GetResult();
03275             if (result == 1)
03276                 doVideoScan();
03277         }
03278         else
03279             m_menuPopup = NULL;
03280     }
03281 }
03282 
03283 void VideoDialog::OnVideoImageSetDone(VideoMetadata *metadata)
03284 {
03285     // The metadata has some cover file set
03286      if (m_busyPopup)
03287      {
03288          m_busyPopup->Close();
03289          m_busyPopup = NULL;
03290      }
03291 
03292     metadata->SetProcessed(true);
03293     metadata->UpdateDatabase();
03294 
03295     MythUIButtonListItem *item = GetItemByMetadata(metadata);
03296     if (item != NULL)
03297         UpdateItem(item);
03298 }
03299 
03300 MythUIButtonListItem *VideoDialog::GetItemCurrent()
03301 {
03302     if (m_videoButtonTree)
03303     {
03304         return m_videoButtonTree->GetItemCurrent();
03305     }
03306 
03307     return m_videoButtonList->GetItemCurrent();
03308 }
03309 
03310 MythUIButtonListItem *VideoDialog::GetItemByMetadata(VideoMetadata *metadata)
03311 {
03312     if (m_videoButtonTree)
03313     {
03314         return m_videoButtonTree->GetItemCurrent();
03315     }
03316 
03317     QList<MythGenericTree*>::iterator it;
03318     QList<MythGenericTree*> *children;
03319     QMap<int, int> idPosition;
03320 
03321     children = m_d->m_currentNode->getAllChildren();
03322 
03323     for (it = children->begin(); it != children->end(); ++it)
03324     {
03325         MythGenericTree *child = *it;
03326         int nodeInt = child->getInt();
03327         if (nodeInt != kSubFolder && nodeInt != kUpFolder)
03328         {
03329             VideoMetadata *listmeta =
03330                         GetMetadataPtrFromNode(child);
03331             if (listmeta)
03332             {
03333                 int position = child->getPosition();
03334                 int id = listmeta->GetID();
03335                 idPosition.insert(id, position);
03336             }
03337         }
03338     }
03339 
03340     return m_videoButtonList->GetItemAt(idPosition.value(metadata->GetID()));
03341 }
03342 
03343 void VideoDialog::VideoSearch(MythGenericTree *node,
03344                               bool automode)
03345 {
03346     if (!node)
03347         node = GetNodePtrFromButton(GetItemCurrent());
03348 
03349     if (!node)
03350         return;
03351 
03352     VideoMetadata *metadata = GetMetadataPtrFromNode(node);
03353 
03354     if (!metadata)
03355         return;
03356 
03357     m_metadataFactory->Lookup(metadata, automode, true);
03358 
03359     if (!automode)
03360     {
03361         QString msg = tr("Fetching details for %1")
03362                            .arg(metadata->GetTitle());
03363         if (!metadata->GetSubtitle().isEmpty())
03364             msg += QString(": %1").arg(metadata->GetSubtitle());
03365         if (metadata->GetSeason() > 0 || metadata->GetEpisode() > 0)
03366             msg += tr(" %1x%2").arg(metadata->GetSeason())
03367                    .arg(metadata->GetEpisode());
03368         createBusyDialog(msg);
03369     }
03370 }
03371 
03372 void VideoDialog::VideoAutoSearch(MythGenericTree *node)
03373 {
03374     if (!node)
03375         node = m_d->m_rootNode;
03376     typedef QList<MythGenericTree *> MGTreeChildList;
03377     MGTreeChildList *lchildren = node->getAllChildren();
03378 
03379     LOG(VB_GENERAL, LOG_DEBUG,
03380         QString("Fetching details in %1").arg(node->getString()));
03381 
03382     for (MGTreeChildList::const_iterator p = lchildren->begin();
03383             p != lchildren->end(); ++p)
03384     {
03385         if (((*p)->getInt() == kSubFolder) ||
03386             ((*p)->getInt() == kUpFolder))
03387             VideoAutoSearch((*p));
03388         else
03389         {
03390             VideoMetadata *metadata = GetMetadataPtrFromNode((*p));
03391 
03392             if (!metadata)
03393                 continue;
03394 
03395             if (!metadata->GetProcessed())
03396                 VideoSearch((*p), true);
03397         }
03398     }
03399 }
03400 
03401 void VideoDialog::ToggleWatched()
03402 {
03403     MythUIButtonListItem *item = GetItemCurrent();
03404     if (!item)
03405         return;
03406 
03407     VideoMetadata *metadata = GetMetadata(item);
03408     if (metadata)
03409     {
03410         metadata->SetWatched(!metadata->GetWatched());
03411         metadata->UpdateDatabase();
03412         item->DisplayState(WatchedToState(metadata->GetWatched()),
03413                                        "watchedstate");
03414     }
03415 }
03416 
03417 void VideoDialog::OnVideoSearchListSelection(MetadataLookup *lookup)
03418 {
03419     if (!lookup)
03420         return;
03421 
03422     lookup->SetStep(kLookupData);
03423     m_metadataFactory->Lookup(lookup);
03424 }
03425 
03426 void VideoDialog::OnParentalChange(int amount)
03427 {
03428     VideoMetadata *metadata = GetMetadata(GetItemCurrent());
03429     if (metadata)
03430     {
03431         ParentalLevel curshowlevel = metadata->GetShowLevel();
03432 
03433         curshowlevel += amount;
03434 
03435         if (curshowlevel.GetLevel() != metadata->GetShowLevel())
03436         {
03437             metadata->SetShowLevel(curshowlevel.GetLevel());
03438             metadata->UpdateDatabase();
03439             refreshData();
03440         }
03441     }
03442 }
03443 
03444 void VideoDialog::EditMetadata()
03445 {
03446     VideoMetadata *metadata = GetMetadata(GetItemCurrent());
03447     if (!metadata)
03448         return;
03449 
03450     MythScreenStack *screenStack = GetScreenStack();
03451 
03452     EditMetadataDialog *md_editor = new EditMetadataDialog(screenStack,
03453             "mythvideoeditmetadata", metadata,
03454             m_d->m_videoList->getListCache());
03455 
03456     connect(md_editor, SIGNAL(Finished()), SLOT(refreshData()));
03457 
03458     if (md_editor->Create())
03459         screenStack->AddScreen(md_editor);
03460 }
03461 
03462 void VideoDialog::RemoveVideo()
03463 {
03464     VideoMetadata *metadata = GetMetadata(GetItemCurrent());
03465 
03466     if (!metadata)
03467         return;
03468 
03469     QString message = tr("Are you sure you want to permanently delete:\n%1")
03470                           .arg(metadata->GetTitle());
03471 
03472     MythConfirmationDialog *confirmdialog =
03473             new MythConfirmationDialog(m_popupStack,message);
03474 
03475     if (confirmdialog->Create())
03476         m_popupStack->AddScreen(confirmdialog);
03477 
03478     connect(confirmdialog, SIGNAL(haveResult(bool)),
03479             SLOT(OnRemoveVideo(bool)));
03480 }
03481 
03482 void VideoDialog::OnRemoveVideo(bool dodelete)
03483 {
03484     if (!dodelete)
03485         return;
03486 
03487     MythUIButtonListItem *item = GetItemCurrent();
03488     MythGenericTree *gtItem = GetNodePtrFromButton(item);
03489 
03490     VideoMetadata *metadata = GetMetadata(item);
03491 
03492     if (!metadata)
03493         return;
03494 
03495     if (m_d->m_videoList->Delete(metadata->GetID()))
03496     {
03497         if (m_videoButtonTree)
03498             m_videoButtonTree->RemoveItem(item, false); // FIXME Segfault when true
03499         else
03500             m_videoButtonList->RemoveItem(item);
03501 
03502         MythGenericTree *parent = gtItem->getParent();
03503         parent->deleteNode(gtItem);
03504     }
03505     else
03506     {
03507         QString message = tr("Failed to delete file");
03508 
03509         MythConfirmationDialog *confirmdialog =
03510                         new MythConfirmationDialog(m_popupStack,message,false);
03511 
03512         if (confirmdialog->Create())
03513             m_popupStack->AddScreen(confirmdialog);
03514     }
03515 }
03516 
03517 void VideoDialog::ResetMetadata()
03518 {
03519     MythUIButtonListItem *item = GetItemCurrent();
03520     VideoMetadata *metadata = GetMetadata(item);
03521 
03522     if (metadata)
03523     {
03524         metadata->Reset();
03525         metadata->UpdateDatabase();
03526         UpdateItem(item);
03527     }
03528 }
03529 
03530 void VideoDialog::StartVideoImageSet(VideoMetadata *metadata)
03531 {
03532     if (!metadata)
03533         return;
03534 
03535     QStringList cover_dirs;
03536     cover_dirs += m_d->m_artDir;
03537 
03538     QString cover_file;
03539     QString inetref = metadata->GetInetRef();
03540     QString filename = metadata->GetFilename();
03541     QString title = metadata->GetTitle();
03542     int season = metadata->GetSeason();
03543     QString host = metadata->GetHost();
03544     int episode = metadata->GetEpisode();
03545 
03546     if (metadata->GetCoverFile().isEmpty() ||
03547         IsDefaultCoverFile(metadata->GetCoverFile()))
03548     {
03549         if (GetLocalVideoImage(inetref, filename,
03550                                 cover_dirs, cover_file, title,
03551                                 season, host, "Coverart", episode))
03552         {
03553             metadata->SetCoverFile(cover_file);
03554             OnVideoImageSetDone(metadata);
03555         }
03556     }
03557 
03558     QStringList fanart_dirs;
03559     fanart_dirs += m_d->m_fanDir;
03560 
03561     QString fanart_file;
03562 
03563     if (metadata->GetFanart().isEmpty())
03564     {
03565         if (GetLocalVideoImage(inetref, filename,
03566                                 fanart_dirs, fanart_file, title,
03567                                 season, host, "Fanart", episode))
03568         {
03569             metadata->SetFanart(fanart_file);
03570             OnVideoImageSetDone(metadata);
03571         }
03572     }
03573 
03574     QStringList banner_dirs;
03575     banner_dirs += m_d->m_banDir;
03576 
03577     QString banner_file;
03578 
03579     if (metadata->GetBanner().isEmpty())
03580     {
03581         if (GetLocalVideoImage(inetref, filename,
03582                                 banner_dirs, banner_file, title,
03583                                 season, host, "Banners", episode))
03584         {
03585             metadata->SetBanner(banner_file);
03586             OnVideoImageSetDone(metadata);
03587         }
03588     }
03589 
03590     QStringList screenshot_dirs;
03591     screenshot_dirs += m_d->m_sshotDir;
03592 
03593     QString screenshot_file;
03594 
03595     if (metadata->GetScreenshot().isEmpty())
03596     {
03597         if (GetLocalVideoImage(inetref, filename,
03598                                 screenshot_dirs, screenshot_file, title,
03599                                 season, host, "Screenshots", episode,
03600                                 true))
03601         {
03602             metadata->SetScreenshot(screenshot_file);
03603             OnVideoImageSetDone(metadata);
03604         }
03605     }
03606 }
03607 
03608 void VideoDialog::OnVideoSearchDone(MetadataLookup *lookup)
03609 {
03610     if (m_busyPopup)
03611     {
03612         m_busyPopup->Close();
03613         m_busyPopup = NULL;
03614     }
03615 
03616     if (!lookup)
03617        return;
03618 
03619     VideoMetadata *metadata = qVariantValue<VideoMetadata *>(lookup->GetData());
03620 
03621     if (!metadata)
03622         return;
03623 
03624     metadata->SetTitle(lookup->GetTitle());
03625     metadata->SetSubtitle(lookup->GetSubtitle());
03626 
03627     if (metadata->GetTagline().isEmpty())
03628         metadata->SetTagline(lookup->GetTagline());
03629     if (metadata->GetYear() == 1895 || metadata->GetYear() == 0)
03630         metadata->SetYear(lookup->GetYear());
03631     if (metadata->GetReleaseDate() == QDate())
03632         metadata->SetReleaseDate(lookup->GetReleaseDate());
03633     if (metadata->GetDirector() == VIDEO_DIRECTOR_UNKNOWN ||
03634         metadata->GetDirector().isEmpty())
03635     {
03636         QList<PersonInfo> director = lookup->GetPeople(kPersonDirector);
03637         if (director.count() > 0)
03638             metadata->SetDirector(director.takeFirst().name);
03639     }
03640     if (metadata->GetStudio().isEmpty())
03641     {
03642         QStringList studios = lookup->GetStudios();
03643         if (studios.count() > 0)
03644             metadata->SetStudio(studios.takeFirst());
03645     }
03646     if (metadata->GetPlot() == VIDEO_PLOT_DEFAULT ||
03647         metadata->GetPlot().isEmpty())
03648         metadata->SetPlot(lookup->GetDescription());
03649     if (metadata->GetUserRating() == 0)
03650         metadata->SetUserRating(lookup->GetUserRating());
03651     if (metadata->GetRating() == VIDEO_RATING_DEFAULT)
03652         metadata->SetRating(lookup->GetCertification());
03653     if (metadata->GetLength() == 0)
03654         metadata->SetLength(lookup->GetRuntime());
03655     if (metadata->GetSeason() == 0)
03656         metadata->SetSeason(lookup->GetSeason());
03657     if (metadata->GetEpisode() == 0)
03658         metadata->SetEpisode(lookup->GetEpisode());
03659     if (metadata->GetHomepage().isEmpty())
03660         metadata->SetHomepage(lookup->GetHomepage());
03661 
03662     metadata->SetInetRef(lookup->GetInetref());
03663 
03664     m_d->AutomaticParentalAdjustment(metadata);
03665 
03666     // Cast
03667     QList<PersonInfo> actors = lookup->GetPeople(kPersonActor);
03668     QList<PersonInfo> gueststars = lookup->GetPeople(kPersonGuestStar);
03669 
03670     for (QList<PersonInfo>::const_iterator p = gueststars.begin();
03671         p != gueststars.end(); ++p)
03672     {
03673         actors.append(*p);
03674     }
03675 
03676     VideoMetadata::cast_list cast;
03677     QStringList cl;
03678 
03679     for (QList<PersonInfo>::const_iterator p = actors.begin();
03680         p != actors.end(); ++p)
03681     {
03682         cl.append((*p).name);
03683     }
03684 
03685     for (QStringList::const_iterator p = cl.begin();
03686         p != cl.end(); ++p)
03687     {
03688         QString cn = (*p).trimmed();
03689         if (cn.length())
03690         {
03691             cast.push_back(VideoMetadata::cast_list::
03692                         value_type(-1, cn));
03693         }
03694     }
03695 
03696     metadata->SetCast(cast);
03697 
03698     // Genres
03699     VideoMetadata::genre_list video_genres;
03700     QStringList genres = lookup->GetCategories();
03701 
03702     for (QStringList::const_iterator p = genres.begin();
03703         p != genres.end(); ++p)
03704     {
03705         QString genre_name = (*p).trimmed();
03706         if (genre_name.length())
03707         {
03708             video_genres.push_back(
03709                     VideoMetadata::genre_list::value_type(-1, genre_name));
03710         }
03711     }
03712 
03713     metadata->SetGenres(video_genres);
03714 
03715     // Countries
03716     VideoMetadata::country_list video_countries;
03717     QStringList countries = lookup->GetCountries();
03718 
03719     for (QStringList::const_iterator p = countries.begin();
03720         p != countries.end(); ++p)
03721     {
03722         QString country_name = (*p).trimmed();
03723         if (country_name.length())
03724         {
03725             video_countries.push_back(
03726                     VideoMetadata::country_list::value_type(-1,
03727                             country_name));
03728         }
03729     }
03730 
03731     metadata->SetCountries(video_countries);
03732     metadata->SetProcessed(true);
03733 
03734     metadata->UpdateDatabase();
03735 
03736     MythUIButtonListItem *item = GetItemByMetadata(metadata);
03737     if (item != NULL)
03738         UpdateItem(item);
03739 
03740     delete lookup;
03741     lookup = NULL;
03742 
03743     StartVideoImageSet(metadata);
03744 }
03745 
03746 void VideoDialog::doVideoScan()
03747 {
03748     if (!m_d->m_scanner)
03749         m_d->m_scanner = new VideoScanner();
03750     connect(m_d->m_scanner, SIGNAL(finished(bool)), SLOT(scanFinished(bool)));
03751     m_d->m_scanner->doScan(GetVideoDirs());
03752 }
03753 
03754 void VideoDialog::PromptToScan()
03755 {
03756     QString message = tr("There are no videos in the database, would you like "
03757                          "to scan your video directories now?");
03758     MythConfirmationDialog *dialog = new MythConfirmationDialog(m_popupStack,
03759                                                                 message,
03760                                                                 true);
03761     dialog->SetReturnEvent(this, "scanprompt");
03762     if (dialog->Create())
03763         m_popupStack->AddScreen(dialog);
03764     else
03765         delete dialog;
03766 }
03767 
03768 #include "videodlg.moc"
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends