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