CURL::Encode usage refactoring
[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().empty())
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 (StringUtils::StartsWith(item->GetPath(), "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.empty())
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 = StringUtils::Format("%i %s", iItems, g_localizeStrings.Get(127).c_str());
369   SET_CONTROL_LABEL(CONTROL_LABELFILES, items);
370
371   // set the filter label
372   CStdString strLabel;
373
374   // "Playlists"
375   if (m_vecItems->GetPath().Equals("special://musicplaylists/"))
376     strLabel = g_localizeStrings.Get(136);
377   // "{Playlist Name}"
378   else if (m_vecItems->IsPlayList())
379   {
380     // get playlist name from path
381     CStdString strDummy;
382     URIUtils::Split(m_vecItems->GetPath(), strDummy, strLabel);
383   }
384   // everything else is from a musicdb:// path
385   else
386   {
387     CMusicDatabaseDirectory dir;
388     dir.GetLabel(m_vecItems->GetPath(), strLabel);
389   }
390
391   SET_CONTROL_LABEL(CONTROL_FILTER, strLabel);
392
393   SET_CONTROL_SELECTED(GetID(),CONTROL_BTNPARTYMODE, g_partyModeManager.IsEnabled());
394
395   CONTROL_ENABLE_ON_CONDITION(CONTROL_UPDATE_LIBRARY, !m_vecItems->IsAddonsPath() && !m_vecItems->IsPlugin() && !m_vecItems->IsScript());
396 }
397
398 void CGUIWindowMusicNav::PlayItem(int iItem)
399 {
400   // unlike additemtoplaylist, we need to check the items here
401   // before calling it since the current playlist will be stopped
402   // and cleared!
403
404   // root is not allowed
405   if (m_vecItems->IsVirtualDirectoryRoot())
406     return;
407
408   CGUIWindowMusicBase::PlayItem(iItem);
409 }
410
411 void CGUIWindowMusicNav::OnWindowLoaded()
412 {
413   const CGUIControl *control = GetControl(CONTROL_SEARCH);
414   m_searchWithEdit = (control && control->GetControlType() == CGUIControl::GUICONTROL_EDIT);
415
416   CGUIWindowMusicBase::OnWindowLoaded();
417
418   if (m_searchWithEdit)
419   {
420     SendMessage(GUI_MSG_SET_TYPE, CONTROL_SEARCH, CGUIEditControl::INPUT_TYPE_SEARCH);
421     SET_CONTROL_LABEL2(CONTROL_SEARCH, GetProperty("search").asString());
422   }
423 }
424
425 void CGUIWindowMusicNav::GetContextButtons(int itemNumber, CContextButtons &buttons)
426 {
427   CGUIWindowMusicBase::GetContextButtons(itemNumber, buttons);
428
429   CFileItemPtr item;
430   if (itemNumber >= 0 && itemNumber < m_vecItems->Size())
431     item = m_vecItems->Get(itemNumber);
432   if (item && !StringUtils::StartsWithNoCase(item->GetPath(), "addons://more/"))
433   {
434     // are we in the playlists location?
435     bool inPlaylists = m_vecItems->GetPath().Equals(CUtil::MusicPlaylistsLocation()) ||
436                        m_vecItems->GetPath().Equals("special://musicplaylists/");
437
438     CMusicDatabaseDirectory dir;
439     // enable music info button on an album or on a song.
440     if (item->IsAudio() && !item->IsPlayList() && !item->IsSmartPlayList() &&
441         !item->m_bIsFolder)
442     {
443       buttons.Add(CONTEXT_BUTTON_SONG_INFO, 658);
444     }
445     else if (item->IsVideoDb())
446     {
447       if (!item->m_bIsFolder) // music video
448        buttons.Add(CONTEXT_BUTTON_INFO, 20393);
449       if (StringUtils::StartsWithNoCase(item->GetPath(), "videodb://musicvideos/artists/") && item->m_bIsFolder)
450       {
451         long idArtist = m_musicdatabase.GetArtistByName(m_vecItems->Get(itemNumber)->GetLabel());
452         if (idArtist > - 1)
453           buttons.Add(CONTEXT_BUTTON_INFO,21891);
454       }
455     }
456     else if (!inPlaylists && (dir.HasAlbumInfo(item->GetPath())||
457                               dir.IsArtistDir(item->GetPath())   )      &&
458              !dir.IsAllItem(item->GetPath()) && !item->IsParentFolder() &&
459              !item->IsPlugin() && !item->IsScript() &&
460              !StringUtils::StartsWithNoCase(item->GetPath(), "musicsearch://"))
461     {
462       if (dir.IsArtistDir(item->GetPath()))
463         buttons.Add(CONTEXT_BUTTON_INFO, 21891);
464       else
465         buttons.Add(CONTEXT_BUTTON_INFO, 13351);
466     }
467
468     // enable query all albums button only in album view
469     if (dir.HasAlbumInfo(item->GetPath()) && !dir.IsAllItem(item->GetPath()) &&
470         item->m_bIsFolder && !item->IsVideoDb() && !item->IsParentFolder()   &&
471        !item->IsPlugin() && !StringUtils::StartsWithNoCase(item->GetPath(), "musicsearch://"))
472     {
473       buttons.Add(CONTEXT_BUTTON_INFO_ALL, 20059);
474     }
475
476     // enable query all artist button only in album view
477     if (dir.IsArtistDir(item->GetPath()) && !dir.IsAllItem(item->GetPath()) &&
478       item->m_bIsFolder && !item->IsVideoDb())
479     {
480       ADDON::ScraperPtr info;
481       m_musicdatabase.GetScraperForPath(item->GetPath(), info, ADDON::ADDON_SCRAPER_ARTISTS);
482       if (info && info->Supports(CONTENT_ARTISTS))
483         buttons.Add(CONTEXT_BUTTON_INFO_ALL, 21884);
484     }
485
486     //Set default or clear default
487     NODE_TYPE nodetype = dir.GetDirectoryType(item->GetPath());
488     if (!item->IsParentFolder() && !inPlaylists &&
489         (nodetype == NODE_TYPE_ROOT     ||
490          nodetype == NODE_TYPE_OVERVIEW ||
491          nodetype == NODE_TYPE_TOP100))
492     {
493       if (!item->GetPath().Equals(CSettings::Get().GetString("mymusic.defaultlibview").c_str()))
494         buttons.Add(CONTEXT_BUTTON_SET_DEFAULT, 13335); // set default
495       if (strcmp(CSettings::Get().GetString("mymusic.defaultlibview").c_str(), ""))
496         buttons.Add(CONTEXT_BUTTON_CLEAR_DEFAULT, 13403); // clear default
497     }
498     NODE_TYPE childtype = dir.GetDirectoryChildType(item->GetPath());
499     if (childtype == NODE_TYPE_ALBUM               ||
500         childtype == NODE_TYPE_ARTIST              ||
501         nodetype == NODE_TYPE_GENRE                ||
502         nodetype == NODE_TYPE_ALBUM                ||
503         nodetype == NODE_TYPE_ALBUM_RECENTLY_ADDED ||
504         nodetype == NODE_TYPE_ALBUM_COMPILATIONS)
505     {
506       // we allow the user to set content for
507       // 1. general artist and album nodes
508       // 2. specific per genre
509       // 3. specific per artist
510       // 4. specific per album
511       buttons.Add(CONTEXT_BUTTON_SET_CONTENT,20195);
512     }
513     if (item->HasMusicInfoTag() && item->GetMusicInfoTag()->GetArtist().size() > 0)
514     {
515       CVideoDatabase database;
516       database.Open();
517       if (database.GetMatchingMusicVideo(StringUtils::Join(item->GetMusicInfoTag()->GetArtist(), g_advancedSettings.m_musicItemSeparator)) > -1)
518         buttons.Add(CONTEXT_BUTTON_GO_TO_ARTIST, 20400);
519     }
520     if (item->HasMusicInfoTag() && item->GetMusicInfoTag()->GetArtist().size() > 0 &&
521         item->GetMusicInfoTag()->GetAlbum().size() > 0 &&
522         item->GetMusicInfoTag()->GetTitle().size() > 0)
523     {
524       CVideoDatabase database;
525       database.Open();
526       if (database.GetMatchingMusicVideo(StringUtils::Join(item->GetMusicInfoTag()->GetArtist(), g_advancedSettings.m_musicItemSeparator),item->GetMusicInfoTag()->GetAlbum(),item->GetMusicInfoTag()->GetTitle()) > -1)
527         buttons.Add(CONTEXT_BUTTON_PLAY_OTHER, 20401);
528     }
529     if (item->HasVideoInfoTag() && !item->m_bIsFolder)
530     {
531       if (item->GetVideoInfoTag()->m_playCount > 0)
532         buttons.Add(CONTEXT_BUTTON_MARK_UNWATCHED, 16104); //Mark as UnWatched
533       else
534         buttons.Add(CONTEXT_BUTTON_MARK_WATCHED, 16103);   //Mark as Watched
535       if ((CProfilesManager::Get().GetCurrentProfile().canWriteDatabases() || g_passwordManager.bMasterUser) && !item->IsPlugin())
536       {
537         buttons.Add(CONTEXT_BUTTON_RENAME, 16105);
538         buttons.Add(CONTEXT_BUTTON_DELETE, 646);
539       }
540     }
541     if (inPlaylists && !URIUtils::GetFileName(item->GetPath()).Equals("PartyMode.xsp")
542                     && (item->IsPlayList() || item->IsSmartPlayList()))
543       buttons.Add(CONTEXT_BUTTON_DELETE, 117);
544
545     if (item->IsPlugin() || item->IsScript() || m_vecItems->IsPlugin())
546       buttons.Add(CONTEXT_BUTTON_PLUGIN_SETTINGS, 1045);
547   }
548   // noncontextual buttons
549
550   CGUIWindowMusicBase::GetNonContextButtons(buttons);
551 }
552
553 bool CGUIWindowMusicNav::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
554 {
555   CFileItemPtr item;
556   if (itemNumber >= 0 && itemNumber < m_vecItems->Size())
557     item = m_vecItems->Get(itemNumber);
558
559   switch (button)
560   {
561   case CONTEXT_BUTTON_INFO:
562     {
563       if (!item->IsVideoDb())
564         return CGUIWindowMusicBase::OnContextButton(itemNumber,button);
565
566       // music videos - artists
567       if (StringUtils::StartsWithNoCase(item->GetPath(), "videodb://musicvideos/artists/"))
568       {
569         long idArtist = m_musicdatabase.GetArtistByName(item->GetLabel());
570         if (idArtist == -1)
571           return false;
572         CStdString path = StringUtils::Format("musicdb://artists/%ld/", idArtist);
573         CArtist artist;
574         m_musicdatabase.GetArtist(idArtist, artist, false);
575         *item = CFileItem(artist);
576         item->SetPath(path);
577         CGUIWindowMusicBase::OnContextButton(itemNumber,button);
578         Refresh();
579         m_viewControl.SetSelectedItem(itemNumber);
580         return true;
581       }
582
583       // music videos - albums
584       if (StringUtils::StartsWithNoCase(item->GetPath(), "videodb://musicvideos/albums/"))
585       {
586         long idAlbum = m_musicdatabase.GetAlbumByName(item->GetLabel());
587         if (idAlbum == -1)
588           return false;
589         CStdString path = StringUtils::Format("musicdb://albums/%ld/", idAlbum);
590         CAlbum album;
591         m_musicdatabase.GetAlbum(idAlbum, album, false);
592         *item = CFileItem(path,album);
593         item->SetPath(path);
594         CGUIWindowMusicBase::OnContextButton(itemNumber,button);
595         Refresh();
596         m_viewControl.SetSelectedItem(itemNumber);
597         return true;
598       }
599
600       if (item->HasVideoInfoTag() && !item->GetVideoInfoTag()->m_strTitle.empty())
601       {
602         CGUIWindowVideoNav* pWindow = (CGUIWindowVideoNav*)g_windowManager.GetWindow(WINDOW_VIDEO_NAV);
603         if (pWindow)
604         {
605           ADDON::ScraperPtr info;
606           pWindow->OnInfo(item.get(),info);
607           Refresh();
608         }
609       }
610       return true;
611     }
612
613   case CONTEXT_BUTTON_INFO_ALL:
614     OnInfoAll(itemNumber);
615     return true;
616
617   case CONTEXT_BUTTON_SET_DEFAULT:
618     CSettings::Get().SetString("mymusic.defaultlibview", GetQuickpathName(item->GetPath()));
619     CSettings::Get().Save();
620     return true;
621
622   case CONTEXT_BUTTON_CLEAR_DEFAULT:
623     CSettings::Get().SetString("mymusic.defaultlibview", "");
624     CSettings::Get().Save();
625     return true;
626
627   case CONTEXT_BUTTON_GO_TO_ARTIST:
628     {
629       CStdString strPath;
630       CVideoDatabase database;
631       database.Open();
632       strPath = StringUtils::Format("videodb://musicvideos/artists/%ld/",
633                                     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       CGUIDialogVideoInfo::DeleteVideoItemFromDatabase(item);
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 = StringUtils::Format("musicdb://albums/%i/",params.GetAlbumId());
689       else if (params.GetArtistId() != -1)
690       {
691         path = StringUtils::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(CURL::Encode(GetProperty("search").asString()));
770   if (!search.empty())
771   {
772     CStdString path = "musicsearch://" + search + "/";
773     m_history.ClearSearchHistory();
774     Update(path);
775   }
776   else if (m_vecItems->IsVirtualDirectoryRoot())
777   {
778     Update("");
779   }
780 }
781
782 void CGUIWindowMusicNav::FrameMove()
783 {
784   static const int search_timeout = 2000;
785   // update our searching
786   if (m_searchTimer.IsRunning() && m_searchTimer.GetElapsedMilliseconds() > search_timeout)
787   {
788     m_searchTimer.Stop();
789     OnSearchUpdate();
790   }
791   if (m_bDisplayEmptyDatabaseMessage)
792     SET_CONTROL_LABEL(CONTROL_LABELEMPTY,g_localizeStrings.Get(745)+'\n'+g_localizeStrings.Get(746));
793   else
794     SET_CONTROL_LABEL(CONTROL_LABELEMPTY,"");
795   CGUIWindowMusicBase::FrameMove();
796 }
797
798 void CGUIWindowMusicNav::AddSearchFolder()
799 {
800   // we use a general viewstate (and not our member) here as our
801   // current viewstate may be specific to some other folder, and
802   // we know we're in the root here
803   CFileItemList items;
804   CGUIViewState* viewState = CGUIViewState::GetViewState(GetID(), items);
805   if (viewState)
806   {
807     // add our remove the musicsearch source
808     VECSOURCES &sources = viewState->GetSources();
809     bool haveSearchSource = false;
810     bool needSearchSource = !GetProperty("search").empty() || !m_searchWithEdit; // we always need it if we don't have the edit control
811     for (IVECSOURCES it = sources.begin(); it != sources.end(); ++it)
812     {
813       CMediaSource& share = *it;
814       if (share.strPath == "musicsearch://")
815       {
816         haveSearchSource = true;
817         if (!needSearchSource)
818         { // remove it
819           sources.erase(it);
820           break;
821         }
822       }
823     }
824     if (!haveSearchSource && needSearchSource)
825     {
826       // add earch share
827       CMediaSource share;
828       share.strName=g_localizeStrings.Get(137); // Search
829       share.strPath = "musicsearch://";
830       share.m_iDriveType = CMediaSource::SOURCE_TYPE_LOCAL;
831       sources.push_back(share);
832     }
833     m_rootDir.SetSources(sources);
834     delete viewState;
835   }
836 }
837
838 CStdString CGUIWindowMusicNav::GetStartFolder(const CStdString &dir)
839 {
840   if (dir.Equals("Genres"))
841     return "musicdb://genres/";
842   else if (dir.Equals("Artists"))
843     return "musicdb://artists/";
844   else if (dir.Equals("Albums"))
845     return "musicdb://albums/";
846   else if (dir.Equals("Singles"))
847     return "musicdb://singles/";
848   else if (dir.Equals("Songs"))
849     return "musicdb://songs/";
850   else if (dir.Equals("Top100"))
851     return "musicdb://top100/";
852   else if (dir.Equals("Top100Songs"))
853     return "musicdb://top100/songs/";
854   else if (dir.Equals("Top100Albums"))
855     return "musicdb://top100/albums/";
856   else if (dir.Equals("RecentlyAddedAlbums"))
857     return "musicdb://recentlyaddedalbums/";
858   else if (dir.Equals("RecentlyPlayedAlbums"))
859    return "musicdb://recentlyplayedalbums/";
860   else if (dir.Equals("Compilations"))
861     return "musicdb://compilations/";
862   else if (dir.Equals("Years"))
863     return "musicdb://years/";
864   return CGUIWindowMusicBase::GetStartFolder(dir);
865 }