speed up retrieval of library info when browsing by file
[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   items.SetContent(content.IsEmpty() ? "files" : content);
417
418   bool clean = (g_guiSettings.GetBool("myvideos.cleanstrings") &&
419                 !items.IsVirtualDirectoryRoot() &&
420                 m_stackingAvailable);
421
422   CFileItemList dbItems;
423   if (content.IsEmpty())
424     m_database.GetPlayCounts(items);
425   else
426   {
427     m_database.GetItemsForPath(content, items.m_strPath, dbItems);
428     dbItems.SetFastLookup(true);
429   }
430   for (int i = 0; i < items.Size(); i++)
431   {
432     CFileItemPtr pItem = items[i];
433     CFileItemPtr match;
434     if (!content.IsEmpty())
435       match = dbItems.Get(pItem->m_strPath);
436     if (match)
437     {
438       pItem->UpdateInfo(*match);
439       if (match->m_bIsFolder)
440         pItem->m_strPath = match->GetVideoInfoTag()->m_strPath;
441       else
442         pItem->m_strPath = match->GetVideoInfoTag()->m_strFileNameAndPath;
443       // if we switch from a file to a folder item it means we really shouldn't be sorting files and
444       // folders separately
445       if (pItem->m_bIsFolder != match->m_bIsFolder)
446         items.SetSortIgnoreFolders(true);
447       pItem->m_bIsFolder = match->m_bIsFolder;
448     }
449     else
450     { // set the watched overlay (note: items in a folder with content set that aren't in the db
451       //                                won't get picked up here - in the future all items will be returned)
452       // and clean the label
453       if (pItem->HasVideoInfoTag())
454         pItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, pItem->GetVideoInfoTag()->m_playCount > 0);
455       if (clean)
456         pItem->CleanString();
457     }
458   }
459 }
460
461 void CGUIWindowVideoNav::UpdateButtons()
462 {
463   CGUIWindowVideoBase::UpdateButtons();
464
465   // Update object count
466   int iItems = m_vecItems->Size();
467   if (iItems)
468   {
469     // check for parent dir and "all" items
470     // should always be the first two items
471     for (int i = 0; i <= (iItems>=2 ? 1 : 0); i++)
472     {
473       CFileItemPtr pItem = m_vecItems->Get(i);
474       if (pItem->IsParentFolder()) iItems--;
475       if (pItem->m_strPath.Left(4).Equals("/-1/")) iItems--;
476     }
477     // or the last item
478     if (m_vecItems->Size() > 2 &&
479       m_vecItems->Get(m_vecItems->Size()-1)->m_strPath.Left(4).Equals("/-1/"))
480       iItems--;
481   }
482   CStdString items;
483   items.Format("%i %s", iItems, g_localizeStrings.Get(127).c_str());
484   SET_CONTROL_LABEL(CONTROL_LABELFILES, items);
485
486   // set the filter label
487   CStdString strLabel;
488
489   // "Playlists"
490   if (m_vecItems->m_strPath.Equals("special://videoplaylists/"))
491     strLabel = g_localizeStrings.Get(136);
492   // "{Playlist Name}"
493   else if (m_vecItems->IsPlayList())
494   {
495     // get playlist name from path
496     CStdString strDummy;
497     URIUtils::Split(m_vecItems->m_strPath, strDummy, strLabel);
498   }
499   else if (m_vecItems->m_strPath.Equals("sources://video/"))
500     strLabel = g_localizeStrings.Get(744);
501   // everything else is from a videodb:// path
502   else if (m_vecItems->IsVideoDb())
503   {
504     CVideoDatabaseDirectory dir;
505     dir.GetLabel(m_vecItems->m_strPath, strLabel);
506   }
507   else
508     strLabel = URIUtils::GetFileName(m_vecItems->m_strPath);
509
510   SET_CONTROL_LABEL(CONTROL_FILTER, strLabel);
511
512   int watchMode = g_settings.GetWatchMode(m_vecItems->GetContent());
513   SET_CONTROL_LABEL(CONTROL_BTNSHOWMODE, g_localizeStrings.Get(16100 + watchMode));
514
515   SET_CONTROL_SELECTED(GetID(), CONTROL_BTNSHOWALL, watchMode != VIDEO_SHOW_ALL);
516
517   SET_CONTROL_SELECTED(GetID(),CONTROL_BTNPARTYMODE, g_partyModeManager.IsEnabled());
518
519   SET_CONTROL_SELECTED(GetID(),CONTROL_BTNFLATTEN, g_settings.m_bMyVideoNavFlatten);
520 }
521
522 /// \brief Search for names, genres, artists, directors, and plots with search string \e strSearch in the
523 /// \brief video databases and return the found \e items
524 /// \param strSearch The search string
525 /// \param items Items Found
526 void CGUIWindowVideoNav::DoSearch(const CStdString& strSearch, CFileItemList& items)
527 {
528   CFileItemList tempItems;
529   CStdString strGenre = g_localizeStrings.Get(515); // Genre
530   CStdString strActor = g_localizeStrings.Get(20337); // Actor
531   CStdString strDirector = g_localizeStrings.Get(20339); // Director
532   CStdString strMovie = g_localizeStrings.Get(20338); // Movie
533
534   //get matching names
535   m_database.GetMoviesByName(strSearch, tempItems);
536   AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(20338) + "] ", items);
537
538   m_database.GetEpisodesByName(strSearch, tempItems);
539   AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(20359) + "] ", items);
540
541   m_database.GetTvShowsByName(strSearch, tempItems);
542   AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(20364) + "] ", items);
543
544   m_database.GetMusicVideosByName(strSearch, tempItems);
545   AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(20391) + "] ", items);
546
547   m_database.GetMusicVideosByAlbum(strSearch, tempItems);
548   AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(558) + "] ", items);
549   
550   // get matching genres
551   m_database.GetMovieGenresByName(strSearch, tempItems);
552   AppendAndClearSearchItems(tempItems, "[" + strGenre + " - " + g_localizeStrings.Get(20342) + "] ", items);
553
554   m_database.GetTvShowGenresByName(strSearch, tempItems);
555   AppendAndClearSearchItems(tempItems, "[" + strGenre + " - " + g_localizeStrings.Get(20343) + "] ", items);
556
557   m_database.GetMusicVideoGenresByName(strSearch, tempItems);
558   AppendAndClearSearchItems(tempItems, "[" + strGenre + " - " + g_localizeStrings.Get(20389) + "] ", items);
559
560   //get actors/artists
561   m_database.GetMovieActorsByName(strSearch, tempItems);
562   AppendAndClearSearchItems(tempItems, "[" + strActor + " - " + g_localizeStrings.Get(20342) + "] ", items);
563
564   m_database.GetTvShowsActorsByName(strSearch, tempItems);
565   AppendAndClearSearchItems(tempItems, "[" + strActor + " - " + g_localizeStrings.Get(20343) + "] ", items);
566
567   m_database.GetMusicVideoArtistsByName(strSearch, tempItems);
568   AppendAndClearSearchItems(tempItems, "[" + strActor + " - " + g_localizeStrings.Get(20389) + "] ", items);
569
570   //directors
571   m_database.GetMovieDirectorsByName(strSearch, tempItems);
572   AppendAndClearSearchItems(tempItems, "[" + strDirector + " - " + g_localizeStrings.Get(20342) + "] ", items);
573
574   m_database.GetTvShowsDirectorsByName(strSearch, tempItems);
575   AppendAndClearSearchItems(tempItems, "[" + strDirector + " - " + g_localizeStrings.Get(20343) + "] ", items);
576
577   m_database.GetMusicVideoDirectorsByName(strSearch, tempItems);
578   AppendAndClearSearchItems(tempItems, "[" + strDirector + " - " + g_localizeStrings.Get(20389) + "] ", items);
579
580   //plot
581   m_database.GetEpisodesByPlot(strSearch, tempItems);
582   AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(20365) + "] ", items);
583
584   m_database.GetMoviesByPlot(strSearch, tempItems);
585   AppendAndClearSearchItems(tempItems, "[" + strMovie + " " + g_localizeStrings.Get(207) + "] ", items);
586 }
587
588 void CGUIWindowVideoNav::PlayItem(int iItem)
589 {
590   // unlike additemtoplaylist, we need to check the items here
591   // before calling it since the current playlist will be stopped
592   // and cleared!
593
594   // root is not allowed
595   if (m_vecItems->IsVirtualDirectoryRoot())
596     return;
597
598   CGUIWindowVideoBase::PlayItem(iItem);
599 }
600
601 void CGUIWindowVideoNav::OnInfo(CFileItem* pItem, ADDON::ScraperPtr& scraper)
602 {
603   m_database.Open(); // since we can be called from the music library without being inited
604   if (pItem->IsVideoDb())
605     scraper = m_database.GetScraperForPath(pItem->GetVideoInfoTag()->m_strPath);
606   else
607   {
608     CStdString strPath,strFile;
609     URIUtils::Split(pItem->m_strPath,strPath,strFile);
610     scraper = m_database.GetScraperForPath(strPath);
611   }
612   m_database.Close();
613   CGUIWindowVideoBase::OnInfo(pItem,scraper);
614 }
615
616 bool CGUIWindowVideoNav::CanDelete(const CStdString& strPath)
617 {
618   CQueryParams params;
619   CVideoDatabaseDirectory::GetQueryParams(strPath,params);
620
621   if (params.GetMovieId()   != -1 ||
622       params.GetEpisodeId() != -1 ||
623       params.GetMVideoId()  != -1 ||
624       (params.GetTvShowId() != -1 && params.GetSeason() == -1
625               && !CVideoDatabaseDirectory::IsAllItem(strPath)))
626     return true;
627
628   return false;
629 }
630
631 void CGUIWindowVideoNav::OnDeleteItem(CFileItemPtr pItem)
632 {
633   if (m_vecItems->IsParentFolder())
634     return;
635
636   if (!m_vecItems->IsVideoDb())
637   {
638     if (!pItem->m_strPath.Equals("newsmartplaylist://video") &&
639         !pItem->m_strPath.Equals("special://videoplaylists/") &&
640         !pItem->m_strPath.Equals("sources://video/"))
641       CGUIWindowVideoBase::OnDeleteItem(pItem);
642   }
643   else if (pItem->m_strPath.Left(14).Equals("videodb://1/7/") &&
644            pItem->m_strPath.size() > 14 && pItem->m_bIsFolder)
645   {
646     CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
647     pDialog->SetLine(0, g_localizeStrings.Get(432));
648     CStdString strLabel;
649     strLabel.Format(g_localizeStrings.Get(433),pItem->GetLabel());
650     pDialog->SetLine(1, strLabel);
651     pDialog->SetLine(2, "");;
652     pDialog->DoModal();
653     if (pDialog->IsConfirmed())
654     {
655       CFileItemList items;
656       CDirectory::GetDirectory(pItem->m_strPath,items,"",false,false,DIR_CACHE_ONCE,true,true);
657       for (int i=0;i<items.Size();++i)
658         OnDeleteItem(items[i]);
659
660        CVideoDatabaseDirectory dir;
661        CQueryParams params;
662        dir.GetQueryParams(pItem->m_strPath,params);
663        m_database.DeleteSet(params.GetSetId());
664     }
665   }
666   else
667   {
668     if (!DeleteItem(pItem.get()))
669       return;
670
671     CStdString strDeletePath;
672     if (pItem->m_bIsFolder)
673       strDeletePath=pItem->GetVideoInfoTag()->m_strPath;
674     else
675       strDeletePath=pItem->GetVideoInfoTag()->m_strFileNameAndPath;
676
677     if (URIUtils::GetFileName(strDeletePath).Equals("VIDEO_TS.IFO"))
678     {
679       URIUtils::GetDirectory(strDeletePath.Mid(0),strDeletePath);
680       if (strDeletePath.Right(9).Equals("VIDEO_TS/"))
681       {
682         URIUtils::RemoveSlashAtEnd(strDeletePath);
683         URIUtils::GetDirectory(strDeletePath.Mid(0),strDeletePath);
684       }
685     }
686     if (URIUtils::HasSlashAtEnd(strDeletePath))
687       pItem->m_bIsFolder=true;
688
689     if (g_guiSettings.GetBool("filelists.allowfiledeletion") &&
690         CUtil::SupportsFileOperations(strDeletePath))
691     {
692       pItem->m_strPath = strDeletePath;
693       CGUIWindowVideoBase::OnDeleteItem(pItem);
694     }
695   }
696
697   CUtil::DeleteVideoDatabaseDirectoryCache();
698 }
699
700 bool CGUIWindowVideoNav::DeleteItem(CFileItem* pItem, bool bUnavailable /* = false */)
701 {
702   if (!pItem->HasVideoInfoTag() || !CanDelete(pItem->m_strPath))
703     return false;
704
705   VIDEODB_CONTENT_TYPE iType=VIDEODB_CONTENT_MOVIES;
706   if (pItem->HasVideoInfoTag() && !pItem->GetVideoInfoTag()->m_strShowTitle.IsEmpty())
707     iType = VIDEODB_CONTENT_TVSHOWS;
708   if (pItem->HasVideoInfoTag() && pItem->GetVideoInfoTag()->m_iSeason > -1 && !pItem->m_bIsFolder)
709     iType = VIDEODB_CONTENT_EPISODES;
710   if (pItem->HasVideoInfoTag() && !pItem->GetVideoInfoTag()->m_strArtist.IsEmpty())
711     iType = VIDEODB_CONTENT_MUSICVIDEOS;
712
713   // dont allow update while scanning
714   CGUIDialogVideoScan* pDialogScan = (CGUIDialogVideoScan*)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_SCAN);
715   if (pDialogScan && pDialogScan->IsScanning())
716   {
717     CGUIDialogOK::ShowAndGetInput(257, 0, 14057, 0);
718     return false;
719   }
720
721
722   CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
723   if (!pDialog)
724     return false;
725   if (iType == VIDEODB_CONTENT_MOVIES)
726     pDialog->SetHeading(432);
727   if (iType == VIDEODB_CONTENT_EPISODES)
728     pDialog->SetHeading(20362);
729   if (iType == VIDEODB_CONTENT_TVSHOWS)
730     pDialog->SetHeading(20363);
731   if (iType == VIDEODB_CONTENT_MUSICVIDEOS)
732     pDialog->SetHeading(20392);
733
734   if(bUnavailable)
735   {
736     pDialog->SetLine(0, g_localizeStrings.Get(662));
737     pDialog->SetLine(1, g_localizeStrings.Get(663));
738     pDialog->SetLine(2, "");;
739     pDialog->DoModal();
740   }
741   else
742   {
743     CStdString strLine;
744     strLine.Format(g_localizeStrings.Get(433),pItem->GetLabel());
745     pDialog->SetLine(0, strLine);
746     pDialog->SetLine(1, "");
747     pDialog->SetLine(2, "");;
748     pDialog->DoModal();
749   }
750
751   if (!pDialog->IsConfirmed())
752     return false;
753
754   CStdString path;
755   CVideoDatabase database;
756   database.Open();
757
758   database.GetFilePathById(pItem->GetVideoInfoTag()->m_iDbId, path, iType);
759   if (path.IsEmpty())
760     return false;
761   if (iType == VIDEODB_CONTENT_MOVIES)
762     database.DeleteMovie(path);
763   if (iType == VIDEODB_CONTENT_EPISODES)
764     database.DeleteEpisode(path, pItem->GetVideoInfoTag()->m_iDbId);
765   if (iType == VIDEODB_CONTENT_TVSHOWS)
766     database.DeleteTvShow(path);
767   if (iType == VIDEODB_CONTENT_MUSICVIDEOS)
768     database.DeleteMusicVideo(path);
769
770   if (iType == VIDEODB_CONTENT_TVSHOWS)
771     database.SetPathHash(path,"");
772   else
773   {
774     CStdString strDirectory;
775     URIUtils::GetDirectory(path,strDirectory);
776     database.SetPathHash(strDirectory,"");
777   }
778
779   return true;
780 }
781
782 void CGUIWindowVideoNav::OnPrepareFileItems(CFileItemList &items)
783 {
784   CGUIWindowVideoBase::OnPrepareFileItems(items);
785
786   // set fanart
787   CQueryParams params;
788   CVideoDatabaseDirectory dir;
789   dir.GetQueryParams(items.m_strPath,params);
790   if (params.GetContentType() == VIDEODB_CONTENT_MUSICVIDEOS)
791     CGUIWindowMusicNav::SetupFanart(items);
792
793   NODE_TYPE node = dir.GetDirectoryChildType(items.m_strPath);
794
795   // now filter as necessary
796   bool filterWatched=false;
797   if (node == NODE_TYPE_EPISODES
798   ||  node == NODE_TYPE_SEASONS
799   ||  node == NODE_TYPE_TITLE_MOVIES
800   ||  node == NODE_TYPE_TITLE_TVSHOWS
801   ||  node == NODE_TYPE_TITLE_MUSICVIDEOS
802   ||  node == NODE_TYPE_RECENTLY_ADDED_EPISODES
803   ||  node == NODE_TYPE_RECENTLY_ADDED_MOVIES
804   ||  node == NODE_TYPE_RECENTLY_ADDED_MUSICVIDEOS)
805     filterWatched = true;
806   if (!items.IsVideoDb())
807     filterWatched = true;
808   if (items.IsSmartPlayList() && items.GetContent() == "tvshows")
809     node = NODE_TYPE_TITLE_TVSHOWS; // so that the check below works
810
811   int watchMode = g_settings.GetWatchMode(m_vecItems->GetContent());
812
813   for (int i = 0; i < items.Size(); i++)
814   {
815     CFileItemPtr item = items.Get(i);
816     if(item->HasVideoInfoTag() && (node == NODE_TYPE_TITLE_TVSHOWS || node == NODE_TYPE_SEASONS))
817     {
818       if (watchMode == VIDEO_SHOW_UNWATCHED)
819         item->GetVideoInfoTag()->m_iEpisode = item->GetPropertyInt("unwatchedepisodes");
820       if (watchMode == VIDEO_SHOW_WATCHED)
821         item->GetVideoInfoTag()->m_iEpisode = item->GetPropertyInt("watchedepisodes");
822       item->SetProperty("numepisodes", item->GetVideoInfoTag()->m_iEpisode);
823     }
824
825     if(filterWatched)
826     {
827       if((watchMode==VIDEO_SHOW_WATCHED   && item->GetVideoInfoTag()->m_playCount== 0)
828       || (watchMode==VIDEO_SHOW_UNWATCHED && item->GetVideoInfoTag()->m_playCount > 0))
829       {
830         items.Remove(i);
831         i--;
832       }
833     }
834   }
835 }
836
837 void CGUIWindowVideoNav::GetContextButtons(int itemNumber, CContextButtons &buttons)
838 {
839   CFileItemPtr item;
840   if (itemNumber >= 0 && itemNumber < m_vecItems->Size())
841     item = m_vecItems->Get(itemNumber);
842
843   CGUIWindowVideoBase::GetContextButtons(itemNumber, buttons);
844
845   if (item && item->GetPropertyBOOL("pluginreplacecontextitems"))
846     return;
847
848   CVideoDatabaseDirectory dir;
849   NODE_TYPE node = dir.GetDirectoryChildType(m_vecItems->m_strPath);
850
851   if (!item)
852   {
853     CGUIDialogVideoScan *pScanDlg = (CGUIDialogVideoScan *)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_SCAN);
854     if (pScanDlg && pScanDlg->IsScanning())
855       buttons.Add(CONTEXT_BUTTON_STOP_SCANNING, 13353);
856     else
857       buttons.Add(CONTEXT_BUTTON_UPDATE_LIBRARY, 653);
858   }
859   else if (m_vecItems->m_strPath.Equals("sources://video/"))
860   {
861     // get the usual shares
862     CGUIDialogContextMenu::GetContextButtons("video", item, buttons);
863     // add scan button somewhere here
864     CGUIDialogVideoScan *pScanDlg = (CGUIDialogVideoScan *)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_SCAN);
865     if (pScanDlg && pScanDlg->IsScanning())
866       buttons.Add(CONTEXT_BUTTON_STOP_SCANNING, 13353);  // Stop Scanning
867     if (!item->IsDVD() && item->m_strPath != "add" &&
868         (g_settings.GetCurrentProfile().canWriteDatabases() || g_passwordManager.bMasterUser))
869     {
870       CVideoDatabase database;
871       database.Open();
872       ADDON::ScraperPtr info = database.GetScraperForPath(item->m_strPath);
873
874       if (!pScanDlg || (pScanDlg && !pScanDlg->IsScanning()))
875       {
876         if (!item->IsLiveTV() && !item->IsPlugin() && !item->IsAddonsPath())
877         {
878           if (info && info->Content() != CONTENT_NONE)
879             buttons.Add(CONTEXT_BUTTON_SET_CONTENT, 20442);
880           else
881             buttons.Add(CONTEXT_BUTTON_SET_CONTENT, 20333);
882         }
883       }
884
885       if (info && (!pScanDlg || (pScanDlg && !pScanDlg->IsScanning())))
886         buttons.Add(CONTEXT_BUTTON_SCAN, 13349);
887     }
888   }
889   else
890   {
891     ADDON::ScraperPtr info;
892     VIDEO::SScanSettings settings;
893     GetScraperForItem(item.get(), info, settings);
894
895     if (info && info->Content() == CONTENT_TVSHOWS)
896       buttons.Add(CONTEXT_BUTTON_INFO, item->m_bIsFolder ? 20351 : 20352);
897     else if (info && info->Content() == CONTENT_MUSICVIDEOS)
898       buttons.Add(CONTEXT_BUTTON_INFO,20393);
899     else if (!item->m_bIsFolder && !item->m_strPath.Left(19).Equals("newsmartplaylist://"))
900       buttons.Add(CONTEXT_BUTTON_INFO, 13346);
901
902     if (item->HasVideoInfoTag() && !item->GetVideoInfoTag()->m_strArtist.IsEmpty())
903     {
904       CMusicDatabase database;
905       database.Open();
906       if (database.GetArtistByName(item->GetVideoInfoTag()->m_strArtist) > -1)
907         buttons.Add(CONTEXT_BUTTON_GO_TO_ARTIST, 20396);
908     }
909     if (item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_strAlbum.size() > 0)
910     {
911       CMusicDatabase database;
912       database.Open();
913       if (database.GetAlbumByName(item->GetVideoInfoTag()->m_strAlbum) > -1)
914         buttons.Add(CONTEXT_BUTTON_GO_TO_ALBUM, 20397);
915     }
916     if (item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_strAlbum.size() > 0 &&
917         item->GetVideoInfoTag()->m_strArtist.size() > 0                           &&
918         item->GetVideoInfoTag()->m_strTitle.size() > 0)
919     {
920       CMusicDatabase database;
921       database.Open();
922       if (database.GetSongByArtistAndAlbumAndTitle(item->GetVideoInfoTag()->m_strArtist,
923                                                    item->GetVideoInfoTag()->m_strAlbum,
924                                                    item->GetVideoInfoTag()->m_strTitle) > -1)
925       {
926         buttons.Add(CONTEXT_BUTTON_PLAY_OTHER, 20398);
927       }
928     }
929     if (!item->IsParentFolder())
930     {
931       // can we update the database?
932       if (g_settings.GetCurrentProfile().canWriteDatabases() || g_passwordManager.bMasterUser)
933       {
934         if (node == NODE_TYPE_TITLE_TVSHOWS)
935         {
936           CGUIDialogVideoScan *pScanDlg = (CGUIDialogVideoScan *)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_SCAN);
937           if (pScanDlg && pScanDlg->IsScanning())
938             buttons.Add(CONTEXT_BUTTON_STOP_SCANNING, 13353);
939           else
940             buttons.Add(CONTEXT_BUTTON_UPDATE_TVSHOW, 13349);
941         }
942         if (!item->IsPlugin() && !item->IsLiveTV() && !item->IsAddonsPath() &&
943              item->m_strPath != "sources://video/" && item->m_strPath != "special://videoplaylists/")
944         {
945           if (item->m_bIsFolder)
946           {
947             // Have both options for folders since we don't know whether all childs are watched/unwatched
948             buttons.Add(CONTEXT_BUTTON_MARK_UNWATCHED, 16104); //Mark as UnWatched
949             buttons.Add(CONTEXT_BUTTON_MARK_WATCHED, 16103);   //Mark as Watched
950           }
951           else
952           {
953             if (item->GetOverlayImage().Equals("OverlayWatched.png"))
954               buttons.Add(CONTEXT_BUTTON_MARK_UNWATCHED, 16104); //Mark as UnWatched
955             else
956               buttons.Add(CONTEXT_BUTTON_MARK_WATCHED, 16103);   //Mark as Watched
957           }
958         }
959         if ((node == NODE_TYPE_TITLE_TVSHOWS) ||
960             (item->IsVideoDb() && item->HasVideoInfoTag() && !item->m_bIsFolder))
961         {
962           buttons.Add(CONTEXT_BUTTON_EDIT, 16105); //Edit Title
963         }
964         if (m_database.HasContent(VIDEODB_CONTENT_TVSHOWS) && item->HasVideoInfoTag() &&
965            !item->m_bIsFolder && item->GetVideoInfoTag()->m_iEpisode == -1 &&
966             item->GetVideoInfoTag()->m_strArtist.IsEmpty() && item->GetVideoInfoTag()->m_iDbId >= 0) // movie entry
967         {
968           if (m_database.IsLinkedToTvshow(item->GetVideoInfoTag()->m_iDbId))
969             buttons.Add(CONTEXT_BUTTON_UNLINK_MOVIE,20385);
970           buttons.Add(CONTEXT_BUTTON_LINK_MOVIE,20384);
971         }
972
973         if (node == NODE_TYPE_SEASONS && item->m_bIsFolder)
974           buttons.Add(CONTEXT_BUTTON_SET_SEASON_THUMB, 20371);
975
976         if (item->m_strPath.Left(14).Equals("videodb://1/7/") && item->m_strPath.size() > 14 && item->m_bIsFolder) // sets
977         {
978           buttons.Add(CONTEXT_BUTTON_EDIT, 16105);
979           buttons.Add(CONTEXT_BUTTON_SET_MOVIESET_THUMB, 20435);
980           buttons.Add(CONTEXT_BUTTON_DELETE, 646);
981         }
982
983         if (node == NODE_TYPE_ACTOR && !dir.IsAllItem(item->m_strPath) && item->m_bIsFolder)
984         {
985           if (m_vecItems->m_strPath.Left(11).Equals("videodb://3")) // mvids
986             buttons.Add(CONTEXT_BUTTON_SET_ARTIST_THUMB, 13359);
987           else
988             buttons.Add(CONTEXT_BUTTON_SET_ACTOR_THUMB, 20403);
989         }
990         if (item->IsVideoDb() && item->HasVideoInfoTag() &&
991           (!item->m_bIsFolder || node == NODE_TYPE_TITLE_TVSHOWS))
992         {
993           if (info && info->Content() == CONTENT_TVSHOWS)
994           {
995             if(item->GetVideoInfoTag()->m_iBookmarkId != -1 &&
996                item->GetVideoInfoTag()->m_iBookmarkId != 0)
997             {
998               buttons.Add(CONTEXT_BUTTON_UNLINK_BOOKMARK, 20405);
999             }
1000           }
1001           buttons.Add(CONTEXT_BUTTON_DELETE, 646);
1002         }
1003
1004         // this should ideally be non-contextual (though we need some context for non-tv show node I guess)
1005         CGUIDialogVideoScan *pScanDlg = (CGUIDialogVideoScan *)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_SCAN);
1006         if (pScanDlg && pScanDlg->IsScanning())
1007         {
1008           if (node != NODE_TYPE_TITLE_TVSHOWS)
1009             buttons.Add(CONTEXT_BUTTON_STOP_SCANNING, 13353);
1010         }
1011         else
1012           buttons.Add(CONTEXT_BUTTON_UPDATE_LIBRARY, 653);
1013       }
1014
1015       if (!m_vecItems->IsVideoDb() && !m_vecItems->IsVirtualDirectoryRoot())
1016       { // non-video db items, file operations are allowed
1017         if (g_guiSettings.GetBool("filelists.allowfiledeletion") &&
1018             CUtil::SupportsFileOperations(item->m_strPath))
1019         {
1020           buttons.Add(CONTEXT_BUTTON_DELETE, 117);
1021           buttons.Add(CONTEXT_BUTTON_RENAME, 118);
1022         }
1023         // add "Set/Change content" to folders
1024         if (item->m_bIsFolder && !item->IsPlayList() && !item->IsLiveTV() && !item->IsPlugin() && !item->IsAddonsPath())
1025         {
1026           CGUIDialogVideoScan *pScanDlg = (CGUIDialogVideoScan *)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_SCAN);
1027           if (!pScanDlg || (pScanDlg && !pScanDlg->IsScanning()))
1028           {
1029             if (info && info->Content() != CONTENT_NONE)
1030               buttons.Add(CONTEXT_BUTTON_SET_CONTENT, 20442);
1031             else
1032               buttons.Add(CONTEXT_BUTTON_SET_CONTENT, 20333);
1033           }
1034         }
1035       }
1036       if (item->IsPlugin() || item->m_strPath.Left(9).Equals("script://") || m_vecItems->IsPlugin())
1037         buttons.Add(CONTEXT_BUTTON_PLUGIN_SETTINGS, 1045);
1038     }
1039   }
1040   CGUIWindowVideoBase::GetNonContextButtons(itemNumber, buttons);
1041 }
1042
1043 bool CGUIWindowVideoNav::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
1044 {
1045   CFileItemPtr item;
1046   if (itemNumber >= 0 && itemNumber < m_vecItems->Size())
1047     item = m_vecItems->Get(itemNumber);
1048   if (CGUIDialogContextMenu::OnContextButton("video", item, button))
1049   {
1050     //TODO should we search DB for entries from plugins?
1051     if (button == CONTEXT_BUTTON_REMOVE_SOURCE && !item->IsPlugin()
1052         && !item->IsLiveTV() &&!item->IsRSS())
1053     {
1054       OnUnAssignContent(item->m_strPath,20375,20340,20341);
1055     }
1056     Update(m_vecItems->m_strPath);
1057     return true;
1058   }
1059   switch (button)
1060   {
1061   case CONTEXT_BUTTON_EDIT:
1062     UpdateVideoTitle(item.get());
1063     CUtil::DeleteVideoDatabaseDirectoryCache();
1064     Update(m_vecItems->m_strPath);
1065     return true;
1066
1067   case CONTEXT_BUTTON_SET_SEASON_THUMB:
1068   case CONTEXT_BUTTON_SET_ACTOR_THUMB:
1069   case CONTEXT_BUTTON_SET_ARTIST_THUMB:
1070   case CONTEXT_BUTTON_SET_MOVIESET_THUMB:
1071     {
1072       // Grab the thumbnails from the web
1073       CStdString strPath;
1074       CFileItemList items;
1075       URIUtils::AddFileToFolder(g_advancedSettings.m_cachePath,"imdbthumbs",strPath);
1076       CFileItemPtr cacheItem(new CFileItem(strPath,true));
1077       CFileUtils::DeleteItem(cacheItem,true);
1078       XFILE::CDirectory::Create(strPath);
1079       CFileItemPtr noneitem(new CFileItem("thumb://None", false));
1080       CStdString cachedThumb = m_vecItems->Get(itemNumber)->GetCachedSeasonThumb();
1081       if (button == CONTEXT_BUTTON_SET_ACTOR_THUMB)
1082         cachedThumb = m_vecItems->Get(itemNumber)->GetCachedActorThumb();
1083       if (button == CONTEXT_BUTTON_SET_ARTIST_THUMB)
1084         cachedThumb = m_vecItems->Get(itemNumber)->GetCachedArtistThumb();
1085       if (button == CONTEXT_BUTTON_SET_MOVIESET_THUMB)
1086         cachedThumb = m_vecItems->Get(itemNumber)->GetCachedVideoThumb();
1087       if (CFile::Exists(cachedThumb))
1088       {
1089         CFileItemPtr item(new CFileItem("thumb://Current", false));
1090         item->SetThumbnailImage(cachedThumb);
1091         item->SetLabel(g_localizeStrings.Get(20016));
1092         items.Add(item);
1093       }
1094       noneitem->SetIconImage("DefaultFolder.png");
1095       noneitem->SetLabel(g_localizeStrings.Get(20018));
1096
1097       vector<CStdString> thumbs;
1098       if (button != CONTEXT_BUTTON_SET_ARTIST_THUMB)
1099       {
1100         CVideoInfoTag tag;
1101         if (button == CONTEXT_BUTTON_SET_SEASON_THUMB)
1102           m_database.GetTvShowInfo("",tag,m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_iDbId);
1103         else
1104           tag = *m_vecItems->Get(itemNumber)->GetVideoInfoTag();
1105         if (button == CONTEXT_BUTTON_SET_SEASON_THUMB)
1106           tag.m_strPictureURL.GetThumbURLs(thumbs, m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_iSeason);
1107         else
1108           tag.m_strPictureURL.GetThumbURLs(thumbs);
1109
1110         for (unsigned int i = 0; i < thumbs.size(); i++)
1111         {
1112           CStdString strItemPath;
1113           strItemPath.Format("thumb://Remote%i",i);
1114           CFileItemPtr item(new CFileItem(strItemPath, false));
1115           item->SetThumbnailImage(thumbs[i]);
1116           item->SetIconImage("DefaultPicture.png");
1117           item->SetLabel(g_localizeStrings.Get(20015));
1118           items.Add(item);
1119
1120           // TODO: Do we need to clear the cached image?
1121           //    CTextureCache::Get().ClearCachedImage(thumbs[i]);
1122         }
1123       }
1124
1125       bool local=false;
1126       if (button == CONTEXT_BUTTON_SET_ARTIST_THUMB)
1127       {
1128         CStdString picturePath;
1129
1130         CStdString strPath = m_vecItems->Get(itemNumber)->m_strPath;
1131         URIUtils::RemoveSlashAtEnd(strPath);
1132
1133         int nPos=strPath.ReverseFind("/");
1134         if (nPos>-1)
1135         {
1136           //  try to guess where the user should start
1137           //  browsing for the artist thumb
1138           CMusicDatabase database;
1139           database.Open();
1140           long idArtist=database.GetArtistByName(m_vecItems->Get(itemNumber)->GetLabel());
1141           database.GetArtistPath(idArtist, picturePath);
1142         }
1143
1144         CStdString strThumb;
1145         URIUtils::AddFileToFolder(picturePath,"folder.jpg",strThumb);
1146         if (XFILE::CFile::Exists(strThumb))
1147         {
1148           CFileItemPtr pItem(new CFileItem(strThumb,false));
1149           pItem->SetLabel(g_localizeStrings.Get(20017));
1150           pItem->SetThumbnailImage(strThumb);
1151           items.Add(pItem);
1152           local = true;
1153         }
1154         else
1155           noneitem->SetIconImage("DefaultArtist.png");
1156       }
1157
1158       if (button == CONTEXT_BUTTON_SET_ACTOR_THUMB)
1159       {
1160         CStdString picturePath;
1161         CStdString strThumb;
1162         URIUtils::AddFileToFolder(picturePath,"folder.jpg",strThumb);
1163         if (XFILE::CFile::Exists(strThumb))
1164         {
1165           CFileItemPtr pItem(new CFileItem(strThumb,false));
1166           pItem->SetLabel(g_localizeStrings.Get(20017));
1167           pItem->SetThumbnailImage(strThumb);
1168           items.Add(pItem);
1169           local = true;
1170         }
1171         else
1172           noneitem->SetIconImage("DefaultActor.png");
1173       }
1174
1175       if (button == CONTEXT_BUTTON_SET_MOVIESET_THUMB)
1176         noneitem->SetIconImage("DefaultVideo.png");
1177
1178       if (!local)
1179         items.Add(noneitem);
1180
1181       VECSOURCES sources=g_settings.m_videoSources;
1182       g_mediaManager.GetLocalDrives(sources);
1183       CStdString result;
1184       if (!CGUIDialogFileBrowser::ShowAndGetImage(items, sources,
1185                                                   g_localizeStrings.Get(20019), result))
1186       {
1187         return false;   // user cancelled
1188       }
1189
1190       if (result == "thumb://Current")
1191         return false;   // user chose the one they have
1192
1193       // delete the thumbnail if that's what the user wants, else overwrite with the
1194       // new thumbnail
1195       CTextureCache::Get().ClearCachedImage(cachedThumb, true);
1196       if (result.Left(14) == "thumb://Remote")
1197       {
1198         int number = atoi(result.Mid(14));
1199         CFile::Cache(thumbs[number], cachedThumb);
1200       }
1201       if (result == "thumb://None")
1202         CTextureCache::Get().ClearCachedImage(cachedThumb, true);
1203       else
1204         CFile::Cache(result,cachedThumb);
1205
1206       CUtil::DeleteVideoDatabaseDirectoryCache();
1207       CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_REFRESH_THUMBS);
1208       g_windowManager.SendMessage(msg);
1209       Update(m_vecItems->m_strPath);
1210
1211       return true;
1212     }
1213   case CONTEXT_BUTTON_UPDATE_LIBRARY:
1214     {
1215       OnScan("");
1216       return true;
1217     }
1218   case CONTEXT_BUTTON_UNLINK_MOVIE:
1219     {
1220       OnLinkMovieToTvShow(itemNumber, true);
1221       Update(m_vecItems->m_strPath);
1222       return true;
1223     }
1224   case CONTEXT_BUTTON_LINK_MOVIE:
1225     {
1226       OnLinkMovieToTvShow(itemNumber, false);
1227       return true;
1228     }
1229   case CONTEXT_BUTTON_GO_TO_ARTIST:
1230     {
1231       CStdString strPath;
1232       CMusicDatabase database;
1233       database.Open();
1234       strPath.Format("musicdb://2/%ld/",database.GetArtistByName(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strArtist));
1235       g_windowManager.ActivateWindow(WINDOW_MUSIC_NAV,strPath);
1236       return true;
1237     }
1238   case CONTEXT_BUTTON_GO_TO_ALBUM:
1239     {
1240       CStdString strPath;
1241       CMusicDatabase database;
1242       database.Open();
1243       strPath.Format("musicdb://3/%ld/",database.GetAlbumByName(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strAlbum));
1244       g_windowManager.ActivateWindow(WINDOW_MUSIC_NAV,strPath);
1245       return true;
1246     }
1247   case CONTEXT_BUTTON_PLAY_OTHER:
1248     {
1249       CMusicDatabase database;
1250       database.Open();
1251       CSong song;
1252       if (database.GetSongById(database.GetSongByArtistAndAlbumAndTitle(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strArtist,m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strAlbum,
1253                                                                         m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strTitle),
1254                                                                         song))
1255       {
1256         g_application.getApplicationMessenger().PlayFile(song);
1257       }
1258       return true;
1259     }
1260
1261   case CONTEXT_BUTTON_UNLINK_BOOKMARK:
1262     {
1263       m_database.Open();
1264       m_database.DeleteBookMarkForEpisode(*m_vecItems->Get(itemNumber)->GetVideoInfoTag());
1265       m_database.Close();
1266       CUtil::DeleteVideoDatabaseDirectoryCache();
1267       Update(m_vecItems->m_strPath);
1268       return true;
1269     }
1270
1271   default:
1272     break;
1273
1274   }
1275   return CGUIWindowVideoBase::OnContextButton(itemNumber, button);
1276 }
1277
1278 void CGUIWindowVideoNav::OnLinkMovieToTvShow(int itemnumber, bool bRemove)
1279 {
1280   CFileItemList list;
1281   if (bRemove)
1282   {
1283     vector<int> ids;
1284     if (!m_database.GetLinksToTvShow(m_vecItems->Get(itemnumber)->GetVideoInfoTag()->m_iDbId,ids))
1285       return;
1286     for (unsigned int i=0;i<ids.size();++i)
1287     {
1288       CVideoInfoTag tag;
1289       m_database.GetTvShowInfo("",tag,ids[i]);
1290       CFileItemPtr show(new CFileItem(tag));
1291       list.Add(show);
1292     }
1293   }
1294   else
1295   {
1296     m_database.GetTvShowsNav("videodb://2/2",list);
1297
1298     // remove already linked shows
1299     vector<int> ids;
1300     if (!m_database.GetLinksToTvShow(m_vecItems->Get(itemnumber)->GetVideoInfoTag()->m_iDbId,ids))
1301       return;
1302     for (int i=0;i<list.Size();)
1303     {
1304       unsigned int j;
1305       for (j=0;j<ids.size();++j)
1306       {
1307         if (list[i]->GetVideoInfoTag()->m_iDbId == ids[j])
1308           break;
1309       }
1310       if (j == ids.size())
1311         i++;
1312       else
1313         list.Remove(i);
1314     }
1315   }
1316   int iSelectedLabel = 0;
1317   if (list.Size() > 1)
1318   {
1319     list.Sort(g_guiSettings.GetBool("filelists.ignorethewhensorting") ? SORT_METHOD_LABEL_IGNORE_THE : SORT_METHOD_LABEL, SORT_ORDER_ASC);
1320     CGUIDialogSelect* pDialog = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
1321     pDialog->Reset();
1322     pDialog->SetItems(&list);
1323     pDialog->SetHeading(20356);
1324     pDialog->DoModal();
1325     iSelectedLabel = pDialog->GetSelectedLabel();
1326   }
1327   if (iSelectedLabel > -1)
1328   {
1329     m_database.LinkMovieToTvshow(m_vecItems->Get(itemnumber)->GetVideoInfoTag()->m_iDbId,
1330                                  list[iSelectedLabel]->GetVideoInfoTag()->m_iDbId, bRemove);
1331     CUtil::DeleteVideoDatabaseDirectoryCache();
1332   }
1333 }
1334
1335 bool CGUIWindowVideoNav::OnClick(int iItem)
1336 {
1337   CFileItemPtr item = m_vecItems->Get(iItem);
1338   if (!item->m_bIsFolder && item->IsVideoDb() && !item->Exists())
1339   {
1340     if (!DeleteItem(item.get(), true))
1341       return true;
1342
1343     // update list
1344     m_vecItems->RemoveDiscCache(GetID());
1345     Update(m_vecItems->m_strPath);
1346     m_viewControl.SetSelectedItem(iItem);
1347     return true;
1348   }
1349
1350   return CGUIWindowVideoBase::OnClick(iItem);
1351 }
1352
1353 CStdString CGUIWindowVideoNav::GetStartFolder(const CStdString &dir)
1354 {
1355   if (dir.Equals("MovieGenres"))
1356     return "videodb://1/1/";
1357   else if (dir.Equals("MovieTitles"))
1358     return "videodb://1/2/";
1359   else if (dir.Equals("MovieYears"))
1360     return "videodb://1/3/";
1361   else if (dir.Equals("MovieActors"))
1362     return "videodb://1/4/";
1363   else if (dir.Equals("MovieDirectors"))
1364     return "videodb://1/5/";
1365   else if (dir.Equals("MovieStudios"))
1366     return "videodb://1/6/";
1367   else if (dir.Equals("MovieSets"))
1368     return "videodb://1/7/";
1369   else if (dir.Equals("MovieCountries"))
1370     return "videodb://1/8/";
1371   else if (dir.Equals("Movies"))
1372     return "videodb://1/";
1373   else if (dir.Equals("TvShowGenres"))
1374     return "videodb://2/1/";
1375   else if (dir.Equals("TvShowTitles"))
1376     return "videodb://2/2/";
1377   else if (dir.Equals("TvShowYears"))
1378     return "videodb://2/3/";
1379   else if (dir.Equals("TvShowActors"))
1380     return "videodb://2/4/";
1381   else if (dir.Equals("TvShowStudios"))
1382     return "videodb://2/5/";
1383   else if (dir.Equals("TvShows"))
1384     return "videodb://2/";
1385   else if (dir.Equals("MusicVideoGenres"))
1386     return "videodb://3/1/";
1387   else if (dir.Equals("MusicVideoTitles"))
1388     return "videodb://3/2/";
1389   else if (dir.Equals("MusicVideoYears"))
1390     return "videodb://3/3/";
1391   else if (dir.Equals("MusicVideoArtists"))
1392     return "videodb://3/4/";
1393   else if (dir.Equals("MusicVideoDirectors"))
1394     return "videodb://3/5/";
1395   else if (dir.Equals("MusicVideoStudios"))
1396     return "videodb://3/6/";
1397   else if (dir.Equals("MusicVideos"))
1398     return "videodb://3/";
1399   else if (dir.Equals("RecentlyAddedMovies"))
1400     return "videodb://4/";
1401   else if (dir.Equals("RecentlyAddedEpisodes"))
1402     return "videodb://5/";
1403   else if (dir.Equals("RecentlyAddedMusicVideos"))
1404     return "videodb://6/";
1405   else if (dir.Equals("Files"))
1406     return "sources://video/";
1407   return CGUIWindowVideoBase::GetStartFolder(dir);
1408 }