strip added smb:// shares of their user/pass when adding, and instead store that...
[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         if (m_movieItem->GetVideoInfoTag()->m_iIdShow > -1)
313         {
314           string thumb = db.GetArtForItem(m_movieItem->GetVideoInfoTag()->m_iIdShow, "tvshow", "thumb");
315           if (!thumb.empty())
316             m_movieItem->SetProperty("tvshowthumb", thumb);
317         }
318         db.Close();
319       }
320     }
321     else if (type == VIDEODB_CONTENT_MOVIES)
322     {
323       m_castList->SetContent("movies");
324
325       // local trailers should always override non-local, so check 
326       // for a local one if the registered trailer is online
327       if (m_movieItem->GetVideoInfoTag()->m_strTrailer.IsEmpty() ||
328           URIUtils::IsInternetStream(m_movieItem->GetVideoInfoTag()->m_strTrailer))
329       {
330         CStdString localTrailer = m_movieItem->FindTrailer();
331         if (!localTrailer.IsEmpty())
332         {
333           m_movieItem->GetVideoInfoTag()->m_strTrailer = localTrailer;
334           CVideoDatabase database;
335           if(database.Open())
336           {
337             database.SetDetail(m_movieItem->GetVideoInfoTag()->m_strTrailer,
338                                m_movieItem->GetVideoInfoTag()->m_iDbId,
339                                VIDEODB_ID_TRAILER, VIDEODB_CONTENT_MOVIES);
340             database.Close();
341             CUtil::DeleteVideoDatabaseDirectoryCache();
342           }
343         }
344       }
345     }
346   }
347   m_loader.LoadItem(m_movieItem.get());
348 }
349
350 void CGUIDialogVideoInfo::Update()
351 {
352   // setup plot text area
353   CStdString strTmp = m_movieItem->GetVideoInfoTag()->m_strPlot;
354   if (!(!m_movieItem->GetVideoInfoTag()->m_strShowTitle.IsEmpty() && m_movieItem->GetVideoInfoTag()->m_iSeason == 0)) // dont apply to tvshows
355     if (m_movieItem->GetVideoInfoTag()->m_playCount == 0 && !g_guiSettings.GetBool("videolibrary.showunwatchedplots"))
356       strTmp = g_localizeStrings.Get(20370);
357
358   strTmp.Trim();
359   SetLabel(CONTROL_TEXTAREA, strTmp);
360
361   CGUIMessage msg(GUI_MSG_LABEL_BIND, GetID(), CONTROL_LIST, 0, 0, m_castList);
362   OnMessage(msg);
363
364   if (GetControl(CONTROL_BTN_TRACKS)) // if no CONTROL_BTN_TRACKS found - allow skinner full visibility control over CONTROL_TEXTAREA and CONTROL_LIST
365   {
366     if (m_bViewReview)
367     {
368       if (!m_movieItem->GetVideoInfoTag()->m_artist.empty())
369       {
370         SET_CONTROL_LABEL(CONTROL_BTN_TRACKS, 133);
371       }
372       else
373       {
374         SET_CONTROL_LABEL(CONTROL_BTN_TRACKS, 206);
375       }
376
377       SET_CONTROL_HIDDEN(CONTROL_LIST);
378       SET_CONTROL_VISIBLE(CONTROL_TEXTAREA);
379     }
380     else
381     {
382       SET_CONTROL_LABEL(CONTROL_BTN_TRACKS, 207);
383
384       SET_CONTROL_HIDDEN(CONTROL_TEXTAREA);
385       SET_CONTROL_VISIBLE(CONTROL_LIST);
386     }
387   }
388
389   // Check for resumability
390   if (m_movieItem->GetVideoInfoTag()->m_resumePoint.timeInSeconds > 0.0)
391     CONTROL_ENABLE(CONTROL_BTN_RESUME);
392   else
393     CONTROL_DISABLE(CONTROL_BTN_RESUME);
394
395   CONTROL_ENABLE(CONTROL_BTN_PLAY);
396
397   // update the thumbnail
398   const CGUIControl* pControl = GetControl(CONTROL_IMAGE);
399   if (pControl)
400   {
401     CGUIImage* pImageControl = (CGUIImage*)pControl;
402     pImageControl->FreeResources();
403     pImageControl->SetFileName(m_movieItem->GetThumbnailImage());
404   }
405   // tell our GUI to completely reload all controls (as some of them
406   // are likely to have had this image in use so will need refreshing)
407   if (m_hasUpdatedThumb)
408   {
409     CGUIMessage reload(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_REFRESH_THUMBS);
410     g_windowManager.SendMessage(reload);
411   }
412 }
413
414 bool CGUIDialogVideoInfo::NeedRefresh() const
415 {
416   return m_bRefresh;
417 }
418
419 bool CGUIDialogVideoInfo::RefreshAll() const
420 {
421   return m_bRefreshAll;
422 }
423
424 /// \brief Search the current directory for a string got from the virtual keyboard
425 void CGUIDialogVideoInfo::OnSearch(CStdString& strSearch)
426 {
427   if (m_dlgProgress)
428   {
429     m_dlgProgress->SetHeading(194);
430     m_dlgProgress->SetLine(0, strSearch);
431     m_dlgProgress->SetLine(1, "");
432     m_dlgProgress->SetLine(2, "");
433     m_dlgProgress->StartModal();
434     m_dlgProgress->Progress();
435   }
436   CFileItemList items;
437   DoSearch(strSearch, items);
438
439   if (m_dlgProgress)
440     m_dlgProgress->Close();
441
442   if (items.Size())
443   {
444     CGUIDialogSelect* pDlgSelect = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
445     pDlgSelect->Reset();
446     pDlgSelect->SetHeading(283);
447
448     for (int i = 0; i < (int)items.Size(); i++)
449     {
450       CFileItemPtr pItem = items[i];
451       pDlgSelect->Add(pItem->GetLabel());
452     }
453
454     pDlgSelect->DoModal();
455
456     int iItem = pDlgSelect->GetSelectedLabel();
457     if (iItem < 0)
458       return;
459
460     CFileItem* pSelItem = new CFileItem(*items[iItem]);
461
462     OnSearchItemFound(pSelItem);
463
464     delete pSelItem;
465   }
466   else
467   {
468     CGUIDialogOK::ShowAndGetInput(194, 284, 0, 0);
469   }
470 }
471
472 /// \brief Make the actual search for the OnSearch function.
473 /// \param strSearch The search string
474 /// \param items Items Found
475 void CGUIDialogVideoInfo::DoSearch(CStdString& strSearch, CFileItemList& items)
476 {
477   CVideoDatabase db;
478   if (!db.Open())
479     return;
480
481   CFileItemList movies;
482   db.GetMoviesByActor(strSearch, movies);
483   for (int i = 0; i < movies.Size(); ++i)
484   {
485     CStdString label = movies[i]->GetVideoInfoTag()->m_strTitle;
486     if (movies[i]->GetVideoInfoTag()->m_iYear > 0)
487       label.AppendFormat(" (%i)", movies[i]->GetVideoInfoTag()->m_iYear);
488     movies[i]->SetLabel(label);
489   }
490   CGUIWindowVideoBase::AppendAndClearSearchItems(movies, "[" + g_localizeStrings.Get(20338) + "] ", items);
491
492   db.GetTvShowsByActor(strSearch, movies);
493   for (int i = 0; i < movies.Size(); ++i)
494   {
495     CStdString label = movies[i]->GetVideoInfoTag()->m_strShowTitle;
496     if (movies[i]->GetVideoInfoTag()->m_iYear > 0)
497       label.AppendFormat(" (%i)", movies[i]->GetVideoInfoTag()->m_iYear);
498     movies[i]->SetLabel(label);
499   }
500   CGUIWindowVideoBase::AppendAndClearSearchItems(movies, "[" + g_localizeStrings.Get(20364) + "] ", items);
501
502   db.GetEpisodesByActor(strSearch, movies);
503   for (int i = 0; i < movies.Size(); ++i)
504   {
505     CStdString label = movies[i]->GetVideoInfoTag()->m_strTitle + " (" +  movies[i]->GetVideoInfoTag()->m_strShowTitle + ")";
506     movies[i]->SetLabel(label);
507   }
508   CGUIWindowVideoBase::AppendAndClearSearchItems(movies, "[" + g_localizeStrings.Get(20359) + "] ", items);
509
510   db.GetMusicVideosByArtist(strSearch, movies);
511   for (int i = 0; i < movies.Size(); ++i)
512   {
513     CStdString label = StringUtils::Join(movies[i]->GetVideoInfoTag()->m_artist, g_advancedSettings.m_videoItemSeparator) + " - " + movies[i]->GetVideoInfoTag()->m_strTitle;
514     if (movies[i]->GetVideoInfoTag()->m_iYear > 0)
515       label.AppendFormat(" (%i)", movies[i]->GetVideoInfoTag()->m_iYear);
516     movies[i]->SetLabel(label);
517   }
518   CGUIWindowVideoBase::AppendAndClearSearchItems(movies, "[" + g_localizeStrings.Get(20391) + "] ", items);
519   db.Close();
520 }
521
522 /// \brief React on the selected search item
523 /// \param pItem Search result item
524 void CGUIDialogVideoInfo::OnSearchItemFound(const CFileItem* pItem)
525 {
526   VIDEODB_CONTENT_TYPE type = (VIDEODB_CONTENT_TYPE)pItem->GetVideoContentType();
527
528   CVideoDatabase db;
529   if (!db.Open())
530     return;
531
532   CVideoInfoTag movieDetails;
533   if (type == VIDEODB_CONTENT_MOVIES)
534     db.GetMovieInfo(pItem->GetPath(), movieDetails, pItem->GetVideoInfoTag()->m_iDbId);
535   if (type == VIDEODB_CONTENT_EPISODES)
536     db.GetEpisodeInfo(pItem->GetPath(), movieDetails, pItem->GetVideoInfoTag()->m_iDbId);
537   if (type == VIDEODB_CONTENT_TVSHOWS)
538     db.GetTvShowInfo(pItem->GetPath(), movieDetails, pItem->GetVideoInfoTag()->m_iDbId);
539   if (type == VIDEODB_CONTENT_MUSICVIDEOS)
540     db.GetMusicVideoInfo(pItem->GetPath(), movieDetails, pItem->GetVideoInfoTag()->m_iDbId);
541   db.Close();
542
543   CFileItem item(*pItem);
544   *item.GetVideoInfoTag() = movieDetails;
545   SetMovie(&item);
546   // refresh our window entirely
547   Close();
548   DoModal();
549 }
550
551 void CGUIDialogVideoInfo::ClearCastList()
552 {
553   CGUIMessage msg(GUI_MSG_LABEL_RESET, GetID(), CONTROL_LIST);
554   OnMessage(msg);
555   m_castList->Clear();
556 }
557
558 void CGUIDialogVideoInfo::Play(bool resume)
559 {
560   if (!m_movieItem->GetVideoInfoTag()->m_strEpisodeGuide.IsEmpty())
561   {
562     CStdString strPath;
563     strPath.Format("videodb://2/2/%i/",m_movieItem->GetVideoInfoTag()->m_iDbId);
564     Close();
565     g_windowManager.ActivateWindow(WINDOW_VIDEO_NAV,strPath);
566     return;
567   }
568
569   CFileItem movie(*m_movieItem->GetVideoInfoTag());
570   if (m_movieItem->GetVideoInfoTag()->m_strFileNameAndPath.IsEmpty())
571     movie.SetPath(m_movieItem->GetPath());
572   CGUIWindowVideoNav* pWindow = (CGUIWindowVideoNav*)g_windowManager.GetWindow(WINDOW_VIDEO_NAV);
573   if (pWindow)
574   {
575     // close our dialog
576     Close(true);
577     if (resume)
578       movie.m_lStartOffset = STARTOFFSET_RESUME;
579     else if (!CGUIWindowVideoBase::ShowResumeMenu(movie)) 
580     {
581       // The Resume dialog was closed without any choice
582       DoModal();
583       return;
584     }
585     pWindow->PlayMovie(&movie);
586   }
587 }
588
589 // Get Thumb from user choice.
590 // Options are:
591 // 1.  Current thumb
592 // 2.  IMDb thumb
593 // 3.  Local thumb
594 // 4.  No thumb (if no Local thumb is available)
595 void CGUIDialogVideoInfo::OnGetThumb()
596 {
597   CFileItemList items;
598
599   // Current thumb
600   if (CFile::Exists(m_movieItem->GetThumbnailImage()))
601   {
602     CFileItemPtr item(new CFileItem("thumb://Current", false));
603     item->SetThumbnailImage(m_movieItem->GetThumbnailImage());
604     item->SetLabel(g_localizeStrings.Get(20016));
605     items.Add(item);
606   }
607
608   // Grab the thumbnails from the web
609   vector<CStdString> thumbs;
610   m_movieItem->GetVideoInfoTag()->m_strPictureURL.GetThumbURLs(thumbs);
611
612   for (unsigned int i = 0; i < thumbs.size(); ++i)
613   {
614     CStdString strItemPath;
615     strItemPath.Format("thumb://Remote%i", i);
616     CFileItemPtr item(new CFileItem(strItemPath, false));
617     item->SetThumbnailImage(thumbs[i]);
618     item->SetIconImage("DefaultPicture.png");
619     item->SetLabel(g_localizeStrings.Get(20015));
620
621     // TODO: Do we need to clear the cached image?
622     //    CTextureCache::Get().ClearCachedImage(thumb);
623     items.Add(item);
624   }
625
626   CStdString localThumb(m_movieItem->GetUserVideoThumb());
627   if (CFile::Exists(localThumb))
628   {
629     CFileItemPtr item(new CFileItem("thumb://Local", false));
630     item->SetThumbnailImage(localThumb);
631     item->SetLabel(g_localizeStrings.Get(20017));
632     items.Add(item);
633   }
634   else
635   { // no local thumb exists, so we are just using the IMDb thumb or cached thumb
636     // which is probably the IMDb thumb.  These could be wrong, so allow the user
637     // to delete the incorrect thumb
638     CFileItemPtr item(new CFileItem("thumb://None", false));
639     item->SetIconImage("DefaultVideo.png");
640     item->SetLabel(g_localizeStrings.Get(20018));
641     items.Add(item);
642   }
643
644   CStdString result;
645   VECSOURCES sources(g_settings.m_videoSources);
646   g_mediaManager.GetLocalDrives(sources);
647   if (!CGUIDialogFileBrowser::ShowAndGetImage(items, sources, g_localizeStrings.Get(20019), result))
648     return;   // user cancelled
649
650   if (result == "thumb://Current")
651     return;   // user chose the one they have
652
653   CStdString newThumb;
654   if (result.Left(14) == "thumb://Remote")
655   {
656     int number = atoi(result.Mid(14));
657     newThumb = thumbs[number];
658   }
659   else if (result == "thumb://Local")
660     newThumb = localThumb;
661   else if (CFile::Exists(result))
662     newThumb = result;
663   else // none
664     newThumb = "-"; // force local thumbs to be ignored
665
666   // update thumb in the database
667   CVideoDatabase db;
668   if (db.Open())
669   {
670     db.SetArtForItem(m_movieItem->GetVideoInfoTag()->m_iDbId, m_movieItem->GetVideoInfoTag()->m_type, "thumb", newThumb);
671     db.Close();
672   }
673
674   CUtil::DeleteVideoDatabaseDirectoryCache(); // to get them new thumbs to show
675   m_movieItem->SetThumbnailImage(newThumb);
676   if (m_movieItem->HasProperty("set_folder_thumb"))
677   { // have a folder thumb to set as well
678     VIDEO::CVideoInfoScanner::ApplyThumbToFolder(m_movieItem->GetProperty("set_folder_thumb").asString(), newThumb);
679   }
680   m_hasUpdatedThumb = true;
681
682   // Update our screen
683   Update();
684 }
685
686 // Allow user to select a Fanart
687 void CGUIDialogVideoInfo::OnGetFanart()
688 {
689   CFileItemList items;
690
691   CFileItem item(*m_movieItem->GetVideoInfoTag());
692   if (item.HasProperty("fanart_image"))
693   {
694     CFileItemPtr itemCurrent(new CFileItem("fanart://Current",false));
695     itemCurrent->SetThumbnailImage(item.GetProperty("fanart_image").asString());
696     itemCurrent->SetLabel(g_localizeStrings.Get(20440));
697     items.Add(itemCurrent);
698   }
699
700   // ensure the fanart is unpacked
701   m_movieItem->GetVideoInfoTag()->m_fanart.Unpack();
702
703   // Grab the thumbnails from the web
704   for (unsigned int i = 0; i < m_movieItem->GetVideoInfoTag()->m_fanart.GetNumFanarts(); i++)
705   {
706     CStdString strItemPath;
707     strItemPath.Format("fanart://Remote%i",i);
708     CFileItemPtr item(new CFileItem(strItemPath, false));
709     CStdString thumb = m_movieItem->GetVideoInfoTag()->m_fanart.GetPreviewURL(i);
710     item->SetThumbnailImage(CTextureCache::GetWrappedThumbURL(thumb));
711     item->SetIconImage("DefaultPicture.png");
712     item->SetLabel(g_localizeStrings.Get(20441));
713
714     // TODO: Do we need to clear the cached image?
715 //    CTextureCache::Get().ClearCachedImage(thumb);
716     items.Add(item);
717   }
718
719   CStdString strLocal = item.GetLocalFanart();
720   if (!strLocal.IsEmpty())
721   {
722     CFileItemPtr itemLocal(new CFileItem("fanart://Local",false));
723     itemLocal->SetThumbnailImage(strLocal);
724     itemLocal->SetLabel(g_localizeStrings.Get(20438));
725
726     // TODO: Do we need to clear the cached image?
727     CTextureCache::Get().ClearCachedImage(strLocal);
728     items.Add(itemLocal);
729   }
730   else
731   {
732     CFileItemPtr itemNone(new CFileItem("fanart://None", false));
733     itemNone->SetIconImage("DefaultVideo.png");
734     itemNone->SetLabel(g_localizeStrings.Get(20439));
735     items.Add(itemNone);
736   }
737
738   CStdString result;
739   VECSOURCES sources(g_settings.m_videoSources);
740   g_mediaManager.GetLocalDrives(sources);
741   bool flip=false;
742   if (!CGUIDialogFileBrowser::ShowAndGetImage(items, sources, g_localizeStrings.Get(20437), result, &flip, 20445) || result.Equals("fanart://Current"))
743     return;   // user cancelled
744
745   if (result.Equals("fanart://Local"))
746     result = strLocal;
747
748   if (result.Left(15) == "fanart://Remote")
749   {
750     int iFanart = atoi(result.Mid(15).c_str());
751     // set new primary fanart, and update our database accordingly
752     m_movieItem->GetVideoInfoTag()->m_fanart.SetPrimaryFanart(iFanart);
753     CVideoDatabase db;
754     if (db.Open())
755     {
756       db.UpdateFanart(*m_movieItem, (VIDEODB_CONTENT_TYPE)m_movieItem->GetVideoContentType());
757       db.Close();
758     }
759     result = m_movieItem->GetVideoInfoTag()->m_fanart.GetImageURL();
760   }
761   else if (result.Equals("fanart://None") || !CFile::Exists(result))
762     result.clear();
763
764   // set the fanart image
765   if (flip && !result.IsEmpty())
766     result = CTextureCache::GetWrappedImageURL(result, "", "flipped");
767   CVideoDatabase db;
768   if (db.Open())
769   {
770     db.SetArtForItem(m_movieItem->GetVideoInfoTag()->m_iDbId, m_movieItem->GetVideoInfoTag()->m_type, "fanart", result);
771     db.Close();
772   }
773
774   CUtil::DeleteVideoDatabaseDirectoryCache(); // to get them new thumbs to show
775   if (!result.IsEmpty())
776     m_movieItem->SetProperty("fanart_image", result);
777   else
778     m_movieItem->ClearProperty("fanart_image");
779   m_hasUpdatedThumb = true;
780
781   // Update our screen
782   Update();
783 }
784
785 void CGUIDialogVideoInfo::PlayTrailer()
786 {
787   CFileItem item;
788   item.SetPath(m_movieItem->GetVideoInfoTag()->m_strTrailer);
789   *item.GetVideoInfoTag() = *m_movieItem->GetVideoInfoTag();
790   item.GetVideoInfoTag()->m_streamDetails.Reset();
791   item.GetVideoInfoTag()->m_strTitle.Format("%s (%s)",m_movieItem->GetVideoInfoTag()->m_strTitle.c_str(),g_localizeStrings.Get(20410));
792   item.SetThumbnailImage(m_movieItem->GetThumbnailImage());
793   item.GetVideoInfoTag()->m_iDbId = -1;
794   item.GetVideoInfoTag()->m_iFileId = -1;
795
796   // Close the dialog.
797   Close(true);
798
799   if (item.IsPlayList())
800     g_application.getApplicationMessenger().MediaPlay(item);
801   else
802     g_application.getApplicationMessenger().PlayFile(item);
803 }
804
805 void CGUIDialogVideoInfo::SetLabel(int iControl, const CStdString &strLabel)
806 {
807   if (strLabel.IsEmpty())
808   {
809     SET_CONTROL_LABEL(iControl, 416);  // "Not available"
810   }
811   else
812   {
813     SET_CONTROL_LABEL(iControl, strLabel);
814   }
815 }
816
817 const CStdString& CGUIDialogVideoInfo::GetThumbnail() const
818 {
819   return m_movieItem->GetThumbnailImage();
820 }