Merge pull request #4754 from koying/fixsetsdelete
[vuplus_xbmc] / xbmc / video / dialogs / GUIDialogVideoInfo.cpp
index e351aeb..78a0515 100644 (file)
@@ -305,11 +305,14 @@ void CGUIDialogVideoInfo::SetMovie(const CFileItem *item)
       m_movieItem->m_dateTime = m_movieItem->GetVideoInfoTag()->m_premiered;
       if(m_movieItem->GetVideoInfoTag()->m_iYear == 0 && m_movieItem->m_dateTime.IsValid())
         m_movieItem->GetVideoInfoTag()->m_iYear = m_movieItem->m_dateTime.GetYear();
-      m_movieItem->SetProperty("totalepisodes", m_movieItem->GetVideoInfoTag()->m_iEpisode);
-      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
-      m_movieItem->SetProperty("watchedepisodes", m_movieItem->GetVideoInfoTag()->m_playCount);
-      m_movieItem->SetProperty("unwatchedepisodes", m_movieItem->GetVideoInfoTag()->m_iEpisode - m_movieItem->GetVideoInfoTag()->m_playCount);
-      m_movieItem->GetVideoInfoTag()->m_playCount = (m_movieItem->GetVideoInfoTag()->m_iEpisode == m_movieItem->GetVideoInfoTag()->m_playCount) ? 1 : 0;
+      if (!m_movieItem->HasProperty("totalepisodes"))
+      {
+        m_movieItem->SetProperty("totalepisodes", m_movieItem->GetVideoInfoTag()->m_iEpisode);
+        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
+        m_movieItem->SetProperty("watchedepisodes", m_movieItem->GetVideoInfoTag()->m_playCount);
+        m_movieItem->SetProperty("unwatchedepisodes", m_movieItem->GetVideoInfoTag()->m_iEpisode - m_movieItem->GetVideoInfoTag()->m_playCount);
+        m_movieItem->GetVideoInfoTag()->m_playCount = (m_movieItem->GetVideoInfoTag()->m_iEpisode == m_movieItem->GetVideoInfoTag()->m_playCount) ? 1 : 0;
+      }
     }
     else if (type == VIDEODB_CONTENT_EPISODES)
     {
@@ -954,7 +957,10 @@ int CGUIDialogVideoInfo::ManageVideoItem(const CFileItemPtr &item)
   int dbId = item->GetVideoInfoTag()->m_iDbId;
 
   CContextButtons buttons;
-  buttons.Add(CONTEXT_BUTTON_EDIT, 16105);
+  if (type == "movie" || type == "set" ||
+      type == "tvshow" || type == "episode" ||
+      type == "musicvideo")
+    buttons.Add(CONTEXT_BUTTON_EDIT, 16105);
 
   if (type == "movie" || type == "tvshow")
     buttons.Add(CONTEXT_BUTTON_EDIT_SORTTITLE, 16107);
@@ -998,6 +1004,19 @@ int CGUIDialogVideoInfo::ManageVideoItem(const CFileItemPtr &item)
     buttons.Add(CONTEXT_BUTTON_MOVIESET_ADD_REMOVE_ITEMS, 20465);
   }
 
+  // tags
+  if (item->m_bIsFolder && type == "tag")
+  {
+    CVideoDbUrl videoUrl;
+    if (videoUrl.FromString(item->GetPath()))
+    {
+      const std::string &mediaType = videoUrl.GetItemType();
+
+      buttons.Add(CONTEXT_BUTTON_TAGS_ADD_ITEMS, StringUtils::Format(g_localizeStrings.Get(20460), GetLocalizedVideoType(mediaType).c_str()));
+      buttons.Add(CONTEXT_BUTTON_TAGS_REMOVE_ITEMS, StringUtils::Format(g_localizeStrings.Get(20461), GetLocalizedVideoType(mediaType).c_str()));
+    }
+  }
+
   buttons.Add(CONTEXT_BUTTON_DELETE, 646);
 
   bool result = false;
@@ -1055,6 +1074,14 @@ int CGUIDialogVideoInfo::ManageVideoItem(const CFileItemPtr &item)
         result = ManageMovieSets(item);
         break;
 
+      case CONTEXT_BUTTON_TAGS_ADD_ITEMS:
+        result = AddItemsToTag(item);
+        break;
+
+      case CONTEXT_BUTTON_TAGS_REMOVE_ITEMS:
+        result = RemoveItemsFromTag(item);
+        break;
+
       default:
         result = false;
         break;
