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