2 * Copyright (C) 2005-2013 Team XBMC
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)
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.
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/>.
21 #include "GUIUserMessages.h"
22 #include "GUIWindowVideoNav.h"
23 #include "music/windows/GUIWindowMusicNav.h"
24 #include "utils/FileUtils.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"
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"
62 using namespace XFILE;
63 using namespace VIDEODATABASEDIRECTORY;
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
73 #define CONTROL_BTN_FILTER 19
74 #define CONTROL_BTNSHOWMODE 10
75 #define CONTROL_BTNSHOWALL 14
76 #define CONTROL_UNLOCK 11
78 #define CONTROL_FILTER 15
79 #define CONTROL_BTNPARTYMODE 16
80 #define CONTROL_LABELEMPTY 18
82 #define CONTROL_UPDATE_LIBRARY 20
84 CGUIWindowVideoNav::CGUIWindowVideoNav(void)
85 : CGUIWindowVideoBase(WINDOW_VIDEO_NAV, "MyVideoNav.xml")
87 m_thumbLoader.SetObserver(this);
90 CGUIWindowVideoNav::~CGUIWindowVideoNav(void)
94 bool CGUIWindowVideoNav::OnAction(const CAction &action)
96 if (action.GetID() == ACTION_TOGGLE_WATCHED)
98 CFileItemPtr pItem = m_vecItems->Get(m_viewControl.GetSelectedItem());
99 if (pItem->IsParentFolder())
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);
106 return CGUIWindowVideoBase::OnAction(action);
109 bool CGUIWindowVideoNav::OnMessage(CGUIMessage& message)
111 switch (message.GetMessage())
113 case GUI_MSG_WINDOW_RESET:
114 m_vecItems->SetPath("");
116 case GUI_MSG_WINDOW_DEINIT:
117 if (m_thumbLoader.IsLoading())
118 m_thumbLoader.StopThread();
120 case GUI_MSG_WINDOW_INIT:
122 /* We don't want to show Autosourced items (ie removable pendrives, memorycards) in Library mode */
123 m_rootDir.AllowNonLocalSources(false);
125 SetProperty("flattened", CSettings::Get().GetBool("myvideos.flatten"));
126 if (message.GetNumStringParams() && message.GetStringParam(0).Equals("Files") &&
127 CMediaSourceSettings::Get().GetSources("video")->empty())
129 message.SetStringParam("");
132 if (!CGUIWindowVideoBase::OnMessage(message))
139 case GUI_MSG_CLICKED:
141 int iControl = message.GetSenderId();
142 if (iControl == CONTROL_BTNPARTYMODE)
144 if (g_partyModeManager.IsEnabled())
145 g_partyModeManager.Disable();
148 if (!g_partyModeManager.Enable(PARTYMODECONTEXT_VIDEO))
150 SET_CONTROL_SELECTED(GetID(),CONTROL_BTNPARTYMODE,false);
154 // Playlist directory is the root of the playlist window
155 if (m_guiState.get()) m_guiState->SetPlaylistDirectory("playlistvideo://");
162 if (iControl == CONTROL_BTNSEARCH)
166 else if (iControl == CONTROL_BTNSHOWMODE)
168 CMediaSettings::Get().CycleWatchedMode(m_vecItems->GetContent());
169 CSettings::Get().Save();
170 OnFilterItems(GetProperty("filter").asString());
173 else if (iControl == CONTROL_BTNSHOWALL)
175 if (CMediaSettings::Get().GetWatchedMode(m_vecItems->GetContent()) == WatchedModeAll)
176 CMediaSettings::Get().SetWatchedMode(m_vecItems->GetContent(), WatchedModeUnwatched);
178 CMediaSettings::Get().SetWatchedMode(m_vecItems->GetContent(), WatchedModeAll);
179 CSettings::Get().Save();
180 OnFilterItems(GetProperty("filter").asString());
183 else if (iControl == CONTROL_UPDATE_LIBRARY)
185 if (!g_application.IsVideoScanning())
188 g_application.StopVideoScan();
193 // update the display
194 case GUI_MSG_SCAN_FINISHED:
195 case GUI_MSG_REFRESH_THUMBS:
199 return CGUIWindowVideoBase::OnMessage(message);
202 CStdString CGUIWindowVideoNav::GetQuickpathName(const CStdString& strPath) const
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/"))
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/"))
219 else if (path.Equals("videodb://movies/countries/"))
220 return "MovieCountries";
221 else if (path.Equals("videodb://movies/tags/"))
223 else if (path.Equals("videodb://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/"))
237 else if (path.Equals("videodb://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/"))
261 else if (path.Equals("sources://video/"))
265 CLog::Log(LOGERROR, " CGUIWindowVideoNav::GetQuickpathName: Unknown parameter (%s)", strPath.c_str());
270 bool CGUIWindowVideoNav::GetDirectory(const CStdString &strDirectory, CFileItemList &items)
272 if (m_thumbLoader.IsLoading())
273 m_thumbLoader.StopThread();
275 items.ClearProperties();
277 bool bResult = CGUIWindowVideoBase::GetDirectory(strDirectory, items);
280 if (items.IsVideoDb())
282 XFILE::CVideoDatabaseDirectory dir;
284 dir.GetQueryParams(items.GetPath(),params);
285 VIDEODATABASEDIRECTORY::NODE_TYPE node = dir.GetDirectoryChildType(items.GetPath());
287 items.SetArt("thumb", "");
288 if (node == VIDEODATABASEDIRECTORY::NODE_TYPE_EPISODES ||
289 node == NODE_TYPE_SEASONS ||
290 node == NODE_TYPE_RECENTLY_ADDED_EPISODES)
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))
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");
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));
315 // save the show description (showplot)
316 items.SetProperty("showplot", details.m_strPlot);
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)
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))
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");
336 items.SetContent("seasons");
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)
352 if (params.GetContentType() == VIDEODB_CONTENT_MUSICVIDEOS)
353 items.SetContent("artists");
355 items.SetContent("actors");
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");
370 items.SetContent("");
372 else if (!items.IsVirtualDirectoryRoot())
373 { // load info from the database
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);
381 CVideoDbUrl videoUrl;
382 if (videoUrl.FromString(items.GetPath()) && items.GetContent() == "tags" &&
383 !items.Contains("newtag://" + videoUrl.GetType()))
385 CFileItemPtr newTag(new CFileItem("newtag://" + videoUrl.GetType(), false));
386 newTag->SetLabel(g_localizeStrings.Get(20462));
387 newTag->SetLabelPreformated(true);
388 newTag->SetSpecialSort(SortSpecialOnTop);
395 void CGUIWindowVideoNav::LoadVideoInfo(CFileItemList &items)
397 LoadVideoInfo(items, m_database);
400 void CGUIWindowVideoNav::LoadVideoInfo(CFileItemList &items, CVideoDatabase &database, bool allowReplaceLabels)
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
407 CStdString content = items.GetContent();
408 // determine content only if it isn't set
411 content = database.GetContentForPath(items.GetPath());
412 items.SetContent(content.empty() ? "files" : content);
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.
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.
423 Similarly, we assign the "clean" library labels to the item only if the "Replace filenames with library titles"
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");
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())
435 database.GetItemsForPath(content, items.GetPath(), dbItems);
436 dbItems.SetFastLookup(true);
439 for (int i = 0; i < items.Size(); i++)
441 CFileItemPtr pItem = items[i];
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());
447 pItem->UpdateInfo(*match, replaceLabels);
451 if (match->m_bIsFolder)
452 pItem->SetPath(match->GetVideoInfoTag()->m_strPath);
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)
459 items.SetSortIgnoreFolders(true);
460 pItem->m_bIsFolder = match->m_bIsFolder;
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)
471 database.GetPlayCounts(items.GetPath(), items);
472 fetchedPlayCounts = true;
475 // preferably use some information from PVR info tag if available
476 if (pItem->HasPVRRecordingInfoTag())
477 pItem->GetPVRRecordingInfoTag()->CopyClientInfo(pItem->GetVideoInfoTag());
479 // set the watched overlay
480 if (pItem->IsVideo())
481 pItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, pItem->HasVideoInfoTag() && pItem->GetVideoInfoTag()->m_playCount > 0);
486 void CGUIWindowVideoNav::UpdateButtons()
488 CGUIWindowVideoBase::UpdateButtons();
490 // Update object count
491 int iItems = m_vecItems->Size();
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++)
498 CFileItemPtr pItem = m_vecItems->Get(i);
499 if (pItem->IsParentFolder()) iItems--;
500 if (StringUtils::StartsWith(pItem->GetPath(), "/-1/")) iItems--;
503 if (m_vecItems->Size() > 2 &&
504 StringUtils::StartsWith(m_vecItems->Get(m_vecItems->Size()-1)->GetPath(), "/-1/"))
507 CStdString items = StringUtils::Format("%i %s", iItems, g_localizeStrings.Get(127).c_str());
508 SET_CONTROL_LABEL(CONTROL_LABELFILES, items);
510 // set the filter label
514 if (m_vecItems->GetPath().Equals("special://videoplaylists/"))
515 strLabel = g_localizeStrings.Get(136);
517 else if (m_vecItems->IsPlayList())
519 // get playlist name from path
521 URIUtils::Split(m_vecItems->GetPath(), strDummy, strLabel);
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())
528 CVideoDatabaseDirectory dir;
529 dir.GetLabel(m_vecItems->GetPath(), strLabel);
532 strLabel = URIUtils::GetFileName(m_vecItems->GetPath());
534 SET_CONTROL_LABEL(CONTROL_FILTER, strLabel);
536 int watchMode = CMediaSettings::Get().GetWatchedMode(m_vecItems->GetContent());
537 SET_CONTROL_LABEL(CONTROL_BTNSHOWMODE, g_localizeStrings.Get(16100 + watchMode));
539 SET_CONTROL_SELECTED(GetID(), CONTROL_BTNSHOWALL, watchMode != WatchedModeAll);
541 SET_CONTROL_SELECTED(GetID(),CONTROL_BTNPARTYMODE, g_partyModeManager.IsEnabled());
543 CONTROL_ENABLE_ON_CONDITION(CONTROL_UPDATE_LIBRARY, !m_vecItems->IsAddonsPath() && !m_vecItems->IsPlugin() && !m_vecItems->IsScript());
546 bool CGUIWindowVideoNav::GetFilteredItems(const CStdString &filter, CFileItemList &items)
548 bool listchanged = CGUIMediaWindow::GetFilteredItems(filter, items);
549 listchanged |= ApplyWatchedFilter(items);
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)
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
567 m_database.GetMoviesByName(strSearch, tempItems);
568 AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(20338) + "] ", items);
570 m_database.GetEpisodesByName(strSearch, tempItems);
571 AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(20359) + "] ", items);
573 m_database.GetTvShowsByName(strSearch, tempItems);
574 AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(20364) + "] ", items);
576 m_database.GetMusicVideosByName(strSearch, tempItems);
577 AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(20391) + "] ", items);
579 m_database.GetMusicVideosByAlbum(strSearch, tempItems);
580 AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(558) + "] ", items);
582 // get matching genres
583 m_database.GetMovieGenresByName(strSearch, tempItems);
584 AppendAndClearSearchItems(tempItems, "[" + strGenre + " - " + g_localizeStrings.Get(20342) + "] ", items);
586 m_database.GetTvShowGenresByName(strSearch, tempItems);
587 AppendAndClearSearchItems(tempItems, "[" + strGenre + " - " + g_localizeStrings.Get(20343) + "] ", items);
589 m_database.GetMusicVideoGenresByName(strSearch, tempItems);
590 AppendAndClearSearchItems(tempItems, "[" + strGenre + " - " + g_localizeStrings.Get(20389) + "] ", items);
593 m_database.GetMovieActorsByName(strSearch, tempItems);
594 AppendAndClearSearchItems(tempItems, "[" + strActor + " - " + g_localizeStrings.Get(20342) + "] ", items);
596 m_database.GetTvShowsActorsByName(strSearch, tempItems);
597 AppendAndClearSearchItems(tempItems, "[" + strActor + " - " + g_localizeStrings.Get(20343) + "] ", items);
599 m_database.GetMusicVideoArtistsByName(strSearch, tempItems);
600 AppendAndClearSearchItems(tempItems, "[" + strActor + " - " + g_localizeStrings.Get(20389) + "] ", items);
603 m_database.GetMovieDirectorsByName(strSearch, tempItems);
604 AppendAndClearSearchItems(tempItems, "[" + strDirector + " - " + g_localizeStrings.Get(20342) + "] ", items);
606 m_database.GetTvShowsDirectorsByName(strSearch, tempItems);
607 AppendAndClearSearchItems(tempItems, "[" + strDirector + " - " + g_localizeStrings.Get(20343) + "] ", items);
609 m_database.GetMusicVideoDirectorsByName(strSearch, tempItems);
610 AppendAndClearSearchItems(tempItems, "[" + strDirector + " - " + g_localizeStrings.Get(20389) + "] ", items);
613 m_database.GetEpisodesByPlot(strSearch, tempItems);
614 AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(20365) + "] ", items);
616 m_database.GetMoviesByPlot(strSearch, tempItems);
617 AppendAndClearSearchItems(tempItems, "[" + strMovie + " " + g_localizeStrings.Get(207) + "] ", items);
620 void CGUIWindowVideoNav::PlayItem(int iItem)
622 // unlike additemtoplaylist, we need to check the items here
623 // before calling it since the current playlist will be stopped
626 // root is not allowed
627 if (m_vecItems->IsVirtualDirectoryRoot())
630 CGUIWindowVideoBase::PlayItem(iItem);
633 void CGUIWindowVideoNav::OnInfo(CFileItem* pItem, ADDON::ScraperPtr& scraper)
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);
640 CStdString strPath,strFile;
641 URIUtils::Split(pItem->GetPath(),strPath,strFile);
642 scraper = m_database.GetScraperForPath(strPath);
645 CGUIWindowVideoBase::OnInfo(pItem,scraper);
648 void CGUIWindowVideoNav::OnDeleteItem(CFileItemPtr pItem)
650 if (m_vecItems->IsParentFolder())
653 if (!m_vecItems->IsVideoDb() && !pItem->IsVideoDb())
655 if (!pItem->GetPath().Equals("newsmartplaylist://video") &&
656 !pItem->GetPath().Equals("special://videoplaylists/") &&
657 !pItem->GetPath().Equals("sources://video/") &&
658 !StringUtils::StartsWithNoCase(pItem->GetPath(), "newtag://"))
659 CGUIWindowVideoBase::OnDeleteItem(pItem);
661 else if (StringUtils::StartsWithNoCase(pItem->GetPath(), "videodb://movies/sets/") &&
662 pItem->GetPath().size() > 22 && pItem->m_bIsFolder)
664 CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
665 pDialog->SetHeading(432);
666 CStdString strLabel = StringUtils::Format(g_localizeStrings.Get(433),pItem->GetLabel().c_str());
667 pDialog->SetLine(1, strLabel);
668 pDialog->SetLine(2, "");;
670 if (pDialog->IsConfirmed())
673 CDirectory::GetDirectory(pItem->GetPath(),items,"",DIR_FLAG_NO_FILE_DIRS);
674 for (int i=0;i<items.Size();++i)
675 OnDeleteItem(items[i]);
677 CVideoDatabaseDirectory dir;
679 dir.GetQueryParams(pItem->GetPath(),params);
680 m_database.DeleteSet(params.GetSetId());
683 else if (m_vecItems->GetContent() == "tags" && pItem->m_bIsFolder)
685 CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
686 pDialog->SetHeading(432);
687 CStdString strLabel = StringUtils::Format(g_localizeStrings.Get(433), pItem->GetLabel().c_str());
688 pDialog->SetLine(1, strLabel);
689 pDialog->SetLine(2, "");
691 if (pDialog->IsConfirmed())
693 CVideoDatabaseDirectory dir;
695 dir.GetQueryParams(pItem->GetPath(), params);
696 m_database.DeleteTag(params.GetTagId(), (VIDEODB_CONTENT_TYPE)params.GetContentType());
699 else if (m_vecItems->GetPath().Equals(CUtil::VideoPlaylistsLocation()) ||
700 m_vecItems->GetPath().Equals("special://videoplaylists/"))
702 pItem->m_bIsFolder = false;
703 CFileUtils::DeleteItem(pItem);
707 if (!CGUIDialogVideoInfo::DeleteVideoItem(pItem))
711 CUtil::DeleteVideoDatabaseDirectoryCache();
714 void CGUIWindowVideoNav::GetContextButtons(int itemNumber, CContextButtons &buttons)
717 if (itemNumber >= 0 && itemNumber < m_vecItems->Size())
718 item = m_vecItems->Get(itemNumber);
720 CGUIWindowVideoBase::GetContextButtons(itemNumber, buttons);
722 if (item && item->GetProperty("pluginreplacecontextitems").asBoolean())
725 CVideoDatabaseDirectory dir;
726 NODE_TYPE node = dir.GetDirectoryChildType(m_vecItems->GetPath());
730 // nothing to do here
732 else if (m_vecItems->GetPath().Equals("sources://video/"))
734 // get the usual shares
735 CGUIDialogContextMenu::GetContextButtons("video", item, buttons);
736 // add scan button somewhere here
737 if (g_application.IsVideoScanning())
738 buttons.Add(CONTEXT_BUTTON_STOP_SCANNING, 13353); // Stop Scanning
739 if (!item->IsDVD() && item->GetPath() != "add" && !item->IsParentFolder() &&
740 (CProfilesManager::Get().GetCurrentProfile().canWriteDatabases() || g_passwordManager.bMasterUser))
742 CVideoDatabase database;
744 ADDON::ScraperPtr info = database.GetScraperForPath(item->GetPath());
746 if (!g_application.IsVideoScanning())
748 if (!item->IsLiveTV() && !item->IsPlugin() && !item->IsAddonsPath() && !URIUtils::IsUPnP(item->GetPath()))
750 if (info && info->Content() != CONTENT_NONE)
751 buttons.Add(CONTEXT_BUTTON_SET_CONTENT, 20442);
753 buttons.Add(CONTEXT_BUTTON_SET_CONTENT, 20333);
757 if (info && !g_application.IsVideoScanning())
758 buttons.Add(CONTEXT_BUTTON_SCAN, 13349);
763 // are we in the playlists location?
764 bool inPlaylists = m_vecItems->GetPath().Equals(CUtil::VideoPlaylistsLocation()) ||
765 m_vecItems->GetPath().Equals("special://videoplaylists/");
767 if (item->HasVideoInfoTag() && !item->GetVideoInfoTag()->m_artist.empty())
769 CMusicDatabase database;
771 if (database.GetArtistByName(StringUtils::Join(item->GetVideoInfoTag()->m_artist, g_advancedSettings.m_videoItemSeparator)) > -1)
772 buttons.Add(CONTEXT_BUTTON_GO_TO_ARTIST, 20396);
774 if (item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_strAlbum.size() > 0)
776 CMusicDatabase database;
778 if (database.GetAlbumByName(item->GetVideoInfoTag()->m_strAlbum) > -1)
779 buttons.Add(CONTEXT_BUTTON_GO_TO_ALBUM, 20397);
781 if (item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_strAlbum.size() > 0 &&
782 item->GetVideoInfoTag()->m_artist.size() > 0 &&
783 item->GetVideoInfoTag()->m_strTitle.size() > 0)
785 CMusicDatabase database;
787 if (database.GetSongByArtistAndAlbumAndTitle(StringUtils::Join(item->GetVideoInfoTag()->m_artist, g_advancedSettings.m_videoItemSeparator),
788 item->GetVideoInfoTag()->m_strAlbum,
789 item->GetVideoInfoTag()->m_strTitle) > -1)
791 buttons.Add(CONTEXT_BUTTON_PLAY_OTHER, 20398);
794 if (!item->IsParentFolder())
796 ADDON::ScraperPtr info;
797 VIDEO::SScanSettings settings;
798 GetScraperForItem(item.get(), info, settings);
800 if (info && info->Content() == CONTENT_TVSHOWS)
801 buttons.Add(CONTEXT_BUTTON_INFO, item->m_bIsFolder ? 20351 : 20352);
802 else if (info && info->Content() == CONTENT_MUSICVIDEOS)
803 buttons.Add(CONTEXT_BUTTON_INFO,20393);
804 else if (info && info->Content() == CONTENT_MOVIES)
805 buttons.Add(CONTEXT_BUTTON_INFO, 13346);
807 // can we update the database?
808 if (CProfilesManager::Get().GetCurrentProfile().canWriteDatabases() || g_passwordManager.bMasterUser)
810 if (node == NODE_TYPE_TITLE_TVSHOWS)
812 if (g_application.IsVideoScanning())
813 buttons.Add(CONTEXT_BUTTON_STOP_SCANNING, 13353);
815 buttons.Add(CONTEXT_BUTTON_SCAN, 13349);
817 if (!item->IsPlugin() && !item->IsScript() && !item->IsLiveTV() && !item->IsAddonsPath() &&
818 item->GetPath() != "sources://video/" &&
819 item->GetPath() != "special://videoplaylists/" &&
820 !StringUtils::StartsWith(item->GetPath(), "newsmartplaylist://") &&
821 !StringUtils::StartsWith(item->GetPath(), "newplaylist://") &&
822 !StringUtils::StartsWith(item->GetPath(), "newtag://"))
824 if (item->m_bIsFolder)
826 // Have both options for folders since we don't know whether all childs are watched/unwatched
827 buttons.Add(CONTEXT_BUTTON_MARK_UNWATCHED, 16104); //Mark as UnWatched
828 buttons.Add(CONTEXT_BUTTON_MARK_WATCHED, 16103); //Mark as Watched
832 if (item->GetOverlayImage().Equals("OverlayWatched.png"))
833 buttons.Add(CONTEXT_BUTTON_MARK_UNWATCHED, 16104); //Mark as UnWatched
835 buttons.Add(CONTEXT_BUTTON_MARK_WATCHED, 16103); //Mark as Watched
838 if (!g_application.IsVideoScanning() && item->IsVideoDb() && item->HasVideoInfoTag() &&
839 (!item->m_bIsFolder || m_vecItems->GetContent().Equals("movies") || m_vecItems->GetContent().Equals("tvshows")))
841 buttons.Add(CONTEXT_BUTTON_EDIT, 16106);
844 if (node == NODE_TYPE_SEASONS && item->m_bIsFolder)
845 buttons.Add(CONTEXT_BUTTON_SET_SEASON_ART, 13511);
847 if (StringUtils::StartsWithNoCase(item->GetPath(), "videodb://movies/sets/") && item->GetPath().size() > 22 && item->m_bIsFolder) // sets
849 buttons.Add(CONTEXT_BUTTON_SET_MOVIESET_ART, 13511);
850 buttons.Add(CONTEXT_BUTTON_MOVIESET_ADD_REMOVE_ITEMS, 20465);
851 buttons.Add(CONTEXT_BUTTON_DELETE, 646);
854 if (m_vecItems->GetContent() == "tags" && item->m_bIsFolder) // tags
856 CVideoDbUrl videoUrl;
857 if (videoUrl.FromString(item->GetPath()))
859 std::string mediaType = videoUrl.GetItemType();
861 CStdString strLabelAdd = StringUtils::Format(g_localizeStrings.Get(20460), GetLocalizedType(videoUrl.GetItemType()).c_str());
862 CStdString strLabelRemove = StringUtils::Format(g_localizeStrings.Get(20461), GetLocalizedType(videoUrl.GetItemType()).c_str());
863 buttons.Add(CONTEXT_BUTTON_TAGS_ADD_ITEMS, strLabelAdd);
864 buttons.Add(CONTEXT_BUTTON_TAGS_REMOVE_ITEMS, strLabelRemove);
865 buttons.Add(CONTEXT_BUTTON_DELETE, 646);
869 if (node == NODE_TYPE_ACTOR && !dir.IsAllItem(item->GetPath()) && item->m_bIsFolder)
871 if (StringUtils::StartsWithNoCase(m_vecItems->GetPath(), "videodb://musicvideos")) // mvids
872 buttons.Add(CONTEXT_BUTTON_SET_ARTIST_THUMB, 13359);
874 buttons.Add(CONTEXT_BUTTON_SET_ACTOR_THUMB, 20403);
878 if (!m_vecItems->IsVideoDb() && !m_vecItems->IsVirtualDirectoryRoot())
879 { // non-video db items, file operations are allowed
880 if ((CSettings::Get().GetBool("filelists.allowfiledeletion") &&
881 CUtil::SupportsWriteFileOperations(item->GetPath())) ||
882 (inPlaylists && !URIUtils::GetFileName(item->GetPath()).Equals("PartyMode-Video.xsp")
883 && (item->IsPlayList() || item->IsSmartPlayList())))
885 buttons.Add(CONTEXT_BUTTON_DELETE, 117);
886 buttons.Add(CONTEXT_BUTTON_RENAME, 118);
888 // add "Set/Change content" to folders
889 if (item->m_bIsFolder && !item->IsVideoDb() && !item->IsPlayList() && !item->IsSmartPlayList() && !item->IsLibraryFolder() && !item->IsLiveTV() && !item->IsPlugin() && !item->IsAddonsPath() && !URIUtils::IsUPnP(item->GetPath()))
891 if (!g_application.IsVideoScanning())
893 if (info && info->Content() != CONTENT_NONE)
895 buttons.Add(CONTEXT_BUTTON_SET_CONTENT, 20442);
896 buttons.Add(CONTEXT_BUTTON_SCAN, 13349);
899 buttons.Add(CONTEXT_BUTTON_SET_CONTENT, 20333);
903 if (item->IsPlugin() || item->IsScript() || m_vecItems->IsPlugin())
904 buttons.Add(CONTEXT_BUTTON_PLUGIN_SETTINGS, 1045);
909 // predicate used by sorting and set_difference
910 bool compFileItemsByDbId(const CFileItemPtr& lhs, const CFileItemPtr& rhs)
912 return lhs->HasVideoInfoTag() && rhs->HasVideoInfoTag() && lhs->GetVideoInfoTag()->m_iDbId < rhs->GetVideoInfoTag()->m_iDbId;
915 bool CGUIWindowVideoNav::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
918 if (itemNumber >= 0 && itemNumber < m_vecItems->Size())
919 item = m_vecItems->Get(itemNumber);
920 if (CGUIDialogContextMenu::OnContextButton("video", item, button))
922 //TODO should we search DB for entries from plugins?
923 if (button == CONTEXT_BUTTON_REMOVE_SOURCE && !item->IsPlugin()
924 && !item->IsLiveTV() &&!item->IsRSS() && !URIUtils::IsUPnP(item->GetPath()))
926 OnUnAssignContent(item->GetPath(),20375,20340,20341);
933 case CONTEXT_BUTTON_EDIT:
935 CONTEXT_BUTTON ret = (CONTEXT_BUTTON)CGUIDialogVideoInfo::ManageVideoItem(item);
938 if (ret == CONTEXT_BUTTON_MARK_WATCHED)
939 m_viewControl.SetSelectedItem(itemNumber + 1);
946 case CONTEXT_BUTTON_SET_SEASON_ART:
947 case CONTEXT_BUTTON_SET_ACTOR_THUMB:
948 case CONTEXT_BUTTON_SET_ARTIST_THUMB:
949 case CONTEXT_BUTTON_SET_MOVIESET_ART:
951 // Grab the thumbnails from the web
953 CFileItemPtr noneitem(new CFileItem("thumb://None", false));
954 CStdString currentThumb;
956 CStdString artistPath;
957 string artType = "thumb";
958 if (button == CONTEXT_BUTTON_SET_ARTIST_THUMB)
960 CMusicDatabase database;
962 idArtist = database.GetArtistByName(m_vecItems->Get(itemNumber)->GetLabel());
963 database.GetArtistPath(idArtist, artistPath);
964 currentThumb = database.GetArtForItem(idArtist, "artist", "thumb");
965 if (currentThumb.empty())
966 currentThumb = m_database.GetArtForItem(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_iDbId, m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_type, artType);
968 else if (button == CONTEXT_BUTTON_SET_ACTOR_THUMB)
969 currentThumb = m_database.GetArtForItem(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_iDbId, m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_type, artType);
972 map<string, string> currentArt;
973 artType = CGUIDialogVideoInfo::ChooseArtType(*m_vecItems->Get(itemNumber), currentArt);
977 if (artType == "fanart")
979 OnChooseFanart(*m_vecItems->Get(itemNumber));
983 if (currentArt.find(artType) != currentArt.end())
984 currentThumb = currentArt[artType];
985 else if ((artType == "poster" || artType == "banner") && currentArt.find("thumb") != currentArt.end())
986 currentThumb = currentArt["thumb"];
988 if (!currentThumb.empty())
990 CFileItemPtr item(new CFileItem("thumb://Current", false));
991 item->SetArt("thumb", currentThumb);
992 item->SetLabel(g_localizeStrings.Get(13512));
995 noneitem->SetIconImage("DefaultFolder.png");
996 noneitem->SetLabel(g_localizeStrings.Get(13515));
998 vector<CStdString> thumbs;
999 if (button != CONTEXT_BUTTON_SET_ARTIST_THUMB)
1002 if (button == CONTEXT_BUTTON_SET_SEASON_ART)
1003 m_database.GetTvShowInfo("",tag,m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_iIdShow);
1005 tag = *m_vecItems->Get(itemNumber)->GetVideoInfoTag();
1006 if (button == CONTEXT_BUTTON_SET_SEASON_ART)
1007 tag.m_strPictureURL.GetThumbURLs(thumbs, artType, m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_iSeason);
1009 tag.m_strPictureURL.GetThumbURLs(thumbs, artType);
1011 for (unsigned int i = 0; i < thumbs.size(); i++)
1013 CStdString strItemPath = StringUtils::Format("thumb://Remote%i",i);
1014 CFileItemPtr item(new CFileItem(strItemPath, false));
1015 item->SetArt("thumb", thumbs[i]);
1016 item->SetIconImage("DefaultPicture.png");
1017 item->SetLabel(g_localizeStrings.Get(13513));
1020 // TODO: Do we need to clear the cached image?
1021 // CTextureCache::Get().ClearCachedImage(thumbs[i]);
1026 if (button == CONTEXT_BUTTON_SET_ARTIST_THUMB)
1028 CStdString strThumb = URIUtils::AddFileToFolder(artistPath, "folder.jpg");
1029 if (XFILE::CFile::Exists(strThumb))
1031 CFileItemPtr pItem(new CFileItem(strThumb,false));
1032 pItem->SetLabel(g_localizeStrings.Get(13514));
1033 pItem->SetArt("thumb", strThumb);
1038 noneitem->SetIconImage("DefaultArtist.png");
1041 if (button == CONTEXT_BUTTON_SET_ACTOR_THUMB)
1043 CStdString picturePath;
1044 CStdString strThumb = URIUtils::AddFileToFolder(picturePath, "folder.jpg");
1045 if (XFILE::CFile::Exists(strThumb))
1047 CFileItemPtr pItem(new CFileItem(strThumb,false));
1048 pItem->SetLabel(g_localizeStrings.Get(13514));
1049 pItem->SetArt("thumb", strThumb);
1054 noneitem->SetIconImage("DefaultActor.png");
1057 if (button == CONTEXT_BUTTON_SET_MOVIESET_ART)
1058 noneitem->SetIconImage("DefaultVideo.png");
1061 items.Add(noneitem);
1063 VECSOURCES sources=*CMediaSourceSettings::Get().GetSources("video");
1064 g_mediaManager.GetLocalDrives(sources);
1066 CGUIDialogVideoInfo::AddItemPathToFileBrowserSources(sources, *item);
1067 if (!CGUIDialogFileBrowser::ShowAndGetImage(items, sources,
1068 g_localizeStrings.Get(13511), result))
1070 return false; // user cancelled
1073 if (result == "thumb://Current")
1074 result = currentThumb; // user chose the one they have
1076 // delete the thumbnail if that's what the user wants, else overwrite with the
1078 if (StringUtils::StartsWith(result, "thumb://Remote"))
1080 int number = atoi(result.substr(14).c_str());
1081 result = thumbs[number];
1083 else if (result == "thumb://None")
1085 if (button == CONTEXT_BUTTON_SET_MOVIESET_ART ||
1086 button == CONTEXT_BUTTON_SET_ACTOR_THUMB ||
1087 button == CONTEXT_BUTTON_SET_SEASON_ART ||
1088 (button == CONTEXT_BUTTON_SET_ARTIST_THUMB && idArtist < 0))
1089 m_database.SetArtForItem(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_iDbId, m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_type, artType, result);
1094 db.SetArtForItem(idArtist, "artist", artType, result);
1097 CUtil::DeleteVideoDatabaseDirectoryCache();
1098 CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_REFRESH_THUMBS);
1099 g_windowManager.SendMessage(msg);
1104 case CONTEXT_BUTTON_TAGS_ADD_ITEMS:
1106 CVideoDbUrl videoUrl;
1107 if (!videoUrl.FromString(item->GetPath()))
1110 std::string mediaType = videoUrl.GetItemType();
1111 mediaType = mediaType.substr(0, mediaType.length() - 1);
1113 CFileItemList items;
1114 CStdString localizedType = GetLocalizedType(mediaType);
1115 CStdString strLabel = StringUtils::Format(g_localizeStrings.Get(20464), localizedType.c_str());
1116 if (!GetItemsForTag(strLabel, mediaType, items, item->GetVideoInfoTag()->m_iDbId))
1119 CVideoDatabase videodb;
1120 if (!videodb.Open())
1123 for (int index = 0; index < items.Size(); index++)
1125 if (!items[index]->HasVideoInfoTag() || items[index]->GetVideoInfoTag()->m_iDbId <= 0)
1128 videodb.AddTagToItem(items[index]->GetVideoInfoTag()->m_iDbId, item->GetVideoInfoTag()->m_iDbId, mediaType);
1131 // we need to clear any cached version of this tag's listing
1132 items.SetPath(item->GetPath());
1133 items.RemoveDiscCache(GetID());
1136 case CONTEXT_BUTTON_TAGS_REMOVE_ITEMS:
1138 CVideoDbUrl videoUrl;
1139 if (!videoUrl.FromString(item->GetPath()))
1142 std::string mediaType = videoUrl.GetItemType();
1143 mediaType = mediaType.substr(0, mediaType.length() - 1);
1145 CFileItemList items;
1146 CStdString localizedType = GetLocalizedType(mediaType);
1147 CStdString strLabel = StringUtils::Format(g_localizeStrings.Get(20464), localizedType.c_str());
1148 if (!GetItemsForTag(strLabel, mediaType, items, item->GetVideoInfoTag()->m_iDbId, false))
1151 CVideoDatabase videodb;
1152 if (!videodb.Open())
1155 for (int index = 0; index < items.Size(); index++)
1157 if (!items[index]->HasVideoInfoTag() || items[index]->GetVideoInfoTag()->m_iDbId <= 0)
1160 videodb.RemoveTagFromItem(items[index]->GetVideoInfoTag()->m_iDbId, item->GetVideoInfoTag()->m_iDbId, mediaType);
1163 // we need to clear any cached version of this tag's listing
1164 items.SetPath(item->GetPath());
1165 items.RemoveDiscCache(GetID());
1168 case CONTEXT_BUTTON_MOVIESET_ADD_REMOVE_ITEMS:
1170 CFileItemList originalItems;
1171 CFileItemList selectedItems;
1173 if (!CGUIDialogVideoInfo::GetMoviesForSet(item.get(), originalItems, selectedItems) || selectedItems.Size() == 0) // need at least one item selected
1175 VECFILEITEMS original = originalItems.GetList();
1176 std::sort(original.begin(), original.end(), compFileItemsByDbId);
1177 VECFILEITEMS selected = selectedItems.GetList();
1178 std::sort(selected.begin(), selected.end(), compFileItemsByDbId);
1180 bool refreshNeeded = false;
1181 // update the "added" items
1182 VECFILEITEMS addedItems;
1183 set_difference(selected.begin(),selected.end(), original.begin(),original.end(), std::back_inserter(addedItems), compFileItemsByDbId);
1184 for (VECFILEITEMS::iterator it = addedItems.begin(); it != addedItems.end(); ++it)
1186 if (CGUIDialogVideoInfo::SetMovieSet(it->get(), item.get()))
1187 refreshNeeded = true;
1189 // update the "deleted" items
1190 CFileItemPtr clearItem(new CFileItem());
1191 clearItem->GetVideoInfoTag()->m_iDbId = -1; // -1 will be used to clear set
1192 VECFILEITEMS deletedItems;
1193 set_difference(original.begin(),original.end(), selected.begin(),selected.end(), std::back_inserter(deletedItems), compFileItemsByDbId);
1194 for (VECFILEITEMS::iterator it = deletedItems.begin(); it != deletedItems.end(); ++it)
1196 if (CGUIDialogVideoInfo::SetMovieSet(it->get(), clearItem.get()))
1197 refreshNeeded = true;
1200 // we need to clear any cached version of this tag's listing
1205 case CONTEXT_BUTTON_GO_TO_ARTIST:
1208 CMusicDatabase database;
1210 strPath = StringUtils::Format("musicdb://artists/%ld/",
1211 database.GetArtistByName(StringUtils::Join(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_artist, g_advancedSettings.m_videoItemSeparator)));
1212 g_windowManager.ActivateWindow(WINDOW_MUSIC_NAV,strPath);
1215 case CONTEXT_BUTTON_GO_TO_ALBUM:
1218 CMusicDatabase database;
1220 strPath = StringUtils::Format("musicdb://albums/%ld/",
1221 database.GetAlbumByName(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strAlbum));
1222 g_windowManager.ActivateWindow(WINDOW_MUSIC_NAV,strPath);
1225 case CONTEXT_BUTTON_PLAY_OTHER:
1227 CMusicDatabase database;
1230 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,
1231 m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strTitle),
1234 CApplicationMessenger::Get().PlayFile(song);
1243 return CGUIWindowVideoBase::OnContextButton(itemNumber, button);
1246 void CGUIWindowVideoNav::OnChooseFanart(const CFileItem &videoItem)
1248 if (!videoItem.HasVideoInfoTag())
1251 CFileItem item(videoItem);
1253 CFileItemList items;
1255 CVideoThumbLoader loader;
1256 loader.LoadItem(&item);
1258 if (item.HasArt("fanart"))
1260 CFileItemPtr itemCurrent(new CFileItem("fanart://Current",false));
1261 itemCurrent->SetArt("thumb", item.GetArt("fanart"));
1262 itemCurrent->SetLabel(g_localizeStrings.Get(20440));
1263 items.Add(itemCurrent);
1266 // add the none option
1268 CFileItemPtr itemNone(new CFileItem("fanart://None", false));
1269 itemNone->SetIconImage("DefaultVideo.png");
1270 itemNone->SetLabel(g_localizeStrings.Get(20439));
1271 items.Add(itemNone);
1275 VECSOURCES sources(*CMediaSourceSettings::Get().GetSources("video"));
1276 g_mediaManager.GetLocalDrives(sources);
1277 CGUIDialogVideoInfo::AddItemPathToFileBrowserSources(sources, item);
1279 if (!CGUIDialogFileBrowser::ShowAndGetImage(items, sources, g_localizeStrings.Get(20437), result, &flip, 20445) || result.Equals("fanart://Current"))
1282 if (result.Equals("fanart://None") || !CFile::Exists(result))
1284 if (!result.empty() && flip)
1285 result = CTextureUtils::GetWrappedImageURL(result, "", "flipped");
1291 db.SetArtForItem(item.GetVideoInfoTag()->m_iDbId, item.GetVideoInfoTag()->m_type, "fanart", result);
1295 // clear view cache and reload images
1296 CUtil::DeleteVideoDatabaseDirectoryCache();
1301 bool CGUIWindowVideoNav::OnClick(int iItem)
1303 CFileItemPtr item = m_vecItems->Get(iItem);
1304 if (!item->m_bIsFolder && item->IsVideoDb() && !item->Exists())
1306 CLog::Log(LOGDEBUG, "%s called on '%s' but file doesn't exist", __FUNCTION__, item->GetPath().c_str());
1307 if (!CGUIDialogVideoInfo::DeleteVideoItemFromDatabase(item, true))
1312 m_viewControl.SetSelectedItem(iItem);
1315 else if (StringUtils::StartsWithNoCase(item->GetPath(), "newtag://"))
1317 // dont allow update while scanning
1318 if (g_application.IsVideoScanning())
1320 CGUIDialogOK::ShowAndGetInput(257, 0, 14057, 0);
1326 if (!CGUIKeyboardFactory::ShowAndGetInput(strTag, g_localizeStrings.Get(20462), false))
1329 CVideoDatabase videodb;
1330 if (!videodb.Open())
1333 // get the media type and convert from plural to singular (by removing the trailing "s")
1334 CStdString mediaType = item->GetPath().substr(9);
1335 mediaType = mediaType.substr(0, mediaType.size() - 1);
1336 CStdString localizedType = GetLocalizedType(mediaType);
1337 if (localizedType.empty())
1340 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())
1342 CStdString strError = StringUtils::Format(g_localizeStrings.Get(20463), strTag.c_str());
1343 CGUIDialogOK::ShowAndGetInput(20462, "", strError, "");
1347 int idTag = videodb.AddTag(strTag);
1348 CFileItemList items;
1349 CStdString strLabel = StringUtils::Format(g_localizeStrings.Get(20464), localizedType.c_str());
1350 if (GetItemsForTag(strLabel, mediaType, items, idTag))
1352 for (int index = 0; index < items.Size(); index++)
1354 if (!items[index]->HasVideoInfoTag() || items[index]->GetVideoInfoTag()->m_iDbId <= 0)
1357 videodb.AddTagToItem(items[index]->GetVideoInfoTag()->m_iDbId, idTag, mediaType);
1365 return CGUIWindowVideoBase::OnClick(iItem);
1368 CStdString CGUIWindowVideoNav::GetStartFolder(const CStdString &dir)
1370 if (dir.Equals("MovieGenres"))
1371 return "videodb://movies/genres/";
1372 else if (dir.Equals("MovieTitles"))
1373 return "videodb://movies/titles/";
1374 else if (dir.Equals("MovieYears"))
1375 return "videodb://movies/years/";
1376 else if (dir.Equals("MovieActors"))
1377 return "videodb://movies/actors/";
1378 else if (dir.Equals("MovieDirectors"))
1379 return "videodb://movies/directors/";
1380 else if (dir.Equals("MovieStudios"))
1381 return "videodb://movies/studios/";
1382 else if (dir.Equals("MovieSets"))
1383 return "videodb://movies/sets/";
1384 else if (dir.Equals("MovieCountries"))
1385 return "videodb://movies/countries/";
1386 else if (dir.Equals("MovieTags"))
1387 return "videodb://movies/tags/";
1388 else if (dir.Equals("Movies"))
1389 return "videodb://movies/";
1390 else if (dir.Equals("TvShowGenres"))
1391 return "videodb://tvshows/genres/";
1392 else if (dir.Equals("TvShowTitles"))
1393 return "videodb://tvshows/titles/";
1394 else if (dir.Equals("TvShowYears"))
1395 return "videodb://tvshows/years/";
1396 else if (dir.Equals("TvShowActors"))
1397 return "videodb://tvshows/actors/";
1398 else if (dir.Equals("TvShowStudios"))
1399 return "videodb://tvshows/studios/";
1400 else if (dir.Equals("TvShowTags"))
1401 return "videodb://tvshows/tags/";
1402 else if (dir.Equals("TvShows"))
1403 return "videodb://tvshows/";
1404 else if (dir.Equals("MusicVideoGenres"))
1405 return "videodb://musicvideos/genres/";
1406 else if (dir.Equals("MusicVideoTitles"))
1407 return "videodb://musicvideos/titles/";
1408 else if (dir.Equals("MusicVideoYears"))
1409 return "videodb://musicvideos/years/";
1410 else if (dir.Equals("MusicVideoArtists"))
1411 return "videodb://musicvideos/artists/";
1412 else if (dir.Equals("MusicVideoAlbums"))
1413 return "videodb://musicvideos/albums/";
1414 else if (dir.Equals("MusicVideoDirectors"))
1415 return "videodb://musicvideos/directors/";
1416 else if (dir.Equals("MusicVideoStudios"))
1417 return "videodb://musicvideos/studios/";
1418 else if (dir.Equals("MusicVideoTags"))
1419 return "videodb://musicvideos/tags/";
1420 else if (dir.Equals("MusicVideos"))
1421 return "videodb://musicvideos/";
1422 else if (dir.Equals("RecentlyAddedMovies"))
1423 return "videodb://recentlyaddedmovies/";
1424 else if (dir.Equals("RecentlyAddedEpisodes"))
1425 return "videodb://recentlyaddedepisodes/";
1426 else if (dir.Equals("RecentlyAddedMusicVideos"))
1427 return "videodb://recentlyaddedmusicvideos/";
1428 else if (dir.Equals("Files"))
1429 return "sources://video/";
1430 return CGUIWindowVideoBase::GetStartFolder(dir);
1433 bool CGUIWindowVideoNav::ApplyWatchedFilter(CFileItemList &items)
1435 bool listchanged = false;
1436 CVideoDatabaseDirectory dir;
1437 NODE_TYPE node = dir.GetDirectoryChildType(items.GetPath());
1439 // now filter watched items as necessary
1440 bool filterWatched=false;
1441 if (node == NODE_TYPE_EPISODES
1442 || node == NODE_TYPE_SEASONS
1443 || node == NODE_TYPE_SETS
1444 || node == NODE_TYPE_TAGS
1445 || node == NODE_TYPE_TITLE_MOVIES
1446 || node == NODE_TYPE_TITLE_TVSHOWS
1447 || node == NODE_TYPE_TITLE_MUSICVIDEOS
1448 || node == NODE_TYPE_RECENTLY_ADDED_EPISODES
1449 || node == NODE_TYPE_RECENTLY_ADDED_MOVIES
1450 || node == NODE_TYPE_RECENTLY_ADDED_MUSICVIDEOS)
1451 filterWatched = true;
1452 if (!items.IsVideoDb())
1453 filterWatched = true;
1454 if (items.GetContent() == "tvshows" &&
1455 (items.IsSmartPlayList() || items.IsLibraryFolder()))
1456 node = NODE_TYPE_TITLE_TVSHOWS; // so that the check below works
1458 int watchMode = CMediaSettings::Get().GetWatchedMode(m_vecItems->GetContent());
1460 for (int i = 0; i < items.Size(); i++)
1462 CFileItemPtr item = items.Get(i);
1464 if(item->HasVideoInfoTag() && (node == NODE_TYPE_TITLE_TVSHOWS || node == NODE_TYPE_SEASONS))
1466 if (watchMode == WatchedModeUnwatched)
1467 item->GetVideoInfoTag()->m_iEpisode = (int)item->GetProperty("unwatchedepisodes").asInteger();
1468 if (watchMode == WatchedModeWatched)
1469 item->GetVideoInfoTag()->m_iEpisode = (int)item->GetProperty("watchedepisodes").asInteger();
1470 if (watchMode == WatchedModeAll)
1471 item->GetVideoInfoTag()->m_iEpisode = (int)item->GetProperty("totalepisodes").asInteger();
1472 item->SetProperty("numepisodes", item->GetVideoInfoTag()->m_iEpisode);
1478 if((watchMode==WatchedModeWatched && item->GetVideoInfoTag()->m_playCount== 0)
1479 || (watchMode==WatchedModeUnwatched && item->GetVideoInfoTag()->m_playCount > 0))
1488 if(node == NODE_TYPE_TITLE_TVSHOWS || node == NODE_TYPE_SEASONS)
1490 // the watched filter may change the "numepisodes" property which is reflected in the TV_SHOWS and SEASONS nodes
1491 // therefore, the items labels have to be refreshed, and possibly the list needs resorting as well.
1492 items.ClearSortState(); // this is needed to force resorting even if sort method did not change
1493 FormatAndSort(items);
1499 bool CGUIWindowVideoNav::GetItemsForTag(const CStdString &strHeading, const std::string &type, CFileItemList &items, int idTag /* = -1 */, bool showAll /* = true */)
1501 CVideoDatabase videodb;
1502 if (!videodb.Open())
1505 MediaType mediaType = MediaTypeNone;
1506 std::string baseDir = "videodb://";
1507 std::string idColumn;
1508 if (type.compare("movie") == 0)
1510 mediaType = MediaTypeMovie;
1511 baseDir += "movies";
1512 idColumn = "idMovie";
1514 else if (type.compare("tvshow") == 0)
1516 mediaType = MediaTypeTvShow;
1517 baseDir += "tvshows";
1518 idColumn = "idShow";
1520 else if (type.compare("musicvideo") == 0)
1522 mediaType = MediaTypeMusicVideo;
1523 baseDir += "musicvideos";
1524 idColumn = "idMVideo";
1527 baseDir += "/titles/";
1528 CVideoDbUrl videoUrl;
1529 if (!videoUrl.FromString(baseDir))
1532 CVideoDatabase::Filter filter;
1536 videoUrl.AddOption("tagid", idTag);
1538 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());
1541 CFileItemList listItems;
1542 if (!videodb.GetSortedVideos(mediaType, videoUrl.ToString(), SortDescription(), listItems, filter) || listItems.Size() <= 0)
1545 CGUIDialogSelect *dialog = (CGUIDialogSelect *)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
1549 listItems.Sort(SortByLabel, SortOrderAscending, SortAttributeIgnoreArticle);
1552 dialog->SetMultiSelection(true);
1553 dialog->SetHeading(strHeading);
1554 dialog->SetItems(&listItems);
1555 dialog->EnableButton(true, 186);
1558 items.Copy(dialog->GetSelectedItems());
1559 return items.Size() > 0;
1562 CStdString CGUIWindowVideoNav::GetLocalizedType(const std::string &strType)
1564 if (strType == "movie" || strType == "movies")
1565 return g_localizeStrings.Get(20342);
1566 else if (strType == "tvshow" || strType == "tvshows")
1567 return g_localizeStrings.Get(20343);
1568 else if (strType == "episode" || strType == "episodes")
1569 return g_localizeStrings.Get(20359);
1570 else if (strType == "musicvideo" || strType == "musicvideos")
1571 return g_localizeStrings.Get(20391);