Merge pull request #1129 from jmarshallnz/remove_smb_auth_details_in_add_source
[vuplus_xbmc] / xbmc / video / dialogs / GUIDialogVideoInfo.cpp
1 /*
2  *      Copyright (C) 2005-2008 Team XBMC
3  *      http://www.xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, write to
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21
22 #include "GUIDialogVideoInfo.h"
23 #include "guilib/GUIWindow.h"
24 #include "Util.h"
25 #include "guilib/GUIImage.h"
26 #include "utils/StringUtils.h"
27 #include "utils/URIUtils.h"
28 #include "video/windows/GUIWindowVideoNav.h"
29 #include "dialogs/GUIDialogFileBrowser.h"
30 #include "video/VideoInfoScanner.h"
31 #include "Application.h"
32 #include "video/VideoInfoTag.h"
33 #include "guilib/GUIWindowManager.h"
34 #include "dialogs/GUIDialogOK.h"
35 #include "dialogs/GUIDialogYesNo.h"
36 #include "dialogs/GUIDialogSelect.h"
37 #include "dialogs/GUIDialogProgress.h"
38 #include "filesystem/File.h"
39 #include "FileItem.h"
40 #include "storage/MediaManager.h"
41 #include "utils/AsyncFileCopy.h"
42 #include "settings/Settings.h"
43 #include "settings/AdvancedSettings.h"
44 #include "settings/GUISettings.h"
45 #include "guilib/LocalizeStrings.h"
46 #include "GUIUserMessages.h"
47 #include "TextureCache.h"
48 #include "music/MusicDatabase.h"
49
50 using namespace std;
51 using namespace XFILE;
52
53 #define CONTROL_IMAGE                3
54 #define CONTROL_TEXTAREA             4
55 #define CONTROL_BTN_TRACKS           5
56 #define CONTROL_BTN_REFRESH          6
57 #define CONTROL_BTN_PLAY             8
58 #define CONTROL_BTN_RESUME           9
59 #define CONTROL_BTN_GET_THUMB       10
60 #define CONTROL_BTN_PLAY_TRAILER    11
61 #define CONTROL_BTN_GET_FANART      12
62 #define CONTROL_BTN_DIRECTOR        13
63
64 #define CONTROL_LIST                50
65
66 CGUIDialogVideoInfo::CGUIDialogVideoInfo(void)
67     : CGUIDialog(WINDOW_DIALOG_VIDEO_INFO, "DialogVideoInfo.xml")
68     , m_movieItem(new CFileItem)
69 {
70   m_bRefreshAll = true;
71   m_bRefresh = false;
72   m_hasUpdatedThumb = false;
73   m_castList = new CFileItemList;
74 }
75
76 CGUIDialogVideoInfo::~CGUIDialogVideoInfo(void)
77 {
78   delete m_castList;
79 }
80
81 bool CGUIDialogVideoInfo::OnMessage(CGUIMessage& message)
82 {
83   switch ( message.GetMessage() )
84   {
85   case GUI_MSG_WINDOW_DEINIT:
86     {
87       ClearCastList();
88     }
89     break;
90
91   case GUI_MSG_WINDOW_INIT:
92     {
93       m_dlgProgress = (CGUIDialogProgress*)g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS);
94
95       m_bRefresh = false;
96       m_bRefreshAll = true;
97       m_hasUpdatedThumb = false;
98
99       CGUIDialog::OnMessage(message);
100       m_bViewReview = true;
101
102       CVideoDatabase database;
103       ADDON::ScraperPtr scraper;
104
105       if(database.Open())
106       {
107         scraper = database.GetScraperForPath(m_movieItem->GetVideoInfoTag()->GetPath());
108         database.Close();
109       }
110
111       CONTROL_ENABLE_ON_CONDITION(CONTROL_BTN_REFRESH, (g_settings.GetCurrentProfile().canWriteDatabases() || g_passwordManager.bMasterUser) && !m_movieItem->GetVideoInfoTag()->m_strIMDBNumber.Left(2).Equals("xx") && scraper);
112       CONTROL_ENABLE_ON_CONDITION(CONTROL_BTN_GET_THUMB, (g_settings.GetCurrentProfile().canWriteDatabases() || g_passwordManager.bMasterUser) && !m_movieItem->GetVideoInfoTag()->m_strIMDBNumber.Mid(2).Equals("plugin"));
113
114       VIDEODB_CONTENT_TYPE type = (VIDEODB_CONTENT_TYPE)m_movieItem->GetVideoContentType();
115       if (type == VIDEODB_CONTENT_TVSHOWS || type == VIDEODB_CONTENT_MOVIES)
116         CONTROL_ENABLE_ON_CONDITION(CONTROL_BTN_GET_FANART, (g_settings.GetCurrentProfile().canWriteDatabases() || g_passwordManager.bMasterUser) && !m_movieItem->GetVideoInfoTag()->m_strIMDBNumber.Mid(2).Equals("plugin"));
117       else
118         CONTROL_DISABLE(CONTROL_BTN_GET_FANART);
119
120       Update();
121       return true;
122     }
123     break;
124
125
126   case GUI_MSG_CLICKED:
127     {
128       int iControl = message.GetSenderId();
129       if (iControl == CONTROL_BTN_REFRESH)
130       {
131         if (m_movieItem->GetVideoInfoTag()->m_iSeason < 0 && !m_movieItem->GetVideoInfoTag()->m_strShowTitle.IsEmpty()) // tv show
132         {
133           bool bCanceled=false;
134           if (CGUIDialogYesNo::ShowAndGetInput(20377,20378,-1,-1,bCanceled))
135           {
136             m_bRefreshAll = true;
137             CVideoDatabase db;
138             if (db.Open())
139             {
140               db.SetPathHash(m_movieItem->GetVideoInfoTag()->m_strPath,"");
141               db.Close();
142             }
143           }
144           else
145             m_bRefreshAll = false;
146
147           if (bCanceled)
148             return false;
149         }
150         m_bRefresh = true;
151         Close();
152         return true;
153       }
154       else if (iControl == CONTROL_BTN_TRACKS)
155       {
156         m_bViewReview = !m_bViewReview;
157         Update();
158       }
159       else if (iControl == CONTROL_BTN_PLAY)
160       {
161         Play();
162       }
163       else if (iControl == CONTROL_BTN_RESUME)
164       {
165         Play(true);
166       }
167       else if (iControl == CONTROL_BTN_GET_THUMB)
168       {
169         OnGetThumb();
170       }
171       else if (iControl == CONTROL_BTN_PLAY_TRAILER)
172       {
173         PlayTrailer();
174       }
175       else if (iControl == CONTROL_BTN_GET_FANART)
176       {
177         OnGetFanart();
178       }
179       else if (iControl == CONTROL_BTN_DIRECTOR)
180       {
181         CStdString strDirector = StringUtils::Join(m_movieItem->GetVideoInfoTag()->m_director, g_advancedSettings.m_videoItemSeparator);
182         OnSearch(strDirector);
183       }
184       else if (iControl == CONTROL_LIST)
185       {
186         int iAction = message.GetParam1();
187         if (ACTION_SELECT_ITEM == iAction || ACTION_MOUSE_LEFT_CLICK == iAction)
188         {
189           CGUIMessage msg(GUI_MSG_ITEM_SELECTED, GetID(), iControl);
190           OnMessage(msg);
191           int iItem = msg.GetParam1();
192           if (iItem < 0 || iItem >= m_castList->Size())
193             break;
194           CStdString strItem = m_castList->Get(iItem)->GetLabel();
195           CStdString strFind;
196           strFind.Format(" %s ",g_localizeStrings.Get(20347));
197           int iPos = strItem.Find(strFind);
198           if (iPos == -1)
199             iPos = strItem.size();
200           CStdString tmp = strItem.Left(iPos);
201           OnSearch(tmp);
202         }
203       }
204     }
205     break;
206   case GUI_MSG_NOTIFY_ALL:
207     {
208       if (IsActive() && message.GetParam1() == GUI_MSG_UPDATE_ITEM && message.GetItem())
209       {
210         CFileItemPtr item = boost::static_pointer_cast<CFileItem>(message.GetItem());
211         if (item && m_movieItem->GetPath().Equals(item->GetPath()))
212         { // Just copy over the stream details and the thumb if we don't already have one
213           if (!m_movieItem->HasThumbnail())
214             m_movieItem->SetThumbnailImage(item->GetThumbnailImage());
215           m_movieItem->GetVideoInfoTag()->m_streamDetails = item->GetVideoInfoTag()->m_streamDetails;
216         }
217         return true;
218       }
219     }
220   }
221
222   return CGUIDialog::OnMessage(message);
223 }
224
225 void CGUIDialogVideoInfo::SetMovie(const CFileItem *item)
226 {
227   *m_movieItem = *item;
228   // setup cast list + determine type.  We need to do this here as it makes
229   // sure that content type (among other things) is set correctly for the
230   // old fixed id labels that we have floating around (they may be using
231   // content type to determine visibility, so we'll set the wrong label)
232   ClearCastList();
233   VIDEODB_CONTENT_TYPE type = (VIDEODB_CONTENT_TYPE)m_movieItem->GetVideoContentType();
234   if (type == VIDEODB_CONTENT_MUSICVIDEOS)
235   { // music video
236     CMusicDatabase database;
237     database.Open();
238     const std::vector<std::string> &artists = m_movieItem->GetVideoInfoTag()->m_artist;
239     for (std::vector<std::string>::const_iterator it = artists.begin(); it != artists.end(); ++it)
240     {
241       int idArtist = database.GetArtistByName(*it);
242       CStdString thumb = database.GetArtForItem(idArtist, "artist", "thumb");
243       CFileItemPtr item(new CFileItem(*it));
244       if (!thumb.empty())
245         item->SetThumbnailImage(thumb);
246       item->SetIconImage("DefaultArtist.png");
247       m_castList->Add(item);
248     }
249     m_castList->SetContent("musicvideos");
250   }
251   else
252   { // movie/show/episode
253     for (CVideoInfoTag::iCast it = m_movieItem->GetVideoInfoTag()->m_cast.begin(); it != m_movieItem->GetVideoInfoTag()->m_cast.end(); ++it)
254     {
255       CStdString character;
256       if (it->strRole.IsEmpty())
257         character = it->strName;
258       else
259         character.Format("%s %s %s", it->strName.c_str(), g_localizeStrings.Get(20347).c_str(), it->strRole.c_str());
260       CFileItemPtr item(new CFileItem(it->strName));
261       if (!it->thumb.IsEmpty())
262         item->SetThumbnailImage(it->thumb);
263       else if (g_guiSettings.GetBool("videolibrary.actorthumbs"))
264       { // backward compatibility
265         CStdString thumb = CScraperUrl::GetThumbURL(it->thumbUrl.GetFirstThumb());
266         if (!thumb.IsEmpty())
267         {
268           item->SetThumbnailImage(thumb);
269           CTextureCache::Get().BackgroundCacheImage(thumb);
270         }
271       }
272       item->SetIconImage("DefaultActor.png");
273       item->SetLabel(character);
274       m_castList->Add(item);
275     }
276     // determine type:
277     if (type == VIDEODB_CONTENT_TVSHOWS)
278     {
279       m_castList->SetContent("tvshows");
280       // special case stuff for shows (not currently retrieved from the library in filemode (ref: GetTvShowInfo vs GetTVShowsByWhere)
281       m_movieItem->m_dateTime = m_movieItem->GetVideoInfoTag()->m_premiered;
282       if(m_movieItem->GetVideoInfoTag()->m_iYear == 0 && m_movieItem->m_dateTime.IsValid())
283         m_movieItem->GetVideoInfoTag()->m_iYear = m_movieItem->m_dateTime.GetYear();
284       m_movieItem->SetProperty("totalepisodes", m_movieItem->GetVideoInfoTag()->m_iEpisode);
285       m_movieItem->SetProperty("numepisodes", m_movieItem->GetVideoInfoTag()->m_iEpisode); // info view has no concept of current watched/unwatched filter as we could come here from files view, but set for consistency
286       m_movieItem->SetProperty("watchedepisodes", m_movieItem->GetVideoInfoTag()->m_playCount);
287       m_movieItem->SetProperty("unwatchedepisodes", m_movieItem->GetVideoInfoTag()->m_iEpisode - m_movieItem->GetVideoInfoTag()->m_playCount);
288       m_movieItem->GetVideoInfoTag()->m_playCount = (m_movieItem->GetVideoInfoTag()->m_iEpisode == m_movieItem->GetVideoInfoTag()->m_playCount) ? 1 : 0;
289     }
290     else if (type == VIDEODB_CONTENT_EPISODES)
291     {
292       m_castList->SetContent("episodes");
293       // special case stuff for episodes (not currently retrieved from the library in filemode (ref: GetEpisodeInfo vs GetEpisodesByWhere)
294       m_movieItem->m_dateTime = m_movieItem->GetVideoInfoTag()->m_firstAired;
295       if(m_movieItem->GetVideoInfoTag()->m_iYear == 0 && m_movieItem->m_dateTime.IsValid())
296         m_movieItem->GetVideoInfoTag()->m_iYear = m_movieItem->m_dateTime.GetYear();
297       // retrieve the season thumb.
298       // TODO: should we use the thumbloader for this?
299       CVideoDatabase db;
300       if (db.Open())
301       {
302         if (m_movieItem->GetVideoInfoTag()->m_iSeason > -1)
303         {
304           int seasonID = m_movieItem->GetVideoInfoTag()->m_iIdSeason;
305           if (seasonID < 0)
306             seasonID = db.GetSeasonId(m_movieItem->GetVideoInfoTag()->m_iIdShow,
307                                       m_movieItem->GetVideoInfoTag()->m_iSeason);
308           string thumb = db.GetArtForItem(seasonID, "season", "thumb");
309           if (!thumb.empty())
310             m_movieItem->SetProperty("seasonthumb", thumb);
311         }
312         db.Close();
313       }
314     }
315     else if (type == VIDEODB_CONTENT_MOVIES)
316     {
317       m_castList->SetContent("movies");
318
319       // local trailers should always override non-local, so check 
320       // for a local one if the registered trailer is online
321       if (m_movieItem->GetVideoInfoTag()->m_strTrailer.IsEmpty() ||
322           URIUtils::IsInternetStream(m_movieItem->GetVideoInfoTag()->m_strTrailer))
323       {
324         CStdString localTrailer = m_movieItem->FindTrailer();
325         if (!localTrailer.IsEmpty())
326         {
327           m_movieItem->GetVideoInfoTag()->m_strTrailer = localTrailer;
328           CVideoDatabase database;
329           if(database.Open())
330           {
331             database.SetDetail(m_movieItem->GetVideoInfoTag()->m_strTrailer,
332                                m_movieItem->GetVideoInfoTag()->m_iDbId,
333                                VIDEODB_ID_TRAILER, VIDEODB_CONTENT_MOVIES);
334             database.Close();
335             CUtil::DeleteVideoDatabaseDirectoryCache();
336           }
337         }
338       }
339     }
340   }
341   m_loader.LoadItem(m_movieItem.get());
342 }
343
344 void CGUIDialogVideoInfo::Update()
345 {
346   // setup plot text area
347   CStdString strTmp = m_movieItem->GetVideoInfoTag()->m_strPlot;
348   if (!(!m_movieItem->GetVideoInfoTag()->m_strShowTitle.IsEmpty() && m_movieItem->GetVideoInfoTag()->m_iSeason == 0)) // dont apply to tvshows
349     if (m_movieItem->GetVideoInfoTag()->m_playCount == 0 && !g_guiSettings.GetBool("videolibrary.showunwatchedplots"))
350       strTmp = g_localizeStrings.Get(20370);
351
352   strTmp.Trim();
353   SetLabel(CONTROL_TEXTAREA, strTmp);
354
355   CGUIMessage msg(GUI_MSG_LABEL_BIND, GetID(), CONTROL_LIST, 0, 0, m_castList);
356   OnMessage(msg);
357
358   if (GetControl(CONTROL_BTN_TRACKS)) // if no CONTROL_BTN_TRACKS found - allow skinner full visibility control over CONTROL_TEXTAREA and CONTROL_LIST
359   {
360     if (m_bViewReview)
361     {
362       if (!m_movieItem->GetVideoInfoTag()->m_artist.empty())
363       {
364         SET_CONTROL_LABEL(CONTROL_BTN_TRACKS, 133);
365       }
366       else
367       {
368         SET_CONTROL_LABEL(CONTROL_BTN_TRACKS, 206);
369       }
370
371       SET_CONTROL_HIDDEN(CONTROL_LIST);
372       SET_CONTROL_VISIBLE(CONTROL_TEXTAREA);
373     }
374     else
375     {
376       SET_CONTROL_LABEL(CONTROL_BTN_TRACKS, 207);
377
378       SET_CONTROL_HIDDEN(CONTROL_TEXTAREA);
379       SET_CONTROL_VISIBLE(CONTROL_LIST);
380     }
381   }
382
383   // Check for resumability
384   if (m_movieItem->GetVideoInfoTag()->m_resumePoint.timeInSeconds > 0.0)
385     CONTROL_ENABLE(CONTROL_BTN_RESUME);
386   else
387     CONTROL_DISABLE(CONTROL_BTN_RESUME);
388
389   CONTROL_ENABLE(CONTROL_BTN_PLAY);
390
391   // update the thumbnail
392   const CGUIControl* pControl = GetControl(CONTROL_IMAGE);
393   if (pControl)
394   {
395     CGUIImage* pImageControl = (CGUIImage*)pControl;
396     pImageControl->FreeResources();
397     pImageControl->SetFileName(m_movieItem->GetThumbnailImage());
398   }
399   // tell our GUI to completely reload all controls (as some of them
400   // are likely to have had this image in use so will need refreshing)
401   if (m_hasUpdatedThumb)
402   {
403     CGUIMessage reload(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_REFRESH_THUMBS);
404     g_windowManager.SendMessage(reload);
405   }
406 }
407
408 bool CGUIDialogVideoInfo::NeedRefresh() const
409 {
410   return m_bRefresh;
411 }
412
413 bool CGUIDialogVideoInfo::RefreshAll() const
414 {
415   return m_bRefreshAll;
416 }
417
418 /// \brief Search the current directory for a string got from the virtual keyboard
419 void CGUIDialogVideoInfo::OnSearch(CStdString& strSearch)
420 {
421   if (m_dlgProgress)
422   {
423     m_dlgProgress->SetHeading(194);
424     m_dlgProgress->SetLine(0, strSearch);
425     m_dlgProgress->SetLine(1, "");
426     m_dlgProgress->SetLine(2, "");
427     m_dlgProgress->StartModal();
428     m_dlgProgress->Progress();
429   }
430   CFileItemList items;
431   DoSearch(strSearch, items);
432
433   if (m_dlgProgress)
434     m_dlgProgress->Close();
435
436   if (items.Size())
437   {
438     CGUIDialogSelect* pDlgSelect = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
439     pDlgSelect->Reset();
440     pDlgSelect->SetHeading(283);
441
442     for (int i = 0; i < (int)items.Size(); i++)
443     {
444       CFileItemPtr pItem = items[i];
445       pDlgSelect->Add(pItem->GetLabel());
446     }
447
448     pDlgSelect->DoModal();
449
450     int iItem = pDlgSelect->GetSelectedLabel();
451     if (iItem < 0)
452       return;
453
454     CFileItem* pSelItem = new CFileItem(*items[iItem]);
455
456     OnSearchItemFound(pSelItem);
457
458     delete pSelItem;
459   }
460   else
461   {
462     CGUIDialogOK::ShowAndGetInput(194, 284, 0, 0);
463   }
464 }
465
466 /// \brief Make the actual search for the OnSearch function.
467 /// \param strSearch The search string
468 /// \param items Items Found
469 void CGUIDialogVideoInfo::DoSearch(CStdString& strSearch, CFileItemList& items)
470 {
471   CVideoDatabase db;
472   if (!db.Open())
473     return;
474
475   CFileItemList movies;
476   db.GetMoviesByActor(strSearch, movies);
477   for (int i = 0; i < movies.Size(); ++i)
478   {
479     CStdString label = movies[i]->GetVideoInfoTag()->m_strTitle;
480     if (movies[i]->GetVideoInfoTag()->m_iYear > 0)
481       label.AppendFormat(" (%i)", movies[i]->GetVideoInfoTag()->m_iYear);
482     movies[i]->SetLabel(label);
483   }
484   CGUIWindowVideoBase::AppendAndClearSearchItems(movies, "[" + g_localizeStrings.Get(20338) + "] ", items);
485
486   db.GetTvShowsByActor(strSearch, movies);
487   for (int i = 0; i < movies.Size(); ++i)
488   {
489     CStdString label = movies[i]->GetVideoInfoTag()->m_strShowTitle;
490     if (movies[i]->GetVideoInfoTag()->m_iYear > 0)
491       label.AppendFormat(" (%i)", movies[i]->GetVideoInfoTag()->m_iYear);
492     movies[i]->SetLabel(label);
493   }
494   CGUIWindowVideoBase::AppendAndClearSearchItems(movies, "[" + g_localizeStrings.Get(20364) + "] ", items);
495
496   db.GetEpisodesByActor(strSearch, movies);
497   for (int i = 0; i < movies.Size(); ++i)
498   {
499     CStdString label = movies[i]->GetVideoInfoTag()->m_strTitle + " (" +  movies[i]->GetVideoInfoTag()->m_strShowTitle + ")";
500     movies[i]->SetLabel(label);
501   }
502   CGUIWindowVideoBase::AppendAndClearSearchItems(movies, "[" + g_localizeStrings.Get(20359) + "] ", items);
503
504   db.GetMusicVideosByArtist(strSearch, movies);
505   for (int i = 0; i < movies.Size(); ++i)
506   {
507     CStdString label = StringUtils::Join(movies[i]->GetVideoInfoTag()->m_artist, g_advancedSettings.m_videoItemSeparator) + " - " + movies[i]->GetVideoInfoTag()->m_strTitle;
508     if (movies[i]->GetVideoInfoTag()->m_iYear > 0)
509       label.AppendFormat(" (%i)", movies[i]->GetVideoInfoTag()->m_iYear);
510     movies[i]->SetLabel(label);
511   }
512   CGUIWindowVideoBase::AppendAndClearSearchItems(movies, "[" + g_localizeStrings.Get(20391) + "] ", items);
513   db.Close();
514 }
515
516 /// \brief React on the selected search item
517 /// \param pItem Search result item
518 void CGUIDialogVideoInfo::OnSearchItemFound(const CFileItem* pItem)
519 {
520   VIDEODB_CONTENT_TYPE type = (VIDEODB_CONTENT_TYPE)pItem->GetVideoContentType();
521
522   CVideoDatabase db;
523   if (!db.Open())
524     return;
525
526   CVideoInfoTag movieDetails;
527   if (type == VIDEODB_CONTENT_MOVIES)
528     db.GetMovieInfo(pItem->GetPath(), movieDetails, pItem->GetVideoInfoTag()->m_iDbId);
529   if (type == VIDEODB_CONTENT_EPISODES)
530     db.GetEpisodeInfo(pItem->GetPath(), movieDetails, pItem->GetVideoInfoTag()->m_iDbId);
531   if (type == VIDEODB_CONTENT_TVSHOWS)
532     db.GetTvShowInfo(pItem->GetPath(), movieDetails, pItem->GetVideoInfoTag()->m_iDbId);
533   if (type == VIDEODB_CONTENT_MUSICVIDEOS)
534     db.GetMusicVideoInfo(pItem->GetPath(), movieDetails, pItem->GetVideoInfoTag()->m_iDbId);
535   db.Close();
536
537   CFileItem item(*pItem);
538   *item.GetVideoInfoTag() = movieDetails;
539   SetMovie(&item);
540   // refresh our window entirely
541   Close();
542   DoModal();
543 }
544
545 void CGUIDialogVideoInfo::ClearCastList()
546 {
547   CGUIMessage msg(GUI_MSG_LABEL_RESET, GetID(), CONTROL_LIST);
548   OnMessage(msg);
549   m_castList->Clear();
550 }
551
552 void CGUIDialogVideoInfo::Play(bool resume)
553 {
554   if (!m_movieItem->GetVideoInfoTag()->m_strEpisodeGuide.IsEmpty())
555   {
556     CStdString strPath;
557     strPath.Format("videodb://2/2/%i/",m_movieItem->GetVideoInfoTag()->m_iDbId);
558     Close();
559     g_windowManager.ActivateWindow(WINDOW_VIDEO_NAV,strPath);
560     return;
561   }
562
563   CFileItem movie(*m_movieItem->GetVideoInfoTag());
564   if (m_movieItem->GetVideoInfoTag()->m_strFileNameAndPath.IsEmpty())
565     movie.SetPath(m_movieItem->GetPath());
566   CGUIWindowVideoNav* pWindow = (CGUIWindowVideoNav*)g_windowManager.GetWindow(WINDOW_VIDEO_NAV);
567   if (pWindow)
568   {
569     // close our dialog
570     Close(true);
571     if (resume)
572       movie.m_lStartOffset = STARTOFFSET_RESUME;
573     else if (!CGUIWindowVideoBase::ShowResumeMenu(movie)) 
574     {
575       // The Resume dialog was closed without any choice
576       DoModal();
577       return;
578     }
579     pWindow->PlayMovie(&movie);
580   }
581 }
582
583 // Get Thumb from user choice.
584 // Options are:
585 // 1.  Current thumb
586 // 2.  IMDb thumb
587 // 3.  Local thumb
588 // 4.  No thumb (if no Local thumb is available)
589 void CGUIDialogVideoInfo::OnGetThumb()
590 {
591   CFileItemList items;
592
593   // Current thumb
594   if (CFile::Exists(m_movieItem->GetThumbnailImage()))
595   {
596     CFileItemPtr item(new CFileItem("thumb://Current", false));
597     item->SetThumbnailImage(m_movieItem->GetThumbnailImage());
598     item->SetLabel(g_localizeStrings.Get(20016));
599     items.Add(item);
600   }
601
602   // Grab the thumbnails from the web
603   vector<CStdString> thumbs;
604   m_movieItem->GetVideoInfoTag()->m_strPictureURL.GetThumbURLs(thumbs);
605
606   for (unsigned int i = 0; i < thumbs.size(); ++i)
607   {
608     CStdString strItemPath;
609     strItemPath.Format("thumb://Remote%i", i);
610     CFileItemPtr item(new CFileItem(strItemPath, false));
611     item->SetThumbnailImage(thumbs[i]);
612     item->SetIconImage("DefaultPicture.png");
613     item->SetLabel(g_localizeStrings.Get(20015));
614
615     // TODO: Do we need to clear the cached image?
616     //    CTextureCache::Get().ClearCachedImage(thumb);
617     items.Add(item);
618   }
619
620   CStdString localThumb(m_movieItem->GetUserVideoThumb());
621   if (CFile::Exists(localThumb))
622   {
623     CFileItemPtr item(new CFileItem("thumb://Local", false));
624     item->SetThumbnailImage(localThumb);
625     item->SetLabel(g_localizeStrings.Get(20017));
626     items.Add(item);
627   }
628   else
629   { // no local thumb exists, so we are just using the IMDb thumb or cached thumb
630     // which is probably the IMDb thumb.  These could be wrong, so allow the user
631     // to delete the incorrect thumb
632     CFileItemPtr item(new CFileItem("thumb://None", false));
633     item->SetIconImage("DefaultVideo.png");
634     item->SetLabel(g_localizeStrings.Get(20018));
635     items.Add(item);
636   }
637
638   CStdString result;
639   VECSOURCES sources(g_settings.m_videoSources);
640   g_mediaManager.GetLocalDrives(sources);
641   if (!CGUIDialogFileBrowser::ShowAndGetImage(items, sources, g_localizeStrings.Get(20019), result))
642     return;   // user cancelled
643
644   if (result == "thumb://Current")
645     return;   // user chose the one they have
646
647   CStdString newThumb;
648   if (result.Left(14) == "thumb://Remote")
649   {
650     int number = atoi(result.Mid(14));
651     newThumb = thumbs[number];
652   }
653   else if (result == "thumb://Local")
654     newThumb = localThumb;
655   else if (CFile::Exists(result))
656     newThumb = result;
657   else // none
658     newThumb = "-"; // force local thumbs to be ignored
659
660   // update thumb in the database
661   CVideoDatabase db;
662   if (db.Open())
663   {
664     db.SetArtForItem(m_movieItem->GetVideoInfoTag()->m_iDbId, m_movieItem->GetVideoInfoTag()->m_type, "thumb", newThumb);
665     db.Close();
666   }
667
668   CUtil::DeleteVideoDatabaseDirectoryCache(); // to get them new thumbs to show
669   m_movieItem->SetThumbnailImage(newThumb);
670   if (m_movieItem->HasProperty("set_folder_thumb"))
671   { // have a folder thumb to set as well
672     VIDEO::CVideoInfoScanner::ApplyThumbToFolder(m_movieItem->GetProperty("set_folder_thumb").asString(), newThumb);
673   }
674   m_hasUpdatedThumb = true;
675
676   // Update our screen
677   Update();
678 }
679
680 // Allow user to select a Fanart
681 void CGUIDialogVideoInfo::OnGetFanart()
682 {
683   CFileItemList items;
684
685   CFileItem item(*m_movieItem->GetVideoInfoTag());
686   if (item.HasProperty("fanart_image"))
687   {
688     CFileItemPtr itemCurrent(new CFileItem("fanart://Current",false));
689     itemCurrent->SetThumbnailImage(item.GetProperty("fanart_image").asString());
690     itemCurrent->SetLabel(g_localizeStrings.Get(20440));
691     items.Add(itemCurrent);
692   }
693
694   // ensure the fanart is unpacked
695   m_movieItem->GetVideoInfoTag()->m_fanart.Unpack();
696
697   // Grab the thumbnails from the web
698   for (unsigned int i = 0; i < m_movieItem->GetVideoInfoTag()->m_fanart.GetNumFanarts(); i++)
699   {
700     CStdString strItemPath;
701     strItemPath.Format("fanart://Remote%i",i);
702     CFileItemPtr item(new CFileItem(strItemPath, false));
703     CStdString thumb = m_movieItem->GetVideoInfoTag()->m_fanart.GetPreviewURL(i);
704     item->SetThumbnailImage(CTextureCache::GetWrappedThumbURL(thumb));
705     item->SetIconImage("DefaultPicture.png");
706     item->SetLabel(g_localizeStrings.Get(20441));
707
708     // TODO: Do we need to clear the cached image?
709 //    CTextureCache::Get().ClearCachedImage(thumb);
710     items.Add(item);
711   }
712
713   CStdString strLocal = item.GetLocalFanart();
714   if (!strLocal.IsEmpty())
715   {
716     CFileItemPtr itemLocal(new CFileItem("fanart://Local",false));
717     itemLocal->SetThumbnailImage(strLocal);
718     itemLocal->SetLabel(g_localizeStrings.Get(20438));
719
720     // TODO: Do we need to clear the cached image?
721     CTextureCache::Get().ClearCachedImage(strLocal);
722     items.Add(itemLocal);
723   }
724   else
725   {
726     CFileItemPtr itemNone(new CFileItem("fanart://None", false));
727     itemNone->SetIconImage("DefaultVideo.png");
728     itemNone->SetLabel(g_localizeStrings.Get(20439));
729     items.Add(itemNone);
730   }
731
732   CStdString result;
733   VECSOURCES sources(g_settings.m_videoSources);
734   g_mediaManager.GetLocalDrives(sources);
735   bool flip=false;
736   if (!CGUIDialogFileBrowser::ShowAndGetImage(items, sources, g_localizeStrings.Get(20437), result, &flip, 20445) || result.Equals("fanart://Current"))
737     return;   // user cancelled
738
739   if (result.Equals("fanart://Local"))
740     result = strLocal;
741
742   if (result.Left(15) == "fanart://Remote")
743   {
744     int iFanart = atoi(result.Mid(15).c_str());
745     // set new primary fanart, and update our database accordingly
746     m_movieItem->GetVideoInfoTag()->m_fanart.SetPrimaryFanart(iFanart);
747     CVideoDatabase db;
748     if (db.Open())
749     {
750       db.UpdateFanart(*m_movieItem, (VIDEODB_CONTENT_TYPE)m_movieItem->GetVideoContentType());
751       db.Close();
752     }
753     result = m_movieItem->GetVideoInfoTag()->m_fanart.GetImageURL();
754   }
755   else if (result.Equals("fanart://None") || !CFile::Exists(result))
756     result.clear();
757
758   // set the fanart image
759   if (flip && !result.IsEmpty())
760     result = CTextureCache::GetWrappedImageURL(result, "", "flipped");
761   CVideoDatabase db;
762   if (db.Open())
763   {
764     db.SetArtForItem(m_movieItem->GetVideoInfoTag()->m_iDbId, m_movieItem->GetVideoInfoTag()->m_type, "fanart", result);
765     db.Close();
766   }
767
768   CUtil::DeleteVideoDatabaseDirectoryCache(); // to get them new thumbs to show
769   if (!result.IsEmpty())
770     m_movieItem->SetProperty("fanart_image", result);
771   else
772     m_movieItem->ClearProperty("fanart_image");
773   m_hasUpdatedThumb = true;
774
775   // Update our screen
776   Update();
777 }
778
779 void CGUIDialogVideoInfo::PlayTrailer()
780 {
781   CFileItem item;
782   item.SetPath(m_movieItem->GetVideoInfoTag()->m_strTrailer);
783   *item.GetVideoInfoTag() = *m_movieItem->GetVideoInfoTag();
784   item.GetVideoInfoTag()->m_streamDetails.Reset();
785   item.GetVideoInfoTag()->m_strTitle.Format("%s (%s)",m_movieItem->GetVideoInfoTag()->m_strTitle.c_str(),g_localizeStrings.Get(20410));
786   item.SetThumbnailImage(m_movieItem->GetThumbnailImage());
787   item.GetVideoInfoTag()->m_iDbId = -1;
788   item.GetVideoInfoTag()->m_iFileId = -1;
789
790   // Close the dialog.
791   Close(true);
792
793   if (item.IsPlayList())
794     g_application.getApplicationMessenger().MediaPlay(item);
795   else
796     g_application.getApplicationMessenger().PlayFile(item);
797 }
798
799 void CGUIDialogVideoInfo::SetLabel(int iControl, const CStdString &strLabel)
800 {
801   if (strLabel.IsEmpty())
802   {
803     SET_CONTROL_LABEL(iControl, 416);  // "Not available"
804   }
805   else
806   {
807     SET_CONTROL_LABEL(iControl, strLabel);
808   }
809 }
810
811 const CStdString& CGUIDialogVideoInfo::GetThumbnail() const
812 {
813   return m_movieItem->GetThumbnailImage();
814 }