only call IPlayerCallback::OnPlayBackSpeedChanged if the speed has actually changed
[vuplus_xbmc] / xbmc / video / windows / GUIWindowVideoNav.cpp
1 /*
2  *      Copyright (C) 2005-2008 Team XBMC
3  *      http://www.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, write to
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21
22 #include "GUIUserMessages.h"
23 #include "GUIWindowVideoNav.h"
24 #include "music/windows/GUIWindowMusicNav.h"
25 #include "utils/FileUtils.h"
26 #include "Util.h"
27 #include "utils/RegExp.h"
28 #include "PlayListPlayer.h"
29 #include "GUIPassword.h"
30 #include "dialogs/GUIDialogFileBrowser.h"
31 #include "filesystem/VideoDatabaseDirectory.h"
32 #include "playlists/PlayListFactory.h"
33 #include "video/dialogs/GUIDialogVideoScan.h"
34 #include "dialogs/GUIDialogOK.h"
35 #include "addons/AddonManager.h"
36 #include "PartyModeManager.h"
37 #include "music/MusicDatabase.h"
38 #include "guilib/GUIWindowManager.h"
39 #include "dialogs/GUIDialogYesNo.h"
40 #include "dialogs/GUIDialogSelect.h"
41 #include "filesystem/Directory.h"
42 #include "filesystem/File.h"
43 #include "FileItem.h"
44 #include "Application.h"
45 #include "settings/Settings.h"
46 #include "settings/AdvancedSettings.h"
47 #include "settings/GUISettings.h"
48 #include "guilib/LocalizeStrings.h"
49 #include "storage/MediaManager.h"
50 #include "utils/log.h"
51 #include "utils/URIUtils.h"
52 #include "pictures/Picture.h"
53 #include "TextureCache.h"
54
55 using namespace XFILE;
56 using namespace VIDEODATABASEDIRECTORY;
57 using namespace std;
58
59 #define CONTROL_BTNVIEWASICONS     2
60 #define CONTROL_BTNSORTBY          3
61 #define CONTROL_BTNSORTASC         4
62 #define CONTROL_BTNTYPE            5
63 #define CONTROL_BTNSEARCH          8
64 #define CONTROL_LABELFILES        12
65
66 #define CONTROL_BTN_FILTER        19
67 #define CONTROL_BTNSHOWMODE       10
68 #define CONTROL_BTNSHOWALL        14
69 #define CONTROL_UNLOCK            11
70
71 #define CONTROL_FILTER            15
72 #define CONTROL_BTNPARTYMODE      16
73 #define CONTROL_BTNFLATTEN        17
74 #define CONTROL_LABELEMPTY        18
75
76 CGUIWindowVideoNav::CGUIWindowVideoNav(void)
77     : CGUIWindowVideoBase(WINDOW_VIDEO_NAV, "MyVideoNav.xml")
78 {
79   m_thumbLoader.SetObserver(this);
80 }
81
82 CGUIWindowVideoNav::~CGUIWindowVideoNav(void)
83 {
84 }
85
86 bool CGUIWindowVideoNav::OnAction(const CAction &action)
87 {
88   if (action.GetID() == ACTION_TOGGLE_WATCHED)
89   {
90     CFileItemPtr pItem = m_vecItems->Get(m_viewControl.GetSelectedItem());
91     if (pItem->IsParentFolder())
92       return false;
93     if (pItem && pItem->GetVideoInfoTag()->m_playCount == 0)
94       return OnContextButton(m_viewControl.GetSelectedItem(),CONTEXT_BUTTON_MARK_WATCHED);
95     if (pItem && pItem->GetVideoInfoTag()->m_playCount > 0)
96       return OnContextButton(m_viewControl.GetSelectedItem(),CONTEXT_BUTTON_MARK_UNWATCHED);
97   }
98   return CGUIWindowVideoBase::OnAction(action);
99 }
100
101 bool CGUIWindowVideoNav::OnMessage(CGUIMessage& message)
102 {
103   switch (message.GetMessage())
104   {
105   case GUI_MSG_WINDOW_RESET:
106     m_vecItems->SetPath("");
107     break;
108   case GUI_MSG_WINDOW_DEINIT:
109     if (m_thumbLoader.IsLoading())
110       m_thumbLoader.StopThread();
111     break;
112   case GUI_MSG_WINDOW_INIT:
113     {
114       /* We don't want to show Autosourced items (ie removable pendrives, memorycards) in Library mode */
115       m_rootDir.AllowNonLocalSources(false);
116
117       SetProperty("flattened", g_settings.m_bMyVideoNavFlatten);
118       
119       if (!CGUIWindowVideoBase::OnMessage(message))
120         return false;
121
122       //  base class has opened the database, do our check
123       m_database.Open();
124
125       if (!m_database.HasContent() && m_vecItems->IsVideoDb())
126       { // no library - make sure we default to the root.
127         m_vecItems->SetPath("");
128         SetHistoryForPath("");
129         Update("");
130       }
131
132       m_database.Close();
133       return true;
134     }
135     break;
136
137   case GUI_MSG_CLICKED:
138     {
139       int iControl = message.GetSenderId();
140       if (iControl == CONTROL_BTNPARTYMODE)
141       {
142         if (g_partyModeManager.IsEnabled())
143           g_partyModeManager.Disable();
144         else
145         {
146           if (!g_partyModeManager.Enable(PARTYMODECONTEXT_VIDEO))
147           {
148             SET_CONTROL_SELECTED(GetID(),CONTROL_BTNPARTYMODE,false);
149             return false;
150           }
151
152           // Playlist directory is the root of the playlist window
153           if (m_guiState.get()) m_guiState->SetPlaylistDirectory("playlistvideo://");
154
155           return true;
156         }
157         UpdateButtons();
158       }
159
160       if (iControl == CONTROL_BTNSEARCH)
161       {
162         OnSearch();
163       }
164       else if (iControl == CONTROL_BTNSHOWMODE)
165       {
166         g_settings.CycleWatchMode(m_vecItems->GetContent());
167         g_settings.Save();
168
169         // TODO: Can we perhaps filter this directly?  Probably not for some of the more complicated views,
170         //       but for those perhaps we can just display them all, and only filter when we get a list
171         //       of actual videos?
172         Update(m_vecItems->GetPath());
173         return true;
174       }
175       else if (iControl == CONTROL_BTNFLATTEN)
176       {
177         g_settings.m_bMyVideoNavFlatten = !g_settings.m_bMyVideoNavFlatten;
178         g_settings.Save();
179         SetProperty("flattened", g_settings.m_bMyVideoNavFlatten);
180         CUtil::DeleteVideoDatabaseDirectoryCache();
181         SetupShares();
182         Update("");
183         return true;
184       }
185       else if (iControl == CONTROL_BTNSHOWALL)
186       {
187         if (g_settings.GetWatchMode(m_vecItems->GetContent()) == VIDEO_SHOW_ALL)
188           g_settings.SetWatchMode(m_vecItems->GetContent(), VIDEO_SHOW_UNWATCHED);
189         else
190           g_settings.SetWatchMode(m_vecItems->GetContent(), VIDEO_SHOW_ALL);
191         g_settings.Save();
192         // TODO: Can we perhaps filter this directly?  Probably not for some of the more complicated views,
193         //       but for those perhaps we can just display them all, and only filter when we get a list
194         //       of actual videos?
195         Update(m_vecItems->GetPath());
196         return true;
197       }
198     }
199     break;
200     // update the display
201     case GUI_MSG_SCAN_FINISHED:
202     case GUI_MSG_REFRESH_THUMBS:
203     {
204       Update(m_vecItems->GetPath());
205     }
206     break;
207   }
208   return CGUIWindowVideoBase::OnMessage(message);
209 }
210
211 CStdString CGUIWindowVideoNav::GetQuickpathName(const CStdString& strPath) const
212 {
213   if (strPath.Equals("videodb://1/1/"))
214     return "MovieGenres";
215   else if (strPath.Equals("videodb://1/2/"))
216     return "MovieTitles";
217   else if (strPath.Equals("videodb://1/3/"))
218     return "MovieYears";
219   else if (strPath.Equals("videodb://1/4/"))
220     return "MovieActors";
221   else if (strPath.Equals("videodb://1/5/"))
222     return "MovieDirectors";
223   else if (strPath.Equals("videodb://1/"))
224     return "Movies";
225   else if (strPath.Equals("videodb://2/1/"))
226     return "TvShowGenres";
227   else if (strPath.Equals("videodb://2/2/"))
228     return "TvShowTitles";
229   else if (strPath.Equals("videodb://2/3/"))
230     return "TvShowYears";
231   else if (strPath.Equals("videodb://2/4/"))
232     return "TvShowActors";
233   else if (strPath.Equals("videodb://2/"))
234     return "TvShows";
235   else if (strPath.Equals("videodb://3/1/"))
236     return "MusicVideoGenres";
237   else if (strPath.Equals("videodb://3/2/"))
238     return "MusicVideoTitles";
239   else if (strPath.Equals("videodb://3/3/"))
240     return "MusicVideoYears";
241   else if (strPath.Equals("videodb://3/4/"))
242     return "MusicVideoArtists";
243   else if (strPath.Equals("videodb://3/5/"))
244     return "MusicVideoDirectors";
245   else if (strPath.Equals("videodb://3/"))
246     return "MusicVideos";
247   else if (strPath.Equals("videodb://4/"))
248     return "RecentlyAddedMovies";
249   else if (strPath.Equals("videodb://5/"))
250     return "RecentlyAddedEpisodes";
251   else if (strPath.Equals("videodb://6/"))
252     return "RecentlyAddedMusicVideos";
253   else if (strPath.Equals("special://videoplaylists/"))
254     return "Playlists";
255   else if (strPath.Equals("sources://video/"))
256     return "Files";
257   else
258   {
259     CLog::Log(LOGERROR, "  CGUIWindowVideoNav::GetQuickpathName: Unknown parameter (%s)", strPath.c_str());
260     return strPath;
261   }
262 }
263
264 void CGUIWindowVideoNav::OnItemLoaded(CFileItem* pItem)
265 {
266   /* even though the background loader is running multiple threads and we could,
267      be acting on someone else's flag, we don't care who invalidates the cache
268      only that it is done.  We also don't care if it is done multiple times due
269      to a race between multiple threads here at the same time */
270   CUtil::DeleteVideoDatabaseDirectoryCache();
271 }
272
273 bool CGUIWindowVideoNav::GetDirectory(const CStdString &strDirectory, CFileItemList &items)
274 {
275   CFileItem directory(strDirectory, true);
276
277   if (m_thumbLoader.IsLoading())
278     m_thumbLoader.StopThread();
279
280   m_rootDir.SetCacheDirectory(DIR_CACHE_ONCE);
281   items.ClearProperties();
282
283   bool bResult = CGUIWindowVideoBase::GetDirectory(strDirectory, items);
284   if (bResult)
285   {
286     if (items.IsVideoDb())
287     {
288       XFILE::CVideoDatabaseDirectory dir;
289       CQueryParams params;
290       dir.GetQueryParams(items.GetPath(),params);
291       VIDEODATABASEDIRECTORY::NODE_TYPE node = dir.GetDirectoryChildType(items.GetPath());
292
293       items.SetThumbnailImage("");
294       if (node == VIDEODATABASEDIRECTORY::NODE_TYPE_EPISODES ||
295           node == NODE_TYPE_SEASONS                          ||
296           node == NODE_TYPE_RECENTLY_ADDED_EPISODES)
297       {
298         CLog::Log(LOGDEBUG, "WindowVideoNav::GetDirectory");
299         // grab the show thumb
300         CStdString path;
301         m_database.GetFilePathById(params.GetTvShowId(),path,VIDEODB_CONTENT_TVSHOWS);
302         CFileItem showItem(path, true);
303         showItem.SetVideoThumb();
304         items.SetProperty("tvshowthumb", showItem.GetThumbnailImage());
305         // Grab fanart data
306         CVideoInfoTag details;
307         m_database.GetTvShowInfo(showItem.GetPath(), details, params.GetTvShowId());
308         items.SetProperty("fanart_color1", details.m_fanart.GetColor(0));
309         items.SetProperty("fanart_color2", details.m_fanart.GetColor(1));
310         items.SetProperty("fanart_color3", details.m_fanart.GetColor(2));
311         if (showItem.CacheLocalFanart())
312           items.SetProperty("fanart_image", showItem.GetCachedFanart());
313
314         // save the show description (showplot)
315         items.SetProperty("showplot", details.m_strPlot);
316
317         // set the season thumb
318         CStdString strLabel;
319         if (params.GetSeason() == 0)
320           strLabel = g_localizeStrings.Get(20381);
321         else
322           strLabel.Format(g_localizeStrings.Get(20358), params.GetSeason());
323
324         CFileItem item(strLabel);
325         item.SetPath(URIUtils::GetParentPath(items.GetPath()));
326         item.m_bIsFolder = true;
327         item.SetCachedSeasonThumb();
328         if (item.HasThumbnail())
329           items.SetProperty("seasonthumb",item.GetThumbnailImage());
330
331         // the container folder thumb is the parent (i.e. season or show)
332         if (node == NODE_TYPE_EPISODES || node == NODE_TYPE_RECENTLY_ADDED_EPISODES)
333         {
334           items.SetContent("episodes");
335           // grab the season thumb as the folder thumb
336           CStdString strLabel;
337           CStdString strPath;
338           if (params.GetSeason() == -1 && items.Size() > 0)
339           {
340             CQueryParams params2;
341             dir.GetQueryParams(items[0]->GetPath(),params2);
342             strLabel.Format(g_localizeStrings.Get(20358), params2.GetSeason());
343             strPath = URIUtils::GetParentPath(items.GetPath());
344           }
345           else
346           {
347             if (params.GetSeason() == 0)
348               strLabel = g_localizeStrings.Get(20381);
349             else
350               strLabel.Format(g_localizeStrings.Get(20358), params.GetSeason());
351             strPath = items.GetPath();
352           }
353
354           CFileItem item(strPath, true);
355           item.SetLabel(strLabel);
356           item.GetVideoInfoTag()->m_strPath = showItem.GetPath();
357           item.SetCachedSeasonThumb();
358
359           items.SetThumbnailImage(item.GetThumbnailImage());
360           items.SetProperty("seasonthumb",item.GetThumbnailImage());
361         }
362         else
363         {
364           items.SetContent("seasons");
365           items.SetThumbnailImage(showItem.GetThumbnailImage());
366         }
367       }
368       else if (node == NODE_TYPE_TITLE_MOVIES ||
369                node == NODE_TYPE_RECENTLY_ADDED_MOVIES)
370         items.SetContent("movies");
371       else if (node == NODE_TYPE_TITLE_TVSHOWS)
372         items.SetContent("tvshows");
373       else if (node == NODE_TYPE_TITLE_MUSICVIDEOS ||
374                node == NODE_TYPE_RECENTLY_ADDED_MUSICVIDEOS)
375         items.SetContent("musicvideos");
376       else if (node == NODE_TYPE_GENRE)
377         items.SetContent("genres");
378       else if (node == NODE_TYPE_COUNTRY)
379         items.SetContent("countries");
380       else if (node == NODE_TYPE_ACTOR)
381       {
382         if (params.GetContentType() == VIDEODB_CONTENT_MUSICVIDEOS)
383           items.SetContent("artists");
384         else
385           items.SetContent("actors");
386       }
387       else if (node == NODE_TYPE_DIRECTOR)
388         items.SetContent("directors");
389       else if (node == NODE_TYPE_STUDIO)
390         items.SetContent("studios");
391       else if (node == NODE_TYPE_YEAR)
392         items.SetContent("years");
393       else if (node == NODE_TYPE_MUSICVIDEOS_ALBUM)
394         items.SetContent("albums");
395       else
396         items.SetContent("");
397     }
398     else
399     { // load info from the database
400       CStdString label;
401       if (items.GetLabel().IsEmpty() && m_rootDir.IsSource(items.GetPath(), g_settings.GetSourcesFromType("video"), &label)) 
402         items.SetLabel(label);
403       LoadVideoInfo(items);
404     }
405   }
406   return bResult;
407 }
408
409 void CGUIWindowVideoNav::LoadVideoInfo(CFileItemList &items)
410 {
411   // TODO: this could possibly be threaded as per the music info loading,
412   //       we could also cache the info
413   if (!items.GetContent().IsEmpty())
414     return; // don't load for listings that have content set
415
416   CStdString content = m_database.GetContentForPath(items.GetPath());
417   items.SetContent(content.IsEmpty() ? "files" : content);
418
419   bool fileMetaData = (g_guiSettings.GetBool("myvideos.filemetadata") &&
420                       !content.IsEmpty() &&
421                        m_stackingAvailable);
422
423   CFileItemList dbItems;
424   /* NOTE: In the future when GetItemsForPath returns all items regardless of whether they're "in the library"
425            we won't need the fetchedPlayCounts code, and can "simply" do this directly on absense of content. */
426   bool fetchedPlayCounts = false;
427   if (!content.IsEmpty())
428   {
429     m_database.GetItemsForPath(content, items.GetPath(), dbItems);
430     dbItems.SetFastLookup(true);
431   }
432
433   for (int i = 0; i < items.Size(); i++)
434   {
435     CFileItemPtr pItem = items[i];
436     CFileItemPtr match;
437     if (!content.IsEmpty())
438       match = dbItems.Get(pItem->GetPath());
439     if (match)
440     {
441       CStdString label (pItem->GetLabel ());
442       CStdString label2(pItem->GetLabel2());
443       pItem->UpdateInfo(*match);
444       
445       if (fileMetaData)
446       {
447         if (match->m_bIsFolder)
448           pItem->SetPath(match->GetVideoInfoTag()->m_strPath);
449         else
450           pItem->SetPath(match->GetVideoInfoTag()->m_strFileNameAndPath);
451         // if we switch from a file to a folder item it means we really shouldn't be sorting files and
452         // folders separately
453         if (pItem->m_bIsFolder != match->m_bIsFolder)
454         {
455           items.SetSortIgnoreFolders(true);
456           pItem->m_bIsFolder = match->m_bIsFolder;
457         }
458       }
459       else
460       {
461         if (CFile::Exists(match->GetCachedFanart()))
462           pItem->SetProperty("fanart_image", match->GetCachedFanart());
463
464         pItem->SetLabel (label);
465         pItem->SetLabel2(label2);
466       }
467     }
468     else
469     {
470       /* NOTE: Currently we GetPlayCounts on our items regardless of whether content is set
471                 as if content is set, GetItemsForPaths doesn't return anything not in the content tables.
472                 This code can be removed once the content tables are always filled */
473       if (!pItem->m_bIsFolder && !fetchedPlayCounts)
474       {
475         m_database.GetPlayCounts(items.GetPath(), items);
476         fetchedPlayCounts = true;
477       }
478       
479       // set the watched overlay
480       if (pItem->HasVideoInfoTag())
481         pItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, pItem->GetVideoInfoTag()->m_playCount > 0);
482
483       // Since the item is not in our db, as an alternative clean its name
484       if (fileMetaData)
485         pItem->CleanString();
486     }
487   }
488 }
489
490 void CGUIWindowVideoNav::UpdateButtons()
491 {
492   CGUIWindowVideoBase::UpdateButtons();
493
494   // Update object count
495   int iItems = m_vecItems->Size();
496   if (iItems)
497   {
498     // check for parent dir and "all" items
499     // should always be the first two items
500     for (int i = 0; i <= (iItems>=2 ? 1 : 0); i++)
501     {
502       CFileItemPtr pItem = m_vecItems->Get(i);
503       if (pItem->IsParentFolder()) iItems--;
504       if (pItem->GetPath().Left(4).Equals("/-1/")) iItems--;
505     }
506     // or the last item
507     if (m_vecItems->Size() > 2 &&
508       m_vecItems->Get(m_vecItems->Size()-1)->GetPath().Left(4).Equals("/-1/"))
509       iItems--;
510   }
511   CStdString items;
512   items.Format("%i %s", iItems, g_localizeStrings.Get(127).c_str());
513   SET_CONTROL_LABEL(CONTROL_LABELFILES, items);
514
515   // set the filter label
516   CStdString strLabel;
517
518   // "Playlists"
519   if (m_vecItems->GetPath().Equals("special://videoplaylists/"))
520     strLabel = g_localizeStrings.Get(136);
521   // "{Playlist Name}"
522   else if (m_vecItems->IsPlayList())
523   {
524     // get playlist name from path
525     CStdString strDummy;
526     URIUtils::Split(m_vecItems->GetPath(), strDummy, strLabel);
527   }
528   else if (m_vecItems->GetPath().Equals("sources://video/"))
529     strLabel = g_localizeStrings.Get(744);
530   // everything else is from a videodb:// path
531   else if (m_vecItems->IsVideoDb())
532   {
533     CVideoDatabaseDirectory dir;
534     dir.GetLabel(m_vecItems->GetPath(), strLabel);
535   }
536   else
537     strLabel = URIUtils::GetFileName(m_vecItems->GetPath());
538
539   SET_CONTROL_LABEL(CONTROL_FILTER, strLabel);
540
541   int watchMode = g_settings.GetWatchMode(m_vecItems->GetContent());
542   SET_CONTROL_LABEL(CONTROL_BTNSHOWMODE, g_localizeStrings.Get(16100 + watchMode));
543
544   SET_CONTROL_SELECTED(GetID(), CONTROL_BTNSHOWALL, watchMode != VIDEO_SHOW_ALL);
545
546   SET_CONTROL_SELECTED(GetID(),CONTROL_BTNPARTYMODE, g_partyModeManager.IsEnabled());
547
548   SET_CONTROL_SELECTED(GetID(),CONTROL_BTNFLATTEN, g_settings.m_bMyVideoNavFlatten);
549 }
550
551 /// \brief Search for names, genres, artists, directors, and plots with search string \e strSearch in the
552 /// \brief video databases and return the found \e items
553 /// \param strSearch The search string
554 /// \param items Items Found
555 void CGUIWindowVideoNav::DoSearch(const CStdString& strSearch, CFileItemList& items)
556 {
557   CFileItemList tempItems;
558   CStdString strGenre = g_localizeStrings.Get(515); // Genre
559   CStdString strActor = g_localizeStrings.Get(20337); // Actor
560   CStdString strDirector = g_localizeStrings.Get(20339); // Director
561   CStdString strMovie = g_localizeStrings.Get(20338); // Movie
562
563   //get matching names
564   m_database.GetMoviesByName(strSearch, tempItems);
565   AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(20338) + "] ", items);
566
567   m_database.GetEpisodesByName(strSearch, tempItems);
568   AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(20359) + "] ", items);
569
570   m_database.GetTvShowsByName(strSearch, tempItems);
571   AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(20364) + "] ", items);
572
573   m_database.GetMusicVideosByName(strSearch, tempItems);
574   AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(20391) + "] ", items);
575
576   m_database.GetMusicVideosByAlbum(strSearch, tempItems);
577   AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(558) + "] ", items);
578   
579   // get matching genres
580   m_database.GetMovieGenresByName(strSearch, tempItems);
581   AppendAndClearSearchItems(tempItems, "[" + strGenre + " - " + g_localizeStrings.Get(20342) + "] ", items);
582
583   m_database.GetTvShowGenresByName(strSearch, tempItems);
584   AppendAndClearSearchItems(tempItems, "[" + strGenre + " - " + g_localizeStrings.Get(20343) + "] ", items);
585
586   m_database.GetMusicVideoGenresByName(strSearch, tempItems);
587   AppendAndClearSearchItems(tempItems, "[" + strGenre + " - " + g_localizeStrings.Get(20389) + "] ", items);
588
589   //get actors/artists
590   m_database.GetMovieActorsByName(strSearch, tempItems);
591   AppendAndClearSearchItems(tempItems, "[" + strActor + " - " + g_localizeStrings.Get(20342) + "] ", items);
592
593   m_database.GetTvShowsActorsByName(strSearch, tempItems);
594   AppendAndClearSearchItems(tempItems, "[" + strActor + " - " + g_localizeStrings.Get(20343) + "] ", items);
595
596   m_database.GetMusicVideoArtistsByName(strSearch, tempItems);
597   AppendAndClearSearchItems(tempItems, "[" + strActor + " - " + g_localizeStrings.Get(20389) + "] ", items);
598
599   //directors
600   m_database.GetMovieDirectorsByName(strSearch, tempItems);
601   AppendAndClearSearchItems(tempItems, "[" + strDirector + " - " + g_localizeStrings.Get(20342) + "] ", items);
602
603   m_database.GetTvShowsDirectorsByName(strSearch, tempItems);
604   AppendAndClearSearchItems(tempItems, "[" + strDirector + " - " + g_localizeStrings.Get(20343) + "] ", items);
605
606   m_database.GetMusicVideoDirectorsByName(strSearch, tempItems);
607   AppendAndClearSearchItems(tempItems, "[" + strDirector + " - " + g_localizeStrings.Get(20389) + "] ", items);
608
609   //plot
610   m_database.GetEpisodesByPlot(strSearch, tempItems);
611   AppendAndClearSearchItems(tempItems, "[" + g_localizeStrings.Get(20365) + "] ", items);
612
613   m_database.GetMoviesByPlot(strSearch, tempItems);
614   AppendAndClearSearchItems(tempItems, "[" + strMovie + " " + g_localizeStrings.Get(207) + "] ", items);
615 }
616
617 void CGUIWindowVideoNav::PlayItem(int iItem)
618 {
619   // unlike additemtoplaylist, we need to check the items here
620   // before calling it since the current playlist will be stopped
621   // and cleared!
622
623   // root is not allowed
624   if (m_vecItems->IsVirtualDirectoryRoot())
625     return;
626
627   CGUIWindowVideoBase::PlayItem(iItem);
628 }
629
630 void CGUIWindowVideoNav::OnInfo(CFileItem* pItem, ADDON::ScraperPtr& scraper)
631 {
632   m_database.Open(); // since we can be called from the music library without being inited
633   if (pItem->IsVideoDb())
634     scraper = m_database.GetScraperForPath(pItem->GetVideoInfoTag()->m_strPath);
635   else
636   {
637     CStdString strPath,strFile;
638     URIUtils::Split(pItem->GetPath(),strPath,strFile);
639     scraper = m_database.GetScraperForPath(strPath);
640   }
641   m_database.Close();
642   CGUIWindowVideoBase::OnInfo(pItem,scraper);
643 }
644
645 bool CGUIWindowVideoNav::CanDelete(const CStdString& strPath)
646 {
647   CQueryParams params;
648   CVideoDatabaseDirectory::GetQueryParams(strPath,params);
649
650   if (params.GetMovieId()   != -1 ||
651       params.GetEpisodeId() != -1 ||
652       params.GetMVideoId()  != -1 ||
653       (params.GetTvShowId() != -1 && params.GetSeason() == -1
654               && !CVideoDatabaseDirectory::IsAllItem(strPath)))
655     return true;
656
657   return false;
658 }
659
660 void CGUIWindowVideoNav::OnDeleteItem(CFileItemPtr pItem)
661 {
662   if (m_vecItems->IsParentFolder())
663     return;
664
665   if (!m_vecItems->IsVideoDb() && !pItem->IsVideoDb())
666   {
667     if (!pItem->GetPath().Equals("newsmartplaylist://video") &&
668         !pItem->GetPath().Equals("special://videoplaylists/") &&
669         !pItem->GetPath().Equals("sources://video/"))
670       CGUIWindowVideoBase::OnDeleteItem(pItem);
671   }
672   else if (pItem->GetPath().Left(14).Equals("videodb://1/7/") &&
673            pItem->GetPath().size() > 14 && pItem->m_bIsFolder)
674   {
675     CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
676     pDialog->SetLine(0, g_localizeStrings.Get(432));
677     CStdString strLabel;
678     strLabel.Format(g_localizeStrings.Get(433),pItem->GetLabel());
679     pDialog->SetLine(1, strLabel);
680     pDialog->SetLine(2, "");;
681     pDialog->DoModal();
682     if (pDialog->IsConfirmed())
683     {
684       CFileItemList items;
685       CDirectory::GetDirectory(pItem->GetPath(),items,"",false,false,DIR_CACHE_ONCE,true,true);
686       for (int i=0;i<items.Size();++i)
687         OnDeleteItem(items[i]);
688
689        CVideoDatabaseDirectory dir;
690        CQueryParams params;
691        dir.GetQueryParams(pItem->GetPath(),params);
692        m_database.DeleteSet(params.GetSetId());
693     }
694   }
695   else if (m_vecItems->GetPath().Equals(CUtil::VideoPlaylistsLocation()) ||
696            m_vecItems->GetPath().Equals("special://videoplaylists/"))
697   {
698     pItem->m_bIsFolder = false;
699     CFileUtils::DeleteItem(pItem);
700   }
701   else
702   {
703     if (!DeleteItem(pItem.get()))
704       return;
705
706     CStdString strDeletePath;
707     if (pItem->m_bIsFolder)
708       strDeletePath=pItem->GetVideoInfoTag()->m_strPath;
709     else
710       strDeletePath=pItem->GetVideoInfoTag()->m_strFileNameAndPath;
711
712     if (URIUtils::GetFileName(strDeletePath).Equals("VIDEO_TS.IFO"))
713     {
714       URIUtils::GetDirectory(strDeletePath.Mid(0),strDeletePath);
715       if (strDeletePath.Right(9).Equals("VIDEO_TS/"))
716       {
717         URIUtils::RemoveSlashAtEnd(strDeletePath);
718         URIUtils::GetDirectory(strDeletePath.Mid(0),strDeletePath);
719       }
720     }
721     if (URIUtils::HasSlashAtEnd(strDeletePath))
722       pItem->m_bIsFolder=true;
723
724     if (g_guiSettings.GetBool("filelists.allowfiledeletion") &&
725         CUtil::SupportsFileOperations(strDeletePath))
726     {
727       pItem->SetPath(strDeletePath);
728       CGUIWindowVideoBase::OnDeleteItem(pItem);
729     }
730   }
731
732   CUtil::DeleteVideoDatabaseDirectoryCache();
733 }
734
735 bool CGUIWindowVideoNav::DeleteItem(CFileItem* pItem, bool bUnavailable /* = false */)
736 {
737   if (!pItem->HasVideoInfoTag() || !CanDelete(pItem->GetPath()))
738     return false;
739
740   VIDEODB_CONTENT_TYPE iType=VIDEODB_CONTENT_MOVIES;
741   if (pItem->HasVideoInfoTag() && !pItem->GetVideoInfoTag()->m_strShowTitle.IsEmpty())
742     iType = VIDEODB_CONTENT_TVSHOWS;
743   if (pItem->HasVideoInfoTag() && pItem->GetVideoInfoTag()->m_iSeason > -1 && !pItem->m_bIsFolder)
744     iType = VIDEODB_CONTENT_EPISODES;
745   if (pItem->HasVideoInfoTag() && !pItem->GetVideoInfoTag()->m_strArtist.IsEmpty())
746     iType = VIDEODB_CONTENT_MUSICVIDEOS;
747
748   // dont allow update while scanning
749   CGUIDialogVideoScan* pDialogScan = (CGUIDialogVideoScan*)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_SCAN);
750   if (pDialogScan && pDialogScan->IsScanning())
751   {
752     CGUIDialogOK::ShowAndGetInput(257, 0, 14057, 0);
753     return false;
754   }
755
756
757   CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
758   if (!pDialog)
759     return false;
760   if (iType == VIDEODB_CONTENT_MOVIES)
761     pDialog->SetHeading(432);
762   if (iType == VIDEODB_CONTENT_EPISODES)
763     pDialog->SetHeading(20362);
764   if (iType == VIDEODB_CONTENT_TVSHOWS)
765     pDialog->SetHeading(20363);
766   if (iType == VIDEODB_CONTENT_MUSICVIDEOS)
767     pDialog->SetHeading(20392);
768
769   if(bUnavailable)
770   {
771     pDialog->SetLine(0, g_localizeStrings.Get(662));
772     pDialog->SetLine(1, g_localizeStrings.Get(663));
773     pDialog->SetLine(2, "");;
774     pDialog->DoModal();
775   }
776   else
777   {
778     CStdString strLine;
779     strLine.Format(g_localizeStrings.Get(433),pItem->GetLabel());
780     pDialog->SetLine(0, strLine);
781     pDialog->SetLine(1, "");
782     pDialog->SetLine(2, "");;
783     pDialog->DoModal();
784   }
785
786   if (!pDialog->IsConfirmed())
787     return false;
788
789   CStdString path;
790   CVideoDatabase database;
791   database.Open();
792
793   database.GetFilePathById(pItem->GetVideoInfoTag()->m_iDbId, path, iType);
794   if (path.IsEmpty())
795     return false;
796   if (iType == VIDEODB_CONTENT_MOVIES)
797     database.DeleteMovie(path);
798   if (iType == VIDEODB_CONTENT_EPISODES)
799     database.DeleteEpisode(path, pItem->GetVideoInfoTag()->m_iDbId);
800   if (iType == VIDEODB_CONTENT_TVSHOWS)
801     database.DeleteTvShow(path);
802   if (iType == VIDEODB_CONTENT_MUSICVIDEOS)
803     database.DeleteMusicVideo(path);
804
805   if (iType == VIDEODB_CONTENT_TVSHOWS)
806     database.SetPathHash(path,"");
807   else
808   {
809     CStdString strDirectory;
810     URIUtils::GetDirectory(path,strDirectory);
811     database.SetPathHash(strDirectory,"");
812   }
813
814   return true;
815 }
816
817 void CGUIWindowVideoNav::OnPrepareFileItems(CFileItemList &items)
818 {
819   CGUIWindowVideoBase::OnPrepareFileItems(items);
820
821   // set fanart
822   CQueryParams params;
823   CVideoDatabaseDirectory dir;
824   dir.GetQueryParams(items.GetPath(),params);
825   if (params.GetContentType() == VIDEODB_CONTENT_MUSICVIDEOS)
826     CGUIWindowMusicNav::SetupFanart(items);
827
828   NODE_TYPE node = dir.GetDirectoryChildType(items.GetPath());
829
830   // now filter as necessary
831   bool filterWatched=false;
832   if (node == NODE_TYPE_EPISODES
833   ||  node == NODE_TYPE_SEASONS
834   ||  node == NODE_TYPE_TITLE_MOVIES
835   ||  node == NODE_TYPE_TITLE_TVSHOWS
836   ||  node == NODE_TYPE_TITLE_MUSICVIDEOS
837   ||  node == NODE_TYPE_RECENTLY_ADDED_EPISODES
838   ||  node == NODE_TYPE_RECENTLY_ADDED_MOVIES
839   ||  node == NODE_TYPE_RECENTLY_ADDED_MUSICVIDEOS)
840     filterWatched = true;
841   if (!items.IsVideoDb())
842     filterWatched = true;
843   if (items.IsSmartPlayList() && items.GetContent() == "tvshows")
844     node = NODE_TYPE_TITLE_TVSHOWS; // so that the check below works
845
846   int watchMode = g_settings.GetWatchMode(m_vecItems->GetContent());
847
848   for (int i = 0; i < items.Size(); i++)
849   {
850     CFileItemPtr item = items.Get(i);
851     if(item->HasVideoInfoTag() && (node == NODE_TYPE_TITLE_TVSHOWS || node == NODE_TYPE_SEASONS))
852     {
853       if (watchMode == VIDEO_SHOW_UNWATCHED)
854         item->GetVideoInfoTag()->m_iEpisode = (int)item->GetProperty("unwatchedepisodes").asInteger();
855       if (watchMode == VIDEO_SHOW_WATCHED)
856         item->GetVideoInfoTag()->m_iEpisode = (int)item->GetProperty("watchedepisodes").asInteger();
857       item->SetProperty("numepisodes", item->GetVideoInfoTag()->m_iEpisode);
858     }
859
860     if(filterWatched)
861     {
862       if((watchMode==VIDEO_SHOW_WATCHED   && item->GetVideoInfoTag()->m_playCount== 0)
863       || (watchMode==VIDEO_SHOW_UNWATCHED && item->GetVideoInfoTag()->m_playCount > 0))
864       {
865         items.Remove(i);
866         i--;
867       }
868     }
869   }
870 }
871
872 void CGUIWindowVideoNav::GetContextButtons(int itemNumber, CContextButtons &buttons)
873 {
874   CFileItemPtr item;
875   if (itemNumber >= 0 && itemNumber < m_vecItems->Size())
876     item = m_vecItems->Get(itemNumber);
877
878   CGUIWindowVideoBase::GetContextButtons(itemNumber, buttons);
879
880   if (item && item->GetProperty("pluginreplacecontextitems").asBoolean())
881     return;
882
883   CVideoDatabaseDirectory dir;
884   NODE_TYPE node = dir.GetDirectoryChildType(m_vecItems->GetPath());
885
886   if (!item)
887   {
888     CGUIDialogVideoScan *pScanDlg = (CGUIDialogVideoScan *)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_SCAN);
889     if (pScanDlg && pScanDlg->IsScanning())
890       buttons.Add(CONTEXT_BUTTON_STOP_SCANNING, 13353);
891     else
892       buttons.Add(CONTEXT_BUTTON_UPDATE_LIBRARY, 653);
893   }
894   else if (m_vecItems->GetPath().Equals("sources://video/"))
895   {
896     // get the usual shares
897     CGUIDialogContextMenu::GetContextButtons("video", item, buttons);
898     // add scan button somewhere here
899     CGUIDialogVideoScan *pScanDlg = (CGUIDialogVideoScan *)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_SCAN);
900     if (pScanDlg && pScanDlg->IsScanning())
901       buttons.Add(CONTEXT_BUTTON_STOP_SCANNING, 13353);  // Stop Scanning
902     if (!item->IsDVD() && item->GetPath() != "add" &&
903         (g_settings.GetCurrentProfile().canWriteDatabases() || g_passwordManager.bMasterUser))
904     {
905       CVideoDatabase database;
906       database.Open();
907       ADDON::ScraperPtr info = database.GetScraperForPath(item->GetPath());
908
909       if (!pScanDlg || (pScanDlg && !pScanDlg->IsScanning()))
910       {
911         if (!item->IsLiveTV() && !item->IsPlugin() && !item->IsAddonsPath())
912         {
913           if (info && info->Content() != CONTENT_NONE)
914             buttons.Add(CONTEXT_BUTTON_SET_CONTENT, 20442);
915           else
916             buttons.Add(CONTEXT_BUTTON_SET_CONTENT, 20333);
917         }
918       }
919
920       if (info && (!pScanDlg || (pScanDlg && !pScanDlg->IsScanning())))
921         buttons.Add(CONTEXT_BUTTON_SCAN, 13349);
922     }
923   }
924   else
925   {
926     // are we in the playlists location?
927     bool inPlaylists = m_vecItems->GetPath().Equals(CUtil::VideoPlaylistsLocation()) ||
928                        m_vecItems->GetPath().Equals("special://videoplaylists/");
929
930     if (item->HasVideoInfoTag() && !item->GetVideoInfoTag()->m_strArtist.IsEmpty())
931     {
932       CMusicDatabase database;
933       database.Open();
934       if (database.GetArtistByName(item->GetVideoInfoTag()->m_strArtist) > -1)
935         buttons.Add(CONTEXT_BUTTON_GO_TO_ARTIST, 20396);
936     }
937     if (item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_strAlbum.size() > 0)
938     {
939       CMusicDatabase database;
940       database.Open();
941       if (database.GetAlbumByName(item->GetVideoInfoTag()->m_strAlbum) > -1)
942         buttons.Add(CONTEXT_BUTTON_GO_TO_ALBUM, 20397);
943     }
944     if (item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_strAlbum.size() > 0 &&
945         item->GetVideoInfoTag()->m_strArtist.size() > 0                           &&
946         item->GetVideoInfoTag()->m_strTitle.size() > 0)
947     {
948       CMusicDatabase database;
949       database.Open();
950       if (database.GetSongByArtistAndAlbumAndTitle(item->GetVideoInfoTag()->m_strArtist,
951                                                    item->GetVideoInfoTag()->m_strAlbum,
952                                                    item->GetVideoInfoTag()->m_strTitle) > -1)
953       {
954         buttons.Add(CONTEXT_BUTTON_PLAY_OTHER, 20398);
955       }
956     }
957     if (!item->IsParentFolder())
958     {
959       ADDON::ScraperPtr info;
960       VIDEO::SScanSettings settings;
961       GetScraperForItem(item.get(), info, settings);
962
963       if (info && info->Content() == CONTENT_TVSHOWS)
964         buttons.Add(CONTEXT_BUTTON_INFO, item->m_bIsFolder ? 20351 : 20352);
965       else if (info && info->Content() == CONTENT_MUSICVIDEOS)
966         buttons.Add(CONTEXT_BUTTON_INFO,20393);
967       else if (info && info->Content() == CONTENT_MOVIES)
968         buttons.Add(CONTEXT_BUTTON_INFO, 13346);
969
970       // can we update the database?
971       if (g_settings.GetCurrentProfile().canWriteDatabases() || g_passwordManager.bMasterUser)
972       {
973         if (node == NODE_TYPE_TITLE_TVSHOWS)
974         {
975           CGUIDialogVideoScan *pScanDlg = (CGUIDialogVideoScan *)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_SCAN);
976           if (pScanDlg && pScanDlg->IsScanning())
977             buttons.Add(CONTEXT_BUTTON_STOP_SCANNING, 13353);
978           else
979             buttons.Add(CONTEXT_BUTTON_UPDATE_TVSHOW, 13349);
980         }
981         if (!item->IsPlugin() && !item->IsScript() && !item->IsLiveTV() && !item->IsAddonsPath() &&
982              item->GetPath() != "sources://video/" && item->GetPath() != "special://videoplaylists/")
983         {
984           if (item->m_bIsFolder)
985           {
986             // Have both options for folders since we don't know whether all childs are watched/unwatched
987             buttons.Add(CONTEXT_BUTTON_MARK_UNWATCHED, 16104); //Mark as UnWatched
988             buttons.Add(CONTEXT_BUTTON_MARK_WATCHED, 16103);   //Mark as Watched
989           }
990           else
991           {
992             if (item->GetOverlayImage().Equals("OverlayWatched.png"))
993               buttons.Add(CONTEXT_BUTTON_MARK_UNWATCHED, 16104); //Mark as UnWatched
994             else
995               buttons.Add(CONTEXT_BUTTON_MARK_WATCHED, 16103);   //Mark as Watched
996           }
997         }
998         if ((node == NODE_TYPE_TITLE_TVSHOWS) ||
999             (item->IsVideoDb() && item->HasVideoInfoTag() && !item->m_bIsFolder))
1000         {
1001           buttons.Add(CONTEXT_BUTTON_EDIT, 16105); //Edit Title
1002         }
1003         if (m_database.HasContent(VIDEODB_CONTENT_TVSHOWS) && item->HasVideoInfoTag() &&
1004            !item->m_bIsFolder && item->GetVideoInfoTag()->m_iEpisode == -1 &&
1005             item->GetVideoInfoTag()->m_strArtist.IsEmpty() && item->GetVideoInfoTag()->m_iDbId >= 0) // movie entry
1006         {
1007           if (m_database.IsLinkedToTvshow(item->GetVideoInfoTag()->m_iDbId))
1008             buttons.Add(CONTEXT_BUTTON_UNLINK_MOVIE,20385);
1009           buttons.Add(CONTEXT_BUTTON_LINK_MOVIE,20384);
1010         }
1011
1012         if (node == NODE_TYPE_SEASONS && item->m_bIsFolder)
1013           buttons.Add(CONTEXT_BUTTON_SET_SEASON_THUMB, 20371);
1014
1015         if (item->GetPath().Left(14).Equals("videodb://1/7/") && item->GetPath().size() > 14 && item->m_bIsFolder) // sets
1016         {
1017           buttons.Add(CONTEXT_BUTTON_EDIT, 16105);
1018           buttons.Add(CONTEXT_BUTTON_SET_MOVIESET_THUMB, 20435);
1019           buttons.Add(CONTEXT_BUTTON_SET_MOVIESET_FANART, 20456);
1020           buttons.Add(CONTEXT_BUTTON_DELETE, 646);
1021         }
1022
1023         if (node == NODE_TYPE_ACTOR && !dir.IsAllItem(item->GetPath()) && item->m_bIsFolder)
1024         {
1025           if (m_vecItems->GetPath().Left(11).Equals("videodb://3")) // mvids
1026             buttons.Add(CONTEXT_BUTTON_SET_ARTIST_THUMB, 13359);
1027           else
1028             buttons.Add(CONTEXT_BUTTON_SET_ACTOR_THUMB, 20403);
1029         }
1030         if (item->IsVideoDb() && item->HasVideoInfoTag() &&
1031           (!item->m_bIsFolder || node == NODE_TYPE_TITLE_TVSHOWS))
1032         {
1033           if (info && info->Content() == CONTENT_TVSHOWS)
1034           {
1035             if(item->GetVideoInfoTag()->m_iBookmarkId != -1 &&
1036                item->GetVideoInfoTag()->m_iBookmarkId != 0)
1037             {
1038               buttons.Add(CONTEXT_BUTTON_UNLINK_BOOKMARK, 20405);
1039             }
1040           }
1041           buttons.Add(CONTEXT_BUTTON_DELETE, 646);
1042         }
1043
1044         // this should ideally be non-contextual (though we need some context for non-tv show node I guess)
1045         CGUIDialogVideoScan *pScanDlg = (CGUIDialogVideoScan *)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_SCAN);
1046         if (pScanDlg && pScanDlg->IsScanning())
1047         {
1048           if (node != NODE_TYPE_TITLE_TVSHOWS)
1049             buttons.Add(CONTEXT_BUTTON_STOP_SCANNING, 13353);
1050         }
1051         else
1052           buttons.Add(CONTEXT_BUTTON_UPDATE_LIBRARY, 653);
1053       }
1054
1055       if (!m_vecItems->IsVideoDb() && !m_vecItems->IsVirtualDirectoryRoot())
1056       { // non-video db items, file operations are allowed
1057         if ((g_guiSettings.GetBool("filelists.allowfiledeletion") &&
1058             CUtil::SupportsFileOperations(item->GetPath())) ||
1059             (inPlaylists && !URIUtils::GetFileName(item->GetPath()).Equals("PartyMode-Video.xsp")
1060                          && (item->IsPlayList() || item->IsSmartPlayList())))
1061         {
1062           buttons.Add(CONTEXT_BUTTON_DELETE, 117);
1063           buttons.Add(CONTEXT_BUTTON_RENAME, 118);
1064         }
1065         // add "Set/Change content" to folders
1066         if (item->m_bIsFolder && !item->IsPlayList() && !item->IsSmartPlayList() && !item->IsLiveTV() && !item->IsPlugin() && !item->IsAddonsPath())
1067         {
1068           CGUIDialogVideoScan *pScanDlg = (CGUIDialogVideoScan *)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_SCAN);
1069           if (!pScanDlg || (pScanDlg && !pScanDlg->IsScanning()))
1070           {
1071             if (info && info->Content() != CONTENT_NONE)
1072               buttons.Add(CONTEXT_BUTTON_SET_CONTENT, 20442);
1073             else
1074               buttons.Add(CONTEXT_BUTTON_SET_CONTENT, 20333);
1075           }
1076         }
1077       }
1078       if (item->IsPlugin() || item->IsScript() || m_vecItems->IsPlugin())
1079         buttons.Add(CONTEXT_BUTTON_PLUGIN_SETTINGS, 1045);
1080     }
1081   }
1082   CGUIWindowVideoBase::GetNonContextButtons(itemNumber, buttons);
1083 }
1084
1085 bool CGUIWindowVideoNav::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
1086 {
1087   CFileItemPtr item;
1088   if (itemNumber >= 0 && itemNumber < m_vecItems->Size())
1089     item = m_vecItems->Get(itemNumber);
1090   if (CGUIDialogContextMenu::OnContextButton("video", item, button))
1091   {
1092     //TODO should we search DB for entries from plugins?
1093     if (button == CONTEXT_BUTTON_REMOVE_SOURCE && !item->IsPlugin()
1094         && !item->IsLiveTV() &&!item->IsRSS())
1095     {
1096       OnUnAssignContent(item->GetPath(),20375,20340,20341);
1097     }
1098     Update(m_vecItems->GetPath());
1099     return true;
1100   }
1101   switch (button)
1102   {
1103   case CONTEXT_BUTTON_EDIT:
1104     UpdateVideoTitle(item.get());
1105     CUtil::DeleteVideoDatabaseDirectoryCache();
1106     Update(m_vecItems->GetPath());
1107     return true;
1108
1109   case CONTEXT_BUTTON_SET_SEASON_THUMB:
1110   case CONTEXT_BUTTON_SET_ACTOR_THUMB:
1111   case CONTEXT_BUTTON_SET_ARTIST_THUMB:
1112   case CONTEXT_BUTTON_SET_MOVIESET_THUMB:
1113     {
1114       // Grab the thumbnails from the web
1115       CStdString strPath;
1116       CFileItemList items;
1117       URIUtils::AddFileToFolder(g_advancedSettings.m_cachePath,"imdbthumbs",strPath);
1118       CFileItemPtr cacheItem(new CFileItem(strPath,true));
1119       CFileUtils::DeleteItem(cacheItem,true);
1120       XFILE::CDirectory::Create(strPath);
1121       CFileItemPtr noneitem(new CFileItem("thumb://None", false));
1122       CStdString cachedThumb = m_vecItems->Get(itemNumber)->GetCachedSeasonThumb();
1123       if (button == CONTEXT_BUTTON_SET_ACTOR_THUMB)
1124         cachedThumb = m_vecItems->Get(itemNumber)->GetCachedActorThumb();
1125       if (button == CONTEXT_BUTTON_SET_ARTIST_THUMB)
1126         cachedThumb = m_vecItems->Get(itemNumber)->GetCachedArtistThumb();
1127       if (button == CONTEXT_BUTTON_SET_MOVIESET_THUMB)
1128         cachedThumb = m_vecItems->Get(itemNumber)->GetCachedVideoThumb();
1129       if (CFile::Exists(cachedThumb))
1130       {
1131         CFileItemPtr item(new CFileItem("thumb://Current", false));
1132         item->SetThumbnailImage(cachedThumb);
1133         item->SetLabel(g_localizeStrings.Get(20016));
1134         items.Add(item);
1135       }
1136       noneitem->SetIconImage("DefaultFolder.png");
1137       noneitem->SetLabel(g_localizeStrings.Get(20018));
1138
1139       vector<CStdString> thumbs;
1140       if (button != CONTEXT_BUTTON_SET_ARTIST_THUMB)
1141       {
1142         CVideoInfoTag tag;
1143         if (button == CONTEXT_BUTTON_SET_SEASON_THUMB)
1144           m_database.GetTvShowInfo("",tag,m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_iDbId);
1145         else
1146           tag = *m_vecItems->Get(itemNumber)->GetVideoInfoTag();
1147         if (button == CONTEXT_BUTTON_SET_SEASON_THUMB)
1148           tag.m_strPictureURL.GetThumbURLs(thumbs, m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_iSeason);
1149         else
1150           tag.m_strPictureURL.GetThumbURLs(thumbs);
1151
1152         for (unsigned int i = 0; i < thumbs.size(); i++)
1153         {
1154           CStdString strItemPath;
1155           strItemPath.Format("thumb://Remote%i",i);
1156           CFileItemPtr item(new CFileItem(strItemPath, false));
1157           item->SetThumbnailImage(thumbs[i]);
1158           item->SetIconImage("DefaultPicture.png");
1159           item->SetLabel(g_localizeStrings.Get(20015));
1160           items.Add(item);
1161
1162           // TODO: Do we need to clear the cached image?
1163           //    CTextureCache::Get().ClearCachedImage(thumbs[i]);
1164         }
1165       }
1166
1167       bool local=false;
1168       if (button == CONTEXT_BUTTON_SET_ARTIST_THUMB)
1169       {
1170         CStdString picturePath;
1171
1172         CStdString strPath = m_vecItems->Get(itemNumber)->GetPath();
1173         URIUtils::RemoveSlashAtEnd(strPath);
1174
1175         int nPos=strPath.ReverseFind("/");
1176         if (nPos>-1)
1177         {
1178           //  try to guess where the user should start
1179           //  browsing for the artist thumb
1180           CMusicDatabase database;
1181           database.Open();
1182           long idArtist=database.GetArtistByName(m_vecItems->Get(itemNumber)->GetLabel());
1183           database.GetArtistPath(idArtist, picturePath);
1184         }
1185
1186         CStdString strThumb;
1187         URIUtils::AddFileToFolder(picturePath,"folder.jpg",strThumb);
1188         if (XFILE::CFile::Exists(strThumb))
1189         {
1190           CFileItemPtr pItem(new CFileItem(strThumb,false));
1191           pItem->SetLabel(g_localizeStrings.Get(20017));
1192           pItem->SetThumbnailImage(strThumb);
1193           items.Add(pItem);
1194           local = true;
1195         }
1196         else
1197           noneitem->SetIconImage("DefaultArtist.png");
1198       }
1199
1200       if (button == CONTEXT_BUTTON_SET_ACTOR_THUMB)
1201       {
1202         CStdString picturePath;
1203         CStdString strThumb;
1204         URIUtils::AddFileToFolder(picturePath,"folder.jpg",strThumb);
1205         if (XFILE::CFile::Exists(strThumb))
1206         {
1207           CFileItemPtr pItem(new CFileItem(strThumb,false));
1208           pItem->SetLabel(g_localizeStrings.Get(20017));
1209           pItem->SetThumbnailImage(strThumb);
1210           items.Add(pItem);
1211           local = true;
1212         }
1213         else
1214           noneitem->SetIconImage("DefaultActor.png");
1215       }
1216
1217       if (button == CONTEXT_BUTTON_SET_MOVIESET_THUMB)
1218         noneitem->SetIconImage("DefaultVideo.png");
1219
1220       if (!local)
1221         items.Add(noneitem);
1222
1223       VECSOURCES sources=g_settings.m_videoSources;
1224       g_mediaManager.GetLocalDrives(sources);
1225       CStdString result;
1226       if (!CGUIDialogFileBrowser::ShowAndGetImage(items, sources,
1227                                                   g_localizeStrings.Get(20019), result))
1228       {
1229         return false;   // user cancelled
1230       }
1231
1232       if (result == "thumb://Current")
1233         return false;   // user chose the one they have
1234
1235       // delete the thumbnail if that's what the user wants, else overwrite with the
1236       // new thumbnail
1237       CTextureCache::Get().ClearCachedImage(cachedThumb, true);
1238       if (result.Left(14) == "thumb://Remote")
1239       {
1240         int number = atoi(result.Mid(14));
1241         CFile::Cache(thumbs[number], cachedThumb);
1242       }
1243       if (result == "thumb://None")
1244         CTextureCache::Get().ClearCachedImage(cachedThumb, true);
1245       else
1246         CFile::Cache(result,cachedThumb);
1247
1248       CUtil::DeleteVideoDatabaseDirectoryCache();
1249       CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_REFRESH_THUMBS);
1250       g_windowManager.SendMessage(msg);
1251       Update(m_vecItems->GetPath());
1252
1253       return true;
1254     }
1255   case CONTEXT_BUTTON_SET_MOVIESET_FANART:
1256     {
1257       CFileItemList items;
1258       CStdString cachedFanart(item->GetCachedFanart());
1259
1260       if (CFile::Exists(cachedFanart))
1261       {
1262         CFileItemPtr itemCurrent(new CFileItem("fanart://Current",false));
1263         itemCurrent->SetThumbnailImage(cachedFanart);
1264         itemCurrent->SetLabel(g_localizeStrings.Get(20440));
1265         items.Add(itemCurrent);
1266       }
1267
1268       CStdString localFanart(item->GetLocalFanart());
1269       if (!localFanart.IsEmpty())
1270       {
1271         CFileItemPtr itemLocal(new CFileItem("fanart://Local",false));
1272         itemLocal->SetThumbnailImage(localFanart);
1273         itemLocal->SetLabel(g_localizeStrings.Get(20438));
1274         CTextureCache::Get().ClearCachedImage(localFanart);
1275         items.Add(itemLocal);
1276       }
1277       else
1278       {
1279         CFileItemPtr itemNone(new CFileItem("fanart://None", false));
1280         itemNone->SetIconImage("DefaultVideo.png");
1281         itemNone->SetLabel(g_localizeStrings.Get(20439));
1282         items.Add(itemNone);
1283       }
1284
1285       CStdString result;
1286       VECSOURCES sources(g_settings.m_videoSources);
1287       g_mediaManager.GetLocalDrives(sources);
1288       bool flip=false;
1289       if (!CGUIDialogFileBrowser::ShowAndGetImage(items, sources, g_localizeStrings.Get(20437), result, &flip, 20445) || result.Equals("fanart://Current"))
1290         return false;
1291
1292       CTextureCache::Get().ClearCachedImage(cachedFanart, true);
1293
1294       if (result.Equals("fanart://Local"))
1295         result = localFanart;
1296
1297       if (CFile::Exists(result))
1298       {
1299         if (flip)
1300           CPicture::ConvertFile(result, cachedFanart,0,1920,-1,100,true);
1301         else
1302           CPicture::CacheFanart(result, cachedFanart);
1303       }
1304
1305       // clear view cache and reload images
1306       CUtil::DeleteVideoDatabaseDirectoryCache();
1307
1308       if (CFile::Exists(cachedFanart))
1309         item->SetProperty("fanart_image", cachedFanart);
1310       else
1311         item->ClearProperty("fanart_image");
1312
1313       Update(m_vecItems->GetPath());
1314       return true;
1315     }
1316   case CONTEXT_BUTTON_UPDATE_LIBRARY:
1317     {
1318       OnScan("");
1319       return true;
1320     }
1321   case CONTEXT_BUTTON_UNLINK_MOVIE:
1322     {
1323       OnLinkMovieToTvShow(itemNumber, true);
1324       Update(m_vecItems->GetPath());
1325       return true;
1326     }
1327   case CONTEXT_BUTTON_LINK_MOVIE:
1328     {
1329       OnLinkMovieToTvShow(itemNumber, false);
1330       return true;
1331     }
1332   case CONTEXT_BUTTON_GO_TO_ARTIST:
1333     {
1334       CStdString strPath;
1335       CMusicDatabase database;
1336       database.Open();
1337       strPath.Format("musicdb://2/%ld/",database.GetArtistByName(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strArtist));
1338       g_windowManager.ActivateWindow(WINDOW_MUSIC_NAV,strPath);
1339       return true;
1340     }
1341   case CONTEXT_BUTTON_GO_TO_ALBUM:
1342     {
1343       CStdString strPath;
1344       CMusicDatabase database;
1345       database.Open();
1346       strPath.Format("musicdb://3/%ld/",database.GetAlbumByName(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strAlbum));
1347       g_windowManager.ActivateWindow(WINDOW_MUSIC_NAV,strPath);
1348       return true;
1349     }
1350   case CONTEXT_BUTTON_PLAY_OTHER:
1351     {
1352       CMusicDatabase database;
1353       database.Open();
1354       CSong song;
1355       if (database.GetSongById(database.GetSongByArtistAndAlbumAndTitle(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strArtist,m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strAlbum,
1356                                                                         m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strTitle),
1357                                                                         song))
1358       {
1359         g_application.getApplicationMessenger().PlayFile(song);
1360       }
1361       return true;
1362     }
1363
1364   case CONTEXT_BUTTON_UNLINK_BOOKMARK:
1365     {
1366       m_database.Open();
1367       m_database.DeleteBookMarkForEpisode(*m_vecItems->Get(itemNumber)->GetVideoInfoTag());
1368       m_database.Close();
1369       CUtil::DeleteVideoDatabaseDirectoryCache();
1370       Update(m_vecItems->GetPath());
1371       return true;
1372     }
1373
1374   default:
1375     break;
1376
1377   }
1378   return CGUIWindowVideoBase::OnContextButton(itemNumber, button);
1379 }
1380
1381 void CGUIWindowVideoNav::OnLinkMovieToTvShow(int itemnumber, bool bRemove)
1382 {
1383   CFileItemList list;
1384   if (bRemove)
1385   {
1386     vector<int> ids;
1387     if (!m_database.GetLinksToTvShow(m_vecItems->Get(itemnumber)->GetVideoInfoTag()->m_iDbId,ids))
1388       return;
1389     for (unsigned int i=0;i<ids.size();++i)
1390     {
1391       CVideoInfoTag tag;
1392       m_database.GetTvShowInfo("",tag,ids[i]);
1393       CFileItemPtr show(new CFileItem(tag));
1394       list.Add(show);
1395     }
1396   }
1397   else
1398   {
1399     m_database.GetTvShowsNav("videodb://2/2",list);
1400
1401     // remove already linked shows
1402     vector<int> ids;
1403     if (!m_database.GetLinksToTvShow(m_vecItems->Get(itemnumber)->GetVideoInfoTag()->m_iDbId,ids))
1404       return;
1405     for (int i=0;i<list.Size();)
1406     {
1407       unsigned int j;
1408       for (j=0;j<ids.size();++j)
1409       {
1410         if (list[i]->GetVideoInfoTag()->m_iDbId == ids[j])
1411           break;
1412       }
1413       if (j == ids.size())
1414         i++;
1415       else
1416         list.Remove(i);
1417     }
1418   }
1419   int iSelectedLabel = 0;
1420   if (list.Size() > 1)
1421   {
1422     list.Sort(g_guiSettings.GetBool("filelists.ignorethewhensorting") ? SORT_METHOD_LABEL_IGNORE_THE : SORT_METHOD_LABEL, SORT_ORDER_ASC);
1423     CGUIDialogSelect* pDialog = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
1424     pDialog->Reset();
1425     pDialog->SetItems(&list);
1426     pDialog->SetHeading(20356);
1427     pDialog->DoModal();
1428     iSelectedLabel = pDialog->GetSelectedLabel();
1429   }
1430   if (iSelectedLabel > -1)
1431   {
1432     m_database.LinkMovieToTvshow(m_vecItems->Get(itemnumber)->GetVideoInfoTag()->m_iDbId,
1433                                  list[iSelectedLabel]->GetVideoInfoTag()->m_iDbId, bRemove);
1434     CUtil::DeleteVideoDatabaseDirectoryCache();
1435   }
1436 }
1437
1438 bool CGUIWindowVideoNav::OnClick(int iItem)
1439 {
1440   CFileItemPtr item = m_vecItems->Get(iItem);
1441   if (!item->m_bIsFolder && item->IsVideoDb() && !item->Exists())
1442   {
1443     if (!DeleteItem(item.get(), true))
1444       return true;
1445
1446     // update list
1447     m_vecItems->RemoveDiscCache(GetID());
1448     Update(m_vecItems->GetPath());
1449     m_viewControl.SetSelectedItem(iItem);
1450     return true;
1451   }
1452
1453   return CGUIWindowVideoBase::OnClick(iItem);
1454 }
1455
1456 CStdString CGUIWindowVideoNav::GetStartFolder(const CStdString &dir)
1457 {
1458   if (dir.Equals("MovieGenres"))
1459     return "videodb://1/1/";
1460   else if (dir.Equals("MovieTitles"))
1461     return "videodb://1/2/";
1462   else if (dir.Equals("MovieYears"))
1463     return "videodb://1/3/";
1464   else if (dir.Equals("MovieActors"))
1465     return "videodb://1/4/";
1466   else if (dir.Equals("MovieDirectors"))
1467     return "videodb://1/5/";
1468   else if (dir.Equals("MovieStudios"))
1469     return "videodb://1/6/";
1470   else if (dir.Equals("MovieSets"))
1471     return "videodb://1/7/";
1472   else if (dir.Equals("MovieCountries"))
1473     return "videodb://1/8/";
1474   else if (dir.Equals("Movies"))
1475     return "videodb://1/";
1476   else if (dir.Equals("TvShowGenres"))
1477     return "videodb://2/1/";
1478   else if (dir.Equals("TvShowTitles"))
1479     return "videodb://2/2/";
1480   else if (dir.Equals("TvShowYears"))
1481     return "videodb://2/3/";
1482   else if (dir.Equals("TvShowActors"))
1483     return "videodb://2/4/";
1484   else if (dir.Equals("TvShowStudios"))
1485     return "videodb://2/5/";
1486   else if (dir.Equals("TvShows"))
1487     return "videodb://2/";
1488   else if (dir.Equals("MusicVideoGenres"))
1489     return "videodb://3/1/";
1490   else if (dir.Equals("MusicVideoTitles"))
1491     return "videodb://3/2/";
1492   else if (dir.Equals("MusicVideoYears"))
1493     return "videodb://3/3/";
1494   else if (dir.Equals("MusicVideoArtists"))
1495     return "videodb://3/4/";
1496   else if (dir.Equals("MusicVideoDirectors"))
1497     return "videodb://3/5/";
1498   else if (dir.Equals("MusicVideoStudios"))
1499     return "videodb://3/6/";
1500   else if (dir.Equals("MusicVideos"))
1501     return "videodb://3/";
1502   else if (dir.Equals("RecentlyAddedMovies"))
1503     return "videodb://4/";
1504   else if (dir.Equals("RecentlyAddedEpisodes"))
1505     return "videodb://5/";
1506   else if (dir.Equals("RecentlyAddedMusicVideos"))
1507     return "videodb://6/";
1508   else if (dir.Equals("Files"))
1509     return "sources://video/";
1510   return CGUIWindowVideoBase::GetStartFolder(dir);
1511 }