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