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