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