2 * Copyright (C) 2005-2013 Team XBMC
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)
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.
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/>.
21 #include "GUIDialogMusicInfo.h"
22 #include "guilib/GUIWindowManager.h"
23 #include "guilib/GUIImage.h"
24 #include "dialogs/GUIDialogFileBrowser.h"
25 #include "GUIPassword.h"
26 #include "music/MusicDatabase.h"
27 #include "music/tags/MusicInfoTag.h"
29 #include "filesystem/File.h"
31 #include "profiles/ProfilesManager.h"
32 #include "storage/MediaManager.h"
33 #include "utils/AsyncFileCopy.h"
34 #include "settings/AdvancedSettings.h"
35 #include "settings/MediaSourceSettings.h"
36 #include "settings/Settings.h"
37 #include "guilib/Key.h"
38 #include "guilib/LocalizeStrings.h"
39 #include "utils/log.h"
40 #include "utils/URIUtils.h"
41 #include "utils/StringUtils.h"
42 #include "TextureCache.h"
43 #include "music/MusicThumbLoader.h"
44 #include "filesystem/Directory.h"
47 using namespace XFILE;
49 #define CONTROL_IMAGE 3
50 #define CONTROL_TEXTAREA 4
52 #define CONTROL_BTN_TRACKS 5
53 #define CONTROL_BTN_REFRESH 6
54 #define CONTROL_BTN_GET_THUMB 10
55 #define CONTROL_BTN_GET_FANART 12
57 #define CONTROL_LIST 50
59 CGUIDialogMusicInfo::CGUIDialogMusicInfo(void)
60 : CGUIDialog(WINDOW_DIALOG_MUSIC_INFO, "DialogAlbumInfo.xml")
61 , m_albumItem(new CFileItem)
64 m_albumSongs = new CFileItemList;
65 m_loadType = KEEP_IN_MEMORY;
68 CGUIDialogMusicInfo::~CGUIDialogMusicInfo(void)
73 bool CGUIDialogMusicInfo::OnMessage(CGUIMessage& message)
75 switch ( message.GetMessage() )
77 case GUI_MSG_WINDOW_DEINIT:
79 CGUIMessage message(GUI_MSG_LABEL_RESET, GetID(), CONTROL_LIST);
81 m_albumSongs->Clear();
85 case GUI_MSG_WINDOW_INIT:
87 CGUIDialog::OnMessage(message);
98 int iControl = message.GetSenderId();
99 if (iControl == CONTROL_BTN_REFRESH)
105 else if (iControl == CONTROL_BTN_GET_THUMB)
109 else if (iControl == CONTROL_BTN_TRACKS)
111 m_bViewReview = !m_bViewReview;
114 else if (iControl == CONTROL_LIST)
116 int iAction = message.GetParam1();
117 if (m_bArtistInfo && (ACTION_SELECT_ITEM == iAction || ACTION_MOUSE_LEFT_CLICK == iAction))
119 CGUIMessage msg(GUI_MSG_ITEM_SELECTED, GetID(), iControl);
120 g_windowManager.SendMessage(msg);
121 int iItem = msg.GetParam1();
122 if (iItem < 0 || iItem >= (int)m_albumSongs->Size())
124 CFileItemPtr item = m_albumSongs->Get(iItem);
125 OnSearch(item.get());
129 else if (iControl == CONTROL_BTN_GET_FANART)
137 return CGUIDialog::OnMessage(message);
140 bool CGUIDialogMusicInfo::OnAction(const CAction &action)
142 if (action.GetID() == ACTION_SHOW_INFO)
147 return CGUIDialog::OnAction(action);
150 void CGUIDialogMusicInfo::SetAlbum(const CAlbum& album, const CStdString &path)
153 SetSongs(m_album.songs);
154 *m_albumItem = CFileItem(path, true);
155 m_albumItem->GetMusicInfoTag()->SetAlbum(m_album.strAlbum);
156 m_albumItem->GetMusicInfoTag()->SetAlbumArtist(StringUtils::Join(m_album.artist, g_advancedSettings.m_musicItemSeparator));
157 m_albumItem->GetMusicInfoTag()->SetArtist(m_album.artist);
158 m_albumItem->GetMusicInfoTag()->SetYear(m_album.iYear);
159 m_albumItem->GetMusicInfoTag()->SetLoaded(true);
160 m_albumItem->GetMusicInfoTag()->SetRating('0' + m_album.iRating);
161 m_albumItem->GetMusicInfoTag()->SetGenre(m_album.genre);
162 m_albumItem->GetMusicInfoTag()->SetDatabaseId(m_album.idAlbum, "album");
163 CMusicDatabase::SetPropertiesFromAlbum(*m_albumItem,m_album);
165 CMusicThumbLoader loader;
166 loader.LoadItem(m_albumItem.get());
168 // set the artist thumb, fanart
169 if (!m_album.artist.empty())
173 map<string, string> artwork;
174 if (db.GetArtistArtForItem(m_album.idAlbum, "album", artwork))
176 if (artwork.find("thumb") != artwork.end())
177 m_albumItem->SetProperty("artistthumb", artwork["thumb"]);
178 if (artwork.find("fanart") != artwork.end())
179 m_albumItem->SetArt("fanart",artwork["fanart"]);
182 m_hasUpdatedThumb = false;
183 m_bArtistInfo = false;
184 m_albumSongs->SetContent("albums");
187 void CGUIDialogMusicInfo::SetArtist(const CArtist& artist, const CStdString &path)
191 *m_albumItem = CFileItem(path, true);
192 m_albumItem->SetLabel(artist.strArtist);
193 m_albumItem->GetMusicInfoTag()->SetAlbumArtist(m_artist.strArtist);
194 m_albumItem->GetMusicInfoTag()->SetArtist(m_artist.strArtist);
195 m_albumItem->GetMusicInfoTag()->SetLoaded(true);
196 m_albumItem->GetMusicInfoTag()->SetGenre(m_artist.genre);
197 m_albumItem->GetMusicInfoTag()->SetDatabaseId(m_artist.idArtist, "artist");
198 CMusicDatabase::SetPropertiesFromArtist(*m_albumItem,m_artist);
200 CMusicThumbLoader loader;
201 loader.LoadItem(m_albumItem.get());
203 m_hasUpdatedThumb = false;
204 m_bArtistInfo = true;
205 m_albumSongs->SetContent("artists");
208 void CGUIDialogMusicInfo::SetSongs(const VECSONGS &songs)
210 m_albumSongs->Clear();
211 for (unsigned int i = 0; i < songs.size(); i++)
213 const CSong& song = songs[i];
214 CFileItemPtr item(new CFileItem(song));
215 m_albumSongs->Add(item);
219 void CGUIDialogMusicInfo::SetDiscography()
221 m_albumSongs->Clear();
222 CMusicDatabase database;
225 vector<int> albumsByArtist;
226 database.GetAlbumsByArtist(m_artist.idArtist, true, albumsByArtist);
228 for (unsigned int i=0;i<m_artist.discography.size();++i)
230 CFileItemPtr item(new CFileItem(m_artist.discography[i].first));
231 item->SetLabel2(m_artist.discography[i].second);
234 for (vector<int>::const_iterator album = albumsByArtist.begin(); album != albumsByArtist.end(); ++album)
236 if (database.GetAlbumById(*album).Equals(item->GetLabel()))
239 item->GetMusicInfoTag()->SetDatabaseId(idAlbum, "album");
244 if (idAlbum != -1) // we need this slight stupidity to get correct case for the album name
245 item->SetArt("thumb", database.GetArtForItem(idAlbum, "album", "thumb"));
247 item->SetArt("thumb", "DefaultAlbumCover.png");
249 m_albumSongs->Add(item);
253 void CGUIDialogMusicInfo::Update()
257 CONTROL_ENABLE(CONTROL_BTN_GET_FANART);
259 SetLabel(CONTROL_TEXTAREA, m_artist.strBiography);
260 CGUIMessage message(GUI_MSG_LABEL_BIND, GetID(), CONTROL_LIST, 0, 0, m_albumSongs);
263 if (GetControl(CONTROL_BTN_TRACKS)) // if no CONTROL_BTN_TRACKS found - allow skinner full visibility control over CONTROL_TEXTAREA and CONTROL_LIST
267 SET_CONTROL_VISIBLE(CONTROL_TEXTAREA);
268 SET_CONTROL_HIDDEN(CONTROL_LIST);
269 SET_CONTROL_LABEL(CONTROL_BTN_TRACKS, 21888);
273 SET_CONTROL_VISIBLE(CONTROL_LIST);
274 SET_CONTROL_HIDDEN(CONTROL_TEXTAREA);
275 SET_CONTROL_LABEL(CONTROL_BTN_TRACKS, 21887);
281 CONTROL_DISABLE(CONTROL_BTN_GET_FANART);
283 SetLabel(CONTROL_TEXTAREA, m_album.strReview);
284 CGUIMessage message(GUI_MSG_LABEL_BIND, GetID(), CONTROL_LIST, 0, 0, m_albumSongs);
287 if (GetControl(CONTROL_BTN_TRACKS)) // if no CONTROL_BTN_TRACKS found - allow skinner full visibility control over CONTROL_TEXTAREA and CONTROL_LIST
291 SET_CONTROL_VISIBLE(CONTROL_TEXTAREA);
292 SET_CONTROL_HIDDEN(CONTROL_LIST);
293 SET_CONTROL_LABEL(CONTROL_BTN_TRACKS, 182);
297 SET_CONTROL_VISIBLE(CONTROL_LIST);
298 SET_CONTROL_HIDDEN(CONTROL_TEXTAREA);
299 SET_CONTROL_LABEL(CONTROL_BTN_TRACKS, 183);
303 // update the thumbnail
304 const CGUIControl* pControl = GetControl(CONTROL_IMAGE);
307 CGUIImage* pImageControl = (CGUIImage*)pControl;
308 pImageControl->FreeResources();
309 pImageControl->SetFileName(m_albumItem->GetArt("thumb"));
312 // disable the GetThumb button if the user isn't allowed it
313 CONTROL_ENABLE_ON_CONDITION(CONTROL_BTN_GET_THUMB, CProfilesManager::Get().GetCurrentProfile().canWriteDatabases() || g_passwordManager.bMasterUser);
316 void CGUIDialogMusicInfo::SetLabel(int iControl, const CStdString& strLabel)
318 if (strLabel.empty())
320 SET_CONTROL_LABEL(iControl, (iControl == CONTROL_TEXTAREA) ? (m_bArtistInfo?547:414) : 416);
324 SET_CONTROL_LABEL(iControl, strLabel);
328 bool CGUIDialogMusicInfo::NeedRefresh() const
333 void CGUIDialogMusicInfo::OnInitWindow()
335 CGUIDialog::OnInitWindow();
338 // Get Thumb from user choice.
341 // 2. AllMusic.com thumb
343 // 4. No thumb (if no Local thumb is available)
345 // TODO: Currently no support for "embedded thumb" as there is no easy way to grab it
346 // without sending a file that has this as it's album to this class
347 void CGUIDialogMusicInfo::OnGetThumb()
352 if (CFile::Exists(m_albumItem->GetArt("thumb")))
354 CFileItemPtr item(new CFileItem("thumb://Current", false));
355 item->SetArt("thumb", m_albumItem->GetArt("thumb"));
356 item->SetLabel(g_localizeStrings.Get(20016));
360 // Grab the thumbnail(s) from the web
361 vector<CStdString> thumbs;
363 m_artist.thumbURL.GetThumbURLs(thumbs);
365 m_album.thumbURL.GetThumbURLs(thumbs);
367 for (unsigned int i = 0; i < thumbs.size(); ++i)
369 CStdString strItemPath;
370 strItemPath = StringUtils::Format("thumb://Remote%i", i);
371 CFileItemPtr item(new CFileItem(strItemPath, false));
372 item->SetArt("thumb", thumbs[i]);
373 item->SetIconImage("DefaultPicture.png");
374 item->SetLabel(g_localizeStrings.Get(20015));
376 // TODO: Do we need to clear the cached image?
377 // CTextureCache::Get().ClearCachedImage(thumb);
382 CStdString localThumb;
385 CMusicDatabase database;
387 CStdString strArtistPath;
388 if (database.GetArtistPath(m_artist.idArtist,strArtistPath))
389 localThumb = URIUtils::AddFileToFolder(strArtistPath, "folder.jpg");
392 localThumb = m_albumItem->GetUserMusicThumb();
393 if (CFile::Exists(localThumb))
395 CFileItemPtr item(new CFileItem("thumb://Local", false));
396 item->SetArt("thumb", localThumb);
397 item->SetLabel(g_localizeStrings.Get(20017));
402 CFileItemPtr item(new CFileItem("thumb://None", false));
404 item->SetIconImage("DefaultArtist.png");
406 item->SetIconImage("DefaultAlbumCover.png");
407 item->SetLabel(g_localizeStrings.Get(20018));
413 VECSOURCES sources(*CMediaSourceSettings::Get().GetSources("music"));
414 AddItemPathToFileBrowserSources(sources, *m_albumItem);
415 g_mediaManager.GetLocalDrives(sources);
416 if (!CGUIDialogFileBrowser::ShowAndGetImage(items, sources, g_localizeStrings.Get(1030), result, &flip))
417 return; // user cancelled
419 if (result == "thumb://Current")
420 return; // user chose the one they have
423 if (StringUtils::StartsWith(result, "thumb://Remote"))
425 int number = atoi(result.substr(14).c_str());
426 newThumb = thumbs[number];
428 else if (result == "thumb://Local")
429 newThumb = localThumb;
430 else if (CFile::Exists(result))
433 newThumb = "-"; // force local thumbs to be ignored
435 // update thumb in the database
439 db.SetArtForItem(m_albumItem->GetMusicInfoTag()->GetDatabaseId(), m_albumItem->GetMusicInfoTag()->GetType(), "thumb", newThumb);
443 m_albumItem->SetArt("thumb", newThumb);
444 m_hasUpdatedThumb = true;
446 // tell our GUI to completely reload all controls (as some of them
447 // are likely to have had this image in use so will need refreshing)
448 CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_REFRESH_THUMBS);
449 g_windowManager.SendMessage(msg);
455 // Allow user to select a Fanart
456 void CGUIDialogMusicInfo::OnGetFanart()
460 if (m_albumItem->HasArt("fanart"))
462 CFileItemPtr itemCurrent(new CFileItem("fanart://Current",false));
463 itemCurrent->SetArt("thumb", m_albumItem->GetArt("fanart"));
464 itemCurrent->SetLabel(g_localizeStrings.Get(20440));
465 items.Add(itemCurrent);
468 // Grab the thumbnails from the web
469 for (unsigned int i = 0; i < m_artist.fanart.GetNumFanarts(); i++)
471 CStdString strItemPath = StringUtils::Format("fanart://Remote%i",i);
472 CFileItemPtr item(new CFileItem(strItemPath, false));
473 CStdString thumb = m_artist.fanart.GetPreviewURL(i);
474 item->SetArt("thumb", CTextureUtils::GetWrappedThumbURL(thumb));
475 item->SetIconImage("DefaultPicture.png");
476 item->SetLabel(g_localizeStrings.Get(20441));
478 // TODO: Do we need to clear the cached image?
479 // CTextureCache::Get().ClearCachedImage(thumb);
483 // Grab a local thumb
484 CMusicDatabase database;
486 CStdString strArtistPath;
487 database.GetArtistPath(m_artist.idArtist,strArtistPath);
488 CFileItem item(strArtistPath,true);
489 CStdString strLocal = item.GetLocalFanart();
490 if (!strLocal.empty())
492 CFileItemPtr itemLocal(new CFileItem("fanart://Local",false));
493 itemLocal->SetArt("thumb", strLocal);
494 itemLocal->SetLabel(g_localizeStrings.Get(20438));
496 // TODO: Do we need to clear the cached image?
497 CTextureCache::Get().ClearCachedImage(strLocal);
498 items.Add(itemLocal);
502 CFileItemPtr itemNone(new CFileItem("fanart://None", false));
503 itemNone->SetIconImage("DefaultArtist.png");
504 itemNone->SetLabel(g_localizeStrings.Get(20439));
509 VECSOURCES sources = *CMediaSourceSettings::Get().GetSources("music");
510 g_mediaManager.GetLocalDrives(sources);
512 if (!CGUIDialogFileBrowser::ShowAndGetImage(items, sources, g_localizeStrings.Get(20437), result, &flip, 20445))
513 return; // user cancelled
515 // delete the thumbnail if that's what the user wants, else overwrite with the
517 if (result.Equals("fanart://Current"))
520 if (result.Equals("fanart://Local"))
523 if (StringUtils::StartsWith(result, "fanart://Remote"))
525 int iFanart = atoi(result.substr(15).c_str());
526 m_artist.fanart.SetPrimaryFanart(iFanart);
527 result = m_artist.fanart.GetImageURL();
529 else if (result.Equals("fanart://None") || !CFile::Exists(result))
532 if (flip && !result.empty())
533 result = CTextureUtils::GetWrappedImageURL(result, "", "flipped");
535 // update thumb in the database
539 db.SetArtForItem(m_albumItem->GetMusicInfoTag()->GetDatabaseId(), m_albumItem->GetMusicInfoTag()->GetType(), "fanart", result);
543 m_albumItem->SetArt("fanart", result);
544 m_hasUpdatedThumb = true;
545 // tell our GUI to completely reload all controls (as some of them
546 // are likely to have had this image in use so will need refreshing)
547 CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_REFRESH_THUMBS);
548 g_windowManager.SendMessage(msg);
553 void CGUIDialogMusicInfo::OnSearch(const CFileItem* pItem)
555 CMusicDatabase database;
557 if (pItem->HasMusicInfoTag() &&
558 pItem->GetMusicInfoTag()->GetDatabaseId() > 0)
561 if (database.GetAlbumInfo(pItem->GetMusicInfoTag()->GetDatabaseId(), album, &album.songs))
564 database.GetAlbumPath(pItem->GetMusicInfoTag()->GetDatabaseId(), strPath);
565 SetAlbum(album,strPath);
571 CFileItemPtr CGUIDialogMusicInfo::GetCurrentListItem(int offset)
576 void CGUIDialogMusicInfo::AddItemPathToFileBrowserSources(VECSOURCES &sources, const CFileItem &item)
580 if (item.HasMusicInfoTag() && item.GetMusicInfoTag()->GetType() == "song")
581 itemDir = URIUtils::GetParentPath(item.GetMusicInfoTag()->GetURL());
583 itemDir = item.GetPath();
585 if (!itemDir.empty() && CDirectory::Exists(itemDir))
587 CMediaSource itemSource;
588 itemSource.strName = g_localizeStrings.Get(36041);
589 itemSource.strPath = itemDir;
590 sources.push_back(itemSource);