Merge pull request #3494 from guyrichie/timer_context_m
[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::GetContextButtons(int itemNumber, CContextButtons &buttons)
835 {
836   CFileItemPtr item;
837   if (itemNumber >= 0 && itemNumber < m_vecItems->Size())
838     item = m_vecItems->Get(itemNumber);
839
840   CGUIWindowVideoBase::GetContextButtons(itemNumber, buttons);
841
842   if (item && item->GetProperty("pluginreplacecontextitems").asBoolean())
843     return;
844
845   CVideoDatabaseDirectory dir;
846   NODE_TYPE node = dir.GetDirectoryChildType(m_vecItems->GetPath());
847
848   if (!item)
849   {
850     // nothing to do here
851   }
852   else if (m_vecItems->GetPath().Equals("sources://video/"))
853   {
854     // get the usual shares
855     CGUIDialogContextMenu::GetContextButtons("video", item, buttons);
856     // add scan button somewhere here
857     if (g_application.IsVideoScanning())
858       buttons.Add(CONTEXT_BUTTON_STOP_SCANNING, 13353);  // Stop Scanning
859     if (!item->IsDVD() && item->GetPath() != "add" && !item->IsParentFolder() &&
860         (CProfilesManager::Get().GetCurrentProfile().canWriteDatabases() || g_passwordManager.bMasterUser))
861     {
862       CVideoDatabase database;
863       database.Open();
864       ADDON::ScraperPtr info = database.GetScraperForPath(item->GetPath());
865
866       if (!g_application.IsVideoScanning())
867       {
868         if (!item->IsLiveTV() && !item->IsPlugin() && !item->IsAddonsPath() && !URIUtils::IsUPnP(item->GetPath()))
869         {
870           if (info && info->Content() != CONTENT_NONE)
871             buttons.Add(CONTEXT_BUTTON_SET_CONTENT, 20442);
872           else
873             buttons.Add(CONTEXT_BUTTON_SET_CONTENT, 20333);
874         }
875       }
876
877       if (info && !g_application.IsVideoScanning())
878         buttons.Add(CONTEXT_BUTTON_SCAN, 13349);
879     }
880   }
881   else
882   {
883     // are we in the playlists location?
884     bool inPlaylists = m_vecItems->GetPath().Equals(CUtil::VideoPlaylistsLocation()) ||
885                        m_vecItems->GetPath().Equals("special://videoplaylists/");
886
887     if (item->HasVideoInfoTag() && !item->GetVideoInfoTag()->m_artist.empty())
888     {
889       CMusicDatabase database;
890       database.Open();
891       if (database.GetArtistByName(StringUtils::Join(item->GetVideoInfoTag()->m_artist, g_advancedSettings.m_videoItemSeparator)) > -1)
892         buttons.Add(CONTEXT_BUTTON_GO_TO_ARTIST, 20396);
893     }
894     if (item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_strAlbum.size() > 0)
895     {
896       CMusicDatabase database;
897       database.Open();
898       if (database.GetAlbumByName(item->GetVideoInfoTag()->m_strAlbum) > -1)
899         buttons.Add(CONTEXT_BUTTON_GO_TO_ALBUM, 20397);
900     }
901     if (item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_strAlbum.size() > 0 &&
902         item->GetVideoInfoTag()->m_artist.size() > 0                              &&
903         item->GetVideoInfoTag()->m_strTitle.size() > 0)
904     {
905       CMusicDatabase database;
906       database.Open();
907       if (database.GetSongByArtistAndAlbumAndTitle(StringUtils::Join(item->GetVideoInfoTag()->m_artist, g_advancedSettings.m_videoItemSeparator),
908                                                    item->GetVideoInfoTag()->m_strAlbum,
909                                                    item->GetVideoInfoTag()->m_strTitle) > -1)
910       {
911         buttons.Add(CONTEXT_BUTTON_PLAY_OTHER, 20398);
912       }
913     }
914     if (!item->IsParentFolder())
915     {
916       ADDON::ScraperPtr info;
917       VIDEO::SScanSettings settings;
918       GetScraperForItem(item.get(), info, settings);
919
920       if (info && info->Content() == CONTENT_TVSHOWS)
921         buttons.Add(CONTEXT_BUTTON_INFO, item->m_bIsFolder ? 20351 : 20352);
922       else if (info && info->Content() == CONTENT_MUSICVIDEOS)
923         buttons.Add(CONTEXT_BUTTON_INFO,20393);
924       else if (info && info->Content() == CONTENT_MOVIES)
925         buttons.Add(CONTEXT_BUTTON_INFO, 13346);
926
927       // can we update the database?
928       if (CProfilesManager::Get().GetCurrentProfile().canWriteDatabases() || g_passwordManager.bMasterUser)
929       {
930         if (node == NODE_TYPE_TITLE_TVSHOWS)
931         {
932           if (g_application.IsVideoScanning())
933             buttons.Add(CONTEXT_BUTTON_STOP_SCANNING, 13353);
934           else
935             buttons.Add(CONTEXT_BUTTON_SCAN, 13349);
936         }
937         if (!item->IsPlugin() && !item->IsScript() && !item->IsLiveTV() && !item->IsAddonsPath() &&
938             item->GetPath() != "sources://video/" && item->GetPath() != "special://videoplaylists/" &&
939             item->GetPath().Left(19) != "newsmartplaylist://" && item->GetPath().Left(14) != "newplaylist://" &&
940             item->GetPath().Left(9) != "newtag://")
941         {
942           if (item->m_bIsFolder)
943           {
944             // Have both options for folders since we don't know whether all childs are watched/unwatched
945             buttons.Add(CONTEXT_BUTTON_MARK_UNWATCHED, 16104); //Mark as UnWatched
946             buttons.Add(CONTEXT_BUTTON_MARK_WATCHED, 16103);   //Mark as Watched
947           }
948           else
949           {
950             if (item->GetOverlayImage().Equals("OverlayWatched.png"))
951               buttons.Add(CONTEXT_BUTTON_MARK_UNWATCHED, 16104); //Mark as UnWatched
952             else
953               buttons.Add(CONTEXT_BUTTON_MARK_WATCHED, 16103);   //Mark as Watched
954           }
955         }
956         if (!g_application.IsVideoScanning() && item->IsVideoDb() && item->HasVideoInfoTag() &&
957            (!item->m_bIsFolder || m_vecItems->GetContent().Equals("movies") || m_vecItems->GetContent().Equals("tvshows")))
958         {
959           buttons.Add(CONTEXT_BUTTON_EDIT, 16106);
960         }
961
962         if (node == NODE_TYPE_SEASONS && item->m_bIsFolder)
963           buttons.Add(CONTEXT_BUTTON_SET_SEASON_ART, 13511);
964
965         if (StringUtils::StartsWithNoCase(item->GetPath(), "videodb://movies/sets/") && item->GetPath().size() > 22 && item->m_bIsFolder) // sets
966         {
967           buttons.Add(CONTEXT_BUTTON_SET_MOVIESET_ART, 13511);
968           buttons.Add(CONTEXT_BUTTON_MOVIESET_ADD_REMOVE_ITEMS, 20465);
969           buttons.Add(CONTEXT_BUTTON_DELETE, 646);
970         }
971
972         if (m_vecItems->GetContent() == "tags" && item->m_bIsFolder) // tags
973         {
974           CVideoDbUrl videoUrl;
975           if (videoUrl.FromString(item->GetPath()))
976           {
977             std::string mediaType = videoUrl.GetItemType();
978
979             CStdString strLabelAdd; strLabelAdd.Format(g_localizeStrings.Get(20460), GetLocalizedType(videoUrl.GetItemType()).c_str());
980             CStdString strLabelRemove; strLabelRemove.Format(g_localizeStrings.Get(20461), GetLocalizedType(videoUrl.GetItemType()).c_str());
981             buttons.Add(CONTEXT_BUTTON_TAGS_ADD_ITEMS, strLabelAdd);
982             buttons.Add(CONTEXT_BUTTON_TAGS_REMOVE_ITEMS, strLabelRemove);
983             buttons.Add(CONTEXT_BUTTON_DELETE, 646);
984           }
985         }
986
987         if (node == NODE_TYPE_ACTOR && !dir.IsAllItem(item->GetPath()) && item->m_bIsFolder)
988         {
989           if (StringUtils::StartsWithNoCase(m_vecItems->GetPath(), "videodb://musicvideos")) // mvids
990             buttons.Add(CONTEXT_BUTTON_SET_ARTIST_THUMB, 13359);
991           else
992             buttons.Add(CONTEXT_BUTTON_SET_ACTOR_THUMB, 20403);
993         }
994         if (item->IsVideoDb() && item->HasVideoInfoTag() &&
995           (!item->m_bIsFolder || node == NODE_TYPE_TITLE_TVSHOWS))
996           buttons.Add(CONTEXT_BUTTON_DELETE, 646);
997       }
998
999       if (!m_vecItems->IsVideoDb() && !m_vecItems->IsVirtualDirectoryRoot())
1000       { // non-video db items, file operations are allowed
1001         if ((CSettings::Get().GetBool("filelists.allowfiledeletion") &&
1002             CUtil::SupportsWriteFileOperations(item->GetPath())) ||
1003             (inPlaylists && !URIUtils::GetFileName(item->GetPath()).Equals("PartyMode-Video.xsp")
1004                          && (item->IsPlayList() || item->IsSmartPlayList())))
1005         {
1006           buttons.Add(CONTEXT_BUTTON_DELETE, 117);
1007           buttons.Add(CONTEXT_BUTTON_RENAME, 118);
1008         }
1009         // add "Set/Change content" to folders
1010         if (item->m_bIsFolder && !item->IsVideoDb() && !item->IsPlayList() && !item->IsSmartPlayList() && !item->IsLibraryFolder() && !item->IsLiveTV() && !item->IsPlugin() && !item->IsAddonsPath() && !URIUtils::IsUPnP(item->GetPath()))
1011         {
1012           if (!g_application.IsVideoScanning())
1013           {
1014             if (info && info->Content() != CONTENT_NONE)
1015             {
1016               buttons.Add(CONTEXT_BUTTON_SET_CONTENT, 20442);
1017               buttons.Add(CONTEXT_BUTTON_SCAN, 13349);
1018             }
1019             else
1020               buttons.Add(CONTEXT_BUTTON_SET_CONTENT, 20333);
1021           }
1022         }
1023       }
1024       if (item->IsPlugin() || item->IsScript() || m_vecItems->IsPlugin())
1025         buttons.Add(CONTEXT_BUTTON_PLUGIN_SETTINGS, 1045);
1026     }
1027   }
1028 }
1029
1030 // predicate used by sorting and set_difference
1031 bool compFileItemsByDbId(const CFileItemPtr& lhs, const CFileItemPtr& rhs) 
1032 {
1033   return lhs->HasVideoInfoTag() && rhs->HasVideoInfoTag() && lhs->GetVideoInfoTag()->m_iDbId < rhs->GetVideoInfoTag()->m_iDbId;
1034 }
1035
1036 bool CGUIWindowVideoNav::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
1037 {
1038   CFileItemPtr item;
1039   if (itemNumber >= 0 && itemNumber < m_vecItems->Size())
1040     item = m_vecItems->Get(itemNumber);
1041   if (CGUIDialogContextMenu::OnContextButton("video", item, button))
1042   {
1043     //TODO should we search DB for entries from plugins?
1044     if (button == CONTEXT_BUTTON_REMOVE_SOURCE && !item->IsPlugin()
1045         && !item->IsLiveTV() &&!item->IsRSS() && !URIUtils::IsUPnP(item->GetPath()))
1046     {
1047       OnUnAssignContent(item->GetPath(),20375,20340,20341);
1048     }
1049     Refresh();
1050     return true;
1051   }
1052   switch (button)
1053   {
1054   case CONTEXT_BUTTON_EDIT:
1055     {
1056       CONTEXT_BUTTON ret = (CONTEXT_BUTTON)CGUIDialogVideoInfo::ManageVideoItem(item);
1057       if (ret >= 0)
1058       {
1059         if (ret == CONTEXT_BUTTON_MARK_WATCHED)
1060           m_viewControl.SetSelectedItem(itemNumber + 1);
1061
1062         Refresh(true);
1063       }
1064       return true;
1065     }
1066
1067   case CONTEXT_BUTTON_SET_SEASON_ART:
1068   case CONTEXT_BUTTON_SET_ACTOR_THUMB:
1069   case CONTEXT_BUTTON_SET_ARTIST_THUMB:
1070   case CONTEXT_BUTTON_SET_MOVIESET_ART:
1071     {
1072       // Grab the thumbnails from the web
1073       CFileItemList items;
1074       CFileItemPtr noneitem(new CFileItem("thumb://None", false));
1075       CStdString currentThumb;
1076       int idArtist = -1;
1077       CStdString artistPath;
1078       string artType = "thumb";
1079       if (button == CONTEXT_BUTTON_SET_ARTIST_THUMB)
1080       {
1081         CMusicDatabase database;
1082         database.Open();
1083         idArtist = database.GetArtistByName(m_vecItems->Get(itemNumber)->GetLabel());
1084         database.GetArtistPath(idArtist, artistPath);
1085         currentThumb = database.GetArtForItem(idArtist, "artist", "thumb");
1086         if (currentThumb.empty())
1087           currentThumb = m_database.GetArtForItem(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_iDbId, m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_type, artType);
1088       }
1089       else if (button == CONTEXT_BUTTON_SET_ACTOR_THUMB)
1090         currentThumb = m_database.GetArtForItem(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_iDbId, m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_type, artType);
1091       else
1092       { // SEASON, SET
1093         map<string, string> currentArt;
1094         artType = CGUIDialogVideoInfo::ChooseArtType(*m_vecItems->Get(itemNumber), currentArt);
1095         if (artType.empty())
1096           return false;
1097
1098         if (artType == "fanart")
1099         {
1100           OnChooseFanart(*m_vecItems->Get(itemNumber));
1101           return true;
1102         }
1103
1104         if (currentArt.find(artType) != currentArt.end())
1105           currentThumb = currentArt[artType];
1106         else if ((artType == "poster" || artType == "banner") && currentArt.find("thumb") != currentArt.end())
1107           currentThumb = currentArt["thumb"];
1108       }
1109       if (!currentThumb.IsEmpty())
1110       {
1111         CFileItemPtr item(new CFileItem("thumb://Current", false));
1112         item->SetArt("thumb", currentThumb);
1113         item->SetLabel(g_localizeStrings.Get(13512));
1114         items.Add(item);
1115       }
1116       noneitem->SetIconImage("DefaultFolder.png");
1117       noneitem->SetLabel(g_localizeStrings.Get(13515));
1118
1119       vector<CStdString> thumbs;
1120       if (button != CONTEXT_BUTTON_SET_ARTIST_THUMB)
1121       {
1122         CVideoInfoTag tag;
1123         if (button == CONTEXT_BUTTON_SET_SEASON_ART)
1124           m_database.GetTvShowInfo("",tag,m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_iIdShow);
1125         else
1126           tag = *m_vecItems->Get(itemNumber)->GetVideoInfoTag();
1127         if (button == CONTEXT_BUTTON_SET_SEASON_ART)
1128           tag.m_strPictureURL.GetThumbURLs(thumbs, artType, m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_iSeason);
1129         else
1130           tag.m_strPictureURL.GetThumbURLs(thumbs, artType);
1131
1132         for (unsigned int i = 0; i < thumbs.size(); i++)
1133         {
1134           CStdString strItemPath;
1135           strItemPath.Format("thumb://Remote%i",i);
1136           CFileItemPtr item(new CFileItem(strItemPath, false));
1137           item->SetArt("thumb", thumbs[i]);
1138           item->SetIconImage("DefaultPicture.png");
1139           item->SetLabel(g_localizeStrings.Get(13513));
1140           items.Add(item);
1141
1142           // TODO: Do we need to clear the cached image?
1143           //    CTextureCache::Get().ClearCachedImage(thumbs[i]);
1144         }
1145       }
1146
1147       bool local=false;
1148       if (button == CONTEXT_BUTTON_SET_ARTIST_THUMB)
1149       {
1150         CStdString strThumb = URIUtils::AddFileToFolder(artistPath, "folder.jpg");
1151         if (XFILE::CFile::Exists(strThumb))
1152         {
1153           CFileItemPtr pItem(new CFileItem(strThumb,false));
1154           pItem->SetLabel(g_localizeStrings.Get(13514));
1155           pItem->SetArt("thumb", strThumb);
1156           items.Add(pItem);
1157           local = true;
1158         }
1159         else
1160           noneitem->SetIconImage("DefaultArtist.png");
1161       }
1162
1163       if (button == CONTEXT_BUTTON_SET_ACTOR_THUMB)
1164       {
1165         CStdString picturePath;
1166         CStdString strThumb = URIUtils::AddFileToFolder(picturePath, "folder.jpg");
1167         if (XFILE::CFile::Exists(strThumb))
1168         {
1169           CFileItemPtr pItem(new CFileItem(strThumb,false));
1170           pItem->SetLabel(g_localizeStrings.Get(13514));
1171           pItem->SetArt("thumb", strThumb);
1172           items.Add(pItem);
1173           local = true;
1174         }
1175         else
1176           noneitem->SetIconImage("DefaultActor.png");
1177       }
1178
1179       if (button == CONTEXT_BUTTON_SET_MOVIESET_ART)
1180         noneitem->SetIconImage("DefaultVideo.png");
1181
1182       if (!local)
1183         items.Add(noneitem);
1184
1185       VECSOURCES sources=*CMediaSourceSettings::Get().GetSources("video");
1186       g_mediaManager.GetLocalDrives(sources);
1187       CStdString result;
1188       CGUIDialogVideoInfo::AddItemPathToFileBrowserSources(sources, *item);
1189       if (!CGUIDialogFileBrowser::ShowAndGetImage(items, sources,
1190                                                   g_localizeStrings.Get(13511), result))
1191       {
1192         return false;   // user cancelled
1193       }
1194
1195       if (result == "thumb://Current")
1196         result = currentThumb;   // user chose the one they have
1197
1198       // delete the thumbnail if that's what the user wants, else overwrite with the
1199       // new thumbnail
1200       if (result.Left(14) == "thumb://Remote")
1201       {
1202         int number = atoi(result.Mid(14));
1203         result = thumbs[number];
1204       }
1205       else if (result == "thumb://None")
1206         result.clear();
1207       if (button == CONTEXT_BUTTON_SET_MOVIESET_ART ||
1208           button == CONTEXT_BUTTON_SET_ACTOR_THUMB ||
1209           button == CONTEXT_BUTTON_SET_SEASON_ART ||
1210          (button == CONTEXT_BUTTON_SET_ARTIST_THUMB && idArtist < 0))
1211         m_database.SetArtForItem(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_iDbId, m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_type, artType, result);
1212       else
1213       {
1214         CMusicDatabase db;
1215         if (db.Open())
1216           db.SetArtForItem(idArtist, "artist", artType, result);
1217       }
1218
1219       CUtil::DeleteVideoDatabaseDirectoryCache();
1220       CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_REFRESH_THUMBS);
1221       g_windowManager.SendMessage(msg);
1222       Refresh();
1223
1224       return true;
1225     }
1226   case CONTEXT_BUTTON_TAGS_ADD_ITEMS:
1227     {
1228       CVideoDbUrl videoUrl;
1229       if (!videoUrl.FromString(item->GetPath()))
1230         return false;
1231       
1232       std::string mediaType = videoUrl.GetItemType();
1233       mediaType = mediaType.substr(0, mediaType.length() - 1);
1234
1235       CFileItemList items;
1236       CStdString localizedType = GetLocalizedType(mediaType);
1237       CStdString strLabel; strLabel.Format(g_localizeStrings.Get(20464), localizedType.c_str());
1238       if (!GetItemsForTag(strLabel, mediaType, items, item->GetVideoInfoTag()->m_iDbId))
1239         return true;
1240
1241       CVideoDatabase videodb;
1242       if (!videodb.Open())
1243         return true;
1244
1245       for (int index = 0; index < items.Size(); index++)
1246       {
1247         if (!items[index]->HasVideoInfoTag() || items[index]->GetVideoInfoTag()->m_iDbId <= 0)
1248           continue;
1249
1250         videodb.AddTagToItem(items[index]->GetVideoInfoTag()->m_iDbId, item->GetVideoInfoTag()->m_iDbId, mediaType);
1251       }
1252
1253       // we need to clear any cached version of this tag's listing
1254       items.SetPath(item->GetPath());
1255       items.RemoveDiscCache(GetID());
1256       return true;
1257     }
1258   case CONTEXT_BUTTON_TAGS_REMOVE_ITEMS:
1259     {
1260       CVideoDbUrl videoUrl;
1261       if (!videoUrl.FromString(item->GetPath()))
1262         return false;
1263       
1264       std::string mediaType = videoUrl.GetItemType();
1265       mediaType = mediaType.substr(0, mediaType.length() - 1);
1266
1267       CFileItemList items;
1268       CStdString localizedType = GetLocalizedType(mediaType);
1269       CStdString strLabel; strLabel.Format(g_localizeStrings.Get(20464), localizedType.c_str());
1270       if (!GetItemsForTag(strLabel, mediaType, items, item->GetVideoInfoTag()->m_iDbId, false))
1271         return true;
1272
1273       CVideoDatabase videodb;
1274       if (!videodb.Open())
1275         return true;
1276
1277       for (int index = 0; index < items.Size(); index++)
1278       {
1279         if (!items[index]->HasVideoInfoTag() || items[index]->GetVideoInfoTag()->m_iDbId <= 0)
1280           continue;
1281
1282         videodb.RemoveTagFromItem(items[index]->GetVideoInfoTag()->m_iDbId, item->GetVideoInfoTag()->m_iDbId, mediaType);
1283       }
1284
1285       // we need to clear any cached version of this tag's listing
1286       items.SetPath(item->GetPath());
1287       items.RemoveDiscCache(GetID());
1288       return true;
1289     }
1290   case CONTEXT_BUTTON_MOVIESET_ADD_REMOVE_ITEMS:
1291     {
1292       CFileItemList originalItems;
1293       CFileItemList selectedItems;
1294
1295       if (!CGUIDialogVideoInfo::GetMoviesForSet(item.get(), originalItems, selectedItems) || selectedItems.Size() == 0) // need at least one item selected
1296         return true;
1297       VECFILEITEMS original = originalItems.GetList();
1298       std::sort(original.begin(), original.end(), compFileItemsByDbId);
1299       VECFILEITEMS selected = selectedItems.GetList();
1300       std::sort(selected.begin(), selected.end(), compFileItemsByDbId);
1301
1302       bool refreshNeeded = false;
1303       // update the "added" items
1304       VECFILEITEMS addedItems;
1305       set_difference(selected.begin(),selected.end(), original.begin(),original.end(), std::back_inserter(addedItems), compFileItemsByDbId);
1306       for (VECFILEITEMS::iterator it = addedItems.begin();  it != addedItems.end(); ++it)
1307       {
1308         if (CGUIDialogVideoInfo::SetMovieSet(it->get(), item.get()))
1309           refreshNeeded = true;
1310       }
1311       // update the "deleted" items
1312       CFileItemPtr clearItem(new CFileItem());
1313       clearItem->GetVideoInfoTag()->m_iDbId = -1; // -1 will be used to clear set
1314       VECFILEITEMS deletedItems;
1315       set_difference(original.begin(),original.end(), selected.begin(),selected.end(), std::back_inserter(deletedItems), compFileItemsByDbId);
1316       for (VECFILEITEMS::iterator it = deletedItems.begin();  it != deletedItems.end(); ++it)
1317       {
1318         if (CGUIDialogVideoInfo::SetMovieSet(it->get(), clearItem.get()))
1319           refreshNeeded = true;
1320       }
1321
1322       // we need to clear any cached version of this tag's listing
1323       if (refreshNeeded) 
1324         Refresh();
1325       return true;
1326     }
1327   case CONTEXT_BUTTON_GO_TO_ARTIST:
1328     {
1329       CStdString strPath;
1330       CMusicDatabase database;
1331       database.Open();
1332       strPath.Format("musicdb://artists/%ld/",database.GetArtistByName(StringUtils::Join(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_artist, g_advancedSettings.m_videoItemSeparator)));
1333       g_windowManager.ActivateWindow(WINDOW_MUSIC_NAV,strPath);
1334       return true;
1335     }
1336   case CONTEXT_BUTTON_GO_TO_ALBUM:
1337     {
1338       CStdString strPath;
1339       CMusicDatabase database;
1340       database.Open();
1341       strPath.Format("musicdb://albums/%ld/",database.GetAlbumByName(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strAlbum));
1342       g_windowManager.ActivateWindow(WINDOW_MUSIC_NAV,strPath);
1343       return true;
1344     }
1345   case CONTEXT_BUTTON_PLAY_OTHER:
1346     {
1347       CMusicDatabase database;
1348       database.Open();
1349       CSong song;
1350       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,
1351                                                                         m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strTitle),
1352                                                                         song))
1353       {
1354         CApplicationMessenger::Get().PlayFile(song);
1355       }
1356       return true;
1357     }
1358
1359   default:
1360     break;
1361
1362   }
1363   return CGUIWindowVideoBase::OnContextButton(itemNumber, button);
1364 }
1365
1366 void CGUIWindowVideoNav::OnChooseFanart(const CFileItem &videoItem)
1367 {
1368   if (!videoItem.HasVideoInfoTag())
1369     return;
1370
1371   CFileItem item(videoItem);
1372
1373   CFileItemList items;
1374
1375   CVideoThumbLoader loader;
1376   loader.LoadItem(&item);
1377
1378   if (item.HasArt("fanart"))
1379   {
1380     CFileItemPtr itemCurrent(new CFileItem("fanart://Current",false));
1381     itemCurrent->SetArt("thumb", item.GetArt("fanart"));
1382     itemCurrent->SetLabel(g_localizeStrings.Get(20440));
1383     items.Add(itemCurrent);
1384   }
1385
1386   // add the none option
1387   {
1388     CFileItemPtr itemNone(new CFileItem("fanart://None", false));
1389     itemNone->SetIconImage("DefaultVideo.png");
1390     itemNone->SetLabel(g_localizeStrings.Get(20439));
1391     items.Add(itemNone);
1392   }
1393
1394   CStdString result;
1395   VECSOURCES sources(*CMediaSourceSettings::Get().GetSources("video"));
1396   g_mediaManager.GetLocalDrives(sources);
1397   CGUIDialogVideoInfo::AddItemPathToFileBrowserSources(sources, item);
1398   bool flip=false;
1399   if (!CGUIDialogFileBrowser::ShowAndGetImage(items, sources, g_localizeStrings.Get(20437), result, &flip, 20445) || result.Equals("fanart://Current"))
1400     return;
1401
1402   if (result.Equals("fanart://None") || !CFile::Exists(result))
1403     result.clear();
1404   if (!result.IsEmpty() && flip)
1405     result = CTextureUtils::GetWrappedImageURL(result, "", "flipped");
1406
1407   // update the db
1408   CVideoDatabase db;
1409   if (db.Open())
1410   {
1411     db.SetArtForItem(item.GetVideoInfoTag()->m_iDbId, item.GetVideoInfoTag()->m_type, "fanart", result);
1412     db.Close();
1413   }
1414
1415   // clear view cache and reload images
1416   CUtil::DeleteVideoDatabaseDirectoryCache();
1417
1418   Refresh();
1419 }
1420
1421 bool CGUIWindowVideoNav::OnClick(int iItem)
1422 {
1423   CFileItemPtr item = m_vecItems->Get(iItem);
1424   if (!item->m_bIsFolder && item->IsVideoDb() && !item->Exists())
1425   {
1426     CLog::Log(LOGDEBUG, "%s called on '%s' but file doesn't exist", __FUNCTION__, item->GetPath().c_str());
1427     if (!DeleteItem(item.get(), true))
1428       return true;
1429
1430     // update list
1431     Refresh(true);
1432     m_viewControl.SetSelectedItem(iItem);
1433     return true;
1434   }
1435   else if (StringUtils::StartsWithNoCase(item->GetPath(), "newtag://"))
1436   {
1437     // dont allow update while scanning
1438     if (g_application.IsVideoScanning())
1439     {
1440       CGUIDialogOK::ShowAndGetInput(257, 0, 14057, 0);
1441       return true;
1442     }
1443
1444     //Get the new title
1445     CStdString strTag;
1446     if (!CGUIKeyboardFactory::ShowAndGetInput(strTag, g_localizeStrings.Get(20462), false))
1447       return true;
1448
1449     CVideoDatabase videodb;
1450     if (!videodb.Open())
1451       return true;
1452
1453     // get the media type and convert from plural to singular (by removing the trailing "s")
1454     CStdString mediaType = item->GetPath().Mid(9);
1455     mediaType = mediaType.Left(mediaType.size() - 1);
1456     CStdString localizedType = GetLocalizedType(mediaType);
1457     if (localizedType.empty())
1458       return true;
1459
1460     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())
1461     {
1462       CStdString strError; strError.Format(g_localizeStrings.Get(20463), strTag.c_str());
1463       CGUIDialogOK::ShowAndGetInput(20462, "", strError, "");
1464       return true;
1465     }
1466
1467     int idTag = videodb.AddTag(strTag);
1468     CFileItemList items;
1469     CStdString strLabel; strLabel.Format(g_localizeStrings.Get(20464), localizedType.c_str());
1470     if (GetItemsForTag(strLabel, mediaType, items, idTag))
1471     {
1472       for (int index = 0; index < items.Size(); index++)
1473       {
1474         if (!items[index]->HasVideoInfoTag() || items[index]->GetVideoInfoTag()->m_iDbId <= 0)
1475           continue;
1476
1477         videodb.AddTagToItem(items[index]->GetVideoInfoTag()->m_iDbId, idTag, mediaType);
1478       }
1479     }
1480
1481     Refresh(true);
1482     return true;
1483   }
1484
1485   return CGUIWindowVideoBase::OnClick(iItem);
1486 }
1487
1488 CStdString CGUIWindowVideoNav::GetStartFolder(const CStdString &dir)
1489 {
1490   if (dir.Equals("MovieGenres"))
1491     return "videodb://movies/genres/";
1492   else if (dir.Equals("MovieTitles"))
1493     return "videodb://movies/titles/";
1494   else if (dir.Equals("MovieYears"))
1495     return "videodb://movies/years/";
1496   else if (dir.Equals("MovieActors"))
1497     return "videodb://movies/actors/";
1498   else if (dir.Equals("MovieDirectors"))
1499     return "videodb://movies/directors/";
1500   else if (dir.Equals("MovieStudios"))
1501     return "videodb://movies/studios/";
1502   else if (dir.Equals("MovieSets"))
1503     return "videodb://movies/sets/";
1504   else if (dir.Equals("MovieCountries"))
1505     return "videodb://movies/countries/";
1506   else if (dir.Equals("MovieTags"))
1507     return "videodb://movies/tags/";
1508   else if (dir.Equals("Movies"))
1509     return "videodb://movies/";
1510   else if (dir.Equals("TvShowGenres"))
1511     return "videodb://tvshows/genres/";
1512   else if (dir.Equals("TvShowTitles"))
1513     return "videodb://tvshows/titles/";
1514   else if (dir.Equals("TvShowYears"))
1515     return "videodb://tvshows/years/";
1516   else if (dir.Equals("TvShowActors"))
1517     return "videodb://tvshows/actors/";
1518   else if (dir.Equals("TvShowStudios"))
1519     return "videodb://tvshows/studios/";
1520   else if (dir.Equals("TvShowTags"))
1521     return "videodb://tvshows/tags/";
1522   else if (dir.Equals("TvShows"))
1523     return "videodb://tvshows/";
1524   else if (dir.Equals("MusicVideoGenres"))
1525     return "videodb://musicvideos/genres/";
1526   else if (dir.Equals("MusicVideoTitles"))
1527     return "videodb://musicvideos/titles/";
1528   else if (dir.Equals("MusicVideoYears"))
1529     return "videodb://musicvideos/years/";
1530   else if (dir.Equals("MusicVideoArtists"))
1531     return "videodb://musicvideos/artists/";
1532   else if (dir.Equals("MusicVideoAlbums"))
1533     return "videodb://musicvideos/albums/";
1534   else if (dir.Equals("MusicVideoDirectors"))
1535     return "videodb://musicvideos/directors/";
1536   else if (dir.Equals("MusicVideoStudios"))
1537     return "videodb://musicvideos/studios/";
1538   else if (dir.Equals("MusicVideoTags"))
1539     return "videodb://musicvideos/tags/";
1540   else if (dir.Equals("MusicVideos"))
1541     return "videodb://musicvideos/";
1542   else if (dir.Equals("RecentlyAddedMovies"))
1543     return "videodb://recentlyaddedmovies/";
1544   else if (dir.Equals("RecentlyAddedEpisodes"))
1545     return "videodb://recentlyaddedepisodes/";
1546   else if (dir.Equals("RecentlyAddedMusicVideos"))
1547     return "videodb://recentlyaddedmusicvideos/";
1548   else if (dir.Equals("Files"))
1549     return "sources://video/";
1550   return CGUIWindowVideoBase::GetStartFolder(dir);
1551 }
1552
1553 bool CGUIWindowVideoNav::ApplyWatchedFilter(CFileItemList &items)
1554 {
1555   bool listchanged = false;
1556   CVideoDatabaseDirectory dir;
1557   NODE_TYPE node = dir.GetDirectoryChildType(items.GetPath());
1558
1559   // now filter watched items as necessary
1560   bool filterWatched=false;
1561   if (node == NODE_TYPE_EPISODES
1562   ||  node == NODE_TYPE_SEASONS
1563   ||  node == NODE_TYPE_SETS
1564   ||  node == NODE_TYPE_TAGS
1565   ||  node == NODE_TYPE_TITLE_MOVIES
1566   ||  node == NODE_TYPE_TITLE_TVSHOWS
1567   ||  node == NODE_TYPE_TITLE_MUSICVIDEOS
1568   ||  node == NODE_TYPE_RECENTLY_ADDED_EPISODES
1569   ||  node == NODE_TYPE_RECENTLY_ADDED_MOVIES
1570   ||  node == NODE_TYPE_RECENTLY_ADDED_MUSICVIDEOS)
1571     filterWatched = true;
1572   if (!items.IsVideoDb())
1573     filterWatched = true;
1574   if (items.GetContent() == "tvshows" &&
1575      (items.IsSmartPlayList() || items.IsLibraryFolder()))
1576     node = NODE_TYPE_TITLE_TVSHOWS; // so that the check below works
1577
1578   int watchMode = CMediaSettings::Get().GetWatchedMode(m_vecItems->GetContent());
1579
1580   for (int i = 0; i < items.Size(); i++)
1581   {
1582     CFileItemPtr item = items.Get(i);
1583
1584     if(item->HasVideoInfoTag() && (node == NODE_TYPE_TITLE_TVSHOWS || node == NODE_TYPE_SEASONS))
1585     {
1586       if (watchMode == WatchedModeUnwatched)
1587         item->GetVideoInfoTag()->m_iEpisode = (int)item->GetProperty("unwatchedepisodes").asInteger();
1588       if (watchMode == WatchedModeWatched)
1589         item->GetVideoInfoTag()->m_iEpisode = (int)item->GetProperty("watchedepisodes").asInteger();
1590       if (watchMode == WatchedModeAll)
1591         item->GetVideoInfoTag()->m_iEpisode = (int)item->GetProperty("totalepisodes").asInteger();
1592       item->SetProperty("numepisodes", item->GetVideoInfoTag()->m_iEpisode);
1593       listchanged = true;
1594     }
1595
1596     if (filterWatched)
1597     {
1598       if((watchMode==WatchedModeWatched   && item->GetVideoInfoTag()->m_playCount== 0)
1599       || (watchMode==WatchedModeUnwatched && item->GetVideoInfoTag()->m_playCount > 0))
1600       {
1601         items.Remove(i);
1602         i--;
1603         listchanged = true;
1604       }
1605     }
1606   }
1607
1608   if(node == NODE_TYPE_TITLE_TVSHOWS || node == NODE_TYPE_SEASONS)
1609   {
1610     // the watched filter may change the "numepisodes" property which is reflected in the TV_SHOWS and SEASONS nodes
1611     // therefore, the items labels have to be refreshed, and possibly the list needs resorting as well.
1612     items.ClearSortState(); // this is needed to force resorting even if sort method did not change
1613     FormatAndSort(items);
1614   }
1615
1616   return listchanged;
1617 }
1618
1619 bool CGUIWindowVideoNav::GetItemsForTag(const CStdString &strHeading, const std::string &type, CFileItemList &items, int idTag /* = -1 */, bool showAll /* = true */)
1620 {
1621   CVideoDatabase videodb;
1622   if (!videodb.Open())
1623     return false;
1624
1625   MediaType mediaType = MediaTypeNone;
1626   std::string baseDir = "videodb://";
1627   std::string idColumn;
1628   if (type.compare("movie") == 0)
1629   {
1630     mediaType = MediaTypeMovie;
1631     baseDir += "movies";
1632     idColumn = "idMovie";
1633   }
1634   else if (type.compare("tvshow") == 0)
1635   {
1636     mediaType = MediaTypeTvShow;
1637     baseDir += "tvshows";
1638     idColumn = "idShow";
1639   }
1640   else if (type.compare("musicvideo") == 0)
1641   {
1642     mediaType = MediaTypeMusicVideo;
1643     baseDir += "musicvideos";
1644     idColumn = "idMVideo";
1645   }
1646
1647   baseDir += "/titles/";
1648   CVideoDbUrl videoUrl;
1649   if (!videoUrl.FromString(baseDir))
1650     return false;
1651
1652   CVideoDatabase::Filter filter;
1653   if (idTag > 0)
1654   {
1655     if (!showAll)
1656       videoUrl.AddOption("tagid", idTag);
1657     else
1658       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());
1659   }
1660
1661   CFileItemList listItems;
1662   if (!videodb.GetSortedVideos(mediaType, videoUrl.ToString(), SortDescription(), listItems, filter) || listItems.Size() <= 0)
1663     return false;
1664
1665   CGUIDialogSelect *dialog = (CGUIDialogSelect *)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
1666   if (dialog == NULL)
1667     return false;
1668
1669   listItems.Sort(SortByLabel, SortOrderAscending, SortAttributeIgnoreArticle);
1670
1671   dialog->Reset();
1672   dialog->SetMultiSelection(true);
1673   dialog->SetHeading(strHeading);
1674   dialog->SetItems(&listItems);
1675   dialog->EnableButton(true, 186);
1676   dialog->DoModal();
1677
1678   items.Copy(dialog->GetSelectedItems());
1679   return items.Size() > 0;
1680 }
1681
1682 CStdString CGUIWindowVideoNav::GetLocalizedType(const std::string &strType)
1683 {
1684   if (strType == "movie" || strType == "movies")
1685     return g_localizeStrings.Get(20342);
1686   else if (strType == "tvshow" || strType == "tvshows")
1687     return g_localizeStrings.Get(20343);
1688   else if (strType == "episode" || strType == "episodes")
1689     return g_localizeStrings.Get(20359);
1690   else if (strType == "musicvideo" || strType == "musicvideos")
1691     return g_localizeStrings.Get(20391);
1692   else
1693     return "";
1694 }