[textures] move image wrapping functions into a separate class
[vuplus_xbmc] / xbmc / video / windows / GUIWindowVideoNav.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://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, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "GUIUserMessages.h"
22 #include "GUIWindowVideoNav.h"
23 #include "music/windows/GUIWindowMusicNav.h"
24 #include "utils/FileUtils.h"
25 #include "Util.h"
26 #include "utils/RegExp.h"
27 #include "PlayListPlayer.h"
28 #include "GUIPassword.h"
29 #include "dialogs/GUIDialogFileBrowser.h"
30 #include "filesystem/VideoDatabaseDirectory.h"
31 #include "playlists/PlayListFactory.h"
32 #include "dialogs/GUIDialogOK.h"
33 #include "addons/AddonManager.h"
34 #include "PartyModeManager.h"
35 #include "music/MusicDatabase.h"
36 #include "guilib/GUIWindowManager.h"
37 #include "dialogs/GUIDialogYesNo.h"
38 #include "dialogs/GUIDialogSelect.h"
39 #include "filesystem/Directory.h"
40 #include "filesystem/File.h"
41 #include "FileItem.h"
42 #include "Application.h"
43 #include "ApplicationMessenger.h"
44 #include "profiles/ProfilesManager.h"
45 #include "settings/AdvancedSettings.h"
46 #include "settings/MediaSettings.h"
47 #include "settings/MediaSourceSettings.h"
48 #include "settings/Settings.h"
49 #include "guilib/Key.h"
50 #include "guilib/LocalizeStrings.h"
51 #include "storage/MediaManager.h"
52 #include "utils/LegacyPathTranslation.h"
53 #include "utils/log.h"
54 #include "utils/URIUtils.h"
55 #include "utils/StringUtils.h"
56 #include "TextureCache.h"
57 #include "guilib/GUIKeyboardFactory.h"
58 #include "video/VideoInfoScanner.h"
59 #include "video/dialogs/GUIDialogVideoInfo.h"
60 #include "pvr/recordings/PVRRecording.h"
61
62 using namespace XFILE;
63 using namespace VIDEODATABASEDIRECTORY;
64 using namespace std;
65
66 #define CONTROL_BTNVIEWASICONS     2
67 #define CONTROL_BTNSORTBY          3
68 #define CONTROL_BTNSORTASC         4
69 #define CONTROL_BTNTYPE            5
70 #define CONTROL_BTNSEARCH          8
71 #define CONTROL_LABELFILES        12
72
73 #define CONTROL_BTN_FILTER        19
74 #define CONTROL_BTNSHOWMODE       10
75 #define CONTROL_BTNSHOWALL        14
76 #define CONTROL_UNLOCK            11
77
78 #define CONTROL_FILTER            15
79 #define CONTROL_BTNPARTYMODE      16
80 #define CONTROL_LABELEMPTY        18
81
82 #define CONTROL_UPDATE_LIBRARY    20
83
84 CGUIWindowVideoNav::CGUIWindowVideoNav(void)
85     : CGUIWindowVideoBase(WINDOW_VIDEO_NAV, "MyVideoNav.xml")
86 {
87   m_thumbLoader.SetObserver(this);
88 }
89
90 CGUIWindowVideoNav::~CGUIWindowVideoNav(void)
91 {
92 }
93
94 bool CGUIWindowVideoNav::OnAction(const CAction &action)
95 {
96   if (action.GetID() == ACTION_TOGGLE_WATCHED)
97   {
98     CFileItemPtr pItem = m_vecItems->Get(m_viewControl.GetSelectedItem());
99     if (pItem->IsParentFolder())
100       return false;
101     if (pItem && pItem->GetVideoInfoTag()->m_playCount == 0)
102       return OnContextButton(m_viewControl.GetSelectedItem(),CONTEXT_BUTTON_MARK_WATCHED);
103     if (pItem && pItem->GetVideoInfoTag()->m_playCount > 0)
104       return OnContextButton(m_viewControl.GetSelectedItem(),CONTEXT_BUTTON_MARK_UNWATCHED);
105   }
106   return CGUIWindowVideoBase::OnAction(action);
107 }
108
109 bool CGUIWindowVideoNav::OnMessage(CGUIMessage& message)
110 {
111   switch (message.GetMessage())
112   {
113   case GUI_MSG_WINDOW_RESET:
114     m_vecItems->SetPath("");
115     break;
116   case GUI_MSG_WINDOW_DEINIT:
117     if (m_thumbLoader.IsLoading())
118       m_thumbLoader.StopThread();
119     break;
120   case GUI_MSG_WINDOW_INIT:
121     {
122       /* We don't want to show Autosourced items (ie removable pendrives, memorycards) in Library mode */
123       m_rootDir.AllowNonLocalSources(false);
124
125       SetProperty("flattened", CSettings::Get().GetBool("myvideos.flatten"));
126       if (message.GetNumStringParams() && message.GetStringParam(0).Equals("Files") &&
127           CMediaSourceSettings::Get().GetSources("video")->empty())
128       {
129         message.SetStringParam("");
130       }
131       
132       if (!CGUIWindowVideoBase::OnMessage(message))
133         return false;
134
135       return true;
136     }
137     break;
138
139   case GUI_MSG_CLICKED:
140     {
141       int iControl = message.GetSenderId();
142       if (iControl == CONTROL_BTNPARTYMODE)
143       {
144         if (g_partyModeManager.IsEnabled())
145           g_partyModeManager.Disable();
146         else
147         {
148           if (!g_partyModeManager.Enable(PARTYMODECONTEXT_VIDEO))
149           {
150             SET_CONTROL_SELECTED(GetID(),CONTROL_BTNPARTYMODE,false);
151             return false;
152           }
153
154           // Playlist directory is the root of the playlist window
155           if (m_guiState.get()) m_guiState->SetPlaylistDirectory("playlistvideo://");
156
157           return true;
158         }
159         UpdateButtons();
160       }
161
162       if (iControl == CONTROL_BTNSEARCH)
163       {
164         OnSearch();
165       }
166       else if (iControl == CONTROL_BTNSHOWMODE)
167       {
168         CMediaSettings::Get().CycleWatchedMode(m_vecItems->GetContent());
169         CSettings::Get().Save();
170         OnFilterItems(GetProperty("filter").asString());
171         return true;
172       }
173       else if (iControl == CONTROL_BTNSHOWALL)
174       {
175         if (CMediaSettings::Get().GetWatchedMode(m_vecItems->GetContent()) == WatchedModeAll)
176           CMediaSettings::Get().SetWatchedMode(m_vecItems->GetContent(), WatchedModeUnwatched);
177         else
178           CMediaSettings::Get().SetWatchedMode(m_vecItems->GetContent(), WatchedModeAll);
179         CSettings::Get().Save();
180         OnFilterItems(GetProperty("filter").asString());
181         return true;
182       }
183       else if (iControl == CONTROL_UPDATE_LIBRARY)
184       {
185         if (!g_application.IsVideoScanning())
186           OnScan("");
187         else
188           g_application.StopVideoScan();
189         return true;
190       }
191     }
192     break;
193     // update the display
194     case GUI_MSG_SCAN_FINISHED:
195     case GUI_MSG_REFRESH_THUMBS:
196       Refresh();
197       break;
198   }
199   return CGUIWindowVideoBase::OnMessage(message);
200 }
201
202 CStdString CGUIWindowVideoNav::GetQuickpathName(const CStdString& strPath) const
203 {
204   CStdString path = CLegacyPathTranslation::TranslateVideoDbPath(strPath);
205   if (path.Equals("videodb://movies/genres/"))
206     return "MovieGenres";
207   else if (path.Equals("videodb://movies/titles/"))
208     return "MovieTitles";
209   else if (path.Equals("videodb://movies/years/"))
210     return "MovieYears";
211   else if (path.Equals("videodb://movies/actors/"))
212     return "MovieActors";
213   else if (path.Equals("videodb://movies/directors/"))
214     return "MovieDirectors";
215   else if (path.Equals("videodb://movies/studios/"))
216     return "MovieStudios";
217   else if (path.Equals("videodb://movies/sets/"))
218     return "MovieSets";
219   else if (path.Equals("videodb://movies/countries/"))
220     return "MovieCountries";
221   else if (path.Equals("videodb://movies/tags/"))
222     return "MovieTags";
223   else if (path.Equals("videodb://movies/"))
224     return "Movies";
225   else if (path.Equals("videodb://tvshows/genres/"))
226     return "TvShowGenres";
227   else if (path.Equals("videodb://tvshows/titles/"))
228     return "TvShowTitles";
229   else if (path.Equals("videodb://tvshows/years/"))
230     return "TvShowYears";
231   else if (path.Equals("videodb://tvshows/actors/"))
232     return "TvShowActors";
233   else if (path.Equals("videodb://tvshows/studios/"))
234     return "TvShowStudios";
235   else if (path.Equals("videodb://tvshows/tags/"))
236     return "TvShowTags";
237   else if (path.Equals("videodb://tvshows/"))
238     return "TvShows";
239   else if (path.Equals("videodb://musicvideos/genres/"))
240     return "MusicVideoGenres";
241   else if (path.Equals("videodb://musicvideos/titles/"))
242     return "MusicVideoTitles";
243   else if (path.Equals("videodb://musicvideos/years/"))
244     return "MusicVideoYears";
245   else if (path.Equals("videodb://musicvideos/artists/"))
246     return "MusicVideoArtists";
247   else if (path.Equals("videodb://musicvideos/albums/"))
248     return "MusicVideoDirectors";
249   else if (path.Equals("videodb://musicvideos/tags/"))
250     return "MusicVideoTags";
251   else if (path.Equals("videodb://musicvideos/"))
252     return "MusicVideos";
253   else if (path.Equals("videodb://recentlyaddedmovies/"))
254     return "RecentlyAddedMovies";
255   else if (path.Equals("videodb://recentlyaddedepisodes/"))
256     return "RecentlyAddedEpisodes";
257   else if (path.Equals("videodb://recentlyaddedmusicvideos/"))
258     return "RecentlyAddedMusicVideos";
259   else if (path.Equals("special://videoplaylists/"))
260     return "Playlists";
261   else if (path.Equals("sources://video/"))
262     return "Files";
263   else
264   {
265     CLog::Log(LOGERROR, "  CGUIWindowVideoNav::GetQuickpathName: Unknown parameter (%s)", strPath.c_str());
266     return strPath;
267   }
268 }
269
270 bool CGUIWindowVideoNav::GetDirectory(const CStdString &strDirectory, CFileItemList &items)
271 {
272   if (m_thumbLoader.IsLoading())
273     m_thumbLoader.StopThread();
274
275   items.ClearProperties();
276
277   bool bResult = CGUIWindowVideoBase::GetDirectory(strDirectory, items);
278   if (bResult)
279   {
280     if (items.IsVideoDb())
281     {
282       XFILE::CVideoDatabaseDirectory dir;
283       CQueryParams params;
284       dir.GetQueryParams(items.GetPath(),params);
285       VIDEODATABASEDIRECTORY::NODE_TYPE node = dir.GetDirectoryChildType(items.GetPath());
286
287       items.SetArt("thumb", "");
288       if (node == VIDEODATABASEDIRECTORY::NODE_TYPE_EPISODES ||
289           node == NODE_TYPE_SEASONS                          ||
290           node == NODE_TYPE_RECENTLY_ADDED_EPISODES)
291       {
292         CLog::Log(LOGDEBUG, "WindowVideoNav::GetDirectory");
293         // grab the show thumb
294         CVideoInfoTag details;
295         m_database.GetTvShowInfo("", details, params.GetTvShowId());
296         map<string, string> art;
297         if (m_database.GetArtForItem(details.m_iDbId, details.m_type, art))
298         {
299           items.AppendArt(art, "tvshow");
300           items.SetArtFallback("fanart", "tvshow.fanart");
301           if (node == NODE_TYPE_SEASONS)
302           { // set an art fallback for "thumb"
303             if (items.HasArt("tvshow.poster"))
304               items.SetArtFallback("thumb", "tvshow.poster");
305             else if (items.HasArt("tvshow.banner"))
306               items.SetArtFallback("thumb", "tvshow.banner");
307           }
308         }
309
310         // Grab fanart data
311         items.SetProperty("fanart_color1", details.m_fanart.GetColor(0));
312         items.SetProperty("fanart_color2", details.m_fanart.GetColor(1));
313         items.SetProperty("fanart_color3", details.m_fanart.GetColor(2));
314
315         // save the show description (showplot)
316         items.SetProperty("showplot", details.m_strPlot);
317
318         // the container folder thumb is the parent (i.e. season or show)
319         if (node == NODE_TYPE_EPISODES || node == NODE_TYPE_RECENTLY_ADDED_EPISODES)
320         {
321           items.SetContent("episodes");
322           // grab the season thumb as the folder thumb
323           int seasonID = m_database.GetSeasonId(details.m_iDbId, params.GetSeason());
324           CGUIListItem::ArtMap seasonArt;
325           if (m_database.GetArtForItem(seasonID, "season", seasonArt))
326           {
327             items.AppendArt(art, "season");
328             // set an art fallback for "thumb"
329             if (items.HasArt("season.poster"))
330               items.SetArtFallback("thumb", "season.poster");
331             else if (items.HasArt("season.banner"))
332               items.SetArtFallback("thumb", "season.banner");
333           }
334         }
335         else
336           items.SetContent("seasons");
337       }
338       else if (node == NODE_TYPE_TITLE_MOVIES ||
339                node == NODE_TYPE_RECENTLY_ADDED_MOVIES)
340         items.SetContent("movies");
341       else if (node == NODE_TYPE_TITLE_TVSHOWS)
342         items.SetContent("tvshows");
343       else if (node == NODE_TYPE_TITLE_MUSICVIDEOS ||
344                node == NODE_TYPE_RECENTLY_ADDED_MUSICVIDEOS)
345         items.SetContent("musicvideos");
346       else if (node == NODE_TYPE_GENRE)
347         items.SetContent("genres");
348       else if (node == NODE_TYPE_COUNTRY)
349         items.SetContent("countries");
350       else if (node == NODE_TYPE_ACTOR)
351       {
352         if (params.GetContentType() == VIDEODB_CONTENT_MUSICVIDEOS)
353           items.SetContent("artists");
354         else
355           items.SetContent("actors");
356       }
357       else if (node == NODE_TYPE_DIRECTOR)
358         items.SetContent("directors");
359       else if (node == NODE_TYPE_STUDIO)
360         items.SetContent("studios");
361       else if (node == NODE_TYPE_YEAR)
362         items.SetContent("years");
363       else if (node == NODE_TYPE_MUSICVIDEOS_ALBUM)
364         items.SetContent("albums");
365       else if (node == NODE_TYPE_SETS)
366         items.SetContent("sets");
367       else if (node == NODE_TYPE_TAGS)
368         items.SetContent("tags");
369       else
370         items.SetContent("");
371     }
372     else if (!items.IsVirtualDirectoryRoot())
373     { // load info from the database
374       CStdString label;
375       if (items.GetLabel().IsEmpty() && m_rootDir.IsSource(items.GetPath(), CMediaSourceSettings::Get().GetSources("video"), &label)) 
376         items.SetLabel(label);
377       if (!items.IsSourcesPath())
378         LoadVideoInfo(items);
379     }
380
381     CVideoDbUrl videoUrl;
382     if (videoUrl.FromString(items.GetPath()) && items.GetContent() == "tags" &&
383        !items.Contains("newtag://" + videoUrl.GetType()))
384     {
385       CFileItemPtr newTag(new CFileItem("newtag://" + videoUrl.GetType(), false));
386       newTag->SetLabel(g_localizeStrings.Get(20462));
387       newTag->SetLabelPreformated(true);
388       newTag->SetSpecialSort(SortSpecialOnTop);
389       items.Add(newTag);
390     }
391   }
392   return bResult;
393 }
394
395 void CGUIWindowVideoNav::LoadVideoInfo(CFileItemList &items)
396 {
397   LoadVideoInfo(items, m_database);
398 }
399
400 void CGUIWindowVideoNav::LoadVideoInfo(CFileItemList &items, CVideoDatabase &database, bool allowReplaceLabels)
401 {
402   // TODO: this could possibly be threaded as per the music info loading,
403   //       we could also cache the info
404   if (!items.GetContent().IsEmpty() && !items.IsPlugin())
405     return; // don't load for listings that have content set and weren't created from plugins
406
407   CStdString content = items.GetContent();
408   // determine content only if it isn't set
409   if (content.IsEmpty())
410   {
411     content = database.GetContentForPath(items.GetPath());
412     items.SetContent(content.IsEmpty() ? "files" : content);
413   }
414
415   /*
416     If we have a matching item in the library, so we can assign the metadata to it. In addition, we can choose
417     * whether the item is stacked down (eg in the case of folders representing a single item)
418     * whether or not we assign the library's labels to the item, or leave the item as is.
419
420     As certain users (read: certain developers) don't want either of these to occur, we compromise by stacking
421     items down only if stacking is available and enabled.
422
423     Similarly, we assign the "clean" library labels to the item only if the "Replace filenames with library titles"
424     setting is enabled.
425     */
426   const bool stackItems    = items.GetProperty("isstacked").asBoolean() || (StackingAvailable(items) && CSettings::Get().GetBool("myvideos.stackvideos"));
427   const bool replaceLabels = allowReplaceLabels && CSettings::Get().GetBool("myvideos.replacelabels");
428
429   CFileItemList dbItems;
430   /* NOTE: In the future when GetItemsForPath returns all items regardless of whether they're "in the library"
431            we won't need the fetchedPlayCounts code, and can "simply" do this directly on absense of content. */
432   bool fetchedPlayCounts = false;
433   if (!content.IsEmpty())
434   {
435     database.GetItemsForPath(content, items.GetPath(), dbItems);
436     dbItems.SetFastLookup(true);
437   }
438
439   for (int i = 0; i < items.Size(); i++)
440   {
441     CFileItemPtr pItem = items[i];
442     CFileItemPtr match;
443     if (!content.IsEmpty()) /* optical media will be stacked down, so it's path won't match the base path */
444       match = dbItems.Get(pItem->IsOpticalMediaFile() ? pItem->GetLocalMetadataPath() : pItem->GetPath());
445     if (match)
446     {
447       pItem->UpdateInfo(*match, replaceLabels);
448
449       if (stackItems)
450       {
451         if (match->m_bIsFolder)
452           pItem->SetPath(match->GetVideoInfoTag()->m_strPath);
453         else
454           pItem->SetPath(match->GetVideoInfoTag()->m_strFileNameAndPath);
455         // if we switch from a file to a folder item it means we really shouldn't be sorting files and
456         // folders separately
457         if (pItem->m_bIsFolder != match->m_bIsFolder)
458         {
459           items.SetSortIgnoreFolders(true);
460           pItem->m_bIsFolder = match->m_bIsFolder;
461         }
462       }
463     }
464     else
465     {
466       /* NOTE: Currently we GetPlayCounts on our items regardless of whether content is set
467                 as if content is set, GetItemsForPaths doesn't return anything not in the content tables.
468                 This code can be removed once the content tables are always filled */
469       if (!pItem->m_bIsFolder && !fetchedPlayCounts)
470       {
471         database.GetPlayCounts(items.GetPath(), items);
472         fetchedPlayCounts = true;
473       }
474       
475       // preferably use some information from PVR info tag if available
476       if (pItem->HasPVRRecordingInfoTag())
477         pItem->GetPVRRecordingInfoTag()->CopyClientInfo(pItem->GetVideoInfoTag());
478
479       // set the watched overlay
480       if (pItem->IsVideo())
481         pItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, pItem->HasVideoInfoTag() && pItem->GetVideoInfoTag()->m_playCount > 0);
482     }
483   }
484 }
485
486 void CGUIWindowVideoNav::UpdateButtons()
487 {
488   CGUIWindowVideoBase::UpdateButtons();
489
490   // Update object count
491   int iItems = m_vecItems->Size();
492   if (iItems)
493   {
494     // check for parent dir and "all" items
495     // should always be the first two items
496     for (int i = 0; i <= (iItems>=2 ? 1 : 0); i++)
497     {
498       CFileItemPtr pItem = m_vecItems->Get(i);
499       if (pItem->IsParentFolder()) iItems--;
500       if (StringUtils::StartsWith(pItem->GetPath(), "/-1/")) iItems--;
501     }
502     // or the last item
503     if (m_vecItems->Size() > 2 &&
504       StringUtils::StartsWith(m_vecItems->Get(m_vecItems->Size()-1)->GetPath(), "/-1/"))
505       iItems--;
506   }
507   CStdString items;
508   items.Format("%i %s", iItems, g_localizeStrings.Get(127).c_str());
509   SET_CONTROL_LABEL(CONTROL_LABELFILES, items);
510
511   // set the filter label
512   CStdString strLabel;
513
514   // "Playlists"
515   if (m_vecItems->GetPath().Equals("special://videoplaylists/"))
516     strLabel = g_localizeStrings.Get(136);
517   // "{Playlist Name}"
518   else if (m_vecItems->IsPlayList())
519   {
520     // get playlist name from path
521     CStdString strDummy;
522     URIUtils::Split(m_vecItems->GetPath(), strDummy, strLabel);
523   }
524   else if (m_vecItems->GetPath().Equals("sources://video/"))
525     strLabel = g_localizeStrings.Get(744);
526   // everything else is from a videodb:// path
527   else if (m_vecItems->IsVideoDb())
528   {
529     CVideoDatabaseDirectory dir;
530     dir.GetLabel(m_vecItems->GetPath(), strLabel);
531   }
532   else
533     strLabel = URIUtils::GetFileName(m_vecItems->GetPath());
534
535   SET_CONTROL_LABEL(CONTROL_FILTER, strLabel);
536
537   int watchMode = CMediaSettings::Get().GetWatchedMode(m_vecItems->GetContent());
538   SET_CONTROL_LABEL(CONTROL_BTNSHOWMODE, g_localizeStrings.Get(16100 + watchMode));
539
540   SET_CONTROL_SELECTED(GetID(), CONTROL_BTNSHOWALL, watchMode != WatchedModeAll);
541
542   SET_CONTROL_SELECTED(GetID(),CONTROL_BTNPARTYMODE, g_partyModeManager.IsEnabled());
543
544   CONTROL_ENABLE_ON_CONDITION(CONTROL_UPDATE_LIBRARY, !m_vecItems->IsAddonsPath() && !m_vecItems->IsPlugin() && !m_vecItems->IsScript());
545 }
546
547 bool CGUIWindowVideoNav::GetFilteredItems(const CStdString &filter, CFileItemList &items)
548 {
549   bool listchanged = CGUIMediaWindow::GetFilteredItems(filter, items);
550   listchanged |= ApplyWatchedFilter(items);
551
552   return listchanged;
553 }
554
555 /// \brief Search for names, genres, artists, directors, and plots with search string \e strSearch in the
556 /// \brief video databases and return the found \e items
557 /// \param strSearch The search string
558 /// \param items Items Found
559 void CGUIWindowVideoNav::DoSearch(const CStdString& strSearch, CFileItemList& items)
560 {
561   CFileItemList tempItems;
562   CStdString strGenre = g_localizeStrings.Get(515); // Genre
563   CStdString strActor = g_localizeStrings.Get(20337); // Actor
564   CStdString strDirector = g_localizeStrings.Get(20339); // Director
565   CStdString strMovie = g_localizeStrings.Get(20338); // Movie
566
567   //get matching names
568   m_database.GetMoviesByName(strSearch, tempItems);
569   AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(20338) + "] ", items);
570
571   m_database.GetEpisodesByName(strSearch, tempItems);
572   AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(20359) + "] ", items);
573
574   m_database.GetTvShowsByName(strSearch, tempItems);
575   AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(20364) + "] ", items);
576
577   m_database.GetMusicVideosByName(strSearch, tempItems);
578   AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(20391) + "] ", items);
579
580   m_database.GetMusicVideosByAlbum(strSearch, tempItems);
581   AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(558) + "] ", items);
582   
583   // get matching genres
584   m_database.GetMovieGenresByName(strSearch, tempItems);
585   AppendAndClearSearchItems(tempItems, "[" + strGenre + " - " + g_localizeStrings.Get(20342) + "] ", items);
586
587   m_database.GetTvShowGenresByName(strSearch, tempItems);
588   AppendAndClearSearchItems(tempItems, "[" + strGenre + " - " + g_localizeStrings.Get(20343) + "] ", items);
589
590   m_database.GetMusicVideoGenresByName(strSearch, tempItems);
591   AppendAndClearSearchItems(tempItems, "[" + strGenre + " - " + g_localizeStrings.Get(20389) + "] ", items);
592
593   //get actors/artists
594   m_database.GetMovieActorsByName(strSearch, tempItems);
595   AppendAndClearSearchItems(tempItems, "[" + strActor + " - " + g_localizeStrings.Get(20342) + "] ", items);
596
597   m_database.GetTvShowsActorsByName(strSearch, tempItems);
598   AppendAndClearSearchItems(tempItems, "[" + strActor + " - " + g_localizeStrings.Get(20343) + "] ", items);
599
600   m_database.GetMusicVideoArtistsByName(strSearch, tempItems);
601   AppendAndClearSearchItems(tempItems, "[" + strActor + " - " + g_localizeStrings.Get(20389) + "] ", items);
602
603   //directors
604   m_database.GetMovieDirectorsByName(strSearch, tempItems);
605   AppendAndClearSearchItems(tempItems, "[" + strDirector + " - " + g_localizeStrings.Get(20342) + "] ", items);
606
607   m_database.GetTvShowsDirectorsByName(strSearch, tempItems);
608   AppendAndClearSearchItems(tempItems, "[" + strDirector + " - " + g_localizeStrings.Get(20343) + "] ", items);
609
610   m_database.GetMusicVideoDirectorsByName(strSearch, tempItems);
611   AppendAndClearSearchItems(tempItems, "[" + strDirector + " - " + g_localizeStrings.Get(20389) + "] ", items);
612
613   //plot
614   m_database.GetEpisodesByPlot(strSearch, tempItems);
615   AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(20365) + "] ", items);
616
617   m_database.GetMoviesByPlot(strSearch, tempItems);
618   AppendAndClearSearchItems(tempItems, "[" + strMovie + " " + g_localizeStrings.Get(207) + "] ", items);
619 }
620
621 void CGUIWindowVideoNav::PlayItem(int iItem)
622 {
623   // unlike additemtoplaylist, we need to check the items here
624   // before calling it since the current playlist will be stopped
625   // and cleared!
626
627   // root is not allowed
628   if (m_vecItems->IsVirtualDirectoryRoot())
629     return;
630
631   CGUIWindowVideoBase::PlayItem(iItem);
632 }
633
634 void CGUIWindowVideoNav::OnInfo(CFileItem* pItem, ADDON::ScraperPtr& scraper)
635 {
636   m_database.Open(); // since we can be called from the music library without being inited
637   if (pItem->IsVideoDb())
638     scraper = m_database.GetScraperForPath(pItem->GetVideoInfoTag()->m_strPath);
639   else
640   {
641     CStdString strPath,strFile;
642     URIUtils::Split(pItem->GetPath(),strPath,strFile);
643     scraper = m_database.GetScraperForPath(strPath);
644   }
645   m_database.Close();
646   CGUIWindowVideoBase::OnInfo(pItem,scraper);
647 }
648
649 bool CGUIWindowVideoNav::CanDelete(const CStdString& strPath)
650 {
651   CQueryParams params;
652   CVideoDatabaseDirectory::GetQueryParams(strPath,params);
653
654   if (params.GetMovieId()   != -1 ||
655       params.GetEpisodeId() != -1 ||
656       params.GetMVideoId()  != -1 ||
657       (params.GetTvShowId() != -1 && params.GetSeason() <= -1
658               && !CVideoDatabaseDirectory::IsAllItem(strPath)))
659     return true;
660
661   return false;
662 }
663
664 void CGUIWindowVideoNav::OnDeleteItem(CFileItemPtr pItem)
665 {
666   if (m_vecItems->IsParentFolder())
667     return;
668
669   if (!m_vecItems->IsVideoDb() && !pItem->IsVideoDb())
670   {
671     if (!pItem->GetPath().Equals("newsmartplaylist://video") &&
672         !pItem->GetPath().Equals("special://videoplaylists/") &&
673         !pItem->GetPath().Equals("sources://video/") &&
674         !StringUtils::StartsWithNoCase(pItem->GetPath(), "newtag://"))
675       CGUIWindowVideoBase::OnDeleteItem(pItem);
676   }
677   else if (StringUtils::StartsWithNoCase(pItem->GetPath(), "videodb://movies/sets/") &&
678            pItem->GetPath().size() > 22 && pItem->m_bIsFolder)
679   {
680     CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
681     pDialog->SetHeading(432);
682     CStdString strLabel;
683     strLabel.Format(g_localizeStrings.Get(433),pItem->GetLabel());
684     pDialog->SetLine(1, strLabel);
685     pDialog->SetLine(2, "");;
686     pDialog->DoModal();
687     if (pDialog->IsConfirmed())
688     {
689       CFileItemList items;
690       CDirectory::GetDirectory(pItem->GetPath(),items,"",DIR_FLAG_NO_FILE_DIRS);
691       for (int i=0;i<items.Size();++i)
692         OnDeleteItem(items[i]);
693
694       CVideoDatabaseDirectory dir;
695       CQueryParams params;
696       dir.GetQueryParams(pItem->GetPath(),params);
697       m_database.DeleteSet(params.GetSetId());
698     }
699   }
700   else if (m_vecItems->GetContent() == "tags" && pItem->m_bIsFolder)
701   {
702     CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
703     pDialog->SetHeading(432);
704     CStdString strLabel;
705     strLabel.Format(g_localizeStrings.Get(433), pItem->GetLabel());
706     pDialog->SetLine(1, strLabel);
707     pDialog->SetLine(2, "");
708     pDialog->DoModal();
709     if (pDialog->IsConfirmed())
710     {
711       CVideoDatabaseDirectory dir;
712       CQueryParams params;
713       dir.GetQueryParams(pItem->GetPath(), params);
714       m_database.DeleteTag(params.GetTagId(), (VIDEODB_CONTENT_TYPE)params.GetContentType());
715     }
716   }
717   else if (m_vecItems->GetPath().Equals(CUtil::VideoPlaylistsLocation()) ||
718            m_vecItems->GetPath().Equals("special://videoplaylists/"))
719   {
720     pItem->m_bIsFolder = false;
721     CFileUtils::DeleteItem(pItem);
722   }
723   else
724   {
725     if (!DeleteItem(pItem.get()))
726       return;
727
728     CStdString strDeletePath;
729     if (pItem->m_bIsFolder)
730       strDeletePath=pItem->GetVideoInfoTag()->m_strPath;
731     else
732       strDeletePath=pItem->GetVideoInfoTag()->m_strFileNameAndPath;
733
734     if (URIUtils::GetFileName(strDeletePath).Equals("VIDEO_TS.IFO"))
735     {
736       strDeletePath = URIUtils::GetDirectory(strDeletePath);
737       if (StringUtils::EndsWithNoCase(strDeletePath, "video_ts/"))
738       {
739         URIUtils::RemoveSlashAtEnd(strDeletePath);
740         strDeletePath = URIUtils::GetDirectory(strDeletePath);
741       }
742     }
743     if (URIUtils::HasSlashAtEnd(strDeletePath))
744       pItem->m_bIsFolder=true;
745
746     if (CSettings::Get().GetBool("filelists.allowfiledeletion") &&
747         CUtil::SupportsWriteFileOperations(strDeletePath))
748     {
749       pItem->SetPath(strDeletePath);
750       CGUIWindowVideoBase::OnDeleteItem(pItem);
751     }
752   }
753
754   CUtil::DeleteVideoDatabaseDirectoryCache();
755 }
756
757 bool CGUIWindowVideoNav::DeleteItem(CFileItem* pItem, bool bUnavailable /* = false */)
758 {
759   if (!pItem->HasVideoInfoTag() || !CanDelete(pItem->GetPath()))
760     return false;
761
762   VIDEODB_CONTENT_TYPE iType=VIDEODB_CONTENT_MOVIES;
763   if (pItem->HasVideoInfoTag() && !pItem->GetVideoInfoTag()->m_strShowTitle.IsEmpty())
764     iType = VIDEODB_CONTENT_TVSHOWS;
765   if (pItem->HasVideoInfoTag() && pItem->GetVideoInfoTag()->m_iSeason > -1 && !pItem->m_bIsFolder)
766     iType = VIDEODB_CONTENT_EPISODES;
767   if (pItem->HasVideoInfoTag() && !pItem->GetVideoInfoTag()->m_artist.empty())
768     iType = VIDEODB_CONTENT_MUSICVIDEOS;
769
770   // dont allow update while scanning
771   if (g_application.IsVideoScanning())
772   {
773     CGUIDialogOK::ShowAndGetInput(257, 0, 14057, 0);
774     return false;
775   }
776
777
778   CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
779   if (!pDialog)
780     return false;
781   if (iType == VIDEODB_CONTENT_MOVIES)
782     pDialog->SetHeading(432);
783   if (iType == VIDEODB_CONTENT_EPISODES)
784     pDialog->SetHeading(20362);
785   if (iType == VIDEODB_CONTENT_TVSHOWS)
786     pDialog->SetHeading(20363);
787   if (iType == VIDEODB_CONTENT_MUSICVIDEOS)
788     pDialog->SetHeading(20392);
789
790   if(bUnavailable)
791   {
792     pDialog->SetLine(0, g_localizeStrings.Get(662));
793     pDialog->SetLine(1, g_localizeStrings.Get(663));
794     pDialog->SetLine(2, "");;
795     pDialog->DoModal();
796   }
797   else
798   {
799     CStdString strLine;
800     strLine.Format(g_localizeStrings.Get(433),pItem->GetLabel());
801     pDialog->SetLine(0, strLine);
802     pDialog->SetLine(1, "");
803     pDialog->SetLine(2, "");;
804     pDialog->DoModal();
805   }
806
807   if (!pDialog->IsConfirmed())
808     return false;
809
810   CStdString path;
811   CVideoDatabase database;
812   database.Open();
813
814   database.GetFilePathById(pItem->GetVideoInfoTag()->m_iDbId, path, iType);
815   if (path.IsEmpty())
816     return false;
817   if (iType == VIDEODB_CONTENT_MOVIES)
818     database.DeleteMovie(path);
819   if (iType == VIDEODB_CONTENT_EPISODES)
820     database.DeleteEpisode(path, pItem->GetVideoInfoTag()->m_iDbId);
821   if (iType == VIDEODB_CONTENT_TVSHOWS)
822     database.DeleteTvShow(path);
823   if (iType == VIDEODB_CONTENT_MUSICVIDEOS)
824     database.DeleteMusicVideo(path);
825
826   if (iType == VIDEODB_CONTENT_TVSHOWS)
827     database.SetPathHash(path,"");
828   else
829     database.SetPathHash(URIUtils::GetDirectory(path), "");
830
831   return true;
832 }
833
834 void CGUIWindowVideoNav::OnPrepareFileItems(CFileItemList &items)
835 {
836   CGUIWindowVideoBase::OnPrepareFileItems(items);
837 }
838
839 void CGUIWindowVideoNav::GetContextButtons(int itemNumber, CContextButtons &buttons)
840 {
841   CFileItemPtr item;
842   if (itemNumber >= 0 && itemNumber < m_vecItems->Size())
843     item = m_vecItems->Get(itemNumber);
844
845   CGUIWindowVideoBase::GetContextButtons(itemNumber, buttons);
846
847   if (item && item->GetProperty("pluginreplacecontextitems").asBoolean())
848     return;
849
850   CVideoDatabaseDirectory dir;
851   NODE_TYPE node = dir.GetDirectoryChildType(m_vecItems->GetPath());
852
853   if (!item)
854   {
855     // nothing to do here
856   }
857   else if (m_vecItems->GetPath().Equals("sources://video/"))
858   {
859     // get the usual shares
860     CGUIDialogContextMenu::GetContextButtons("video", item, buttons);
861     // add scan button somewhere here
862     if (g_application.IsVideoScanning())
863       buttons.Add(CONTEXT_BUTTON_STOP_SCANNING, 13353);  // Stop Scanning
864     if (!item->IsDVD() && item->GetPath() != "add" && !item->IsParentFolder() &&
865         (CProfilesManager::Get().GetCurrentProfile().canWriteDatabases() || g_passwordManager.bMasterUser))
866     {
867       CVideoDatabase database;
868       database.Open();
869       ADDON::ScraperPtr info = database.GetScraperForPath(item->GetPath());
870
871       if (!g_application.IsVideoScanning())
872       {
873         if (!item->IsLiveTV() && !item->IsPlugin() && !item->IsAddonsPath() && !URIUtils::IsUPnP(item->GetPath()))
874         {
875           if (info && info->Content() != CONTENT_NONE)
876             buttons.Add(CONTEXT_BUTTON_SET_CONTENT, 20442);
877           else
878             buttons.Add(CONTEXT_BUTTON_SET_CONTENT, 20333);
879         }
880       }
881
882       if (info && !g_application.IsVideoScanning())
883         buttons.Add(CONTEXT_BUTTON_SCAN, 13349);
884     }
885   }
886   else
887   {
888     // are we in the playlists location?
889     bool inPlaylists = m_vecItems->GetPath().Equals(CUtil::VideoPlaylistsLocation()) ||
890                        m_vecItems->GetPath().Equals("special://videoplaylists/");
891
892     if (item->HasVideoInfoTag() && !item->GetVideoInfoTag()->m_artist.empty())
893     {
894       CMusicDatabase database;
895       database.Open();
896       if (database.GetArtistByName(StringUtils::Join(item->GetVideoInfoTag()->m_artist, g_advancedSettings.m_videoItemSeparator)) > -1)
897         buttons.Add(CONTEXT_BUTTON_GO_TO_ARTIST, 20396);
898     }
899     if (item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_strAlbum.size() > 0)
900     {
901       CMusicDatabase database;
902       database.Open();
903       if (database.GetAlbumByName(item->GetVideoInfoTag()->m_strAlbum) > -1)
904         buttons.Add(CONTEXT_BUTTON_GO_TO_ALBUM, 20397);
905     }
906     if (item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_strAlbum.size() > 0 &&
907         item->GetVideoInfoTag()->m_artist.size() > 0                              &&
908         item->GetVideoInfoTag()->m_strTitle.size() > 0)
909     {
910       CMusicDatabase database;
911       database.Open();
912       if (database.GetSongByArtistAndAlbumAndTitle(StringUtils::Join(item->GetVideoInfoTag()->m_artist, g_advancedSettings.m_videoItemSeparator),
913                                                    item->GetVideoInfoTag()->m_strAlbum,
914                                                    item->GetVideoInfoTag()->m_strTitle) > -1)
915       {
916         buttons.Add(CONTEXT_BUTTON_PLAY_OTHER, 20398);
917       }
918     }
919     if (!item->IsParentFolder())
920     {
921       ADDON::ScraperPtr info;
922       VIDEO::SScanSettings settings;
923       GetScraperForItem(item.get(), info, settings);
924
925       if (info && info->Content() == CONTENT_TVSHOWS)
926         buttons.Add(CONTEXT_BUTTON_INFO, item->m_bIsFolder ? 20351 : 20352);
927       else if (info && info->Content() == CONTENT_MUSICVIDEOS)
928         buttons.Add(CONTEXT_BUTTON_INFO,20393);
929       else if (info && info->Content() == CONTENT_MOVIES)
930         buttons.Add(CONTEXT_BUTTON_INFO, 13346);
931
932       // can we update the database?
933       if (CProfilesManager::Get().GetCurrentProfile().canWriteDatabases() || g_passwordManager.bMasterUser)
934       {
935         if (node == NODE_TYPE_TITLE_TVSHOWS)
936         {
937           if (g_application.IsVideoScanning())
938             buttons.Add(CONTEXT_BUTTON_STOP_SCANNING, 13353);
939           else
940             buttons.Add(CONTEXT_BUTTON_SCAN, 13349);
941         }
942         if (!item->IsPlugin() && !item->IsScript() && !item->IsLiveTV() && !item->IsAddonsPath() &&
943             item->GetPath() != "sources://video/" && item->GetPath() != "special://videoplaylists/" &&
944             item->GetPath().Left(19) != "newsmartplaylist://" && item->GetPath().Left(14) != "newplaylist://" &&
945             item->GetPath().Left(9) != "newtag://")
946         {
947           if (item->m_bIsFolder)
948           {
949             // Have both options for folders since we don't know whether all childs are watched/unwatched
950             buttons.Add(CONTEXT_BUTTON_MARK_UNWATCHED, 16104); //Mark as UnWatched
951             buttons.Add(CONTEXT_BUTTON_MARK_WATCHED, 16103);   //Mark as Watched
952           }
953           else
954           {
955             if (item->GetOverlayImage().Equals("OverlayWatched.png"))
956               buttons.Add(CONTEXT_BUTTON_MARK_UNWATCHED, 16104); //Mark as UnWatched
957             else
958               buttons.Add(CONTEXT_BUTTON_MARK_WATCHED, 16103);   //Mark as Watched
959           }
960         }
961         if (!g_application.IsVideoScanning() && item->IsVideoDb() && item->HasVideoInfoTag() &&
962            (!item->m_bIsFolder || m_vecItems->GetContent().Equals("movies") || m_vecItems->GetContent().Equals("tvshows")))
963         {
964           buttons.Add(CONTEXT_BUTTON_EDIT, 16106);
965         }
966
967         if (node == NODE_TYPE_SEASONS && item->m_bIsFolder)
968           buttons.Add(CONTEXT_BUTTON_SET_SEASON_ART, 13511);
969
970         if (StringUtils::StartsWithNoCase(item->GetPath(), "videodb://movies/sets/") && item->GetPath().size() > 22 && item->m_bIsFolder) // sets
971         {
972           buttons.Add(CONTEXT_BUTTON_SET_MOVIESET_ART, 13511);
973           buttons.Add(CONTEXT_BUTTON_MOVIESET_ADD_REMOVE_ITEMS, 20465);
974           buttons.Add(CONTEXT_BUTTON_DELETE, 646);
975         }
976
977         if (m_vecItems->GetContent() == "tags" && item->m_bIsFolder) // tags
978         {
979           CVideoDbUrl videoUrl;
980           if (videoUrl.FromString(item->GetPath()))
981           {
982             std::string mediaType = videoUrl.GetItemType();
983
984             CStdString strLabelAdd; strLabelAdd.Format(g_localizeStrings.Get(20460), GetLocalizedType(videoUrl.GetItemType()).c_str());
985             CStdString strLabelRemove; strLabelRemove.Format(g_localizeStrings.Get(20461), GetLocalizedType(videoUrl.GetItemType()).c_str());
986             buttons.Add(CONTEXT_BUTTON_TAGS_ADD_ITEMS, strLabelAdd);
987             buttons.Add(CONTEXT_BUTTON_TAGS_REMOVE_ITEMS, strLabelRemove);
988             buttons.Add(CONTEXT_BUTTON_DELETE, 646);
989           }
990         }
991
992         if (node == NODE_TYPE_ACTOR && !dir.IsAllItem(item->GetPath()) && item->m_bIsFolder)
993         {
994           if (StringUtils::StartsWithNoCase(m_vecItems->GetPath(), "videodb://musicvideos")) // mvids
995             buttons.Add(CONTEXT_BUTTON_SET_ARTIST_THUMB, 13359);
996           else
997             buttons.Add(CONTEXT_BUTTON_SET_ACTOR_THUMB, 20403);
998         }
999         if (item->IsVideoDb() && item->HasVideoInfoTag() &&
1000           (!item->m_bIsFolder || node == NODE_TYPE_TITLE_TVSHOWS))
1001           buttons.Add(CONTEXT_BUTTON_DELETE, 646);
1002       }
1003
1004       if (!m_vecItems->IsVideoDb() && !m_vecItems->IsVirtualDirectoryRoot())
1005       { // non-video db items, file operations are allowed
1006         if ((CSettings::Get().GetBool("filelists.allowfiledeletion") &&
1007             CUtil::SupportsWriteFileOperations(item->GetPath())) ||
1008             (inPlaylists && !URIUtils::GetFileName(item->GetPath()).Equals("PartyMode-Video.xsp")
1009                          && (item->IsPlayList() || item->IsSmartPlayList())))
1010         {
1011           buttons.Add(CONTEXT_BUTTON_DELETE, 117);
1012           buttons.Add(CONTEXT_BUTTON_RENAME, 118);
1013         }
1014         // add "Set/Change content" to folders
1015         if (item->m_bIsFolder && !item->IsVideoDb() && !item->IsPlayList() && !item->IsSmartPlayList() && !item->IsLibraryFolder() && !item->IsLiveTV() && !item->IsPlugin() && !item->IsAddonsPath() && !URIUtils::IsUPnP(item->GetPath()))
1016         {
1017           if (!g_application.IsVideoScanning())
1018           {
1019             if (info && info->Content() != CONTENT_NONE)
1020             {
1021               buttons.Add(CONTEXT_BUTTON_SET_CONTENT, 20442);
1022               buttons.Add(CONTEXT_BUTTON_SCAN, 13349);
1023             }
1024             else
1025               buttons.Add(CONTEXT_BUTTON_SET_CONTENT, 20333);
1026           }
1027         }
1028       }
1029       if (item->IsPlugin() || item->IsScript() || m_vecItems->IsPlugin())
1030         buttons.Add(CONTEXT_BUTTON_PLUGIN_SETTINGS, 1045);
1031     }
1032   }
1033 }
1034
1035 // predicate used by sorting and set_difference
1036 bool compFileItemsByDbId(const CFileItemPtr& lhs, const CFileItemPtr& rhs) 
1037 {
1038   return lhs->HasVideoInfoTag() && rhs->HasVideoInfoTag() && lhs->GetVideoInfoTag()->m_iDbId < rhs->GetVideoInfoTag()->m_iDbId;
1039 }
1040
1041 bool CGUIWindowVideoNav::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
1042 {
1043   CFileItemPtr item;
1044   if (itemNumber >= 0 && itemNumber < m_vecItems->Size())
1045     item = m_vecItems->Get(itemNumber);
1046   if (CGUIDialogContextMenu::OnContextButton("video", item, button))
1047   {
1048     //TODO should we search DB for entries from plugins?
1049     if (button == CONTEXT_BUTTON_REMOVE_SOURCE && !item->IsPlugin()
1050         && !item->IsLiveTV() &&!item->IsRSS() && !URIUtils::IsUPnP(item->GetPath()))
1051     {
1052       OnUnAssignContent(item->GetPath(),20375,20340,20341);
1053     }
1054     Refresh();
1055     return true;
1056   }
1057   switch (button)
1058   {
1059   case CONTEXT_BUTTON_EDIT:
1060     {
1061       CONTEXT_BUTTON ret = (CONTEXT_BUTTON)CGUIDialogVideoInfo::ManageVideoItem(item);
1062       if (ret >= 0)
1063       {
1064         if (ret == CONTEXT_BUTTON_MARK_WATCHED)
1065           m_viewControl.SetSelectedItem(itemNumber + 1);
1066
1067         Refresh(true);
1068       }
1069       return true;
1070     }
1071
1072   case CONTEXT_BUTTON_SET_SEASON_ART:
1073   case CONTEXT_BUTTON_SET_ACTOR_THUMB:
1074   case CONTEXT_BUTTON_SET_ARTIST_THUMB:
1075   case CONTEXT_BUTTON_SET_MOVIESET_ART:
1076     {
1077       // Grab the thumbnails from the web
1078       CFileItemList items;
1079       CFileItemPtr noneitem(new CFileItem("thumb://None", false));
1080       CStdString currentThumb;
1081       int idArtist = -1;
1082       CStdString artistPath;
1083       string artType = "thumb";
1084       if (button == CONTEXT_BUTTON_SET_ARTIST_THUMB)
1085       {
1086         CMusicDatabase database;
1087         database.Open();
1088         idArtist = database.GetArtistByName(m_vecItems->Get(itemNumber)->GetLabel());
1089         database.GetArtistPath(idArtist, artistPath);
1090         currentThumb = database.GetArtForItem(idArtist, "artist", "thumb");
1091         if (currentThumb.empty())
1092           currentThumb = m_database.GetArtForItem(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_iDbId, m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_type, artType);
1093       }
1094       else if (button == CONTEXT_BUTTON_SET_ACTOR_THUMB)
1095         currentThumb = m_database.GetArtForItem(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_iDbId, m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_type, artType);
1096       else
1097       { // SEASON, SET
1098         map<string, string> currentArt;
1099         artType = CGUIDialogVideoInfo::ChooseArtType(*m_vecItems->Get(itemNumber), currentArt);
1100         if (artType.empty())
1101           return false;
1102
1103         if (artType == "fanart")
1104         {
1105           OnChooseFanart(*m_vecItems->Get(itemNumber));
1106           return true;
1107         }
1108
1109         if (currentArt.find(artType) != currentArt.end())
1110           currentThumb = currentArt[artType];
1111         else if ((artType == "poster" || artType == "banner") && currentArt.find("thumb") != currentArt.end())
1112           currentThumb = currentArt["thumb"];
1113       }
1114       if (!currentThumb.IsEmpty())
1115       {
1116         CFileItemPtr item(new CFileItem("thumb://Current", false));
1117         item->SetArt("thumb", currentThumb);
1118         item->SetLabel(g_localizeStrings.Get(13512));
1119         items.Add(item);
1120       }
1121       noneitem->SetIconImage("DefaultFolder.png");
1122       noneitem->SetLabel(g_localizeStrings.Get(13515));
1123
1124       vector<CStdString> thumbs;
1125       if (button != CONTEXT_BUTTON_SET_ARTIST_THUMB)
1126       {
1127         CVideoInfoTag tag;
1128         if (button == CONTEXT_BUTTON_SET_SEASON_ART)
1129           m_database.GetTvShowInfo("",tag,m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_iIdShow);
1130         else
1131           tag = *m_vecItems->Get(itemNumber)->GetVideoInfoTag();
1132         if (button == CONTEXT_BUTTON_SET_SEASON_ART)
1133           tag.m_strPictureURL.GetThumbURLs(thumbs, artType, m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_iSeason);
1134         else
1135           tag.m_strPictureURL.GetThumbURLs(thumbs, artType);
1136
1137         for (unsigned int i = 0; i < thumbs.size(); i++)
1138         {
1139           CStdString strItemPath;
1140           strItemPath.Format("thumb://Remote%i",i);
1141           CFileItemPtr item(new CFileItem(strItemPath, false));
1142           item->SetArt("thumb", thumbs[i]);
1143           item->SetIconImage("DefaultPicture.png");
1144           item->SetLabel(g_localizeStrings.Get(13513));
1145           items.Add(item);
1146
1147           // TODO: Do we need to clear the cached image?
1148           //    CTextureCache::Get().ClearCachedImage(thumbs[i]);
1149         }
1150       }
1151
1152       bool local=false;
1153       if (button == CONTEXT_BUTTON_SET_ARTIST_THUMB)
1154       {
1155         CStdString strThumb = URIUtils::AddFileToFolder(artistPath, "folder.jpg");
1156         if (XFILE::CFile::Exists(strThumb))
1157         {
1158           CFileItemPtr pItem(new CFileItem(strThumb,false));
1159           pItem->SetLabel(g_localizeStrings.Get(13514));
1160           pItem->SetArt("thumb", strThumb);
1161           items.Add(pItem);
1162           local = true;
1163         }
1164         else
1165           noneitem->SetIconImage("DefaultArtist.png");
1166       }
1167
1168       if (button == CONTEXT_BUTTON_SET_ACTOR_THUMB)
1169       {
1170         CStdString picturePath;
1171         CStdString strThumb = URIUtils::AddFileToFolder(picturePath, "folder.jpg");
1172         if (XFILE::CFile::Exists(strThumb))
1173         {
1174           CFileItemPtr pItem(new CFileItem(strThumb,false));
1175           pItem->SetLabel(g_localizeStrings.Get(13514));
1176           pItem->SetArt("thumb", strThumb);
1177           items.Add(pItem);
1178           local = true;
1179         }
1180         else
1181           noneitem->SetIconImage("DefaultActor.png");
1182       }
1183
1184       if (button == CONTEXT_BUTTON_SET_MOVIESET_ART)
1185         noneitem->SetIconImage("DefaultVideo.png");
1186
1187       if (!local)
1188         items.Add(noneitem);
1189
1190       VECSOURCES sources=*CMediaSourceSettings::Get().GetSources("video");
1191       g_mediaManager.GetLocalDrives(sources);
1192       CStdString result;
1193       CGUIDialogVideoInfo::AddItemPathToFileBrowserSources(sources, *item);
1194       if (!CGUIDialogFileBrowser::ShowAndGetImage(items, sources,
1195                                                   g_localizeStrings.Get(13511), result))
1196       {
1197         return false;   // user cancelled
1198       }
1199
1200       if (result == "thumb://Current")
1201         result = currentThumb;   // user chose the one they have
1202
1203       // delete the thumbnail if that's what the user wants, else overwrite with the
1204       // new thumbnail
1205       if (result.Left(14) == "thumb://Remote")
1206       {
1207         int number = atoi(result.Mid(14));
1208         result = thumbs[number];
1209       }
1210       else if (result == "thumb://None")
1211         result.clear();
1212       if (button == CONTEXT_BUTTON_SET_MOVIESET_ART ||
1213           button == CONTEXT_BUTTON_SET_ACTOR_THUMB ||
1214           button == CONTEXT_BUTTON_SET_SEASON_ART ||
1215          (button == CONTEXT_BUTTON_SET_ARTIST_THUMB && idArtist < 0))
1216         m_database.SetArtForItem(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_iDbId, m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_type, artType, result);
1217       else
1218       {
1219         CMusicDatabase db;
1220         if (db.Open())
1221           db.SetArtForItem(idArtist, "artist", artType, result);
1222       }
1223
1224       CUtil::DeleteVideoDatabaseDirectoryCache();
1225       CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_REFRESH_THUMBS);
1226       g_windowManager.SendMessage(msg);
1227       Refresh();
1228
1229       return true;
1230     }
1231   case CONTEXT_BUTTON_TAGS_ADD_ITEMS:
1232     {
1233       CVideoDbUrl videoUrl;
1234       if (!videoUrl.FromString(item->GetPath()))
1235         return false;
1236       
1237       std::string mediaType = videoUrl.GetItemType();
1238       mediaType = mediaType.substr(0, mediaType.length() - 1);
1239
1240       CFileItemList items;
1241       CStdString localizedType = GetLocalizedType(mediaType);
1242       CStdString strLabel; strLabel.Format(g_localizeStrings.Get(20464), localizedType.c_str());
1243       if (!GetItemsForTag(strLabel, mediaType, items, item->GetVideoInfoTag()->m_iDbId))
1244         return true;
1245
1246       CVideoDatabase videodb;
1247       if (!videodb.Open())
1248         return true;
1249
1250       for (int index = 0; index < items.Size(); index++)
1251       {
1252         if (!items[index]->HasVideoInfoTag() || items[index]->GetVideoInfoTag()->m_iDbId <= 0)
1253           continue;
1254
1255         videodb.AddTagToItem(items[index]->GetVideoInfoTag()->m_iDbId, item->GetVideoInfoTag()->m_iDbId, mediaType);
1256       }
1257
1258       // we need to clear any cached version of this tag's listing
1259       items.SetPath(item->GetPath());
1260       items.RemoveDiscCache(GetID());
1261       return true;
1262     }
1263   case CONTEXT_BUTTON_TAGS_REMOVE_ITEMS:
1264     {
1265       CVideoDbUrl videoUrl;
1266       if (!videoUrl.FromString(item->GetPath()))
1267         return false;
1268       
1269       std::string mediaType = videoUrl.GetItemType();
1270       mediaType = mediaType.substr(0, mediaType.length() - 1);
1271
1272       CFileItemList items;
1273       CStdString localizedType = GetLocalizedType(mediaType);
1274       CStdString strLabel; strLabel.Format(g_localizeStrings.Get(20464), localizedType.c_str());
1275       if (!GetItemsForTag(strLabel, mediaType, items, item->GetVideoInfoTag()->m_iDbId, false))
1276         return true;
1277
1278       CVideoDatabase videodb;
1279       if (!videodb.Open())
1280         return true;
1281
1282       for (int index = 0; index < items.Size(); index++)
1283       {
1284         if (!items[index]->HasVideoInfoTag() || items[index]->GetVideoInfoTag()->m_iDbId <= 0)
1285           continue;
1286
1287         videodb.RemoveTagFromItem(items[index]->GetVideoInfoTag()->m_iDbId, item->GetVideoInfoTag()->m_iDbId, mediaType);
1288       }
1289
1290       // we need to clear any cached version of this tag's listing
1291       items.SetPath(item->GetPath());
1292       items.RemoveDiscCache(GetID());
1293       return true;
1294     }
1295   case CONTEXT_BUTTON_MOVIESET_ADD_REMOVE_ITEMS:
1296     {
1297       CFileItemList originalItems;
1298       CFileItemList selectedItems;
1299
1300       if (!CGUIDialogVideoInfo::GetMoviesForSet(item.get(), originalItems, selectedItems) || selectedItems.Size() == 0) // need at least one item selected
1301         return true;
1302       VECFILEITEMS original = originalItems.GetList();
1303       std::sort(original.begin(), original.end(), compFileItemsByDbId);
1304       VECFILEITEMS selected = selectedItems.GetList();
1305       std::sort(selected.begin(), selected.end(), compFileItemsByDbId);
1306
1307       bool refreshNeeded = false;
1308       // update the "added" items
1309       VECFILEITEMS addedItems;
1310       set_difference(selected.begin(),selected.end(), original.begin(),original.end(), std::back_inserter(addedItems), compFileItemsByDbId);
1311       for (VECFILEITEMS::iterator it = addedItems.begin();  it != addedItems.end(); ++it)
1312       {
1313         if (CGUIDialogVideoInfo::SetMovieSet(it->get(), item.get()))
1314           refreshNeeded = true;
1315       }
1316       // update the "deleted" items
1317       CFileItemPtr clearItem(new CFileItem());
1318       clearItem->GetVideoInfoTag()->m_iDbId = -1; // -1 will be used to clear set
1319       VECFILEITEMS deletedItems;
1320       set_difference(original.begin(),original.end(), selected.begin(),selected.end(), std::back_inserter(deletedItems), compFileItemsByDbId);
1321       for (VECFILEITEMS::iterator it = deletedItems.begin();  it != deletedItems.end(); ++it)
1322       {
1323         if (CGUIDialogVideoInfo::SetMovieSet(it->get(), clearItem.get()))
1324           refreshNeeded = true;
1325       }
1326
1327       // we need to clear any cached version of this tag's listing
1328       if (refreshNeeded) 
1329         Refresh();
1330       return true;
1331     }
1332   case CONTEXT_BUTTON_GO_TO_ARTIST:
1333     {
1334       CStdString strPath;
1335       CMusicDatabase database;
1336       database.Open();
1337       strPath.Format("musicdb://artists/%ld/",database.GetArtistByName(StringUtils::Join(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_artist, g_advancedSettings.m_videoItemSeparator)));
1338       g_windowManager.ActivateWindow(WINDOW_MUSIC_NAV,strPath);
1339       return true;
1340     }
1341   case CONTEXT_BUTTON_GO_TO_ALBUM:
1342     {
1343       CStdString strPath;
1344       CMusicDatabase database;
1345       database.Open();
1346       strPath.Format("musicdb://albums/%ld/",database.GetAlbumByName(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strAlbum));
1347       g_windowManager.ActivateWindow(WINDOW_MUSIC_NAV,strPath);
1348       return true;
1349     }
1350   case CONTEXT_BUTTON_PLAY_OTHER:
1351     {
1352       CMusicDatabase database;
1353       database.Open();
1354       CSong song;
1355       if (database.GetSong(database.GetSongByArtistAndAlbumAndTitle(StringUtils::Join(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_artist, g_advancedSettings.m_videoItemSeparator),m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strAlbum,
1356                                                                         m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strTitle),
1357                                                                         song))
1358       {
1359         CApplicationMessenger::Get().PlayFile(song);
1360       }
1361       return true;
1362     }
1363
1364   default:
1365     break;
1366
1367   }
1368   return CGUIWindowVideoBase::OnContextButton(itemNumber, button);
1369 }
1370
1371 void CGUIWindowVideoNav::OnChooseFanart(const CFileItem &videoItem)
1372 {
1373   if (!videoItem.HasVideoInfoTag())
1374     return;
1375
1376   CFileItem item(videoItem);
1377
1378   CFileItemList items;
1379
1380   CVideoThumbLoader loader;
1381   loader.LoadItem(&item);
1382
1383   if (item.HasArt("fanart"))
1384   {
1385     CFileItemPtr itemCurrent(new CFileItem("fanart://Current",false));
1386     itemCurrent->SetArt("thumb", item.GetArt("fanart"));
1387     itemCurrent->SetLabel(g_localizeStrings.Get(20440));
1388     items.Add(itemCurrent);
1389   }
1390
1391   // add the none option
1392   {
1393     CFileItemPtr itemNone(new CFileItem("fanart://None", false));
1394     itemNone->SetIconImage("DefaultVideo.png");
1395     itemNone->SetLabel(g_localizeStrings.Get(20439));
1396     items.Add(itemNone);
1397   }
1398
1399   CStdString result;
1400   VECSOURCES sources(*CMediaSourceSettings::Get().GetSources("video"));
1401   g_mediaManager.GetLocalDrives(sources);
1402   CGUIDialogVideoInfo::AddItemPathToFileBrowserSources(sources, item);
1403   bool flip=false;
1404   if (!CGUIDialogFileBrowser::ShowAndGetImage(items, sources, g_localizeStrings.Get(20437), result, &flip, 20445) || result.Equals("fanart://Current"))
1405     return;
1406
1407   if (result.Equals("fanart://None") || !CFile::Exists(result))
1408     result.clear();
1409   if (!result.IsEmpty() && flip)
1410     result = CTextureUtils::GetWrappedImageURL(result, "", "flipped");
1411
1412   // update the db
1413   CVideoDatabase db;
1414   if (db.Open())
1415   {
1416     db.SetArtForItem(item.GetVideoInfoTag()->m_iDbId, item.GetVideoInfoTag()->m_type, "fanart", result);
1417     db.Close();
1418   }
1419
1420   // clear view cache and reload images
1421   CUtil::DeleteVideoDatabaseDirectoryCache();
1422
1423   Refresh();
1424 }
1425
1426 bool CGUIWindowVideoNav::OnClick(int iItem)
1427 {
1428   CFileItemPtr item = m_vecItems->Get(iItem);
1429   if (!item->m_bIsFolder && item->IsVideoDb() && !item->Exists())
1430   {
1431     CLog::Log(LOGDEBUG, "%s called on '%s' but file doesn't exist", __FUNCTION__, item->GetPath().c_str());
1432     if (!DeleteItem(item.get(), true))
1433       return true;
1434
1435     // update list
1436     Refresh(true);
1437     m_viewControl.SetSelectedItem(iItem);
1438     return true;
1439   }
1440   else if (StringUtils::StartsWithNoCase(item->GetPath(), "newtag://"))
1441   {
1442     // dont allow update while scanning
1443     if (g_application.IsVideoScanning())
1444     {
1445       CGUIDialogOK::ShowAndGetInput(257, 0, 14057, 0);
1446       return true;
1447     }
1448
1449     //Get the new title
1450     CStdString strTag;
1451     if (!CGUIKeyboardFactory::ShowAndGetInput(strTag, g_localizeStrings.Get(20462), false))
1452       return true;
1453
1454     CVideoDatabase videodb;
1455     if (!videodb.Open())
1456       return true;
1457
1458     // get the media type and convert from plural to singular (by removing the trailing "s")
1459     CStdString mediaType = item->GetPath().Mid(9);
1460     mediaType = mediaType.Left(mediaType.size() - 1);
1461     CStdString localizedType = GetLocalizedType(mediaType);
1462     if (localizedType.empty())
1463       return true;
1464
1465     if (!videodb.GetSingleValue("tag", "tag.idTag", videodb.PrepareSQL("tag.strTag = '%s' AND tag.idTag IN (SELECT taglinks.idTag FROM taglinks WHERE taglinks.media_type = '%s')", strTag.c_str(), mediaType.c_str())).empty())
1466     {
1467       CStdString strError; strError.Format(g_localizeStrings.Get(20463), strTag.c_str());
1468       CGUIDialogOK::ShowAndGetInput(20462, "", strError, "");
1469       return true;
1470     }
1471
1472     int idTag = videodb.AddTag(strTag);
1473     CFileItemList items;
1474     CStdString strLabel; strLabel.Format(g_localizeStrings.Get(20464), localizedType.c_str());
1475     if (GetItemsForTag(strLabel, mediaType, items, idTag))
1476     {
1477       for (int index = 0; index < items.Size(); index++)
1478       {
1479         if (!items[index]->HasVideoInfoTag() || items[index]->GetVideoInfoTag()->m_iDbId <= 0)
1480           continue;
1481
1482         videodb.AddTagToItem(items[index]->GetVideoInfoTag()->m_iDbId, idTag, mediaType);
1483       }
1484     }
1485
1486     Refresh(true);
1487     return true;
1488   }
1489
1490   return CGUIWindowVideoBase::OnClick(iItem);
1491 }
1492
1493 CStdString CGUIWindowVideoNav::GetStartFolder(const CStdString &dir)
1494 {
1495   if (dir.Equals("MovieGenres"))
1496     return "videodb://movies/genres/";
1497   else if (dir.Equals("MovieTitles"))
1498     return "videodb://movies/titles/";
1499   else if (dir.Equals("MovieYears"))
1500     return "videodb://movies/years/";
1501   else if (dir.Equals("MovieActors"))
1502     return "videodb://movies/actors/";
1503   else if (dir.Equals("MovieDirectors"))
1504     return "videodb://movies/directors/";
1505   else if (dir.Equals("MovieStudios"))
1506     return "videodb://movies/studios/";
1507   else if (dir.Equals("MovieSets"))
1508     return "videodb://movies/sets/";
1509   else if (dir.Equals("MovieCountries"))
1510     return "videodb://movies/countries/";
1511   else if (dir.Equals("MovieTags"))
1512     return "videodb://movies/tags/";
1513   else if (dir.Equals("Movies"))
1514     return "videodb://movies/";
1515   else if (dir.Equals("TvShowGenres"))
1516     return "videodb://tvshows/genres/";
1517   else if (dir.Equals("TvShowTitles"))
1518     return "videodb://tvshows/titles/";
1519   else if (dir.Equals("TvShowYears"))
1520     return "videodb://tvshows/years/";
1521   else if (dir.Equals("TvShowActors"))
1522     return "videodb://tvshows/actors/";
1523   else if (dir.Equals("TvShowStudios"))
1524     return "videodb://tvshows/studios/";
1525   else if (dir.Equals("TvShowTags"))
1526     return "videodb://tvshows/tags/";
1527   else if (dir.Equals("TvShows"))
1528     return "videodb://tvshows/";
1529   else if (dir.Equals("MusicVideoGenres"))
1530     return "videodb://musicvideos/genres/";
1531   else if (dir.Equals("MusicVideoTitles"))
1532     return "videodb://musicvideos/titles/";
1533   else if (dir.Equals("MusicVideoYears"))
1534     return "videodb://musicvideos/years/";
1535   else if (dir.Equals("MusicVideoArtists"))
1536     return "videodb://musicvideos/artists/";
1537   else if (dir.Equals("MusicVideoAlbums"))
1538     return "videodb://musicvideos/albums/";
1539   else if (dir.Equals("MusicVideoDirectors"))
1540     return "videodb://musicvideos/directors/";
1541   else if (dir.Equals("MusicVideoStudios"))
1542     return "videodb://musicvideos/studios/";
1543   else if (dir.Equals("MusicVideoTags"))
1544     return "videodb://musicvideos/tags/";
1545   else if (dir.Equals("MusicVideos"))
1546     return "videodb://musicvideos/";
1547   else if (dir.Equals("RecentlyAddedMovies"))
1548     return "videodb://recentlyaddedmovies/";
1549   else if (dir.Equals("RecentlyAddedEpisodes"))
1550     return "videodb://recentlyaddedepisodes/";
1551   else if (dir.Equals("RecentlyAddedMusicVideos"))
1552     return "videodb://recentlyaddedmusicvideos/";
1553   else if (dir.Equals("Files"))
1554     return "sources://video/";
1555   return CGUIWindowVideoBase::GetStartFolder(dir);
1556 }
1557
1558 bool CGUIWindowVideoNav::ApplyWatchedFilter(CFileItemList &items)
1559 {
1560   bool listchanged = false;
1561   CVideoDatabaseDirectory dir;
1562   NODE_TYPE node = dir.GetDirectoryChildType(items.GetPath());
1563
1564   // now filter watched items as necessary
1565   bool filterWatched=false;
1566   if (node == NODE_TYPE_EPISODES
1567   ||  node == NODE_TYPE_SEASONS
1568   ||  node == NODE_TYPE_SETS
1569   ||  node == NODE_TYPE_TAGS
1570   ||  node == NODE_TYPE_TITLE_MOVIES
1571   ||  node == NODE_TYPE_TITLE_TVSHOWS
1572   ||  node == NODE_TYPE_TITLE_MUSICVIDEOS
1573   ||  node == NODE_TYPE_RECENTLY_ADDED_EPISODES
1574   ||  node == NODE_TYPE_RECENTLY_ADDED_MOVIES
1575   ||  node == NODE_TYPE_RECENTLY_ADDED_MUSICVIDEOS)
1576     filterWatched = true;
1577   if (!items.IsVideoDb())
1578     filterWatched = true;
1579   if (items.GetContent() == "tvshows" &&
1580      (items.IsSmartPlayList() || items.IsLibraryFolder()))
1581     node = NODE_TYPE_TITLE_TVSHOWS; // so that the check below works
1582
1583   int watchMode = CMediaSettings::Get().GetWatchedMode(m_vecItems->GetContent());
1584
1585   for (int i = 0; i < items.Size(); i++)
1586   {
1587     CFileItemPtr item = items.Get(i);
1588
1589     if(item->HasVideoInfoTag() && (node == NODE_TYPE_TITLE_TVSHOWS || node == NODE_TYPE_SEASONS))
1590     {
1591       if (watchMode == WatchedModeUnwatched)
1592         item->GetVideoInfoTag()->m_iEpisode = (int)item->GetProperty("unwatchedepisodes").asInteger();
1593       if (watchMode == WatchedModeWatched)
1594         item->GetVideoInfoTag()->m_iEpisode = (int)item->GetProperty("watchedepisodes").asInteger();
1595       if (watchMode == WatchedModeAll)
1596         item->GetVideoInfoTag()->m_iEpisode = (int)item->GetProperty("totalepisodes").asInteger();
1597       item->SetProperty("numepisodes", item->GetVideoInfoTag()->m_iEpisode);
1598       listchanged = true;
1599     }
1600
1601     if (filterWatched)
1602     {
1603       if((watchMode==WatchedModeWatched   && item->GetVideoInfoTag()->m_playCount== 0)
1604       || (watchMode==WatchedModeUnwatched && item->GetVideoInfoTag()->m_playCount > 0))
1605       {
1606         items.Remove(i);
1607         i--;
1608         listchanged = true;
1609       }
1610     }
1611   }
1612
1613   if(node == NODE_TYPE_TITLE_TVSHOWS || node == NODE_TYPE_SEASONS)
1614   {
1615     // the watched filter may change the "numepisodes" property which is reflected in the TV_SHOWS and SEASONS nodes
1616     // therefore, the items labels have to be refreshed, and possibly the list needs resorting as well.
1617     items.ClearSortState(); // this is needed to force resorting even if sort method did not change
1618     FormatAndSort(items);
1619   }
1620
1621   return listchanged;
1622 }
1623
1624 bool CGUIWindowVideoNav::GetItemsForTag(const CStdString &strHeading, const std::string &type, CFileItemList &items, int idTag /* = -1 */, bool showAll /* = true */)
1625 {
1626   CVideoDatabase videodb;
1627   if (!videodb.Open())
1628     return false;
1629
1630   MediaType mediaType = MediaTypeNone;
1631   std::string baseDir = "videodb://";
1632   std::string idColumn;
1633   if (type.compare("movie") == 0)
1634   {
1635     mediaType = MediaTypeMovie;
1636     baseDir += "movies";
1637     idColumn = "idMovie";
1638   }
1639   else if (type.compare("tvshow") == 0)
1640   {
1641     mediaType = MediaTypeTvShow;
1642     baseDir += "tvshows";
1643     idColumn = "idShow";
1644   }
1645   else if (type.compare("musicvideo") == 0)
1646   {
1647     mediaType = MediaTypeMusicVideo;
1648     baseDir += "musicvideos";
1649     idColumn = "idMVideo";
1650   }
1651
1652   baseDir += "/titles/";
1653   CVideoDbUrl videoUrl;
1654   if (!videoUrl.FromString(baseDir))
1655     return false;
1656
1657   CVideoDatabase::Filter filter;
1658   if (idTag > 0)
1659   {
1660     if (!showAll)
1661       videoUrl.AddOption("tagid", idTag);
1662     else
1663       filter.where = videodb.PrepareSQL("%sview.%s NOT IN (SELECT taglinks.idMedia FROM taglinks WHERE taglinks.idTag = %d AND taglinks.media_type = '%s')", type.c_str(), idColumn.c_str(), idTag, type.c_str());
1664   }
1665
1666   CFileItemList listItems;
1667   if (!videodb.GetSortedVideos(mediaType, videoUrl.ToString(), SortDescription(), listItems, filter) || listItems.Size() <= 0)
1668     return false;
1669
1670   CGUIDialogSelect *dialog = (CGUIDialogSelect *)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
1671   if (dialog == NULL)
1672     return false;
1673
1674   listItems.Sort(SortByLabel, SortOrderAscending, SortAttributeIgnoreArticle);
1675
1676   dialog->Reset();
1677   dialog->SetMultiSelection(true);
1678   dialog->SetHeading(strHeading);
1679   dialog->SetItems(&listItems);
1680   dialog->EnableButton(true, 186);
1681   dialog->DoModal();
1682
1683   items.Copy(dialog->GetSelectedItems());
1684   return items.Size() > 0;
1685 }
1686
1687 CStdString CGUIWindowVideoNav::GetLocalizedType(const std::string &strType)
1688 {
1689   if (strType == "movie" || strType == "movies")
1690     return g_localizeStrings.Get(20342);
1691   else if (strType == "tvshow" || strType == "tvshows")
1692     return g_localizeStrings.Get(20343);
1693   else if (strType == "episode" || strType == "episodes")
1694     return g_localizeStrings.Get(20359);
1695   else if (strType == "musicvideo" || strType == "musicvideos")
1696     return g_localizeStrings.Get(20391);
1697   else
1698     return "";
1699 }