changed: Mayaswell allow filtering of the overview lists in the video library as...
[xbmc:xbmc-antiquated.git] / xbmc / 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 "GUIWindowVideoFiles.h"
25 #include "GUIWindowMusicNav.h"
26 #include "utils/FileUtils.h"
27 #include "utils/GUIInfoManager.h"
28 #include "Util.h"
29 #include "utils/RegExp.h"
30 #include "PlayListM3U.h"
31 #include "PlayListPlayer.h"
32 #include "GUIPassword.h"
33 #include "GUIDialogFileBrowser.h"
34 #include "Picture.h"
35 #include "FileSystem/VideoDatabaseDirectory.h"
36 #include "PlayListFactory.h"
37 #include "GUIDialogVideoScan.h"
38 #include "GUIDialogOK.h"
39 #include "PartyModeManager.h"
40 #include "MusicDatabase.h"
41 #include "GUIWindowManager.h"
42 #include "GUIDialogYesNo.h"
43 #include "GUIDialogSelect.h"
44 #include "FileSystem/Directory.h"
45 #include "FileSystem/File.h"
46 #include "FileItem.h"
47 #include "Application.h"
48 #include "Settings.h"
49 #include "AdvancedSettings.h"
50 #include "GUISettings.h"
51 #include "LocalizeStrings.h"
52 #include "StringUtils.h"
53 #include "MediaManager.h"
54 #include "utils/log.h"
55
56 using namespace XFILE;
57 using namespace VIDEODATABASEDIRECTORY;
58 using namespace std;
59
60 #define CONTROL_BTNVIEWASICONS     2
61 #define CONTROL_BTNSORTBY          3
62 #define CONTROL_BTNSORTASC         4
63 #define CONTROL_BTNTYPE            5
64 #define CONTROL_BTNSEARCH          8
65 #define CONTROL_LABELFILES        12
66
67 #define CONTROL_BTN_FILTER        19
68 #define CONTROL_BTNSHOWMODE       10
69 #define CONTROL_BTNSHOWALL        14
70 #define CONTROL_UNLOCK            11
71
72 #define CONTROL_FILTER            15
73 #define CONTROL_BTNPARTYMODE      16
74 #define CONTROL_BTNFLATTEN        17
75 #define CONTROL_LABELEMPTY        18
76
77 CGUIWindowVideoNav::CGUIWindowVideoNav(void)
78     : CGUIWindowVideoBase(WINDOW_VIDEO_NAV, "MyVideoNav.xml")
79 {
80   m_vecItems->m_strPath = "?";
81   m_bDisplayEmptyDatabaseMessage = false;
82   m_thumbLoader.SetObserver(this);
83 }
84
85 CGUIWindowVideoNav::~CGUIWindowVideoNav(void)
86 {
87 }
88
89 bool CGUIWindowVideoNav::OnAction(const CAction &action)
90 {
91   if (action.GetID() == ACTION_PARENT_DIR)
92   {
93     if (g_advancedSettings.m_bUseEvilB &&
94         m_vecItems->m_strPath == m_startDirectory)
95     {
96       g_windowManager.PreviousWindow();
97       return true;
98     }
99   }
100   if (action.GetID() == ACTION_TOGGLE_WATCHED)
101   {
102     CFileItemPtr pItem = m_vecItems->Get(m_viewControl.GetSelectedItem());
103     if (pItem && pItem->GetVideoInfoTag()->m_playCount == 0)
104       return OnContextButton(m_viewControl.GetSelectedItem(),CONTEXT_BUTTON_MARK_WATCHED);
105     if (pItem && pItem->GetVideoInfoTag()->m_playCount > 0)
106       return OnContextButton(m_viewControl.GetSelectedItem(),CONTEXT_BUTTON_MARK_UNWATCHED);
107   }
108   return CGUIWindowVideoBase::OnAction(action);
109 }
110
111 bool CGUIWindowVideoNav::OnMessage(CGUIMessage& message)
112 {
113   switch (message.GetMessage())
114   {
115   case GUI_MSG_WINDOW_RESET:
116     m_vecItems->m_strPath = "?";
117     break;
118   case GUI_MSG_WINDOW_DEINIT:
119     if (m_thumbLoader.IsLoading())
120       m_thumbLoader.StopThread();
121     break;
122   case GUI_MSG_WINDOW_INIT:
123     {
124       /* We don't want to show Autosourced items (ie removable pendrives, memorycards) in Library mode */
125       m_rootDir.AllowNonLocalSources(false);
126       // check for valid quickpath parameter
127       CStdString strDestination = message.GetNumStringParams() ? message.GetStringParam(0) : "";
128       CStdString strReturn = message.GetNumStringParams() > 1 ? message.GetStringParam(1) : "";
129       bool returning = strReturn.CompareNoCase("return") == 0;
130
131       if (!strDestination.IsEmpty())
132       {
133         message.SetStringParam("");
134         CLog::Log(LOGINFO, "Attempting to %s to: %s", returning ? "return" : "quickpath", strDestination.c_str());
135       }
136
137       // is this the first time the window is opened?
138       if (m_vecItems->m_strPath == "?" && strDestination.IsEmpty())
139       {
140         strDestination = g_settings.m_defaultVideoLibSource;
141         m_vecItems->m_strPath = strDestination;
142         CLog::Log(LOGINFO, "Attempting to default to: %s", strDestination.c_str());
143       }
144
145       CStdString destPath;
146       if (!strDestination.IsEmpty())
147       {
148         if (strDestination.Equals("$ROOT") || strDestination.Equals("Root"))
149           destPath = "";
150         else if (strDestination.Equals("MovieGenres"))
151           destPath = "videodb://1/1/";
152         else if (strDestination.Equals("MovieTitles"))
153           destPath = "videodb://1/2/";
154         else if (strDestination.Equals("MovieYears"))
155           destPath = "videodb://1/3/";
156         else if (strDestination.Equals("MovieActors"))
157           destPath = "videodb://1/4/";
158         else if (strDestination.Equals("MovieDirectors"))
159           destPath = "videodb://1/5/";
160         else if (strDestination.Equals("MovieStudios"))
161           destPath = "videodb://1/6/";
162         else if (strDestination.Equals("Movies"))
163           destPath = "videodb://1/";
164         else if (strDestination.Equals("TvShowGenres"))
165           destPath = "videodb://2/1/";
166         else if (strDestination.Equals("TvShowTitles"))
167           destPath = "videodb://2/2/";
168         else if (strDestination.Equals("TvShowYears"))
169           destPath = "videodb://2/3/";
170         else if (strDestination.Equals("TvShowActors"))
171           destPath = "videodb://2/4/";
172         else if (strDestination.Equals("TvShowStudios"))
173           destPath = "videodb://2/5/";
174         else if (strDestination.Equals("TvShows"))
175           destPath = "videodb://2/";
176         else if (strDestination.Equals("MusicVideoGenres"))
177           destPath = "videodb://3/1/";
178         else if (strDestination.Equals("MusicVideoTitles"))
179           destPath = "videodb://3/2/";
180         else if (strDestination.Equals("MusicVideoYears"))
181           destPath = "videodb://3/3/";
182         else if (strDestination.Equals("MusicVideoArtists"))
183           destPath = "videodb://3/4/";
184         else if (strDestination.Equals("MusicVideoDirectors"))
185           destPath = "videodb://3/5/";
186         else if (strDestination.Equals("MusicVideoStudios"))
187           destPath = "videodb://3/6/";
188         else if (strDestination.Equals("MusicVideos"))
189           destPath = "videodb://3/";
190         else if (strDestination.Equals("RecentlyAddedMovies"))
191           destPath = "videodb://4/";
192         else if (strDestination.Equals("RecentlyAddedEpisodes"))
193           destPath = "videodb://5/";
194         else if (strDestination.Equals("RecentlyAddedMusicVideos"))
195           destPath = "videodb://6/";
196         else if (strDestination.Equals("Playlists"))
197           destPath = "special://videoplaylists/";
198         else if (strDestination.Equals("Plugins"))
199           destPath = "plugin://video/";
200         else
201         {
202           CLog::Log(LOGWARNING, "Warning, destination parameter (%s) may not be valid", strDestination.c_str());
203           destPath = strDestination;
204         }
205         if (!returning || m_vecItems->m_strPath.Left(destPath.GetLength()) != destPath)
206         { // we're not returning to the same path, so set our directory to the requested path
207           m_vecItems->m_strPath = destPath;
208         }
209         SetHistoryForPath(m_vecItems->m_strPath);
210       }
211
212       DisplayEmptyDatabaseMessage(false); // reset message state
213
214       SetProperty("flattened", g_settings.m_bMyVideoNavFlatten);
215       
216       if (!CGUIWindowVideoBase::OnMessage(message))
217         return false;
218
219       if (message.GetParam1() != WINDOW_INVALID)
220       { // first time to this window - make sure we set the root path
221         m_startDirectory = returning ? destPath : "";
222       }
223
224       //  base class has opened the database, do our check
225       m_database.Open();
226       DisplayEmptyDatabaseMessage(!m_database.HasContent());
227
228       if (m_bDisplayEmptyDatabaseMessage)
229       {
230         // no library - make sure we focus on a known control, and default to the root.
231         SET_CONTROL_FOCUS(CONTROL_BTNTYPE, 0);
232         m_vecItems->m_strPath = "";
233         SetHistoryForPath("");
234         Update("");
235       }
236
237       m_database.Close();
238       return true;
239     }
240     break;
241
242   case GUI_MSG_CLICKED:
243     {
244       int iControl = message.GetSenderId();
245       if (iControl == CONTROL_BTNPARTYMODE)
246       {
247         if (g_partyModeManager.IsEnabled())
248           g_partyModeManager.Disable();
249         else
250         {
251           if (!g_partyModeManager.Enable(PARTYMODECONTEXT_VIDEO))
252           {
253             SET_CONTROL_SELECTED(GetID(),CONTROL_BTNPARTYMODE,false);
254             return false;
255           }
256
257           // Playlist directory is the root of the playlist window
258           if (m_guiState.get()) m_guiState->SetPlaylistDirectory("playlistvideo://");
259
260           return true;
261         }
262         UpdateButtons();
263       }
264
265       if (iControl == CONTROL_BTNSEARCH)
266       {
267         OnSearch();
268       }
269       else if (iControl == CONTROL_BTNSHOWMODE)
270       {
271         g_settings.m_iMyVideoWatchMode++;
272         if (g_settings.m_iMyVideoWatchMode > VIDEO_SHOW_WATCHED)
273           g_settings.m_iMyVideoWatchMode = VIDEO_SHOW_ALL;
274         g_settings.Save();
275         // TODO: Can we perhaps filter this directly?  Probably not for some of the more complicated views,
276         //       but for those perhaps we can just display them all, and only filter when we get a list
277         //       of actual videos?
278         Update(m_vecItems->m_strPath);
279         return true;
280       }
281       else if (iControl == CONTROL_BTNFLATTEN)
282       {
283         g_settings.m_bMyVideoNavFlatten = !g_settings.m_bMyVideoNavFlatten;
284         g_settings.Save();
285         SetProperty("flattened", g_settings.m_bMyVideoNavFlatten);
286         CUtil::DeleteVideoDatabaseDirectoryCache();
287         SetupShares();
288         Update("");
289         return true;
290       }
291       else if (iControl == CONTROL_BTNSHOWALL)
292       {
293         if (g_settings.m_iMyVideoWatchMode == VIDEO_SHOW_ALL)
294           g_settings.m_iMyVideoWatchMode = VIDEO_SHOW_UNWATCHED;
295         else
296           g_settings.m_iMyVideoWatchMode = VIDEO_SHOW_ALL;
297         g_settings.Save();
298         // TODO: Can we perhaps filter this directly?  Probably not for some of the more complicated views,
299         //       but for those perhaps we can just display them all, and only filter when we get a list
300         //       of actual videos?
301         Update(m_vecItems->m_strPath);
302         return true;
303       }
304     }
305     break;
306     // update the display
307     case GUI_MSG_SCAN_FINISHED:
308     case GUI_MSG_REFRESH_THUMBS:
309     {
310       Update(m_vecItems->m_strPath);
311     }
312     break;
313   }
314   return CGUIWindowVideoBase::OnMessage(message);
315 }
316
317 CStdString CGUIWindowVideoNav::GetQuickpathName(const CStdString& strPath) const
318 {
319   if (strPath.Equals("videodb://1/1/"))
320     return "MovieGenres";
321   else if (strPath.Equals("videodb://1/2/"))
322     return "MovieTitles";
323   else if (strPath.Equals("videodb://1/3/"))
324     return "MovieYears";
325   else if (strPath.Equals("videodb://1/4/"))
326     return "MovieActors";
327   else if (strPath.Equals("videodb://1/5/"))
328     return "MovieDirectors";
329   else if (strPath.Equals("videodb://1/"))
330     return "Movies";
331   else if (strPath.Equals("videodb://2/1/"))
332     return "TvShowGenres";
333   else if (strPath.Equals("videodb://2/2/"))
334     return "TvShowTitles";
335   else if (strPath.Equals("videodb://2/3/"))
336     return "TvShowYears";
337   else if (strPath.Equals("videodb://2/4/"))
338     return "TvShowActors";
339   else if (strPath.Equals("videodb://2/"))
340     return "TvShows";
341   else if (strPath.Equals("videodb://3/1/"))
342     return "MusicVideoGenres";
343   else if (strPath.Equals("videodb://3/2/"))
344     return "MusicVideoTitles";
345   else if (strPath.Equals("videodb://3/3/"))
346     return "MusicVideoYears";
347   else if (strPath.Equals("videodb://3/4/"))
348     return "MusicVideoArtists";
349   else if (strPath.Equals("videodb://3/5/"))
350     return "MusicVideoDirectors";
351   else if (strPath.Equals("videodb://3/"))
352     return "MusicVideos";
353   else if (strPath.Equals("videodb://4/"))
354     return "RecentlyAddedMovies";
355   else if (strPath.Equals("videodb://5/"))
356     return "RecentlyAddedEpisodes";
357   else if (strPath.Equals("videodb://6/"))
358     return "RecentlyAddedMusicVideos";
359   else if (strPath.Equals("special://videoplaylists/"))
360     return "Playlists";
361   else
362   {
363     CLog::Log(LOGERROR, "  CGUIWindowVideoNav::GetQuickpathName: Unknown parameter (%s)", strPath.c_str());
364     return strPath;
365   }
366 }
367
368 void CGUIWindowVideoNav::OnItemLoaded(CFileItem* pItem)
369 {
370   /* even though the background loader is running multiple threads and we could,
371      be acting on someone else's flag, we don't care who invalidates the cache
372      only that it is done.  We also don't care if it is done multiple times due
373      to a race between multiple threads here at the same time */
374   CUtil::DeleteVideoDatabaseDirectoryCache();
375 }
376
377 bool CGUIWindowVideoNav::GetDirectory(const CStdString &strDirectory, CFileItemList &items)
378 {
379   if (m_bDisplayEmptyDatabaseMessage)
380     return true;
381
382   CFileItem directory(strDirectory, true);
383
384   if (m_thumbLoader.IsLoading())
385     m_thumbLoader.StopThread();
386
387   m_rootDir.SetCacheDirectory(DIR_CACHE_NEVER);
388   items.ClearProperties();
389
390   bool bResult = CGUIWindowVideoBase::GetDirectory(strDirectory, items);
391   if (bResult)
392   {
393     if (items.IsVideoDb())
394     {
395       XFILE::CVideoDatabaseDirectory dir;
396       CQueryParams params;
397       dir.GetQueryParams(items.m_strPath,params);
398       VIDEODATABASEDIRECTORY::NODE_TYPE node = dir.GetDirectoryChildType(items.m_strPath);
399
400       items.SetThumbnailImage("");
401       if (node == VIDEODATABASEDIRECTORY::NODE_TYPE_EPISODES ||
402           node == NODE_TYPE_SEASONS                          ||
403           node == NODE_TYPE_RECENTLY_ADDED_EPISODES)
404       {
405         CLog::Log(LOGDEBUG, "WindowVideoNav::GetDirectory");
406         // grab the show thumb
407         CFileItem showItem;
408         m_database.GetFilePathById(params.GetTvShowId(),showItem.m_strPath,VIDEODB_CONTENT_TVSHOWS);
409         showItem.SetVideoThumb();
410         items.SetProperty("tvshowthumb", showItem.GetThumbnailImage());
411         // Grab fanart data
412         CVideoInfoTag details;
413         m_database.GetTvShowInfo(showItem.m_strPath, details, params.GetTvShowId());
414         items.SetProperty("fanart_color1", details.m_fanart.GetColor(0));
415         items.SetProperty("fanart_color2", details.m_fanart.GetColor(1));
416         items.SetProperty("fanart_color3", details.m_fanart.GetColor(2));
417         if (showItem.CacheLocalFanart())
418           items.SetProperty("fanart_image", showItem.GetCachedFanart());
419
420         // save the show description (showplot)
421         items.SetProperty("showplot", details.m_strPlot);
422
423         // set the season thumb
424         CStdString strLabel;
425         if (params.GetSeason() == 0)
426           strLabel = g_localizeStrings.Get(20381);
427         else
428           strLabel.Format(g_localizeStrings.Get(20358), params.GetSeason());
429
430         CFileItem item(strLabel);
431         CUtil::GetParentPath(items.m_strPath,item.m_strPath);
432         item.m_bIsFolder = true;
433         item.SetCachedSeasonThumb();
434         if (item.HasThumbnail())
435           items.SetProperty("seasonthumb",item.GetThumbnailImage());
436
437         // the container folder thumb is the parent (i.e. season or show)
438         if (node == NODE_TYPE_EPISODES || node == NODE_TYPE_RECENTLY_ADDED_EPISODES)
439         {
440           items.SetContent("episodes");
441           // grab the season thumb as the folder thumb
442           CStdString strLabel;
443           CStdString strPath;
444           if (params.GetSeason() == -1 && items.Size() > 0)
445           {
446             CQueryParams params2;
447             dir.GetQueryParams(items[0]->m_strPath,params2);
448             strLabel.Format(g_localizeStrings.Get(20358), params2.GetSeason());
449             CUtil::GetParentPath(items.m_strPath,strPath);
450           }
451           else
452           {
453             if (params.GetSeason() == 0)
454               strLabel = g_localizeStrings.Get(20381);
455             else
456               strLabel.Format(g_localizeStrings.Get(20358), params.GetSeason());
457             strPath = items.m_strPath;
458           }
459
460           CFileItem item(strLabel);
461           item.m_strPath = strPath;
462           item.m_bIsFolder = true;
463           item.GetVideoInfoTag()->m_strPath = showItem.m_strPath;
464           item.SetCachedSeasonThumb();
465
466           items.SetThumbnailImage(item.GetThumbnailImage());
467           items.SetProperty("seasonthumb",item.GetThumbnailImage());
468         }
469         else
470         {
471           items.SetContent("seasons");
472           items.SetThumbnailImage(showItem.GetThumbnailImage());
473         }
474       }
475       else if (node == NODE_TYPE_TITLE_MOVIES ||
476                node == NODE_TYPE_RECENTLY_ADDED_MOVIES)
477         items.SetContent("movies");
478       else if (node == NODE_TYPE_TITLE_TVSHOWS)
479         items.SetContent("tvshows");
480       else if (node == NODE_TYPE_TITLE_MUSICVIDEOS ||
481                node == NODE_TYPE_RECENTLY_ADDED_MUSICVIDEOS)
482         items.SetContent("musicvideos");
483       else if (node == NODE_TYPE_GENRE)
484         items.SetContent("genres");
485      else if (node == NODE_TYPE_ACTOR)
486      {
487        if (params.GetContentType() == VIDEODB_CONTENT_MUSICVIDEOS)
488          items.SetContent("artists");
489        else
490          items.SetContent("actors");
491      }
492      else if (node == NODE_TYPE_DIRECTOR)
493        items.SetContent("directors");
494      else if (node == NODE_TYPE_STUDIO)
495        items.SetContent("studios");
496      else if (node == NODE_TYPE_YEAR)
497        items.SetContent("years");
498      else if (node == NODE_TYPE_MUSICVIDEOS_ALBUM)
499        items.SetContent("albums");
500      else
501         items.SetContent("");
502     }
503   }
504
505   return bResult;
506 }
507
508 void CGUIWindowVideoNav::UpdateButtons()
509 {
510   CGUIWindowVideoBase::UpdateButtons();
511
512   // Update object count
513   int iItems = m_vecItems->Size();
514   if (iItems)
515   {
516     // check for parent dir and "all" items
517     // should always be the first two items
518     for (int i = 0; i <= (iItems>=2 ? 1 : 0); i++)
519     {
520       CFileItemPtr pItem = m_vecItems->Get(i);
521       if (pItem->IsParentFolder()) iItems--;
522       if (pItem->m_strPath.Left(4).Equals("/-1/")) iItems--;
523     }
524     // or the last item
525     if (m_vecItems->Size() > 2 &&
526       m_vecItems->Get(m_vecItems->Size()-1)->m_strPath.Left(4).Equals("/-1/"))
527       iItems--;
528   }
529   CStdString items;
530   items.Format("%i %s", iItems, g_localizeStrings.Get(127).c_str());
531   SET_CONTROL_LABEL(CONTROL_LABELFILES, items);
532
533   // set the filter label
534   CStdString strLabel;
535
536   // "Playlists"
537   if (m_vecItems->m_strPath.Equals("special://videoplaylists/"))
538     strLabel = g_localizeStrings.Get(136);
539   // "{Playlist Name}"
540   else if (m_vecItems->IsPlayList())
541   {
542     // get playlist name from path
543     CStdString strDummy;
544     CUtil::Split(m_vecItems->m_strPath, strDummy, strLabel);
545   }
546   // everything else is from a videodb:// path
547   else
548   {
549     CVideoDatabaseDirectory dir;
550     dir.GetLabel(m_vecItems->m_strPath, strLabel);
551   }
552
553   SET_CONTROL_LABEL(CONTROL_FILTER, strLabel);
554
555   SET_CONTROL_LABEL(CONTROL_BTNSHOWMODE, g_localizeStrings.Get(16100 + g_settings.m_iMyVideoWatchMode));
556
557   SET_CONTROL_SELECTED(GetID(),CONTROL_BTNSHOWALL,g_settings.m_iMyVideoWatchMode != VIDEO_SHOW_ALL);
558
559   SET_CONTROL_SELECTED(GetID(),CONTROL_BTNPARTYMODE, g_partyModeManager.IsEnabled());
560
561   SET_CONTROL_SELECTED(GetID(),CONTROL_BTNFLATTEN, g_settings.m_bMyVideoNavFlatten);
562 }
563
564 /// \brief Search for genres, artists, directors, names, and plots with search string \e strSearch in the
565 /// \brief video databases and return the found \e items
566 /// \param strSearch The search string
567 /// \param items Items Found
568 void CGUIWindowVideoNav::DoSearch(const CStdString& strSearch, CFileItemList& items)
569 {
570   CFileItemList tempItems;
571   CStdString strGenre = g_localizeStrings.Get(515); // Genre
572   CStdString strActor = g_localizeStrings.Get(20337); // Actor
573   CStdString strDirector = g_localizeStrings.Get(20339); // Director
574   CStdString strMovie = g_localizeStrings.Get(20338); // Movie
575
576   // get matching genres
577   m_database.GetMovieGenresByName(strSearch, tempItems);
578   if (tempItems.Size())
579   {
580     for (int i = 0; i < (int)tempItems.Size(); i++)
581     {
582       tempItems[i]->SetLabel("[" + strGenre + " - "+g_localizeStrings.Get(20342)+"] " + tempItems[i]->GetLabel());
583     }
584     items.Append(tempItems);
585   }
586
587   tempItems.Clear();
588   m_database.GetTvShowGenresByName(strSearch, tempItems);
589   if (tempItems.Size())
590   {
591     for (int i = 0; i < (int)tempItems.Size(); i++)
592     {
593       tempItems[i]->SetLabel("[" + strGenre + " - "+g_localizeStrings.Get(20343)+"] " + tempItems[i]->GetLabel());
594     }
595     items.Append(tempItems);
596   }
597
598   tempItems.Clear();
599   m_database.GetMusicVideoGenresByName(strSearch, tempItems);
600   if (tempItems.Size())
601   {
602     for (int i = 0; i < (int)tempItems.Size(); i++)
603     {
604       tempItems[i]->SetLabel("[" + strGenre + " - "+g_localizeStrings.Get(20389)+"] " + tempItems[i]->GetLabel());
605     }
606     items.Append(tempItems);
607   }
608
609   tempItems.Clear();
610   m_database.GetMovieActorsByName(strSearch, tempItems);
611   if (tempItems.Size())
612   {
613     for (int i = 0; i < (int)tempItems.Size(); i++)
614     {
615       tempItems[i]->SetLabel("[" + strActor + " - "+g_localizeStrings.Get(20342)+"] " + tempItems[i]->GetLabel());
616     }
617     items.Append(tempItems);
618   }
619
620   tempItems.Clear();
621   m_database.GetTvShowsActorsByName(strSearch, tempItems);
622   if (tempItems.Size())
623   {
624     for (int i = 0; i < (int)tempItems.Size(); i++)
625     {
626       tempItems[i]->SetLabel("[" + strActor + " - "+g_localizeStrings.Get(20343)+"] " + tempItems[i]->GetLabel());
627     }
628     items.Append(tempItems);
629   }
630
631   tempItems.Clear();
632   m_database.GetMusicVideoArtistsByName(strSearch, tempItems);
633   if (tempItems.Size())
634   {
635     for (int i = 0; i < (int)tempItems.Size(); i++)
636     {
637       tempItems[i]->SetLabel("[" + strActor + " - "+g_localizeStrings.Get(20389)+"] " + tempItems[i]->GetLabel());
638     }
639     items.Append(tempItems);
640   }
641
642   tempItems.Clear();
643   m_database.GetMovieDirectorsByName(strSearch, tempItems);
644   if (tempItems.Size())
645   {
646     for (int i = 0; i < (int)tempItems.Size(); i++)
647     {
648       tempItems[i]->SetLabel("[" + strDirector + " - "+g_localizeStrings.Get(20342)+"] " + tempItems[i]->GetLabel());
649     }
650     items.Append(tempItems);
651   }
652
653   tempItems.Clear();
654   m_database.GetTvShowsDirectorsByName(strSearch, tempItems);
655   if (tempItems.Size())
656   {
657     CStdString strMovie = g_localizeStrings.Get(20339); // Director
658     for (int i = 0; i < (int)tempItems.Size(); i++)
659     {
660       tempItems[i]->SetLabel("[" + strDirector + " - "+g_localizeStrings.Get(20343)+"] " + tempItems[i]->GetLabel());
661     }
662     items.Append(tempItems);
663   }
664
665   tempItems.Clear();
666   m_database.GetMusicVideoDirectorsByName(strSearch, tempItems);
667   if (tempItems.Size())
668   {
669     CStdString strMovie = g_localizeStrings.Get(20339); // Director
670     for (int i = 0; i < (int)tempItems.Size(); i++)
671     {
672       tempItems[i]->SetLabel("[" + strDirector + " - "+g_localizeStrings.Get(20389)+"] " + tempItems[i]->GetLabel());
673     }
674     items.Append(tempItems);
675   }
676
677   tempItems.Clear();
678   m_database.GetMoviesByName(strSearch, tempItems);
679
680   if (tempItems.Size())
681   {
682     for (int i = 0; i < (int)tempItems.Size(); i++)
683     {
684       tempItems[i]->SetLabel("[" + g_localizeStrings.Get(20338) + "] " + tempItems[i]->GetLabel());
685     }
686     items.Append(tempItems);
687   }
688
689   tempItems.Clear();
690   m_database.GetEpisodesByName(strSearch, tempItems);
691
692   if (tempItems.Size())
693   {
694     for (int i = 0; i < (int)tempItems.Size(); i++)
695     {
696       tempItems[i]->SetLabel("[" + g_localizeStrings.Get(20359) + "] " + tempItems[i]->GetLabel());
697     }
698     items.Append(tempItems);
699   }
700
701   tempItems.Clear();
702   m_database.GetTvShowsByName(strSearch, tempItems);
703
704   if (tempItems.Size())
705   {
706     for (int i = 0; i < (int)tempItems.Size(); i++)
707     {
708       tempItems[i]->SetLabel("[" + g_localizeStrings.Get(20364) + "] " + tempItems[i]->GetLabel());
709     }
710     items.Append(tempItems);
711   }
712
713   tempItems.Clear();
714   m_database.GetMusicVideosByName(strSearch, tempItems);
715
716   if (tempItems.Size())
717   {
718     for (int i = 0; i < (int)tempItems.Size(); i++)
719     {
720       tempItems[i]->SetLabel("[" + g_localizeStrings.Get(20391) + "] " + tempItems[i]->GetLabel());
721     }
722     items.Append(tempItems);
723   }
724
725   tempItems.Clear();
726   m_database.GetMusicVideosByAlbum(strSearch, tempItems);
727
728   if (tempItems.Size())
729   {
730     for (int i = 0; i < (int)tempItems.Size(); i++)
731     {
732       tempItems[i]->SetLabel("[" + g_localizeStrings.Get(558) + "] " + tempItems[i]->GetLabel());
733     }
734     items.Append(tempItems);
735   }
736
737   tempItems.Clear();
738   m_database.GetEpisodesByPlot(strSearch, tempItems);
739
740   if (tempItems.Size())
741   {
742     for (int i = 0; i < (int)tempItems.Size(); i++)
743     {
744       tempItems[i]->SetLabel("[" + g_localizeStrings.Get(20365) + "] " + tempItems[i]->GetLabel());
745     }
746     items.Append(tempItems);
747   }
748
749   tempItems.Clear();
750
751   m_database.GetMoviesByPlot(strSearch, tempItems);
752
753   if (tempItems.Size())
754   {
755     for (int i = 0; i < (int)tempItems.Size(); i++)
756     {
757       tempItems[i]->SetLabel("[" + strMovie + " " + g_localizeStrings.Get(207) + "] " + tempItems[i]->GetLabel());
758     }
759     items.Append(tempItems);
760   }
761 }
762
763 void CGUIWindowVideoNav::PlayItem(int iItem)
764 {
765   // unlike additemtoplaylist, we need to check the items here
766   // before calling it since the current playlist will be stopped
767   // and cleared!
768
769   // root is not allowed
770   if (m_vecItems->IsVirtualDirectoryRoot())
771     return;
772
773   CGUIWindowVideoBase::PlayItem(iItem);
774 }
775
776 void CGUIWindowVideoNav::DisplayEmptyDatabaseMessage(bool bDisplay)
777 {
778   m_bDisplayEmptyDatabaseMessage = bDisplay;
779 }
780
781 void CGUIWindowVideoNav::FrameMove()
782 {
783   if (m_bDisplayEmptyDatabaseMessage)
784     SET_CONTROL_LABEL(CONTROL_LABELEMPTY,g_localizeStrings.Get(745)+'\n'+g_localizeStrings.Get(746));
785   else
786     SET_CONTROL_LABEL(CONTROL_LABELEMPTY,"");
787   CGUIWindowVideoBase::FrameMove();
788 }
789
790 void CGUIWindowVideoNav::OnInfo(CFileItem* pItem, const SScraperInfo& info)
791 {
792   SScraperInfo info2(info);
793   m_database.Open(); // since we can be called from the music library without being inited
794   if (pItem->IsVideoDb())
795     m_database.GetScraperForPath(pItem->GetVideoInfoTag()->m_strPath,info2);
796   else if (m_vecItems->IsPlugin())
797     info2.strContent = "plugin";
798   else
799   {
800     CStdString strPath,strFile;
801     CUtil::Split(pItem->m_strPath,strPath,strFile);
802     m_database.GetScraperForPath(strPath,info2);
803   }
804   m_database.Close();
805   CGUIWindowVideoBase::OnInfo(pItem,info2);
806 }
807
808 bool CGUIWindowVideoNav::CanDelete(const CStdString& strPath)
809 {
810   CQueryParams params;
811   CVideoDatabaseDirectory::GetQueryParams(strPath,params);
812
813   if (params.GetMovieId()   != -1 ||
814       params.GetEpisodeId() != -1 ||
815       params.GetMVideoId()  != -1 ||
816       (params.GetTvShowId() != -1 && params.GetSeason() == -1
817               && !CVideoDatabaseDirectory::IsAllItem(strPath)))
818     return true;
819
820   return false;
821 }
822
823 void CGUIWindowVideoNav::OnDeleteItem(CFileItemPtr pItem)
824 {
825   if (m_vecItems->IsParentFolder())
826     return;
827
828   if (m_vecItems->m_strPath.Equals("special://videoplaylists/"))
829   {
830     if (!pItem->m_strPath.Equals("newsmartplaylist://video"))
831       CGUIWindowVideoBase::OnDeleteItem(pItem);
832   }
833   else if (m_vecItems->m_strPath.Equals("plugin://video/"))
834   {
835     CStdString path;
836     CUtil::GetDirectory(pItem->m_strPath,path);
837     path.Replace("plugin://","special://home/plugins/");
838     CFileItemPtr item2 = CFileItemPtr(new CFileItem(path,true));
839     CFileUtils::DeleteItem(item2);
840   }
841   else if (pItem->m_strPath.Left(14).Equals("videodb://1/7/") &&
842            pItem->m_strPath.size() > 14 && pItem->m_bIsFolder)
843   {
844     CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
845     pDialog->SetLine(0, g_localizeStrings.Get(432));
846     CStdString strLabel;
847     strLabel.Format(g_localizeStrings.Get(433),pItem->GetLabel());
848     pDialog->SetLine(1, strLabel);
849     pDialog->SetLine(2, "");;
850     pDialog->DoModal();
851     if (pDialog->IsConfirmed())
852     {
853       CFileItemList items;
854       CDirectory::GetDirectory(pItem->m_strPath,items);
855       for (int i=0;i<items.Size();++i)
856         OnDeleteItem(items[i]);
857
858        CVideoDatabaseDirectory dir;
859        CQueryParams params;
860        dir.GetQueryParams(pItem->m_strPath,params);
861        m_database.DeleteSet(params.GetSetId());
862     }
863   }
864   else
865   {
866     if (!DeleteItem(pItem.get()))
867       return;
868
869     CStdString strDeletePath;
870     if (pItem->m_bIsFolder)
871       strDeletePath=pItem->GetVideoInfoTag()->m_strPath;
872     else
873       strDeletePath=pItem->GetVideoInfoTag()->m_strFileNameAndPath;
874
875     if (CUtil::GetFileName(strDeletePath).Equals("VIDEO_TS.IFO"))
876     {
877       CUtil::GetDirectory(strDeletePath.Mid(0),strDeletePath);
878       if (strDeletePath.Right(9).Equals("VIDEO_TS/"))
879       {
880         CUtil::RemoveSlashAtEnd(strDeletePath);
881         CUtil::GetDirectory(strDeletePath.Mid(0),strDeletePath);
882       }
883     }
884     if (CUtil::HasSlashAtEnd(strDeletePath))
885       pItem->m_bIsFolder=true;
886
887     if (g_guiSettings.GetBool("filelists.allowfiledeletion") &&
888         CUtil::SupportsFileOperations(strDeletePath))
889     {
890       pItem->m_strPath = strDeletePath;
891       CGUIWindowVideoBase::OnDeleteItem(pItem);
892     }
893   }
894
895   CUtil::DeleteVideoDatabaseDirectoryCache();
896   DisplayEmptyDatabaseMessage(!m_database.HasContent());
897 }
898
899 bool CGUIWindowVideoNav::DeleteItem(CFileItem* pItem, bool bUnavailable /* = false */)
900 {
901   if (!pItem->HasVideoInfoTag() || !CanDelete(pItem->m_strPath))
902     return false;
903
904   VIDEODB_CONTENT_TYPE iType=VIDEODB_CONTENT_MOVIES;
905   if (pItem->HasVideoInfoTag() && !pItem->GetVideoInfoTag()->m_strShowTitle.IsEmpty())
906     iType = VIDEODB_CONTENT_TVSHOWS;
907   if (pItem->HasVideoInfoTag() && pItem->GetVideoInfoTag()->m_iSeason > -1 && !pItem->m_bIsFolder)
908     iType = VIDEODB_CONTENT_EPISODES;
909   if (pItem->HasVideoInfoTag() && !pItem->GetVideoInfoTag()->m_strArtist.IsEmpty())
910     iType = VIDEODB_CONTENT_MUSICVIDEOS;
911
912   // dont allow update while scanning
913   CGUIDialogVideoScan* pDialogScan = (CGUIDialogVideoScan*)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_SCAN);
914   if (pDialogScan && pDialogScan->IsScanning())
915   {
916     CGUIDialogOK::ShowAndGetInput(257, 0, 14057, 0);
917     return false;
918   }
919
920
921   CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
922   if (!pDialog)
923     return false;
924   if (iType == VIDEODB_CONTENT_MOVIES)
925     pDialog->SetHeading(432);
926   if (iType == VIDEODB_CONTENT_EPISODES)
927     pDialog->SetHeading(20362);
928   if (iType == VIDEODB_CONTENT_TVSHOWS)
929     pDialog->SetHeading(20363);
930   if (iType == VIDEODB_CONTENT_MUSICVIDEOS)
931     pDialog->SetHeading(20392);
932
933   if(bUnavailable)
934   {
935     pDialog->SetLine(0, g_localizeStrings.Get(662));
936     pDialog->SetLine(1, g_localizeStrings.Get(663));
937     pDialog->SetLine(2, "");;
938     pDialog->DoModal();
939   }
940   else
941   {
942     CStdString strLine;
943     strLine.Format(g_localizeStrings.Get(433),pItem->GetLabel());
944     pDialog->SetLine(0, strLine);
945     pDialog->SetLine(1, "");
946     pDialog->SetLine(2, "");;
947     pDialog->DoModal();
948   }
949
950   if (!pDialog->IsConfirmed())
951     return false;
952
953   CStdString path;
954   CVideoDatabase database;
955   database.Open();
956
957   database.GetFilePathById(pItem->GetVideoInfoTag()->m_iDbId, path, iType);
958   if (path.IsEmpty())
959     return false;
960   if (iType == VIDEODB_CONTENT_MOVIES)
961     database.DeleteMovie(path);
962   if (iType == VIDEODB_CONTENT_EPISODES)
963     database.DeleteEpisode(path, pItem->GetVideoInfoTag()->m_iDbId);
964   if (iType == VIDEODB_CONTENT_TVSHOWS)
965     database.DeleteTvShow(path);
966   if (iType == VIDEODB_CONTENT_MUSICVIDEOS)
967     database.DeleteMusicVideo(path);
968
969   if (iType == VIDEODB_CONTENT_TVSHOWS)
970     database.SetPathHash(path,"");
971   else
972   {
973     CStdString strDirectory;
974     CUtil::GetDirectory(path,strDirectory);
975     database.SetPathHash(strDirectory,"");
976   }
977
978   return true;
979 }
980
981 void CGUIWindowVideoNav::OnPrepareFileItems(CFileItemList &items)
982 {
983   CGUIWindowVideoBase::OnPrepareFileItems(items);
984
985   // set fanart
986   CQueryParams params;
987   CVideoDatabaseDirectory dir;
988   dir.GetQueryParams(items.m_strPath,params);
989   if (params.GetContentType() == VIDEODB_CONTENT_MUSICVIDEOS)
990     CGUIWindowMusicNav::SetupFanart(items);
991
992   NODE_TYPE node = dir.GetDirectoryChildType(items.m_strPath);
993
994   // now filter as necessary
995   bool filterWatched=false;
996   if (node == NODE_TYPE_EPISODES
997   ||  node == NODE_TYPE_SEASONS
998   ||  node == NODE_TYPE_TITLE_MOVIES
999   ||  node == NODE_TYPE_TITLE_TVSHOWS
1000   ||  node == NODE_TYPE_TITLE_MUSICVIDEOS
1001   ||  node == NODE_TYPE_RECENTLY_ADDED_EPISODES
1002   ||  node == NODE_TYPE_RECENTLY_ADDED_MOVIES
1003   ||  node == NODE_TYPE_RECENTLY_ADDED_MUSICVIDEOS)
1004     filterWatched = true;
1005   if (items.IsPlugin())
1006     filterWatched = true;
1007
1008   int itemsBefore = items.Size();
1009
1010   for (int i = 0; i < items.Size(); i++)
1011   {
1012     CFileItemPtr item = items.Get(i);
1013     if(item->HasVideoInfoTag() && node == NODE_TYPE_TITLE_TVSHOWS)
1014     {
1015       if (g_settings.m_iMyVideoWatchMode == VIDEO_SHOW_UNWATCHED)
1016         item->GetVideoInfoTag()->m_iEpisode = item->GetPropertyInt("unwatchedepisodes");
1017       if (g_settings.m_iMyVideoWatchMode == VIDEO_SHOW_WATCHED)
1018         item->GetVideoInfoTag()->m_iEpisode = item->GetPropertyInt("watchedepisodes");
1019     }
1020
1021     if(filterWatched)
1022     {
1023       if((g_settings.m_iMyVideoWatchMode==VIDEO_SHOW_WATCHED   && item->GetVideoInfoTag()->m_playCount== 0)
1024       || (g_settings.m_iMyVideoWatchMode==VIDEO_SHOW_UNWATCHED && item->GetVideoInfoTag()->m_playCount > 0))
1025       {
1026         items.Remove(i);
1027         i--;
1028       }
1029     }
1030   }
1031   if (g_settings.m_iMyVideoWatchMode != VIDEO_SHOW_ALL && itemsBefore != items.Size() && items.GetObjectCount() == 0)
1032     GoParentFolder();
1033 }
1034
1035 void CGUIWindowVideoNav::GetContextButtons(int itemNumber, CContextButtons &buttons)
1036 {
1037   CFileItemPtr item;
1038   if (itemNumber >= 0 && itemNumber < m_vecItems->Size())
1039     item = m_vecItems->Get(itemNumber);
1040
1041   CGUIWindowVideoBase::GetContextButtons(itemNumber, buttons);
1042
1043   if (item && item->GetPropertyBOOL("pluginreplacecontextitems"))
1044     return;
1045
1046   CVideoDatabaseDirectory dir;
1047   NODE_TYPE node = dir.GetDirectoryChildType(m_vecItems->m_strPath);
1048
1049   if (!item)
1050   {
1051     CGUIDialogVideoScan *pScanDlg = (CGUIDialogVideoScan *)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_SCAN);
1052     if (pScanDlg && pScanDlg->IsScanning())
1053       buttons.Add(CONTEXT_BUTTON_STOP_SCANNING, 13353);
1054     else
1055       buttons.Add(CONTEXT_BUTTON_UPDATE_LIBRARY, 653);
1056   }
1057   else
1058   {
1059     SScraperInfo info;
1060     VIDEO::SScanSettings settings;
1061     GetScraperForItem(item.get(), info, settings);
1062
1063     if (info.strContent.Equals("tvshows"))
1064       buttons.Add(CONTEXT_BUTTON_INFO, item->m_bIsFolder ? 20351 : 20352);
1065     else if (info.strContent.Equals("musicvideos"))
1066       buttons.Add(CONTEXT_BUTTON_INFO,20393);
1067     else if (!item->m_bIsFolder && !item->m_strPath.Left(19).Equals("newsmartplaylist://"))
1068       buttons.Add(CONTEXT_BUTTON_INFO, 13346);
1069
1070     if (item->HasVideoInfoTag() && !item->GetVideoInfoTag()->m_strArtist.IsEmpty())
1071     {
1072       CMusicDatabase database;
1073       database.Open();
1074       if (database.GetArtistByName(item->GetVideoInfoTag()->m_strArtist) > -1)
1075         buttons.Add(CONTEXT_BUTTON_GO_TO_ARTIST, 20396);
1076     }
1077     if (item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_strAlbum.size() > 0)
1078     {
1079       CMusicDatabase database;
1080       database.Open();
1081       if (database.GetAlbumByName(item->GetVideoInfoTag()->m_strAlbum) > -1)
1082         buttons.Add(CONTEXT_BUTTON_GO_TO_ALBUM, 20397);
1083     }
1084     if (item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_strAlbum.size() > 0 &&
1085         item->GetVideoInfoTag()->m_strArtist.size() > 0                           &&
1086         item->GetVideoInfoTag()->m_strTitle.size() > 0)
1087     {
1088       CMusicDatabase database;
1089       database.Open();
1090       if (database.GetSongByArtistAndAlbumAndTitle(item->GetVideoInfoTag()->m_strArtist,
1091                                                    item->GetVideoInfoTag()->m_strAlbum,
1092                                                    item->GetVideoInfoTag()->m_strTitle) > -1)
1093       {
1094         buttons.Add(CONTEXT_BUTTON_PLAY_OTHER, 20398);
1095       }
1096     }
1097     if (!item->IsParentFolder())
1098     {
1099       // can we update the database?
1100       if (g_settings.m_vecProfiles[g_settings.m_iLastLoadedProfileIndex].canWriteDatabases() || g_passwordManager.bMasterUser)
1101       {
1102         if (node == NODE_TYPE_TITLE_TVSHOWS)
1103         {
1104           CGUIDialogVideoScan *pScanDlg = (CGUIDialogVideoScan *)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_SCAN);
1105           if (pScanDlg && pScanDlg->IsScanning())
1106             buttons.Add(CONTEXT_BUTTON_STOP_SCANNING, 13353);
1107           else
1108             buttons.Add(CONTEXT_BUTTON_UPDATE_TVSHOW, 13349);
1109         }
1110         if ((info.strContent.Equals("tvshows") && item->m_bIsFolder) ||
1111             (item->IsVideoDb() && item->HasVideoInfoTag() && !item->m_bIsFolder))
1112         {
1113           if (item->m_bIsFolder || item->GetVideoInfoTag()->m_playCount > 0)
1114             buttons.Add(CONTEXT_BUTTON_MARK_UNWATCHED, 16104); //Mark as UnWatched
1115           if (item->m_bIsFolder || item->GetVideoInfoTag()->m_playCount == 0)
1116             buttons.Add(CONTEXT_BUTTON_MARK_WATCHED, 16103);   //Mark as Watched
1117           if (node != NODE_TYPE_SEASONS)
1118             buttons.Add(CONTEXT_BUTTON_EDIT, 16105); //Edit Title
1119         }
1120         if (m_database.HasContent(VIDEODB_CONTENT_TVSHOWS) && item->HasVideoInfoTag() &&
1121            !item->m_bIsFolder && item->GetVideoInfoTag()->m_iEpisode == -1 &&
1122             item->GetVideoInfoTag()->m_strArtist.IsEmpty()) // movie entry
1123         {
1124           if (m_database.IsLinkedToTvshow(item->GetVideoInfoTag()->m_iDbId))
1125             buttons.Add(CONTEXT_BUTTON_UNLINK_MOVIE,20385);
1126           buttons.Add(CONTEXT_BUTTON_LINK_MOVIE,20384);
1127         }
1128
1129         if (node == NODE_TYPE_SEASONS && item->m_bIsFolder)
1130           buttons.Add(CONTEXT_BUTTON_SET_SEASON_THUMB, 20371);
1131
1132         if (m_vecItems->m_strPath.Equals("plugin://video/"))
1133           buttons.Add(CONTEXT_BUTTON_SET_PLUGIN_THUMB, 1044);
1134
1135         if (item->m_strPath.Left(14).Equals("videodb://1/7/") && item->m_strPath.size() > 14 && item->m_bIsFolder) // sets
1136         {
1137           buttons.Add(CONTEXT_BUTTON_EDIT, 16105);
1138           buttons.Add(CONTEXT_BUTTON_SET_MOVIESET_THUMB, 20435);
1139           buttons.Add(CONTEXT_BUTTON_DELETE, 646);
1140         }
1141
1142         if (node == NODE_TYPE_ACTOR && !dir.IsAllItem(item->m_strPath) && item->m_bIsFolder)
1143         {
1144           if (m_vecItems->m_strPath.Left(11).Equals("videodb://3")) // mvids
1145             buttons.Add(CONTEXT_BUTTON_SET_ARTIST_THUMB, 13359);
1146           else
1147             buttons.Add(CONTEXT_BUTTON_SET_ACTOR_THUMB, 20403);
1148         }
1149         if (item->IsVideoDb() && item->HasVideoInfoTag() &&
1150           (!item->m_bIsFolder || node == NODE_TYPE_TITLE_TVSHOWS))
1151         {
1152           if (info.strContent.Equals("tvshows"))
1153           {
1154             if(item->GetVideoInfoTag()->m_iBookmarkId != -1 &&
1155                item->GetVideoInfoTag()->m_iBookmarkId != 0)
1156             {
1157               buttons.Add(CONTEXT_BUTTON_UNLINK_BOOKMARK, 20405);
1158             }
1159           }
1160           buttons.Add(CONTEXT_BUTTON_DELETE, 646);
1161         }
1162
1163         // this should ideally be non-contextual (though we need some context for non-tv show node I guess)
1164         CGUIDialogVideoScan *pScanDlg = (CGUIDialogVideoScan *)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_SCAN);
1165         if (pScanDlg && pScanDlg->IsScanning())
1166         {
1167           if (node != NODE_TYPE_TITLE_TVSHOWS)
1168             buttons.Add(CONTEXT_BUTTON_STOP_SCANNING, 13353);
1169         }
1170         else
1171           buttons.Add(CONTEXT_BUTTON_UPDATE_LIBRARY, 653);
1172       }
1173
1174       //Set default and/or clear default
1175       NODE_TYPE nodetype = CVideoDatabaseDirectory::GetDirectoryType(item->m_strPath);
1176       if (!item->IsParentFolder() && !m_vecItems->m_strPath.Equals("special://videoplaylists/") &&
1177         (nodetype == NODE_TYPE_ROOT             ||
1178          nodetype == NODE_TYPE_OVERVIEW         ||
1179          nodetype == NODE_TYPE_TVSHOWS_OVERVIEW ||
1180          nodetype == NODE_TYPE_MOVIES_OVERVIEW  ||
1181          nodetype == NODE_TYPE_MUSICVIDEOS_OVERVIEW))
1182       {
1183         if (!item->m_strPath.Equals(g_settings.m_defaultVideoLibSource))
1184           buttons.Add(CONTEXT_BUTTON_SET_DEFAULT, 13335); // set default
1185         if (strcmp(g_settings.m_defaultVideoLibSource, ""))
1186           buttons.Add(CONTEXT_BUTTON_CLEAR_DEFAULT, 13403); // clear default
1187       }
1188
1189       if ((CVideoDatabaseDirectory::GetDirectoryChildType(item->m_strPath) == NODE_TYPE_TITLE_MOVIES ||
1190            CVideoDatabaseDirectory::GetDirectoryChildType(item->m_strPath) == NODE_TYPE_TITLE_MUSICVIDEOS ||
1191            item->m_strPath.Equals("videodb://1/") ||
1192            item->m_strPath.Equals("videodb://4/") ||
1193            item->m_strPath.Equals("videodb://6/")) &&
1194            nodetype != NODE_TYPE_RECENTLY_ADDED_MOVIES)
1195       {
1196         buttons.Add(CONTEXT_BUTTON_MARK_WATCHED, 16103);   //Mark as Watched
1197         buttons.Add(CONTEXT_BUTTON_MARK_UNWATCHED, 16104); //Mark as UnWatched
1198       }
1199
1200       if (m_vecItems->m_strPath.Equals("special://videoplaylists/"))
1201       { // video playlists, file operations are allowed
1202         if (!item->IsReadOnly())
1203         {
1204           buttons.Add(CONTEXT_BUTTON_DELETE, 117);
1205           buttons.Add(CONTEXT_BUTTON_RENAME, 118);
1206         }
1207       }
1208     }
1209   }
1210   CGUIWindowVideoBase::GetNonContextButtons(itemNumber, buttons);
1211 }
1212
1213 bool CGUIWindowVideoNav::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
1214 {
1215   CFileItemPtr item;
1216   if (itemNumber >= 0 && itemNumber < m_vecItems->Size())
1217     item = m_vecItems->Get(itemNumber);
1218   switch (button)
1219   {
1220   case CONTEXT_BUTTON_SET_DEFAULT:
1221     g_settings.m_defaultVideoLibSource = GetQuickpathName(item->m_strPath);
1222     g_settings.Save();
1223     return true;
1224
1225   case CONTEXT_BUTTON_CLEAR_DEFAULT:
1226     g_settings.m_defaultVideoLibSource.Empty();
1227     g_settings.Save();
1228     return true;
1229
1230   case CONTEXT_BUTTON_EDIT:
1231     UpdateVideoTitle(item.get());
1232     CUtil::DeleteVideoDatabaseDirectoryCache();
1233     Update(m_vecItems->m_strPath);
1234     return true;
1235
1236   case CONTEXT_BUTTON_SET_SEASON_THUMB:
1237   case CONTEXT_BUTTON_SET_ACTOR_THUMB:
1238   case CONTEXT_BUTTON_SET_ARTIST_THUMB:
1239   case CONTEXT_BUTTON_SET_PLUGIN_THUMB:
1240   case CONTEXT_BUTTON_SET_MOVIESET_THUMB:
1241     {
1242       // Grab the thumbnails from the web
1243       CStdString strPath;
1244       CFileItemList items;
1245       CUtil::AddFileToFolder(g_advancedSettings.m_cachePath,"imdbthumbs",strPath);
1246       CUtil::WipeDir(strPath);
1247       XFILE::CDirectory::Create(strPath);
1248       CFileItemPtr noneitem(new CFileItem("thumb://None", false));
1249       int i=1;
1250       CStdString cachedThumb = m_vecItems->Get(itemNumber)->GetCachedSeasonThumb();
1251       if (button == CONTEXT_BUTTON_SET_ACTOR_THUMB)
1252         cachedThumb = m_vecItems->Get(itemNumber)->GetCachedActorThumb();
1253       if (button == CONTEXT_BUTTON_SET_ARTIST_THUMB)
1254         cachedThumb = m_vecItems->Get(itemNumber)->GetCachedArtistThumb();
1255       if (button == CONTEXT_BUTTON_SET_MOVIESET_THUMB)
1256         cachedThumb = m_vecItems->Get(itemNumber)->GetCachedVideoThumb();
1257       if (button == CONTEXT_BUTTON_SET_PLUGIN_THUMB)
1258       {
1259         strPath = m_vecItems->Get(itemNumber)->m_strPath;
1260         strPath.Replace("plugin://video/","special://home/plugins/video/");
1261         CFileItem item(strPath,true);
1262         cachedThumb = item.GetCachedProgramThumb();
1263       }
1264       if (CFile::Exists(cachedThumb))
1265       {
1266         CFileItemPtr item(new CFileItem("thumb://Current", false));
1267         item->SetThumbnailImage(cachedThumb);
1268         item->SetLabel(g_localizeStrings.Get(20016));
1269         items.Add(item);
1270       }
1271       noneitem->SetIconImage("DefaultFolder.png");
1272       noneitem->SetLabel(g_localizeStrings.Get(20018));
1273
1274       if (button != CONTEXT_BUTTON_SET_ARTIST_THUMB &&
1275           button != CONTEXT_BUTTON_SET_PLUGIN_THUMB)
1276       {
1277         CVideoInfoTag tag;
1278         if (button == CONTEXT_BUTTON_SET_SEASON_THUMB)
1279           m_database.GetTvShowInfo("",tag,m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_iDbId);
1280         else
1281           tag = *m_vecItems->Get(itemNumber)->GetVideoInfoTag();
1282         for (vector<CScraperUrl::SUrlEntry>::iterator iter=tag.m_strPictureURL.m_url.begin();iter != tag.m_strPictureURL.m_url.end();++iter)
1283         {
1284           if ((iter->m_type != CScraperUrl::URL_TYPE_SEASON ||
1285                iter->m_season != m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_iSeason) &&
1286                button == CONTEXT_BUTTON_SET_SEASON_THUMB)
1287           {
1288             continue;
1289           }
1290
1291           CStdString strItemPath;
1292           strItemPath.Format("thumb://Remote%i",i++);
1293           CFileItemPtr item(new CFileItem(strItemPath, false));
1294           item->SetThumbnailImage("http://this.is/a/thumb/from/the/web");
1295           item->SetIconImage("DefaultPicture.png");
1296           item->GetVideoInfoTag()->m_strPictureURL.m_url.push_back(*iter);
1297           item->SetLabel(g_localizeStrings.Get(415));
1298           item->SetProperty("labelonthumbload",g_localizeStrings.Get(20015));
1299           // make sure any previously cached thumb is removed
1300           if (CFile::Exists(item->GetCachedPictureThumb()))
1301             CFile::Delete(item->GetCachedPictureThumb());
1302           items.Add(item);
1303         }
1304       }
1305
1306       bool local=false;
1307       if (button == CONTEXT_BUTTON_SET_PLUGIN_THUMB)
1308       {
1309         if (items.Size() == 0)
1310         {
1311           CFileItem item2(strPath,false);
1312           CUtil::AddFileToFolder(strPath,"default.py",item2.m_strPath);
1313           if (CFile::Exists(item2.GetCachedProgramThumb()))
1314           {
1315             CFileItemPtr item(new CFileItem("thumb://Current", false));
1316             item->SetThumbnailImage(item2.GetCachedProgramThumb());
1317             item->SetLabel(g_localizeStrings.Get(20016));
1318             items.Add(item);
1319             local = true;
1320           }
1321         }
1322         CStdString strThumb;
1323         CUtil::AddFileToFolder(strPath,"folder.jpg",strThumb);
1324         if (CFile::Exists(strThumb))
1325         {
1326           CFileItemPtr item(new CFileItem(strThumb,false));
1327           item->SetThumbnailImage(strThumb);
1328           item->SetLabel(g_localizeStrings.Get(20017));
1329           items.Add(item);
1330           local = true;
1331         }
1332         CUtil::AddFileToFolder(strPath,"default.tbn",strThumb);
1333         if (CFile::Exists(strThumb))
1334         {
1335           CFileItemPtr item(new CFileItem(strThumb,false));
1336           item->SetThumbnailImage(strThumb);
1337           item->SetLabel(g_localizeStrings.Get(20017));
1338           items.Add(item);
1339           local = true;
1340         }
1341       }
1342       if (button == CONTEXT_BUTTON_SET_ARTIST_THUMB)
1343       {
1344         CStdString picturePath;
1345
1346         CStdString strPath = m_vecItems->Get(itemNumber)->m_strPath;
1347         CUtil::RemoveSlashAtEnd(strPath);
1348
1349         int nPos=strPath.ReverseFind("/");
1350         if (nPos>-1)
1351         {
1352           //  try to guess where the user should start
1353           //  browsing for the artist thumb
1354           CMusicDatabase database;
1355           database.Open();
1356           long idArtist=database.GetArtistByName(m_vecItems->Get(itemNumber)->GetLabel());
1357           database.GetArtistPath(idArtist, picturePath);
1358         }
1359
1360         CStdString strThumb;
1361         CUtil::AddFileToFolder(picturePath,"folder.jpg",strThumb);
1362         if (XFILE::CFile::Exists(strThumb))
1363         {
1364           CFileItemPtr pItem(new CFileItem(strThumb,false));
1365           pItem->SetLabel(g_localizeStrings.Get(20017));
1366           pItem->SetThumbnailImage(strThumb);
1367           items.Add(pItem);
1368           local = true;
1369         }
1370         else
1371           noneitem->SetIconImage("DefaultArtist.png");
1372       }
1373
1374       if (button == CONTEXT_BUTTON_SET_ACTOR_THUMB)
1375       {
1376         CStdString picturePath;
1377         CStdString strThumb;
1378         CUtil::AddFileToFolder(picturePath,"folder.jpg",strThumb);
1379         if (XFILE::CFile::Exists(strThumb))
1380         {
1381           CFileItemPtr pItem(new CFileItem(strThumb,false));
1382           pItem->SetLabel(g_localizeStrings.Get(20017));
1383           pItem->SetThumbnailImage(strThumb);
1384           items.Add(pItem);
1385           local = true;
1386         }
1387         else
1388           noneitem->SetIconImage("DefaultActor.png");
1389       }
1390
1391       if (button == CONTEXT_BUTTON_SET_MOVIESET_THUMB)
1392         noneitem->SetIconImage("DefaultVideo.png");
1393
1394       if (!local)
1395         items.Add(noneitem);
1396
1397       VECSOURCES sources=g_settings.m_videoSources;
1398       g_mediaManager.GetLocalDrives(sources);
1399       CStdString result;
1400       if (!CGUIDialogFileBrowser::ShowAndGetImage(items, sources,
1401                                                   g_localizeStrings.Get(20019), result))
1402       {
1403         return false;   // user cancelled
1404       }
1405
1406       if (result == "thumb://Current")
1407         return false;   // user chose the one they have
1408
1409       // delete the thumbnail if that's what the user wants, else overwrite with the
1410       // new thumbnail
1411       if (result.Left(14) == "thumb://Remote")
1412       {
1413         CFileItem chosen(result,false);
1414         CStdString thumb = chosen.GetCachedPictureThumb();
1415         if (CFile::Exists(thumb))
1416         {
1417           // NOTE: This could fail if the thumbloader was too slow and the user too impatient
1418           CFile::Cache(thumb, cachedThumb);
1419         }
1420         else
1421           result = "thumb://None";
1422       }
1423       if (result == "thumb://None")
1424       {
1425         CFile::Delete(cachedThumb);
1426         if (button == CONTEXT_BUTTON_SET_PLUGIN_THUMB)
1427         {
1428           CFileItem item2(strPath,false);
1429           CUtil::AddFileToFolder(strPath,"default.py",item2.m_strPath);
1430           CFile::Delete(item2.GetCachedProgramThumb());
1431         }
1432       }
1433       else
1434         CFile::Cache(result,cachedThumb);
1435
1436       CUtil::DeleteVideoDatabaseDirectoryCache();
1437       CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_REFRESH_THUMBS);
1438       g_windowManager.SendMessage(msg);
1439       Update(m_vecItems->m_strPath);
1440
1441       return true;
1442     }
1443   case CONTEXT_BUTTON_UPDATE_LIBRARY:
1444     {
1445       SScraperInfo info;
1446       VIDEO::SScanSettings settings;
1447       OnScan("",info,settings);
1448       return true;
1449     }
1450   case CONTEXT_BUTTON_UNLINK_MOVIE:
1451     {
1452       OnLinkMovieToTvShow(itemNumber, true);
1453       Update(m_vecItems->m_strPath);
1454       return true;
1455     }
1456   case CONTEXT_BUTTON_LINK_MOVIE:
1457     {
1458       OnLinkMovieToTvShow(itemNumber, false);
1459       return true;
1460     }
1461   case CONTEXT_BUTTON_GO_TO_ARTIST:
1462     {
1463       CStdString strPath;
1464       CMusicDatabase database;
1465       database.Open();
1466       strPath.Format("musicdb://2/%ld/",database.GetArtistByName(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strArtist));
1467       g_windowManager.ActivateWindow(WINDOW_MUSIC_NAV,strPath);
1468       return true;
1469     }
1470   case CONTEXT_BUTTON_GO_TO_ALBUM:
1471     {
1472       CStdString strPath;
1473       CMusicDatabase database;
1474       database.Open();
1475       strPath.Format("musicdb://3/%ld/",database.GetAlbumByName(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strAlbum));
1476       g_windowManager.ActivateWindow(WINDOW_MUSIC_NAV,strPath);
1477       return true;
1478     }
1479   case CONTEXT_BUTTON_PLAY_OTHER:
1480     {
1481       CMusicDatabase database;
1482       database.Open();
1483       CSong song;
1484       if (database.GetSongById(database.GetSongByArtistAndAlbumAndTitle(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strArtist,m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strAlbum,
1485                                                                         m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strTitle),
1486                                                                         song))
1487       {
1488         g_application.getApplicationMessenger().PlayFile(song);
1489       }
1490       return true;
1491     }
1492
1493   case CONTEXT_BUTTON_UNLINK_BOOKMARK:
1494     {
1495       m_database.Open();
1496       m_database.DeleteBookMarkForEpisode(*m_vecItems->Get(itemNumber)->GetVideoInfoTag());
1497       m_database.Close();
1498       CUtil::DeleteVideoDatabaseDirectoryCache();
1499       Update(m_vecItems->m_strPath);
1500       return true;
1501     }
1502
1503   default:
1504     break;
1505
1506   }
1507   return CGUIWindowVideoBase::OnContextButton(itemNumber, button);
1508 }
1509
1510 void CGUIWindowVideoNav::OnLinkMovieToTvShow(int itemnumber, bool bRemove)
1511 {
1512   CFileItemList list;
1513   if (bRemove)
1514   {
1515     vector<int> ids;
1516     if (!m_database.GetLinksToTvShow(m_vecItems->Get(itemnumber)->GetVideoInfoTag()->m_iDbId,ids))
1517       return;
1518     for (unsigned int i=0;i<ids.size();++i)
1519     {
1520       CVideoInfoTag tag;
1521       m_database.GetTvShowInfo("",tag,ids[i]);
1522       CFileItemPtr show(new CFileItem(tag));
1523       list.Add(show);
1524     }
1525   }
1526   else
1527   {
1528     m_database.GetTvShowsNav("videodb://2/2",list);
1529
1530     // remove already linked shows
1531     vector<int> ids;
1532     if (!m_database.GetLinksToTvShow(m_vecItems->Get(itemnumber)->GetVideoInfoTag()->m_iDbId,ids))
1533       return;
1534     for (int i=0;i<list.Size();)
1535     {
1536       unsigned int j;
1537       for (j=0;j<ids.size();++j)
1538       {
1539         if (list[i]->GetVideoInfoTag()->m_iDbId == ids[j])
1540           break;
1541       }
1542       if (j == ids.size())
1543         i++;
1544       else
1545         list.Remove(i);
1546     }
1547   }
1548   int iSelectedLabel = 0;
1549   if (list.Size() > 1)
1550   {
1551     list.Sort(SORT_METHOD_LABEL,SORT_ORDER_ASC);
1552     CGUIDialogSelect* pDialog = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
1553     pDialog->Reset();
1554     pDialog->SetItems(&list);
1555     pDialog->SetHeading(20356);
1556     pDialog->DoModal();
1557     iSelectedLabel = pDialog->GetSelectedLabel();
1558   }
1559   if (iSelectedLabel > -1)
1560   {
1561     m_database.LinkMovieToTvshow(m_vecItems->Get(itemnumber)->GetVideoInfoTag()->m_iDbId,
1562                                  list[iSelectedLabel]->GetVideoInfoTag()->m_iDbId, bRemove);
1563     CUtil::DeleteVideoDatabaseDirectoryCache();
1564   }
1565 }
1566
1567 bool CGUIWindowVideoNav::OnClick(int iItem)
1568 {
1569   CFileItemPtr item = m_vecItems->Get(iItem);
1570   if (!item->m_bIsFolder && item->IsVideoDb() && !item->Exists())
1571   {
1572     if (!DeleteItem(item.get(), true))
1573       return true;
1574
1575     // update list
1576     m_vecItems->RemoveDiscCache(GetID());
1577     Update(m_vecItems->m_strPath);
1578     m_viewControl.SetSelectedItem(iItem);
1579     return true;
1580   }
1581
1582   return CGUIWindowVideoBase::OnClick(iItem);
1583 }