MythTV  0.27pre
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Groups Pages
videodlg.cpp
Go to the documentation of this file.
1 #include <set>
2 #include <map>
3 
4 #include <QApplication>
5 #include <QTimer>
6 #include <QList>
7 #include <QFile>
8 #include <QFileInfo>
9 #include <QDir>
10 #include <QUrl>
11 
12 #include "mythcontext.h"
13 #include "compat.h"
14 #include "mythdirs.h"
15 
16 #include "mythuihelper.h"
17 #include "mythprogressdialog.h"
18 #include "mythuitext.h"
19 #include "mythuibutton.h"
20 #include "mythuibuttonlist.h"
21 #include "mythuibuttontree.h"
22 #include "mythuiimage.h"
23 #include "mythuistatetype.h"
24 #include "mythuimetadataresults.h"
25 #include "mythdialogbox.h"
26 #include "mythgenerictree.h"
27 #include "mythsystem.h"
28 #include "remotefile.h"
29 #include "remoteutil.h"
30 #include "storagegroup.h"
31 
32 #include "videoscan.h"
33 #include "globals.h"
35 #include "parentalcontrols.h"
36 #include "videoutils.h"
37 #include "dbaccess.h"
38 #include "dirscan.h"
39 #include "metadatafactory.h"
40 #include "videofilter.h"
41 #include "editvideometadata.h"
42 #include "videopopups.h"
43 #include "videolist.h"
44 #include "videoplayercommand.h"
45 #include "videodlg.h"
46 #include "videofileassoc.h"
47 #include "videoplayersettings.h"
48 #include "videometadatasettings.h"
49 
50 namespace
51 {
52  bool IsValidDialogType(int num)
53  {
54  for (int i = 1; i <= VideoDialog::dtLast - 1; i <<= 1)
55  if (num == i) return true;
56  return false;
57  }
58 
59  class ParentalLevelNotifyContainer : public QObject
60  {
61  Q_OBJECT
62 
63  signals:
64  void SigLevelChanged();
65 
66  public:
67  ParentalLevelNotifyContainer(QObject *lparent = 0) :
68  QObject(lparent), m_level(ParentalLevel::plNone)
69  {
70  connect(&m_levelCheck,
71  SIGNAL(SigResultReady(bool, ParentalLevel::Level)),
72  SLOT(OnResultReady(bool, ParentalLevel::Level)));
73  }
74 
75  const ParentalLevel &GetLevel() const { return m_level; }
76 
77  void SetLevel(ParentalLevel level)
78  {
79  m_levelCheck.Check(m_level.GetLevel(), level.GetLevel());
80  }
81 
82  private slots:
83  void OnResultReady(bool passwordValid, ParentalLevel::Level newLevel)
84  {
85  ParentalLevel lastLevel = m_level;
86  if (passwordValid)
87  {
88  m_level = newLevel;
89  }
90 
91  if (m_level.GetLevel() == ParentalLevel::plNone)
92  {
94  }
95 
96  if (lastLevel != m_level)
97  {
98  emit SigLevelChanged();
99  }
100  }
101 
102  private:
103  ParentalLevel m_level;
104  ParentalLevelChangeChecker m_levelCheck;
105  };
106 
107  MythGenericTree *GetNodePtrFromButton(MythUIButtonListItem *item)
108  {
109  if (item)
110  return item->GetData().value<MythGenericTree *>();
111 
112  return NULL;
113  }
114 
115  VideoMetadata *GetMetadataPtrFromNode(MythGenericTree *node)
116  {
117  if (node)
118  return node->GetData().value<TreeNodeData>().GetMetadata();
119 
120  return NULL;
121  }
122 
123  bool GetLocalVideoImage(const QString &video_uid, const QString &filename,
124  const QStringList &in_dirs, QString &image,
125  QString title, int season,
126  const QString host, QString sgroup,
127  int episode = 0, bool isScreenshot = false)
128  {
129  QStringList search_dirs(in_dirs);
130  QFileInfo qfi(filename);
131  search_dirs += qfi.absolutePath();
132  if (title.contains("/"))
133  title.replace("/", "-");
134 
135  const QString base_name = qfi.completeBaseName();
136  QList<QByteArray> image_types = QImageReader::supportedImageFormats();
137 
138  typedef std::set<QString> image_type_list;
139  image_type_list image_exts;
140 
141  QString suffix;
142 
143  if (sgroup == "Coverart")
144  suffix = "coverart";
145  if (sgroup == "Fanart")
146  suffix = "fanart";
147  if (sgroup == "Screenshots")
148  suffix = "screenshot";
149  if (sgroup == "Banners")
150  suffix = "banner";
151 
152  for (QList<QByteArray>::const_iterator it = image_types.begin();
153  it != image_types.end(); ++it)
154  {
155  image_exts.insert(QString(*it).toLower());
156  }
157 
158  if (!host.isEmpty())
159  {
160  QStringList hostFiles;
161 
162  RemoteGetFileList(host, "", &hostFiles, sgroup, true);
163  const QString hntm("%2.%3");
164 
165  for (image_type_list::const_iterator ext = image_exts.begin();
166  ext != image_exts.end(); ++ext)
167  {
168  QStringList sfn;
169  if (episode > 0 || season > 0)
170  {
171  if (isScreenshot)
172  sfn += hntm.arg(QString("%1 Season %2x%3_%4")
173  .arg(title).arg(QString::number(season))
174  .arg(QString::number(episode))
175  .arg(suffix))
176  .arg(*ext);
177  else
178  sfn += hntm.arg(QString("%1 Season %2_%3")
179  .arg(title).arg(QString::number(season))
180  .arg(suffix))
181  .arg(*ext);
182 
183  }
184  else
185  {
186  sfn += hntm.arg(base_name + "_%1").arg(suffix).arg(*ext);
187  sfn += hntm.arg(video_uid + "_%1").arg(suffix).arg(*ext);
188  }
189 
190  for (QStringList::const_iterator i = sfn.begin();
191  i != sfn.end(); ++i)
192  {
193  if (hostFiles.contains(*i))
194  {
195  image = *i;
196  return true;
197  }
198  }
199  }
200  }
201 
202  const QString fntm("%1/%2.%3");
203 
204  for (QStringList::const_iterator dir = search_dirs.begin();
205  dir != search_dirs.end(); ++dir)
206  {
207  if (!(*dir).length()) continue;
208 
209  for (image_type_list::const_iterator ext = image_exts.begin();
210  ext != image_exts.end(); ++ext)
211  {
212  QStringList sfn;
213  if (season > 0 || episode > 0)
214  {
215  if (isScreenshot)
216  sfn += fntm.arg(*dir).arg(QString("%1 Season %2x%3_%4")
217  .arg(title).arg(QString::number(season))
218  .arg(QString::number(episode))
219  .arg(suffix))
220  .arg(*ext);
221  else if (!isScreenshot)
222  sfn += fntm.arg(*dir).arg(QString("%1 Season %2_%3")
223  .arg(title).arg(QString::number(season))
224  .arg(suffix))
225  .arg(*ext);
226 
227  }
228  if (!isScreenshot)
229  {
230  sfn += fntm.arg(*dir).arg(QString(base_name + "_%1")
231  .arg(suffix)).arg(*ext);
232  sfn += fntm.arg(*dir).arg(QString(video_uid + "_%1")
233  .arg(suffix)).arg(*ext);
234  }
235 
236  for (QStringList::const_iterator i = sfn.begin();
237  i != sfn.end(); ++i)
238  {
239  if (QFile::exists(*i))
240  {
241  image = *i;
242  return true;
243  }
244  }
245  }
246  }
247 
248  return false;
249  }
250 
251  void PlayVideo(const QString &filename,
252  const VideoMetadataListManager &video_list, bool useAltPlayer = false)
253  {
254  const int WATCHED_WATERMARK = 10000; // Less than this and the chain of
255  // videos will not be followed when
256  // playing.
257 
258  VideoMetadataListManager::VideoMetadataPtr item = video_list.byFilename(filename);
259 
260  if (!item) return;
261 
262  QTime playing_time;
263 
264  do
265  {
266  playing_time.start();
267 
268  if (useAltPlayer)
269  VideoPlayerCommand::AltPlayerFor(item.get()).Play();
270  else
271  VideoPlayerCommand::PlayerFor(item.get()).Play();
272 
273  if (item->GetChildID() > 0 && video_list.byID(item->GetChildID()))
274  item = video_list.byID(item->GetChildID());
275  else
276  break;
277  }
278  while (item && playing_time.elapsed() > WATCHED_WATERMARK);
279  }
280 
281  class FanartLoader: public QObject
282  {
283  Q_OBJECT
284 
285  public:
286  FanartLoader() : itemsPast(0), m_fanart(NULL)
287  {
288  connect(&m_fanartTimer, SIGNAL(timeout()), SLOT(fanartLoad()));
289  }
290 
291  ~FanartLoader()
292  {
293  m_fanartTimer.stop();
294  m_fanartTimer.disconnect(this);
295  }
296 
297  void LoadImage(const QString &filename, MythUIImage *image)
298  {
299  bool wasActive = m_fanartTimer.isActive();
300  if (filename.isEmpty())
301  {
302  if (wasActive)
303  m_fanartTimer.stop();
304 
305  image->Reset();
306  itemsPast++;
307  }
308  else
309  {
310  QMutexLocker locker(&m_fanartLock);
311  m_fanart = image;
312  if (filename != m_fanart->GetFilename())
313  {
314  if (wasActive)
315  m_fanartTimer.stop();
316 
317  if (itemsPast > 2)
318  m_fanart->Reset();
319 
320  m_fanart->SetFilename(filename);
321  m_fanartTimer.setSingleShot(true);
322  m_fanartTimer.start(300);
323 
324  if (wasActive)
325  itemsPast++;
326  else
327  itemsPast = 0;
328  }
329  else
330  itemsPast = 0;
331  }
332  }
333 
334  protected slots:
335  void fanartLoad(void)
336  {
337  QMutexLocker locker(&m_fanartLock);
338  m_fanart->Load();
339  }
340 
341  private:
342  int itemsPast;
343  QMutex m_fanartLock;
344  MythUIImage *m_fanart;
345  QTimer m_fanartTimer;
346  };
347 
348  FanartLoader fanartLoader;
349 
350  struct CopyMetadataDestination
351  {
352  virtual void handleText(const QString &name, const QString &value) = 0;
353  virtual void handleState(const QString &name, const QString &value) = 0;
354  virtual void handleImage(const QString &name,
355  const QString &filename) = 0;
356  };
357 
358  class ScreenCopyDest : public CopyMetadataDestination
359  {
360  public:
361  ScreenCopyDest(MythScreenType *screen) : m_screen(screen) {}
362 
363  void handleText(const QString &name, const QString &value)
364  {
365  CheckedSet(m_screen, name, value);
366  }
367 
368  void handleState(const QString &name, const QString &value)
369  {
370  handleText(name, value);
371  }
372 
373  void handleImage(const QString &name, const QString &filename)
374  {
375  MythUIImage *image = NULL;
376  UIUtilW::Assign(m_screen, image, name);
377  if (image)
378  {
379  if (name != "fanart")
380  {
381  if (!filename.isEmpty())
382  {
383  image->SetFilename(filename);
384  image->Load();
385  }
386  else
387  image->Reset();
388  }
389  else
390  {
391  fanartLoader.LoadImage(filename, image);
392  }
393  }
394  }
395 
396  private:
397  MythScreenType *m_screen;
398  };
399 
400  class MythUIButtonListItemCopyDest : public CopyMetadataDestination
401  {
402  public:
403  MythUIButtonListItemCopyDest(MythUIButtonListItem *item) :
404  m_item(item) {}
405 
406  void handleText(const QString &name, const QString &value)
407  {
408  m_item->SetText(value, name);
409  }
410 
411  void handleState(const QString &name, const QString &value)
412  {
413  m_item->DisplayState(value, name);
414  }
415 
416  void handleImage(const QString &name, const QString &filename)
417  {
418  (void) name;
419  (void) filename;
420  }
421 
422  private:
423  MythUIButtonListItem *m_item;
424  };
425 
426  void CopyMetadataToUI(const VideoMetadata *metadata,
427  CopyMetadataDestination &dest)
428  {
429  typedef std::map<QString, QString> valuelist;
430  valuelist tmp;
431 
432  if (metadata)
433  {
434  QString coverfile;
435  if ((metadata->IsHostSet()
436  && !metadata->GetCoverFile().startsWith("/"))
437  && !metadata->GetCoverFile().isEmpty()
438  && !IsDefaultCoverFile(metadata->GetCoverFile()))
439  {
440  coverfile = generate_file_url("Coverart", metadata->GetHost(),
441  metadata->GetCoverFile());
442  }
443  else
444  {
445  coverfile = metadata->GetCoverFile();
446  }
447 
448  if (!IsDefaultCoverFile(coverfile))
449  tmp["coverart"] = coverfile;
450 
451  tmp["coverfile"] = coverfile;
452 
453  QString screenshotfile;
454  if (metadata->IsHostSet() && !metadata->GetScreenshot().startsWith("/")
455  && !metadata->GetScreenshot().isEmpty())
456  {
457  screenshotfile = generate_file_url("Screenshots",
458  metadata->GetHost(), metadata->GetScreenshot());
459  }
460  else
461  {
462  screenshotfile = metadata->GetScreenshot();
463  }
464 
465  if (!IsDefaultScreenshot(screenshotfile))
466  tmp["screenshot"] = screenshotfile;
467 
468  tmp["screenshotfile"] = screenshotfile;
469 
470  QString bannerfile;
471  if (metadata->IsHostSet() && !metadata->GetBanner().startsWith("/")
472  && !metadata->GetBanner().isEmpty())
473  {
474  bannerfile = generate_file_url("Banners", metadata->GetHost(),
475  metadata->GetBanner());
476  }
477  else
478  {
479  bannerfile = metadata->GetBanner();
480  }
481 
482  if (!IsDefaultBanner(bannerfile))
483  tmp["banner"] = bannerfile;
484 
485  tmp["bannerfile"] = bannerfile;
486 
487  QString fanartfile;
488  if (metadata->IsHostSet() && !metadata->GetFanart().startsWith("/")
489  && !metadata->GetFanart().isEmpty())
490  {
491  fanartfile = generate_file_url("Fanart", metadata->GetHost(),
492  metadata->GetFanart());
493  }
494  else
495  {
496  fanartfile = metadata->GetFanart();
497  }
498 
499  if (!IsDefaultFanart(fanartfile))
500  tmp["fanart"] = fanartfile;
501 
502  tmp["fanartfile"] = fanartfile;
503 
504  tmp["trailerstate"] = TrailerToState(metadata->GetTrailer());
505  tmp["studiostate"] = metadata->GetStudio();
506  tmp["userratingstate"] =
507  QString::number((int)(metadata->GetUserRating()));
508  tmp["watchedstate"] = WatchedToState(metadata->GetWatched());
509 
510  tmp["videolevel"] = ParentalLevelToState(metadata->GetShowLevel());
511  }
512 
513  struct helper
514  {
515  helper(valuelist &values, CopyMetadataDestination &d) :
516  m_vallist(values), m_dest(d) {}
517 
518  void handleImage(const QString &name)
519  {
520  m_dest.handleImage(name, m_vallist[name]);
521  }
522 
523  void handleState(const QString &name)
524  {
525  m_dest.handleState(name, m_vallist[name]);
526  }
527  private:
528  valuelist &m_vallist;
529  CopyMetadataDestination &m_dest;
530  };
531 
532  helper h(tmp, dest);
533 
534  h.handleImage("coverart");
535  h.handleImage("screenshot");
536  h.handleImage("banner");
537  h.handleImage("fanart");
538 
539  h.handleState("trailerstate");
540  h.handleState("userratingstate");
541  h.handleState("watchedstate");
542  h.handleState("videolevel");
543  }
544 }
545 
547 {
548  Q_OBJECT
549 
550  public:
551  static bool Exists()
552  {
553  // TODO: Add ability to theme loader to do this a better way.
554  return LoadWindowFromXML("video-ui.xml", WINDOW_NAME, NULL);
555  }
556 
557  public:
559  const VideoMetadataListManager &listManager) :
560  MythScreenType(lparent, WINDOW_NAME), m_metadata(metadata),
561  m_listManager(listManager), m_playButton(NULL), m_doneButton(NULL)
562  {
563  }
564 
565  bool Create()
566  {
567  if (!LoadWindowFromXML("video-ui.xml", WINDOW_NAME, this))
568  return false;
569 
570  UIUtilW::Assign(this, m_playButton, "play_button");
571  UIUtilW::Assign(this, m_doneButton, "done_button");
572 
573  if (m_playButton)
574  connect(m_playButton, SIGNAL(Clicked()), SLOT(OnPlay()));
575 
576  if (m_doneButton)
577  connect(m_doneButton, SIGNAL(Clicked()), SLOT(OnDone()));
578 
579  BuildFocusList();
580 
581  if (m_playButton || m_doneButton)
583 
584  MetadataMap metadataMap;
585  m_metadata->toMap(metadataMap);
586  SetTextFromMap(metadataMap);
587 
588  ScreenCopyDest dest(this);
589  CopyMetadataToUI(m_metadata, dest);
590 
591  return true;
592  }
593 
594  private slots:
595  void OnPlay()
596  {
597  PlayVideo(m_metadata->GetFilename(), m_listManager);
598  }
599 
600  void OnDone()
601  {
602  // TODO: Close() can do horrible things, this will pop
603  // our screen, delete us, and return here.
604  Close();
605  }
606 
607  private:
608  bool OnKeyAction(const QStringList &actions)
609  {
610  bool handled = false;
611  for (QStringList::const_iterator key = actions.begin();
612  key != actions.end(); ++key)
613  {
614  handled = true;
615  if (*key == "SELECT" || *key == "PLAYBACK")
616  OnPlay();
617  else
618  handled = false;
619  }
620 
621  return handled;
622  }
623 
624  protected:
625  bool keyPressEvent(QKeyEvent *levent)
626  {
627  if (!MythScreenType::keyPressEvent(levent))
628  {
629  QStringList actions;
630  bool handled = GetMythMainWindow()->TranslateKeyPress("Video",
631  levent, actions);
632 
633  if (!handled && !OnKeyAction(actions))
634  {
635  handled = GetMythMainWindow()->TranslateKeyPress("TV Frontend",
636  levent, actions);
637  OnKeyAction(actions);
638  }
639  }
640 
641  return true;
642  }
643 
644  private:
645  static const char * const WINDOW_NAME;
648 
651 };
652 
653 const char * const ItemDetailPopup::WINDOW_NAME = "itemdetailpopup";
654 
656 {
657  private:
658  typedef std::list<std::pair<QString, ParentalLevel::Level> >
660 
662  public std::binary_function<parental_level_map::value_type,
663  parental_level_map::value_type, bool>
664  {
665  bool operator()(const parental_level_map::value_type &lhs,
666  const parental_level_map::value_type &rhs) const
667  {
668  return lhs.first.length() < rhs.first.length();
669  }
670  };
671 
673 
674  public:
676  VideoDialog::BrowseType browse) :
680  m_type(type), m_browse(browse), m_scanner(0)
681  {
682  if (gCoreContext->GetNumSetting("mythvideo.ParentalLevelFromRating", 0))
683  {
685  sl.GetLevel() <= ParentalLevel::plHigh && sl.good(); ++sl)
686  {
687  QString ratingstring =
688  gCoreContext->GetSetting(QString("mythvideo.AutoR2PL%1")
689  .arg(sl.GetLevel()));
690  QStringList ratings =
691  ratingstring.split(':', QString::SkipEmptyParts);
692 
693  for (QStringList::const_iterator p = ratings.begin();
694  p != ratings.end(); ++p)
695  {
696  m_rating_to_pl.push_back(
697  parental_level_map::value_type(*p, sl.GetLevel()));
698  }
699  }
700  m_rating_to_pl.sort(std::not2(rating_to_pl_less()));
701  }
702 
704  gCoreContext->GetNumSetting("mythvideo.VideoTreeRemember", 0);
705 
706  m_isFileBrowser = gCoreContext->GetNumSetting("VideoDialogNoDB", 0);
707  m_groupType = gCoreContext->GetNumSetting("mythvideo.db_group_type", 0);
708 
710  gCoreContext->GetNumSetting("mythvideo.EnableAlternatePlayer");
711 
712  m_autoMeta = gCoreContext->GetNumSetting("mythvideo.AutoMetaDataScan", 1);
713 
714  m_artDir = gCoreContext->GetSetting("VideoArtworkDir");
715  m_sshotDir = gCoreContext->GetSetting("mythvideo.screenshotDir");
716  m_fanDir = gCoreContext->GetSetting("mythvideo.fanartDir");
717  m_banDir = gCoreContext->GetSetting("mythvideo.bannerDir");
718  }
719 
721  {
722  delete m_scanner;
723 
724  if (m_rememberPosition && m_lastTreeNodePath.length())
725  {
726  gCoreContext->SaveSetting("mythvideo.VideoTreeLastActive",
728  }
729  }
730 
732  {
733  if (metadata && !m_rating_to_pl.empty())
734  {
735  QString rating = metadata->GetRating();
736  for (parental_level_map::const_iterator p = m_rating_to_pl.begin();
737  !rating.isEmpty() && p != m_rating_to_pl.end(); ++p)
738  {
739  if (rating.indexOf(p->first) != -1)
740  {
741  metadata->SetShowLevel(p->second);
742  break;
743  }
744  }
745  }
746  }
747 
749  {
750  m_savedPtr = new VideoListDeathDelay(videoList);
751  }
752 
753  public:
754  ParentalLevelNotifyContainer m_parentalLevel;
756 
758 
760 
762 
764 
767 
769 
776 
778 
779  QString m_artDir;
780  QString m_sshotDir;
781  QString m_fanDir;
782  QString m_banDir;
784 
786 
787  private:
789 };
790 
792 
794 {
795  public:
797  m_savedList(toSave)
798  {
799  }
800 
802  {
803  return m_savedList;
804  }
805 
806  private:
808 };
809 
811  QObject(qApp)
812 {
813  m_d = new VideoListDeathDelayPrivate(toSave);
814  QTimer::singleShot(3000, this, SLOT(OnTimeUp()));
815 }
816 
818 {
819  delete m_d;
820 }
821 
823 {
824  return m_d->GetSaved();
825 }
826 
828 {
829  deleteLater();
830 }
831 
833 {
834  return VideoDialogPrivate::m_savedPtr;
835 }
836 
838  VideoListPtr video_list, DialogType type, BrowseType browse) :
839  MythScreenType(lparent, lname), m_menuPopup(0), m_busyPopup(0),
840  m_videoButtonList(0), m_videoButtonTree(0), m_titleText(0),
841  m_novideoText(0), m_positionText(0), m_crumbText(0), m_coverImage(0),
842  m_screenshot(0), m_banner(0), m_fanart(0), m_trailerState(0),
843  m_parentalLevelState(0), m_watchedState(0), m_studioState(0)
844 {
846 
847  m_d = new VideoDialogPrivate(video_list, type, browse);
848 
849  m_popupStack = GetMythMainWindow()->GetStack("popup stack");
851 
853  lname));
854 
856  GetNumSetting("VideoDefaultParentalLevel",
858 
860 }
861 
863 {
864  if (!m_d->m_switchingLayout)
866 
867  SavePosition();
868 
869  delete m_d;
870 }
871 
873 {
874  m_d->m_lastTreeNodePath = "";
875 
876  if (m_d->m_type == DLG_TREE)
877  {
879  if (node)
880  m_d->m_lastTreeNodePath = node->getRouteByString().join("\n");
881  }
882  else if (m_d->m_type == DLG_BROWSER || m_d->m_type == DLG_GALLERY)
883  {
885  if (item)
886  {
887  MythGenericTree *node = GetNodePtrFromButton(item);
888  if (node)
889  m_d->m_lastTreeNodePath = node->getRouteByString().join("\n");
890  }
891  }
892 
893  gCoreContext->SaveSetting("mythvideo.VideoTreeLastActive", m_d->m_lastTreeNodePath);
894 }
895 
897 {
898  if (m_d->m_type == DLG_DEFAULT)
899  {
900  m_d->m_type = static_cast<DialogType>(
901  gCoreContext->GetNumSetting("Default MythVideo View", DLG_GALLERY));
902  m_d->m_browse = static_cast<BrowseType>(
903  gCoreContext->GetNumSetting("mythvideo.db_group_type", BRS_FOLDER));
904  }
905 
906  if (!IsValidDialogType(m_d->m_type))
907  {
909  }
910 
911  QString windowName = "videogallery";
912  int flatlistDefault = 0;
913 
914  switch (m_d->m_type)
915  {
916  case DLG_BROWSER:
917  windowName = "browser";
918  flatlistDefault = 1;
919  break;
920  case DLG_GALLERY:
921  windowName = "gallery";
922  break;
923  case DLG_TREE:
924  windowName = "tree";
925  break;
926  case DLG_MANAGER:
927  m_d->m_isFlatList =
928  gCoreContext->GetNumSetting("mythvideo.db_folder_view", 1);
929  windowName = "manager";
930  flatlistDefault = 1;
931  break;
932  case DLG_DEFAULT:
933  default:
934  break;
935  }
936 
937  switch (m_d->m_browse)
938  {
939  case BRS_GENRE:
941  break;
942  case BRS_CATEGORY:
944  break;
945  case BRS_YEAR:
947  break;
948  case BRS_DIRECTOR:
950  break;
951  case BRS_STUDIO:
953  break;
954  case BRS_CAST:
956  break;
957  case BRS_USERRATING:
959  break;
960  case BRS_INSERTDATE:
962  break;
963  case BRS_TVMOVIE:
965  break;
966  case BRS_FOLDER:
967  default:
969  break;
970  }
971 
972  m_d->m_isFlatList =
973  gCoreContext->GetNumSetting(QString("mythvideo.folder_view_%1")
974  .arg(m_d->m_type), flatlistDefault);
975 
976  if (!LoadWindowFromXML("video-ui.xml", windowName, this))
977  return false;
978 
979  bool err = false;
980  if (m_d->m_type == DLG_TREE)
981  UIUtilE::Assign(this, m_videoButtonTree, "videos", &err);
982  else
983  UIUtilE::Assign(this, m_videoButtonList, "videos", &err);
984 
985  UIUtilW::Assign(this, m_titleText, "title");
986  UIUtilW::Assign(this, m_novideoText, "novideos");
987  UIUtilW::Assign(this, m_positionText, "position");
988  UIUtilW::Assign(this, m_crumbText, "breadcrumbs");
989 
990  UIUtilW::Assign(this, m_coverImage, "coverart");
991  UIUtilW::Assign(this, m_screenshot, "screenshot");
992  UIUtilW::Assign(this, m_banner, "banner");
993  UIUtilW::Assign(this, m_fanart, "fanart");
994 
995  UIUtilW::Assign(this, m_trailerState, "trailerstate");
996  UIUtilW::Assign(this, m_parentalLevelState, "parentallevel");
997  UIUtilW::Assign(this, m_watchedState, "watchedstate");
998  UIUtilW::Assign(this, m_studioState, "studiostate");
999 
1000  if (err)
1001  {
1002  LOG(VB_GENERAL, LOG_ERR, "Cannot load screen '" + windowName + "'");
1003  return false;
1004  }
1005 
1006  CheckedSet(m_trailerState, "None");
1008  CheckedSet(m_watchedState, "None");
1009  CheckedSet(m_studioState, "None");
1010 
1011  BuildFocusList();
1012 
1013  if (m_d->m_type == DLG_TREE)
1014  {
1016 
1017  connect(m_videoButtonTree, SIGNAL(itemClicked(MythUIButtonListItem *)),
1019  connect(m_videoButtonTree, SIGNAL(itemSelected(MythUIButtonListItem *)),
1020  SLOT(UpdateText(MythUIButtonListItem *)));
1021  connect(m_videoButtonTree, SIGNAL(nodeChanged(MythGenericTree *)),
1022  SLOT(SetCurrentNode(MythGenericTree *)));
1023  }
1024  else
1025  {
1027 
1028  connect(m_videoButtonList, SIGNAL(itemClicked(MythUIButtonListItem *)),
1030  connect(m_videoButtonList, SIGNAL(itemSelected(MythUIButtonListItem *)),
1031  SLOT(UpdateText(MythUIButtonListItem *)));
1032  }
1033 
1034  return true;
1035 }
1036 
1038 {
1039  connect(&m_d->m_parentalLevel, SIGNAL(SigLevelChanged()),
1040  SLOT(reloadData()));
1041 }
1042 
1044 {
1045  reloadData();
1046  // We only want to prompt once, on startup, hence this is done in Load()
1047  if (m_d->m_rootNode->childCount() == 1 &&
1049  PromptToScan();
1050 }
1051 
1057 {
1058  fetchVideos();
1059  loadData();
1060 
1063 
1064  bool noFiles = (m_d->m_rootNode->childCount() == 1 &&
1066 
1067  if (m_novideoText)
1068  m_novideoText->SetVisible(noFiles);
1069 }
1070 
1071 void VideoDialog::scanFinished(bool dbChanged)
1072 {
1073  delete m_d->m_scanner;
1074  m_d->m_scanner = 0;
1075 
1076  if (dbChanged)
1078 
1079  m_d->m_currentNode = NULL;
1080  reloadData();
1081 
1082  if (m_d->m_autoMeta)
1083  VideoAutoSearch();
1084 
1085  if (m_d->m_rootNode->childCount() == 1 &&
1087  {
1088  QString message = tr("The video scan found no files, have you "
1089  "configured a video storage group?");
1090  ShowOkPopup(message);
1091  }
1092 }
1093 
1099 {
1100  m_d->m_treeLoaded = false;
1101  refreshData();
1102 }
1103 
1109 {
1110  if (m_d->m_type == DLG_TREE)
1111  {
1113 
1114  if (m_d->m_firstLoadPass)
1115  {
1116  m_d->m_firstLoadPass = false;
1117 
1118  if (m_d->m_rememberPosition)
1119  {
1120  QStringList route =
1121  gCoreContext->GetSetting("mythvideo.VideoTreeLastActive",
1122  "").split("\n");
1124  }
1125  }
1126  }
1127  else
1128  {
1130 
1131  if (!m_d->m_treeLoaded)
1132  return;
1133 
1134  if (!m_d->m_currentNode)
1136 
1137  if (!m_d->m_currentNode)
1138  return;
1139 
1140  MythGenericTree *selectedNode = m_d->m_currentNode->getSelectedChild();
1141 
1142  // restore the last saved position in the video tree if this is the first
1143  // time this method is called and the option is set in the database
1144  if (m_d->m_firstLoadPass)
1145  {
1146  if (m_d->m_rememberPosition)
1147  {
1148  QStringList lastTreeNodePath = gCoreContext->GetSetting("mythvideo.VideoTreeLastActive", "").split("\n");
1149 
1150  if (m_d->m_type == DLG_GALLERY || m_d->m_type == DLG_BROWSER)
1151  {
1152  if (!lastTreeNodePath.isEmpty())
1153  {
1154  MythGenericTree *node;
1155 
1156  // go through the path list and set the current node
1157  for (int i = 0; i < lastTreeNodePath.size(); i++)
1158  {
1159  node = m_d->m_currentNode->getChildByName(lastTreeNodePath.at(i));
1160  if (node != NULL)
1161  {
1162  // check if the node name is the same as the currently selected
1163  // one in the saved tree list. if yes then we are on the right
1164  // way down the video tree to find the last saved position
1165  if (node->GetText().compare(lastTreeNodePath.at(i)) == 0)
1166  {
1167  // set the folder as the new node so we can travel further down
1168  // dont do this if its the last part of the saved video path tree
1169  if (node->getInt() == kSubFolder &&
1170  node->childCount() > 1 &&
1171  i < lastTreeNodePath.size()-1)
1172  {
1173  SetCurrentNode(node);
1174  }
1175  // in the last run the selectedNode will be the last
1176  // entry of the saved tree node.
1177  if (lastTreeNodePath.at(i) == lastTreeNodePath.last())
1178  selectedNode = node;
1179  }
1180  }
1181  }
1182  m_d->m_firstLoadPass = false;
1183  }
1184  }
1185  }
1186  }
1187 
1188  typedef QList<MythGenericTree *> MGTreeChildList;
1189  MGTreeChildList *lchildren = m_d->m_currentNode->getAllChildren();
1190 
1191  for (MGTreeChildList::const_iterator p = lchildren->begin();
1192  p != lchildren->end(); ++p)
1193  {
1194  if (*p != NULL)
1195  {
1196  MythUIButtonListItem *item =
1197  new MythUIButtonListItem(m_videoButtonList, QString(), 0,
1199 
1200  item->SetData(qVariantFromValue(*p));
1201 
1202  UpdateItem(item);
1203 
1204  if (*p == selectedNode)
1206  }
1207  }
1208  }
1209 
1210  UpdatePosition();
1211 }
1212 
1218 {
1219  if (!item)
1220  return;
1221 
1222  MythGenericTree *node = GetNodePtrFromButton(item);
1223 
1224  VideoMetadata *metadata = GetMetadata(item);
1225 
1226  if (metadata)
1227  {
1228  MetadataMap metadataMap;
1229  metadata->toMap(metadataMap);
1230  item->SetTextFromMap(metadataMap);
1231  }
1232 
1233  MythUIButtonListItemCopyDest dest(item);
1234  CopyMetadataToUI(metadata, dest);
1235 
1236  MythGenericTree *parent = node->getParent();
1237 
1238  if (parent && metadata && ((QString::compare(parent->GetText(),
1239  metadata->GetTitle(), Qt::CaseInsensitive) == 0) ||
1240  parent->GetText().startsWith(tr("Season"), Qt::CaseInsensitive)))
1241  item->SetText(metadata->GetSubtitle());
1242  else if (metadata && !metadata->GetSubtitle().isEmpty())
1243  item->SetText(QString("%1: %2").arg(metadata->GetTitle()).arg(metadata->GetSubtitle()));
1244  else
1245  item->SetText(metadata ? metadata->GetTitle() : node->GetText());
1246 
1247  QString coverimage = GetCoverImage(node);
1248  QString screenshot = GetScreenshot(node);
1249  QString banner = GetBanner(node);
1250  QString fanart = GetFanart(node);
1251 
1252  if (!screenshot.isEmpty() && parent && metadata &&
1253  ((QString::compare(parent->GetText(),
1254  metadata->GetTitle(), Qt::CaseInsensitive) == 0) ||
1255  parent->GetText().startsWith(tr("Season"), Qt::CaseInsensitive)))
1256  {
1257  item->SetImage(screenshot);
1258  }
1259  else
1260  {
1261  if (coverimage.isEmpty())
1262  coverimage = GetFirstImage(node, "Coverart");
1263  item->SetImage(coverimage);
1264  }
1265 
1266  int nodeInt = node->getInt();
1267 
1268  if (coverimage.isEmpty() && nodeInt == kSubFolder)
1269  coverimage = GetFirstImage(node, "Coverart");
1270 
1271  item->SetImage(coverimage, "coverart");
1272 
1273  if (screenshot.isEmpty() && nodeInt == kSubFolder)
1274  screenshot = GetFirstImage(node, "Screenshots");
1275 
1276  item->SetImage(screenshot, "screenshot");
1277 
1278  if (banner.isEmpty() && nodeInt == kSubFolder)
1279  banner = GetFirstImage(node, "Banners");
1280 
1281  item->SetImage(banner, "banner");
1282 
1283  if (fanart.isEmpty() && nodeInt == kSubFolder)
1284  fanart = GetFirstImage(node, "Fanart");
1285 
1286  item->SetImage(fanart, "fanart");
1287 
1288  if (nodeInt == kSubFolder)
1289  {
1290  item->SetText(QString("%1").arg(node->visibleChildCount()), "childcount");
1291  item->DisplayState("subfolder", "nodetype");
1292  item->SetText(node->GetText(), "title");
1293  item->SetText(node->GetText());
1294  }
1295  else if (nodeInt == kUpFolder)
1296  {
1297  item->DisplayState("upfolder", "nodetype");
1298  item->SetText(node->GetText(), "title");
1299  item->SetText(node->GetText());
1300  }
1301 
1302  if (item == GetItemCurrent())
1303  UpdateText(item);
1304 }
1305 
1311 {
1312  MythGenericTree *oldroot = m_d->m_rootNode;
1313  if (!m_d->m_treeLoaded)
1314  {
1317  m_d->m_parentalLevel.GetLevel(), true);
1318  }
1319  else
1320  {
1322  m_d->m_parentalLevel.GetLevel(),
1325  }
1326 
1327  m_d->m_treeLoaded = true;
1328 
1329  // Move a node down if there is a single directory item here...
1330  if (m_d->m_rootNode->childCount() == 1)
1331  {
1333  if (node->getInt() == kSubFolder && node->childCount() > 1)
1334  m_d->m_rootNode = node;
1335  else if (node->getInt() == kUpFolder)
1336  m_d->m_treeLoaded = false;
1337  }
1338  else if (m_d->m_rootNode->childCount() == 0)
1339  m_d->m_treeLoaded = false;
1340 
1341  if (!m_d->m_currentNode || m_d->m_rootNode != oldroot)
1343 }
1344 
1349 QString VideoDialog::RemoteImageCheck(QString host, QString filename)
1350 {
1351  QString result = "";
1352 #if 0
1353  LOG(VB_GENERAL, LOG_DEBUG, QString("RemoteImageCheck(%1)").arg(filename));
1354 #endif
1355 
1356  QStringList dirs = GetVideoDirsByHost(host);
1357 
1358  if (!dirs.isEmpty())
1359  {
1360  for (QStringList::const_iterator iter = dirs.begin();
1361  iter != dirs.end(); ++iter)
1362  {
1363  QUrl sgurl = *iter;
1364  QString path = sgurl.path();
1365 
1366  QString fname = QString("%1/%2").arg(path).arg(filename);
1367 
1368  QStringList list( QString("QUERY_SG_FILEQUERY") );
1369  list << host;
1370  list << "Videos";
1371  list << fname;
1372 
1373  bool ok = gCoreContext->SendReceiveStringList(list);
1374 
1375  if (!ok || list.at(0).startsWith("SLAVE UNREACHABLE"))
1376  {
1377  LOG(VB_GENERAL, LOG_WARNING,
1378  QString("Backend : %1 currently Unreachable. Skipping "
1379  "this one.") .arg(host));
1380  break;
1381  }
1382 
1383  if ((!list.isEmpty()) && (list.at(0) == fname))
1384  result = generate_file_url("Videos", host, filename);
1385 
1386  if (!result.isEmpty())
1387  {
1388 #if 0
1389  LOG(VB_GENERAL, LOG_DEBUG,
1390  QString("RemoteImageCheck(%1) res :%2: :%3:")
1391  .arg(fname).arg(result).arg(*iter));
1392 #endif
1393  break;
1394  }
1395 
1396  }
1397  }
1398 
1399  return result;
1400 }
1401 
1407 {
1408  QString icon_file;
1409  QString host = metadata->GetHost();
1410  QFileInfo fullpath(metadata->GetFilename());
1411  QDir dir = fullpath.dir();
1412  QString prefix = QDir::cleanPath(dir.path());
1413 
1414  QString filename = QString("%1/folder").arg(prefix);
1415 
1416  QStringList test_files;
1417  test_files.append(filename + ".png");
1418  test_files.append(filename + ".jpg");
1419  test_files.append(filename + ".gif");
1420  bool foundCover;
1421 
1422  for (QStringList::const_iterator tfp = test_files.begin();
1423  tfp != test_files.end(); ++tfp)
1424  {
1425  QString imagePath = *tfp;
1426  foundCover = false;
1427  if (!host.isEmpty())
1428  {
1429  // Strip out any extra /'s
1430  imagePath.replace("//", "/");
1431  prefix.replace("//","/");
1432  imagePath = imagePath.right(imagePath.length() - (prefix.length() + 1));
1433  QString tmpCover = RemoteImageCheck(host, imagePath);
1434 
1435  if (!tmpCover.isEmpty())
1436  {
1437  foundCover = true;
1438  imagePath = tmpCover;
1439  }
1440  }
1441  else
1442  foundCover = QFile::exists(imagePath);
1443 
1444  if (foundCover)
1445  {
1446  icon_file = imagePath;
1447  return icon_file;
1448  }
1449  }
1450 
1451  // If we found nothing, load something that matches the title.
1452  // If that fails, load anything we find.
1453  if (icon_file.isEmpty())
1454  {
1455  QStringList imageTypes;
1456  imageTypes.append(metadata->GetTitle() + ".png");
1457  imageTypes.append(metadata->GetTitle() + ".jpg");
1458  imageTypes.append(metadata->GetTitle() + ".gif");
1459  imageTypes.append("*.png");
1460  imageTypes.append("*.jpg");
1461  imageTypes.append("*.gif");
1462 
1463  QStringList fList;
1464 
1465  if (!host.isEmpty())
1466  {
1467  // TODO: This can likely get a little cleaner
1468 
1469  QStringList dirs = GetVideoDirsByHost(host);
1470 
1471  if (!dirs.isEmpty())
1472  {
1473  for (QStringList::const_iterator iter = dirs.begin();
1474  iter != dirs.end(); ++iter)
1475  {
1476  QUrl sgurl = *iter;
1477  QString path = sgurl.path();
1478 
1479  QString subdir = prefix;
1480 
1481  path = path + "/" + subdir;
1482  QStringList tmpList;
1483  bool ok = RemoteGetFileList(host, path, &tmpList, "Videos");
1484 
1485  if (ok)
1486  {
1487  for (QStringList::const_iterator pattern = imageTypes.begin();
1488  pattern != imageTypes.end(); ++pattern)
1489  {
1490  QRegExp rx(*pattern);
1491  rx.setPatternSyntax(QRegExp::Wildcard);
1492  QStringList matches = tmpList.filter(rx);
1493  if (!matches.isEmpty())
1494  {
1495  fList.clear();
1496  fList.append(subdir + "/" + matches.at(0).split("::").at(1));
1497  break;
1498  }
1499  }
1500 
1501  break;
1502  }
1503  }
1504  }
1505  }
1506  else
1507  {
1508  QDir vidDir(prefix);
1509  vidDir.setNameFilters(imageTypes);
1510  fList = vidDir.entryList();
1511  }
1512 
1513  if (!fList.isEmpty())
1514  {
1515  if (host.isEmpty())
1516  icon_file = QString("%1/%2")
1517  .arg(prefix)
1518  .arg(fList.at(0));
1519  else
1520  icon_file = generate_file_url("Videos", host, fList.at(0));
1521  }
1522  }
1523 
1524  if (!icon_file.isEmpty())
1525  LOG(VB_GENERAL, LOG_DEBUG, QString("Found Image : %1 :")
1526  .arg(icon_file));
1527  else
1528  LOG(VB_GENERAL, LOG_DEBUG, QString("Could not find cover Image : %1 ")
1529  .arg(prefix));
1530 
1531  if (IsDefaultCoverFile(icon_file))
1532  icon_file.clear();
1533 
1534  return icon_file;
1535 }
1536 
1542 {
1543  int nodeInt = node->getInt();
1544 
1545  QString icon_file;
1546 
1547  if (nodeInt == kSubFolder) // subdirectory
1548  {
1549  // load folder icon
1550  QString folder_path = node->GetData().value<TreeNodeData>().GetPath();
1551  QString host = node->GetData().value<TreeNodeData>().GetHost();
1552  QString prefix = node->GetData().value<TreeNodeData>().GetPrefix();
1553 
1554  if (folder_path.startsWith("myth://"))
1555  folder_path = folder_path.right(folder_path.length()
1556  - folder_path.lastIndexOf("//") - 1);
1557 
1558  QString filename = QString("%1/folder").arg(folder_path);
1559 
1560 #if 0
1561  LOG(VB_GENERAL, LOG_DEBUG,
1562  QString("GetCoverImage host : %1 prefix : %2 file : %3")
1563  .arg(host).arg(prefix).arg(filename));
1564 #endif
1565 
1566  QStringList test_files;
1567  test_files.append(filename + ".png");
1568  test_files.append(filename + ".jpg");
1569  test_files.append(filename + ".gif");
1570  bool foundCover;
1571 
1572  for (QStringList::const_iterator tfp = test_files.begin();
1573  tfp != test_files.end(); ++tfp)
1574  {
1575  QString imagePath = *tfp;
1576 #if 0
1577  LOG(VB_GENERAL, LOG_DEBUG, QString("Cover check :%1 : ").arg(*tfp));
1578 #endif
1579 
1580  foundCover = false;
1581  if (!host.isEmpty())
1582  {
1583  // Strip out any extra /'s
1584  imagePath.replace("//", "/");
1585  prefix.replace("//","/");
1586  imagePath = imagePath.right(imagePath.length() - (prefix.length() + 1));
1587  QString tmpCover = RemoteImageCheck(host, imagePath);
1588 
1589  if (!tmpCover.isEmpty())
1590  {
1591  foundCover = true;
1592  imagePath = tmpCover;
1593  }
1594  }
1595  else
1596  foundCover = QFile::exists(imagePath);
1597 
1598  if (foundCover)
1599  {
1600  icon_file = imagePath;
1601  break;
1602  }
1603  }
1604 
1605  // If we found nothing, load the first image we find
1606  if (icon_file.isEmpty())
1607  {
1608  QStringList imageTypes;
1609  imageTypes.append("*.png");
1610  imageTypes.append("*.jpg");
1611  imageTypes.append("*.gif");
1612 
1613  QStringList fList;
1614 
1615  if (!host.isEmpty())
1616  {
1617  // TODO: This can likely get a little cleaner
1618 
1619  QStringList dirs = GetVideoDirsByHost(host);
1620 
1621  if (!dirs.isEmpty())
1622  {
1623  for (QStringList::const_iterator iter = dirs.begin();
1624  iter != dirs.end(); ++iter)
1625  {
1626  QUrl sgurl = *iter;
1627  QString path = sgurl.path();
1628 
1629  QString subdir = folder_path.right(folder_path.length() - (prefix.length() + 2));
1630 
1631  path = path + "/" + subdir;
1632 
1633  QStringList tmpList;
1634  bool ok = RemoteGetFileList(host, path, &tmpList, "Videos");
1635 
1636  if (ok)
1637  {
1638  for (QStringList::const_iterator pattern = imageTypes.begin();
1639  pattern != imageTypes.end(); ++pattern)
1640  {
1641  QRegExp rx(*pattern);
1642  rx.setPatternSyntax(QRegExp::Wildcard);
1643  QStringList matches = tmpList.filter(rx);
1644  if (!matches.isEmpty())
1645  {
1646  fList.clear();
1647  fList.append(subdir + "/" + matches.at(0).split("::").at(1));
1648  break;
1649  }
1650  }
1651 
1652  break;
1653  }
1654  }
1655  }
1656 
1657  }
1658  else
1659  {
1660  QDir vidDir(folder_path);
1661  vidDir.setNameFilters(imageTypes);
1662  fList = vidDir.entryList();
1663  }
1664 
1665  // Take the Coverfile for the first valid node in the dir, if it exists.
1666  if (icon_file.isEmpty())
1667  {
1668  int list_count = node->visibleChildCount();
1669  if (list_count > 0)
1670  {
1671  for (int i = 0; i < list_count; i++)
1672  {
1673  MythGenericTree *subnode = node->getVisibleChildAt(i);
1674  if (subnode)
1675  {
1676  VideoMetadata *metadata = GetMetadataPtrFromNode(subnode);
1677  if (metadata)
1678  {
1679  if (!metadata->GetHost().isEmpty() &&
1680  !metadata->GetCoverFile().startsWith("/"))
1681  {
1682  QString test_file = generate_file_url("Coverart",
1683  metadata->GetHost(), metadata->GetCoverFile());
1684  if (!test_file.endsWith("/") && !test_file.isEmpty() &&
1685  !IsDefaultCoverFile(test_file))
1686  {
1687  icon_file = test_file;
1688  break;
1689  }
1690  }
1691  else
1692  {
1693  QString test_file = metadata->GetCoverFile();
1694  if (!test_file.isEmpty() &&
1695  !IsDefaultCoverFile(test_file))
1696  {
1697  icon_file = test_file;
1698  break;
1699  }
1700  }
1701  }
1702  }
1703  }
1704  }
1705  }
1706 
1707  if (!fList.isEmpty())
1708  {
1709  if (host.isEmpty())
1710  icon_file = QString("%1/%2")
1711  .arg(folder_path)
1712  .arg(fList.at(0));
1713  else
1714  icon_file = generate_file_url("Videos", host, fList.at(0));
1715  }
1716  }
1717 
1718  if (!icon_file.isEmpty())
1719  LOG(VB_GENERAL, LOG_DEBUG, QString("Found Image : %1 :")
1720  .arg(icon_file));
1721  else
1722  LOG(VB_GENERAL, LOG_DEBUG,
1723  QString("Could not find folder cover Image : %1 ")
1724  .arg(folder_path));
1725  }
1726  else
1727  {
1728  const VideoMetadata *metadata = GetMetadataPtrFromNode(node);
1729 
1730  if (metadata)
1731  {
1732  if (metadata->IsHostSet() &&
1733  !metadata->GetCoverFile().startsWith("/") &&
1734  !IsDefaultCoverFile(metadata->GetCoverFile()))
1735  {
1736  icon_file = generate_file_url("Coverart", metadata->GetHost(),
1737  metadata->GetCoverFile());
1738  }
1739  else
1740  {
1741  icon_file = metadata->GetCoverFile();
1742  }
1743  }
1744  }
1745 
1746  if (IsDefaultCoverFile(icon_file))
1747  icon_file.clear();
1748 
1749  return icon_file;
1750 }
1751 
1764  QString gpnode, int levels)
1765 {
1766  if (!node || type.isEmpty())
1767  return QString();
1768 
1769  QString icon_file;
1770 
1771  int list_count = node->visibleChildCount();
1772  if (list_count > 0)
1773  {
1774  QList<MythGenericTree *> subDirs;
1775  int maxRecurse = 1;
1776 
1777  for (int i = 0; i < list_count; i++)
1778  {
1779  MythGenericTree *subnode = node->getVisibleChildAt(i);
1780  if (subnode)
1781  {
1782  if (subnode->childCount() > 0)
1783  subDirs << subnode;
1784 
1785  VideoMetadata *metadata = GetMetadataPtrFromNode(subnode);
1786  if (metadata)
1787  {
1788  QString test_file;
1789  QString host = metadata->GetHost();
1790  QString title = metadata->GetTitle();
1791 
1792  if (type == "Coverart" && !host.isEmpty() &&
1793  !metadata->GetCoverFile().startsWith("/"))
1794  {
1795  test_file = generate_file_url("Coverart",
1796  host, metadata->GetCoverFile());
1797  }
1798  else if (type == "Coverart")
1799  test_file = metadata->GetCoverFile();
1800 
1801  if (!test_file.endsWith("/") && !test_file.isEmpty() &&
1802  !IsDefaultCoverFile(test_file) && (gpnode.isEmpty() ||
1803  (QString::compare(gpnode, title, Qt::CaseInsensitive) == 0)))
1804  {
1805  icon_file = test_file;
1806  break;
1807  }
1808 
1809  if (type == "Fanart" && !host.isEmpty() &&
1810  !metadata->GetFanart().startsWith("/"))
1811  {
1812  test_file = generate_file_url("Fanart",
1813  host, metadata->GetFanart());
1814  }
1815  else if (type == "Fanart")
1816  test_file = metadata->GetFanart();
1817 
1818  if (!test_file.endsWith("/") && !test_file.isEmpty() &&
1819  test_file != VIDEO_FANART_DEFAULT && (gpnode.isEmpty() ||
1820  (QString::compare(gpnode, title, Qt::CaseInsensitive) == 0)))
1821  {
1822  icon_file = test_file;
1823  break;
1824  }
1825 
1826  if (type == "Banners" && !host.isEmpty() &&
1827  !metadata->GetBanner().startsWith("/"))
1828  {
1829  test_file = generate_file_url("Banners",
1830  host, metadata->GetBanner());
1831  }
1832  else if (type == "Banners")
1833  test_file = metadata->GetBanner();
1834 
1835  if (!test_file.endsWith("/") && !test_file.isEmpty() &&
1836  test_file != VIDEO_BANNER_DEFAULT && (gpnode.isEmpty() ||
1837  (QString::compare(gpnode, title, Qt::CaseInsensitive) == 0)))
1838  {
1839  icon_file = test_file;
1840  break;
1841  }
1842 
1843  if (type == "Screenshots" && !host.isEmpty() &&
1844  !metadata->GetScreenshot().startsWith("/"))
1845  {
1846  test_file = generate_file_url("Screenshots",
1847  host, metadata->GetScreenshot());
1848  }
1849  else if (type == "Screenshots")
1850  test_file = metadata->GetScreenshot();
1851 
1852  if (!test_file.endsWith("/") && !test_file.isEmpty() &&
1853  test_file != VIDEO_SCREENSHOT_DEFAULT && (gpnode.isEmpty() ||
1854  (QString::compare(gpnode, title, Qt::CaseInsensitive) == 0)))
1855  {
1856  icon_file = test_file;
1857  break;
1858  }
1859  }
1860  }
1861  }
1862  if (icon_file.isEmpty() && !subDirs.isEmpty())
1863  {
1864  QString test_file;
1865  int subDirCount = subDirs.count();
1866  for (int i = 0; i < subDirCount; i ++)
1867  {
1868  if (levels < maxRecurse)
1869  {
1870  test_file = GetFirstImage(subDirs[i], type,
1871  node->GetText(), levels + 1);
1872  if (!test_file.isEmpty())
1873  {
1874  icon_file = test_file;
1875  break;
1876  }
1877  }
1878  }
1879  }
1880  }
1881  return icon_file;
1882 }
1883 
1889 {
1890  const int nodeInt = node->getInt();
1891 
1892  QString icon_file;
1893 
1894  if (nodeInt == kSubFolder || nodeInt == kUpFolder) // subdirectory
1895  {
1896  icon_file = VIDEO_SCREENSHOT_DEFAULT;
1897  }
1898  else
1899  {
1900  const VideoMetadata *metadata = GetMetadataPtrFromNode(node);
1901 
1902  if (metadata)
1903  {
1904  if (metadata->IsHostSet() &&
1905  !metadata->GetScreenshot().startsWith("/") &&
1906  !metadata->GetScreenshot().isEmpty())
1907  {
1908  icon_file = generate_file_url("Screenshots", metadata->GetHost(),
1909  metadata->GetScreenshot());
1910  }
1911  else
1912  {
1913  icon_file = metadata->GetScreenshot();
1914  }
1915  }
1916  }
1917 
1918  if (IsDefaultScreenshot(icon_file))
1919  icon_file.clear();
1920 
1921  return icon_file;
1922 }
1923 
1929 {
1930  const int nodeInt = node->getInt();
1931 
1932  if (nodeInt == kSubFolder || nodeInt == kUpFolder)
1933  return QString();
1934 
1935  QString icon_file;
1936  const VideoMetadata *metadata = GetMetadataPtrFromNode(node);
1937 
1938  if (metadata)
1939  {
1940  if (metadata->IsHostSet() &&
1941  !metadata->GetBanner().startsWith("/") &&
1942  !metadata->GetBanner().isEmpty())
1943  {
1944  icon_file = generate_file_url("Banners", metadata->GetHost(),
1945  metadata->GetBanner());
1946  }
1947  else
1948  {
1949  icon_file = metadata->GetBanner();
1950  }
1951 
1952  if (IsDefaultBanner(icon_file))
1953  icon_file.clear();
1954  }
1955 
1956  return icon_file;
1957 }
1958 
1964 {
1965  const int nodeInt = node->getInt();
1966 
1967  if (nodeInt == kSubFolder || nodeInt == kUpFolder) // subdirectory
1968  return QString();
1969 
1970  QString icon_file;
1971  const VideoMetadata *metadata = GetMetadataPtrFromNode(node);
1972 
1973  if (metadata)
1974  {
1975  if (metadata->IsHostSet() &&
1976  !metadata->GetFanart().startsWith("/") &&
1977  !metadata->GetFanart().isEmpty())
1978  {
1979  icon_file = generate_file_url("Fanart", metadata->GetHost(),
1980  metadata->GetFanart());
1981  }
1982  else
1983  {
1984  icon_file = metadata->GetFanart();
1985  }
1986 
1987  if (IsDefaultFanart(icon_file))
1988  icon_file.clear();
1989  }
1990 
1991  return icon_file;
1992 }
1993 
1998 bool VideoDialog::keyPressEvent(QKeyEvent *levent)
1999 {
2000  if (GetFocusWidget()->keyPressEvent(levent))
2001  return true;
2002 
2003  bool handled = false;
2004  QStringList actions;
2005  handled = GetMythMainWindow()->TranslateKeyPress("Video", levent, actions);
2006 
2007  for (int i = 0; i < actions.size() && !handled; i++)
2008  {
2009  QString action = actions[i];
2010  handled = true;
2011 
2012  if (action == "INFO")
2013  {
2015  MythGenericTree *node = GetNodePtrFromButton(item);
2016  if (!m_menuPopup && node->getInt() != kUpFolder)
2017  VideoMenu();
2018  }
2019  else if (action == "INCPARENT")
2020  shiftParental(1);
2021  else if (action == "DECPARENT")
2022  shiftParental(-1);
2023  else if (action == "1" || action == "2" ||
2024  action == "3" || action == "4")
2025  setParentalLevel((ParentalLevel::Level)action.toInt());
2026  else if (action == "FILTER")
2027  ChangeFilter();
2028  else if (action == "MENU")
2029  {
2030  if (!m_menuPopup)
2031  DisplayMenu();
2032  }
2033  else if (action == "PLAYALT")
2034  {
2035  if (!m_menuPopup && GetMetadata(GetItemCurrent()) &&
2037  playVideoAlt();
2038  }
2039  else if (action == "DOWNLOADDATA")
2040  {
2042  VideoSearch();
2043  }
2044  else if (action == "INCSEARCH")
2045  searchStart();
2046  else if (action == "ITEMDETAIL")
2047  DoItemDetailShow();
2048  else if (action == "DELETE")
2049  {
2051  RemoveVideo();
2052  }
2053  else if (action == "EDIT" && !m_menuPopup)
2054  EditMetadata();
2055  else if (action == "ESCAPE")
2056  {
2057  if (m_d->m_type != DLG_TREE
2058  && !GetMythMainWindow()->IsExitingToMain()
2059  && m_d->m_currentNode != m_d->m_rootNode)
2060  handled = goBack();
2061  else
2062  handled = false;
2063  }
2064  else
2065  handled = false;
2066  }
2067 
2068  if (!handled)
2069  {
2070  handled = GetMythMainWindow()->TranslateKeyPress("TV Frontend", levent,
2071  actions);
2072 
2073  for (int i = 0; i < actions.size() && !handled; i++)
2074  {
2075  QString action = actions[i];
2076  if (action == "PLAYBACK")
2077  {
2078  handled = true;
2079  playVideo();
2080  }
2081  }
2082  }
2083 
2084  if (!handled && MythScreenType::keyPressEvent(levent))
2085  handled = true;
2086 
2087  return handled;
2088 }
2089 
2095 {
2096  if (m_busyPopup)
2097  return;
2098 
2099  QString message = title;
2100 
2101  m_busyPopup = new MythUIBusyDialog(message, m_popupStack,
2102  "mythvideobusydialog");
2103 
2104  if (m_busyPopup->Create())
2106 }
2107 
2112 void VideoDialog::createOkDialog(QString title)
2113 {
2114  QString message = title;
2115 
2116  MythConfirmationDialog *okPopup =
2117  new MythConfirmationDialog(m_popupStack, message, false);
2118 
2119  if (okPopup->Create())
2120  m_popupStack->AddScreen(okPopup);
2121 }
2122 
2127 void VideoDialog::searchComplete(QString string)
2128 {
2129  LOG(VB_GENERAL, LOG_DEBUG, QString("Jumping to: %1").arg(string));
2130 
2132  QStringList childList;
2133  QList<MythGenericTree*>::iterator it;
2134  QList<MythGenericTree*> *children;
2135  QMap<int, QString> idTitle;
2136 
2137  if (parent && m_d->m_type == DLG_TREE)
2138  children = parent->getAllChildren();
2139  else
2140  children = m_d->m_currentNode->getAllChildren();
2141 
2142  for (it = children->begin(); it != children->end(); ++it)
2143  {
2144  MythGenericTree *child = *it;
2145  QString title = child->GetText();
2146  int id = child->getPosition();
2147  idTitle.insert(id, title);
2148  }
2149 
2150  if (m_d->m_type == DLG_TREE)
2151  {
2153  MythGenericTree *new_node = parent->getChildAt(idTitle.key(string));
2154  if (new_node)
2155  {
2156  m_videoButtonTree->SetCurrentNode(new_node);
2158  }
2159  }
2160  else
2161  m_videoButtonList->SetItemCurrent(idTitle.key(string));
2162 }
2163 
2169 {
2171 
2172  QStringList childList;
2173  QList<MythGenericTree*>::iterator it;
2174  QList<MythGenericTree*> *children;
2175  if (parent && m_d->m_type == DLG_TREE)
2176  children = parent->getAllChildren();
2177  else
2178  children = m_d->m_currentNode->getAllChildren();
2179 
2180  for (it = children->begin(); it != children->end(); ++it)
2181  {
2182  MythGenericTree *child = *it;
2183  childList << child->GetText();
2184  }
2185 
2186  MythScreenStack *popupStack =
2187  GetMythMainWindow()->GetStack("popup stack");
2188  MythUISearchDialog *searchDialog = new MythUISearchDialog(popupStack,
2189  tr("Video Search"), childList, false, "");
2190 
2191  if (searchDialog->Create())
2192  {
2193  connect(searchDialog, SIGNAL(haveResult(QString)),
2194  SLOT(searchComplete(QString)));
2195 
2196  popupStack->AddScreen(searchDialog);
2197  }
2198  else
2199  delete searchDialog;
2200 }
2201 
2207 {
2208  bool handled = false;
2209 
2210  if (m_d->m_currentNode != m_d->m_rootNode)
2211  {
2212  MythGenericTree *lparent = m_d->m_currentNode->getParent();
2213  if (lparent)
2214  {
2215  SetCurrentNode(lparent);
2216 
2217  handled = true;
2218  }
2219  }
2220 
2221  loadData();
2222 
2223  return handled;
2224 }
2225 
2231 {
2232  if (!node)
2233  return;
2234 
2235  m_d->m_currentNode = node;
2236 }
2237 
2243 {
2245  MythUIButtonList *currentList = ci ? ci->parent() : 0;
2246 
2247  if (!currentList)
2248  return;
2249 
2250  CheckedSet(m_positionText, tr("%1 of %2")
2251  .arg(currentList->IsEmpty() ? 0 : currentList->GetCurrentPos() + 1)
2252  .arg(currentList->GetCount()));
2253 }
2254 
2260 {
2261  if (!item)
2262  return;
2263 
2264  MythUIButtonList *currentList = item->parent();
2265 
2266  if (!currentList)
2267  return;
2268 
2269  VideoMetadata *metadata = GetMetadata(item);
2270 
2271  MythGenericTree *node = GetNodePtrFromButton(item);
2272 
2273  if (!node)
2274  return;
2275 
2276  if (metadata)
2277  {
2278  MetadataMap metadataMap;
2279  metadata->toMap(metadataMap);
2280  SetTextFromMap(metadataMap);
2281  }
2282  else
2283  {
2284  MetadataMap metadataMap;
2285  ClearMap(metadataMap);
2286  SetTextFromMap(metadataMap);
2287  }
2288 
2289  ScreenCopyDest dest(this);
2290  CopyMetadataToUI(metadata, dest);
2291 
2292  if (node->getInt() == kSubFolder && !metadata)
2293  {
2294  QString cover = GetFirstImage(node, "Coverart");
2295  QString fanart = GetFirstImage(node, "Fanart");
2296  QString banner = GetFirstImage(node, "Banners");
2297  QString screenshot = GetFirstImage(node, "Screenshots");
2298  CheckedSet(m_coverImage, cover);
2299  CheckedSet(m_fanart, fanart);
2300  CheckedSet(m_banner, banner);
2301  CheckedSet(m_screenshot, screenshot);
2302  }
2303 
2304  if (!metadata)
2305  CheckedSet(m_titleText, item->GetText());
2306  UpdatePosition();
2307 
2308  if (m_d->m_currentNode)
2309  {
2311  CheckedSet(this, "foldername", m_d->m_currentNode->GetText());
2312  }
2313 
2314  if (node && node->getInt() == kSubFolder)
2315  CheckedSet(this, "childcount",
2316  QString("%1").arg(node->visibleChildCount()));
2317 
2318  if (node)
2319  node->becomeSelectedChild();
2320 }
2321 
2327 {
2328  VideoMetadata *metadata = GetMetadata(GetItemCurrent());
2329  QString label;
2330 
2331  if (metadata)
2332  {
2333  if (!metadata->GetSubtitle().isEmpty())
2334  label = tr("Video Options\n%1\n%2").arg(metadata->GetTitle())
2335  .arg(metadata->GetSubtitle());
2336  else
2337  label = tr("Video Options\n%1").arg(metadata->GetTitle());
2338  }
2339  else
2340  label = tr("Video Options");
2341 
2342  MythMenu *menu = new MythMenu(label, this, "actions");
2343 
2345  MythGenericTree *node = GetNodePtrFromButton(item);
2346  if (metadata)
2347  {
2348  if (!metadata->GetTrailer().isEmpty() ||
2349  gCoreContext->GetNumSetting("mythvideo.TrailersRandomEnabled", 0) ||
2351  menu->AddItem(tr("Play..."), NULL, CreatePlayMenu());
2352  else
2353  menu->AddItem(tr("Play"), SLOT(playVideo()));
2354  if (metadata->GetWatched())
2355  menu->AddItem(tr("Mark as Unwatched"), SLOT(ToggleWatched()));
2356  else
2357  menu->AddItem(tr("Mark as Watched"), SLOT(ToggleWatched()));
2358  menu->AddItem(tr("Video Info"), NULL, CreateInfoMenu());
2359  menu->AddItem(tr("Change Video Details"), NULL, CreateManageMenu());
2360  menu->AddItem(tr("Delete"), SLOT(RemoveVideo()));
2361  }
2362  else if (node && node->getInt() != kUpFolder)
2363  {
2364  menu->AddItem(tr("Play Folder"), SLOT(playFolder()));
2365  }
2366 
2367 
2368  m_menuPopup = new MythDialogBox(menu, m_popupStack, "videomenupopup");
2369 
2370  if (m_menuPopup->Create())
2372  else
2373  delete m_menuPopup;
2374 }
2375 
2382 {
2383  VideoMetadata *metadata = GetMetadata(GetItemCurrent());
2384  QString label;
2385 
2386  if (metadata)
2387  label = tr("Playback Options\n%1").arg(metadata->GetTitle());
2388  else
2389  return NULL;
2390 
2391  MythMenu *menu = new MythMenu(label, this, "actions");
2392 
2393  menu->AddItem(tr("Play"), SLOT(playVideo()));
2394 
2395  if (m_d->m_altPlayerEnabled)
2396  {
2397  menu->AddItem(tr("Play in Alternate Player"), SLOT(playVideoAlt()));
2398  }
2399 
2400  if (gCoreContext->GetNumSetting("mythvideo.TrailersRandomEnabled", 0))
2401  {
2402  menu->AddItem(tr("Play With Trailers"), SLOT(playVideoWithTrailers()));
2403  }
2404 
2405  QString trailerFile = metadata->GetTrailer();
2406  if (QFile::exists(trailerFile) ||
2407  (!metadata->GetHost().isEmpty() && !trailerFile.isEmpty()))
2408  {
2409  menu->AddItem(tr("Play Trailer"), SLOT(playTrailer()));
2410  }
2411 
2412  return menu;
2413 }
2414 
2420 {
2421  QString label = tr("Video Display Menu");
2422 
2423  MythMenu *menu = new MythMenu(label, this, "display");
2424 
2425  menu->AddItem(tr("Scan For Changes"), SLOT(doVideoScan()));
2426  menu->AddItem(tr("Retrieve All Details"), SLOT(VideoAutoSearch()));
2427  menu->AddItem(tr("Filter Display"), SLOT(ChangeFilter()));
2428  menu->AddItem(tr("Browse By..."), NULL, CreateMetadataBrowseMenu());
2429  menu->AddItem(tr("Change View"), NULL, CreateViewMenu());
2430  menu->AddItem(tr("Settings"), NULL, CreateSettingsMenu());
2431 
2432  m_menuPopup = new MythDialogBox(menu, m_popupStack, "videomenupopup");
2433 
2434  if (m_menuPopup->Create())
2436  else
2437  delete m_menuPopup;
2438 }
2439 
2445 {
2446  QString label = tr("Change View");
2447 
2448  MythMenu *menu = new MythMenu(label, this, "view");
2449 
2450  if (!(m_d->m_type & DLG_BROWSER))
2451  menu->AddItem(tr("Switch to Browse View"), SLOT(SwitchBrowse()));
2452 
2453  if (!(m_d->m_type & DLG_GALLERY))
2454  menu->AddItem(tr("Switch to Gallery View"), SLOT(SwitchGallery()));
2455 
2456  if (!(m_d->m_type & DLG_TREE))
2457  menu->AddItem(tr("Switch to List View"), SLOT(SwitchTree()));
2458 
2459  if (!(m_d->m_type & DLG_MANAGER))
2460  menu->AddItem(tr("Switch to Manage View"), SLOT(SwitchManager()));
2461 
2462  if (m_d->m_isFlatList)
2463  menu->AddItem(tr("Show Directory Structure"), SLOT(ToggleFlatView()));
2464  else
2465  menu->AddItem(tr("Hide Directory Structure"), SLOT(ToggleFlatView()));
2466 
2467  if (m_d->m_isFileBrowser)
2468  menu->AddItem(tr("Browse Library (recommended)"), SLOT(ToggleBrowseMode()));
2469  else
2470  menu->AddItem(tr("Browse Filesystem (slow)"), SLOT(ToggleBrowseMode()));
2471 
2472 
2473  return menu;
2474 }
2475 
2481 {
2482  QString label = tr("Video Settings");
2483 
2484  MythMenu *menu = new MythMenu(label, this, "settings");
2485 
2486  menu->AddItem(tr("Player Settings"), SLOT(ShowPlayerSettings()));
2487  menu->AddItem(tr("Metadata Settings"), SLOT(ShowMetadataSettings()));
2488  menu->AddItem(tr("File Type Settings"), SLOT(ShowExtensionSettings()));
2489 
2490  return menu;
2491 }
2492 
2498 {
2499  PlayerSettings *ps = new PlayerSettings(m_mainStack, "player settings");
2500 
2501  if (ps->Create())
2502  m_mainStack->AddScreen(ps);
2503  else
2504  delete ps;
2505 }
2506 
2512 {
2513  MetadataSettings *ms = new MetadataSettings(m_mainStack, "metadata settings");
2514 
2515  if (ms->Create())
2516  m_mainStack->AddScreen(ms);
2517  else
2518  delete ms;
2519 }
2520 
2526 {
2527  FileAssocDialog *fa = new FileAssocDialog(m_mainStack, "fa dialog");
2528 
2529  if (fa->Create())
2530  m_mainStack->AddScreen(fa);
2531  else
2532  delete fa;
2533 }
2534 
2540 {
2541  QString label = tr("Browse By");
2542 
2543  MythMenu *menu = new MythMenu(label, this, "metadata");
2544 
2545  if (m_d->m_groupType != BRS_CAST)
2546  menu->AddItem(tr("Cast"), SLOT(SwitchVideoCastGroup()));
2547 
2548  if (m_d->m_groupType != BRS_CATEGORY)
2549  menu->AddItem(tr("Category"), SLOT(SwitchVideoCategoryGroup()));
2550 
2551  if (m_d->m_groupType != BRS_INSERTDATE)
2552  menu->AddItem(tr("Date Added"), SLOT(SwitchVideoInsertDateGroup()));
2553 
2554  if (m_d->m_groupType != BRS_DIRECTOR)
2555  menu->AddItem(tr("Director"), SLOT(SwitchVideoDirectorGroup()));
2556 
2557  if (m_d->m_groupType != BRS_STUDIO)
2558  menu->AddItem(tr("Studio"), SLOT(SwitchVideoStudioGroup()));
2559 
2560  if (m_d->m_groupType != BRS_FOLDER)
2561  menu->AddItem(tr("Folder"), SLOT(SwitchVideoFolderGroup()));
2562 
2563  if (m_d->m_groupType != BRS_GENRE)
2564  menu->AddItem(tr("Genre"), SLOT(SwitchVideoGenreGroup()));
2565 
2566  if (m_d->m_groupType != BRS_TVMOVIE)
2567  menu->AddItem(tr("TV/Movies"),SLOT(SwitchVideoTVMovieGroup()));
2568 
2569  if (m_d->m_groupType != BRS_USERRATING)
2570  menu->AddItem(tr("User Rating"), SLOT(SwitchVideoUserRatingGroup()));
2571 
2572  if (m_d->m_groupType != BRS_YEAR)
2573  menu->AddItem(tr("Year"), SLOT(SwitchVideoYearGroup()));
2574 
2575  return menu;
2576 }
2577 
2583 {
2584  QString label = tr("Video Info");
2585 
2586  MythMenu *menu = new MythMenu(label, this, "info");
2587 
2589  menu->AddItem(tr("View Details"), SLOT(DoItemDetailShow()));
2590 
2591  menu->AddItem(tr("View Full Plot"), SLOT(ViewPlot()));
2592 
2593  VideoMetadata *metadata = GetMetadata(GetItemCurrent());
2594  if (metadata)
2595  {
2596  if (!metadata->GetCast().empty())
2597  menu->AddItem(tr("View Cast"), SLOT(ShowCastDialog()));
2598  if (!metadata->GetHomepage().isEmpty())
2599  menu->AddItem(tr("View Homepage"), SLOT(ShowHomepage()));
2600  }
2601 
2602  return menu;
2603 }
2604 
2610 {
2611  QString label = tr("Manage Video Details");
2612 
2613  MythMenu *menu = new MythMenu(label, this, "manage");
2614 
2615  VideoMetadata *metadata = GetMetadata(GetItemCurrent());
2616 
2617  menu->AddItem(tr("Edit Details"), SLOT(EditMetadata()));
2618  menu->AddItem(tr("Retrieve Details"), SLOT(VideoSearch()));
2619  if (metadata->GetProcessed())
2620  menu->AddItem(tr("Allow Updates"), SLOT(ToggleProcess()));
2621  else
2622  menu->AddItem(tr("Disable Updates"), SLOT(ToggleProcess()));
2623  menu->AddItem(tr("Reset Details"), SLOT(ResetMetadata()));
2624 
2625  return menu;
2626 }
2627 
2629 {
2630  VideoMetadata *metadata = GetMetadata(GetItemCurrent());
2631  if (metadata)
2632  {
2633  metadata->SetProcessed(!metadata->GetProcessed());
2634  metadata->UpdateDatabase();
2635 
2636  refreshData();
2637  }
2638 }
2639 
2645 {
2647  gCoreContext->SaveSetting("VideoDialogNoDB",
2648  QString("%1").arg((int)m_d->m_isFileBrowser));
2649  reloadData();
2650 }
2651 
2657 {
2659  gCoreContext->SaveSetting(QString("mythvideo.folder_view_%1").arg(m_d->m_type),
2660  QString("%1").arg((int)m_d->m_isFlatList));
2661  // TODO: This forces a complete tree rebuild, this is SLOW and shouldn't
2662  // be necessary since MythGenericTree can do a flat view without a rebuild,
2663  // I just don't want to re-write VideoList just now
2664  reloadData();
2665 }
2666 
2672 {
2673  SetCurrentNode(node);
2674  loadData();
2675 }
2676 
2682 {
2683  QStringList route = node->getRouteByString();
2684  if (m_d->m_videoList && m_d->m_videoList->refreshNode(node))
2685  reloadData();
2687 }
2688 
2694 {
2695  MythGenericTree *node = GetNodePtrFromButton(item);
2696  int nodeInt = node->getInt();
2697 
2698  switch (nodeInt)
2699  {
2700  case kDynamicSubFolder:
2701  handleDynamicDirSelect(node);
2702  break;
2703  case kSubFolder:
2704  handleDirSelect(node);
2705  break;
2706  case kUpFolder:
2707  goBack();
2708  break;
2709  default:
2710  {
2711  bool doPlay = true;
2712  if (m_d->m_type == DLG_GALLERY)
2713  {
2714  doPlay = !DoItemDetailShow();
2715  }
2716 
2717  if (doPlay)
2718  playVideo();
2719  }
2720  };
2721 }
2722 
2728 {
2730 }
2731 
2737 {
2739 }
2740 
2746 {
2748 }
2749 
2755 {
2757 }
2758 
2764 {
2766 }
2767 
2773 {
2775 }
2776 
2782 {
2784 }
2785 
2791 {
2793 }
2794 
2800 {
2802 }
2803 
2809 {
2811 }
2812 
2818 {
2820 }
2821 
2827 {
2829 }
2830 
2836 {
2838 }
2839 
2845 {
2847 }
2848 
2854 {
2855  m_d->m_switchingLayout = true;
2856 
2857  // save current position so it can be restored after the switch
2858  SavePosition();
2859 
2860  VideoDialog *mythvideo =
2861  new VideoDialog(GetMythMainWindow()->GetMainStack(), "mythvideo",
2862  m_d->m_videoList, type, browse);
2863 
2864  if (mythvideo->Create())
2865  {
2866  gCoreContext->SaveSetting("Default MythVideo View", type);
2867  gCoreContext->SaveSetting("mythvideo.db_group_type", browse);
2868  MythScreenStack *screenStack = GetScreenStack();
2869  screenStack->AddScreen(mythvideo);
2870  screenStack->PopScreen(this, false, false);
2871  deleteLater();
2872  }
2873  else
2874  {
2875  ShowOkPopup(tr("An error occurred when switching views."));
2876  }
2877 }
2878 
2884 {
2885  VideoMetadata *metadata = GetMetadata(GetItemCurrent());
2886 
2887  PlotDialog *plotdialog = new PlotDialog(m_popupStack, metadata);
2888 
2889  if (plotdialog->Create())
2890  m_popupStack->AddScreen(plotdialog);
2891 }
2892 
2898 {
2899  VideoMetadata *metadata = GetMetadata(GetItemCurrent());
2900 
2901  if (metadata)
2902  {
2904  ItemDetailPopup *idp = new ItemDetailPopup(mainStack, metadata,
2906 
2907  if (idp->Create())
2908  {
2909  mainStack->AddScreen(idp);
2910  return true;
2911  }
2912  }
2913 
2914  return false;
2915 }
2916 
2922 {
2923  VideoMetadata *metadata = GetMetadata(GetItemCurrent());
2924 
2925  CastDialog *castdialog = new CastDialog(m_popupStack, metadata);
2926 
2927  if (castdialog->Create())
2928  m_popupStack->AddScreen(castdialog);
2929 }
2930 
2932 {
2933  VideoMetadata *metadata = GetMetadata(GetItemCurrent());
2934 
2935  if (!metadata)
2936  return;
2937 
2938  QString url = metadata->GetHomepage();
2939 
2940  if (url.isEmpty())
2941  return;
2942 
2943  QString browser = gCoreContext->GetSetting("WebBrowserCommand", "");
2944  QString zoom = gCoreContext->GetSetting("WebBrowserZoomLevel", "1.0");
2945 
2946  if (browser.isEmpty())
2947  {
2948  ShowOkPopup(tr("No browser command set! MythVideo needs MythBrowser "
2949  "installed to display the homepage."));
2950  return;
2951  }
2952 
2953  if (browser.toLower() == "internal")
2954  {
2955  GetMythMainWindow()->HandleMedia("WebBrowser", url);
2956  return;
2957  }
2958  else
2959  {
2960  QString cmd = browser;
2961  cmd.replace("%ZOOM%", zoom);
2962  cmd.replace("%URL%", url);
2963  cmd.replace('\'', "%27");
2964  cmd.replace("&","\\&");
2965  cmd.replace(";","\\;");
2966 
2967  GetMythMainWindow()->AllowInput(false);
2969  GetMythMainWindow()->AllowInput(true);
2970  return;
2971  }
2972 }
2973 
2979 {
2980  VideoMetadata *metadata = GetMetadata(GetItemCurrent());
2981  if (metadata)
2982  PlayVideo(metadata->GetFilename(), m_d->m_videoList->getListCache());
2983 }
2984 
2990 {
2991  VideoMetadata *metadata = GetMetadata(GetItemCurrent());
2992  if (metadata)
2993  PlayVideo(metadata->GetFilename(),
2994  m_d->m_videoList->getListCache(), true);
2995 }
2996 
3002 {
3003  const int WATCHED_WATERMARK = 10000; // Play less then this milisec and the chain of
3004  // videos will not be followed when
3005  // playing.
3006  QTime playing_time;
3007 
3009  MythGenericTree *node = GetNodePtrFromButton(item);
3010  int list_count;
3011 
3012  if (node && !(node->getInt() >= 0))
3013  list_count = node->childCount();
3014  else
3015  return;
3016 
3017  if (list_count > 0)
3018  {
3019  bool video_started = false;
3020  int i = 0;
3021  while (i < list_count &&
3022  (!video_started || playing_time.elapsed() > WATCHED_WATERMARK))
3023  {
3024  MythGenericTree *subnode = node->getChildAt(i);
3025  if (subnode)
3026  {
3027  VideoMetadata *metadata = GetMetadataPtrFromNode(subnode);
3028  if (metadata)
3029  {
3030  playing_time.start();
3031  video_started = true;
3032  PlayVideo(metadata->GetFilename(),
3034  }
3035  }
3036  i++;
3037  }
3038  }
3039 }
3040 
3041 namespace
3042 {
3043  struct SimpleCollect : public DirectoryHandler
3044  {
3045  SimpleCollect(QStringList &fileList) : m_fileList(fileList) {}
3046 
3047  DirectoryHandler *newDir(const QString &dirName,
3048  const QString &fqDirName)
3049  {
3050  (void) dirName;
3051  (void) fqDirName;
3052  return this;
3053  }
3054 
3055  void handleFile(const QString &fileName, const QString &fqFileName,
3056  const QString &extension, const QString &host)
3057  {
3058  (void) fileName;
3059  (void) extension;
3060  (void) host;
3061  m_fileList.push_back(fqFileName);
3062  }
3063 
3064  private:
3065  QStringList &m_fileList;
3066  };
3067 
3068  QStringList GetTrailersInDirectory(const QString &startDir)
3069  {
3072  .getExtensionIgnoreList(extensions);
3073  QStringList ret;
3074  SimpleCollect sc(ret);
3075 
3076  (void) ScanVideoDirectory(startDir, &sc, extensions, false);
3077  return ret;
3078  }
3079 }
3080 
3086 {
3087  VideoMetadata *metadata = GetMetadata(GetItemCurrent());
3088  if (!metadata) return;
3089 
3090  QStringList trailers = GetTrailersInDirectory(gCoreContext->
3091  GetSetting("mythvideo.TrailersDir"));
3092 
3093  if (trailers.isEmpty())
3094  return;
3095 
3096  const int trailersToPlay =
3097  gCoreContext->GetNumSetting("mythvideo.TrailersRandomCount");
3098 
3099  int i = 0;
3100  while (!trailers.isEmpty() && i < trailersToPlay)
3101  {
3102  ++i;
3103  QString trailer = trailers.takeAt(random() % trailers.size());
3104 
3105  LOG(VB_GENERAL, LOG_DEBUG,
3106  QString("Random trailer to play will be: %1").arg(trailer));
3107 
3109  }
3110 
3111  PlayVideo(metadata->GetFilename(), m_d->m_videoList->getListCache());
3112 }
3113 
3119 {
3120  VideoMetadata *metadata = GetMetadata(GetItemCurrent());
3121  if (!metadata) return;
3122  QString url;
3123 
3124  if (metadata->IsHostSet() && !metadata->GetTrailer().startsWith("/"))
3125  url = generate_file_url("Trailers", metadata->GetHost(),
3126  metadata->GetTrailer());
3127  else
3128  url = metadata->GetTrailer();
3129 
3131 }
3132 
3138 {
3139  m_d->m_parentalLevel.SetLevel(level);
3140 }
3141 
3147 {
3149  .GetLevel() + amount).GetLevel());
3150 }
3151 
3157 {
3158  MythScreenStack *mainStack = GetScreenStack();
3159 
3160  VideoFilterDialog *filterdialog = new VideoFilterDialog(mainStack,
3161  "videodialogfilters", m_d->m_videoList.get());
3162 
3163  if (filterdialog->Create())
3164  mainStack->AddScreen(filterdialog);
3165 
3166  connect(filterdialog, SIGNAL(filterChanged()), SLOT(reloadData()));
3167 }
3168 
3174 {
3175  VideoMetadata *metadata = NULL;
3176 
3177  if (item)
3178  {
3179  MythGenericTree *node = GetNodePtrFromButton(item);
3180  if (node)
3181  {
3182  int nodeInt = node->getInt();
3183 
3184  if (nodeInt >= 0)
3185  metadata = GetMetadataPtrFromNode(node);
3186  }
3187  }
3188 
3189  return metadata;
3190 }
3191 
3192 void VideoDialog::customEvent(QEvent *levent)
3193 {
3194  if (levent->type() == MetadataFactoryMultiResult::kEventType)
3195  {
3196  MetadataFactoryMultiResult *mfmr = dynamic_cast<MetadataFactoryMultiResult*>(levent);
3197 
3198  if (!mfmr)
3199  return;
3200 
3201  MetadataLookupList list = mfmr->results;
3202 
3203  if (m_busyPopup)
3204  {
3205  m_busyPopup->Close();
3206  m_busyPopup = NULL;
3207  }
3208 
3209  if (list.count() > 1)
3210  {
3211  MetadataResultsDialog *resultsdialog =
3213 
3214  connect(resultsdialog, SIGNAL(haveResult(MetadataLookup*)),
3216  Qt::QueuedConnection);
3217 
3218  if (resultsdialog->Create())
3219  m_popupStack->AddScreen(resultsdialog);
3220  }
3221  }
3222  else if (levent->type() == MetadataFactorySingleResult::kEventType)
3223  {
3224  MetadataFactorySingleResult *mfsr = dynamic_cast<MetadataFactorySingleResult*>(levent);
3225 
3226  if (!mfsr)
3227  return;
3228 
3229  MetadataLookup *lookup = mfsr->result;
3230 
3231  if (!lookup)
3232  return;
3233 
3234  OnVideoSearchDone(lookup);
3235  }
3236  else if (levent->type() == MetadataFactoryNoResult::kEventType)
3237  {
3238  MetadataFactoryNoResult *mfnr = dynamic_cast<MetadataFactoryNoResult*>(levent);
3239 
3240  if (!mfnr)
3241  return;
3242 
3243  MetadataLookup *lookup = mfnr->result;
3244 
3245  if (!lookup)
3246  return;
3247 
3248  if (m_busyPopup)
3249  {
3250  m_busyPopup->Close();
3251  m_busyPopup = NULL;
3252  }
3253 
3254  VideoMetadata *metadata =
3255  qVariantValue<VideoMetadata *>(lookup->GetData());
3256  if (metadata)
3257  {
3258  metadata->SetProcessed(true);
3259  metadata->UpdateDatabase();
3260  }
3261  LOG(VB_GENERAL, LOG_INFO,
3262  QString("No results found for %1 %2 %3").arg(lookup->GetTitle())
3263  .arg(lookup->GetSeason()).arg(lookup->GetEpisode()));
3264  }
3265  else if (levent->type() == DialogCompletionEvent::kEventType)
3266  {
3267  DialogCompletionEvent *dce = static_cast<DialogCompletionEvent *>(levent);
3268  QString id = dce->GetId();
3269 
3270  if (id == "scanprompt")
3271  {
3272  int result = dce->GetResult();
3273  if (result == 1)
3274  doVideoScan();
3275  }
3276  else
3277  m_menuPopup = NULL;
3278  }
3279 }
3280 
3282 {
3283  // The metadata has some cover file set
3284  if (m_busyPopup)
3285  {
3286  m_busyPopup->Close();
3287  m_busyPopup = NULL;
3288  }
3289 
3290  metadata->SetProcessed(true);
3291  metadata->UpdateDatabase();
3292 
3293  MythUIButtonListItem *item = GetItemByMetadata(metadata);
3294  if (item != NULL)
3295  UpdateItem(item);
3296 }
3297 
3299 {
3300  if (m_videoButtonTree)
3301  {
3303  }
3304 
3306 }
3307 
3309 {
3310  if (m_videoButtonTree)
3311  {
3313  }
3314 
3315  QList<MythGenericTree*>::iterator it;
3316  QList<MythGenericTree*> *children;
3317  QMap<int, int> idPosition;
3318 
3319  children = m_d->m_currentNode->getAllChildren();
3320 
3321  for (it = children->begin(); it != children->end(); ++it)
3322  {
3323  MythGenericTree *child = *it;
3324  int nodeInt = child->getInt();
3325  if (nodeInt != kSubFolder && nodeInt != kUpFolder)
3326  {
3327  VideoMetadata *listmeta =
3328  GetMetadataPtrFromNode(child);
3329  if (listmeta)
3330  {
3331  int position = child->getPosition();
3332  int id = listmeta->GetID();
3333  idPosition.insert(id, position);
3334  }
3335  }
3336  }
3337 
3338  return m_videoButtonList->GetItemAt(idPosition.value(metadata->GetID()));
3339 }
3340 
3342  bool automode)
3343 {
3344  if (!node)
3345  node = GetNodePtrFromButton(GetItemCurrent());
3346 
3347  if (!node)
3348  return;
3349 
3350  VideoMetadata *metadata = GetMetadataPtrFromNode(node);
3351 
3352  if (!metadata)
3353  return;
3354 
3355  m_metadataFactory->Lookup(metadata, automode, true);
3356 
3357  if (!automode)
3358  {
3359  QString msg = tr("Fetching details for %1")
3360  .arg(metadata->GetTitle());
3361  if (!metadata->GetSubtitle().isEmpty())
3362  msg += QString(": %1").arg(metadata->GetSubtitle());
3363  if (metadata->GetSeason() > 0 || metadata->GetEpisode() > 0)
3364  msg += tr(" %1x%2").arg(metadata->GetSeason())
3365  .arg(metadata->GetEpisode());
3366  createBusyDialog(msg);
3367  }
3368 }
3369 
3371 {
3372  if (!node)
3373  node = m_d->m_rootNode;
3374  typedef QList<MythGenericTree *> MGTreeChildList;
3375  MGTreeChildList *lchildren = node->getAllChildren();
3376 
3377  LOG(VB_GENERAL, LOG_DEBUG,
3378  QString("Fetching details in %1").arg(node->GetText()));
3379 
3380  for (MGTreeChildList::const_iterator p = lchildren->begin();
3381  p != lchildren->end(); ++p)
3382  {
3383  if (((*p)->getInt() == kSubFolder) ||
3384  ((*p)->getInt() == kUpFolder))
3385  VideoAutoSearch((*p));
3386  else
3387  {
3388  VideoMetadata *metadata = GetMetadataPtrFromNode((*p));
3389 
3390  if (!metadata)
3391  continue;
3392 
3393  if (!metadata->GetProcessed())
3394  VideoSearch((*p), true);
3395  }
3396  }
3397 }
3398 
3400 {
3402  if (!item)
3403  return;
3404 
3405  VideoMetadata *metadata = GetMetadata(item);
3406  if (metadata)
3407  {
3408  metadata->SetWatched(!metadata->GetWatched());
3409  metadata->UpdateDatabase();
3410  item->DisplayState(WatchedToState(metadata->GetWatched()),
3411  "watchedstate");
3412  }
3413 }
3414 
3416 {
3417  if (!lookup)
3418  return;
3419 
3420  lookup->SetStep(kLookupData);
3421  m_metadataFactory->Lookup(lookup);
3422 }
3423 
3425 {
3426  VideoMetadata *metadata = GetMetadata(GetItemCurrent());
3427  if (metadata)
3428  {
3429  ParentalLevel curshowlevel = metadata->GetShowLevel();
3430 
3431  curshowlevel += amount;
3432 
3433  if (curshowlevel.GetLevel() != metadata->GetShowLevel())
3434  {
3435  metadata->SetShowLevel(curshowlevel.GetLevel());
3436  metadata->UpdateDatabase();
3437  refreshData();
3438  }
3439  }
3440 }
3441 
3443 {
3444  VideoMetadata *metadata = GetMetadata(GetItemCurrent());
3445  if (!metadata)
3446  return;
3447 
3448  MythScreenStack *screenStack = GetScreenStack();
3449 
3450  EditMetadataDialog *md_editor = new EditMetadataDialog(screenStack,
3451  "mythvideoeditmetadata", metadata,
3453 
3454  connect(md_editor, SIGNAL(Finished()), SLOT(refreshData()));
3455 
3456  if (md_editor->Create())
3457  screenStack->AddScreen(md_editor);
3458 }
3459 
3461 {
3462  VideoMetadata *metadata = GetMetadata(GetItemCurrent());
3463 
3464  if (!metadata)
3465  return;
3466 
3467  QString message = tr("Are you sure you want to permanently delete:\n%1")
3468  .arg(metadata->GetTitle());
3469 
3470  MythConfirmationDialog *confirmdialog =
3471  new MythConfirmationDialog(m_popupStack,message);
3472 
3473  if (confirmdialog->Create())
3474  m_popupStack->AddScreen(confirmdialog);
3475 
3476  connect(confirmdialog, SIGNAL(haveResult(bool)),
3477  SLOT(OnRemoveVideo(bool)));
3478 }
3479 
3480 void VideoDialog::OnRemoveVideo(bool dodelete)
3481 {
3482  if (!dodelete)
3483  return;
3484 
3486  MythGenericTree *gtItem = GetNodePtrFromButton(item);
3487 
3488  VideoMetadata *metadata = GetMetadata(item);
3489 
3490  if (!metadata)
3491  return;
3492 
3493  if (m_d->m_videoList->Delete(metadata->GetID()))
3494  {
3495  if (m_videoButtonTree)
3496  m_videoButtonTree->RemoveItem(item, false); // FIXME Segfault when true
3497  else
3499 
3500  MythGenericTree *parent = gtItem->getParent();
3501  parent->deleteNode(gtItem);
3502  }
3503  else
3504  {
3505  QString message = tr("Failed to delete file");
3506 
3507  MythConfirmationDialog *confirmdialog =
3508  new MythConfirmationDialog(m_popupStack,message,false);
3509 
3510  if (confirmdialog->Create())
3511  m_popupStack->AddScreen(confirmdialog);
3512  }
3513 }
3514 
3516 {
3518  VideoMetadata *metadata = GetMetadata(item);
3519 
3520  if (metadata)
3521  {
3522  metadata->Reset();
3523  metadata->UpdateDatabase();
3524  UpdateItem(item);
3525  }
3526 }
3527 
3529 {
3530  if (!metadata)
3531  return;
3532 
3533  QStringList cover_dirs;
3534  cover_dirs += m_d->m_artDir;
3535 
3536  QString cover_file;
3537  QString inetref = metadata->GetInetRef();
3538  QString filename = metadata->GetFilename();
3539  QString title = metadata->GetTitle();
3540  int season = metadata->GetSeason();
3541  QString host = metadata->GetHost();
3542  int episode = metadata->GetEpisode();
3543 
3544  if (metadata->GetCoverFile().isEmpty() ||
3545  IsDefaultCoverFile(metadata->GetCoverFile()))
3546  {
3547  if (GetLocalVideoImage(inetref, filename,
3548  cover_dirs, cover_file, title,
3549  season, host, "Coverart", episode))
3550  {
3551  metadata->SetCoverFile(cover_file);
3552  OnVideoImageSetDone(metadata);
3553  }
3554  }
3555 
3556  QStringList fanart_dirs;
3557  fanart_dirs += m_d->m_fanDir;
3558 
3559  QString fanart_file;
3560 
3561  if (metadata->GetFanart().isEmpty())
3562  {
3563  if (GetLocalVideoImage(inetref, filename,
3564  fanart_dirs, fanart_file, title,
3565  season, host, "Fanart", episode))
3566  {
3567  metadata->SetFanart(fanart_file);
3568  OnVideoImageSetDone(metadata);
3569  }
3570  }
3571 
3572  QStringList banner_dirs;
3573  banner_dirs += m_d->m_banDir;
3574 
3575  QString banner_file;
3576 
3577  if (metadata->GetBanner().isEmpty())
3578  {
3579  if (GetLocalVideoImage(inetref, filename,
3580  banner_dirs, banner_file, title,
3581  season, host, "Banners", episode))
3582  {
3583  metadata->SetBanner(banner_file);
3584  OnVideoImageSetDone(metadata);
3585  }
3586  }
3587 
3588  QStringList screenshot_dirs;
3589  screenshot_dirs += m_d->m_sshotDir;
3590 
3591  QString screenshot_file;
3592 
3593  if (metadata->GetScreenshot().isEmpty())
3594  {
3595  if (GetLocalVideoImage(inetref, filename,
3596  screenshot_dirs, screenshot_file, title,
3597  season, host, "Screenshots", episode,
3598  true))
3599  {
3600  metadata->SetScreenshot(screenshot_file);
3601  OnVideoImageSetDone(metadata);
3602  }
3603  }
3604 }
3605 
3607 {
3608  if (m_busyPopup)
3609  {
3610  m_busyPopup->Close();
3611  m_busyPopup = NULL;
3612  }
3613 
3614  if (!lookup)
3615  return;
3616 
3617  VideoMetadata *metadata = qVariantValue<VideoMetadata *>(lookup->GetData());
3618 
3619  if (!metadata)
3620  return;
3621 
3622  metadata->SetTitle(lookup->GetTitle());
3623  metadata->SetSubtitle(lookup->GetSubtitle());
3624 
3625  if (metadata->GetTagline().isEmpty())
3626  metadata->SetTagline(lookup->GetTagline());
3627  if (metadata->GetYear() == 1895 || metadata->GetYear() == 0)
3628  metadata->SetYear(lookup->GetYear());
3629  if (metadata->GetReleaseDate() == QDate())
3630  metadata->SetReleaseDate(lookup->GetReleaseDate());
3631  if (metadata->GetDirector() == VIDEO_DIRECTOR_UNKNOWN ||
3632  metadata->GetDirector().isEmpty())
3633  {
3634  QList<PersonInfo> director = lookup->GetPeople(kPersonDirector);
3635  if (director.count() > 0)
3636  metadata->SetDirector(director.takeFirst().name);
3637  }
3638  if (metadata->GetStudio().isEmpty())
3639  {
3640  QStringList studios = lookup->GetStudios();
3641  if (studios.count() > 0)
3642  metadata->SetStudio(studios.takeFirst());
3643  }
3644  if (metadata->GetPlot() == VIDEO_PLOT_DEFAULT ||
3645  metadata->GetPlot().isEmpty())
3646  metadata->SetPlot(lookup->GetDescription());
3647  if (metadata->GetUserRating() == 0)
3648  metadata->SetUserRating(lookup->GetUserRating());
3649  if (metadata->GetRating() == VIDEO_RATING_DEFAULT)
3650  metadata->SetRating(lookup->GetCertification());
3651  if (metadata->GetLength() == 0)
3652  metadata->SetLength(lookup->GetRuntime());
3653  if (metadata->GetSeason() == 0)
3654  metadata->SetSeason(lookup->GetSeason());
3655  if (metadata->GetEpisode() == 0)
3656  metadata->SetEpisode(lookup->GetEpisode());
3657  if (metadata->GetHomepage().isEmpty())
3658  metadata->SetHomepage(lookup->GetHomepage());
3659 
3660  metadata->SetInetRef(lookup->GetInetref());
3661 
3662  m_d->AutomaticParentalAdjustment(metadata);
3663 
3664  // Cast
3665  QList<PersonInfo> actors = lookup->GetPeople(kPersonActor);
3666  QList<PersonInfo> gueststars = lookup->GetPeople(kPersonGuestStar);
3667 
3668  for (QList<PersonInfo>::const_iterator p = gueststars.begin();
3669  p != gueststars.end(); ++p)
3670  {
3671  actors.append(*p);
3672  }
3673 
3675  QStringList cl;
3676 
3677  for (QList<PersonInfo>::const_iterator p = actors.begin();
3678  p != actors.end(); ++p)
3679  {
3680  cl.append((*p).name);
3681  }
3682 
3683  for (QStringList::const_iterator p = cl.begin();
3684  p != cl.end(); ++p)
3685  {
3686  QString cn = (*p).trimmed();
3687  if (cn.length())
3688  {
3689  cast.push_back(VideoMetadata::cast_list::
3690  value_type(-1, cn));
3691  }
3692  }
3693 
3694  metadata->SetCast(cast);
3695 
3696  // Genres
3697  VideoMetadata::genre_list video_genres;
3698  QStringList genres = lookup->GetCategories();
3699 
3700  for (QStringList::const_iterator p = genres.begin();
3701  p != genres.end(); ++p)
3702  {
3703  QString genre_name = (*p).trimmed();
3704  if (genre_name.length())
3705  {
3706  video_genres.push_back(
3707  VideoMetadata::genre_list::value_type(-1, genre_name));
3708  }
3709  }
3710 
3711  metadata->SetGenres(video_genres);
3712 
3713  // Countries
3714  VideoMetadata::country_list video_countries;
3715  QStringList countries = lookup->GetCountries();
3716 
3717  for (QStringList::const_iterator p = countries.begin();
3718  p != countries.end(); ++p)
3719  {
3720  QString country_name = (*p).trimmed();
3721  if (country_name.length())
3722  {
3723  video_countries.push_back(
3724  VideoMetadata::country_list::value_type(-1,
3725  country_name));
3726  }
3727  }
3728 
3729  metadata->SetCountries(video_countries);
3730  metadata->SetProcessed(true);
3731 
3732  metadata->UpdateDatabase();
3733 
3734  MythUIButtonListItem *item = GetItemByMetadata(metadata);
3735  if (item != NULL)
3736  UpdateItem(item);
3737 
3738  delete lookup;
3739  lookup = NULL;
3740 
3741  StartVideoImageSet(metadata);
3742 }
3743 
3745 {
3746  if (!m_d->m_scanner)
3747  m_d->m_scanner = new VideoScanner();
3748  connect(m_d->m_scanner, SIGNAL(finished(bool)), SLOT(scanFinished(bool)));
3750 }
3751 
3753 {
3754  QString message = tr("There are no videos in the database, would you like "
3755  "to scan your video directories now?");
3757  message,
3758  true);
3759  dialog->SetReturnEvent(this, "scanprompt");
3760  if (dialog->Create())
3761  m_popupStack->AddScreen(dialog);
3762  else
3763  delete dialog;
3764 }
3765 
3766 #include "videodlg.moc"