merged: Linuxport revisions through to r15292.
[xbmc:xbmc-antiquated.git] / xbmc / 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 "stdafx.h"
23 #include "GUIWindowVideoNav.h"
24 #include "GUIWindowVideoFiles.h"
25 #include "utils/GUIInfoManager.h"
26 #include "Util.h"
27 #include "utils/RegExp.h"
28 #include "PlayListM3U.h"
29 #include "PlayListPlayer.h"
30 #include "GUIPassword.h"
31 #include "GUILabelControl.h"
32 #include "GUIDialogFileBrowser.h"
33 #include "Picture.h"
34 #include "FileSystem/VideoDatabaseDirectory.h"
35 #include "PlayListFactory.h"
36 #include "GUIFontManager.h"
37 #include "GUIDialogVideoScan.h"
38 #include "GUIDialogOK.h"
39 #include "PartyModeManager.h"
40 #include "MusicDatabase.h"
41 #include "GUIWindowManager.h"
42 #include "GUIDialogYesNo.h"
43 #include "GUIDialogSelect.h"
44 #include "GUIDialogKeyboard.h"
45 #include "GUIEditControl.h"
46 #include "FileSystem/Directory.h"
47 #include "FileSystem/File.h"
48 #include "FileItem.h"
49 #include "Application.h"
50
51 using namespace XFILE;
52 using namespace DIRECTORY;
53 using namespace VIDEODATABASEDIRECTORY;
54
55 #define CONTROL_BTNVIEWASICONS     2
56 #define CONTROL_BTNSORTBY          3
57 #define CONTROL_BTNSORTASC         4
58 #define CONTROL_BTNTYPE            5
59 #define CONTROL_BTNSEARCH          8
60 #define CONTROL_LIST              50
61 #define CONTROL_THUMBS            51
62 #define CONTROL_BIGLIST           52
63 #define CONTROL_LABELFILES        12
64
65 #define CONTROL_BTN_FILTER        19
66 #define CONTROL_BTNSHOWMODE       10
67 #define CONTROL_BTNSHOWALL        14
68 #define CONTROL_UNLOCK            11
69
70 #define CONTROL_FILTER            15
71 #define CONTROL_BTNPARTYMODE      16
72 #define CONTROL_BTNFLATTEN        17
73 #define CONTROL_LABELEMPTY        18
74
75 CGUIWindowVideoNav::CGUIWindowVideoNav(void)
76     : CGUIWindowVideoBase(WINDOW_VIDEO_NAV, "MyVideoNav.xml")
77 {
78   m_vecItems->m_strPath = "?";
79   m_bDisplayEmptyDatabaseMessage = false;
80   m_thumbLoader.SetObserver(this);
81   m_unfilteredItems = new CFileItemList;
82 }
83
84 CGUIWindowVideoNav::~CGUIWindowVideoNav(void)
85 {
86   delete m_unfilteredItems;
87 }
88
89 bool CGUIWindowVideoNav::OnMessage(CGUIMessage& message)
90 {
91   switch (message.GetMessage())
92   {
93   case GUI_MSG_WINDOW_RESET:
94     m_vecItems->m_strPath = "?";
95     break;
96   case GUI_MSG_WINDOW_DEINIT:
97     if (m_thumbLoader.IsLoading())
98       m_thumbLoader.StopThread();
99     break;
100   case GUI_MSG_WINDOW_INIT:
101     {
102 /* We don't want to show Autosourced items (ie removable pendrives, memorycards) in Library mode */
103       m_rootDir.AllowNonLocalSources(false);
104       // check for valid quickpath parameter
105       CStdStringArray params;
106       StringUtils::SplitString(message.GetStringParam(), ",", params);
107       bool returning = params.size() > 1 && params[1] == "return";
108
109       CStdString strDestination = params.size() ? params[0] : "";
110       if (!strDestination.IsEmpty())
111       {
112         message.SetStringParam("");
113         CLog::Log(LOGINFO, "Attempting to %s to: %s", returning ? "return" : "quickpath", strDestination.c_str());
114       }
115
116       // is this the first time the window is opened?
117       if (m_vecItems->m_strPath == "?" && strDestination.IsEmpty())
118       {
119         strDestination = g_settings.m_defaultVideoLibSource;
120         m_vecItems->m_strPath = strDestination;
121         CLog::Log(LOGINFO, "Attempting to default to: %s", strDestination.c_str());
122       }
123
124       CStdString destPath;
125       if (!strDestination.IsEmpty())
126       {
127         if (strDestination.Equals("$ROOT") || strDestination.Equals("Root"))
128           destPath = "";
129         else if (strDestination.Equals("MovieGenres"))
130           destPath = "videodb://1/1/";
131         else if (strDestination.Equals("MovieTitles"))
132           destPath = "videodb://1/2/";
133         else if (strDestination.Equals("MovieYears"))
134           destPath = "videodb://1/3/";
135         else if (strDestination.Equals("MovieActors"))
136           destPath = "videodb://1/4/";
137         else if (strDestination.Equals("MovieDirectors"))
138           destPath = "videodb://1/5/";
139         else if (strDestination.Equals("MovieStudios"))
140           destPath = "videodb://1/6/";
141         else if (strDestination.Equals("Movies"))
142           destPath = "videodb://1/";
143         else if (strDestination.Equals("TvShowGenres"))
144           destPath = "videodb://2/1/";
145         else if (strDestination.Equals("TvShowTitles"))
146           destPath = "videodb://2/2/";
147         else if (strDestination.Equals("TvShowYears"))
148           destPath = "videodb://2/3/";
149         else if (strDestination.Equals("TvShowActors"))
150           destPath = "videodb://2/4/";
151         else if (strDestination.Equals("TvShows"))
152           destPath = "videodb://2/";
153         else if (strDestination.Equals("MusicVideoGenres"))
154           destPath = "videodb://3/1/";
155         else if (strDestination.Equals("MusicVideoTitles"))
156           destPath = "videodb://3/2/";
157         else if (strDestination.Equals("MusicVideoYears"))
158           destPath = "videodb://3/3/";
159         else if (strDestination.Equals("MusicVideoArtists"))
160           destPath = "videodb://3/4/";
161         else if (strDestination.Equals("MusicVideoDirectors"))
162           destPath = "videodb://3/5/";
163         else if (strDestination.Equals("MusicVideoStudios"))
164           destPath = "videodb://3/6/";
165         else if (strDestination.Equals("MusicVideos"))
166           destPath = "videodb://3/";
167         else if (strDestination.Equals("RecentlyAddedMovies"))
168           destPath = "videodb://4/";
169         else if (strDestination.Equals("RecentlyAddedEpisodes"))
170           destPath = "videodb://5/";
171         else if (strDestination.Equals("RecentlyAddedMusicVideos"))
172           destPath = "videodb://6/";
173         else if (strDestination.Equals("Playlists"))
174           destPath = "special://videoplaylists/";
175         else if (strDestination.Equals("Plugins"))
176           destPath = "plugin://video/";
177         else
178         {
179           CLog::Log(LOGWARNING, "Warning, destination parameter (%s) may not be valid", strDestination.c_str());
180           destPath = strDestination;
181         }
182         if (!returning || m_vecItems->m_strPath.Left(destPath.GetLength()) != destPath)
183         { // we're not returning to the same path, so set our directory to the requested path
184           m_vecItems->m_strPath = destPath;
185         }
186         SetHistoryForPath(m_vecItems->m_strPath);
187       }
188
189       DisplayEmptyDatabaseMessage(false); // reset message state
190
191       if (!CGUIWindowVideoBase::OnMessage(message))
192         return false;
193
194       //  base class has opened the database, do our check
195       m_database.Open();
196       DisplayEmptyDatabaseMessage(!m_database.HasContent());
197
198       if (m_bDisplayEmptyDatabaseMessage)
199       {
200         // no library - make sure we focus on a known control, and default to the root.
201         SET_CONTROL_FOCUS(CONTROL_BTNTYPE, 0);
202         m_vecItems->m_strPath = "";
203         SetHistoryForPath("");
204         Update("");
205       }
206
207       m_database.Close();
208       return true;
209     }
210     break;
211
212   case GUI_MSG_CLICKED:
213     {
214       int iControl = message.GetSenderId();
215       if (iControl == CONTROL_BTNPARTYMODE)
216       {
217         if (g_partyModeManager.IsEnabled())
218           g_partyModeManager.Disable();
219         else
220         {
221           if (!g_partyModeManager.Enable(PARTYMODECONTEXT_VIDEO))
222           {
223             SET_CONTROL_SELECTED(GetID(),CONTROL_BTNPARTYMODE,false);
224             return false;
225           }
226
227           // Playlist directory is the root of the playlist window
228           if (m_guiState.get()) m_guiState->SetPlaylistDirectory("playlistvideo://");
229
230           return true;
231         }
232         UpdateButtons();
233       }
234
235       if (iControl == CONTROL_BTNSEARCH)
236       {
237         OnSearch();
238       }
239       else if (iControl == CONTROL_BTN_FILTER)
240       {
241         if (GetControl(iControl)->GetControlType() == CGUIControl::GUICONTROL_EDIT)
242         { // filter updated
243           CGUIMessage selected(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_BTN_FILTER);
244           OnMessage(selected);
245           m_filter = selected.GetLabel();
246           OnFilterItems();
247           return true;
248         }
249         if (m_filter.IsEmpty())
250           CGUIDialogKeyboard::ShowAndGetFilter(m_filter, false);
251         else
252         {
253           m_filter.Empty();
254           OnFilterItems();
255         }
256         return true;
257       }
258       else if (iControl == CONTROL_BTNSHOWMODE)
259       {
260         g_stSettings.m_iMyVideoWatchMode++;
261         if (g_stSettings.m_iMyVideoWatchMode > VIDEO_SHOW_WATCHED)
262           g_stSettings.m_iMyVideoWatchMode = VIDEO_SHOW_ALL;
263         g_settings.Save();
264         // TODO: Can we perhaps filter this directly?  Probably not for some of the more complicated views,
265         //       but for those perhaps we can just display them all, and only filter when we get a list
266         //       of actual videos?
267         Update(m_vecItems->m_strPath);
268         return true;
269       }
270       else if (iControl == CONTROL_BTNFLATTEN)
271       {
272         g_stSettings.m_bMyVideoNavFlatten = !g_stSettings.m_bMyVideoNavFlatten;
273         g_settings.Save();
274         CUtil::DeleteVideoDatabaseDirectoryCache();
275         SetupShares();
276         Update("");
277         return true;
278       }
279       else if (iControl == CONTROL_BTNSHOWALL)
280       {
281         if (g_stSettings.m_iMyVideoWatchMode == VIDEO_SHOW_ALL)
282           g_stSettings.m_iMyVideoWatchMode = VIDEO_SHOW_UNWATCHED;
283         else
284           g_stSettings.m_iMyVideoWatchMode = VIDEO_SHOW_ALL;
285         g_settings.Save();
286         // TODO: Can we perhaps filter this directly?  Probably not for some of the more complicated views,
287         //       but for those perhaps we can just display them all, and only filter when we get a list
288         //       of actual videos?
289         Update(m_vecItems->m_strPath);
290         return true;
291       }
292     }
293     break;
294     // update the display
295     case GUI_MSG_SCAN_FINISHED:
296     case GUI_MSG_REFRESH_THUMBS:
297     {
298       Update(m_vecItems->m_strPath);
299     }
300     break;
301
302   case GUI_MSG_NOTIFY_ALL:
303     {
304       if (message.GetParam1() == GUI_MSG_FILTER_ITEMS && IsActive())
305       {
306         if (message.GetParam2() == 1)  // append
307           m_filter += message.GetStringParam();
308         else if (message.GetParam2() == 2) // delete
309         {
310           if (m_filter.size())
311             m_filter.erase(m_filter.end() - 1);
312         }
313         else
314           m_filter = message.GetStringParam();
315         OnFilterItems();
316       }
317     }
318     break;
319   }
320   return CGUIWindowVideoBase::OnMessage(message);
321 }
322
323 CStdString CGUIWindowVideoNav::GetQuickpathName(const CStdString& strPath) const
324 {
325   if (strPath.Equals("videodb://1/1/"))
326     return "MovieGenres";
327   else if (strPath.Equals("videodb://1/2/"))
328     return "MovieTitles";
329   else if (strPath.Equals("videodb://1/3/"))
330     return "MovieYears";
331   else if (strPath.Equals("videodb://1/4/"))
332     return "MovieActors";
333   else if (strPath.Equals("videodb://1/5/"))
334     return "MovieDirectors";
335   else if (strPath.Equals("videodb://1/"))
336     return "Movies";
337   else if (strPath.Equals("videodb://2/1/"))
338     return "TvShowGenres";
339   else if (strPath.Equals("videodb://2/2/"))
340     return "TvShowTitles";
341   else if (strPath.Equals("videodb://2/3/"))
342     return "TvShowYears";
343   else if (strPath.Equals("videodb://2/4/"))
344     return "TvShowActors";
345   else if (strPath.Equals("videodb://2/"))
346     return "TvShows";
347   else if (strPath.Equals("videodb://3/1/"))
348     return "MusicVideoGenres";
349   else if (strPath.Equals("videodb://3/2/"))
350     return "MusicVideoTitles";
351   else if (strPath.Equals("videodb://3/3/"))
352     return "MusicVideoYears";
353   else if (strPath.Equals("videodb://3/4/"))
354     return "MusicVideoArtists";
355   else if (strPath.Equals("videodb://3/5/"))
356     return "MusicVideoDirectors";
357   else if (strPath.Equals("videodb://3/"))
358     return "MusicVideos";
359   else if (strPath.Equals("videodb://4/"))
360     return "RecentlyAddedMovies";
361   else if (strPath.Equals("videodb://5/"))
362     return "RecentlyAddedEpisodes";
363   else if (strPath.Equals("videodb://6/"))
364     return "RecentlyAddedMusicVideos";
365   else if (strPath.Equals("special://videoplaylists/"))
366     return "Playlists";
367   else
368   {
369     CLog::Log(LOGERROR, "  CGUIWindowVideoNav::GetQuickpathName: Unknown parameter (%s)", strPath.c_str());
370     return strPath;
371   }
372 }
373
374 bool CGUIWindowVideoNav::GetDirectory(const CStdString &strDirectory, CFileItemList &items)
375 {
376   if (m_bDisplayEmptyDatabaseMessage)
377     return true;
378
379   CFileItem directory(strDirectory, true);
380
381   if (m_thumbLoader.IsLoading())
382     m_thumbLoader.StopThread();
383
384   m_rootDir.SetCacheDirectory(false);
385   items.ClearProperties();
386
387   bool bResult = CGUIWindowVideoBase::GetDirectory(strDirectory, items);
388   if (bResult)
389   {
390     if (items.IsVideoDb())
391     {
392       DIRECTORY::CVideoDatabaseDirectory dir;
393       CQueryParams params;
394       dir.GetQueryParams(items.m_strPath,params);
395       VIDEODATABASEDIRECTORY::NODE_TYPE node = dir.GetDirectoryChildType(items.m_strPath);
396
397       items.SetThumbnailImage("");
398       if (node == VIDEODATABASEDIRECTORY::NODE_TYPE_EPISODES ||
399           node == NODE_TYPE_SEASONS                          ||
400           node == NODE_TYPE_RECENTLY_ADDED_EPISODES)
401       {
402         CLog::Log(LOGDEBUG, "WindowVideoNav::GetDirectory");
403         // grab the show thumb
404         CFileItem showItem;
405         m_database.GetFilePathById(params.GetTvShowId(),showItem.m_strPath,VIDEODB_CONTENT_TVSHOWS);
406         showItem.SetVideoThumb();
407         items.SetProperty("tvshowthumb", showItem.GetThumbnailImage());
408         // Grab fanart data
409         CVideoInfoTag details;
410         m_database.GetTvShowInfo(showItem.m_strPath, details, params.GetTvShowId());
411         items.SetProperty("fanart_color1", details.m_fanart.GetColor(0));
412         items.SetProperty("fanart_color2", details.m_fanart.GetColor(1));
413         items.SetProperty("fanart_color3", details.m_fanart.GetColor(2));
414         showItem.CacheFanart();
415         CStdString fanart(showItem.GetCachedFanart());
416         if (CFile::Exists(fanart))
417           items.SetProperty("fanart_image", fanart);
418
419         // save the show description (showplot)
420         items.SetProperty("showplot", details.m_strPlot);
421
422         // set the season thumb
423         CStdString strLabel;
424         if (params.GetSeason() == 0)
425           strLabel = g_localizeStrings.Get(20381);
426         else
427           strLabel.Format(g_localizeStrings.Get(20358), params.GetSeason());
428
429         CFileItem item(strLabel);
430         CUtil::GetParentPath(items.m_strPath,item.m_strPath);
431         item.m_bIsFolder = true;
432         item.SetCachedSeasonThumb();
433         if (item.HasThumbnail())
434           items.SetProperty("seasonthumb",item.GetThumbnailImage());
435
436         // the container folder thumb is the parent (i.e. season or show)
437         if (node == NODE_TYPE_EPISODES || node == NODE_TYPE_RECENTLY_ADDED_EPISODES)
438         {
439           items.SetContent("episodes");
440           // grab the season thumb as the folder thumb
441           CStdString strLabel;
442           CStdString strPath;
443           if (params.GetSeason() == -1 && items.Size() > 0)
444           {
445             CQueryParams params2;
446             dir.GetQueryParams(items[0]->m_strPath,params2);
447             strLabel.Format(g_localizeStrings.Get(20358), params2.GetSeason());
448             CUtil::GetParentPath(items.m_strPath,strPath);
449           }
450           else
451           {
452             if (params.GetSeason() == 0)
453               strLabel = g_localizeStrings.Get(20381);
454             else
455               strLabel.Format(g_localizeStrings.Get(20358), params.GetSeason());
456             strPath = items.m_strPath;
457           }
458
459           CFileItem item(strLabel);
460           item.m_strPath = strPath;
461           item.m_bIsFolder = true;
462           item.GetVideoInfoTag()->m_strPath = showItem.m_strPath;
463           item.SetCachedSeasonThumb();
464
465           items.SetThumbnailImage(item.GetThumbnailImage());
466           items.SetProperty("seasonthumb",item.GetThumbnailImage());
467         }
468         else
469         {
470           items.SetContent("seasons");
471           items.SetThumbnailImage(showItem.GetThumbnailImage());
472         }
473       }
474       else if (node == NODE_TYPE_TITLE_MOVIES || node == NODE_TYPE_RECENTLY_ADDED_MOVIES)
475         items.SetContent("movies");
476       else if (node == NODE_TYPE_TITLE_TVSHOWS)
477         items.SetContent("tvshows");
478       else if (node == NODE_TYPE_TITLE_MUSICVIDEOS ||
479                node == NODE_TYPE_RECENTLY_ADDED_MUSICVIDEOS)
480         items.SetContent("musicvideos");
481       else
482         items.SetContent("");
483     }
484   }
485
486   // clear the filter
487   m_filter.Empty();
488   return bResult;
489 }
490
491 void CGUIWindowVideoNav::UpdateButtons()
492 {
493   CGUIWindowVideoBase::UpdateButtons();
494
495   // Update object count
496   int iItems = m_vecItems->Size();
497   if (iItems)
498   {
499     // check for parent dir and "all" items
500     // should always be the first two items
501     for (int i = 0; i <= (iItems>=2 ? 1 : 0); i++)
502     {
503       CFileItemPtr pItem = m_vecItems->Get(i);
504       if (pItem->IsParentFolder()) iItems--;
505       if (pItem->m_strPath.Left(4).Equals("/-1/")) iItems--;
506     }
507     // or the last item
508     if (m_vecItems->Size() > 2 &&
509       m_vecItems->Get(m_vecItems->Size()-1)->m_strPath.Left(4).Equals("/-1/"))
510       iItems--;
511   }
512   CStdString items;
513   items.Format("%i %s", iItems, g_localizeStrings.Get(127).c_str());
514   SET_CONTROL_LABEL(CONTROL_LABELFILES, items);
515
516   // set the filter label
517   CStdString strLabel;
518
519   // "Playlists"
520   if (m_vecItems->m_strPath.Equals("special://videoplaylists/"))
521     strLabel = g_localizeStrings.Get(136);
522   // "{Playlist Name}"
523   else if (m_vecItems->IsPlayList())
524   {
525     // get playlist name from path
526     CStdString strDummy;
527     CUtil::Split(m_vecItems->m_strPath, strDummy, strLabel);
528   }
529   // everything else is from a videodb:// path
530   else
531   {
532     CVideoDatabaseDirectory dir;
533     dir.GetLabel(m_vecItems->m_strPath, strLabel);
534   }
535
536   SET_CONTROL_LABEL(CONTROL_FILTER, strLabel);
537
538   SET_CONTROL_LABEL(CONTROL_BTNSHOWMODE, g_localizeStrings.Get(16100 + g_stSettings.m_iMyVideoWatchMode));
539
540   SET_CONTROL_SELECTED(GetID(),CONTROL_BTNSHOWALL,g_stSettings.m_iMyVideoWatchMode != VIDEO_SHOW_ALL);
541
542   SET_CONTROL_SELECTED(GetID(),CONTROL_BTN_FILTER, !m_filter.IsEmpty());
543   SET_CONTROL_LABEL2(CONTROL_BTN_FILTER, m_filter);
544
545   SET_CONTROL_SELECTED(GetID(),CONTROL_BTNPARTYMODE, g_partyModeManager.IsEnabled());
546
547   SET_CONTROL_SELECTED(GetID(),CONTROL_BTNFLATTEN, g_stSettings.m_bMyVideoNavFlatten);
548 }
549
550 /// \brief Search for genres, artists and albums with search string \e strSearch in the musicdatabase and return the found \e items
551 /// \param strSearch The search string
552 /// \param items Items Found
553 void CGUIWindowVideoNav::DoSearch(const CStdString& strSearch, CFileItemList& items)
554 {
555   // get matching genres
556   CFileItemList tempItems;
557
558   m_database.GetMovieGenresByName(strSearch, tempItems);
559   if (tempItems.Size())
560   {
561     CStdString strGenre = g_localizeStrings.Get(515); // Genre
562     for (int i = 0; i < (int)tempItems.Size(); i++)
563     {
564       tempItems[i]->SetLabel("[" + strGenre + " - "+g_localizeStrings.Get(20342)+"] " + tempItems[i]->GetLabel());
565     }
566     items.Append(tempItems);
567   }
568
569   tempItems.Clear();
570   m_database.GetTvShowGenresByName(strSearch, tempItems);
571   if (tempItems.Size())
572   {
573     CStdString strGenre = g_localizeStrings.Get(515); // Genre
574     for (int i = 0; i < (int)tempItems.Size(); i++)
575     {
576       tempItems[i]->SetLabel("[" + strGenre + " - "+g_localizeStrings.Get(20343)+"] " + tempItems[i]->GetLabel());
577     }
578     items.Append(tempItems);
579   }
580
581   tempItems.Clear();
582   m_database.GetMusicVideoGenresByName(strSearch, tempItems);
583   if (tempItems.Size())
584   {
585     CStdString strGenre = g_localizeStrings.Get(515); // Genre
586     for (int i = 0; i < (int)tempItems.Size(); i++)
587     {
588       tempItems[i]->SetLabel("[" + strGenre + " - "+g_localizeStrings.Get(20389)+"] " + tempItems[i]->GetLabel());
589     }
590     items.Append(tempItems);
591   }
592
593   tempItems.Clear();
594   m_database.GetMusicVideoGenresByName(strSearch, tempItems);
595   if (tempItems.Size())
596   {
597     CStdString strGenre = g_localizeStrings.Get(515); // Genre
598     for (int i = 0; i < (int)tempItems.Size(); i++)
599     {
600       tempItems[i]->SetLabel("[" + strGenre + " - "+g_localizeStrings.Get(20389)+"] " + tempItems[i]->GetLabel());
601     }
602     items.Append(tempItems);
603   }
604
605   tempItems.Clear();
606   m_database.GetMovieActorsByName(strSearch, tempItems);
607   if (tempItems.Size())
608   {
609     CStdString strActor = g_localizeStrings.Get(20337); // Actor
610     for (int i = 0; i < (int)tempItems.Size(); i++)
611     {
612       tempItems[i]->SetLabel("[" + strActor + " - "+g_localizeStrings.Get(20342)+"] " + tempItems[i]->GetLabel());
613     }
614     items.Append(tempItems);
615   }
616
617   tempItems.Clear();
618   m_database.GetTvShowsActorsByName(strSearch, tempItems);
619   if (tempItems.Size())
620   {
621     CStdString strActor = g_localizeStrings.Get(20337); // Actor
622     for (int i = 0; i < (int)tempItems.Size(); i++)
623     {
624       tempItems[i]->SetLabel("[" + strActor + " - "+g_localizeStrings.Get(20343)+"] " + tempItems[i]->GetLabel());
625     }
626     items.Append(tempItems);
627   }
628
629   tempItems.Clear();
630   m_database.GetMusicVideoArtistsByName(strSearch, tempItems);
631   if (tempItems.Size())
632   {
633     CStdString strActor = g_localizeStrings.Get(557); // Artist
634     for (int i = 0; i < (int)tempItems.Size(); i++)
635     {
636       tempItems[i]->SetLabel("[" + strActor + " - "+g_localizeStrings.Get(20389)+"] " + tempItems[i]->GetLabel());
637     }
638     items.Append(tempItems);
639   }
640
641   tempItems.Clear();
642   m_database.GetMovieDirectorsByName(strSearch, tempItems);
643   if (tempItems.Size())
644   {
645     CStdString strMovie = g_localizeStrings.Get(20339); // Director
646     for (int i = 0; i < (int)tempItems.Size(); i++)
647     {
648       tempItems[i]->SetLabel("[" + strMovie + " - "+g_localizeStrings.Get(20342)+"] " + tempItems[i]->GetLabel());
649     }
650     items.Append(tempItems);
651   }
652
653   tempItems.Clear();
654   m_database.GetTvShowsDirectorsByName(strSearch, tempItems);
655   if (tempItems.Size())
656   {
657     CStdString strMovie = g_localizeStrings.Get(20339); // Director
658     for (int i = 0; i < (int)tempItems.Size(); i++)
659     {
660       tempItems[i]->SetLabel("[" + strMovie + " - "+g_localizeStrings.Get(20343)+"] " + tempItems[i]->GetLabel());
661     }
662     items.Append(tempItems);
663   }
664
665   tempItems.Clear();
666   m_database.GetMusicVideoDirectorsByName(strSearch, tempItems);
667   if (tempItems.Size())
668   {
669     CStdString strMovie = g_localizeStrings.Get(20339); // Director
670     for (int i = 0; i < (int)tempItems.Size(); i++)
671     {
672       tempItems[i]->SetLabel("[" + strMovie + " - "+g_localizeStrings.Get(20389)+"] " + tempItems[i]->GetLabel());
673     }
674     items.Append(tempItems);
675   }
676
677   tempItems.Clear();
678   m_database.GetMoviesByName(strSearch, tempItems);
679
680   if (tempItems.Size())
681   {
682     for (int i = 0; i < (int)tempItems.Size(); i++)
683     {
684       tempItems[i]->SetLabel("[" + g_localizeStrings.Get(20338) + "] " + tempItems[i]->GetLabel());
685     }
686     items.Append(tempItems);
687   }
688
689   tempItems.Clear();
690   m_database.GetEpisodesByName(strSearch, tempItems);
691
692   if (tempItems.Size())
693   {
694     for (int i = 0; i < (int)tempItems.Size(); i++)
695     {
696       tempItems[i]->SetLabel("[" + g_localizeStrings.Get(20359) + "] " + tempItems[i]->GetLabel());
697     }
698     items.Append(tempItems);
699   }
700
701   tempItems.Clear();
702   m_database.GetMusicVideosByName(strSearch, tempItems);
703
704   if (tempItems.Size())
705   {
706     for (int i = 0; i < (int)tempItems.Size(); i++)
707     {
708       tempItems[i]->SetLabel("[" + g_localizeStrings.Get(20391) + "] " + tempItems[i]->GetLabel());
709     }
710     items.Append(tempItems);
711   }
712
713   tempItems.Clear();
714   m_database.GetMusicVideosByAlbum(strSearch, tempItems);
715
716   if (tempItems.Size())
717   {
718     for (int i = 0; i < (int)tempItems.Size(); i++)
719     {
720       tempItems[i]->SetLabel("[" + g_localizeStrings.Get(558) + "] " + tempItems[i]->GetLabel());
721     }
722     items.Append(tempItems);
723   }
724
725   tempItems.Clear();
726   m_database.GetEpisodesByPlot(strSearch, tempItems);
727
728   if (tempItems.Size())
729   {
730     for (int i = 0; i < (int)tempItems.Size(); i++)
731     {
732       tempItems[i]->SetLabel("[" + g_localizeStrings.Get(20365) + "] " + tempItems[i]->GetLabel());
733     }
734     items.Append(tempItems);
735   }
736 }
737
738 void CGUIWindowVideoNav::PlayItem(int iItem)
739 {
740   // unlike additemtoplaylist, we need to check the items here
741   // before calling it since the current playlist will be stopped
742   // and cleared!
743
744   // root is not allowed
745   if (m_vecItems->IsVirtualDirectoryRoot())
746     return;
747
748   CGUIWindowVideoBase::PlayItem(iItem);
749 }
750
751 void CGUIWindowVideoNav::OnWindowLoaded()
752 {
753 #ifdef PRE_SKIN_VERSION_2_1_COMPATIBILITY
754   const CGUIControl *pList = GetControl(CONTROL_LIST);
755   if (pList && !GetControl(CONTROL_LABELEMPTY))
756   {
757     CLabelInfo info;
758     info.align = XBFONT_CENTER_X | XBFONT_CENTER_Y;
759     info.font = g_fontManager.GetFont("font13");
760     info.textColor = 0xffffffff;
761     CGUILabelControl *pLabel = new CGUILabelControl(GetID(),CONTROL_LABELEMPTY,pList->GetXPosition(),pList->GetYPosition(),pList->GetWidth(),pList->GetHeight(),info,false,false);
762     pLabel->SetAnimations(pList->GetAnimations());
763     Add(pLabel);
764   }
765 #endif
766   SendMessage(GUI_MSG_SET_TYPE, CONTROL_BTN_FILTER, CGUIEditControl::INPUT_TYPE_FILTER);
767   CGUIWindowVideoBase::OnWindowLoaded();
768 }
769
770 void CGUIWindowVideoNav::DisplayEmptyDatabaseMessage(bool bDisplay)
771 {
772   m_bDisplayEmptyDatabaseMessage = bDisplay;
773 }
774
775 void CGUIWindowVideoNav::Render()
776 {
777   if (m_bDisplayEmptyDatabaseMessage)
778     SET_CONTROL_LABEL(CONTROL_LABELEMPTY,g_localizeStrings.Get(745)+'\n'+g_localizeStrings.Get(746));
779   else
780     SET_CONTROL_LABEL(CONTROL_LABELEMPTY,"");
781   CGUIWindowVideoBase::Render();
782 }
783
784 void CGUIWindowVideoNav::OnInfo(CFileItem* pItem, const SScraperInfo& info)
785 {
786   SScraperInfo info2(info);
787   CStdString strPath,strFile;
788   m_database.Open(); // since we can be called from the music library without being inited
789   if (pItem->IsVideoDb())
790     m_database.GetScraperForPath(pItem->GetVideoInfoTag()->m_strPath,info2);
791   else if (m_vecItems->IsPluginFolder())
792     info2.strContent = "plugin";
793   else
794   {
795     CUtil::Split(pItem->m_strPath,strPath,strFile);
796     m_database.GetScraperForPath(strPath,info2);
797   }
798   m_database.Close();
799   CGUIWindowVideoBase::OnInfo(pItem,info2);
800 }
801
802 void CGUIWindowVideoNav::OnDeleteItem(int iItem)
803 {
804   if (iItem < 0 || iItem >= (int)m_vecItems->Size()) return;
805
806   if (m_vecItems->m_strPath.Equals("special://videoplaylists/"))
807   {
808     CGUIWindowVideoBase::OnDeleteItem(iItem);
809     return;
810   }
811
812   CFileItemPtr pItem = m_vecItems->Get(iItem);
813   if (!DeleteItem(pItem.get()))
814     return;
815
816   CStdString strDeletePath;
817   if (pItem->m_bIsFolder)
818     strDeletePath=pItem->GetVideoInfoTag()->m_strPath;
819   else
820     strDeletePath=pItem->GetVideoInfoTag()->m_strFileNameAndPath;
821
822   if (g_guiSettings.GetBool("filelists.allowfiledeletion") &&
823       CUtil::SupportsFileOperations(strDeletePath))
824   {
825     pItem->m_strPath = strDeletePath;
826     CGUIWindowVideoBase::OnDeleteItem(iItem);
827   }
828
829   CUtil::DeleteVideoDatabaseDirectoryCache();
830
831   DisplayEmptyDatabaseMessage(!m_database.HasContent());
832   Update( m_vecItems->m_strPath );
833   m_viewControl.SetSelectedItem(iItem);
834 }
835
836 bool CGUIWindowVideoNav::DeleteItem(CFileItem* pItem)
837 {
838   // dont allow update while scanning
839   CGUIDialogVideoScan* pDialogScan = (CGUIDialogVideoScan*)m_gWindowManager.GetWindow(WINDOW_DIALOG_VIDEO_SCAN);
840   if (pDialogScan && pDialogScan->IsScanning())
841   {
842     CGUIDialogOK::ShowAndGetInput(257, 0, 14057, 0);
843     return false;
844   }
845
846   VIDEODB_CONTENT_TYPE iType=VIDEODB_CONTENT_MOVIES;
847   if (pItem->HasVideoInfoTag() && !pItem->GetVideoInfoTag()->m_strShowTitle.IsEmpty())
848     iType = VIDEODB_CONTENT_TVSHOWS;
849   if (pItem->HasVideoInfoTag() && pItem->GetVideoInfoTag()->m_iSeason > -1 && !pItem->m_bIsFolder)
850     iType = VIDEODB_CONTENT_EPISODES;
851   if (pItem->HasVideoInfoTag() && !pItem->GetVideoInfoTag()->m_strArtist.IsEmpty())
852     iType = VIDEODB_CONTENT_MUSICVIDEOS;
853
854   CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*)m_gWindowManager.GetWindow(WINDOW_DIALOG_YES_NO);
855   if (!pDialog)
856     return false;
857   if (iType == VIDEODB_CONTENT_MOVIES)
858     pDialog->SetHeading(432);
859   if (iType == VIDEODB_CONTENT_EPISODES)
860     pDialog->SetHeading(20362);
861   if (iType == VIDEODB_CONTENT_TVSHOWS)
862     pDialog->SetHeading(20363);
863   if (iType == VIDEODB_CONTENT_MUSICVIDEOS)
864     pDialog->SetHeading(20392);
865   CStdString strLine;
866   strLine.Format(g_localizeStrings.Get(433),pItem->GetLabel());
867   pDialog->SetLine(0, strLine);
868   pDialog->SetLine(1, "");
869   pDialog->SetLine(2, "");;
870   pDialog->DoModal();
871   if (!pDialog->IsConfirmed())
872     return false;
873
874   CStdString path;
875   CVideoDatabase database;
876   database.Open();
877
878   database.GetFilePathById(pItem->GetVideoInfoTag()->m_iDbId, path, iType);
879   if (path.IsEmpty()) 
880     return false;
881   if (iType == VIDEODB_CONTENT_MOVIES)
882     database.DeleteMovie(path);
883   if (iType == VIDEODB_CONTENT_EPISODES)
884     database.DeleteEpisode(path);
885   if (iType == VIDEODB_CONTENT_TVSHOWS)
886     database.DeleteTvShow(path);
887   if (iType == VIDEODB_CONTENT_MUSICVIDEOS)
888     database.DeleteMusicVideo(path);
889
890   if (iType == VIDEODB_CONTENT_TVSHOWS)
891     database.SetPathHash(path,"");
892   else
893   {
894     CStdString strDirectory;
895     CUtil::GetDirectory(path,strDirectory);
896     database.SetPathHash(strDirectory,"");
897   }
898
899   // delete the cached thumb for this item (it will regenerate if it is a user thumb)
900   CStdString thumb(pItem->GetCachedVideoThumb());
901   CFile::Delete(thumb);
902
903   return true;
904 }
905
906 void CGUIWindowVideoNav::OnFinalizeFileItems(CFileItemList& items)
907 {
908   m_unfilteredItems->Append(items);
909   // now filter as necessary
910   CVideoDatabaseDirectory dir;
911   CQueryParams params;
912   dir.GetQueryParams(items.m_strPath,params);
913   bool filterWatched=false;
914   if ((params.GetContentType() == VIDEODB_CONTENT_TVSHOWS &&
915        dir.GetDirectoryChildType(items.m_strPath) == NODE_TYPE_EPISODES) ||
916        dir.GetDirectoryChildType(items.m_strPath) == NODE_TYPE_RECENTLY_ADDED_EPISODES)
917     filterWatched = true;
918   if (items.IsPluginFolder())
919     filterWatched = true;
920   if (g_stSettings.m_iMyVideoWatchMode == VIDEO_SHOW_ALL)
921     filterWatched = false;
922   if (params.GetContentType() == VIDEODB_CONTENT_MOVIES                             ||
923       params.GetContentType() == VIDEODB_CONTENT_MUSICVIDEOS                        ||
924       dir.GetDirectoryChildType(items.m_strPath) == NODE_TYPE_RECENTLY_ADDED_MOVIES ||
925       dir.GetDirectoryChildType(items.m_strPath) == NODE_TYPE_RECENTLY_ADDED_MUSICVIDEOS)
926   { // need to filter no matter to get rid of duplicates - price to pay for not filtering in db
927     filterWatched = true;
928   }
929
930   if (filterWatched || !m_filter.IsEmpty())
931     FilterItems(items);
932 }
933
934 void CGUIWindowVideoNav::ClearFileItems()
935 {
936   m_viewControl.Clear();
937   m_vecItems->Clear();
938   m_unfilteredItems->Clear();
939 }
940
941 void CGUIWindowVideoNav::OnFilterItems()
942 {
943   CStdString currentItem;
944   int item = m_viewControl.GetSelectedItem();
945   if (item >= 0)
946     currentItem = m_vecItems->Get(item)->m_strPath;
947
948   m_viewControl.Clear();
949
950   FilterItems(*m_vecItems);
951
952   // and update our view control + buttons
953   m_viewControl.SetItems(*m_vecItems);
954   m_viewControl.SetSelectedItem(currentItem);
955   UpdateButtons();
956 }
957
958 void CGUIWindowVideoNav::FilterItems(CFileItemList &items)
959 {
960   CVideoDatabaseDirectory dir;
961   CQueryParams params;
962   dir.GetQueryParams(items.m_strPath,params);
963   bool filterWatched=false;
964   if ((params.GetContentType() == VIDEODB_CONTENT_TVSHOWS &&
965        dir.GetDirectoryChildType(items.m_strPath) == NODE_TYPE_EPISODES) ||
966        dir.GetDirectoryChildType(items.m_strPath) == NODE_TYPE_RECENTLY_ADDED_EPISODES)
967   {
968     filterWatched = true;
969   }
970   if (params.GetContentType() == VIDEODB_CONTENT_MOVIES                             ||
971       params.GetContentType() == VIDEODB_CONTENT_MUSICVIDEOS                        ||
972       dir.GetDirectoryChildType(items.m_strPath) == NODE_TYPE_RECENTLY_ADDED_MOVIES ||
973       dir.GetDirectoryChildType(items.m_strPath) == NODE_TYPE_RECENTLY_ADDED_MUSICVIDEOS)
974     filterWatched = true;
975   if (items.IsPluginFolder())
976     filterWatched = true;
977   if (g_stSettings.m_iMyVideoWatchMode == VIDEO_SHOW_ALL)
978     filterWatched = false;
979
980   NODE_TYPE node = dir.GetDirectoryChildType(items.m_strPath);
981   // todo: why aren't we filtering every view consistently?
982   if (m_vecItems->IsVirtualDirectoryRoot() ||
983       node == NODE_TYPE_MOVIES_OVERVIEW    ||
984       node == NODE_TYPE_TVSHOWS_OVERVIEW   ||
985       node == NODE_TYPE_MUSICVIDEOS_OVERVIEW)
986   {
987     return;
988   }
989  
990   CStdString filter = m_filter;
991   filter.TrimLeft().ToLower();
992   bool numericMatch = StringUtils::IsNaturalNumber(filter);
993
994   items.ClearItems(); // clear the items only - we want to keep content etc.
995   items.SetFastLookup(true);
996   for (int i = 0; i < m_unfilteredItems->Size(); i++)
997   {
998     CFileItemPtr item = m_unfilteredItems->Get(i);
999     if (item->m_bIsFolder || item->IsParentFolder()         ||
1000         CVideoDatabaseDirectory::IsAllItem(item->m_strPath) ||
1001       (filter.IsEmpty() && (!filterWatched               ||
1002       (item->GetVideoInfoTag()->m_playCount>0) == (g_stSettings.m_iMyVideoWatchMode==2))))
1003     {
1004       if ((params.GetContentType() != VIDEODB_CONTENT_MOVIES  && params.GetContentType() != VIDEODB_CONTENT_MUSICVIDEOS) || !items.Contains(item->m_strPath))
1005         items.Add(item);
1006       continue;
1007     }
1008     // TODO: Need to update this to get all labels, ideally out of the displayed info (ie from m_layout and m_focusedLayout)
1009     // though that isn't practical.  Perhaps a better idea would be to just grab the info that we should filter on based on
1010     // where we are in the library tree.
1011     // Another idea is tying the filter string to the current level of the tree, so that going deeper disables the filter,
1012     // but it's re-enabled on the way back out.
1013     CStdString match;
1014 /*    if (item->GetFocusedLayout())
1015       match = item->GetFocusedLayout()->GetAllText();
1016     else if (item->GetLayout())
1017       match = item->GetLayout()->GetAllText();
1018     else*/
1019     match = item->GetLabel(); // Filter label only for now
1020
1021     if (numericMatch)
1022       StringUtils::WordToDigits(match);
1023
1024     size_t pos = StringUtils::FindWords(match.c_str(), filter.c_str());
1025     if (pos != CStdString::npos &&
1026        (!filterWatched || (item->GetVideoInfoTag()->m_playCount>0) == (g_stSettings.m_iMyVideoWatchMode==2)))
1027     {
1028       if ((params.GetContentType() != VIDEODB_CONTENT_MOVIES && params.GetContentType() != VIDEODB_CONTENT_MUSICVIDEOS) || !items.Contains(item->m_strPath))
1029         items.Add(item); 
1030     }
1031   }
1032   items.SetFastLookup(false);
1033 }
1034
1035 void CGUIWindowVideoNav::GetContextButtons(int itemNumber, CContextButtons &buttons)
1036 {
1037   CFileItemPtr item;
1038   if (itemNumber >= 0 && itemNumber < m_vecItems->Size())
1039     item = m_vecItems->Get(itemNumber);
1040
1041   CGUIWindowVideoBase::GetContextButtons(itemNumber, buttons);
1042
1043   CVideoDatabaseDirectory dir;
1044   NODE_TYPE node = dir.GetDirectoryChildType(m_vecItems->m_strPath);
1045
1046   if (!item)
1047   {
1048     CGUIDialogVideoScan *pScanDlg = (CGUIDialogVideoScan *)m_gWindowManager.GetWindow(WINDOW_DIALOG_VIDEO_SCAN);
1049     if (pScanDlg && pScanDlg->IsScanning())
1050       buttons.Add(CONTEXT_BUTTON_STOP_SCANNING, 13353);
1051     else
1052       buttons.Add(CONTEXT_BUTTON_UPDATE_LIBRARY, 653);
1053   }
1054   else
1055   {
1056     SScraperInfo info;
1057     VIDEO::SScanSettings settings;
1058     GetScraperForItem(item.get(), info, settings);
1059
1060     if (info.strContent.Equals("tvshows"))
1061       buttons.Add(CONTEXT_BUTTON_INFO, item->m_bIsFolder ? 20351 : 20352);
1062     else if (info.strContent.Equals("musicvideos"))
1063       buttons.Add(CONTEXT_BUTTON_INFO,20393);
1064     else if (!item->m_bIsFolder && !item->m_strPath.Left(19).Equals("newsmartplaylist://"))
1065       buttons.Add(CONTEXT_BUTTON_INFO, 13346);
1066
1067     if (item->HasVideoInfoTag() && !item->GetVideoInfoTag()->m_strArtist.IsEmpty())
1068     {
1069       CMusicDatabase database;
1070       database.Open();
1071       if (database.GetArtistByName(item->GetVideoInfoTag()->m_strArtist) > -1)
1072         buttons.Add(CONTEXT_BUTTON_GO_TO_ARTIST, 20396);
1073     }
1074     if (item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_strAlbum.size() > 0)
1075     {
1076       CMusicDatabase database;
1077       database.Open();
1078       if (database.GetAlbumByName(item->GetVideoInfoTag()->m_strAlbum) > -1)
1079         buttons.Add(CONTEXT_BUTTON_GO_TO_ALBUM, 20397);
1080     }
1081     if (item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_strAlbum.size() > 0 &&
1082         item->GetVideoInfoTag()->m_strArtist.size() > 0                           && 
1083         item->GetVideoInfoTag()->m_strTitle.size() > 0)
1084     {
1085       CMusicDatabase database;
1086       database.Open();
1087       if (database.GetSongByArtistAndAlbumAndTitle(item->GetVideoInfoTag()->m_strArtist,
1088                                                    item->GetVideoInfoTag()->m_strAlbum,
1089                                                    item->GetVideoInfoTag()->m_strTitle) > -1)
1090       {
1091         buttons.Add(CONTEXT_BUTTON_PLAY_OTHER, 20398);
1092       }
1093     }
1094     if (!item->IsParentFolder())
1095     {
1096       // can we update the database?
1097       if (g_settings.m_vecProfiles[g_settings.m_iLastLoadedProfileIndex].canWriteDatabases() || g_passwordManager.bMasterUser)
1098       {
1099         if (node == NODE_TYPE_TITLE_TVSHOWS)
1100         {
1101           CGUIDialogVideoScan *pScanDlg = (CGUIDialogVideoScan *)m_gWindowManager.GetWindow(WINDOW_DIALOG_VIDEO_SCAN);
1102           if (pScanDlg && pScanDlg->IsScanning())
1103             buttons.Add(CONTEXT_BUTTON_STOP_SCANNING, 13353);
1104           else
1105             buttons.Add(CONTEXT_BUTTON_UPDATE_TVSHOW, 13349);
1106         }
1107         if ((info.strContent.Equals("tvshows") && item->m_bIsFolder) || 
1108             (item->IsVideoDb() && item->HasVideoInfoTag() && !item->m_bIsFolder))
1109         {
1110           if (item->m_bIsFolder || item->GetVideoInfoTag()->m_playCount > 0)
1111             buttons.Add(CONTEXT_BUTTON_MARK_UNWATCHED, 16104); //Mark as UnWatched
1112           if (item->m_bIsFolder || item->GetVideoInfoTag()->m_playCount == 0)
1113             buttons.Add(CONTEXT_BUTTON_MARK_WATCHED, 16103);   //Mark as Watched
1114           if (node != NODE_TYPE_SEASONS)
1115             buttons.Add(CONTEXT_BUTTON_EDIT, 16105); //Edit Title
1116         }
1117         if (m_database.HasContent(VIDEODB_CONTENT_TVSHOWS) && item->HasVideoInfoTag() && 
1118            !item->m_bIsFolder && item->GetVideoInfoTag()->m_iEpisode == -1 && 
1119             item->GetVideoInfoTag()->m_strArtist.IsEmpty()) // movie entry
1120         {
1121           if (m_database.IsLinkedToTvshow(item->GetVideoInfoTag()->m_iDbId))
1122             buttons.Add(CONTEXT_BUTTON_UNLINK_MOVIE,20385);
1123           buttons.Add(CONTEXT_BUTTON_LINK_MOVIE,20384);
1124         }
1125
1126         if (node == NODE_TYPE_SEASONS && !dir.IsAllItem(item->m_strPath) && item->m_bIsFolder)
1127           buttons.Add(CONTEXT_BUTTON_SET_SEASON_THUMB, 20371);
1128
1129         if (m_vecItems->m_strPath.Equals("plugin://video/"))
1130           buttons.Add(CONTEXT_BUTTON_SET_PLUGIN_THUMB, 1044);
1131
1132         if (node == NODE_TYPE_ACTOR && !dir.IsAllItem(item->m_strPath) && item->m_bIsFolder)
1133         {
1134           if (m_vecItems->m_strPath.Left(11).Equals("videodb://3")) // mvids
1135             buttons.Add(CONTEXT_BUTTON_SET_ARTIST_THUMB, 13359);
1136           else
1137             buttons.Add(CONTEXT_BUTTON_SET_ACTOR_THUMB, 20403);
1138         }
1139         if (item->IsVideoDb() && item->HasVideoInfoTag() &&
1140           (!item->m_bIsFolder || node == NODE_TYPE_TITLE_TVSHOWS))
1141         {
1142           if (info.strContent.Equals("tvshows"))
1143           {
1144             if(item->GetVideoInfoTag()->m_iBookmarkId != -1 &&
1145                item->GetVideoInfoTag()->m_iBookmarkId != 0)
1146             {
1147               buttons.Add(CONTEXT_BUTTON_UNLINK_BOOKMARK, 20405);
1148             }
1149           }
1150           buttons.Add(CONTEXT_BUTTON_DELETE, 646);
1151         }
1152
1153         // this should ideally be non-contextual (though we need some context for non-tv show node I guess)
1154         CGUIDialogVideoScan *pScanDlg = (CGUIDialogVideoScan *)m_gWindowManager.GetWindow(WINDOW_DIALOG_VIDEO_SCAN);
1155         if (pScanDlg && pScanDlg->IsScanning())
1156         {
1157           if (node != NODE_TYPE_TITLE_TVSHOWS)
1158             buttons.Add(CONTEXT_BUTTON_STOP_SCANNING, 13353);
1159         }
1160         else
1161           buttons.Add(CONTEXT_BUTTON_UPDATE_LIBRARY, 653);
1162       }
1163
1164       //Set default and/or clear default
1165       CVideoDatabaseDirectory dir;
1166       NODE_TYPE nodetype = dir.GetDirectoryType(item->m_strPath);
1167       if (!item->IsParentFolder() && !m_vecItems->m_strPath.Equals("special://videoplaylists/") &&
1168         (nodetype == NODE_TYPE_ROOT             ||
1169          nodetype == NODE_TYPE_OVERVIEW         ||
1170          nodetype == NODE_TYPE_TVSHOWS_OVERVIEW ||
1171          nodetype == NODE_TYPE_MOVIES_OVERVIEW  ||
1172          nodetype == NODE_TYPE_MUSICVIDEOS_OVERVIEW))
1173       {
1174         if (!item->m_strPath.Equals(g_settings.m_defaultVideoLibSource))
1175           buttons.Add(CONTEXT_BUTTON_SET_DEFAULT, 13335); // set default
1176         if (strcmp(g_settings.m_defaultVideoLibSource, ""))
1177           buttons.Add(CONTEXT_BUTTON_CLEAR_DEFAULT, 13403); // clear default
1178       }
1179
1180       if (m_vecItems->m_strPath.Equals("special://videoplaylists/"))
1181       { // video playlists, file operations are allowed
1182         if (!item->IsReadOnly())
1183         {
1184           buttons.Add(CONTEXT_BUTTON_DELETE, 117);
1185           buttons.Add(CONTEXT_BUTTON_RENAME, 118);
1186         }
1187       }
1188     }
1189   }
1190   CGUIWindowVideoBase::GetNonContextButtons(itemNumber, buttons);
1191 }
1192
1193 bool CGUIWindowVideoNav::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
1194 {
1195   CFileItemPtr item;
1196   if (itemNumber >= 0 && itemNumber < m_vecItems->Size())
1197     item = m_vecItems->Get(itemNumber);
1198   switch (button)
1199   {
1200   case CONTEXT_BUTTON_SET_DEFAULT:
1201     g_settings.m_defaultVideoLibSource = GetQuickpathName(item->m_strPath);
1202     g_settings.Save();
1203     return true;
1204
1205   case CONTEXT_BUTTON_CLEAR_DEFAULT:
1206     g_settings.m_defaultVideoLibSource.Empty();
1207     g_settings.Save();
1208     return true;
1209
1210   case CONTEXT_BUTTON_MARK_WATCHED:
1211     MarkWatched(item);
1212     CUtil::DeleteVideoDatabaseDirectoryCache();
1213     Update(m_vecItems->m_strPath);
1214     return true;
1215
1216   case CONTEXT_BUTTON_MARK_UNWATCHED:
1217     {
1218       MarkUnWatched(item);
1219       CUtil::DeleteVideoDatabaseDirectoryCache();
1220       Update(m_vecItems->m_strPath);
1221     }
1222     return true;
1223
1224   case CONTEXT_BUTTON_EDIT:
1225     UpdateVideoTitle(item.get());
1226     CUtil::DeleteVideoDatabaseDirectoryCache();
1227     Update(m_vecItems->m_strPath);
1228     return true;
1229
1230   case CONTEXT_BUTTON_SET_SEASON_THUMB:
1231   case CONTEXT_BUTTON_SET_ACTOR_THUMB:
1232   case CONTEXT_BUTTON_SET_ARTIST_THUMB:
1233   case CONTEXT_BUTTON_SET_PLUGIN_THUMB:
1234     {
1235       // Grab the thumbnails from the web
1236       CStdString strPath;
1237       CFileItemList items;
1238       CUtil::AddFileToFolder(g_advancedSettings.m_cachePath,"imdbthumbs",strPath);
1239       CUtil::WipeDir(strPath);
1240       DIRECTORY::CDirectory::Create(strPath);
1241       CFileItemPtr noneitem(new CFileItem("thumb://None", false));
1242       int i=1;
1243       CVideoInfoTag tag;
1244       if (button != CONTEXT_BUTTON_SET_ARTIST_THUMB &&
1245           button != CONTEXT_BUTTON_SET_PLUGIN_THUMB)
1246       {
1247         if (button == CONTEXT_BUTTON_SET_SEASON_THUMB)
1248           m_database.GetTvShowInfo("",tag,m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_iDbId);
1249         else
1250           tag = *m_vecItems->Get(itemNumber)->GetVideoInfoTag();
1251         for (std::vector<CScraperUrl::SUrlEntry>::iterator iter=tag.m_strPictureURL.m_url.begin();iter != tag.m_strPictureURL.m_url.end();++iter)
1252         {
1253           if ((iter->m_type != CScraperUrl::URL_TYPE_SEASON ||
1254                iter->m_season != m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_iSeason) &&
1255                button == CONTEXT_BUTTON_SET_SEASON_THUMB)
1256           {
1257             continue;
1258           }
1259           CStdString thumbFromWeb;
1260           CStdString strLabel;
1261           strLabel.Format("imdbthumb%i.jpg",i);
1262           CUtil::AddFileToFolder(strPath, strLabel, thumbFromWeb);
1263           if (CScraperUrl::DownloadThumbnail(thumbFromWeb,*iter))
1264           {
1265             CStdString strItemPath;
1266             strItemPath.Format("thumb://IMDb%i",i++);
1267             CFileItemPtr item(new CFileItem(strItemPath, false));
1268             item->SetThumbnailImage(thumbFromWeb);
1269             CStdString strLabel;
1270             item->SetLabel(g_localizeStrings.Get(20015));
1271             items.Add(item);
1272           }
1273         }
1274       }
1275       CStdString cachedThumb = m_vecItems->Get(itemNumber)->GetCachedSeasonThumb();
1276       if (button == CONTEXT_BUTTON_SET_ACTOR_THUMB)
1277         cachedThumb = m_vecItems->Get(itemNumber)->GetCachedActorThumb();
1278       if (button == CONTEXT_BUTTON_SET_ARTIST_THUMB)
1279         cachedThumb = m_vecItems->Get(itemNumber)->GetCachedArtistThumb();
1280       if (button == CONTEXT_BUTTON_SET_SEASON_THUMB)
1281       {
1282         CFileItemList tbnItems;
1283         CDirectory::GetDirectory(tag.m_strPath,tbnItems,".tbn");
1284         CStdString strExpression;
1285         strExpression.Format("season[ ._-](0?%i)\\.tbn",m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_iSeason);
1286         CRegExp reg;
1287         if (reg.RegComp(strExpression.c_str()))
1288         {
1289           for (int j=0;j<tbnItems.Size();++j)
1290           {
1291             CStdString strCheck = CUtil::GetFileName(tbnItems[j]->m_strPath);
1292             strCheck.ToLower();
1293             if (reg.RegFind(strCheck.c_str()) > -1)
1294             {
1295               CFileItemPtr item(new CFileItem("thumb://Local", false));
1296               item->SetThumbnailImage(cachedThumb); // this doesn't look right to me - perhaps tbnItems[j]->m_strPath?
1297               item->SetLabel(g_localizeStrings.Get(20017));
1298               items.Add(item);
1299               break;
1300             }
1301             else
1302             {
1303               noneitem->SetThumbnailImage("DefaultFolderBig.png");
1304               noneitem->SetLabel(g_localizeStrings.Get(20018));
1305             }
1306           }
1307         }
1308       }
1309       if (button == CONTEXT_BUTTON_SET_PLUGIN_THUMB)
1310       {
1311         strPath = m_vecItems->Get(itemNumber)->m_strPath;
1312         strPath.Replace("plugin://video/","Q:\\plugins\\video\\");
1313         strPath.Replace("/","\\");
1314         CFileItem item(strPath,true);
1315         cachedThumb = item.GetCachedProgramThumb();
1316       }
1317       if (CFile::Exists(cachedThumb))
1318       {
1319         CFileItemPtr item(new CFileItem("thumb://Current", false));
1320         item->SetThumbnailImage(cachedThumb);
1321         item->SetLabel(g_localizeStrings.Get(20016));
1322         items.Add(item);
1323       }
1324       else
1325       {
1326         noneitem->SetThumbnailImage("DefaultFolderBig.png");
1327         noneitem->SetLabel(g_localizeStrings.Get(20018));
1328       }
1329
1330       if (button == CONTEXT_BUTTON_SET_PLUGIN_THUMB)
1331       {
1332         if (items.Size() == 0)
1333         {
1334           CFileItem item2(strPath,false);
1335           CUtil::AddFileToFolder(strPath,"default.py",item2.m_strPath);
1336           if (CFile::Exists(item2.GetCachedProgramThumb()))
1337           {
1338             CFileItemPtr item(new CFileItem("thumb://Current", false));
1339             item->SetThumbnailImage(item2.GetCachedProgramThumb());
1340             item->SetLabel(g_localizeStrings.Get(20016));
1341             items.Add(item);
1342           }
1343           else
1344           {
1345             noneitem->SetThumbnailImage("DefaultFolderBig.png");
1346             noneitem->SetLabel(g_localizeStrings.Get(20018));
1347           }
1348         }
1349         CStdString strThumb;
1350         CUtil::AddFileToFolder(strPath,"folder.jpg",strThumb);
1351         if (CFile::Exists(strThumb))
1352         {
1353           CFileItemPtr item(new CFileItem(strThumb,false));
1354           item->SetThumbnailImage(strThumb);
1355           item->SetLabel(g_localizeStrings.Get(20017));
1356           items.Add(item);
1357         }
1358         else
1359         {
1360           noneitem->SetThumbnailImage("DefaultFolderBig.png");
1361           noneitem->SetLabel(g_localizeStrings.Get(20018));
1362         }
1363         CUtil::AddFileToFolder(strPath,"default.tbn",strThumb);
1364         if (CFile::Exists(strThumb))
1365         {
1366           CFileItemPtr item(new CFileItem(strThumb,false));
1367           item->SetThumbnailImage(strThumb);
1368           item->SetLabel(g_localizeStrings.Get(20017));
1369           items.Add(item);
1370         }
1371         else
1372         {
1373           noneitem->SetThumbnailImage("DefaultFolderBig.png");
1374           noneitem->SetLabel(g_localizeStrings.Get(20018));
1375         }
1376       }
1377       if (button == CONTEXT_BUTTON_SET_ARTIST_THUMB)
1378       {
1379         CStdString picturePath;
1380
1381         CStdString strPath = m_vecItems->Get(itemNumber)->m_strPath;
1382         CUtil::RemoveSlashAtEnd(strPath);
1383
1384         int nPos=strPath.ReverseFind("/");
1385         if (nPos>-1)
1386         {
1387           //  try to guess where the user should start
1388           //  browsing for the artist thumb
1389           CMusicDatabase database;
1390           database.Open();
1391           CFileItemList albums;
1392           long idArtist=database.GetArtistByName(m_vecItems->Get(itemNumber)->GetLabel());
1393           CStdString path;
1394           database.GetArtistPath(idArtist, picturePath);
1395         }
1396
1397         CStdString strThumb;
1398         CUtil::AddFileToFolder(picturePath,"folder.jpg",strThumb);
1399         if (XFILE::CFile::Exists(strThumb))
1400         {
1401           CFileItemPtr pItem(new CFileItem(strThumb,false));
1402           pItem->SetLabel(g_localizeStrings.Get(20017));
1403           pItem->SetThumbnailImage(strThumb);
1404           items.Add(pItem);
1405         }
1406         else
1407         {
1408           noneitem->SetThumbnailImage("DefaultArtistBig.png");
1409           noneitem->SetLabel(g_localizeStrings.Get(20018));
1410         }
1411       }
1412
1413       if (button == CONTEXT_BUTTON_SET_ACTOR_THUMB)
1414       {
1415         CStdString picturePath;
1416         CStdString strThumb;
1417         CUtil::AddFileToFolder(picturePath,"folder.jpg",strThumb);
1418         if (XFILE::CFile::Exists(strThumb))
1419         {
1420           CFileItemPtr pItem(new CFileItem(strThumb,false));
1421           pItem->SetLabel(g_localizeStrings.Get(20017));
1422           pItem->SetThumbnailImage(strThumb);
1423           items.Add(pItem);
1424         }
1425         else
1426         {
1427           noneitem->SetThumbnailImage("DefaultActorBig.png");
1428           noneitem->SetLabel(g_localizeStrings.Get(20018));
1429         }
1430       }
1431
1432       items.Add(noneitem);
1433
1434       CStdString result;
1435       if (!CGUIDialogFileBrowser::ShowAndGetImage(items, g_settings.m_videoSources,
1436                                                   g_localizeStrings.Get(20019), result))
1437       {
1438         return false;   // user cancelled
1439       }
1440
1441       if (result == "thumb://Current")
1442         return false;   // user chose the one they have
1443
1444       // delete the thumbnail if that's what the user wants, else overwrite with the
1445       // new thumbnail
1446       if (result.Mid(0,12) == "thumb://IMDb")
1447       {
1448         CStdString strFile;
1449         CUtil::AddFileToFolder(strPath,"imdbthumb"+result.Mid(12)+".jpg",strFile);
1450         if (CFile::Exists(strFile))
1451           CFile::Cache(strFile, cachedThumb);
1452         else
1453           result = "thumb://None";
1454       }
1455       if (result == "thumb://None")
1456       {
1457         CFile::Delete(cachedThumb);
1458         if (button == CONTEXT_BUTTON_SET_PLUGIN_THUMB)
1459         {
1460           CPicture picture;
1461           picture.CacheSkinImage("DefaultFolderBig.png",cachedThumb);
1462           CFileItem item2(strPath,false);
1463           CUtil::AddFileToFolder(strPath,"default.py",item2.m_strPath);
1464           CFile::Delete(item2.GetCachedProgramThumb());
1465         }
1466       }
1467       else
1468         CFile::Cache(result,cachedThumb);
1469
1470       CUtil::DeleteVideoDatabaseDirectoryCache();
1471       CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_REFRESH_THUMBS);
1472       g_graphicsContext.SendMessage(msg);
1473       Update(m_vecItems->m_strPath);
1474
1475       return true;
1476     }
1477   case CONTEXT_BUTTON_UPDATE_LIBRARY:
1478     {
1479       SScraperInfo info;
1480       VIDEO::SScanSettings settings;
1481       OnScan("",info,settings);
1482       return true;
1483     }
1484   case CONTEXT_BUTTON_UNLINK_MOVIE:
1485     {
1486       OnLinkMovieToTvShow(itemNumber, true);
1487       Update(m_vecItems->m_strPath);
1488       return true;
1489     }
1490   case CONTEXT_BUTTON_LINK_MOVIE:
1491     {
1492       OnLinkMovieToTvShow(itemNumber, false);
1493       return true;
1494     }
1495   case CONTEXT_BUTTON_GO_TO_ARTIST:
1496     {
1497       CStdString strPath;
1498       CMusicDatabase database;
1499       database.Open();
1500       strPath.Format("musicdb://2/%ld/",database.GetArtistByName(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strArtist));
1501       m_gWindowManager.ActivateWindow(WINDOW_MUSIC_NAV,strPath);
1502       return true;
1503     }
1504   case CONTEXT_BUTTON_GO_TO_ALBUM:
1505     {
1506       CStdString strPath;
1507       CMusicDatabase database;
1508       database.Open();
1509       strPath.Format("musicdb://3/%ld/",database.GetAlbumByName(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strAlbum));
1510       m_gWindowManager.ActivateWindow(WINDOW_MUSIC_NAV,strPath);
1511       return true;
1512     }
1513   case CONTEXT_BUTTON_PLAY_OTHER:
1514     {
1515       CMusicDatabase database;
1516       database.Open();
1517       CSong song;
1518       if (database.GetSongById(database.GetSongByArtistAndAlbumAndTitle(m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strArtist,m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strAlbum,
1519                                                                         m_vecItems->Get(itemNumber)->GetVideoInfoTag()->m_strTitle),
1520                                                                         song))
1521       {
1522         g_applicationMessenger.PlayFile(song);
1523       }
1524       return true;
1525     }
1526
1527   case CONTEXT_BUTTON_UNLINK_BOOKMARK:
1528     {
1529       m_database.Open();
1530       m_database.DeleteBookMarkForEpisode(*m_vecItems->Get(itemNumber)->GetVideoInfoTag());
1531       m_database.Close();
1532       CUtil::DeleteVideoDatabaseDirectoryCache();
1533       Update(m_vecItems->m_strPath);
1534       return true;
1535     }
1536
1537   default:
1538     break;
1539
1540   }
1541   return CGUIWindowVideoBase::OnContextButton(itemNumber, button);
1542 }
1543
1544 void CGUIWindowVideoNav::OnLinkMovieToTvShow(int itemnumber, bool bRemove)
1545 {
1546   CFileItemList list;
1547   if (bRemove)
1548   {
1549     std::vector<long> ids;
1550     if (!m_database.GetLinksToTvShow(m_vecItems->Get(itemnumber)->GetVideoInfoTag()->m_iDbId,ids))
1551       return;
1552     for (unsigned int i=0;i<ids.size();++i)
1553     {
1554       CVideoInfoTag tag;
1555       m_database.GetTvShowInfo("",tag,ids[i]);
1556       CFileItemPtr show(new CFileItem(tag));
1557       list.Add(show);
1558     }
1559   }
1560   else
1561   {
1562     m_database.GetTvShowsNav("videodb://2/2",list);
1563
1564     // remove already linked shows
1565     std::vector<long> ids;
1566     if (!m_database.GetLinksToTvShow(m_vecItems->Get(itemnumber)->GetVideoInfoTag()->m_iDbId,ids))
1567       return;
1568     for (int i=0;i<list.Size();)
1569     {
1570       unsigned int j;
1571       for (j=0;j<ids.size();++j)
1572       {
1573         if (list[i]->GetVideoInfoTag()->m_iDbId == ids[j])
1574           break;
1575       }
1576       if (j == ids.size())
1577         i++;
1578       else
1579         list.Remove(i);
1580     }
1581   }
1582   int iSelectedLabel = 0;
1583   if (list.Size() > 1)
1584   {
1585     list.Sort(SORT_METHOD_LABEL,SORT_ORDER_ASC);
1586     CGUIDialogSelect* pDialog = (CGUIDialogSelect*)m_gWindowManager.GetWindow(WINDOW_DIALOG_SELECT);
1587     pDialog->Reset();
1588     pDialog->SetItems(&list);
1589     pDialog->SetHeading(20356);
1590     pDialog->DoModal();
1591     iSelectedLabel = pDialog->GetSelectedLabel();
1592   }
1593   if (iSelectedLabel > -1)
1594   {
1595     m_database.LinkMovieToTvshow(m_vecItems->Get(itemnumber)->GetVideoInfoTag()->m_iDbId,
1596                                  list[iSelectedLabel]->GetVideoInfoTag()->m_iDbId, bRemove);
1597     CUtil::DeleteVideoDatabaseDirectoryCache();
1598   }
1599 }