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