[cstdstring] demise Format, replacing with StringUtils::Format
[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 = StringUtils::Format("%i %s", iItems, g_localizeStrings.Get(127).c_str());
508   SET_CONTROL_LABEL(CONTROL_LABELFILES, items);
509
510   // set the filter label
511   CStdString strLabel;
512
513   // "Playlists"
514   if (m_vecItems->GetPath().Equals("special://videoplaylists/"))
515     strLabel = g_localizeStrings.Get(136);
516   // "{Playlist Name}"
517   else if (m_vecItems->IsPlayList())
518   {
519     // get playlist name from path
520     CStdString strDummy;
521     URIUtils::Split(m_vecItems->GetPath(), strDummy, strLabel);
522   }
523   else if (m_vecItems->GetPath().Equals("sources://video/"))
524     strLabel = g_localizeStrings.Get(744);
525   // everything else is from a videodb:// path
526   else if (m_vecItems->IsVideoDb())
527   {
528     CVideoDatabaseDirectory dir;
529     dir.GetLabel(m_vecItems->GetPath(), strLabel);
530   }
531   else
532     strLabel = URIUtils::GetFileName(m_vecItems->GetPath());
533
534   SET_CONTROL_LABEL(CONTROL_FILTER, strLabel);
535
536   int watchMode = CMediaSettings::Get().GetWatchedMode(m_vecItems->GetContent());
537   SET_CONTROL_LABEL(CONTROL_BTNSHOWMODE, g_localizeStrings.Get(16100 + watchMode));
538
539   SET_CONTROL_SELECTED(GetID(), CONTROL_BTNSHOWALL, watchMode != WatchedModeAll);
540
541   SET_CONTROL_SELECTED(GetID(),CONTROL_BTNPARTYMODE, g_partyModeManager.IsEnabled());
542
543   CONTROL_ENABLE_ON_CONDITION(CONTROL_UPDATE_LIBRARY, !m_vecItems->IsAddonsPath() && !m_vecItems->IsPlugin() && !m_vecItems->IsScript());
544 }
545
546 bool CGUIWindowVideoNav::GetFilteredItems(const CStdString &filter, CFileItemList &items)
547 {
548   bool listchanged = CGUIMediaWindow::GetFilteredItems(filter, items);
549   listchanged |= ApplyWatchedFilter(items);
550
551   return listchanged;
552 }
553
554 /// \brief Search for names, genres, artists, directors, and plots with search string \e strSearch in the
555 /// \brief video databases and return the found \e items
556 /// \param strSearch The search string
557 /// \param items Items Found
558 void CGUIWindowVideoNav::DoSearch(const CStdString& strSearch, CFileItemList& items)
559 {
560   CFileItemList tempItems;
561   CStdString strGenre = g_localizeStrings.Get(515); // Genre
562   CStdString strActor = g_localizeStrings.Get(20337); // Actor
563   CStdString strDirector = g_localizeStrings.Get(20339); // Director
564   CStdString strMovie = g_localizeStrings.Get(20338); // Movie
565
566   //get matching names
567   m_database.GetMoviesByName(strSearch, tempItems);
568   AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(20338) + "] ", items);
569
570   m_database.GetEpisodesByName(strSearch, tempItems);
571   AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(20359) + "] ", items);
572
573   m_database.GetTvShowsByName(strSearch, tempItems);
574   AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(20364) + "] ", items);
575
576   m_database.GetMusicVideosByName(strSearch, tempItems);
577   AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(20391) + "] ", items);
578
579   m_database.GetMusicVideosByAlbum(strSearch, tempItems);
580   AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(558) + "] ", items);
581   
582   // get matching genres
583   m_database.GetMovieGenresByName(strSearch, tempItems);
584   AppendAndClearSearchItems(tempItems, "[" + strGenre + " - " + g_localizeStrings.Get(20342) + "] ", items);
585
586   m_database.GetTvShowGenresByName(strSearch, tempItems);
587   AppendAndClearSearchItems(tempItems, "[" + strGenre + " - " + g_localizeStrings.Get(20343) + "] ", items);
588
589   m_database.GetMusicVideoGenresByName(strSearch, tempItems);
590   AppendAndClearSearchItems(tempItems, "[" + strGenre + " - " + g_localizeStrings.Get(20389) + "] ", items);
591
592   //get actors/artists
593   m_database.GetMovieActorsByName(strSearch, tempItems);
594   AppendAndClearSearchItems(tempItems, "[" + strActor + " - " + g_localizeStrings.Get(20342) + "] ", items);
595
596   m_database.GetTvShowsActorsByName(strSearch, tempItems);
597   AppendAndClearSearchItems(tempItems, "[" + strActor + " - " + g_localizeStrings.Get(20343) + "] ", items);
598
599   m_database.GetMusicVideoArtistsByName(strSearch, tempItems);
600   AppendAndClearSearchItems(tempItems, "[" + strActor + " - " + g_localizeStrings.Get(20389) + "] ", items);
601
602   //directors
603   m_database.GetMovieDirectorsByName(strSearch, tempItems);
604   AppendAndClearSearchItems(tempItems, "[" + strDirector + " - " + g_localizeStrings.Get(20342) + "] ", items);
605
606   m_database.GetTvShowsDirectorsByName(strSearch, tempItems);
607   AppendAndClearSearchItems(tempItems, "[" + strDirector + " - " + g_localizeStrings.Get(20343) + "] ", items);
608
609   m_database.GetMusicVideoDirectorsByName(strSearch, tempItems);
610   AppendAndClearSearchItems(tempItems, "[" + strDirector + " - " + g_localizeStrings.Get(20389) + "] ", items);
611
612   //plot
613   m_database.GetEpisodesByPlot(strSearch, tempItems);
614   AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(20365) + "] ", items);
615
616   m_database.GetMoviesByPlot(strSearch, tempItems);
617   AppendAndClearSearchItems(tempItems, "[" + strMovie + " " + g_localizeStrings.Get(207) + "] ", items);
618 }
619
620 void CGUIWindowVideoNav::PlayItem(int iItem)
621 {
622   // unlike additemtoplaylist, we need to check the items here
623   // before calling it since the current playlist will be stopped
624   // and cleared!
625
626   // root is not allowed
627   if (m_vecItems->IsVirtualDirectoryRoot())
628     return;
629
630   CGUIWindowVideoBase::PlayItem(iItem);
631 }
632
633 void CGUIWindowVideoNav::OnInfo(CFileItem* pItem, ADDON::ScraperPtr& scraper)
634 {
635   m_database.Open(); // since we can be called from the music library without being inited
636   if (pItem->IsVideoDb())
637     scraper = m_database.GetScraperForPath(pItem->GetVideoInfoTag()->m_strPath);
638   else
639   {
640     CStdString strPath,strFile;
641     URIUtils::Split(pItem->GetPath(),strPath,strFile);
642     scraper = m_database.GetScraperForPath(strPath);
643   }
644   m_database.Close();
645   CGUIWindowVideoBase::OnInfo(pItem,scraper);
646 }
647
648 bool CGUIWindowVideoNav::CanDelete(const CStdString& strPath)
649 {
650   CQueryParams params;
651   CVideoDatabaseDirectory::GetQueryParams(strPath,params);
652
653   if (params.GetMovieId()   != -1 ||
654       params.GetEpisodeId() != -1 ||
655       params.GetMVideoId()  != -1 ||
656       (params.GetTvShowId() != -1 && params.GetSeason() <= -1
657               && !CVideoDatabaseDirectory::IsAllItem(strPath)))
658     return true;
659
660   return false;
661 }
662
663 void CGUIWindowVideoNav::OnDeleteItem(CFileItemPtr pItem)
664 {
665   if (m_vecItems->IsParentFolder())
666     return;
667
668   if (!m_vecItems->IsVideoDb() && !pItem->IsVideoDb())
669   {
670     if (!pItem->GetPath().Equals("newsmartplaylist://video") &&
671         !pItem->GetPath().Equals("special://videoplaylists/") &&
672         !pItem->GetPath().Equals("sources://video/") &&
673         !StringUtils::StartsWithNoCase(pItem->GetPath(), "newtag://"))
674       CGUIWindowVideoBase::OnDeleteItem(pItem);
675   }
676   else if (StringUtils::StartsWithNoCase(pItem->GetPath(), "videodb://movies/sets/") &&
677            pItem->GetPath().size() > 22 && pItem->m_bIsFolder)
678   {
679     CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
680     pDialog->SetHeading(432);
681     CStdString strLabel = StringUtils::Format(g_localizeStrings.Get(433),pItem->GetLabel().c_str());
682     pDialog->SetLine(1, strLabel);
683     pDialog->SetLine(2, "");;
684     pDialog->DoModal();
685     if (pDialog->IsConfirmed())
686     {
687       CFileItemList items;
688       CDirectory::GetDirectory(pItem->GetPath(),items,"",DIR_FLAG_NO_FILE_DIRS);
689       for (int i=0;i<items.Size();++i)
690         OnDeleteItem(items[i]);
691
692       CVideoDatabaseDirectory dir;
693       CQueryParams params;
694       dir.GetQueryParams(pItem->GetPath(),params);
695       m_database.DeleteSet(params.GetSetId());
696     }
697   }
698   else if (m_vecItems->GetContent() == "tags" && pItem->m_bIsFolder)
699   {
700     CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
701     pDialog->SetHeading(432);
702     CStdString strLabel = StringUtils::Format(g_localizeStrings.Get(433), pItem->GetLabel().c_str());
703     pDialog->SetLine(1, strLabel);
704     pDialog->SetLine(2, "");
705     pDialog->DoModal();
706     if (pDialog->IsConfirmed())
707     {
708       CVideoDatabaseDirectory dir;
709       CQueryParams params;
710       dir.GetQueryParams(pItem->GetPath(), params);
711       m_database.DeleteTag(params.GetTagId(), (VIDEODB_CONTENT_TYPE)params.GetContentType());
712     }
713   }
714   else if (m_vecItems->GetPath().Equals(CUtil::VideoPlaylistsLocation()) ||
715            m_vecItems->GetPath().Equals("special://videoplaylists/"))
716   {
717     pItem->m_bIsFolder = false;
718     CFileUtils::DeleteItem(pItem);
719   }
720   else
721   {
722     if (!DeleteItem(pItem.get()))
723       return;
724
725     CStdString strDeletePath;
726     if (pItem->m_bIsFolder)
727       strDeletePath=pItem->GetVideoInfoTag()->m_strPath;
728     else
729       strDeletePath=pItem->GetVideoInfoTag()->m_strFileNameAndPath;
730
731     if (URIUtils::GetFileName(strDeletePath).Equals("VIDEO_TS.IFO"))
732     {
733       strDeletePath = URIUtils::GetDirectory(strDeletePath);
734       if (StringUtils::EndsWithNoCase(strDeletePath, "video_ts/"))
735       {
736         URIUtils::RemoveSlashAtEnd(strDeletePath);
737         strDeletePath = URIUtils::GetDirectory(strDeletePath);
738       }
739     }
740     if (URIUtils::HasSlashAtEnd(strDeletePath))
741       pItem->m_bIsFolder=true;
742
743     if (CSettings::Get().GetBool("filelists.allowfiledeletion") &&
744         CUtil::SupportsWriteFileOperations(strDeletePath))
745     {
746       pItem->SetPath(strDeletePath);
747       CGUIWindowVideoBase::OnDeleteItem(pItem);
748     }
749   }
750
751   CUtil::DeleteVideoDatabaseDirectoryCache();
752 }
753
754 bool CGUIWindowVideoNav::DeleteItem(CFileItem* pItem, bool bUnavailable /* = false */)
755 {
756   if (!pItem->HasVideoInfoTag() || !CanDelete(pItem->GetPath()))
757     return false;
758
759   VIDEODB_CONTENT_TYPE iType=VIDEODB_CONTENT_MOVIES;
760   if (pItem->HasVideoInfoTag() && !pItem->GetVideoInfoTag()->m_strShowTitle.IsEmpty())
761     iType = VIDEODB_CONTENT_TVSHOWS;
762   if (pItem->HasVideoInfoTag() && pItem->GetVideoInfoTag()->m_iSeason > -1 && !pItem->m_bIsFolder)
763     iType = VIDEODB_CONTENT_EPISODES;
764   if (pItem->HasVideoInfoTag() && !pItem->GetVideoInfoTag()->m_artist.empty())
765     iType = VIDEODB_CONTENT_MUSICVIDEOS;
766
767   // dont allow update while scanning
768   if (g_application.IsVideoScanning())
769   {
770     CGUIDialogOK::ShowAndGetInput(257, 0, 14057, 0);
771     return false;
772   }
773
774
775   CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
776   if (!pDialog)
777     return false;
778   if (iType == VIDEODB_CONTENT_MOVIES)
779     pDialog->SetHeading(432);
780   if (iType == VIDEODB_CONTENT_EPISODES)
781     pDialog->SetHeading(20362);
782   if (iType == VIDEODB_CONTENT_TVSHOWS)
783     pDialog->SetHeading(20363);
784   if (iType == VIDEODB_CONTENT_MUSICVIDEOS)
785     pDialog->SetHeading(20392);
786
787   if(bUnavailable)
788   {
789     pDialog->SetLine(0, g_localizeStrings.Get(662));
790     pDialog->SetLine(1, g_localizeStrings.Get(663));
791     pDialog->SetLine(2, "");;
792     pDialog->DoModal();
793   }
794   else
795   {
796     CStdString strLine = StringUtils::Format(g_localizeStrings.Get(433), pItem->GetLabel().c_str());
797     pDialog->SetLine(0, strLine);
798     pDialog->SetLine(1, "");
799     pDialog->SetLine(2, "");;
800     pDialog->DoModal();
801   }
802
803   if (!pDialog->IsConfirmed())
804     return false;
805
806   CStdString path;
807   CVideoDatabase database;
808   database.Open();
809
810   database.GetFilePathById(pItem->GetVideoInfoTag()->m_iDbId, path, iType);
811   if (path.IsEmpty())
812     return false;
813   if (iType == VIDEODB_CONTENT_MOVIES)
814     database.DeleteMovie(path);
815   if (iType == VIDEODB_CONTENT_EPISODES)
816     database.DeleteEpisode(path, pItem->GetVideoInfoTag()->m_iDbId);
817   if (iType == VIDEODB_CONTENT_TVSHOWS)
818     database.DeleteTvShow(path);
819   if (iType == VIDEODB_CONTENT_MUSICVIDEOS)
820     database.DeleteMusicVideo(path);
821
822   if (iType == VIDEODB_CONTENT_TVSHOWS)
823     database.SetPathHash(path,"");
824   else
825     database.SetPathHash(URIUtils::GetDirectory(path), "");
826
827   return true;
828 }
829
830 void CGUIWindowVideoNav::GetContextButtons(int itemNumber, CContextButtons &buttons)
831 {
832   CFileItemPtr item;
833   if (itemNumber >= 0 && itemNumber < m_vecItems->Size())
834     item = m_vecItems->Get(itemNumber);
835
836   CGUIWindowVideoBase::GetContextButtons(itemNumber, buttons);
837
838   if (item && item->GetProperty("pluginreplacecontextitems").asBoolean())
839     return;
840
841   CVideoDatabaseDirectory dir;
842   NODE_TYPE node = dir.GetDirectoryChildType(m_vecItems->GetPath());
843
844   if (!item)
845   {
846     // nothing to do here
847   }
848   else if (m_vecItems->GetPath().Equals("sources://video/"))
849   {
850     // get the usual shares
851     CGUIDialogContextMenu::GetContextButtons("video", item, buttons);
852     // add scan button somewhere here
853     if (g_application.IsVideoScanning())
854       buttons.Add(CONTEXT_BUTTON_STOP_SCANNING, 13353);  // Stop Scanning
855     if (!item->IsDVD() && item->GetPath() != "add" && !item->IsParentFolder() &&
856         (CProfilesManager::Get().GetCurrentProfile().canWriteDatabases() || g_passwordManager.bMasterUser))
857     {
858       CVideoDatabase database;
859       database.Open();
860       ADDON::ScraperPtr info = database.GetScraperForPath(item->GetPath());
861
862       if (!g_application.IsVideoScanning())
863       {
864         if (!item->IsLiveTV() && !item->IsPlugin() && !item->IsAddonsPath() && !URIUtils::IsUPnP(item->GetPath()))
865         {
866           if (info && info->Content() != CONTENT_NONE)
867             buttons.Add(CONTEXT_BUTTON_SET_CONTENT, 20442);
868           else
869             buttons.Add(CONTEXT_BUTTON_SET_CONTENT, 20333);
870         }
871       }
872
873       if (info && !g_application.IsVideoScanning())
874         buttons.Add(CONTEXT_BUTTON_SCAN, 13349);
875     }
876   }
877   else
878   {
879     // are we in the playlists location?
880     bool inPlaylists = m_vecItems->GetPath().Equals(CUtil::VideoPlaylistsLocation()) ||
881                        m_vecItems->GetPath().Equals("special://videoplaylists/");
882
883     if (item->HasVideoInfoTag() && !item->GetVideoInfoTag()->m_artist.empty())
884     {
885       CMusicDatabase database;
886       database.Open();
887       if (database.GetArtistByName(StringUtils::Join(item->GetVideoInfoTag()->m_artist, g_advancedSettings.m_videoItemSeparator)) > -1)
888         buttons.Add(CONTEXT_BUTTON_GO_TO_ARTIST, 20396);
889     }
890     if (item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_strAlbum.size() > 0)
891     {
892       CMusicDatabase database;
893       database.Open();
894       if (database.GetAlbumByName(item->GetVideoInfoTag()->m_strAlbum) > -1)
895         buttons.Add(CONTEXT_BUTTON_GO_TO_ALBUM, 20397);
896     }
897     if (item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_strAlbum.size() > 0 &&
898         item->GetVideoInfoTag()->m_artist.size() > 0                              &&
899         item->GetVideoInfoTag()->m_strTitle.size() > 0)
900     {
901       CMusicDatabase database;
902       database.Open();
903       if (database.GetSongByArtistAndAlbumAndTitle(StringUtils::Join(item->GetVideoInfoTag()->m_artist, g_advancedSettings.m_videoItemSeparator),
904                                                    item->GetVideoInfoTag()->m_strAlbum,
905                                                    item->GetVideoInfoTag()->m_strTitle) > -1)
906       {
907         buttons.Add(CONTEXT_BUTTON_PLAY_OTHER, 20398);
908       }
909     }
910     if (!item->IsParentFolder())
911     {
912       ADDON::ScraperPtr info;
913       VIDEO::SScanSettings settings;
914       GetScraperForItem(item.get(), info, settings);
915
916       if (info && info->Content() == CONTENT_TVSHOWS)
917         buttons.Add(CONTEXT_BUTTON_INFO, item->m_bIsFolder ? 20351 : 20352);
918       else if (info && info->Content() == CONTENT_MUSICVIDEOS)
919         buttons.Add(CONTEXT_BUTTON_INFO,20393);
920       else if (info && info->Content() == CONTENT_MOVIES)
921         buttons.Add(CONTEXT_BUTTON_INFO, 13346);
922
923       // can we update the database?
924       if (CProfilesManager::Get().GetCurrentProfile().canWriteDatabases() || g_passwordManager.bMasterUser)
925       {
926         if (node == NODE_TYPE_TITLE_TVSHOWS)
927         {
928           if (g_application.IsVideoScanning())
929             buttons.Add(CONTEXT_BUTTON_STOP_SCANNING, 13353);
930           else
931             buttons.Add(CONTEXT_BUTTON_SCAN, 13349);
932         }
933         if (!item->IsPlugin() && !item->IsScript() && !item->IsLiveTV() && !item->IsAddonsPath() &&
934             item->GetPath() != "sources://video/" && item->GetPath() != "special://videoplaylists/" &&
935             item->GetPath().Left(19) != "newsmartplaylist://" && item->GetPath().Left(14) != "newplaylist://" &&
936             item->GetPath().Left(9) != "newtag://")
937         {
938           if (item->m_bIsFolder)
939           {
940             // Have both options for folders since we don't know whether all childs are watched/unwatched
941             buttons.Add(CONTEXT_BUTTON_MARK_UNWATCHED, 16104); //Mark as UnWatched
942             buttons.Add(CONTEXT_BUTTON_MARK_WATCHED, 16103);   //Mark as Watched
943           }
944           else
945           {
946             if (item->GetOverlayImage().Equals("OverlayWatched.png"))
947               buttons.Add(CONTEXT_BUTTON_MARK_UNWATCHED, 16104); //Mark as UnWatched
948             else
949               buttons.Add(CONTEXT_BUTTON_MARK_WATCHED, 16103);   //Mark as Watched
950           }
951         }
952         if (!g_application.IsVideoScanning() && item->IsVideoDb() && item->HasVideoInfoTag() &&
953            (!item->m_bIsFolder || m_vecItems->GetContent().Equals("movies") || m_vecItems->GetContent().Equals("tvshows")))
954         {
955           buttons.Add(CONTEXT_BUTTON_EDIT, 16106);
956         }
957
958         if (node == NODE_TYPE_SEASONS && item->m_bIsFolder)
959           buttons.Add(CONTEXT_BUTTON_SET_SEASON_ART, 13511);
960
961         if (StringUtils::StartsWithNoCase(item->GetPath(), "videodb://movies/sets/") && item->GetPath().size() > 22 && item->m_bIsFolder) // sets
962         {
963           buttons.Add(CONTEXT_BUTTON_SET_MOVIESET_ART, 13511);
964           buttons.Add(CONTEXT_BUTTON_MOVIESET_ADD_REMOVE_ITEMS, 20465);
965           buttons.Add(CONTEXT_BUTTON_DELETE, 646);
966         }
967
968         if (m_vecItems->GetContent() == "tags" && item->m_bIsFolder) // tags
969         {
970           CVideoDbUrl videoUrl;
971           if (videoUrl.FromString(item->GetPath()))
972           {
973             std::string mediaType = videoUrl.GetItemType();
974
975             CStdString strLabelAdd = StringUtils::Format(g_localizeStrings.Get(20460), GetLocalizedType(videoUrl.GetItemType()).c_str());
976             CStdString strLabelRemove = StringUtils::Format(g_localizeStrings.Get(20461), GetLocalizedType(videoUrl.GetItemType()).c_str());
977             buttons.Add(CONTEXT_BUTTON_TAGS_ADD_ITEMS, strLabelAdd);
978             buttons.Add(CONTEXT_BUTTON_TAGS_REMOVE_ITEMS, strLabelRemove);
979             buttons.Add(CONTEXT_BUTTON_DELETE, 646);
980           }
981         }
982
983         if (node == NODE_TYPE_ACTOR && !dir.IsAllItem(item->GetPath()) && item->m_bIsFolder)
984         {
985           if (StringUtils::StartsWithNoCase(m_vecItems->GetPath(), "videodb://musicvideos")) // mvids
986             buttons.Add(CONTEXT_BUTTON_SET_ARTIST_THUMB, 13359);
987           else
988             buttons.Add(CONTEXT_BUTTON_SET_ACTOR_THUMB, 20403);
989         }
990         if (item->IsVideoDb() && item->HasVideoInfoTag() &&
991           (!item->m_bIsFolder || node == NODE_TYPE_TITLE_TVSHOWS))
992           buttons.Add(CONTEXT_BUTTON_DELETE, 646);
993       }
994
995       if (!m_vecItems->IsVideoDb() && !m_vecItems->IsVirtualDirectoryRoot())
996       { // non-video db items, file operations are allowed
997         if ((CSettings::Get().GetBool("filelists.allowfiledeletion") &&
998             CUtil::SupportsWriteFileOperations(item->GetPath())) ||
999             (inPlaylists && !URIUtils::GetFileName(item->GetPath()).Equals("PartyMode-Video.xsp")
1000                          && (item->IsPlayList() || item->IsSmartPlayList())))
1001         {
1002           buttons.Add(CONTEXT_BUTTON_DELETE, 117);
1003           buttons.Add(CONTEXT_BUTTON_RENAME, 118);
1004         }
1005         // add "Set/Change content" to folders
1006         if (item->m_bIsFolder && !item->IsVideoDb() && !item->IsPlayList() && !item->IsSmartPlayList() && !item->IsLibraryFolder() && !item->IsLiveTV() && !item->IsPlugin() && !item->IsAddonsPath() && !URIUtils::IsUPnP(item->GetPath()))
1007         {
1008           if (!g_application.IsVideoScanning())
1009           {
1010             if (info && info->Content() != CONTENT_NONE)
1011             {
1012               buttons.Add(CONTEXT_BUTTON_SET_CONTENT, 20442);
1013               buttons.Add(CONTEXT_BUTTON_SCAN, 13349);
1014             }
1015             else
1016               buttons.Add(CONTEXT_BUTTON_SET_CONTENT, 20333);
1017           }
1018         }
1019       }
1020       if (item->IsPlugin() || item->IsScript() || m_vecItems->IsPlugin())
1021         buttons.Add(CONTEXT_BUTTON_PLUGIN_SETTINGS, 1045);
1022     }
1023   }
1024 }
1025
1026 // predicate used by sorting and set_difference
1027 bool compFileItemsByDbId(const CFileItemPtr& lhs, const CFileItemPtr& rhs) 
1028 {
1029   return lhs->HasVideoInfoTag() && rhs->HasVideoInfoTag() && lhs->GetVideoInfoTag()->m_iDbId < rhs->GetVideoInfoTag()->m_iDbId;
1030 }
1031
1032 bool CGUIWindowVideoNav::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
1033 {
1034   CFileItemPtr item;
1035   if (itemNumber >= 0 && itemNumber < m_vecItems->Size())
1036     item = m_vecItems->Get(itemNumber);
1037   if (CGUIDialogContextMenu::OnContextButton("video", item, button))
1038   {
1039     //TODO should we search DB for entries from plugins?
1040     if (button == CONTEXT_BUTTON_REMOVE_SOURCE && !item->IsPlugin()
1041         && !item->IsLiveTV() &&!item->IsRSS() && !URIUtils::IsUPnP(item->GetPath()))
1042     {
1043       OnUnAssignContent(item->GetPath(),20375,20340,20341);
1044     }
1045     Refresh();
1046     return true;
1047   }
1048   switch (button)
1049   {
1050   case CONTEXT_BUTTON_EDIT:
1051     {
1052       CONTEXT_BUTTON ret = (CONTEXT_BUTTON)CGUIDialogVideoInfo::ManageVideoItem(item);
1053       if (ret >= 0)
1054       {
1055         if (ret == CONTEXT_BUTTON_MARK_WATCHED)
1056           m_viewControl.SetSelectedItem(itemNumber + 1);
1057
1058         Refresh(true);
1059       }
1060       return true;
1061     }
1062
1063   case CONTEXT_BUTTON_SET_SEASON_ART:
1064   case CONTEXT_BUTTON_SET_ACTOR_THUMB:
1065   case CONTEXT_BUTTON_SET_ARTIST_THUMB:
1066   case CONTEXT_BUTTON_SET_MOVIESET_ART:
1067     {
1068       // Grab the thumbnails from the web
1069       CFileItemList items;
1070       CFileItemPtr noneitem(new CFileItem("thumb://None", false));
1071       CStdString currentThumb;
1072       int idArtist = -1;
1073       CStdString artistPath;
1074       string artType = "thumb";
1075       if (button == CONTEXT_BUTTON_SET_ARTIST_THUMB)
1076       {
1077         CMusicDatabase database;
1078         database.Open();
1079         idArtist = database.GetArtistByName(m_vecItems->Get(itemNumber)->GetLabel());
1080         database.GetArtistPath(idArtist, artistPath);
1081         currentThumb = database.GetArtForItem(idArtist, "artist", "thumb");
1082         if (currentThumb.empty())
1083           currentThumb = m_database.GetArtForItem(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_iDbId, m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_type, artType);
1084       }
1085       else if (button == CONTEXT_BUTTON_SET_ACTOR_THUMB)
1086         currentThumb = m_database.GetArtForItem(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_iDbId, m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_type, artType);
1087       else
1088       { // SEASON, SET
1089         map<string, string> currentArt;
1090         artType = CGUIDialogVideoInfo::ChooseArtType(*m_vecItems->Get(itemNumber), currentArt);
1091         if (artType.empty())
1092           return false;
1093
1094         if (artType == "fanart")
1095         {
1096           OnChooseFanart(*m_vecItems->Get(itemNumber));
1097           return true;
1098         }
1099
1100         if (currentArt.find(artType) != currentArt.end())
1101           currentThumb = currentArt[artType];
1102         else if ((artType == "poster" || artType == "banner") && currentArt.find("thumb") != currentArt.end())
1103           currentThumb = currentArt["thumb"];
1104       }
1105       if (!currentThumb.IsEmpty())
1106       {
1107         CFileItemPtr item(new CFileItem("thumb://Current", false));
1108         item->SetArt("thumb", currentThumb);
1109         item->SetLabel(g_localizeStrings.Get(13512));
1110         items.Add(item);
1111       }
1112       noneitem->SetIconImage("DefaultFolder.png");
1113       noneitem->SetLabel(g_localizeStrings.Get(13515));
1114
1115       vector<CStdString> thumbs;
1116       if (button != CONTEXT_BUTTON_SET_ARTIST_THUMB)
1117       {
1118         CVideoInfoTag tag;
1119         if (button == CONTEXT_BUTTON_SET_SEASON_ART)
1120           m_database.GetTvShowInfo("",tag,m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_iIdShow);
1121         else
1122           tag = *m_vecItems->Get(itemNumber)->GetVideoInfoTag();
1123         if (button == CONTEXT_BUTTON_SET_SEASON_ART)
1124           tag.m_strPictureURL.GetThumbURLs(thumbs, artType, m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_iSeason);
1125         else
1126           tag.m_strPictureURL.GetThumbURLs(thumbs, artType);
1127
1128         for (unsigned int i = 0; i < thumbs.size(); i++)
1129         {
1130           CStdString strItemPath = StringUtils::Format("thumb://Remote%i",i);
1131           CFileItemPtr item(new CFileItem(strItemPath, false));
1132           item->SetArt("thumb", thumbs[i]);
1133           item->SetIconImage("DefaultPicture.png");
1134           item->SetLabel(g_localizeStrings.Get(13513));
1135           items.Add(item);
1136
1137           // TODO: Do we need to clear the cached image?
1138           //    CTextureCache::Get().ClearCachedImage(thumbs[i]);
1139         }
1140       }
1141
1142       bool local=false;
1143       if (button == CONTEXT_BUTTON_SET_ARTIST_THUMB)
1144       {
1145         CStdString strThumb = URIUtils::AddFileToFolder(artistPath, "folder.jpg");
1146         if (XFILE::CFile::Exists(strThumb))
1147         {
1148           CFileItemPtr pItem(new CFileItem(strThumb,false));
1149           pItem->SetLabel(g_localizeStrings.Get(13514));
1150           pItem->SetArt("thumb", strThumb);
1151           items.Add(pItem);
1152           local = true;
1153         }
1154         else
1155           noneitem->SetIconImage("DefaultArtist.png");
1156       }
1157
1158       if (button == CONTEXT_BUTTON_SET_ACTOR_THUMB)
1159       {
1160         CStdString picturePath;
1161         CStdString strThumb = URIUtils::AddFileToFolder(picturePath, "folder.jpg");
1162         if (XFILE::CFile::Exists(strThumb))
1163         {
1164           CFileItemPtr pItem(new CFileItem(strThumb,false));
1165           pItem->SetLabel(g_localizeStrings.Get(13514));
1166           pItem->SetArt("thumb", strThumb);
1167           items.Add(pItem);
1168           local = true;
1169         }
1170         else
1171           noneitem->SetIconImage("DefaultActor.png");
1172       }
1173
1174       if (button == CONTEXT_BUTTON_SET_MOVIESET_ART)
1175         noneitem->SetIconImage("DefaultVideo.png");
1176
1177       if (!local)
1178         items.Add(noneitem);
1179
1180       VECSOURCES sources=*CMediaSourceSettings::Get().GetSources("video");
1181       g_mediaManager.GetLocalDrives(sources);
1182       CStdString result;
1183       CGUIDialogVideoInfo::AddItemPathToFileBrowserSources(sources, *item);
1184       if (!CGUIDialogFileBrowser::ShowAndGetImage(items, sources,
1185                                                   g_localizeStrings.Get(13511), result))
1186       {
1187         return false;   // user cancelled
1188       }
1189
1190       if (result == "thumb://Current")
1191         result = currentThumb;   // user chose the one they have
1192
1193       // delete the thumbnail if that's what the user wants, else overwrite with the
1194       // new thumbnail
1195       if (result.Left(14) == "thumb://Remote")
1196       {
1197         int number = atoi(result.Mid(14));
1198         result = thumbs[number];
1199       }
1200       else if (result == "thumb://None")
1201         result.clear();
1202       if (button == CONTEXT_BUTTON_SET_MOVIESET_ART ||
1203           button == CONTEXT_BUTTON_SET_ACTOR_THUMB ||
1204           button == CONTEXT_BUTTON_SET_SEASON_ART ||
1205          (button == CONTEXT_BUTTON_SET_ARTIST_THUMB && idArtist < 0))
1206         m_database.SetArtForItem(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_iDbId, m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_type, artType, result);
1207       else
1208       {
1209         CMusicDatabase db;
1210         if (db.Open())
1211           db.SetArtForItem(idArtist, "artist", artType, result);
1212       }
1213
1214       CUtil::DeleteVideoDatabaseDirectoryCache();
1215       CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_REFRESH_THUMBS);
1216       g_windowManager.SendMessage(msg);
1217       Refresh();
1218
1219       return true;
1220     }
1221   case CONTEXT_BUTTON_TAGS_ADD_ITEMS:
1222     {
1223       CVideoDbUrl videoUrl;
1224       if (!videoUrl.FromString(item->GetPath()))
1225         return false;
1226       
1227       std::string mediaType = videoUrl.GetItemType();
1228       mediaType = mediaType.substr(0, mediaType.length() - 1);
1229
1230       CFileItemList items;
1231       CStdString localizedType = GetLocalizedType(mediaType);
1232       CStdString strLabel = StringUtils::Format(g_localizeStrings.Get(20464), localizedType.c_str());
1233       if (!GetItemsForTag(strLabel, mediaType, items, item->GetVideoInfoTag()->m_iDbId))
1234         return true;
1235
1236       CVideoDatabase videodb;
1237       if (!videodb.Open())
1238         return true;
1239
1240       for (int index = 0; index < items.Size(); index++)
1241       {
1242         if (!items[index]->HasVideoInfoTag() || items[index]->GetVideoInfoTag()->m_iDbId <= 0)
1243           continue;
1244
1245         videodb.AddTagToItem(items[index]->GetVideoInfoTag()->m_iDbId, item->GetVideoInfoTag()->m_iDbId, mediaType);
1246       }
1247
1248       // we need to clear any cached version of this tag's listing
1249       items.SetPath(item->GetPath());
1250       items.RemoveDiscCache(GetID());
1251       return true;
1252     }
1253   case CONTEXT_BUTTON_TAGS_REMOVE_ITEMS:
1254     {
1255       CVideoDbUrl videoUrl;
1256       if (!videoUrl.FromString(item->GetPath()))
1257         return false;
1258       
1259       std::string mediaType = videoUrl.GetItemType();
1260       mediaType = mediaType.substr(0, mediaType.length() - 1);
1261
1262       CFileItemList items;
1263       CStdString localizedType = GetLocalizedType(mediaType);
1264       CStdString strLabel = StringUtils::Format(g_localizeStrings.Get(20464), localizedType.c_str());
1265       if (!GetItemsForTag(strLabel, mediaType, items, item->GetVideoInfoTag()->m_iDbId, false))
1266         return true;
1267
1268       CVideoDatabase videodb;
1269       if (!videodb.Open())
1270         return true;
1271
1272       for (int index = 0; index < items.Size(); index++)
1273       {
1274         if (!items[index]->HasVideoInfoTag() || items[index]->GetVideoInfoTag()->m_iDbId <= 0)
1275           continue;
1276
1277         videodb.RemoveTagFromItem(items[index]->GetVideoInfoTag()->m_iDbId, item->GetVideoInfoTag()->m_iDbId, mediaType);
1278       }
1279
1280       // we need to clear any cached version of this tag's listing
1281       items.SetPath(item->GetPath());
1282       items.RemoveDiscCache(GetID());
1283       return true;
1284     }
1285   case CONTEXT_BUTTON_MOVIESET_ADD_REMOVE_ITEMS:
1286     {
1287       CFileItemList originalItems;
1288       CFileItemList selectedItems;
1289
1290       if (!CGUIDialogVideoInfo::GetMoviesForSet(item.get(), originalItems, selectedItems) || selectedItems.Size() == 0) // need at least one item selected
1291         return true;
1292       VECFILEITEMS original = originalItems.GetList();
1293       std::sort(original.begin(), original.end(), compFileItemsByDbId);
1294       VECFILEITEMS selected = selectedItems.GetList();
1295       std::sort(selected.begin(), selected.end(), compFileItemsByDbId);
1296
1297       bool refreshNeeded = false;
1298       // update the "added" items
1299       VECFILEITEMS addedItems;
1300       set_difference(selected.begin(),selected.end(), original.begin(),original.end(), std::back_inserter(addedItems), compFileItemsByDbId);
1301       for (VECFILEITEMS::iterator it = addedItems.begin();  it != addedItems.end(); ++it)
1302       {
1303         if (CGUIDialogVideoInfo::SetMovieSet(it->get(), item.get()))
1304           refreshNeeded = true;
1305       }
1306       // update the "deleted" items
1307       CFileItemPtr clearItem(new CFileItem());
1308       clearItem->GetVideoInfoTag()->m_iDbId = -1; // -1 will be used to clear set
1309       VECFILEITEMS deletedItems;
1310       set_difference(original.begin(),original.end(), selected.begin(),selected.end(), std::back_inserter(deletedItems), compFileItemsByDbId);
1311       for (VECFILEITEMS::iterator it = deletedItems.begin();  it != deletedItems.end(); ++it)
1312       {
1313         if (CGUIDialogVideoInfo::SetMovieSet(it->get(), clearItem.get()))
1314           refreshNeeded = true;
1315       }
1316
1317       // we need to clear any cached version of this tag's listing
1318       if (refreshNeeded) 
1319         Refresh();
1320       return true;
1321     }
1322   case CONTEXT_BUTTON_GO_TO_ARTIST:
1323     {
1324       CStdString strPath;
1325       CMusicDatabase database;
1326       database.Open();
1327       strPath = StringUtils::Format("musicdb://artists/%ld/",
1328                                     database.GetArtistByName(StringUtils::Join(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_artist, g_advancedSettings.m_videoItemSeparator)));
1329       g_windowManager.ActivateWindow(WINDOW_MUSIC_NAV,strPath);
1330       return true;
1331     }
1332   case CONTEXT_BUTTON_GO_TO_ALBUM:
1333     {
1334       CStdString strPath;
1335       CMusicDatabase database;
1336       database.Open();
1337       strPath = StringUtils::Format("musicdb://albums/%ld/",
1338                                     database.GetAlbumByName(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strAlbum));
1339       g_windowManager.ActivateWindow(WINDOW_MUSIC_NAV,strPath);
1340       return true;
1341     }
1342   case CONTEXT_BUTTON_PLAY_OTHER:
1343     {
1344       CMusicDatabase database;
1345       database.Open();
1346       CSong song;
1347       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,
1348                                                                         m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strTitle),
1349                                                                         song))
1350       {
1351         CApplicationMessenger::Get().PlayFile(song);
1352       }
1353       return true;
1354     }
1355
1356   default:
1357     break;
1358
1359   }
1360   return CGUIWindowVideoBase::OnContextButton(itemNumber, button);
1361 }
1362
1363 void CGUIWindowVideoNav::OnChooseFanart(const CFileItem &videoItem)
1364 {
1365   if (!videoItem.HasVideoInfoTag())
1366     return;
1367
1368   CFileItem item(videoItem);
1369
1370   CFileItemList items;
1371
1372   CVideoThumbLoader loader;
1373   loader.LoadItem(&item);
1374
1375   if (item.HasArt("fanart"))
1376   {
1377     CFileItemPtr itemCurrent(new CFileItem("fanart://Current",false));
1378     itemCurrent->SetArt("thumb", item.GetArt("fanart"));
1379     itemCurrent->SetLabel(g_localizeStrings.Get(20440));
1380     items.Add(itemCurrent);
1381   }
1382
1383   // add the none option
1384   {
1385     CFileItemPtr itemNone(new CFileItem("fanart://None", false));
1386     itemNone->SetIconImage("DefaultVideo.png");
1387     itemNone->SetLabel(g_localizeStrings.Get(20439));
1388     items.Add(itemNone);
1389   }
1390
1391   CStdString result;
1392   VECSOURCES sources(*CMediaSourceSettings::Get().GetSources("video"));
1393   g_mediaManager.GetLocalDrives(sources);
1394   CGUIDialogVideoInfo::AddItemPathToFileBrowserSources(sources, item);
1395   bool flip=false;
1396   if (!CGUIDialogFileBrowser::ShowAndGetImage(items, sources, g_localizeStrings.Get(20437), result, &flip, 20445) || result.Equals("fanart://Current"))
1397     return;
1398
1399   if (result.Equals("fanart://None") || !CFile::Exists(result))
1400     result.clear();
1401   if (!result.IsEmpty() && flip)
1402     result = CTextureUtils::GetWrappedImageURL(result, "", "flipped");
1403
1404   // update the db
1405   CVideoDatabase db;
1406   if (db.Open())
1407   {
1408     db.SetArtForItem(item.GetVideoInfoTag()->m_iDbId, item.GetVideoInfoTag()->m_type, "fanart", result);
1409     db.Close();
1410   }
1411
1412   // clear view cache and reload images
1413   CUtil::DeleteVideoDatabaseDirectoryCache();
1414
1415   Refresh();
1416 }
1417
1418 bool CGUIWindowVideoNav::OnClick(int iItem)
1419 {
1420   CFileItemPtr item = m_vecItems->Get(iItem);
1421   if (!item->m_bIsFolder && item->IsVideoDb() && !item->Exists())
1422   {
1423     CLog::Log(LOGDEBUG, "%s called on '%s' but file doesn't exist", __FUNCTION__, item->GetPath().c_str());
1424     if (!DeleteItem(item.get(), true))
1425       return true;
1426
1427     // update list
1428     Refresh(true);
1429     m_viewControl.SetSelectedItem(iItem);
1430     return true;
1431   }
1432   else if (StringUtils::StartsWithNoCase(item->GetPath(), "newtag://"))
1433   {
1434     // dont allow update while scanning
1435     if (g_application.IsVideoScanning())
1436     {
1437       CGUIDialogOK::ShowAndGetInput(257, 0, 14057, 0);
1438       return true;
1439     }
1440
1441     //Get the new title
1442     CStdString strTag;
1443     if (!CGUIKeyboardFactory::ShowAndGetInput(strTag, g_localizeStrings.Get(20462), false))
1444       return true;
1445
1446     CVideoDatabase videodb;
1447     if (!videodb.Open())
1448       return true;
1449
1450     // get the media type and convert from plural to singular (by removing the trailing "s")
1451     CStdString mediaType = item->GetPath().Mid(9);
1452     mediaType = mediaType.Left(mediaType.size() - 1);
1453     CStdString localizedType = GetLocalizedType(mediaType);
1454     if (localizedType.empty())
1455       return true;
1456
1457     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())
1458     {
1459       CStdString strError = StringUtils::Format(g_localizeStrings.Get(20463), strTag.c_str());
1460       CGUIDialogOK::ShowAndGetInput(20462, "", strError, "");
1461       return true;
1462     }
1463
1464     int idTag = videodb.AddTag(strTag);
1465     CFileItemList items;
1466     CStdString strLabel = StringUtils::Format(g_localizeStrings.Get(20464), localizedType.c_str());
1467     if (GetItemsForTag(strLabel, mediaType, items, idTag))
1468     {
1469       for (int index = 0; index < items.Size(); index++)
1470       {
1471         if (!items[index]->HasVideoInfoTag() || items[index]->GetVideoInfoTag()->m_iDbId <= 0)
1472           continue;
1473
1474         videodb.AddTagToItem(items[index]->GetVideoInfoTag()->m_iDbId, idTag, mediaType);
1475       }
1476     }
1477
1478     Refresh(true);
1479     return true;
1480   }
1481
1482   return CGUIWindowVideoBase::OnClick(iItem);
1483 }
1484
1485 CStdString CGUIWindowVideoNav::GetStartFolder(const CStdString &dir)
1486 {
1487   if (dir.Equals("MovieGenres"))
1488     return "videodb://movies/genres/";
1489   else if (dir.Equals("MovieTitles"))
1490     return "videodb://movies/titles/";
1491   else if (dir.Equals("MovieYears"))
1492     return "videodb://movies/years/";
1493   else if (dir.Equals("MovieActors"))
1494     return "videodb://movies/actors/";
1495   else if (dir.Equals("MovieDirectors"))
1496     return "videodb://movies/directors/";
1497   else if (dir.Equals("MovieStudios"))
1498     return "videodb://movies/studios/";
1499   else if (dir.Equals("MovieSets"))
1500     return "videodb://movies/sets/";
1501   else if (dir.Equals("MovieCountries"))
1502     return "videodb://movies/countries/";
1503   else if (dir.Equals("MovieTags"))
1504     return "videodb://movies/tags/";
1505   else if (dir.Equals("Movies"))
1506     return "videodb://movies/";
1507   else if (dir.Equals("TvShowGenres"))
1508     return "videodb://tvshows/genres/";
1509   else if (dir.Equals("TvShowTitles"))
1510     return "videodb://tvshows/titles/";
1511   else if (dir.Equals("TvShowYears"))
1512     return "videodb://tvshows/years/";
1513   else if (dir.Equals("TvShowActors"))
1514     return "videodb://tvshows/actors/";
1515   else if (dir.Equals("TvShowStudios"))
1516     return "videodb://tvshows/studios/";
1517   else if (dir.Equals("TvShowTags"))
1518     return "videodb://tvshows/tags/";
1519   else if (dir.Equals("TvShows"))
1520     return "videodb://tvshows/";
1521   else if (dir.Equals("MusicVideoGenres"))
1522     return "videodb://musicvideos/genres/";
1523   else if (dir.Equals("MusicVideoTitles"))
1524     return "videodb://musicvideos/titles/";
1525   else if (dir.Equals("MusicVideoYears"))
1526     return "videodb://musicvideos/years/";
1527   else if (dir.Equals("MusicVideoArtists"))
1528     return "videodb://musicvideos/artists/";
1529   else if (dir.Equals("MusicVideoAlbums"))
1530     return "videodb://musicvideos/albums/";
1531   else if (dir.Equals("MusicVideoDirectors"))
1532     return "videodb://musicvideos/directors/";
1533   else if (dir.Equals("MusicVideoStudios"))
1534     return "videodb://musicvideos/studios/";
1535   else if (dir.Equals("MusicVideoTags"))
1536     return "videodb://musicvideos/tags/";
1537   else if (dir.Equals("MusicVideos"))
1538     return "videodb://musicvideos/";
1539   else if (dir.Equals("RecentlyAddedMovies"))
1540     return "videodb://recentlyaddedmovies/";
1541   else if (dir.Equals("RecentlyAddedEpisodes"))
1542     return "videodb://recentlyaddedepisodes/";
1543   else if (dir.Equals("RecentlyAddedMusicVideos"))
1544     return "videodb://recentlyaddedmusicvideos/";
1545   else if (dir.Equals("Files"))
1546     return "sources://video/";
1547   return CGUIWindowVideoBase::GetStartFolder(dir);
1548 }
1549
1550 bool CGUIWindowVideoNav::ApplyWatchedFilter(CFileItemList &items)
1551 {
1552   bool listchanged = false;
1553   CVideoDatabaseDirectory dir;
1554   NODE_TYPE node = dir.GetDirectoryChildType(items.GetPath());
1555
1556   // now filter watched items as necessary
1557   bool filterWatched=false;
1558   if (node == NODE_TYPE_EPISODES
1559   ||  node == NODE_TYPE_SEASONS
1560   ||  node == NODE_TYPE_SETS
1561   ||  node == NODE_TYPE_TAGS
1562   ||  node == NODE_TYPE_TITLE_MOVIES
1563   ||  node == NODE_TYPE_TITLE_TVSHOWS
1564   ||  node == NODE_TYPE_TITLE_MUSICVIDEOS
1565   ||  node == NODE_TYPE_RECENTLY_ADDED_EPISODES
1566   ||  node == NODE_TYPE_RECENTLY_ADDED_MOVIES
1567   ||  node == NODE_TYPE_RECENTLY_ADDED_MUSICVIDEOS)
1568     filterWatched = true;
1569   if (!items.IsVideoDb())
1570     filterWatched = true;
1571   if (items.GetContent() == "tvshows" &&
1572      (items.IsSmartPlayList() || items.IsLibraryFolder()))
1573     node = NODE_TYPE_TITLE_TVSHOWS; // so that the check below works
1574
1575   int watchMode = CMediaSettings::Get().GetWatchedMode(m_vecItems->GetContent());
1576
1577   for (int i = 0; i < items.Size(); i++)
1578   {
1579     CFileItemPtr item = items.Get(i);
1580
1581     if(item->HasVideoInfoTag() && (node == NODE_TYPE_TITLE_TVSHOWS || node == NODE_TYPE_SEASONS))
1582     {
1583       if (watchMode == WatchedModeUnwatched)
1584         item->GetVideoInfoTag()->m_iEpisode = (int)item->GetProperty("unwatchedepisodes").asInteger();
1585       if (watchMode == WatchedModeWatched)
1586         item->GetVideoInfoTag()->m_iEpisode = (int)item->GetProperty("watchedepisodes").asInteger();
1587       if (watchMode == WatchedModeAll)
1588         item->GetVideoInfoTag()->m_iEpisode = (int)item->GetProperty("totalepisodes").asInteger();
1589       item->SetProperty("numepisodes", item->GetVideoInfoTag()->m_iEpisode);
1590       listchanged = true;
1591     }
1592
1593     if (filterWatched)
1594     {
1595       if((watchMode==WatchedModeWatched   && item->GetVideoInfoTag()->m_playCount== 0)
1596       || (watchMode==WatchedModeUnwatched && item->GetVideoInfoTag()->m_playCount > 0))
1597       {
1598         items.Remove(i);
1599         i--;
1600         listchanged = true;
1601       }
1602     }
1603   }
1604
1605   if(node == NODE_TYPE_TITLE_TVSHOWS || node == NODE_TYPE_SEASONS)
1606   {
1607     // the watched filter may change the "numepisodes" property which is reflected in the TV_SHOWS and SEASONS nodes
1608     // therefore, the items labels have to be refreshed, and possibly the list needs resorting as well.
1609     items.ClearSortState(); // this is needed to force resorting even if sort method did not change
1610     FormatAndSort(items);
1611   }
1612
1613   return listchanged;
1614 }
1615
1616 bool CGUIWindowVideoNav::GetItemsForTag(const CStdString &strHeading, const std::string &type, CFileItemList &items, int idTag /* = -1 */, bool showAll /* = true */)
1617 {
1618   CVideoDatabase videodb;
1619   if (!videodb.Open())
1620     return false;
1621
1622   MediaType mediaType = MediaTypeNone;
1623   std::string baseDir = "videodb://";
1624   std::string idColumn;
1625   if (type.compare("movie") == 0)
1626   {
1627     mediaType = MediaTypeMovie;
1628     baseDir += "movies";
1629     idColumn = "idMovie";
1630   }
1631   else if (type.compare("tvshow") == 0)
1632   {
1633     mediaType = MediaTypeTvShow;
1634     baseDir += "tvshows";
1635     idColumn = "idShow";
1636   }
1637   else if (type.compare("musicvideo") == 0)
1638   {
1639     mediaType = MediaTypeMusicVideo;
1640     baseDir += "musicvideos";
1641     idColumn = "idMVideo";
1642   }
1643
1644   baseDir += "/titles/";
1645   CVideoDbUrl videoUrl;
1646   if (!videoUrl.FromString(baseDir))
1647     return false;
1648
1649   CVideoDatabase::Filter filter;
1650   if (idTag > 0)
1651   {
1652     if (!showAll)
1653       videoUrl.AddOption("tagid", idTag);
1654     else
1655       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());
1656   }
1657
1658   CFileItemList listItems;
1659   if (!videodb.GetSortedVideos(mediaType, videoUrl.ToString(), SortDescription(), listItems, filter) || listItems.Size() <= 0)
1660     return false;
1661
1662   CGUIDialogSelect *dialog = (CGUIDialogSelect *)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
1663   if (dialog == NULL)
1664     return false;
1665
1666   listItems.Sort(SortByLabel, SortOrderAscending, SortAttributeIgnoreArticle);
1667
1668   dialog->Reset();
1669   dialog->SetMultiSelection(true);
1670   dialog->SetHeading(strHeading);
1671   dialog->SetItems(&listItems);
1672   dialog->EnableButton(true, 186);
1673   dialog->DoModal();
1674
1675   items.Copy(dialog->GetSelectedItems());
1676   return items.Size() > 0;
1677 }
1678
1679 CStdString CGUIWindowVideoNav::GetLocalizedType(const std::string &strType)
1680 {
1681   if (strType == "movie" || strType == "movies")
1682     return g_localizeStrings.Get(20342);
1683   else if (strType == "tvshow" || strType == "tvshows")
1684     return g_localizeStrings.Get(20343);
1685   else if (strType == "episode" || strType == "episodes")
1686     return g_localizeStrings.Get(20359);
1687   else if (strType == "musicvideo" || strType == "musicvideos")
1688     return g_localizeStrings.Get(20391);
1689   else
1690     return "";
1691 }