@@ -1072,7 +1099,7 @@ int CGUIDialogVideoInfo::ManageVideoItem(const CFileItemPtr &item)
 //Add change a title's name
 bool CGUIDialogVideoInfo::UpdateVideoItemTitle(const CFileItemPtr &pItem)
 {
-  if (!pItem->HasVideoInfoTag())
+  if (pItem == NULL || !pItem->HasVideoInfoTag())
     return false;
 
   // dont allow update while scanning
@@ -1110,7 +1137,7 @@ bool CGUIDialogVideoInfo::UpdateVideoItemTitle(const CFileItemPtr &pItem)
 
 bool CGUIDialogVideoInfo::MarkWatched(const CFileItemPtr &item, bool bMark)
 {
-  if (!CProfilesManager::Get().GetCurrentProfile().canWriteDatabases())
+  if (item == NULL || !CProfilesManager::Get().GetCurrentProfile().canWriteDatabases())
     return false;
 
   // dont allow update while scanning
@@ -1175,13 +1202,15 @@ bool CGUIDialogVideoInfo::CanDeleteVideoItem(const CFileItemPtr &item)
   return params.GetMovieId()   != -1 ||
          params.GetEpisodeId() != -1 ||
          params.GetMVideoId()  != -1 ||
+         params.GetSetId()     != -1 ||
          (params.GetTvShowId() != -1 && params.GetSeason() <= -1 &&
           !CVideoDatabaseDirectory::IsAllItem(item->GetPath()));
 }
 
 bool CGUIDialogVideoInfo::DeleteVideoItemFromDatabase(const CFileItemPtr &item, bool unavailable /* = false */)
 {
-  if (!item->HasVideoInfoTag() || !CanDeleteVideoItem(item))
+  if (item == NULL || !item->HasVideoInfoTag() ||
+      !CanDeleteVideoItem(item))
     return false;
 
   // dont allow update while scanning
@@ -1211,6 +1240,9 @@ bool CGUIDialogVideoInfo::DeleteVideoItemFromDatabase(const CFileItemPtr &item,
     case VIDEODB_CONTENT_MUSICVIDEOS:
       heading = 20392;
       break;
+    case VIDEODB_CONTENT_MOVIE_SETS:
+      heading = 646;
+      break;
 
     default:
       return false;
@@ -1234,10 +1266,16 @@ bool CGUIDialogVideoInfo::DeleteVideoItemFromDatabase(const CFileItemPtr &item,
   if (!pDialog->IsConfirmed())
     return false;
 
-  CStdString path;
   CVideoDatabase database;
   database.Open();
 
+  if (type == VIDEODB_CONTENT_MOVIE_SETS)
+  {
+    database.DeleteSet(item->GetVideoInfoTag()->m_iDbId);
+    return true;
+  }
+
+  CStdString path;
   database.GetFilePathById(item->GetVideoInfoTag()->m_iDbId, path, type);
   if (path.empty())
     return false;
@@ -1271,11 +1309,13 @@ bool CGUIDialogVideoInfo::DeleteVideoItemFromDatabase(const CFileItemPtr &item,
 
 bool CGUIDialogVideoInfo::DeleteVideoItem(const CFileItemPtr &item, bool unavailable /* = false */)
 {
+  if (item == NULL)
+    return false;
+
   // delete the video item from the database
   if (!DeleteVideoItemFromDatabase(item, unavailable))
     return false;
 
-  bool result = true;
   // check if the user is allowed to delete the actual file as well
   if ((CProfilesManager::Get().GetCurrentProfile().getLockMode() == LOCK_MODE_EVERYONE ||
        !CProfilesManager::Get().GetCurrentProfile().filesLocked() ||
@@ -1304,13 +1344,13 @@ bool CGUIDialogVideoInfo::DeleteVideoItem(const CFileItemPtr &item, bool unavail
       // HACK: stacked files need to be treated as folders in order to be deleted
       if (item->IsStack())
         item->m_bIsFolder = true;
-      result = CFileUtils::DeleteItem(item);
+      CFileUtils::DeleteItem(item);
     }
   }
 
   CUtil::DeleteVideoDatabaseDirectoryCache();
 
-  return result;
+  return true;
 }
 
 bool CGUIDialogVideoInfo::ManageMovieSets(const CFileItemPtr &item)
@@ -1356,6 +1396,9 @@ bool CGUIDialogVideoInfo::ManageMovieSets(const CFileItemPtr &item)
 
 bool CGUIDialogVideoInfo::GetMoviesForSet(const CFileItem *setItem, CFileItemList &originalMovies, CFileItemList &selectedMovies)
 {
+  if (setItem == NULL || !setItem->HasVideoInfoTag())
+    return false;
+
   CVideoDatabase videodb;
   if (!videodb.Open())
     return false;
@@ -1407,13 +1450,16 @@ bool CGUIDialogVideoInfo::GetMoviesForSet(const CFileItem *setItem, CFileItemLis
 
 bool CGUIDialogVideoInfo::GetSetForMovie(const CFileItem *movieItem, CFileItemPtr &selectedSet)
 {
+  if (movieItem == NULL || !movieItem->HasVideoInfoTag())
+    return false;
+
   CVideoDatabase videodb;
   if (!videodb.Open())
     return false;
 
   CFileItemList listItems;
   CStdString baseDir = "videodb://movies/sets/";
-  if (!CDirectory::GetDirectory(baseDir, listItems) || listItems.Size() <= 0)
+  if (!CDirectory::GetDirectory(baseDir, listItems))
     return false;
   listItems.Sort(SortByLabel, SortOrderAscending, SortAttributeIgnoreArticle);
 
@@ -1490,6 +1536,10 @@ bool CGUIDialogVideoInfo::GetSetForMovie(const CFileItem *movieItem, CFileItemPt
 
 bool CGUIDialogVideoInfo::SetMovieSet(const CFileItem *movieItem, const CFileItem *selectedSet)
 {
+  if (movieItem == NULL || !movieItem->HasVideoInfoTag() ||
+      selectedSet == NULL || !selectedSet->HasVideoInfoTag())
+    return false;
+
   CVideoDatabase videodb;
   if (!videodb.Open())
     return false;
@@ -1498,6 +1548,135 @@ bool CGUIDialogVideoInfo::SetMovieSet(const CFileItem *movieItem, const CFileIte
   return true;
 }
 
+bool CGUIDialogVideoInfo::GetItemsForTag(const CStdString &strHeading, const std::string &type, CFileItemList &items, int idTag /* = -1 */, bool showAll /* = true */)
+{
+  CVideoDatabase videodb;
+  if (!videodb.Open())
+    return false;
+
+  MediaType mediaType = MediaTypeNone;
+  std::string baseDir = "videodb://";
+  std::string idColumn;
+  if (type.compare("movie") == 0)
+  {
+    mediaType = MediaTypeMovie;
+    baseDir += "movies";
+    idColumn = "idMovie";
+  }
+  else if (type.compare("tvshow") == 0)
+  {
+    mediaType = MediaTypeTvShow;
+    baseDir += "tvshows";
+    idColumn = "idShow";
+  }
+  else if (type.compare("musicvideo") == 0)
+  {
+    mediaType = MediaTypeMusicVideo;
+    baseDir += "musicvideos";
+    idColumn = "idMVideo";
+  }
+
+  baseDir += "/titles/";
+  CVideoDbUrl videoUrl;
+  if (!videoUrl.FromString(baseDir))
+    return false;
+
+  CVideoDatabase::Filter filter;
+  if (idTag > 0)
+  {
+    if (!showAll)
+      videoUrl.AddOption("tagid", idTag);
+    else
+      filter.where = videodb.PrepareSQL("%sview.%s NOT IN (SELECT taglinks.idMedia FROM taglinks WHERE taglinks.idTag = %d AND taglinks.media_type = '%s')", type.c_str(), idColumn.c_str(), idTag, type.c_str());
+  }
+
+  CFileItemList listItems;
+  if (!videodb.GetSortedVideos(mediaType, videoUrl.ToString(), SortDescription(), listItems, filter) || listItems.Size() <= 0)
+    return false;
+
+  CGUIDialogSelect *dialog = (CGUIDialogSelect *)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
+  if (dialog == NULL)
+    return false;
+
+  listItems.Sort(SortByLabel, SortOrderAscending, SortAttributeIgnoreArticle);
+
+  dialog->Reset();
+  dialog->SetMultiSelection(true);
+  dialog->SetHeading(strHeading);
+  dialog->SetItems(&listItems);
+  dialog->EnableButton(true, 186);
+  dialog->DoModal();
+
+  items.Copy(dialog->GetSelectedItems());
+  return items.Size() > 0;
+}
+
+bool CGUIDialogVideoInfo::AddItemsToTag(const CFileItemPtr &tagItem)
+{
+  if (tagItem == NULL || !tagItem->HasVideoInfoTag())
+    return false;
+
+  CVideoDbUrl videoUrl;
+  if (!videoUrl.FromString(tagItem->GetPath()))
+    return false;
+
+  CVideoDatabase videodb;
+  if (!videodb.Open())
+    return true;
+
+  std::string mediaType = videoUrl.GetItemType();
+  mediaType = mediaType.substr(0, mediaType.length() - 1);
+
+  CFileItemList items;
+  std::string localizedType = GetLocalizedVideoType(mediaType);
+  std::string strLabel = StringUtils::Format(g_localizeStrings.Get(20464), localizedType.c_str());
+  if (!GetItemsForTag(strLabel, mediaType, items, tagItem->GetVideoInfoTag()->m_iDbId))
+    return true;
+
+  for (int index = 0; index < items.Size(); index++)
+  {
+    if (!items[index]->HasVideoInfoTag() || items[index]->GetVideoInfoTag()->m_iDbId <= 0)
+      continue;
+
+    videodb.AddTagToItem(items[index]->GetVideoInfoTag()->m_iDbId, tagItem->GetVideoInfoTag()->m_iDbId, mediaType);
+  }
+
+  return true;
+}
+
+bool CGUIDialogVideoInfo::RemoveItemsFromTag(const CFileItemPtr &tagItem)
+{
+  if (tagItem == NULL || !tagItem->HasVideoInfoTag())
+    return false;
+
+  CVideoDbUrl videoUrl;
+  if (!videoUrl.FromString(tagItem->GetPath()))
+    return false;
+
+  CVideoDatabase videodb;
+  if (!videodb.Open())
+    return true;
+
+  std::string mediaType = videoUrl.GetItemType();
+  mediaType = mediaType.substr(0, mediaType.length() - 1);
+
+  CFileItemList items;
+  std::string localizedType = GetLocalizedVideoType(mediaType);
+  std::string strLabel = StringUtils::Format(g_localizeStrings.Get(20464), localizedType.c_str());
+  if (!GetItemsForTag(strLabel, mediaType, items, tagItem->GetVideoInfoTag()->m_iDbId, false))
+    return true;
+
+  for (int index = 0; index < items.Size(); index++)
+  {
+    if (!items[index]->HasVideoInfoTag() || items[index]->GetVideoInfoTag()->m_iDbId <= 0)
+      continue;
+
+    videodb.RemoveTagFromItem(items[index]->GetVideoInfoTag()->m_iDbId, tagItem->GetVideoInfoTag()->m_iDbId, mediaType);
+  }
+
+  return true;
+}
+
 bool CGUIDialogVideoInfo::ManageVideoItemArtwork(const CFileItemPtr &item, const std::string &type)
 {
   if (item == NULL || !item->HasVideoInfoTag() || type.empty())
@@ -1657,6 +1836,20 @@ bool CGUIDialogVideoInfo::ManageVideoItemArtwork(const CFileItemPtr &item, const
   return true;
 }
 
+std::string CGUIDialogVideoInfo::GetLocalizedVideoType(const std::string &strType)
+{
+  if (strType == "movie" || strType == "movies")
+    return g_localizeStrings.Get(20342);
+  else if (strType == "tvshow" || strType == "tvshows")
+    return g_localizeStrings.Get(20343);
+  else if (strType == "episode" || strType == "episodes")
+    return g_localizeStrings.Get(20359);
+  else if (strType == "musicvideo" || strType == "musicvideos")
+    return g_localizeStrings.Get(20391);
+
+  return "";
+}
+
 bool CGUIDialogVideoInfo::UpdateVideoItemSortTitle(const CFileItemPtr &pItem)
 {
   // dont allow update while scanning
@@ -1735,7 +1928,7 @@ bool CGUIDialogVideoInfo::LinkMovieToTvShow(const CFileItemPtr &item, bool bRemo
   }
 
   int iSelectedLabel = 0;
-  if (list.Size() > 1)
+  if (list.Size() > 1 || (!bRemove && !list.IsEmpty()))
   {
     list.Sort(SortByLabel, SortOrderAscending, CSettings::Get().GetBool("filelists.ignorethewhensorting") ? SortAttributeIgnoreArticle : SortAttributeNone);
     CGUIDialogSelect* pDialog = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
@@ -1746,7 +1939,7 @@ bool CGUIDialogVideoInfo::LinkMovieToTvShow(const CFileItemPtr &item, bool bRemo
     iSelectedLabel = pDialog->GetSelectedLabel();
   }
 
-  if (iSelectedLabel > -1)
+  if (iSelectedLabel > -1 && iSelectedLabel < list.Size())
     return database.LinkMovieToTvshow(dbId, list[iSelectedLabel]->GetVideoInfoTag()->m_iDbId, bRemove);
 
   return false;