[cstdstring] demise Format, replacing with StringUtils::Format
[vuplus_xbmc] / xbmc / music / dialogs / GUIDialogMusicInfo.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 "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"
28 #include "URL.h"
29 #include "filesystem/File.h"
30 #include "FileItem.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"
45
46 using namespace std;
47 using namespace XFILE;
48
49 #define CONTROL_IMAGE            3
50 #define CONTROL_TEXTAREA         4
51
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
56
57 #define CONTROL_LIST            50
58
59 CGUIDialogMusicInfo::CGUIDialogMusicInfo(void)
60     : CGUIDialog(WINDOW_DIALOG_MUSIC_INFO, "DialogAlbumInfo.xml")
61     , m_albumItem(new CFileItem)
62 {
63   m_bRefresh = false;
64   m_albumSongs = new CFileItemList;
65   m_loadType = KEEP_IN_MEMORY;
66 }
67
68 CGUIDialogMusicInfo::~CGUIDialogMusicInfo(void)
69 {
70   delete m_albumSongs;
71 }
72
73 bool CGUIDialogMusicInfo::OnMessage(CGUIMessage& message)
74 {
75   switch ( message.GetMessage() )
76   {
77   case GUI_MSG_WINDOW_DEINIT:
78     {
79       CGUIMessage message(GUI_MSG_LABEL_RESET, GetID(), CONTROL_LIST);
80       OnMessage(message);
81       m_albumSongs->Clear();
82     }
83     break;
84
85   case GUI_MSG_WINDOW_INIT:
86     {
87       CGUIDialog::OnMessage(message);
88       m_bViewReview = true;
89       m_bRefresh = false;
90       Update();
91       return true;
92     }
93     break;
94
95
96   case GUI_MSG_CLICKED:
97     {
98       int iControl = message.GetSenderId();
99       if (iControl == CONTROL_BTN_REFRESH)
100       {
101         m_bRefresh = true;
102         Close();
103         return true;
104       }
105       else if (iControl == CONTROL_BTN_GET_THUMB)
106       {
107         OnGetThumb();
108       }
109       else if (iControl == CONTROL_BTN_TRACKS)
110       {
111         m_bViewReview = !m_bViewReview;
112         Update();
113       }
114       else if (iControl == CONTROL_LIST)
115       {
116         int iAction = message.GetParam1();
117         if (m_bArtistInfo && (ACTION_SELECT_ITEM == iAction || ACTION_MOUSE_LEFT_CLICK == iAction))
118         {
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())
123             break;
124           CFileItemPtr item = m_albumSongs->Get(iItem);
125           OnSearch(item.get());
126           return true;
127         }
128       }
129       else if (iControl == CONTROL_BTN_GET_FANART)
130       {
131         OnGetFanart();
132       }
133     }
134     break;
135   }
136
137   return CGUIDialog::OnMessage(message);
138 }
139
140 bool CGUIDialogMusicInfo::OnAction(const CAction &action)
141 {
142   if (action.GetID() == ACTION_SHOW_INFO)
143   {
144     Close();
145     return true;
146   }
147   return CGUIDialog::OnAction(action);
148 }
149
150 void CGUIDialogMusicInfo::SetAlbum(const CAlbum& album, const CStdString &path)
151 {
152   m_album = album;
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);
164
165   CMusicThumbLoader loader;
166   loader.LoadItem(m_albumItem.get());
167
168   // set the artist thumb, fanart
169   if (!m_album.artist.empty())
170   {
171     CMusicDatabase db;
172     db.Open();
173     map<string, string> artwork;
174     if (db.GetArtistArtForItem(m_album.idAlbum, "album", artwork))
175     {
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"]);
180     }
181   }
182   m_hasUpdatedThumb = false;
183   m_bArtistInfo = false;
184   m_albumSongs->SetContent("albums");
185 }
186
187 void CGUIDialogMusicInfo::SetArtist(const CArtist& artist, const CStdString &path)
188 {
189   m_artist = artist;
190   SetDiscography();
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);
199
200   CMusicThumbLoader loader;
201   loader.LoadItem(m_albumItem.get());
202
203   m_hasUpdatedThumb = false;
204   m_bArtistInfo = true;
205   m_albumSongs->SetContent("artists");
206 }
207
208 void CGUIDialogMusicInfo::SetSongs(const VECSONGS &songs)
209 {
210   m_albumSongs->Clear();
211   for (unsigned int i = 0; i < songs.size(); i++)
212   {
213     const CSong& song = songs[i];
214     CFileItemPtr item(new CFileItem(song));
215     m_albumSongs->Add(item);
216   }
217 }
218
219 void CGUIDialogMusicInfo::SetDiscography()
220 {
221   m_albumSongs->Clear();
222   CMusicDatabase database;
223   database.Open();
224
225   for (unsigned int i=0;i<m_artist.discography.size();++i)
226   {
227     CFileItemPtr item(new CFileItem(m_artist.discography[i].first));
228     item->SetLabel2(m_artist.discography[i].second);
229     long idAlbum = database.GetAlbumByName(item->GetLabel(),m_artist.strArtist);
230
231     if (idAlbum != -1) // we need this slight stupidity to get correct case for the album name
232       item->SetArt("thumb", database.GetArtForItem(idAlbum, "album", "thumb"));
233     else
234       item->SetArt("thumb", "DefaultAlbumCover.png");
235
236     m_albumSongs->Add(item);
237   }
238 }
239
240 void CGUIDialogMusicInfo::Update()
241 {
242   if (m_bArtistInfo)
243   {
244     CONTROL_ENABLE(CONTROL_BTN_GET_FANART);
245
246     SetLabel(CONTROL_TEXTAREA, m_artist.strBiography);
247     CGUIMessage message(GUI_MSG_LABEL_BIND, GetID(), CONTROL_LIST, 0, 0, m_albumSongs);
248     OnMessage(message);
249
250     if (GetControl(CONTROL_BTN_TRACKS)) // if no CONTROL_BTN_TRACKS found - allow skinner full visibility control over CONTROL_TEXTAREA and CONTROL_LIST
251     {
252       if (m_bViewReview)
253       {
254         SET_CONTROL_VISIBLE(CONTROL_TEXTAREA);
255         SET_CONTROL_HIDDEN(CONTROL_LIST);
256         SET_CONTROL_LABEL(CONTROL_BTN_TRACKS, 21888);
257       }
258       else
259       {
260         SET_CONTROL_VISIBLE(CONTROL_LIST);
261         SET_CONTROL_HIDDEN(CONTROL_TEXTAREA);
262         SET_CONTROL_LABEL(CONTROL_BTN_TRACKS, 21887);
263       }
264     }
265   }
266   else
267   {
268     CONTROL_DISABLE(CONTROL_BTN_GET_FANART);
269
270     SetLabel(CONTROL_TEXTAREA, m_album.strReview);
271     CGUIMessage message(GUI_MSG_LABEL_BIND, GetID(), CONTROL_LIST, 0, 0, m_albumSongs);
272     OnMessage(message);
273
274     if (GetControl(CONTROL_BTN_TRACKS)) // if no CONTROL_BTN_TRACKS found - allow skinner full visibility control over CONTROL_TEXTAREA and CONTROL_LIST
275     {
276       if (m_bViewReview)
277       {
278         SET_CONTROL_VISIBLE(CONTROL_TEXTAREA);
279         SET_CONTROL_HIDDEN(CONTROL_LIST);
280         SET_CONTROL_LABEL(CONTROL_BTN_TRACKS, 182);
281       }
282       else
283       {
284         SET_CONTROL_VISIBLE(CONTROL_LIST);
285         SET_CONTROL_HIDDEN(CONTROL_TEXTAREA);
286         SET_CONTROL_LABEL(CONTROL_BTN_TRACKS, 183);
287       }
288     }
289   }
290   // update the thumbnail
291   const CGUIControl* pControl = GetControl(CONTROL_IMAGE);
292   if (pControl)
293   {
294     CGUIImage* pImageControl = (CGUIImage*)pControl;
295     pImageControl->FreeResources();
296     pImageControl->SetFileName(m_albumItem->GetArt("thumb"));
297   }
298
299   // disable the GetThumb button if the user isn't allowed it
300   CONTROL_ENABLE_ON_CONDITION(CONTROL_BTN_GET_THUMB, CProfilesManager::Get().GetCurrentProfile().canWriteDatabases() || g_passwordManager.bMasterUser);
301 }
302
303 void CGUIDialogMusicInfo::SetLabel(int iControl, const CStdString& strLabel)
304 {
305   if (strLabel.IsEmpty())
306   {
307     SET_CONTROL_LABEL(iControl, (iControl == CONTROL_TEXTAREA) ? (m_bArtistInfo?547:414) : 416);
308   }
309   else
310   {
311     SET_CONTROL_LABEL(iControl, strLabel);
312   }
313 }
314
315 bool CGUIDialogMusicInfo::NeedRefresh() const
316 {
317   return m_bRefresh;
318 }
319
320 void CGUIDialogMusicInfo::OnInitWindow()
321 {
322   CGUIDialog::OnInitWindow();
323 }
324
325 // Get Thumb from user choice.
326 // Options are:
327 // 1.  Current thumb
328 // 2.  AllMusic.com thumb
329 // 3.  Local thumb
330 // 4.  No thumb (if no Local thumb is available)
331
332 // TODO: Currently no support for "embedded thumb" as there is no easy way to grab it
333 //       without sending a file that has this as it's album to this class
334 void CGUIDialogMusicInfo::OnGetThumb()
335 {
336   CFileItemList items;
337
338   // Current thumb
339   if (CFile::Exists(m_albumItem->GetArt("thumb")))
340   {
341     CFileItemPtr item(new CFileItem("thumb://Current", false));
342     item->SetArt("thumb", m_albumItem->GetArt("thumb"));
343     item->SetLabel(g_localizeStrings.Get(20016));
344     items.Add(item);
345   }
346
347   // Grab the thumbnail(s) from the web
348   vector<CStdString> thumbs;
349   if (m_bArtistInfo)
350     m_artist.thumbURL.GetThumbURLs(thumbs);
351   else
352     m_album.thumbURL.GetThumbURLs(thumbs);
353
354   for (unsigned int i = 0; i < thumbs.size(); ++i)
355   {
356     CStdString strItemPath;
357     strItemPath = StringUtils::Format("thumb://Remote%i", i);
358     CFileItemPtr item(new CFileItem(strItemPath, false));
359     item->SetArt("thumb", thumbs[i]);
360     item->SetIconImage("DefaultPicture.png");
361     item->SetLabel(g_localizeStrings.Get(20015));
362     
363     // TODO: Do we need to clear the cached image?
364     //    CTextureCache::Get().ClearCachedImage(thumb);
365     items.Add(item);
366   }
367
368   // local thumb
369   CStdString localThumb;
370   if (m_bArtistInfo)
371   {
372     CMusicDatabase database;
373     database.Open();
374     CStdString strArtistPath;
375     if (database.GetArtistPath(m_artist.idArtist,strArtistPath))
376       localThumb = URIUtils::AddFileToFolder(strArtistPath, "folder.jpg");
377   }
378   else
379     localThumb = m_albumItem->GetUserMusicThumb();
380   if (CFile::Exists(localThumb))
381   {
382     CFileItemPtr item(new CFileItem("thumb://Local", false));
383     item->SetArt("thumb", localThumb);
384     item->SetLabel(g_localizeStrings.Get(20017));
385     items.Add(item);
386   }
387   else
388   {
389     CFileItemPtr item(new CFileItem("thumb://None", false));
390     if (m_bArtistInfo)
391       item->SetIconImage("DefaultArtist.png");
392     else
393       item->SetIconImage("DefaultAlbumCover.png");
394     item->SetLabel(g_localizeStrings.Get(20018));
395     items.Add(item);
396   }
397
398   CStdString result;
399   bool flip=false;
400   VECSOURCES sources(*CMediaSourceSettings::Get().GetSources("music"));
401   AddItemPathToFileBrowserSources(sources, *m_albumItem);
402   g_mediaManager.GetLocalDrives(sources);
403   if (!CGUIDialogFileBrowser::ShowAndGetImage(items, sources, g_localizeStrings.Get(1030), result, &flip))
404     return;   // user cancelled
405
406   if (result == "thumb://Current")
407     return;   // user chose the one they have
408
409   CStdString newThumb;
410   if (result.Left(14) == "thumb://Remote")
411   {
412     int number = atoi(result.Mid(14));
413     newThumb = thumbs[number];
414   }
415   else if (result == "thumb://Local")
416     newThumb = localThumb;
417   else if (CFile::Exists(result))
418     newThumb = result;
419   else // none
420     newThumb = "-"; // force local thumbs to be ignored
421
422   // update thumb in the database
423   CMusicDatabase db;
424   if (db.Open())
425   {
426     db.SetArtForItem(m_albumItem->GetMusicInfoTag()->GetDatabaseId(), m_albumItem->GetMusicInfoTag()->GetType(), "thumb", newThumb);
427     db.Close();
428   }
429
430   m_albumItem->SetArt("thumb", newThumb);
431   m_hasUpdatedThumb = true;
432
433   // tell our GUI to completely reload all controls (as some of them
434   // are likely to have had this image in use so will need refreshing)
435   CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_REFRESH_THUMBS);
436   g_windowManager.SendMessage(msg);
437   // Update our screen
438   Update();
439 }
440
441
442 // Allow user to select a Fanart
443 void CGUIDialogMusicInfo::OnGetFanart()
444 {
445   CFileItemList items;
446
447   if (m_albumItem->HasArt("fanart"))
448   {
449     CFileItemPtr itemCurrent(new CFileItem("fanart://Current",false));
450     itemCurrent->SetArt("thumb", m_albumItem->GetArt("fanart"));
451     itemCurrent->SetLabel(g_localizeStrings.Get(20440));
452     items.Add(itemCurrent);
453   }
454
455   // Grab the thumbnails from the web
456   for (unsigned int i = 0; i < m_artist.fanart.GetNumFanarts(); i++)
457   {
458     CStdString strItemPath = StringUtils::Format("fanart://Remote%i",i);
459     CFileItemPtr item(new CFileItem(strItemPath, false));
460     CStdString thumb = m_artist.fanart.GetPreviewURL(i);
461     item->SetArt("thumb", CTextureUtils::GetWrappedThumbURL(thumb));
462     item->SetIconImage("DefaultPicture.png");
463     item->SetLabel(g_localizeStrings.Get(20441));
464
465     // TODO: Do we need to clear the cached image?
466     //    CTextureCache::Get().ClearCachedImage(thumb);
467     items.Add(item);
468   }
469
470   // Grab a local thumb
471   CMusicDatabase database;
472   database.Open();
473   CStdString strArtistPath;
474   database.GetArtistPath(m_artist.idArtist,strArtistPath);
475   CFileItem item(strArtistPath,true);
476   CStdString strLocal = item.GetLocalFanart();
477   if (!strLocal.IsEmpty())
478   {
479     CFileItemPtr itemLocal(new CFileItem("fanart://Local",false));
480     itemLocal->SetArt("thumb", strLocal);
481     itemLocal->SetLabel(g_localizeStrings.Get(20438));
482
483     // TODO: Do we need to clear the cached image?
484     CTextureCache::Get().ClearCachedImage(strLocal);
485     items.Add(itemLocal);
486   }
487   else
488   {
489     CFileItemPtr itemNone(new CFileItem("fanart://None", false));
490     itemNone->SetIconImage("DefaultArtist.png");
491     itemNone->SetLabel(g_localizeStrings.Get(20439));
492     items.Add(itemNone);
493   }
494
495   CStdString result;
496   VECSOURCES sources = *CMediaSourceSettings::Get().GetSources("music");
497   g_mediaManager.GetLocalDrives(sources);
498   bool flip=false;
499   if (!CGUIDialogFileBrowser::ShowAndGetImage(items, sources, g_localizeStrings.Get(20437), result, &flip, 20445))
500     return;   // user cancelled
501
502   // delete the thumbnail if that's what the user wants, else overwrite with the
503   // new thumbnail
504   if (result.Equals("fanart://Current"))
505    return;
506
507   if (result.Equals("fanart://Local"))
508     result = strLocal;
509
510   if (result.Left(15)  == "fanart://Remote")
511   {
512     int iFanart = atoi(result.Mid(15).c_str());
513     m_artist.fanart.SetPrimaryFanart(iFanart);
514     result = m_artist.fanart.GetImageURL();
515   }
516   else if (result.Equals("fanart://None") || !CFile::Exists(result))
517     result.clear();
518
519   if (flip && !result.empty())
520     result = CTextureUtils::GetWrappedImageURL(result, "", "flipped");
521
522   // update thumb in the database
523   CMusicDatabase db;
524   if (db.Open())
525   {
526     db.SetArtForItem(m_albumItem->GetMusicInfoTag()->GetDatabaseId(), m_albumItem->GetMusicInfoTag()->GetType(), "fanart", result);
527     db.Close();
528   }
529
530   m_albumItem->SetArt("fanart", result);
531   m_hasUpdatedThumb = true;
532   // tell our GUI to completely reload all controls (as some of them
533   // are likely to have had this image in use so will need refreshing)
534   CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_REFRESH_THUMBS);
535   g_windowManager.SendMessage(msg);
536   // Update our screen
537   Update();
538 }
539
540 void CGUIDialogMusicInfo::OnSearch(const CFileItem* pItem)
541 {
542   CMusicDatabase database;
543   database.Open();
544   long idAlbum = database.GetAlbumByName(pItem->GetLabel(),m_artist.strArtist);
545   if (idAlbum != -1)
546   {
547     CAlbum album;
548     if (database.GetAlbumInfo(idAlbum,album,&album.songs))
549     {
550       CStdString strPath;
551       database.GetAlbumPath(idAlbum,strPath);
552       SetAlbum(album,strPath);
553       Update();
554     }
555   }
556 }
557
558 CFileItemPtr CGUIDialogMusicInfo::GetCurrentListItem(int offset)
559 {
560   return m_albumItem;
561 }
562
563 void CGUIDialogMusicInfo::AddItemPathToFileBrowserSources(VECSOURCES &sources, const CFileItem &item)
564 {
565   CStdString itemDir;
566
567   if (item.HasMusicInfoTag() && item.GetMusicInfoTag()->GetType() == "song")
568     itemDir = URIUtils::GetParentPath(item.GetMusicInfoTag()->GetURL());
569   else
570     itemDir = item.GetPath();
571
572   if (!itemDir.IsEmpty() && CDirectory::Exists(itemDir))
573   {
574     CMediaSource itemSource;
575     itemSource.strName = g_localizeStrings.Get(36041);
576     itemSource.strPath = itemDir;
577     sources.push_back(itemSource);
578   }
579 }