76edccf82326e402157f97aa3d07a7b8ef2c115e
[vuplus_xbmc] / xbmc / music / windows / GUIWindowMusicNav.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "GUIWindowMusicNav.h"
22 #include "utils/FileUtils.h"
23 #include "utils/URIUtils.h"
24 #include "PlayListPlayer.h"
25 #include "GUIPassword.h"
26 #include "settings/dialogs/GUIDialogContentSettings.h"
27 #include "filesystem/MusicDatabaseDirectory.h"
28 #include "filesystem/VideoDatabaseDirectory.h"
29 #include "PartyModeManager.h"
30 #include "playlists/PlayList.h"
31 #include "playlists/PlayListFactory.h"
32 #include "profiles/ProfilesManager.h"
33 #include "video/VideoDatabase.h"
34 #include "video/dialogs/GUIDialogVideoInfo.h"
35 #include "video/windows/GUIWindowVideoNav.h"
36 #include "music/tags/MusicInfoTag.h"
37 #include "guilib/GUIWindowManager.h"
38 #include "dialogs/GUIDialogOK.h"
39 #include "guilib/GUIKeyboardFactory.h"
40 #include "guilib/Key.h"
41 #include "dialogs/GUIDialogYesNo.h"
42 #include "guilib/GUIEditControl.h"
43 #include "GUIUserMessages.h"
44 #include "filesystem/File.h"
45 #include "FileItem.h"
46 #include "Application.h"
47 #include "ApplicationMessenger.h"
48 #include "settings/Settings.h"
49 #include "settings/AdvancedSettings.h"
50 #include "guilib/LocalizeStrings.h"
51 #include "utils/LegacyPathTranslation.h"
52 #include "utils/log.h"
53 #include "utils/StringUtils.h"
54 #include "TextureCache.h"
55 #include "Util.h"
56 #include "URL.h"
57
58 using namespace std;
59 using namespace XFILE;
60 using namespace PLAYLIST;
61 using namespace MUSICDATABASEDIRECTORY;
62
63 #define CONTROL_BTNVIEWASICONS     2
64 #define CONTROL_BTNSORTBY          3
65 #define CONTROL_BTNSORTASC         4
66 #define CONTROL_BTNTYPE            5
67 #define CONTROL_LABELFILES        12
68
69 #define CONTROL_SEARCH             8
70 #define CONTROL_FILTER            15
71 #define CONTROL_BTNPARTYMODE      16
72 #define CONTROL_BTNMANUALINFO     17
73 #define CONTROL_BTN_FILTER        19
74 #define CONTROL_LABELEMPTY        18
75
76 #define CONTROL_UPDATE_LIBRARY    20
77
78 CGUIWindowMusicNav::CGUIWindowMusicNav(void)
79     : CGUIWindowMusicBase(WINDOW_MUSIC_NAV, "MyMusicNav.xml")
80 {
81   m_vecItems->SetPath("?");
82   m_bDisplayEmptyDatabaseMessage = false;
83   m_thumbLoader.SetObserver(this);
84   m_searchWithEdit = false;
85 }
86
87 CGUIWindowMusicNav::~CGUIWindowMusicNav(void)
88 {
89 }
90
91 bool CGUIWindowMusicNav::OnMessage(CGUIMessage& message)
92 {
93   switch (message.GetMessage())
94   {
95   case GUI_MSG_WINDOW_RESET:
96     m_vecItems->SetPath("?");
97     break;
98   case GUI_MSG_WINDOW_DEINIT:
99     if (m_thumbLoader.IsLoading())
100       m_thumbLoader.StopThread();
101     break;
102   case GUI_MSG_WINDOW_INIT:
103     {
104 /* We don't want to show Autosourced items (ie removable pendrives, memorycards) in Library mode */
105       m_rootDir.AllowNonLocalSources(false);
106
107       // is this the first time the window is opened?
108       if (m_vecItems->GetPath() == "?" && message.GetStringParam().IsEmpty())
109         message.SetStringParam(CSettings::Get().GetString("mymusic.defaultlibview"));
110       
111       DisplayEmptyDatabaseMessage(false); // reset message state
112
113       if (!CGUIWindowMusicBase::OnMessage(message))
114         return false;
115
116       //  base class has opened the database, do our check
117       DisplayEmptyDatabaseMessage(m_musicdatabase.GetSongsCount() <= 0);
118
119       if (m_bDisplayEmptyDatabaseMessage)
120       {
121         // no library - make sure we focus on a known control, and default to the root.
122         SET_CONTROL_FOCUS(CONTROL_BTNTYPE, 0);
123         m_vecItems->SetPath("");
124         SetHistoryForPath("");
125         Update("");
126       }
127
128       return true;
129     }
130     break;
131
132   case GUI_MSG_CLICKED:
133     {
134       int iControl = message.GetSenderId();
135       if (iControl == CONTROL_BTNPARTYMODE)
136       {
137         if (g_partyModeManager.IsEnabled())
138           g_partyModeManager.Disable();
139         else
140         {
141           if (!g_partyModeManager.Enable())
142           {
143             SET_CONTROL_SELECTED(GetID(),CONTROL_BTNPARTYMODE,false);
144             return false;
145           }
146
147           // Playlist directory is the root of the playlist window
148           if (m_guiState.get()) m_guiState->SetPlaylistDirectory("playlistmusic://");
149
150           return true;
151         }
152         UpdateButtons();
153       }
154       else if (iControl == CONTROL_SEARCH)
155       {
156         if (m_searchWithEdit)
157         {
158           // search updated - reset timer
159           m_searchTimer.StartZero();
160           // grab our search string
161           CGUIMessage selected(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_SEARCH);
162           OnMessage(selected);
163           SetProperty("search", selected.GetLabel());
164           return true;
165         }
166         CStdString search(GetProperty("search").asString());
167         CGUIKeyboardFactory::ShowAndGetFilter(search, true);
168         SetProperty("search", search);
169         return true;
170       }
171       else if (iControl == CONTROL_UPDATE_LIBRARY)
172       {
173         if (!g_application.IsMusicScanning())
174           g_application.StartMusicScan("");
175         else
176           g_application.StopMusicScan();
177         return true;
178       }
179     }
180     break;
181   case GUI_MSG_PLAYBACK_STOPPED:
182   case GUI_MSG_PLAYBACK_ENDED:
183   case GUI_MSG_PLAYLISTPLAYER_STOPPED:
184   case GUI_MSG_PLAYBACK_STARTED:
185     {
186       SET_CONTROL_SELECTED(GetID(),CONTROL_BTNPARTYMODE, g_partyModeManager.IsEnabled());
187     }
188     break;
189   case GUI_MSG_NOTIFY_ALL:
190     {
191       if (message.GetParam1() == GUI_MSG_SEARCH_UPDATE && IsActive())
192       {
193         // search updated - reset timer
194         m_searchTimer.StartZero();
195         SetProperty("search", message.GetStringParam());
196       }
197     }
198   }
199   return CGUIWindowMusicBase::OnMessage(message);
200 }
201
202 bool CGUIWindowMusicNav::OnAction(const CAction& action)
203 {
204   if (action.GetID() == ACTION_SCAN_ITEM)
205   {
206     int item = m_viewControl.GetSelectedItem();
207     CMusicDatabaseDirectory dir;
208     if (item > -1 && m_vecItems->Get(item)->m_bIsFolder
209                   && (dir.HasAlbumInfo(m_vecItems->Get(item)->GetPath())||
210                       dir.IsArtistDir(m_vecItems->Get(item)->GetPath())))
211       OnContextButton(item,CONTEXT_BUTTON_INFO);
212
213     return true;
214   }
215
216   return CGUIWindowMusicBase::OnAction(action);
217 }
218
219 CStdString CGUIWindowMusicNav::GetQuickpathName(const CStdString& strPath) const
220 {
221   CStdString path = CLegacyPathTranslation::TranslateMusicDbPath(strPath);
222   if (path.Equals("musicdb://genres/"))
223     return "Genres";
224   else if (path.Equals("musicdb://artists/"))
225     return "Artists";
226   else if (path.Equals("musicdb://albums/"))
227     return "Albums";
228   else if (path.Equals("musicdb://songs/"))
229     return "Songs";
230   else if (path.Equals("musicdb://top100/"))
231     return "Top100";
232   else if (path.Equals("musicdb://top100/songs/"))
233     return "Top100Songs";
234   else if (path.Equals("musicdb://top100/albums/"))
235     return "Top100Albums";
236   else if (path.Equals("musicdb://recentlyaddedalbums/"))
237     return "RecentlyAddedAlbums";
238   else if (path.Equals("musicdb://recentlyplayedalbums/"))
239     return "RecentlyPlayedAlbums";
240   else if (path.Equals("musicdb://compilations/"))
241     return "Compilations";
242   else if (path.Equals("musicdb://years/"))
243     return "Years";
244   else if (path.Equals("musicdb://singles/"))
245     return "Singles";
246   else if (path.Equals("special://musicplaylists/"))
247     return "Playlists";
248   else
249   {
250     CLog::Log(LOGERROR, "  CGUIWindowMusicNav::GetQuickpathName: Unknown parameter (%s)", strPath.c_str());
251     return strPath;
252   }
253 }
254
255 bool CGUIWindowMusicNav::OnClick(int iItem)
256 {
257   if (iItem < 0 || iItem >= m_vecItems->Size()) return false;
258
259   CFileItemPtr item = m_vecItems->Get(iItem);
260   if (item->GetPath().Left(14) == "musicsearch://")
261   {
262     if (m_searchWithEdit)
263       OnSearchUpdate();
264     else
265     {
266       CStdString search(GetProperty("search").asString());
267       CGUIKeyboardFactory::ShowAndGetFilter(search, true);
268       SetProperty("search", search);
269     }
270     return true;
271   }
272   if (item->IsMusicDb() && !item->m_bIsFolder)
273     m_musicdatabase.SetPropertiesForFileItem(*item);
274     
275   return CGUIWindowMusicBase::OnClick(iItem);
276 }
277
278 bool CGUIWindowMusicNav::Update(const CStdString &strDirectory, bool updateFilterPath /* = true */)
279 {
280   if (m_thumbLoader.IsLoading())
281     m_thumbLoader.StopThread();
282
283   if (CGUIWindowMusicBase::Update(strDirectory, updateFilterPath))
284   {
285     m_thumbLoader.Load(*m_unfilteredItems);
286     return true;
287   }
288
289   return false;
290 }
291
292 bool CGUIWindowMusicNav::GetDirectory(const CStdString &strDirectory, CFileItemList &items)
293 {
294   if (m_bDisplayEmptyDatabaseMessage)
295     return true;
296
297   if (strDirectory.IsEmpty())
298     AddSearchFolder();
299
300   bool bResult = CGUIWindowMusicBase::GetDirectory(strDirectory, items);
301   if (bResult)
302   {
303     if (items.IsPlayList())
304       OnRetrieveMusicInfo(items);
305   }
306
307   // update our content in the info manager
308   if (StringUtils::StartsWithNoCase(strDirectory, "videodb://"))
309   {
310     CVideoDatabaseDirectory dir;
311     VIDEODATABASEDIRECTORY::NODE_TYPE node = dir.GetDirectoryChildType(strDirectory);
312     if (node == VIDEODATABASEDIRECTORY::NODE_TYPE_TITLE_MUSICVIDEOS)
313       items.SetContent("musicvideos");
314   }
315   else if (StringUtils::StartsWithNoCase(strDirectory, "musicdb://"))
316   {
317     CMusicDatabaseDirectory dir;
318     NODE_TYPE node = dir.GetDirectoryChildType(strDirectory);
319     if (node == NODE_TYPE_ALBUM ||
320         node == NODE_TYPE_ALBUM_RECENTLY_ADDED ||
321         node == NODE_TYPE_ALBUM_RECENTLY_PLAYED ||
322         node == NODE_TYPE_ALBUM_TOP100 ||
323         node == NODE_TYPE_ALBUM_COMPILATIONS ||
324         node == NODE_TYPE_YEAR_ALBUM)
325       items.SetContent("albums");
326     else if (node == NODE_TYPE_ARTIST)
327       items.SetContent("artists");
328     else if (node == NODE_TYPE_SONG ||
329              node == NODE_TYPE_SONG_TOP100 ||
330              node == NODE_TYPE_SINGLES)
331       items.SetContent("songs");
332     else if (node == NODE_TYPE_GENRE)
333       items.SetContent("genres");
334     else if (node == NODE_TYPE_YEAR)
335       items.SetContent("years");
336   }
337   else if (strDirectory.Equals("special://musicplaylists/"))
338     items.SetContent("playlists");
339   else if (strDirectory.Equals("plugin://music/"))
340     items.SetContent("plugins");
341   else if (items.IsPlayList())
342     items.SetContent("songs");
343
344   return bResult;
345 }
346
347 void CGUIWindowMusicNav::UpdateButtons()
348 {
349   CGUIWindowMusicBase::UpdateButtons();
350
351   // Update object count
352   int iItems = m_vecItems->Size();
353   if (iItems)
354   {
355     // check for parent dir and "all" items
356     // should always be the first two items
357     for (int i = 0; i <= (iItems>=2 ? 1 : 0); i++)
358     {
359       CFileItemPtr pItem = m_vecItems->Get(i);
360       if (pItem->IsParentFolder()) iItems--;
361       if (StringUtils::StartsWith(pItem->GetPath(), "/-1/")) iItems--;
362     }
363     // or the last item
364     if (m_vecItems->Size() > 2 &&
365       StringUtils::StartsWith(m_vecItems->Get(m_vecItems->Size()-1)->GetPath(), "/-1/"))
366       iItems--;
367   }
368   CStdString items;
369   items.Format("%i %s", iItems, g_localizeStrings.Get(127).c_str());
370   SET_CONTROL_LABEL(CONTROL_LABELFILES, items);
371
372   // set the filter label
373   CStdString strLabel;
374
375   // "Playlists"
376   if (m_vecItems->GetPath().Equals("special://musicplaylists/"))
377     strLabel = g_localizeStrings.Get(136);
378   // "{Playlist Name}"
379   else if (m_vecItems->IsPlayList())
380   {
381     // get playlist name from path
382     CStdString strDummy;
383     URIUtils::Split(m_vecItems->GetPath(), strDummy, strLabel);
384   }
385   // everything else is from a musicdb:// path
386   else
387   {
388     CMusicDatabaseDirectory dir;
389     dir.GetLabel(m_vecItems->GetPath(), strLabel);
390   }
391
392   SET_CONTROL_LABEL(CONTROL_FILTER, strLabel);
393
394   SET_CONTROL_SELECTED(GetID(),CONTROL_BTNPARTYMODE, g_partyModeManager.IsEnabled());
395
396   CONTROL_ENABLE_ON_CONDITION(CONTROL_UPDATE_LIBRARY, !m_vecItems->IsAddonsPath() && !m_vecItems->IsPlugin() && !m_vecItems->IsScript());
397 }
398
399 void CGUIWindowMusicNav::PlayItem(int iItem)
400 {
401   // unlike additemtoplaylist, we need to check the items here
402   // before calling it since the current playlist will be stopped
403   // and cleared!
404
405   // root is not allowed
406   if (m_vecItems->IsVirtualDirectoryRoot())
407     return;
408
409   CGUIWindowMusicBase::PlayItem(iItem);
410 }
411
412 void CGUIWindowMusicNav::OnWindowLoaded()
413 {
414   const CGUIControl *control = GetControl(CONTROL_SEARCH);
415   m_searchWithEdit = (control && control->GetControlType() == CGUIControl::GUICONTROL_EDIT);
416
417   CGUIWindowMusicBase::OnWindowLoaded();
418
419   if (m_searchWithEdit)
420   {
421     SendMessage(GUI_MSG_SET_TYPE, CONTROL_SEARCH, CGUIEditControl::INPUT_TYPE_SEARCH);
422     SET_CONTROL_LABEL2(CONTROL_SEARCH, GetProperty("search").asString());
423   }
424 }
425
426 void CGUIWindowMusicNav::GetContextButtons(int itemNumber, CContextButtons &buttons)
427 {
428   CGUIWindowMusicBase::GetContextButtons(itemNumber, buttons);
429
430   CFileItemPtr item;
431   if (itemNumber >= 0 && itemNumber < m_vecItems->Size())
432     item = m_vecItems->Get(itemNumber);
433   if (item && !StringUtils::StartsWithNoCase(item->GetPath(), "addons://more/"))
434   {
435     // are we in the playlists location?
436     bool inPlaylists = m_vecItems->GetPath().Equals(CUtil::MusicPlaylistsLocation()) ||
437                        m_vecItems->GetPath().Equals("special://musicplaylists/");
438
439     CMusicDatabaseDirectory dir;
440     // enable music info button on an album or on a song.
441     if (item->IsAudio() && !item->IsPlayList() && !item->IsSmartPlayList() &&
442         !item->m_bIsFolder)
443     {
444       buttons.Add(CONTEXT_BUTTON_SONG_INFO, 658);
445     }
446     else if (item->IsVideoDb())
447     {
448       if (!item->m_bIsFolder) // music video
449        buttons.Add(CONTEXT_BUTTON_INFO, 20393);
450       if (StringUtils::StartsWithNoCase(item->GetPath(), "videodb://musicvideos/artists/") && item->m_bIsFolder)
451       {
452         long idArtist = m_musicdatabase.GetArtistByName(m_vecItems->Get(itemNumber)->GetLabel());
453         if (idArtist > - 1)
454           buttons.Add(CONTEXT_BUTTON_INFO,21891);
455       }
456     }
457     else if (!inPlaylists && (dir.HasAlbumInfo(item->GetPath())||
458                               dir.IsArtistDir(item->GetPath())   )      &&
459              !dir.IsAllItem(item->GetPath()) && !item->IsParentFolder() &&
460              !item->IsPlugin() && !item->IsScript() &&
461              !StringUtils::StartsWithNoCase(item->GetPath(), "musicsearch://"))
462     {
463       if (dir.IsArtistDir(item->GetPath()))
464         buttons.Add(CONTEXT_BUTTON_INFO, 21891);
465       else
466         buttons.Add(CONTEXT_BUTTON_INFO, 13351);
467     }
468
469     // enable query all albums button only in album view
470     if (dir.HasAlbumInfo(item->GetPath()) && !dir.IsAllItem(item->GetPath()) &&
471         item->m_bIsFolder && !item->IsVideoDb() && !item->IsParentFolder()   &&
472        !item->IsPlugin() && !StringUtils::StartsWithNoCase(item->GetPath(), "musicsearch://"))
473     {
474       buttons.Add(CONTEXT_BUTTON_INFO_ALL, 20059);
475     }
476
477     // enable query all artist button only in album view
478     if (dir.IsArtistDir(item->GetPath()) && !dir.IsAllItem(item->GetPath()) &&
479       item->m_bIsFolder && !item->IsVideoDb())
480     {
481       ADDON::ScraperPtr info;
482       m_musicdatabase.GetScraperForPath(item->GetPath(), info, ADDON::ADDON_SCRAPER_ARTISTS);
483       if (info && info->Supports(CONTENT_ARTISTS))
484         buttons.Add(CONTEXT_BUTTON_INFO_ALL, 21884);
485     }
486
487     //Set default or clear default
488     NODE_TYPE nodetype = dir.GetDirectoryType(item->GetPath());
489     if (!item->IsParentFolder() && !inPlaylists &&
490         (nodetype == NODE_TYPE_ROOT     ||
491          nodetype == NODE_TYPE_OVERVIEW ||
492          nodetype == NODE_TYPE_TOP100))
493     {
494       if (!item->GetPath().Equals(CSettings::Get().GetString("mymusic.defaultlibview").c_str()))
495         buttons.Add(CONTEXT_BUTTON_SET_DEFAULT, 13335); // set default
496       if (strcmp(CSettings::Get().GetString("mymusic.defaultlibview").c_str(), ""))
497         buttons.Add(CONTEXT_BUTTON_CLEAR_DEFAULT, 13403); // clear default
498     }
499     NODE_TYPE childtype = dir.GetDirectoryChildType(item->GetPath());
500     if (childtype == NODE_TYPE_ALBUM               ||
501         childtype == NODE_TYPE_ARTIST              ||
502         nodetype == NODE_TYPE_GENRE                ||
503         nodetype == NODE_TYPE_ALBUM                ||
504         nodetype == NODE_TYPE_ALBUM_RECENTLY_ADDED ||
505         nodetype == NODE_TYPE_ALBUM_COMPILATIONS)
506     {
507       // we allow the user to set content for
508       // 1. general artist and album nodes
509       // 2. specific per genre
510       // 3. specific per artist
511       // 4. specific per album
512       buttons.Add(CONTEXT_BUTTON_SET_CONTENT,20195);
513     }
514     if (item->HasMusicInfoTag() && item->GetMusicInfoTag()->GetArtist().size() > 0)
515     {
516       CVideoDatabase database;
517       database.Open();
518       if (database.GetMatchingMusicVideo(StringUtils::Join(item->GetMusicInfoTag()->GetArtist(), g_advancedSettings.m_musicItemSeparator)) > -1)
519         buttons.Add(CONTEXT_BUTTON_GO_TO_ARTIST, 20400);
520     }
521     if (item->HasMusicInfoTag() && item->GetMusicInfoTag()->GetArtist().size() > 0 &&
522         item->GetMusicInfoTag()->GetAlbum().size() > 0 &&
523         item->GetMusicInfoTag()->GetTitle().size() > 0)
524     {
525       CVideoDatabase database;
526       database.Open();
527       if (database.GetMatchingMusicVideo(StringUtils::Join(item->GetMusicInfoTag()->GetArtist(), g_advancedSettings.m_musicItemSeparator),item->GetMusicInfoTag()->GetAlbum(),item->GetMusicInfoTag()->GetTitle()) > -1)
528         buttons.Add(CONTEXT_BUTTON_PLAY_OTHER, 20401);
529     }
530     if (item->HasVideoInfoTag() && !item->m_bIsFolder)
531     {
532       if (item->GetVideoInfoTag()->m_playCount > 0)
533         buttons.Add(CONTEXT_BUTTON_MARK_UNWATCHED, 16104); //Mark as UnWatched
534       else
535         buttons.Add(CONTEXT_BUTTON_MARK_WATCHED, 16103);   //Mark as Watched
536       if ((CProfilesManager::Get().GetCurrentProfile().canWriteDatabases() || g_passwordManager.bMasterUser) && !item->IsPlugin())
537       {
538         buttons.Add(CONTEXT_BUTTON_RENAME, 16105);
539         buttons.Add(CONTEXT_BUTTON_DELETE, 646);
540       }
541     }
542     if (inPlaylists && !URIUtils::GetFileName(item->GetPath()).Equals("PartyMode.xsp")
543                     && (item->IsPlayList() || item->IsSmartPlayList()))
544       buttons.Add(CONTEXT_BUTTON_DELETE, 117);
545
546     if (item->IsPlugin() || item->IsScript() || m_vecItems->IsPlugin())
547       buttons.Add(CONTEXT_BUTTON_PLUGIN_SETTINGS, 1045);
548   }
549   // noncontextual buttons
550
551   CGUIWindowMusicBase::GetNonContextButtons(buttons);
552 }
553
554 bool CGUIWindowMusicNav::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
555 {
556   CFileItemPtr item;
557   if (itemNumber >= 0 && itemNumber < m_vecItems->Size())
558     item = m_vecItems->Get(itemNumber);
559
560   switch (button)
561   {
562   case CONTEXT_BUTTON_INFO:
563     {
564       if (!item->IsVideoDb())
565         return CGUIWindowMusicBase::OnContextButton(itemNumber,button);
566
567       // music videos - artists
568       if (StringUtils::StartsWithNoCase(item->GetPath(), "videodb://musicvideos/artists/"))
569       {
570         long idArtist = m_musicdatabase.GetArtistByName(item->GetLabel());
571         if (idArtist == -1)
572           return false;
573         CStdString path; path.Format("musicdb://artists/%ld/", idArtist);
574         CArtist artist;
575         m_musicdatabase.GetArtistInfo(idArtist,artist,false);
576         *item = CFileItem(artist);
577         item->SetPath(path);
578         CGUIWindowMusicBase::OnContextButton(itemNumber,button);
579         Refresh();
580         m_viewControl.SetSelectedItem(itemNumber);
581         return true;
582       }
583
584       // music videos - albums
585       if (StringUtils::StartsWithNoCase(item->GetPath(), "videodb://musicvideos/albums/"))
586       {
587         long idAlbum = m_musicdatabase.GetAlbumByName(item->GetLabel());
588         if (idAlbum == -1)
589           return false;
590         CStdString path; path.Format("musicdb://albums/%ld/", idAlbum);
591         CAlbum album;
592         m_musicdatabase.GetAlbumInfo(idAlbum,album,NULL);
593         *item = CFileItem(path,album);
594         item->SetPath(path);
595         CGUIWindowMusicBase::OnContextButton(itemNumber,button);
596         Refresh();
597         m_viewControl.SetSelectedItem(itemNumber);
598         return true;
599       }
600
601       if (item->HasVideoInfoTag() && !item->GetVideoInfoTag()->m_strTitle.IsEmpty())
602       {
603         CGUIWindowVideoNav* pWindow = (CGUIWindowVideoNav*)g_windowManager.GetWindow(WINDOW_VIDEO_NAV);
604         if (pWindow)
605         {
606           ADDON::ScraperPtr info;
607           pWindow->OnInfo(item.get(),info);
608           Refresh();
609         }
610       }
611       return true;
612     }
613
614   case CONTEXT_BUTTON_INFO_ALL:
615     OnInfoAll(itemNumber);
616     return true;
617
618   case CONTEXT_BUTTON_SET_DEFAULT:
619     CSettings::Get().SetString("mymusic.defaultlibview", GetQuickpathName(item->GetPath()));
620     CSettings::Get().Save();
621     return true;
622
623   case CONTEXT_BUTTON_CLEAR_DEFAULT:
624     CSettings::Get().SetString("mymusic.defaultlibview", "");
625     CSettings::Get().Save();
626     return true;
627
628   case CONTEXT_BUTTON_GO_TO_ARTIST:
629     {
630       CStdString strPath;
631       CVideoDatabase database;
632       database.Open();
633       strPath.Format("videodb://musicvideos/artists/%ld/",database.GetMatchingMusicVideo(StringUtils::Join(item->GetMusicInfoTag()->GetArtist(), g_advancedSettings.m_musicItemSeparator)));
634       g_windowManager.ActivateWindow(WINDOW_VIDEO_NAV,strPath);
635       return true;
636     }
637
638   case CONTEXT_BUTTON_PLAY_OTHER:
639     {
640       CVideoDatabase database;
641       database.Open();
642       CVideoInfoTag details;
643       database.GetMusicVideoInfo("",details,database.GetMatchingMusicVideo(StringUtils::Join(item->GetMusicInfoTag()->GetArtist(), g_advancedSettings.m_musicItemSeparator),item->GetMusicInfoTag()->GetAlbum(),item->GetMusicInfoTag()->GetTitle()));
644       CApplicationMessenger::Get().PlayFile(CFileItem(details));
645       return true;
646     }
647
648   case CONTEXT_BUTTON_MARK_WATCHED:
649     CGUIDialogVideoInfo::MarkWatched(item, true);
650     CUtil::DeleteVideoDatabaseDirectoryCache();
651     Refresh();
652     return true;
653
654   case CONTEXT_BUTTON_MARK_UNWATCHED:
655     CGUIDialogVideoInfo::MarkWatched(item, false);
656     CUtil::DeleteVideoDatabaseDirectoryCache();
657     Refresh();
658     return true;
659
660   case CONTEXT_BUTTON_RENAME:
661     CGUIDialogVideoInfo::UpdateVideoItemTitle(item);
662     CUtil::DeleteVideoDatabaseDirectoryCache();
663     Refresh();
664     return true;
665
666   case CONTEXT_BUTTON_DELETE:
667     if (item->IsPlayList() || item->IsSmartPlayList())
668     {
669       item->m_bIsFolder = false;
670       CFileUtils::DeleteItem(item);
671     }
672     else
673     {
674       CGUIWindowVideoNav::DeleteItem(item.get());
675       CUtil::DeleteVideoDatabaseDirectoryCache();
676     }
677     Refresh();
678     return true;
679
680   case CONTEXT_BUTTON_SET_CONTENT:
681     {
682       ADDON::ScraperPtr scraper;
683       CStdString path(item->GetPath());
684       CQueryParams params;
685       CDirectoryNode::GetDatabaseInfo(item->GetPath(), params);
686       CONTENT_TYPE content = CONTENT_ALBUMS;
687       if (params.GetAlbumId() != -1)
688         path.Format("musicdb://albums/%i/",params.GetAlbumId());
689       else if (params.GetArtistId() != -1)
690       {
691         path.Format("musicdb://artists/%i/",params.GetArtistId());
692         content = CONTENT_ARTISTS;
693       }
694
695       if (m_vecItems->GetPath().Equals("musicdb://genres/") || item->GetPath().Equals("musicdb://artists/"))
696       {
697         content = CONTENT_ARTISTS;
698       }
699
700       if (!m_musicdatabase.GetScraperForPath(path, scraper, ADDON::ScraperTypeFromContent(content)))
701       {
702         ADDON::AddonPtr defaultScraper;
703         if (ADDON::CAddonMgr::Get().GetDefault(ADDON::ScraperTypeFromContent(content), defaultScraper))
704         {
705           scraper = boost::dynamic_pointer_cast<ADDON::CScraper>(defaultScraper->Clone());
706         }
707       }
708
709       if (CGUIDialogContentSettings::Show(scraper, content))
710       {
711         m_musicdatabase.SetScraperForPath(path,scraper);
712         if (CGUIDialogYesNo::ShowAndGetInput(20442,20443,20444,20022))
713         {
714           OnInfoAll(itemNumber,true,true);
715         }
716
717       }
718       return true;
719     }
720
721   default:
722     break;
723   }
724
725   return CGUIWindowMusicBase::OnContextButton(itemNumber, button);
726 }
727
728 bool CGUIWindowMusicNav::GetSongsFromPlayList(const CStdString& strPlayList, CFileItemList &items)
729 {
730   CStdString strParentPath=m_history.GetParentPath();
731
732   if (m_guiState.get() && !m_guiState->HideParentDirItems())
733   {
734     CFileItemPtr pItem(new CFileItem(".."));
735     pItem->SetPath(strParentPath);
736     items.Add(pItem);
737   }
738
739   items.SetPath(strPlayList);
740   CLog::Log(LOGDEBUG,"CGUIWindowMusicNav, opening playlist [%s]", strPlayList.c_str());
741
742   auto_ptr<CPlayList> pPlayList (CPlayListFactory::Create(strPlayList));
743   if ( NULL != pPlayList.get())
744   {
745     // load it
746     if (!pPlayList->Load(strPlayList))
747     {
748       CGUIDialogOK::ShowAndGetInput(6, 0, 477, 0);
749       return false; //hmmm unable to load playlist?
750     }
751     CPlayList playlist = *pPlayList;
752     // convert playlist items to songs
753     for (int i = 0; i < (int)playlist.size(); ++i)
754     {
755       items.Add(playlist[i]);
756     }
757   }
758
759   return true;
760 }
761
762 void CGUIWindowMusicNav::DisplayEmptyDatabaseMessage(bool bDisplay)
763 {
764   m_bDisplayEmptyDatabaseMessage = bDisplay;
765 }
766
767 void CGUIWindowMusicNav::OnSearchUpdate()
768 {
769   CStdString search(GetProperty("search").asString());
770   CURL::Encode(search);
771   if (!search.IsEmpty())
772   {
773     CStdString path = "musicsearch://" + search + "/";
774     m_history.ClearSearchHistory();
775     Update(path);
776   }
777   else if (m_vecItems->IsVirtualDirectoryRoot())
778   {
779     Update("");
780   }
781 }
782
783 void CGUIWindowMusicNav::FrameMove()
784 {
785   static const int search_timeout = 2000;
786   // update our searching
787   if (m_searchTimer.IsRunning() && m_searchTimer.GetElapsedMilliseconds() > search_timeout)
788   {
789     m_searchTimer.Stop();
790     OnSearchUpdate();
791   }
792   if (m_bDisplayEmptyDatabaseMessage)
793     SET_CONTROL_LABEL(CONTROL_LABELEMPTY,g_localizeStrings.Get(745)+'\n'+g_localizeStrings.Get(746));
794   else
795     SET_CONTROL_LABEL(CONTROL_LABELEMPTY,"");
796   CGUIWindowMusicBase::FrameMove();
797 }
798
799 void CGUIWindowMusicNav::AddSearchFolder()
800 {
801   // we use a general viewstate (and not our member) here as our
802   // current viewstate may be specific to some other folder, and
803   // we know we're in the root here
804   CFileItemList items;
805   CGUIViewState* viewState = CGUIViewState::GetViewState(GetID(), items);
806   if (viewState)
807   {
808     // add our remove the musicsearch source
809     VECSOURCES &sources = viewState->GetSources();
810     bool haveSearchSource = false;
811     bool needSearchSource = !GetProperty("search").empty() || !m_searchWithEdit; // we always need it if we don't have the edit control
812     for (IVECSOURCES it = sources.begin(); it != sources.end(); ++it)
813     {
814       CMediaSource& share = *it;
815       if (share.strPath == "musicsearch://")
816       {
817         haveSearchSource = true;
818         if (!needSearchSource)
819         { // remove it
820           sources.erase(it);
821           break;
822         }
823       }
824     }
825     if (!haveSearchSource && needSearchSource)
826     {
827       // add earch share
828       CMediaSource share;
829       share.strName=g_localizeStrings.Get(137); // Search
830       share.strPath = "musicsearch://";
831       share.m_iDriveType = CMediaSource::SOURCE_TYPE_LOCAL;
832       sources.push_back(share);
833     }
834     m_rootDir.SetSources(sources);
835     delete viewState;
836   }
837 }
838
839 CStdString CGUIWindowMusicNav::GetStartFolder(const CStdString &dir)
840 {
841   if (dir.Equals("Genres"))
842     return "musicdb://genres/";
843   else if (dir.Equals("Artists"))
844     return "musicdb://artists/";
845   else if (dir.Equals("Albums"))
846     return "musicdb://albums/";
847   else if (dir.Equals("Singles"))
848     return "musicdb://singles/";
849   else if (dir.Equals("Songs"))
850     return "musicdb://songs/";
851   else if (dir.Equals("Top100"))
852     return "musicdb://top100/";
853   else if (dir.Equals("Top100Songs"))
854     return "musicdb://top100/songs/";
855   else if (dir.Equals("Top100Albums"))
856     return "musicdb://top100/albums/";
857   else if (dir.Equals("RecentlyAddedAlbums"))
858     return "musicdb://recentlyaddedalbums/";
859   else if (dir.Equals("RecentlyPlayedAlbums"))
860    return "musicdb://recentlyplayedalbums/";
861   else if (dir.Equals("Compilations"))
862     return "musicdb://compilations/";
863   else if (dir.Equals("Years"))
864     return "musicdb://years/";
865   return CGUIWindowMusicBase::GetStartFolder(dir);
866 }