|
MythTV
0.26-pre
|
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"
1.7.6.1