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