Merge branch 'master' of git://github.com/a11599/xbmc into a11599-master
[vuplus_xbmc] / xbmc / video / windows / GUIWindowVideoNav.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 "GUIUserMessages.h"
23 #include "GUIWindowVideoNav.h"
24 #include "music/windows/GUIWindowMusicNav.h"
25 #include "utils/FileUtils.h"
26 #include "Util.h"
27 #include "utils/RegExp.h"
28 #include "PlayListPlayer.h"
29 #include "GUIPassword.h"
30 #include "dialogs/GUIDialogFileBrowser.h"
31 #include "filesystem/VideoDatabaseDirectory.h"
32 #include "playlists/PlayListFactory.h"
33 #include "video/dialogs/GUIDialogVideoScan.h"
34 #include "dialogs/GUIDialogOK.h"
35 #include "addons/AddonManager.h"
36 #include "PartyModeManager.h"
37 #include "music/MusicDatabase.h"
38 #include "guilib/GUIWindowManager.h"
39 #include "dialogs/GUIDialogYesNo.h"
40 #include "dialogs/GUIDialogSelect.h"
41 #include "filesystem/Directory.h"
42 #include "filesystem/File.h"
43 #include "FileItem.h"
44 #include "Application.h"
45 #include "settings/Settings.h"
46 #include "settings/AdvancedSettings.h"
47 #include "settings/GUISettings.h"
48 #include "guilib/LocalizeStrings.h"
49 #include "storage/MediaManager.h"
50 #include "utils/log.h"
51 #include "utils/URIUtils.h"
52 #include "TextureCache.h"
53
54 using namespace XFILE;
55 using namespace VIDEODATABASEDIRECTORY;
56 using namespace std;
57
58 #define CONTROL_BTNVIEWASICONS     2
59 #define CONTROL_BTNSORTBY          3
60 #define CONTROL_BTNSORTASC         4
61 #define CONTROL_BTNTYPE            5
62 #define CONTROL_BTNSEARCH          8
63 #define CONTROL_LABELFILES        12
64
65 #define CONTROL_BTN_FILTER        19
66 #define CONTROL_BTNSHOWMODE       10
67 #define CONTROL_BTNSHOWALL        14
68 #define CONTROL_UNLOCK            11
69
70 #define CONTROL_FILTER            15
71 #define CONTROL_BTNPARTYMODE      16
72 #define CONTROL_BTNFLATTEN        17
73 #define CONTROL_LABELEMPTY        18
74
75 CGUIWindowVideoNav::CGUIWindowVideoNav(void)
76     : CGUIWindowVideoBase(WINDOW_VIDEO_NAV, "MyVideoNav.xml")
77 {
78   m_thumbLoader.SetObserver(this);
79 }
80
81 CGUIWindowVideoNav::~CGUIWindowVideoNav(void)
82 {
83 }
84
85 bool CGUIWindowVideoNav::OnAction(const CAction &action)
86 {
87   if (action.GetID() == ACTION_TOGGLE_WATCHED)
88   {
89     CFileItemPtr pItem = m_vecItems->Get(m_viewControl.GetSelectedItem());
90     if (pItem->IsParentFolder())
91       return false;
92     if (pItem && pItem->GetVideoInfoTag()->m_playCount == 0)
93       return OnContextButton(m_viewControl.GetSelectedItem(),CONTEXT_BUTTON_MARK_WATCHED);
94     if (pItem && pItem->GetVideoInfoTag()->m_playCount > 0)
95       return OnContextButton(m_viewControl.GetSelectedItem(),CONTEXT_BUTTON_MARK_UNWATCHED);
96   }
97   return CGUIWindowVideoBase::OnAction(action);
98 }
99
100 bool CGUIWindowVideoNav::OnMessage(CGUIMessage& message)
101 {
102   switch (message.GetMessage())
103   {
104   case GUI_MSG_WINDOW_RESET:
105     m_vecItems->m_strPath.clear();
106     break;
107   case GUI_MSG_WINDOW_DEINIT:
108     if (m_thumbLoader.IsLoading())
109       m_thumbLoader.StopThread();
110     break;
111   case GUI_MSG_WINDOW_INIT:
112     {
113       /* We don't want to show Autosourced items (ie removable pendrives, memorycards) in Library mode */
114       m_rootDir.AllowNonLocalSources(false);
115
116       SetProperty("flattened", g_settings.m_bMyVideoNavFlatten);
117       
118       if (!CGUIWindowVideoBase::OnMessage(message))
119         return false;
120
121       //  base class has opened the database, do our check
122       m_database.Open();
123
124       if (!m_database.HasContent() && m_vecItems->IsVideoDb())
125       { // no library - make sure we default to the root.
126         m_vecItems->m_strPath = "";
127         SetHistoryForPath("");
128         Update("");
129       }
130
131       m_database.Close();
132       return true;
133     }
134     break;
135
136   case GUI_MSG_CLICKED:
137     {
138       int iControl = message.GetSenderId();
139       if (iControl == CONTROL_BTNPARTYMODE)
140       {
141         if (g_partyModeManager.IsEnabled())
142           g_partyModeManager.Disable();
143         else
144         {
145           if (!g_partyModeManager.Enable(PARTYMODECONTEXT_VIDEO))
146           {
147             SET_CONTROL_SELECTED(GetID(),CONTROL_BTNPARTYMODE,false);
148             return false;
149           }
150
151           // Playlist directory is the root of the playlist window
152           if (m_guiState.get()) m_guiState->SetPlaylistDirectory("playlistvideo://");
153
154           return true;
155         }
156         UpdateButtons();
157       }
158
159       if (iControl == CONTROL_BTNSEARCH)
160       {
161         OnSearch();
162       }
163       else if (iControl == CONTROL_BTNSHOWMODE)
164       {
165         g_settings.CycleWatchMode(m_vecItems->GetContent());
166         g_settings.Save();
167
168         // TODO: Can we perhaps filter this directly?  Probably not for some of the more complicated views,
169         //       but for those perhaps we can just display them all, and only filter when we get a list
170         //       of actual videos?
171         Update(m_vecItems->m_strPath);
172         return true;
173       }
174       else if (iControl == CONTROL_BTNFLATTEN)
175       {
176         g_settings.m_bMyVideoNavFlatten = !g_settings.m_bMyVideoNavFlatten;
177         g_settings.Save();
178         SetProperty("flattened", g_settings.m_bMyVideoNavFlatten);
179         CUtil::DeleteVideoDatabaseDirectoryCache();
180         SetupShares();
181         Update("");
182         return true;
183       }
184       else if (iControl == CONTROL_BTNSHOWALL)
185       {
186         if (g_settings.GetWatchMode(m_vecItems->GetContent()) == VIDEO_SHOW_ALL)
187           g_settings.SetWatchMode(m_vecItems->GetContent(), VIDEO_SHOW_UNWATCHED);
188         else
189           g_settings.SetWatchMode(m_vecItems->GetContent(), VIDEO_SHOW_ALL);
190         g_settings.Save();
191         // TODO: Can we perhaps filter this directly?  Probably not for some of the more complicated views,
192         //       but for those perhaps we can just display them all, and only filter when we get a list
193         //       of actual videos?
194         Update(m_vecItems->m_strPath);
195         return true;
196       }
197     }
198     break;
199     // update the display
200     case GUI_MSG_SCAN_FINISHED:
201     case GUI_MSG_REFRESH_THUMBS:
202     {
203       Update(m_vecItems->m_strPath);
204     }
205     break;
206   }
207   return CGUIWindowVideoBase::OnMessage(message);
208 }
209
210 CStdString CGUIWindowVideoNav::GetQuickpathName(const CStdString& strPath) const
211 {
212   if (strPath.Equals("videodb://1/1/"))
213     return "MovieGenres";
214   else if (strPath.Equals("videodb://1/2/"))
215     return "MovieTitles";
216   else if (strPath.Equals("videodb://1/3/"))
217     return "MovieYears";
218   else if (strPath.Equals("videodb://1/4/"))
219     return "MovieActors";
220   else if (strPath.Equals("videodb://1/5/"))
221     return "MovieDirectors";
222   else if (strPath.Equals("videodb://1/"))
223     return "Movies";
224   else if (strPath.Equals("videodb://2/1/"))
225     return "TvShowGenres";
226   else if (strPath.Equals("videodb://2/2/"))
227     return "TvShowTitles";
228   else if (strPath.Equals("videodb://2/3/"))
229     return "TvShowYears";
230   else if (strPath.Equals("videodb://2/4/"))
231     return "TvShowActors";
232   else if (strPath.Equals("videodb://2/"))
233     return "TvShows";
234   else if (strPath.Equals("videodb://3/1/"))
235     return "MusicVideoGenres";
236   else if (strPath.Equals("videodb://3/2/"))
237     return "MusicVideoTitles";
238   else if (strPath.Equals("videodb://3/3/"))
239     return "MusicVideoYears";
240   else if (strPath.Equals("videodb://3/4/"))
241     return "MusicVideoArtists";
242   else if (strPath.Equals("videodb://3/5/"))
243     return "MusicVideoDirectors";
244   else if (strPath.Equals("videodb://3/"))
245     return "MusicVideos";
246   else if (strPath.Equals("videodb://4/"))
247     return "RecentlyAddedMovies";
248   else if (strPath.Equals("videodb://5/"))
249     return "RecentlyAddedEpisodes";
250   else if (strPath.Equals("videodb://6/"))
251     return "RecentlyAddedMusicVideos";
252   else if (strPath.Equals("special://videoplaylists/"))
253     return "Playlists";
254   else if (strPath.Equals("sources://video/"))
255     return "Files";
256   else
257   {
258     CLog::Log(LOGERROR, "  CGUIWindowVideoNav::GetQuickpathName: Unknown parameter (%s)", strPath.c_str());
259     return strPath;
260   }
261 }
262
263 void CGUIWindowVideoNav::OnItemLoaded(CFileItem* pItem)
264 {
265   /* even though the background loader is running multiple threads and we could,
266      be acting on someone else's flag, we don't care who invalidates the cache
267      only that it is done.  We also don't care if it is done multiple times due
268      to a race between multiple threads here at the same time */
269   CUtil::DeleteVideoDatabaseDirectoryCache();
270 }
271
272 bool CGUIWindowVideoNav::GetDirectory(const CStdString &strDirectory, CFileItemList &items)
273 {
274   CFileItem directory(strDirectory, true);
275
276   if (m_thumbLoader.IsLoading())
277     m_thumbLoader.StopThread();
278
279   m_rootDir.SetCacheDirectory(DIR_CACHE_NEVER);
280   items.ClearProperties();
281
282   bool bResult = CGUIWindowVideoBase::GetDirectory(strDirectory, items);
283   if (bResult)
284   {
285     if (items.IsVideoDb())
286     {
287       XFILE::CVideoDatabaseDirectory dir;
288       CQueryParams params;
289       dir.GetQueryParams(items.m_strPath,params);
290       VIDEODATABASEDIRECTORY::NODE_TYPE node = dir.GetDirectoryChildType(items.m_strPath);
291
292       items.SetThumbnailImage("");
293       if (node == VIDEODATABASEDIRECTORY::NODE_TYPE_EPISODES ||
294           node == NODE_TYPE_SEASONS                          ||
295           node == NODE_TYPE_RECENTLY_ADDED_EPISODES)
296       {
297         CLog::Log(LOGDEBUG, "WindowVideoNav::GetDirectory");
298         // grab the show thumb
299         CFileItem showItem;
300         m_database.GetFilePathById(params.GetTvShowId(),showItem.m_strPath,VIDEODB_CONTENT_TVSHOWS);
301         showItem.SetVideoThumb();
302         items.SetProperty("tvshowthumb", showItem.GetThumbnailImage());
303         // Grab fanart data
304         CVideoInfoTag details;
305         m_database.GetTvShowInfo(showItem.m_strPath, details, params.GetTvShowId());
306         items.SetProperty("fanart_color1", details.m_fanart.GetColor(0));
307         items.SetProperty("fanart_color2", details.m_fanart.GetColor(1));
308         items.SetProperty("fanart_color3", details.m_fanart.GetColor(2));
309         if (showItem.CacheLocalFanart())
310           items.SetProperty("fanart_image", showItem.GetCachedFanart());
311
312         // save the show description (showplot)
313         items.SetProperty("showplot", details.m_strPlot);
314
315         // set the season thumb
316         CStdString strLabel;
317         if (params.GetSeason() == 0)
318           strLabel = g_localizeStrings.Get(20381);
319         else
320           strLabel.Format(g_localizeStrings.Get(20358), params.GetSeason());
321
322         CFileItem item(strLabel);
323         URIUtils::GetParentPath(items.m_strPath,item.m_strPath);
324         item.m_bIsFolder = true;
325         item.SetCachedSeasonThumb();
326         if (item.HasThumbnail())
327           items.SetProperty("seasonthumb",item.GetThumbnailImage());
328
329         // the container folder thumb is the parent (i.e. season or show)
330         if (node == NODE_TYPE_EPISODES || node == NODE_TYPE_RECENTLY_ADDED_EPISODES)
331         {
332           items.SetContent("episodes");
333           // grab the season thumb as the folder thumb
334           CStdString strLabel;
335           CStdString strPath;
336           if (params.GetSeason() == -1 && items.Size() > 0)
337           {
338             CQueryParams params2;
339             dir.GetQueryParams(items[0]->m_strPath,params2);
340             strLabel.Format(g_localizeStrings.Get(20358), params2.GetSeason());
341             URIUtils::GetParentPath(items.m_strPath,strPath);
342           }
343           else
344           {
345             if (params.GetSeason() == 0)
346               strLabel = g_localizeStrings.Get(20381);
347             else
348               strLabel.Format(g_localizeStrings.Get(20358), params.GetSeason());
349             strPath = items.m_strPath;
350           }
351
352           CFileItem item(strLabel);
353           item.m_strPath = strPath;
354           item.m_bIsFolder = true;
355           item.GetVideoInfoTag()->m_strPath = showItem.m_strPath;
356           item.SetCachedSeasonThumb();
357
358           items.SetThumbnailImage(item.GetThumbnailImage());
359           items.SetProperty("seasonthumb",item.GetThumbnailImage());
360         }
361         else
362         {
363           items.SetContent("seasons");
364           items.SetThumbnailImage(showItem.GetThumbnailImage());
365         }
366       }
367       else if (node == NODE_TYPE_TITLE_MOVIES ||
368                node == NODE_TYPE_RECENTLY_ADDED_MOVIES)
369         items.SetContent("movies");
370       else if (node == NODE_TYPE_TITLE_TVSHOWS)
371         items.SetContent("tvshows");
372       else if (node == NODE_TYPE_TITLE_MUSICVIDEOS ||
373                node == NODE_TYPE_RECENTLY_ADDED_MUSICVIDEOS)
374         items.SetContent("musicvideos");
375       else if (node == NODE_TYPE_GENRE)
376         items.SetContent("genres");
377       else if (node == NODE_TYPE_COUNTRY)
378         items.SetContent("countries");
379       else if (node == NODE_TYPE_ACTOR)
380       {
381         if (params.GetContentType() == VIDEODB_CONTENT_MUSICVIDEOS)
382           items.SetContent("artists");
383         else
384           items.SetContent("actors");
385       }
386       else if (node == NODE_TYPE_DIRECTOR)
387         items.SetContent("directors");
388       else if (node == NODE_TYPE_STUDIO)
389         items.SetContent("studios");
390       else if (node == NODE_TYPE_YEAR)
391         items.SetContent("years");
392       else if (node == NODE_TYPE_MUSICVIDEOS_ALBUM)
393         items.SetContent("albums");
394       else
395         items.SetContent("");
396     }
397     else
398     { // load info from the database
399       CStdString label;
400       if (items.GetLabel().IsEmpty() && m_rootDir.IsSource(items.m_strPath, g_settings.GetSourcesFromType("video"), &label)) 
401         items.SetLabel(label);
402       LoadVideoInfo(items);
403     }
404   }
405   return bResult;
406 }
407
408 void CGUIWindowVideoNav::LoadVideoInfo(CFileItemList &items)
409 {
410   // TODO: this could possibly be threaded as per the music info loading,
411   //       we could also cache the info
412   if (!items.GetContent().IsEmpty())
413     return; // don't load for listings that have content set
414
415   CStdString content = m_database.GetContentForPath(items.m_strPath);
416   if (content.IsEmpty())
417   {
418     items.SetContent("files");
419     return;
420   }
421   items.SetContent(content);
422
423   bool clean = (g_guiSettings.GetBool("myvideos.cleanstrings") &&
424                 !items.IsVirtualDirectoryRoot() &&
425                 m_stackingAvailable);
426
427   if (!content.IsEmpty())
428   {
429     for (int i = 0; i < items.Size(); i++)
430     {
431       CFileItemPtr pItem = items[i];
432       CFileItem item;
433       if (m_database.GetItemForPath(content, pItem->m_strPath, item))
434       { // copy info across
435         pItem->UpdateInfo(item);
436         pItem->m_strPath = item.m_strPath;
437         // if we switch from a file to a folder item it means we really shouldn't be sorting files and
438         // folders separately
439         if (pItem->m_bIsFolder != item.m_bIsFolder)
440           items.SetSortIgnoreFolders(true);
441         pItem->m_bIsFolder = item.m_bIsFolder;
442       }
443       else
444       {
445         if (clean)
446           pItem->CleanString();
447       }
448     }
449   }
450   else
451   {
452     for (int i = 0; i < items.Size(); i++)
453     {
454       CFileItemPtr pItem = items[i];
455       int playCount = m_database.GetPlayCount(*pItem);
456       if (playCount >= 0)
457         pItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, playCount > 0);
458       if (clean)
459         pItem->CleanString();
460     }
461   }
462 }
463
464 void CGUIWindowVideoNav::UpdateButtons()
465 {
466   CGUIWindowVideoBase::UpdateButtons();
467
468   // Update object count
469   int iItems = m_vecItems->Size();
470   if (iItems)
471   {
472     // check for parent dir and "all" items
473     // should always be the first two items
474     for (int i = 0; i <= (iItems>=2 ? 1 : 0); i++)
475     {
476       CFileItemPtr pItem = m_vecItems->Get(i);
477       if (pItem->IsParentFolder()) iItems--;
478       if (pItem->m_strPath.Left(4).Equals("/-1/")) iItems--;
479     }
480     // or the last item
481     if (m_vecItems->Size() > 2 &&
482       m_vecItems->Get(m_vecItems->Size()-1)->m_strPath.Left(4).Equals("/-1/"))
483       iItems--;
484   }
485   CStdString items;
486   items.Format("%i %s", iItems, g_localizeStrings.Get(127).c_str());
487   SET_CONTROL_LABEL(CONTROL_LABELFILES, items);
488
489   // set the filter label
490   CStdString strLabel;
491
492   // "Playlists"
493   if (m_vecItems->m_strPath.Equals("special://videoplaylists/"))
494     strLabel = g_localizeStrings.Get(136);
495   // "{Playlist Name}"
496   else if (m_vecItems->IsPlayList())
497   {
498     // get playlist name from path
499     CStdString strDummy;
500     URIUtils::Split(m_vecItems->m_strPath, strDummy, strLabel);
501   }
502   else if (m_vecItems->m_strPath.Equals("sources://video/"))
503     strLabel = g_localizeStrings.Get(744);
504   // everything else is from a videodb:// path
505   else if (m_vecItems->IsVideoDb())
506   {
507     CVideoDatabaseDirectory dir;
508     dir.GetLabel(m_vecItems->m_strPath, strLabel);
509   }
510   else
511     strLabel = URIUtils::GetFileName(m_vecItems->m_strPath);
512
513   SET_CONTROL_LABEL(CONTROL_FILTER, strLabel);
514
515   int watchMode = g_settings.GetWatchMode(m_vecItems->GetContent());
516   SET_CONTROL_LABEL(CONTROL_BTNSHOWMODE, g_localizeStrings.Get(16100 + watchMode));
517
518   SET_CONTROL_SELECTED(GetID(), CONTROL_BTNSHOWALL, watchMode != VIDEO_SHOW_ALL);
519
520   SET_CONTROL_SELECTED(GetID(),CONTROL_BTNPARTYMODE, g_partyModeManager.IsEnabled());
521
522   SET_CONTROL_SELECTED(GetID(),CONTROL_BTNFLATTEN, g_settings.m_bMyVideoNavFlatten);
523 }
524
525 /// \brief Search for names, genres, artists, directors, and plots with search string \e strSearch in the
526 /// \brief video databases and return the found \e items
527 /// \param strSearch The search string
528 /// \param items Items Found
529 void CGUIWindowVideoNav::DoSearch(const CStdString& strSearch, CFileItemList& items)
530 {
531   CFileItemList tempItems;
532   CStdString strGenre = g_localizeStrings.Get(515); // Genre
533   CStdString strActor = g_localizeStrings.Get(20337); // Actor
534   CStdString strDirector = g_localizeStrings.Get(20339); // Director
535   CStdString strMovie = g_localizeStrings.Get(20338); // Movie
536
537   //get matching names
538   m_database.GetMoviesByName(strSearch, tempItems);
539   AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(20338) + "] ", items);
540
541   m_database.GetEpisodesByName(strSearch, tempItems);
542   AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(20359) + "] ", items);
543
544   m_database.GetTvShowsByName(strSearch, tempItems);
545   AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(20364) + "] ", items);
546
547   m_database.GetMusicVideosByName(strSearch, tempItems);
548   AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(20391) + "] ", items);
549
550   m_database.GetMusicVideosByAlbum(strSearch, tempItems);
551   AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(558) + "] ", items);
552   
553   // get matching genres
554   m_database.GetMovieGenresByName(strSearch, tempItems);
555   AppendAndClearSearchItems(tempItems, "[" + strGenre + " - " + g_localizeStrings.Get(20342) + "] ", items);
556
557   m_database.GetTvShowGenresByName(strSearch, tempItems);
558   AppendAndClearSearchItems(tempItems, "[" + strGenre + " - " + g_localizeStrings.Get(20343) + "] ", items);
559
560   m_database.GetMusicVideoGenresByName(strSearch, tempItems);
561   AppendAndClearSearchItems(tempItems, "[" + strGenre + " - " + g_localizeStrings.Get(20389) + "] ", items);
562
563   //get actors/artists
564   m_database.GetMovieActorsByName(strSearch, tempItems);
565   AppendAndClearSearchItems(tempItems, "[" + strActor + " - " + g_localizeStrings.Get(20342) + "] ", items);
566
567   m_database.GetTvShowsActorsByName(strSearch, tempItems);
568   AppendAndClearSearchItems(tempItems, "[" + strActor + " - " + g_localizeStrings.Get(20343) + "] ", items);
569
570   m_database.GetMusicVideoArtistsByName(strSearch, tempItems);
571   AppendAndClearSearchItems(tempItems, "[" + strActor + " - " + g_localizeStrings.Get(20389) + "] ", items);
572
573   //directors
574   m_database.GetMovieDirectorsByName(strSearch, tempItems);
575   AppendAndClearSearchItems(tempItems, "[" + strDirector + " - " + g_localizeStrings.Get(20342) + "] ", items);
576
577   m_database.GetTvShowsDirectorsByName(strSearch, tempItems);
578   AppendAndClearSearchItems(tempItems, "[" + strDirector + " - " + g_localizeStrings.Get(20343) + "] ", items);
579
580   m_database.GetMusicVideoDirectorsByName(strSearch, tempItems);
581   AppendAndClearSearchItems(tempItems, "[" + strDirector + " - " + g_localizeStrings.Get(20389) + "] ", items);
582
583   //plot
584   m_database.GetEpisodesByPlot(strSearch, tempItems);
585   AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(20365) + "] ", items);
586
587   m_database.GetMoviesByPlot(strSearch, tempItems);
588   AppendAndClearSearchItems(tempItems, "[" + strMovie + " " + g_localizeStrings.Get(207) + "] ", items);
589 }
590
591 void CGUIWindowVideoNav::PlayItem(int iItem)
592 {
593   // unlike additemtoplaylist, we need to check the items here
594   // before calling it since the current playlist will be stopped
595   // and cleared!
596
597   // root is not allowed
598   if (m_vecItems->IsVirtualDirectoryRoot())
599     return;
600
601   CGUIWindowVideoBase::PlayItem(iItem);
602 }
603
604 void CGUIWindowVideoNav::OnInfo(CFileItem* pItem, ADDON::ScraperPtr& scraper)
605 {
606   m_database.Open(); // since we can be called from the music library without being inited
607   if (pItem->IsVideoDb())
608     scraper = m_database.GetScraperForPath(pItem->GetVideoInfoTag()->m_strPath);
609   else
610   {
611     CStdString strPath,strFile;
612     URIUtils::Split(pItem->m_strPath,strPath,strFile);
613     scraper = m_database.GetScraperForPath(strPath);
614   }
615   m_database.Close();
616   CGUIWindowVideoBase::OnInfo(pItem,scraper);
617 }
618
619 bool CGUIWindowVideoNav::CanDelete(const CStdString& strPath)
620 {
621   CQueryParams params;
622   CVideoDatabaseDirectory::GetQueryParams(strPath,params);
623
624   if (params.GetMovieId()   != -1 ||
625       params.GetEpisodeId() != -1 ||
626       params.GetMVideoId()  != -1 ||
627       (params.GetTvShowId() != -1 && params.GetSeason() == -1
628               && !CVideoDatabaseDirectory::IsAllItem(strPath)))
629     return true;
630
631   return false;
632 }
633
634 void CGUIWindowVideoNav::OnDeleteItem(CFileItemPtr pItem)
635 {
636   if (m_vecItems->IsParentFolder())
637     return;
638
639   if (!m_vecItems->IsVideoDb())
640   {
641     if (!pItem->m_strPath.Equals("newsmartplaylist://video") &&
642         !pItem->m_strPath.Equals("special://videoplaylists/") &&
643         !pItem->m_strPath.Equals("sources://video/"))
644       CGUIWindowVideoBase::OnDeleteItem(pItem);
645   }
646   else if (pItem->m_strPath.Left(14).Equals("videodb://1/7/") &&
647            pItem->m_strPath.size() > 14 && pItem->m_bIsFolder)
648   {
649     CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
650     pDialog->SetLine(0, g_localizeStrings.Get(432));
651     CStdString strLabel;
652     strLabel.Format(g_localizeStrings.Get(433),pItem->GetLabel());
653     pDialog->SetLine(1, strLabel);
654     pDialog->SetLine(2, "");;
655     pDialog->DoModal();
656     if (pDialog->IsConfirmed())
657     {
658       CFileItemList items;
659       CDirectory::GetDirectory(pItem->m_strPath,items,"",false,false,DIR_CACHE_ONCE,true,true);
660       for (int i=0;i<items.Size();++i)
661         OnDeleteItem(items[i]);
662
663        CVideoDatabaseDirectory dir;
664        CQueryParams params;
665        dir.GetQueryParams(pItem->m_strPath,params);
666        m_database.DeleteSet(params.GetSetId());
667     }
668   }
669   else
670   {
671     if (!DeleteItem(pItem.get()))
672       return;
673
674     CStdString strDeletePath;
675     if (pItem->m_bIsFolder)
676       strDeletePath=pItem->GetVideoInfoTag()->m_strPath;
677     else
678       strDeletePath=pItem->GetVideoInfoTag()->m_strFileNameAndPath;
679
680     if (URIUtils::GetFileName(strDeletePath).Equals("VIDEO_TS.IFO"))
681     {
682       URIUtils::GetDirectory(strDeletePath.Mid(0),strDeletePath);
683       if (strDeletePath.Right(9).Equals("VIDEO_TS/"))
684       {
685         URIUtils::RemoveSlashAtEnd(strDeletePath);
686         URIUtils::GetDirectory(strDeletePath.Mid(0),strDeletePath);
687       }
688     }
689     if (URIUtils::HasSlashAtEnd(strDeletePath))
690       pItem->m_bIsFolder=true;
691
692     if (g_guiSettings.GetBool("filelists.allowfiledeletion") &&
693         CUtil::SupportsFileOperations(strDeletePath))
694     {
695       pItem->m_strPath = strDeletePath;
696       CGUIWindowVideoBase::OnDeleteItem(pItem);
697     }
698   }
699
700   CUtil::DeleteVideoDatabaseDirectoryCache();
701 }
702
703 bool CGUIWindowVideoNav::DeleteItem(CFileItem* pItem, bool bUnavailable /* = false */)
704 {
705   if (!pItem->HasVideoInfoTag() || !CanDelete(pItem->m_strPath))
706     return false;
707
708   VIDEODB_CONTENT_TYPE iType=VIDEODB_CONTENT_MOVIES;
709   if (pItem->HasVideoInfoTag() && !pItem->GetVideoInfoTag()->m_strShowTitle.IsEmpty())
710     iType = VIDEODB_CONTENT_TVSHOWS;
711   if (pItem->HasVideoInfoTag() && pItem->GetVideoInfoTag()->m_iSeason > -1 && !pItem->m_bIsFolder)
712     iType = VIDEODB_CONTENT_EPISODES;
713   if (pItem->HasVideoInfoTag() && !pItem->GetVideoInfoTag()->m_strArtist.IsEmpty())
714     iType = VIDEODB_CONTENT_MUSICVIDEOS;
715
716   // dont allow update while scanning
717   CGUIDialogVideoScan* pDialogScan = (CGUIDialogVideoScan*)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_SCAN);
718   if (pDialogScan && pDialogScan->IsScanning())
719   {
720     CGUIDialogOK::ShowAndGetInput(257, 0, 14057, 0);
721     return false;
722   }
723
724
725   CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
726   if (!pDialog)
727     return false;
728   if (iType == VIDEODB_CONTENT_MOVIES)
729     pDialog->SetHeading(432);
730   if (iType == VIDEODB_CONTENT_EPISODES)
731     pDialog->SetHeading(20362);
732   if (iType == VIDEODB_CONTENT_TVSHOWS)
733     pDialog->SetHeading(20363);
734   if (iType == VIDEODB_CONTENT_MUSICVIDEOS)
735     pDialog->SetHeading(20392);
736
737   if(bUnavailable)
738   {
739     pDialog->SetLine(0, g_localizeStrings.Get(662));
740     pDialog->SetLine(1, g_localizeStrings.Get(663));
741     pDialog->SetLine(2, "");;
742     pDialog->DoModal();
743   }
744   else
745   {
746     CStdString strLine;
747     strLine.Format(g_localizeStrings.Get(433),pItem->GetLabel());
748     pDialog->SetLine(0, strLine);
749     pDialog->SetLine(1, "");
750     pDialog->SetLine(2, "");;
751     pDialog->DoModal();
752   }
753
754   if (!pDialog->IsConfirmed())
755     return false;
756
757   CStdString path;
758   CVideoDatabase database;
759   database.Open();
760
761   database.GetFilePathById(pItem->GetVideoInfoTag()->m_iDbId, path, iType);
762   if (path.IsEmpty())
763     return false;
764   if (iType == VIDEODB_CONTENT_MOVIES)
765     database.DeleteMovie(path);
766   if (iType == VIDEODB_CONTENT_EPISODES)
767     database.DeleteEpisode(path, pItem->GetVideoInfoTag()->m_iDbId);
768   if (iType == VIDEODB_CONTENT_TVSHOWS)
769     database.DeleteTvShow(path);
770   if (iType == VIDEODB_CONTENT_MUSICVIDEOS)
771     database.DeleteMusicVideo(path);
772
773   if (iType == VIDEODB_CONTENT_TVSHOWS)
774     database.SetPathHash(path,"");
775   else
776   {
777     CStdString strDirectory;
778     URIUtils::GetDirectory(path,strDirectory);
779     database.SetPathHash(strDirectory,"");
780   }
781
782   return true;
783 }
784
785 void CGUIWindowVideoNav::OnPrepareFileItems(CFileItemList &items)
786 {
787   CGUIWindowVideoBase::OnPrepareFileItems(items);
788
789   // set fanart
790   CQueryParams params;
791   CVideoDatabaseDirectory dir;
792   dir.GetQueryParams(items.m_strPath,params);
793   if (params.GetContentType() == VIDEODB_CONTENT_MUSICVIDEOS)
794     CGUIWindowMusicNav::SetupFanart(items);
795
796   NODE_TYPE node = dir.GetDirectoryChildType(items.m_strPath);
797
798   // now filter as necessary
799   bool filterWatched=false;
800   if (node == NODE_TYPE_EPISODES
801   ||  node == NODE_TYPE_SEASONS
802   ||  node == NODE_TYPE_TITLE_MOVIES
803   ||  node == NODE_TYPE_TITLE_TVSHOWS
804   ||  node == NODE_TYPE_TITLE_MUSICVIDEOS
805   ||  node == NODE_TYPE_RECENTLY_ADDED_EPISODES
806   ||  node == NODE_TYPE_RECENTLY_ADDED_MOVIES
807   ||  node == NODE_TYPE_RECENTLY_ADDED_MUSICVIDEOS)
808     filterWatched = true;
809   if (!items.IsVideoDb())
810     filterWatched = true;
811   if (items.IsSmartPlayList() && items.GetContent() == "tvshows")
812     node = NODE_TYPE_TITLE_TVSHOWS; // so that the check below works
813
814   int watchMode = g_settings.GetWatchMode(m_vecItems->GetContent());
815
816   for (int i = 0; i < items.Size(); i++)
817   {
818     CFileItemPtr item = items.Get(i);
819     if(item->HasVideoInfoTag() && (node == NODE_TYPE_TITLE_TVSHOWS || node == NODE_TYPE_SEASONS))
820     {
821       if (watchMode == VIDEO_SHOW_UNWATCHED)
822         item->GetVideoInfoTag()->m_iEpisode = item->GetPropertyInt("unwatchedepisodes");
823       if (watchMode == VIDEO_SHOW_WATCHED)
824         item->GetVideoInfoTag()->m_iEpisode = item->GetPropertyInt("watchedepisodes");
825       item->SetProperty("numepisodes", item->GetVideoInfoTag()->m_iEpisode);
826     }
827
828     if(filterWatched)
829     {
830       if((watchMode==VIDEO_SHOW_WATCHED   && item->GetVideoInfoTag()->m_playCount== 0)
831       || (watchMode==VIDEO_SHOW_UNWATCHED && item->GetVideoInfoTag()->m_playCount > 0))
832       {
833         items.Remove(i);
834         i--;
835       }
836     }
837   }
838 }
839
840 void CGUIWindowVideoNav::GetContextButtons(int itemNumber, CContextButtons &buttons)
841 {
842   CFileItemPtr item;
843   if (itemNumber >= 0 && itemNumber < m_vecItems->Size())
844     item = m_vecItems->Get(itemNumber);
845
846   CGUIWindowVideoBase::GetContextButtons(itemNumber, buttons);
847
848   if (item && item->GetPropertyBOOL("pluginreplacecontextitems"))
849     return;
850
851   CVideoDatabaseDirectory dir;
852   NODE_TYPE node = dir.GetDirectoryChildType(m_vecItems->m_strPath);
853
854   if (!item)
855   {
856     CGUIDialogVideoScan *pScanDlg = (CGUIDialogVideoScan *)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_SCAN);
857     if (pScanDlg && pScanDlg->IsScanning())
858       buttons.Add(CONTEXT_BUTTON_STOP_SCANNING, 13353);
859     else
860       buttons.Add(CONTEXT_BUTTON_UPDATE_LIBRARY, 653);
861   }
862   else if (m_vecItems->m_strPath.Equals("sources://video/"))
863   {
864     // get the usual shares
865     CGUIDialogContextMenu::GetContextButtons("video", item, buttons);
866     // add scan button somewhere here
867     CGUIDialogVideoScan *pScanDlg = (CGUIDialogVideoScan *)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_SCAN);
868     if (pScanDlg && pScanDlg->IsScanning())
869       buttons.Add(CONTEXT_BUTTON_STOP_SCANNING, 13353);  // Stop Scanning
870     if (!item->IsDVD() && item->m_strPath != "add" &&
871         (g_settings.GetCurrentProfile().canWriteDatabases() || g_passwordManager.bMasterUser))
872     {
873       CVideoDatabase database;
874       database.Open();
875       ADDON::ScraperPtr info = database.GetScraperForPath(item->m_strPath);
876
877       if (!pScanDlg || (pScanDlg && !pScanDlg->IsScanning()))
878       {
879         if (!item->IsLiveTV() && !item->IsPlugin() && !item->IsAddonsPath())
880         {
881           if (info && info->Content() != CONTENT_NONE)
882             buttons.Add(CONTEXT_BUTTON_SET_CONTENT, 20442);
883           else
884             buttons.Add(CONTEXT_BUTTON_SET_CONTENT, 20333);
885         }
886       }
887
888       if (info && (!pScanDlg || (pScanDlg && !pScanDlg->IsScanning())))
889         buttons.Add(CONTEXT_BUTTON_SCAN, 13349);
890     }
891   }
892   else
893   {
894     ADDON::ScraperPtr info;
895     VIDEO::SScanSettings settings;
896     GetScraperForItem(item.get(), info, settings);
897
898     if (info && info->Content() == CONTENT_TVSHOWS)
899       buttons.Add(CONTEXT_BUTTON_INFO, item->m_bIsFolder ? 20351 : 20352);
900     else if (info && info->Content() == CONTENT_MUSICVIDEOS)
901       buttons.Add(CONTEXT_BUTTON_INFO,20393);
902     else if (!item->m_bIsFolder && !item->m_strPath.Left(19).Equals("newsmartplaylist://"))
903       buttons.Add(CONTEXT_BUTTON_INFO, 13346);
904
905     if (item->HasVideoInfoTag() && !item->GetVideoInfoTag()->m_strArtist.IsEmpty())
906     {
907       CMusicDatabase database;
908       database.Open();
909       if (database.GetArtistByName(item->GetVideoInfoTag()->m_strArtist) > -1)
910         buttons.Add(CONTEXT_BUTTON_GO_TO_ARTIST, 20396);
911     }
912     if (item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_strAlbum.size() > 0)
913     {
914       CMusicDatabase database;
915       database.Open();
916       if (database.GetAlbumByName(item->GetVideoInfoTag()->m_strAlbum) > -1)
917         buttons.Add(CONTEXT_BUTTON_GO_TO_ALBUM, 20397);
918     }
919     if (item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_strAlbum.size() > 0 &&
920         item->GetVideoInfoTag()->m_strArtist.size() > 0                           &&
921         item->GetVideoInfoTag()->m_strTitle.size() > 0)
922     {
923       CMusicDatabase database;
924       database.Open();
925       if (database.GetSongByArtistAndAlbumAndTitle(item->GetVideoInfoTag()->m_strArtist,
926                                                    item->GetVideoInfoTag()->m_strAlbum,
927                                                    item->GetVideoInfoTag()->m_strTitle) > -1)
928       {
929         buttons.Add(CONTEXT_BUTTON_PLAY_OTHER, 20398);
930       }
931     }
932     if (!item->IsParentFolder())
933     {
934       // can we update the database?
935       if (g_settings.GetCurrentProfile().canWriteDatabases() || g_passwordManager.bMasterUser)
936       {
937         if (node == NODE_TYPE_TITLE_TVSHOWS)
938         {
939           CGUIDialogVideoScan *pScanDlg = (CGUIDialogVideoScan *)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_SCAN);
940           if (pScanDlg && pScanDlg->IsScanning())
941             buttons.Add(CONTEXT_BUTTON_STOP_SCANNING, 13353);
942           else
943             buttons.Add(CONTEXT_BUTTON_UPDATE_TVSHOW, 13349);
944         }
945         if (!item->IsPlugin() && !item->IsLiveTV() && !item->IsAddonsPath() &&
946              item->m_strPath != "sources://video/" && item->m_strPath != "special://videoplaylists/")
947         {
948           if (item->m_bIsFolder)
949           {
950             // Have both options for folders since we don't know whether all childs are watched/unwatched
951             buttons.Add(CONTEXT_BUTTON_MARK_UNWATCHED, 16104); //Mark as UnWatched
952             buttons.Add(CONTEXT_BUTTON_MARK_WATCHED, 16103);   //Mark as Watched
953           }
954           else
955           {
956             if (item->GetOverlayImage().Equals("OverlayWatched.png"))
957               buttons.Add(CONTEXT_BUTTON_MARK_UNWATCHED, 16104); //Mark as UnWatched
958             else
959               buttons.Add(CONTEXT_BUTTON_MARK_WATCHED, 16103);   //Mark as Watched
960           }
961         }
962         if ((node == NODE_TYPE_TITLE_TVSHOWS) ||
963             (item->IsVideoDb() && item->HasVideoInfoTag() && !item->m_bIsFolder))
964         {
965           buttons.Add(CONTEXT_BUTTON_EDIT, 16105); //Edit Title
966         }
967         if (m_database.HasContent(VIDEODB_CONTENT_TVSHOWS) && item->HasVideoInfoTag() &&
968            !item->m_bIsFolder && item->GetVideoInfoTag()->m_iEpisode == -1 &&
969             item->GetVideoInfoTag()->m_strArtist.IsEmpty() && item->GetVideoInfoTag()->m_iDbId >= 0) // movie entry
970         {
971           if (m_database.IsLinkedToTvshow(item->GetVideoInfoTag()->m_iDbId))
972             buttons.Add(CONTEXT_BUTTON_UNLINK_MOVIE,20385);
973           buttons.Add(CONTEXT_BUTTON_LINK_MOVIE,20384);
974         }
975
976         if (node == NODE_TYPE_SEASONS && item->m_bIsFolder)
977           buttons.Add(CONTEXT_BUTTON_SET_SEASON_THUMB, 20371);
978
979         if (item->m_strPath.Left(14).Equals("videodb://1/7/") && item->m_strPath.size() > 14 && item->m_bIsFolder) // sets
980         {
981           buttons.Add(CONTEXT_BUTTON_EDIT, 16105);
982           buttons.Add(CONTEXT_BUTTON_SET_MOVIESET_THUMB, 20435);
983           buttons.Add(CONTEXT_BUTTON_DELETE, 646);
984         }
985
986         if (node == NODE_TYPE_ACTOR && !dir.IsAllItem(item->m_strPath) && item->m_bIsFolder)
987         {
988           if (m_vecItems->m_strPath.Left(11).Equals("videodb://3")) // mvids
989             buttons.Add(CONTEXT_BUTTON_SET_ARTIST_THUMB, 13359);
990           else
991             buttons.Add(CONTEXT_BUTTON_SET_ACTOR_THUMB, 20403);
992         }
993         if (item->IsVideoDb() && item->HasVideoInfoTag() &&
994           (!item->m_bIsFolder || node == NODE_TYPE_TITLE_TVSHOWS))
995         {
996           if (info && info->Content() == CONTENT_TVSHOWS)
997           {
998             if(item->GetVideoInfoTag()->m_iBookmarkId != -1 &&
999                item->GetVideoInfoTag()->m_iBookmarkId != 0)
1000             {
1001               buttons.Add(CONTEXT_BUTTON_UNLINK_BOOKMARK, 20405);
1002             }
1003           }
1004           buttons.Add(CONTEXT_BUTTON_DELETE, 646);
1005         }
1006
1007         // this should ideally be non-contextual (though we need some context for non-tv show node I guess)
1008         CGUIDialogVideoScan *pScanDlg = (CGUIDialogVideoScan *)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_SCAN);
1009         if (pScanDlg && pScanDlg->IsScanning())
1010         {
1011           if (node != NODE_TYPE_TITLE_TVSHOWS)
1012             buttons.Add(CONTEXT_BUTTON_STOP_SCANNING, 13353);
1013         }
1014         else
1015           buttons.Add(CONTEXT_BUTTON_UPDATE_LIBRARY, 653);
1016       }
1017
1018       if (!m_vecItems->IsVideoDb() && !m_vecItems->IsVirtualDirectoryRoot())
1019       { // non-video db items, file operations are allowed
1020         if (g_guiSettings.GetBool("filelists.allowfiledeletion") &&
1021             CUtil::SupportsFileOperations(item->m_strPath))
1022         {
1023           buttons.Add(CONTEXT_BUTTON_DELETE, 117);
1024           buttons.Add(CONTEXT_BUTTON_RENAME, 118);
1025         }
1026         // add "Set/Change content" to folders
1027         if (item->m_bIsFolder && !item->IsPlayList() && !item->IsLiveTV() && !item->IsPlugin() && !item->IsAddonsPath())
1028         {
1029           CGUIDialogVideoScan *pScanDlg = (CGUIDialogVideoScan *)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_SCAN);
1030           if (!pScanDlg || (pScanDlg && !pScanDlg->IsScanning()))
1031           {
1032             if (info && info->Content() != CONTENT_NONE)
1033               buttons.Add(CONTEXT_BUTTON_SET_CONTENT, 20442);
1034             else
1035               buttons.Add(CONTEXT_BUTTON_SET_CONTENT, 20333);
1036           }
1037         }
1038       }
1039       if (item->IsPlugin() || item->m_strPath.Left(9).Equals("script://") || m_vecItems->IsPlugin())
1040         buttons.Add(CONTEXT_BUTTON_PLUGIN_SETTINGS, 1045);
1041     }
1042   }
1043   CGUIWindowVideoBase::GetNonContextButtons(itemNumber, buttons);
1044 }
1045
1046 bool CGUIWindowVideoNav::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
1047 {
1048   CFileItemPtr item;
1049   if (itemNumber >= 0 && itemNumber < m_vecItems->Size())
1050     item = m_vecItems->Get(itemNumber);
1051   if (CGUIDialogContextMenu::OnContextButton("video", item, button))
1052   {
1053     //TODO should we search DB for entries from plugins?
1054     if (button == CONTEXT_BUTTON_REMOVE_SOURCE && !item->IsPlugin()
1055         && !item->IsLiveTV() &&!item->IsRSS())
1056     {
1057       OnUnAssignContent(item->m_strPath,20375,20340,20341);
1058     }
1059     Update(m_vecItems->m_strPath);
1060     return true;
1061   }
1062   switch (button)
1063   {
1064   case CONTEXT_BUTTON_EDIT:
1065     UpdateVideoTitle(item.get());
1066     CUtil::DeleteVideoDatabaseDirectoryCache();
1067     Update(m_vecItems->m_strPath);
1068     return true;
1069
1070   case CONTEXT_BUTTON_SET_SEASON_THUMB:
1071   case CONTEXT_BUTTON_SET_ACTOR_THUMB:
1072   case CONTEXT_BUTTON_SET_ARTIST_THUMB:
1073   case CONTEXT_BUTTON_SET_MOVIESET_THUMB:
1074     {
1075       // Grab the thumbnails from the web
1076       CStdString strPath;
1077       CFileItemList items;
1078       URIUtils::AddFileToFolder(g_advancedSettings.m_cachePath,"imdbthumbs",strPath);
1079       CFileItemPtr cacheItem(new CFileItem(strPath,true));
1080       CFileUtils::DeleteItem(cacheItem,true);
1081       XFILE::CDirectory::Create(strPath);
1082       CFileItemPtr noneitem(new CFileItem("thumb://None", false));
1083       CStdString cachedThumb = m_vecItems->Get(itemNumber)->GetCachedSeasonThumb();
1084       if (button == CONTEXT_BUTTON_SET_ACTOR_THUMB)
1085         cachedThumb = m_vecItems->Get(itemNumber)->GetCachedActorThumb();
1086       if (button == CONTEXT_BUTTON_SET_ARTIST_THUMB)
1087         cachedThumb = m_vecItems->Get(itemNumber)->GetCachedArtistThumb();
1088       if (button == CONTEXT_BUTTON_SET_MOVIESET_THUMB)
1089         cachedThumb = m_vecItems->Get(itemNumber)->GetCachedVideoThumb();
1090       if (CFile::Exists(cachedThumb))
1091       {
1092         CFileItemPtr item(new CFileItem("thumb://Current", false));
1093         item->SetThumbnailImage(cachedThumb);
1094         item->SetLabel(g_localizeStrings.Get(20016));
1095         items.Add(item);
1096       }
1097       noneitem->SetIconImage("DefaultFolder.png");
1098       noneitem->SetLabel(g_localizeStrings.Get(20018));
1099
1100       vector<CStdString> thumbs;
1101       if (button != CONTEXT_BUTTON_SET_ARTIST_THUMB)
1102       {
1103         CVideoInfoTag tag;
1104         if (button == CONTEXT_BUTTON_SET_SEASON_THUMB)
1105           m_database.GetTvShowInfo("",tag,m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_iDbId);
1106         else
1107           tag = *m_vecItems->Get(itemNumber)->GetVideoInfoTag();
1108         if (button == CONTEXT_BUTTON_SET_SEASON_THUMB)
1109           tag.m_strPictureURL.GetThumbURLs(thumbs, m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_iSeason);
1110         else
1111           tag.m_strPictureURL.GetThumbURLs(thumbs);
1112
1113         for (unsigned int i = 0; i < thumbs.size(); i++)
1114         {
1115           CStdString strItemPath;
1116           strItemPath.Format("thumb://Remote%i",i);
1117           CFileItemPtr item(new CFileItem(strItemPath, false));
1118           item->SetThumbnailImage(thumbs[i]);
1119           item->SetIconImage("DefaultPicture.png");
1120           item->SetLabel(g_localizeStrings.Get(20015));
1121           items.Add(item);
1122
1123           // TODO: Do we need to clear the cached image?
1124           //    CTextureCache::Get().ClearCachedImage(thumbs[i]);
1125         }
1126       }
1127
1128       bool local=false;
1129       if (button == CONTEXT_BUTTON_SET_ARTIST_THUMB)
1130       {
1131         CStdString picturePath;
1132
1133         CStdString strPath = m_vecItems->Get(itemNumber)->m_strPath;
1134         URIUtils::RemoveSlashAtEnd(strPath);
1135
1136         int nPos=strPath.ReverseFind("/");
1137         if (nPos>-1)
1138         {
1139           //  try to guess where the user should start
1140           //  browsing for the artist thumb
1141           CMusicDatabase database;
1142           database.Open();
1143           long idArtist=database.GetArtistByName(m_vecItems->Get(itemNumber)->GetLabel());
1144           database.GetArtistPath(idArtist, picturePath);
1145         }
1146
1147         CStdString strThumb;
1148         URIUtils::AddFileToFolder(picturePath,"folder.jpg",strThumb);
1149         if (XFILE::CFile::Exists(strThumb))
1150         {
1151           CFileItemPtr pItem(new CFileItem(strThumb,false));
1152           pItem->SetLabel(g_localizeStrings.Get(20017));
1153           pItem->SetThumbnailImage(strThumb);
1154           items.Add(pItem);
1155           local = true;
1156         }
1157         else
1158           noneitem->SetIconImage("DefaultArtist.png");
1159       }
1160
1161       if (button == CONTEXT_BUTTON_SET_ACTOR_THUMB)
1162       {
1163         CStdString picturePath;
1164         CStdString strThumb;
1165         URIUtils::AddFileToFolder(picturePath,"folder.jpg",strThumb);
1166         if (XFILE::CFile::Exists(strThumb))
1167         {
1168           CFileItemPtr pItem(new CFileItem(strThumb,false));
1169           pItem->SetLabel(g_localizeStrings.Get(20017));
1170           pItem->SetThumbnailImage(strThumb);
1171           items.Add(pItem);
1172           local = true;
1173         }
1174         else
1175           noneitem->SetIconImage("DefaultActor.png");
1176       }
1177
1178       if (button == CONTEXT_BUTTON_SET_MOVIESET_THUMB)
1179         noneitem->SetIconImage("DefaultVideo.png");
1180
1181       if (!local)
1182         items.Add(noneitem);
1183
1184       VECSOURCES sources=g_settings.m_videoSources;
1185       g_mediaManager.GetLocalDrives(sources);
1186       CStdString result;
1187       if (!CGUIDialogFileBrowser::ShowAndGetImage(items, sources,
1188                                                   g_localizeStrings.Get(20019), result))
1189       {
1190         return false;   // user cancelled
1191       }
1192
1193       if (result == "thumb://Current")
1194         return false;   // user chose the one they have
1195
1196       // delete the thumbnail if that's what the user wants, else overwrite with the
1197       // new thumbnail
1198       CTextureCache::Get().ClearCachedImage(cachedThumb, true);
1199       if (result.Left(14) == "thumb://Remote")
1200       {
1201         int number = atoi(result.Mid(14));
1202         CFile::Cache(thumbs[number], cachedThumb);
1203       }
1204       if (result == "thumb://None")
1205         CTextureCache::Get().ClearCachedImage(cachedThumb, true);
1206       else
1207         CFile::Cache(result,cachedThumb);
1208
1209       CUtil::DeleteVideoDatabaseDirectoryCache();
1210       CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_REFRESH_THUMBS);
1211       g_windowManager.SendMessage(msg);
1212       Update(m_vecItems->m_strPath);
1213
1214       return true;
1215     }
1216   case CONTEXT_BUTTON_UPDATE_LIBRARY:
1217     {
1218       OnScan("");
1219       return true;
1220     }
1221   case CONTEXT_BUTTON_UNLINK_MOVIE:
1222     {
1223       OnLinkMovieToTvShow(itemNumber, true);
1224       Update(m_vecItems->m_strPath);
1225       return true;
1226     }
1227   case CONTEXT_BUTTON_LINK_MOVIE:
1228     {
1229       OnLinkMovieToTvShow(itemNumber, false);
1230       return true;
1231     }
1232   case CONTEXT_BUTTON_GO_TO_ARTIST:
1233     {
1234       CStdString strPath;
1235       CMusicDatabase database;
1236       database.Open();
1237       strPath.Format("musicdb://2/%ld/",database.GetArtistByName(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strArtist));
1238       g_windowManager.ActivateWindow(WINDOW_MUSIC_NAV,strPath);
1239       return true;
1240     }
1241   case CONTEXT_BUTTON_GO_TO_ALBUM:
1242     {
1243       CStdString strPath;
1244       CMusicDatabase database;
1245       database.Open();
1246       strPath.Format("musicdb://3/%ld/",database.GetAlbumByName(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strAlbum));
1247       g_windowManager.ActivateWindow(WINDOW_MUSIC_NAV,strPath);
1248       return true;
1249     }
1250   case CONTEXT_BUTTON_PLAY_OTHER:
1251     {
1252       CMusicDatabase database;
1253       database.Open();
1254       CSong song;
1255       if (database.GetSongById(database.GetSongByArtistAndAlbumAndTitle(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strArtist,m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strAlbum,
1256                                                                         m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strTitle),
1257                                                                         song))
1258       {
1259         g_application.getApplicationMessenger().PlayFile(song);
1260       }
1261       return true;
1262     }
1263
1264   case CONTEXT_BUTTON_UNLINK_BOOKMARK:
1265     {
1266       m_database.Open();
1267       m_database.DeleteBookMarkForEpisode(*m_vecItems->Get(itemNumber)->GetVideoInfoTag());
1268       m_database.Close();
1269       CUtil::DeleteVideoDatabaseDirectoryCache();
1270       Update(m_vecItems->m_strPath);
1271       return true;
1272     }
1273
1274   default:
1275     break;
1276
1277   }
1278   return CGUIWindowVideoBase::OnContextButton(itemNumber, button);
1279 }
1280
1281 void CGUIWindowVideoNav::OnLinkMovieToTvShow(int itemnumber, bool bRemove)
1282 {
1283   CFileItemList list;
1284   if (bRemove)
1285   {
1286     vector<int> ids;
1287     if (!m_database.GetLinksToTvShow(m_vecItems->Get(itemnumber)->GetVideoInfoTag()->m_iDbId,ids))
1288       return;
1289     for (unsigned int i=0;i<ids.size();++i)
1290     {
1291       CVideoInfoTag tag;
1292       m_database.GetTvShowInfo("",tag,ids[i]);
1293       CFileItemPtr show(new CFileItem(tag));
1294       list.Add(show);
1295     }
1296   }
1297   else
1298   {
1299     m_database.GetTvShowsNav("videodb://2/2",list);
1300
1301     // remove already linked shows
1302     vector<int> ids;
1303     if (!m_database.GetLinksToTvShow(m_vecItems->Get(itemnumber)->GetVideoInfoTag()->m_iDbId,ids))
1304       return;
1305     for (int i=0;i<list.Size();)
1306     {
1307       unsigned int j;
1308       for (j=0;j<ids.size();++j)
1309       {
1310         if (list[i]->GetVideoInfoTag()->m_iDbId == ids[j])
1311           break;
1312       }
1313       if (j == ids.size())
1314         i++;
1315       else
1316         list.Remove(i);
1317     }
1318   }
1319   int iSelectedLabel = 0;
1320   if (list.Size() > 1)
1321   {
1322     list.Sort(g_guiSettings.GetBool("filelists.ignorethewhensorting") ? SORT_METHOD_LABEL_IGNORE_THE : SORT_METHOD_LABEL, SORT_ORDER_ASC);
1323     CGUIDialogSelect* pDialog = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
1324     pDialog->Reset();
1325     pDialog->SetItems(&list);
1326     pDialog->SetHeading(20356);
1327     pDialog->DoModal();
1328     iSelectedLabel = pDialog->GetSelectedLabel();
1329   }
1330   if (iSelectedLabel > -1)
1331   {
1332     m_database.LinkMovieToTvshow(m_vecItems->Get(itemnumber)->GetVideoInfoTag()->m_iDbId,
1333                                  list[iSelectedLabel]->GetVideoInfoTag()->m_iDbId, bRemove);
1334     CUtil::DeleteVideoDatabaseDirectoryCache();
1335   }
1336 }
1337
1338 bool CGUIWindowVideoNav::OnClick(int iItem)
1339 {
1340   CFileItemPtr item = m_vecItems->Get(iItem);
1341   if (!item->m_bIsFolder && item->IsVideoDb() && !item->Exists())
1342   {
1343     if (!DeleteItem(item.get(), true))
1344       return true;
1345
1346     // update list
1347     m_vecItems->RemoveDiscCache(GetID());
1348     Update(m_vecItems->m_strPath);
1349     m_viewControl.SetSelectedItem(iItem);
1350     return true;
1351   }
1352
1353   return CGUIWindowVideoBase::OnClick(iItem);
1354 }
1355
1356 CStdString CGUIWindowVideoNav::GetStartFolder(const CStdString &dir)
1357 {
1358   if (dir.Equals("MovieGenres"))
1359     return "videodb://1/1/";
1360   else if (dir.Equals("MovieTitles"))
1361     return "videodb://1/2/";
1362   else if (dir.Equals("MovieYears"))
1363     return "videodb://1/3/";
1364   else if (dir.Equals("MovieActors"))
1365     return "videodb://1/4/";
1366   else if (dir.Equals("MovieDirectors"))
1367     return "videodb://1/5/";
1368   else if (dir.Equals("MovieStudios"))
1369     return "videodb://1/6/";
1370   else if (dir.Equals("MovieSets"))
1371     return "videodb://1/7/";
1372   else if (dir.Equals("MovieCountries"))
1373     return "videodb://1/8/";
1374   else if (dir.Equals("Movies"))
1375     return "videodb://1/";
1376   else if (dir.Equals("TvShowGenres"))
1377     return "videodb://2/1/";
1378   else if (dir.Equals("TvShowTitles"))
1379     return "videodb://2/2/";
1380   else if (dir.Equals("TvShowYears"))
1381     return "videodb://2/3/";
1382   else if (dir.Equals("TvShowActors"))
1383     return "videodb://2/4/";
1384   else if (dir.Equals("TvShowStudios"))
1385     return "videodb://2/5/";
1386   else if (dir.Equals("TvShows"))
1387     return "videodb://2/";
1388   else if (dir.Equals("MusicVideoGenres"))
1389     return "videodb://3/1/";
1390   else if (dir.Equals("MusicVideoTitles"))
1391     return "videodb://3/2/";
1392   else if (dir.Equals("MusicVideoYears"))
1393     return "videodb://3/3/";
1394   else if (dir.Equals("MusicVideoArtists"))
1395     return "videodb://3/4/";
1396   else if (dir.Equals("MusicVideoDirectors"))
1397     return "videodb://3/5/";
1398   else if (dir.Equals("MusicVideoStudios"))
1399     return "videodb://3/6/";
1400   else if (dir.Equals("MusicVideos"))
1401     return "videodb://3/";
1402   else if (dir.Equals("RecentlyAddedMovies"))
1403     return "videodb://4/";
1404   else if (dir.Equals("RecentlyAddedEpisodes"))
1405     return "videodb://5/";
1406   else if (dir.Equals("RecentlyAddedMusicVideos"))
1407     return "videodb://6/";
1408   else if (dir.Equals("Files"))
1409     return "sources://video/";
1410   return CGUIWindowVideoBase::GetStartFolder(dir);
1411 }