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 "GUIDialogVideoInfo.h"
22 #include "Application.h"
23 #include "guilib/GUIWindow.h"
25 #include "guilib/GUIImage.h"
26 #include "utils/StringUtils.h"
27 #include "utils/URIUtils.h"
28 #include "video/windows/GUIWindowVideoNav.h"
29 #include "dialogs/GUIDialogFileBrowser.h"
30 #include "video/VideoInfoScanner.h"
31 #include "ApplicationMessenger.h"
32 #include "video/VideoInfoTag.h"
33 #include "guilib/GUIKeyboardFactory.h"
34 #include "guilib/GUIWindowManager.h"
35 #include "dialogs/GUIDialogOK.h"
36 #include "dialogs/GUIDialogYesNo.h"
37 #include "dialogs/GUIDialogSelect.h"
38 #include "dialogs/GUIDialogProgress.h"
39 #include "filesystem/File.h"
41 #include "storage/MediaManager.h"
42 #include "utils/AsyncFileCopy.h"
43 #include "profiles/ProfilesManager.h"
44 #include "settings/AdvancedSettings.h"
45 #include "settings/MediaSourceSettings.h"
46 #include "settings/Settings.h"
47 #include "guilib/Key.h"
48 #include "guilib/LocalizeStrings.h"
49 #include "GUIUserMessages.h"
50 #include "TextureCache.h"
51 #include "music/MusicDatabase.h"
53 #include "video/VideoThumbLoader.h"
54 #include "filesystem/Directory.h"
55 #include "filesystem/VideoDatabaseDirectory.h"
56 #include "filesystem/VideoDatabaseDirectory/QueryParams.h"
58 #include "network/upnp/UPnP.h"
60 #include "utils/FileUtils.h"
63 using namespace XFILE::VIDEODATABASEDIRECTORY;
64 using namespace XFILE;
66 #define CONTROL_IMAGE 3
67 #define CONTROL_TEXTAREA 4
68 #define CONTROL_BTN_TRACKS 5
69 #define CONTROL_BTN_REFRESH 6
70 #define CONTROL_BTN_PLAY 8
71 #define CONTROL_BTN_RESUME 9
72 #define CONTROL_BTN_GET_THUMB 10
73 #define CONTROL_BTN_PLAY_TRAILER 11
74 #define CONTROL_BTN_GET_FANART 12
75 #define CONTROL_BTN_DIRECTOR 13
77 #define CONTROL_LIST 50
79 CGUIDialogVideoInfo::CGUIDialogVideoInfo(void)
80 : CGUIDialog(WINDOW_DIALOG_VIDEO_INFO, "DialogVideoInfo.xml")
81 , m_movieItem(new CFileItem)
85 m_hasUpdatedThumb = false;
86 m_castList = new CFileItemList;
87 m_loadType = KEEP_IN_MEMORY;
90 CGUIDialogVideoInfo::~CGUIDialogVideoInfo(void)
95 bool CGUIDialogVideoInfo::OnMessage(CGUIMessage& message)
97 switch ( message.GetMessage() )
99 case GUI_MSG_WINDOW_DEINIT:
105 case GUI_MSG_CLICKED:
107 int iControl = message.GetSenderId();
108 if (iControl == CONTROL_BTN_REFRESH)
110 if (m_movieItem->GetVideoInfoTag()->m_iSeason < 0 && !m_movieItem->GetVideoInfoTag()->m_strShowTitle.empty()) // tv show
112 bool bCanceled=false;
113 if (CGUIDialogYesNo::ShowAndGetInput(20377,20378,-1,-1,bCanceled))
115 m_bRefreshAll = true;
119 db.SetPathHash(m_movieItem->GetVideoInfoTag()->m_strPath,"");
124 m_bRefreshAll = false;
133 else if (iControl == CONTROL_BTN_TRACKS)
135 m_bViewReview = !m_bViewReview;
138 else if (iControl == CONTROL_BTN_PLAY)
142 else if (iControl == CONTROL_BTN_RESUME)
146 else if (iControl == CONTROL_BTN_GET_THUMB)
150 else if (iControl == CONTROL_BTN_PLAY_TRAILER)
154 else if (iControl == CONTROL_BTN_GET_FANART)
158 else if (iControl == CONTROL_BTN_DIRECTOR)
160 CStdString strDirector = StringUtils::Join(m_movieItem->GetVideoInfoTag()->m_director, g_advancedSettings.m_videoItemSeparator);
161 OnSearch(strDirector);
163 else if (iControl == CONTROL_LIST)
165 int iAction = message.GetParam1();
166 if (ACTION_SELECT_ITEM == iAction || ACTION_MOUSE_LEFT_CLICK == iAction)
168 CGUIMessage msg(GUI_MSG_ITEM_SELECTED, GetID(), iControl);
170 int iItem = msg.GetParam1();
171 if (iItem < 0 || iItem >= m_castList->Size())
173 CStdString strItem = m_castList->Get(iItem)->GetLabel();
174 CStdString strFind = StringUtils::Format(" %s ",g_localizeStrings.Get(20347).c_str());
175 size_t iPos = strItem.find(strFind);
176 if (iPos == std::string::npos)
177 iPos = strItem.size();
178 CStdString tmp = strItem.substr(0, iPos);
184 case GUI_MSG_NOTIFY_ALL:
186 if (IsActive() && message.GetParam1() == GUI_MSG_UPDATE_ITEM && message.GetItem())
188 CFileItemPtr item = boost::static_pointer_cast<CFileItem>(message.GetItem());
189 if (item && m_movieItem->GetPath().Equals(item->GetPath()))
190 { // Just copy over the stream details and the thumb if we don't already have one
191 if (!m_movieItem->HasArt("thumb"))
192 m_movieItem->SetArt("thumb", item->GetArt("thumb"));
193 m_movieItem->GetVideoInfoTag()->m_streamDetails = item->GetVideoInfoTag()->m_streamDetails;
200 return CGUIDialog::OnMessage(message);
203 void CGUIDialogVideoInfo::OnInitWindow()
206 m_bRefreshAll = true;
207 m_hasUpdatedThumb = false;
208 m_bViewReview = true;
210 CVideoDatabase database;
211 ADDON::ScraperPtr scraper;
215 scraper = database.GetScraperForPath(m_movieItem->GetVideoInfoTag()->GetPath());
219 CONTROL_ENABLE_ON_CONDITION(CONTROL_BTN_REFRESH, (CProfilesManager::Get().GetCurrentProfile().canWriteDatabases() || g_passwordManager.bMasterUser) && !StringUtils::StartsWithNoCase(m_movieItem->GetVideoInfoTag()->m_strIMDBNumber, "xx") && scraper);
220 CONTROL_ENABLE_ON_CONDITION(CONTROL_BTN_GET_THUMB, (CProfilesManager::Get().GetCurrentProfile().canWriteDatabases() || g_passwordManager.bMasterUser) && !StringUtils::StartsWithNoCase(m_movieItem->GetVideoInfoTag()->m_strIMDBNumber.c_str() + 2, "plugin"));
222 VIDEODB_CONTENT_TYPE type = (VIDEODB_CONTENT_TYPE)m_movieItem->GetVideoContentType();
223 if (type == VIDEODB_CONTENT_TVSHOWS || type == VIDEODB_CONTENT_MOVIES)
224 CONTROL_ENABLE_ON_CONDITION(CONTROL_BTN_GET_FANART, (CProfilesManager::Get().GetCurrentProfile().canWriteDatabases() || g_passwordManager.bMasterUser) && !StringUtils::StartsWithNoCase(m_movieItem->GetVideoInfoTag()->m_strIMDBNumber.c_str() + 2, "plugin"));
226 CONTROL_DISABLE(CONTROL_BTN_GET_FANART);
230 CGUIDialog::OnInitWindow();
233 bool CGUIDialogVideoInfo::OnAction(const CAction &action)
235 if (action.GetID() == ACTION_SHOW_INFO)
240 return CGUIDialog::OnAction(action);
243 void CGUIDialogVideoInfo::SetMovie(const CFileItem *item)
245 *m_movieItem = *item;
246 // setup cast list + determine type. We need to do this here as it makes
247 // sure that content type (among other things) is set correctly for the
248 // old fixed id labels that we have floating around (they may be using
249 // content type to determine visibility, so we'll set the wrong label)
251 VIDEODB_CONTENT_TYPE type = (VIDEODB_CONTENT_TYPE)m_movieItem->GetVideoContentType();
252 if (type == VIDEODB_CONTENT_MUSICVIDEOS)
254 CMusicDatabase database;
256 const std::vector<std::string> &artists = m_movieItem->GetVideoInfoTag()->m_artist;
257 for (std::vector<std::string>::const_iterator it = artists.begin(); it != artists.end(); ++it)
259 int idArtist = database.GetArtistByName(*it);
260 CStdString thumb = database.GetArtForItem(idArtist, "artist", "thumb");
261 CFileItemPtr item(new CFileItem(*it));
263 item->SetArt("thumb", thumb);
264 item->SetIconImage("DefaultArtist.png");
265 m_castList->Add(item);
267 m_castList->SetContent("musicvideos");
270 { // movie/show/episode
271 for (CVideoInfoTag::iCast it = m_movieItem->GetVideoInfoTag()->m_cast.begin(); it != m_movieItem->GetVideoInfoTag()->m_cast.end(); ++it)
273 CStdString character;
274 if (it->strRole.empty())
275 character = it->strName;
277 character = StringUtils::Format("%s %s %s", it->strName.c_str(), g_localizeStrings.Get(20347).c_str(), it->strRole.c_str());
278 CFileItemPtr item(new CFileItem(it->strName));
279 if (!it->thumb.empty())
280 item->SetArt("thumb", it->thumb);
281 else if (CSettings::Get().GetBool("videolibrary.actorthumbs"))
282 { // backward compatibility
283 CStdString thumb = CScraperUrl::GetThumbURL(it->thumbUrl.GetFirstThumb());
286 item->SetArt("thumb", thumb);
287 CTextureCache::Get().BackgroundCacheImage(thumb);
290 item->SetIconImage("DefaultActor.png");
291 item->SetLabel(character);
292 m_castList->Add(item);
295 if (type == VIDEODB_CONTENT_TVSHOWS)
297 m_castList->SetContent("tvshows");
298 // special case stuff for shows (not currently retrieved from the library in filemode (ref: GetTvShowInfo vs GetTVShowsByWhere)
299 m_movieItem->m_dateTime = m_movieItem->GetVideoInfoTag()->m_premiered;
300 if(m_movieItem->GetVideoInfoTag()->m_iYear == 0 && m_movieItem->m_dateTime.IsValid())
301 m_movieItem->GetVideoInfoTag()->m_iYear = m_movieItem->m_dateTime.GetYear();
302 m_movieItem->SetProperty("totalepisodes", m_movieItem->GetVideoInfoTag()->m_iEpisode);
303 m_movieItem->SetProperty("numepisodes", m_movieItem->GetVideoInfoTag()->m_iEpisode); // info view has no concept of current watched/unwatched filter as we could come here from files view, but set for consistency
304 m_movieItem->SetProperty("watchedepisodes", m_movieItem->GetVideoInfoTag()->m_playCount);
305 m_movieItem->SetProperty("unwatchedepisodes", m_movieItem->GetVideoInfoTag()->m_iEpisode - m_movieItem->GetVideoInfoTag()->m_playCount);
306 m_movieItem->GetVideoInfoTag()->m_playCount = (m_movieItem->GetVideoInfoTag()->m_iEpisode == m_movieItem->GetVideoInfoTag()->m_playCount) ? 1 : 0;
308 else if (type == VIDEODB_CONTENT_EPISODES)
310 m_castList->SetContent("episodes");
311 // special case stuff for episodes (not currently retrieved from the library in filemode (ref: GetEpisodeInfo vs GetEpisodesByWhere)
312 m_movieItem->m_dateTime = m_movieItem->GetVideoInfoTag()->m_firstAired;
313 if(m_movieItem->GetVideoInfoTag()->m_iYear == 0 && m_movieItem->m_dateTime.IsValid())
314 m_movieItem->GetVideoInfoTag()->m_iYear = m_movieItem->m_dateTime.GetYear();
315 // retrieve the season thumb.
316 // TODO: should we use the thumbloader for this?
320 if (m_movieItem->GetVideoInfoTag()->m_iSeason > -1)
322 int seasonID = m_movieItem->GetVideoInfoTag()->m_iIdSeason;
324 seasonID = db.GetSeasonId(m_movieItem->GetVideoInfoTag()->m_iIdShow,
325 m_movieItem->GetVideoInfoTag()->m_iSeason);
326 CGUIListItem::ArtMap thumbs;
327 if (db.GetArtForItem(seasonID, "season", thumbs))
329 for (CGUIListItem::ArtMap::iterator i = thumbs.begin(); i != thumbs.end(); i++)
330 m_movieItem->SetArt("season." + i->first, i->second);
336 else if (type == VIDEODB_CONTENT_MOVIES)
338 m_castList->SetContent("movies");
340 // local trailers should always override non-local, so check
341 // for a local one if the registered trailer is online
342 if (m_movieItem->GetVideoInfoTag()->m_strTrailer.empty() ||
343 URIUtils::IsInternetStream(m_movieItem->GetVideoInfoTag()->m_strTrailer))
345 CStdString localTrailer = m_movieItem->FindTrailer();
346 if (!localTrailer.empty())
348 m_movieItem->GetVideoInfoTag()->m_strTrailer = localTrailer;
349 CVideoDatabase database;
352 database.SetSingleValue(VIDEODB_CONTENT_MOVIES, VIDEODB_ID_TRAILER,
353 m_movieItem->GetVideoInfoTag()->m_iDbId,
354 m_movieItem->GetVideoInfoTag()->m_strTrailer);
356 CUtil::DeleteVideoDatabaseDirectoryCache();
362 CVideoThumbLoader loader;
363 loader.LoadItem(m_movieItem.get());
366 void CGUIDialogVideoInfo::Update()
368 // setup plot text area
369 CStdString strTmp = m_movieItem->GetVideoInfoTag()->m_strPlot;
370 if (!(!m_movieItem->GetVideoInfoTag()->m_strShowTitle.empty() && m_movieItem->GetVideoInfoTag()->m_iSeason == 0)) // dont apply to tvshows
371 if (m_movieItem->GetVideoInfoTag()->m_playCount == 0 && !CSettings::Get().GetBool("videolibrary.showunwatchedplots"))
372 strTmp = g_localizeStrings.Get(20370);
374 StringUtils::Trim(strTmp);
375 SetLabel(CONTROL_TEXTAREA, strTmp);
377 CGUIMessage msg(GUI_MSG_LABEL_BIND, GetID(), CONTROL_LIST, 0, 0, m_castList);
380 if (GetControl(CONTROL_BTN_TRACKS)) // if no CONTROL_BTN_TRACKS found - allow skinner full visibility control over CONTROL_TEXTAREA and CONTROL_LIST
384 if (!m_movieItem->GetVideoInfoTag()->m_artist.empty())
386 SET_CONTROL_LABEL(CONTROL_BTN_TRACKS, 133);
390 SET_CONTROL_LABEL(CONTROL_BTN_TRACKS, 206);
393 SET_CONTROL_HIDDEN(CONTROL_LIST);
394 SET_CONTROL_VISIBLE(CONTROL_TEXTAREA);
398 SET_CONTROL_LABEL(CONTROL_BTN_TRACKS, 207);
400 SET_CONTROL_HIDDEN(CONTROL_TEXTAREA);
401 SET_CONTROL_VISIBLE(CONTROL_LIST);
405 // Check for resumability
406 if (m_movieItem->GetVideoInfoTag()->m_resumePoint.timeInSeconds > 0.0)
407 CONTROL_ENABLE(CONTROL_BTN_RESUME);
409 CONTROL_DISABLE(CONTROL_BTN_RESUME);
411 CONTROL_ENABLE(CONTROL_BTN_PLAY);
413 // update the thumbnail
414 const CGUIControl* pControl = GetControl(CONTROL_IMAGE);
417 CGUIImage* pImageControl = (CGUIImage*)pControl;
418 pImageControl->FreeResources();
419 pImageControl->SetFileName(m_movieItem->GetArt("thumb"));
421 // tell our GUI to completely reload all controls (as some of them
422 // are likely to have had this image in use so will need refreshing)
423 if (m_hasUpdatedThumb)
425 CGUIMessage reload(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_REFRESH_THUMBS);
426 g_windowManager.SendMessage(reload);
430 bool CGUIDialogVideoInfo::NeedRefresh() const
435 bool CGUIDialogVideoInfo::RefreshAll() const
437 return m_bRefreshAll;
440 /// \brief Search the current directory for a string got from the virtual keyboard
441 void CGUIDialogVideoInfo::OnSearch(CStdString& strSearch)
443 CGUIDialogProgress *progress = (CGUIDialogProgress *)g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS);
446 progress->SetHeading(194);
447 progress->SetLine(0, strSearch);
448 progress->SetLine(1, "");
449 progress->SetLine(2, "");
450 progress->StartModal();
451 progress->Progress();
454 DoSearch(strSearch, items);
461 CGUIDialogSelect* pDlgSelect = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
463 pDlgSelect->SetHeading(283);
465 for (int i = 0; i < (int)items.Size(); i++)
467 CFileItemPtr pItem = items[i];
468 pDlgSelect->Add(pItem->GetLabel());
471 pDlgSelect->DoModal();
473 int iItem = pDlgSelect->GetSelectedLabel();
477 CFileItem* pSelItem = new CFileItem(*items[iItem]);
479 OnSearchItemFound(pSelItem);
485 CGUIDialogOK::ShowAndGetInput(194, 284, 0, 0);
489 /// \brief Make the actual search for the OnSearch function.
490 /// \param strSearch The search string
491 /// \param items Items Found
492 void CGUIDialogVideoInfo::DoSearch(CStdString& strSearch, CFileItemList& items)
498 CFileItemList movies;
499 db.GetMoviesByActor(strSearch, movies);
500 for (int i = 0; i < movies.Size(); ++i)
502 CStdString label = movies[i]->GetVideoInfoTag()->m_strTitle;
503 if (movies[i]->GetVideoInfoTag()->m_iYear > 0)
504 label += StringUtils::Format(" (%i)", movies[i]->GetVideoInfoTag()->m_iYear);
505 movies[i]->SetLabel(label);
507 CGUIWindowVideoBase::AppendAndClearSearchItems(movies, "[" + g_localizeStrings.Get(20338) + "] ", items);
509 db.GetTvShowsByActor(strSearch, movies);
510 for (int i = 0; i < movies.Size(); ++i)
512 CStdString label = movies[i]->GetVideoInfoTag()->m_strShowTitle;
513 if (movies[i]->GetVideoInfoTag()->m_iYear > 0)
514 label += StringUtils::Format(" (%i)", movies[i]->GetVideoInfoTag()->m_iYear);
515 movies[i]->SetLabel(label);
517 CGUIWindowVideoBase::AppendAndClearSearchItems(movies, "[" + g_localizeStrings.Get(20364) + "] ", items);
519 db.GetEpisodesByActor(strSearch, movies);
520 for (int i = 0; i < movies.Size(); ++i)
522 CStdString label = movies[i]->GetVideoInfoTag()->m_strTitle + " (" + movies[i]->GetVideoInfoTag()->m_strShowTitle + ")";
523 movies[i]->SetLabel(label);
525 CGUIWindowVideoBase::AppendAndClearSearchItems(movies, "[" + g_localizeStrings.Get(20359) + "] ", items);
527 db.GetMusicVideosByArtist(strSearch, movies);
528 for (int i = 0; i < movies.Size(); ++i)
530 CStdString label = StringUtils::Join(movies[i]->GetVideoInfoTag()->m_artist, g_advancedSettings.m_videoItemSeparator) + " - " + movies[i]->GetVideoInfoTag()->m_strTitle;
531 if (movies[i]->GetVideoInfoTag()->m_iYear > 0)
532 label += StringUtils::Format(" (%i)", movies[i]->GetVideoInfoTag()->m_iYear);
533 movies[i]->SetLabel(label);
535 CGUIWindowVideoBase::AppendAndClearSearchItems(movies, "[" + g_localizeStrings.Get(20391) + "] ", items);
539 /// \brief React on the selected search item
540 /// \param pItem Search result item
541 void CGUIDialogVideoInfo::OnSearchItemFound(const CFileItem* pItem)
543 VIDEODB_CONTENT_TYPE type = (VIDEODB_CONTENT_TYPE)pItem->GetVideoContentType();
549 CVideoInfoTag movieDetails;
550 if (type == VIDEODB_CONTENT_MOVIES)
551 db.GetMovieInfo(pItem->GetPath(), movieDetails, pItem->GetVideoInfoTag()->m_iDbId);
552 if (type == VIDEODB_CONTENT_EPISODES)
553 db.GetEpisodeInfo(pItem->GetPath(), movieDetails, pItem->GetVideoInfoTag()->m_iDbId);
554 if (type == VIDEODB_CONTENT_TVSHOWS)
555 db.GetTvShowInfo(pItem->GetPath(), movieDetails, pItem->GetVideoInfoTag()->m_iDbId);
556 if (type == VIDEODB_CONTENT_MUSICVIDEOS)
557 db.GetMusicVideoInfo(pItem->GetPath(), movieDetails, pItem->GetVideoInfoTag()->m_iDbId);
560 CFileItem item(*pItem);
561 *item.GetVideoInfoTag() = movieDetails;
563 // refresh our window entirely
568 void CGUIDialogVideoInfo::ClearCastList()
570 CGUIMessage msg(GUI_MSG_LABEL_RESET, GetID(), CONTROL_LIST);
575 void CGUIDialogVideoInfo::Play(bool resume)
577 if (!m_movieItem->GetVideoInfoTag()->m_strEpisodeGuide.empty())
579 CStdString strPath = StringUtils::Format("videodb://tvshows/titles/%i/",m_movieItem->GetVideoInfoTag()->m_iDbId);
581 g_windowManager.ActivateWindow(WINDOW_VIDEO_NAV,strPath);
585 CFileItem movie(*m_movieItem->GetVideoInfoTag());
586 if (m_movieItem->GetVideoInfoTag()->m_strFileNameAndPath.empty())
587 movie.SetPath(m_movieItem->GetPath());
588 CGUIWindowVideoNav* pWindow = (CGUIWindowVideoNav*)g_windowManager.GetWindow(WINDOW_VIDEO_NAV);
594 movie.m_lStartOffset = STARTOFFSET_RESUME;
595 else if (!CGUIWindowVideoBase::ShowResumeMenu(movie))
597 // The Resume dialog was closed without any choice
601 pWindow->PlayMovie(&movie);
605 string CGUIDialogVideoInfo::ChooseArtType(const CFileItem &videoItem, map<string, string> ¤tArt)
608 CGUIDialogSelect *dialog = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
609 if (!dialog || !videoItem.HasVideoInfoTag())
613 dialog->SetHeading(13511);
615 dialog->SetUseDetails(true);
616 dialog->EnableButton(true, 13516);
621 vector<string> artTypes = CVideoThumbLoader::GetArtTypes(videoItem.GetVideoInfoTag()->m_type);
623 // add in any stored art for this item that is non-empty.
624 db.GetArtForItem(videoItem.GetVideoInfoTag()->m_iDbId, videoItem.GetVideoInfoTag()->m_type, currentArt);
625 for (CGUIListItem::ArtMap::iterator i = currentArt.begin(); i != currentArt.end(); ++i)
627 if (!i->second.empty() && find(artTypes.begin(), artTypes.end(), i->first) == artTypes.end())
628 artTypes.push_back(i->first);
631 // add any art types that exist for other media items of the same type
632 vector<string> dbArtTypes;
633 db.GetArtTypes(videoItem.GetVideoInfoTag()->m_type, dbArtTypes);
634 for (vector<string>::const_iterator it = dbArtTypes.begin(); it != dbArtTypes.end(); it++)
636 if (find(artTypes.begin(), artTypes.end(), *it) == artTypes.end())
637 artTypes.push_back(*it);
640 for (vector<string>::const_iterator i = artTypes.begin(); i != artTypes.end(); ++i)
643 CFileItemPtr item(new CFileItem(type, "false"));
644 item->SetLabel(type);
645 if (videoItem.HasArt(type))
646 item->SetArt("thumb", videoItem.GetArt(type));
650 dialog->SetItems(&items);
653 if (dialog->IsButtonPressed())
655 // Get the new artwork name
656 CStdString strArtworkName;
657 if (!CGUIKeyboardFactory::ShowAndGetInput(strArtworkName, g_localizeStrings.Get(13516), false))
660 return strArtworkName;
663 return dialog->GetSelectedItem()->GetLabel();
666 void CGUIDialogVideoInfo::OnGetArt()
668 map<string, string> currentArt;
669 string type = ChooseArtType(*m_movieItem, currentArt);
673 // TODO: this can be removed once these are unified.
674 if (type == "fanart")
681 if (m_movieItem->HasArt(type))
683 CFileItemPtr item(new CFileItem("thumb://Current", false));
684 item->SetArt("thumb", m_movieItem->GetArt(type));
685 item->SetLabel(g_localizeStrings.Get(13512));
688 else if ((type == "poster" || type == "banner") && currentArt.find("thumb") != currentArt.end())
689 { // add the 'thumb' type in
690 CFileItemPtr item(new CFileItem("thumb://Thumb", false));
691 item->SetArt("thumb", currentArt["thumb"]);
692 item->SetLabel(g_localizeStrings.Get(13512));
696 // Grab the thumbnails from the web
697 vector<CStdString> thumbs;
698 int season = (m_movieItem->GetVideoInfoTag()->m_type == "season") ? m_movieItem->GetVideoInfoTag()->m_iSeason : -1;
699 m_movieItem->GetVideoInfoTag()->m_strPictureURL.GetThumbURLs(thumbs, type, season);
701 for (unsigned int i = 0; i < thumbs.size(); ++i)
703 CStdString strItemPath = StringUtils::Format("thumb://Remote%i", i);
704 CFileItemPtr item(new CFileItem(strItemPath, false));
705 item->SetArt("thumb", thumbs[i]);
706 item->SetIconImage("DefaultPicture.png");
707 item->SetLabel(g_localizeStrings.Get(13513));
709 // TODO: Do we need to clear the cached image?
710 // CTextureCache::Get().ClearCachedImage(thumb);
714 CStdString localThumb = CVideoThumbLoader::GetLocalArt(*m_movieItem, type);
715 if (!localThumb.empty())
717 CFileItemPtr item(new CFileItem("thumb://Local", false));
718 item->SetArt("thumb", localThumb);
719 item->SetLabel(g_localizeStrings.Get(13514));
723 { // no local thumb exists, so we are just using the IMDb thumb or cached thumb
724 // which is probably the IMDb thumb. These could be wrong, so allow the user
725 // to delete the incorrect thumb
726 CFileItemPtr item(new CFileItem("thumb://None", false));
727 item->SetIconImage("DefaultVideo.png");
728 item->SetLabel(g_localizeStrings.Get(13515));
733 VECSOURCES sources(*CMediaSourceSettings::Get().GetSources("video"));
734 AddItemPathToFileBrowserSources(sources, *m_movieItem);
735 g_mediaManager.GetLocalDrives(sources);
736 if (CGUIDialogFileBrowser::ShowAndGetImage(items, sources, g_localizeStrings.Get(13511), result) &&
737 result != "thumb://Current") // user didn't choose the one they have
740 if (StringUtils::StartsWith(result, "thumb://Remote"))
742 int number = atoi(result.substr(14).c_str());
743 newThumb = thumbs[number];
745 else if (result == "thumb://Thumb")
746 newThumb = currentArt["thumb"];
747 else if (result == "thumb://Local")
748 newThumb = localThumb;
749 else if (CFile::Exists(result))
754 // update thumb in the database
758 db.SetArtForItem(m_movieItem->GetVideoInfoTag()->m_iDbId, m_movieItem->GetVideoInfoTag()->m_type, type, newThumb);
761 CUtil::DeleteVideoDatabaseDirectoryCache(); // to get them new thumbs to show
762 m_movieItem->SetArt(type, newThumb);
763 if (m_movieItem->HasProperty("set_folder_thumb"))
764 { // have a folder thumb to set as well
765 VIDEO::CVideoInfoScanner::ApplyThumbToFolder(m_movieItem->GetProperty("set_folder_thumb").asString(), newThumb);
767 m_hasUpdatedThumb = true;
774 // re-open the art selection dialog as we come back from
775 // the image selection dialog
779 // Allow user to select a Fanart
780 void CGUIDialogVideoInfo::OnGetFanart()
784 CFileItem item(*m_movieItem->GetVideoInfoTag());
785 if (item.HasArt("fanart"))
787 CFileItemPtr itemCurrent(new CFileItem("fanart://Current",false));
788 itemCurrent->SetArt("thumb", item.GetArt("fanart"));
789 itemCurrent->SetLabel(g_localizeStrings.Get(20440));
790 items.Add(itemCurrent);
793 // ensure the fanart is unpacked
794 m_movieItem->GetVideoInfoTag()->m_fanart.Unpack();
796 // Grab the thumbnails from the web
797 for (unsigned int i = 0; i < m_movieItem->GetVideoInfoTag()->m_fanart.GetNumFanarts(); i++)
799 CStdString strItemPath = StringUtils::Format("fanart://Remote%i",i);
800 CFileItemPtr item(new CFileItem(strItemPath, false));
801 CStdString thumb = m_movieItem->GetVideoInfoTag()->m_fanart.GetPreviewURL(i);
802 item->SetArt("thumb", CTextureUtils::GetWrappedThumbURL(thumb));
803 item->SetIconImage("DefaultPicture.png");
804 item->SetLabel(g_localizeStrings.Get(20441));
806 // TODO: Do we need to clear the cached image?
807 // CTextureCache::Get().ClearCachedImage(thumb);
811 CStdString strLocal = item.GetLocalFanart();
812 if (!strLocal.empty())
814 CFileItemPtr itemLocal(new CFileItem("fanart://Local",false));
815 itemLocal->SetArt("thumb", strLocal);
816 itemLocal->SetLabel(g_localizeStrings.Get(20438));
818 // TODO: Do we need to clear the cached image?
819 CTextureCache::Get().ClearCachedImage(strLocal);
820 items.Add(itemLocal);
824 CFileItemPtr itemNone(new CFileItem("fanart://None", false));
825 itemNone->SetIconImage("DefaultVideo.png");
826 itemNone->SetLabel(g_localizeStrings.Get(20439));
831 VECSOURCES sources(*CMediaSourceSettings::Get().GetSources("video"));
832 AddItemPathToFileBrowserSources(sources, item);
833 g_mediaManager.GetLocalDrives(sources);
835 if (!CGUIDialogFileBrowser::ShowAndGetImage(items, sources, g_localizeStrings.Get(20437), result, &flip, 20445) || result.Equals("fanart://Current"))
836 return; // user cancelled
838 if (result.Equals("fanart://Local"))
841 if (StringUtils::StartsWith(result, "fanart://Remote"))
843 int iFanart = atoi(result.substr(15).c_str());
844 // set new primary fanart, and update our database accordingly
845 m_movieItem->GetVideoInfoTag()->m_fanart.SetPrimaryFanart(iFanart);
849 db.UpdateFanart(*m_movieItem, (VIDEODB_CONTENT_TYPE)m_movieItem->GetVideoContentType());
852 result = m_movieItem->GetVideoInfoTag()->m_fanart.GetImageURL();
854 else if (result.Equals("fanart://None") || !CFile::Exists(result))
857 // set the fanart image
858 if (flip && !result.empty())
859 result = CTextureUtils::GetWrappedImageURL(result, "", "flipped");
863 db.SetArtForItem(m_movieItem->GetVideoInfoTag()->m_iDbId, m_movieItem->GetVideoInfoTag()->m_type, "fanart", result);
867 CUtil::DeleteVideoDatabaseDirectoryCache(); // to get them new thumbs to show
868 m_movieItem->SetArt("fanart", result);
869 m_hasUpdatedThumb = true;
875 void CGUIDialogVideoInfo::PlayTrailer()
878 item.SetPath(m_movieItem->GetVideoInfoTag()->m_strTrailer);
879 *item.GetVideoInfoTag() = *m_movieItem->GetVideoInfoTag();
880 item.GetVideoInfoTag()->m_streamDetails.Reset();
881 item.GetVideoInfoTag()->m_strTitle = StringUtils::Format("%s (%s)",
882 m_movieItem->GetVideoInfoTag()->m_strTitle.c_str(),
883 g_localizeStrings.Get(20410).c_str());
884 CVideoThumbLoader::SetArt(item, m_movieItem->GetArt());
885 item.GetVideoInfoTag()->m_iDbId = -1;
886 item.GetVideoInfoTag()->m_iFileId = -1;
891 if (item.IsPlayList())
892 CApplicationMessenger::Get().MediaPlay(item);
894 CApplicationMessenger::Get().PlayFile(item);
897 void CGUIDialogVideoInfo::SetLabel(int iControl, const CStdString &strLabel)
899 if (strLabel.empty())
901 SET_CONTROL_LABEL(iControl, 416); // "Not available"
905 SET_CONTROL_LABEL(iControl, strLabel);
909 std::string CGUIDialogVideoInfo::GetThumbnail() const
911 return m_movieItem->GetArt("thumb");
914 void CGUIDialogVideoInfo::AddItemPathToFileBrowserSources(VECSOURCES &sources, const CFileItem &item)
916 if (!item.HasVideoInfoTag())
919 CStdString itemDir = item.GetVideoInfoTag()->m_basePath;
923 itemDir = item.GetVideoInfoTag()->GetPath();
925 CFileItem itemTmp(itemDir, false);
926 if (itemTmp.IsVideo())
927 itemDir = URIUtils::GetParentPath(itemDir);
929 if (!itemDir.empty() && CDirectory::Exists(itemDir))
931 CMediaSource itemSource;
932 itemSource.strName = g_localizeStrings.Get(36041);
933 itemSource.strPath = itemDir;
934 sources.push_back(itemSource);
938 int CGUIDialogVideoInfo::ManageVideoItem(const CFileItemPtr &item)
940 if (item == NULL || !item->IsVideoDb() || !item->HasVideoInfoTag() || item->GetVideoInfoTag()->m_iDbId < 0)
943 CVideoDatabase database;
944 if (!database.Open())
947 VIDEODB_CONTENT_TYPE type = (VIDEODB_CONTENT_TYPE)item->GetVideoContentType();
948 int dbId = item->GetVideoInfoTag()->m_iDbId;
950 CContextButtons buttons;
951 buttons.Add(CONTEXT_BUTTON_EDIT, 16105);
953 if (type == VIDEODB_CONTENT_MOVIES || type == VIDEODB_CONTENT_TVSHOWS)
954 buttons.Add(CONTEXT_BUTTON_EDIT_SORTTITLE, 16107);
956 if (item->m_bIsFolder)
958 // Have both options for folders since we don't know whether all childs are watched/unwatched
959 buttons.Add(CONTEXT_BUTTON_MARK_UNWATCHED, 16104); //Mark as UnWatched
960 buttons.Add(CONTEXT_BUTTON_MARK_WATCHED, 16103); //Mark as Watched
964 if (item->GetOverlayImage().Equals("OverlayWatched.png"))
965 buttons.Add(CONTEXT_BUTTON_MARK_UNWATCHED, 16104); //Mark as UnWatched
967 buttons.Add(CONTEXT_BUTTON_MARK_WATCHED, 16103); //Mark as Watched
970 if (type == VIDEODB_CONTENT_MOVIES)
972 // only show link/unlink if there are tvshows available
973 if (database.HasContent(VIDEODB_CONTENT_TVSHOWS))
975 buttons.Add(CONTEXT_BUTTON_LINK_MOVIE, 20384);
976 if (database.IsLinkedToTvshow(dbId))
977 buttons.Add(CONTEXT_BUTTON_UNLINK_MOVIE, 20385);
980 // set or change movie set the movie belongs to
981 buttons.Add(CONTEXT_BUTTON_SET_MOVIESET, 20465);
984 if (type == VIDEODB_CONTENT_EPISODES &&
985 item->GetVideoInfoTag()->m_iBookmarkId > 0)
986 buttons.Add(CONTEXT_BUTTON_UNLINK_BOOKMARK, 20405);
988 if (!item->m_bIsFolder || type == VIDEODB_CONTENT_TVSHOWS)
989 buttons.Add(CONTEXT_BUTTON_DELETE, 646);
992 int button = CGUIDialogContextMenu::ShowAndGetChoice(buttons);
995 switch ((CONTEXT_BUTTON)button)
997 case CONTEXT_BUTTON_EDIT:
998 result = UpdateVideoItemTitle(item);
1001 case CONTEXT_BUTTON_EDIT_SORTTITLE:
1002 result = UpdateVideoItemSortTitle(item);
1005 case CONTEXT_BUTTON_MARK_WATCHED:
1006 result = MarkWatched(item, true);
1009 case CONTEXT_BUTTON_MARK_UNWATCHED:
1010 result = MarkWatched(item, false);
1013 case CONTEXT_BUTTON_LINK_MOVIE:
1014 result = LinkMovieToTvShow(item, false, database);
1017 case CONTEXT_BUTTON_UNLINK_MOVIE:
1018 result = LinkMovieToTvShow(item, true, database);
1021 case CONTEXT_BUTTON_SET_MOVIESET:
1023 CFileItemPtr selectedSet;
1024 if (GetSetForMovie(item.get(), selectedSet))
1025 result = SetMovieSet(item.get(), selectedSet.get());
1029 case CONTEXT_BUTTON_UNLINK_BOOKMARK:
1030 database.DeleteBookMarkForEpisode(*item->GetVideoInfoTag());
1034 case CONTEXT_BUTTON_DELETE:
1035 result = DeleteVideoItem(item);
1052 //Add change a title's name
1053 bool CGUIDialogVideoInfo::UpdateVideoItemTitle(const CFileItemPtr &pItem)
1055 if (!pItem->HasVideoInfoTag())
1058 // dont allow update while scanning
1059 if (g_application.IsVideoScanning())
1061 CGUIDialogOK::ShowAndGetInput(257, 0, 14057, 0);
1065 CVideoDatabase database;
1066 if (!database.Open())
1069 int iDbId = pItem->GetVideoInfoTag()->m_iDbId;
1070 CVideoInfoTag detail;
1071 VIDEODB_CONTENT_TYPE iType = (VIDEODB_CONTENT_TYPE)pItem->GetVideoContentType();
1072 if (iType == VIDEODB_CONTENT_MOVIES)
1073 database.GetMovieInfo("", detail, iDbId);
1074 else if (iType == VIDEODB_CONTENT_MOVIE_SETS)
1075 database.GetSetInfo(iDbId, detail);
1076 else if (iType == VIDEODB_CONTENT_EPISODES)
1077 database.GetEpisodeInfo(pItem->GetPath(), detail, iDbId);
1078 else if (iType == VIDEODB_CONTENT_TVSHOWS)
1079 database.GetTvShowInfo(pItem->GetVideoInfoTag()->m_strFileNameAndPath, detail, iDbId);
1080 else if (iType == VIDEODB_CONTENT_MUSICVIDEOS)
1081 database.GetMusicVideoInfo(pItem->GetVideoInfoTag()->m_strFileNameAndPath, detail, iDbId);
1083 // get the new title
1084 if (!CGUIKeyboardFactory::ShowAndGetInput(detail.m_strTitle, g_localizeStrings.Get(16105), false))
1087 database.UpdateMovieTitle(iDbId, detail.m_strTitle, iType);
1091 bool CGUIDialogVideoInfo::MarkWatched(const CFileItemPtr &item, bool bMark)
1093 if (!CProfilesManager::Get().GetCurrentProfile().canWriteDatabases())
1096 // dont allow update while scanning
1097 if (g_application.IsVideoScanning())
1099 CGUIDialogOK::ShowAndGetInput(257, 0, 14057, 0);
1103 CVideoDatabase database;
1104 if (!database.Open())
1107 CFileItemList items;
1108 if (item->m_bIsFolder)
1110 CStdString strPath = item->GetPath();
1111 CDirectory::GetDirectory(strPath, items);
1116 for (int i = 0; i < items.Size(); ++i)
1118 CFileItemPtr pTmpItem = items[i];
1119 if (pTmpItem->m_bIsFolder)
1121 MarkWatched(pTmpItem, bMark);
1125 if (pTmpItem->HasVideoInfoTag() &&
1126 ((bMark && pTmpItem->GetVideoInfoTag()->m_playCount) ||
1127 (!bMark && !pTmpItem->GetVideoInfoTag()->m_playCount)))
1131 if (!URIUtils::IsUPnP(item->GetPath()) || !UPNP::CUPnP::MarkWatched(*pTmpItem, bMark))
1134 // Clear resume bookmark
1136 database.ClearBookMarksOfFile(pTmpItem->GetPath(), CBookmark::RESUME);
1138 database.SetPlayCount(*pTmpItem, bMark ? 1 : 0);
1147 bool CGUIDialogVideoInfo::CanDeleteVideoItem(const CFileItemPtr &item)
1149 if (item == NULL || !item->HasVideoInfoTag())
1152 CQueryParams params;
1153 CVideoDatabaseDirectory::GetQueryParams(item->GetPath(), params);
1155 return params.GetMovieId() != -1 ||
1156 params.GetEpisodeId() != -1 ||
1157 params.GetMVideoId() != -1 ||
1158 (params.GetTvShowId() != -1 && params.GetSeason() <= -1 &&
1159 !CVideoDatabaseDirectory::IsAllItem(item->GetPath()));
1162 bool CGUIDialogVideoInfo::DeleteVideoItemFromDatabase(const CFileItemPtr &item, bool unavailable /* = false */)
1164 if (!item->HasVideoInfoTag() || !CanDeleteVideoItem(item))
1167 // dont allow update while scanning
1168 if (g_application.IsVideoScanning())
1170 CGUIDialogOK::ShowAndGetInput(257, 0, 14057, 0);
1174 CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO);
1175 if (pDialog == NULL)
1179 VIDEODB_CONTENT_TYPE type = (VIDEODB_CONTENT_TYPE)item->GetVideoContentType();
1182 case VIDEODB_CONTENT_MOVIES:
1185 case VIDEODB_CONTENT_EPISODES:
1188 case VIDEODB_CONTENT_TVSHOWS:
1191 case VIDEODB_CONTENT_MUSICVIDEOS:
1199 pDialog->SetHeading(heading);
1203 pDialog->SetLine(0, g_localizeStrings.Get(662));
1204 pDialog->SetLine(1, g_localizeStrings.Get(663));
1208 pDialog->SetLine(0, StringUtils::Format(g_localizeStrings.Get(433), item->GetLabel().c_str()));
1209 pDialog->SetLine(1, "");
1211 pDialog->SetLine(2, "");
1214 if (!pDialog->IsConfirmed())
1218 CVideoDatabase database;
1221 database.GetFilePathById(item->GetVideoInfoTag()->m_iDbId, path, type);
1227 case VIDEODB_CONTENT_MOVIES:
1228 database.DeleteMovie(path);
1230 case VIDEODB_CONTENT_EPISODES:
1231 database.DeleteEpisode(path, item->GetVideoInfoTag()->m_iDbId);
1233 case VIDEODB_CONTENT_TVSHOWS:
1234 database.DeleteTvShow(path);
1236 case VIDEODB_CONTENT_MUSICVIDEOS:
1237 database.DeleteMusicVideo(path);
1244 if (type == VIDEODB_CONTENT_TVSHOWS)
1245 database.SetPathHash(path,"");
1247 database.SetPathHash(URIUtils::GetDirectory(path), "");
1252 bool CGUIDialogVideoInfo::DeleteVideoItem(const CFileItemPtr &item, bool unavailable /* = false */)
1254 // delete the video item from the database
1255 if (!DeleteVideoItemFromDatabase(item, unavailable))
1259 // check if the user is allowed to delete the actual file as well
1260 if ((CProfilesManager::Get().GetCurrentProfile().getLockMode() == LOCK_MODE_EVERYONE ||
1261 !CProfilesManager::Get().GetCurrentProfile().filesLocked() ||
1262 g_passwordManager.IsMasterLockUnlocked(true)) &&
1263 CSettings::Get().GetBool("filelists.allowfiledeletion"))
1265 CStdString strDeletePath = item->GetVideoInfoTag()->GetPath();
1267 if (URIUtils::GetFileName(strDeletePath).Equals("VIDEO_TS.IFO"))
1269 strDeletePath = URIUtils::GetDirectory(strDeletePath);
1270 if (StringUtils::EndsWithNoCase(strDeletePath, "video_ts/"))
1272 URIUtils::RemoveSlashAtEnd(strDeletePath);
1273 strDeletePath = URIUtils::GetDirectory(strDeletePath);
1276 if (URIUtils::HasSlashAtEnd(strDeletePath))
1277 item->m_bIsFolder = true;
1279 // check if the file/directory can be deleted
1280 if (CUtil::SupportsWriteFileOperations(strDeletePath))
1282 item->SetPath(strDeletePath);
1284 // HACK: stacked files need to be treated as folders in order to be deleted
1285 if (item->IsStack())
1286 item->m_bIsFolder = true;
1287 result = CFileUtils::DeleteItem(item);
1291 CUtil::DeleteVideoDatabaseDirectoryCache();
1296 bool CGUIDialogVideoInfo::GetMoviesForSet(const CFileItem *setItem, CFileItemList &originalMovies, CFileItemList &selectedMovies)
1298 CVideoDatabase videodb;
1299 if (!videodb.Open())
1302 CStdString strHeading = StringUtils::Format(g_localizeStrings.Get(20457));
1303 CStdString baseDir = StringUtils::Format("videodb://movies/sets/%d", setItem->GetVideoInfoTag()->m_iDbId);
1305 if (!CDirectory::GetDirectory(baseDir, originalMovies) || originalMovies.Size() <= 0) // keep a copy of the original members of the set
1308 CFileItemList listItems;
1309 if (!videodb.GetSortedVideos(MediaTypeMovie, "videodb://movies", SortDescription(), listItems) || listItems.Size() <= 0)
1312 CGUIDialogSelect *dialog = (CGUIDialogSelect *)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
1316 listItems.Sort(SortByLabel, SortOrderAscending, SortAttributeIgnoreArticle);
1319 dialog->SetMultiSelection(true);
1320 dialog->SetHeading(strHeading);
1321 dialog->SetItems(&listItems);
1322 vector<int> selectedIndices;
1323 for (int i = 0; i < originalMovies.Size(); i++)
1325 for (int listIndex = 0; listIndex < listItems.Size(); listIndex++)
1327 if (listItems.Get(listIndex)->GetVideoInfoTag()->m_iDbId == originalMovies[i]->GetVideoInfoTag()->m_iDbId)
1329 selectedIndices.push_back(listIndex);
1334 dialog->SetSelected(selectedIndices);
1335 dialog->EnableButton(true, 186);
1338 if (dialog->IsConfirmed())
1340 selectedMovies.Copy(dialog->GetSelectedItems());
1341 return (selectedMovies.Size() > 0);
1347 bool CGUIDialogVideoInfo::GetSetForMovie(const CFileItem *movieItem, CFileItemPtr &selectedSet)
1349 CVideoDatabase videodb;
1350 if (!videodb.Open())
1353 CFileItemList listItems;
1354 CStdString baseDir = "videodb://movies/sets/";
1355 if (!CDirectory::GetDirectory(baseDir, listItems) || listItems.Size() <= 0)
1357 listItems.Sort(SortByLabel, SortOrderAscending, SortAttributeIgnoreArticle);
1359 int currentSetId = 0;
1360 CStdString currentSetLabel;
1362 if (movieItem->GetVideoInfoTag()->m_iSetId > currentSetId)
1364 currentSetId = movieItem->GetVideoInfoTag()->m_iSetId;
1365 currentSetLabel = videodb.GetSetById(currentSetId);
1368 if (currentSetId > 0)
1371 CStdString strClear = StringUtils::Format(g_localizeStrings.Get(20467), currentSetLabel.c_str());
1372 CFileItemPtr clearItem(new CFileItem(strClear));
1373 clearItem->GetVideoInfoTag()->m_iDbId = -1; // -1 will be used to clear set
1374 listItems.AddFront(clearItem, 0);
1375 // add keep current set item
1376 CStdString strKeep = StringUtils::Format(g_localizeStrings.Get(20469), currentSetLabel.c_str());
1377 CFileItemPtr keepItem(new CFileItem(strKeep));
1378 keepItem->GetVideoInfoTag()->m_iDbId = currentSetId;
1379 listItems.AddFront(keepItem, 1);
1382 CGUIDialogSelect *dialog = (CGUIDialogSelect *)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
1386 CStdString strHeading = StringUtils::Format(g_localizeStrings.Get(20466));
1388 dialog->SetHeading(strHeading);
1389 dialog->SetItems(&listItems);
1390 if (currentSetId >= 0)
1392 for (int listIndex = 0; listIndex < listItems.Size(); listIndex++)
1394 if (listItems.Get(listIndex)->GetVideoInfoTag()->m_iDbId == currentSetId)
1396 dialog->SetSelected(listIndex);
1401 dialog->EnableButton(true, 20468); // new set via button
1404 if (dialog->IsButtonPressed())
1405 { // creating new set
1406 CStdString newSetTitle;
1407 if (!CGUIKeyboardFactory::ShowAndGetInput(newSetTitle, g_localizeStrings.Get(20468), false))
1409 int idSet = videodb.AddSet(newSetTitle);
1410 map<string, string> movieArt, setArt;
1411 if (!videodb.GetArtForItem(idSet, "set", setArt))
1413 videodb.GetArtForItem(movieItem->GetVideoInfoTag()->m_iDbId, "movie", movieArt);
1414 videodb.SetArtForItem(idSet, "set", movieArt);
1416 CFileItemPtr newSet(new CFileItem(newSetTitle));
1417 newSet->GetVideoInfoTag()->m_iDbId = idSet;
1418 selectedSet = newSet;
1421 else if (dialog->IsConfirmed())
1423 selectedSet = dialog->GetSelectedItem();
1424 return (selectedSet != NULL);
1430 bool CGUIDialogVideoInfo::SetMovieSet(const CFileItem *movieItem, const CFileItem *selectedSet)
1432 CVideoDatabase videodb;
1433 if (!videodb.Open())
1436 videodb.SetMovieSet(movieItem->GetVideoInfoTag()->m_iDbId, selectedSet->GetVideoInfoTag()->m_iDbId);
1440 bool CGUIDialogVideoInfo::UpdateVideoItemSortTitle(const CFileItemPtr &pItem)
1442 // dont allow update while scanning
1443 if (g_application.IsVideoScanning())
1445 CGUIDialogOK::ShowAndGetInput(257, 0, 14057, 0);
1449 CVideoDatabase database;
1450 if (!database.Open())
1453 int iDbId = pItem->GetVideoInfoTag()->m_iDbId;
1454 CVideoInfoTag detail;
1455 VIDEODB_CONTENT_TYPE iType = (VIDEODB_CONTENT_TYPE)pItem->GetVideoContentType();
1456 if (iType == VIDEODB_CONTENT_MOVIES)
1457 database.GetMovieInfo("", detail, iDbId);
1458 else if (iType == VIDEODB_CONTENT_TVSHOWS)
1459 database.GetTvShowInfo(pItem->GetVideoInfoTag()->m_strFileNameAndPath, detail, iDbId);
1461 CStdString currentTitle;
1462 if (detail.m_strSortTitle.empty())
1463 currentTitle = detail.m_strTitle;
1465 currentTitle = detail.m_strSortTitle;
1467 // get the new sort title
1468 if (!CGUIKeyboardFactory::ShowAndGetInput(currentTitle, g_localizeStrings.Get(16107), false))
1471 return database.UpdateVideoSortTitle(iDbId, currentTitle, iType);
1474 bool CGUIDialogVideoInfo::LinkMovieToTvShow(const CFileItemPtr &item, bool bRemove, CVideoDatabase &database)
1476 int dbId = item->GetVideoInfoTag()->m_iDbId;
1482 if (!database.GetLinksToTvShow(dbId, ids))
1485 for (unsigned int i = 0; i < ids.size(); ++i)
1488 database.GetTvShowInfo("", tag, ids[i]);
1489 CFileItemPtr show(new CFileItem(tag));
1495 database.GetTvShowsNav("videodb://tvshows/titles", list);
1497 // remove already linked shows
1499 if (!database.GetLinksToTvShow(dbId, ids))
1502 for (int i = 0; i < list.Size(); )
1505 for (j = 0; j < ids.size(); ++j)
1507 if (list[i]->GetVideoInfoTag()->m_iDbId == ids[j])
1510 if (j == ids.size())
1517 int iSelectedLabel = 0;
1518 if (list.Size() > 1)
1520 list.Sort(SortByLabel, SortOrderAscending, CSettings::Get().GetBool("filelists.ignorethewhensorting") ? SortAttributeIgnoreArticle : SortAttributeNone);
1521 CGUIDialogSelect* pDialog = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
1523 pDialog->SetItems(&list);
1524 pDialog->SetHeading(20356);
1526 iSelectedLabel = pDialog->GetSelectedLabel();
1529 if (iSelectedLabel > -1)
1530 return database.LinkMovieToTvshow(dbId, list[iSelectedLabel]->GetVideoInfoTag()->m_iDbId, bRemove);