Very simple movie set management: edit/clear set and add/remove set members #2492

Merged
merged 2 commits into from Apr 6, 2013
@@ -9463,7 +9463,27 @@ msgctxt "#20464"
msgid "Select %s"
msgstr ""
-#empty strings from id 20465 to 21329
+msgctxt "#20465"
+msgid "Manage movie set"
+msgstr ""
+
+msgctxt "#20466"
+msgid "Select movie set"
+msgstr ""
+
+msgctxt "#20467"
+msgid "No set (Remove from %s)"
+msgstr ""
+
+msgctxt "#20468"
+msgid "Add movie to a new set"
+msgstr ""
+
+msgctxt "#20469"
+msgid "Keep current set (%s)"
+msgstr ""
+
+#empty strings from id 20470 to 21329
#up to 21329 is reserved for the video db !! !
#: xbmc/settings/GUISettings.cpp
View
@@ -468,6 +468,7 @@ class CFileItemList : public CFileItem
void Remove(int iItem);
CFileItemPtr Get(int iItem);
const CFileItemPtr Get(int iItem) const;
+ const VECFILEITEMS GetList() const { return m_items; }
CFileItemPtr Get(const CStdString& strPath);
const CFileItemPtr Get(const CStdString& strPath) const;
int Size() const;
@@ -126,6 +126,8 @@ enum CONTEXT_BUTTON { CONTEXT_BUTTON_CANCELLED = 0,
CONTEXT_BUTTON_RECORD_ITEM,
CONTEXT_BUTTON_TAGS_ADD_ITEMS,
CONTEXT_BUTTON_TAGS_REMOVE_ITEMS,
+ CONTEXT_BUTTON_SET_MOVIESET,
+ CONTEXT_BUTTON_MOVIESET_ADD_REMOVE_ITEMS,
CONTEXT_BUTTON_USER1,
CONTEXT_BUTTON_USER2,
CONTEXT_BUTTON_USER3,
@@ -3048,6 +3048,19 @@ void CVideoDatabase::DeleteSet(int idSet)
}
}
+void CVideoDatabase::ClearMovieSet(int idMovie)
+{
+ SetMovieSet(idMovie, -1);
+}
+
+void CVideoDatabase::SetMovieSet(int idMovie, int idSet)
+{
+ if (idSet >= 0)
+ ExecuteQuery(PrepareSQL("update movie set idSet = %i where idMovie = %i", idSet, idMovie));
+ else
+ ExecuteQuery(PrepareSQL("update movie set idSet = null where idMovie = %i", idMovie));
+}
+
void CVideoDatabase::DeleteTag(int idTag, VIDEODB_CONTENT_TYPE mediaType)
{
try
@@ -691,6 +691,10 @@ class CVideoDatabase : public CDatabase
virtual bool GetFilter(CDbUrl &videoUrl, Filter &filter, SortDescription &sorting);
+ int AddSet(const CStdString& strSet);
+ void ClearMovieSet(int idMovie);
+ void SetMovieSet(int idMovie, int idSet);
+
protected:
friend class CEdenVideoArtUpdater;
int GetMovieId(const CStdString& strFilenameAndPath);
@@ -713,7 +717,6 @@ class CVideoDatabase : public CDatabase
int AddGenre(const CStdString& strGenre1);
int AddActor(const CStdString& strActor, const CStdString& thumbURL, const CStdString &thumb = "");
int AddCountry(const CStdString& strCountry);
- int AddSet(const CStdString& strSet);
int AddStudio(const CStdString& strStudio1);
int AddTvShow(const CStdString& strPath);
@@ -981,6 +981,10 @@ void CGUIWindowVideoNav::GetContextButtons(int itemNumber, CContextButtons &butt
buttons.Add(CONTEXT_BUTTON_UNLINK_MOVIE,20385);
buttons.Add(CONTEXT_BUTTON_LINK_MOVIE,20384);
}
+ if (item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_type == "movie") // movie entry
+ {
+ buttons.Add(CONTEXT_BUTTON_SET_MOVIESET,20465); // set or change movie set the movie belongs to
+ }
if (node == NODE_TYPE_SEASONS && item->m_bIsFolder)
buttons.Add(CONTEXT_BUTTON_SET_SEASON_ART, 13511);
@@ -989,6 +993,7 @@ void CGUIWindowVideoNav::GetContextButtons(int itemNumber, CContextButtons &butt
{
buttons.Add(CONTEXT_BUTTON_EDIT, 16105);
buttons.Add(CONTEXT_BUTTON_SET_MOVIESET_ART, 13511);
+ buttons.Add(CONTEXT_BUTTON_MOVIESET_ADD_REMOVE_ITEMS, 20465);
buttons.Add(CONTEXT_BUTTON_DELETE, 646);
}
@@ -1074,6 +1079,12 @@ void CGUIWindowVideoNav::GetContextButtons(int itemNumber, CContextButtons &butt
CGUIWindowVideoBase::GetNonContextButtons(itemNumber, buttons);
}
+// predicate used by sorting and set_difference
+bool compFileItemsByDbId(CFileItemPtr& lhs, CFileItemPtr& rhs)
+{
+ return lhs->HasVideoInfoTag() && rhs->HasVideoInfoTag() && lhs->GetVideoInfoTag()->m_iDbId < rhs->GetVideoInfoTag()->m_iDbId;
+}
+
bool CGUIWindowVideoNav::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
{
CFileItemPtr item;
@@ -1323,6 +1334,54 @@ bool CGUIWindowVideoNav::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
items.RemoveDiscCache(GetID());
return true;
}
+ case CONTEXT_BUTTON_SET_MOVIESET:
+ {
+ CFileItemPtr selectedSet;
+ if (!GetSetForMovie(item, selectedSet))
+ return true;
+
+ if (SetMovieSet(item, selectedSet))
+ Refresh();
+
+ return true;
+ }
+ case CONTEXT_BUTTON_MOVIESET_ADD_REMOVE_ITEMS:
+ {
+ CFileItemList originalItems;
+ CFileItemList selectedItems;
+
+ if (!GetMoviesForSet(item, originalItems, selectedItems) || selectedItems.Size() == 0) // need at least one item selected
+ return true;
+ VECFILEITEMS original = originalItems.GetList();
+ std::sort(original.begin(), original.end(), compFileItemsByDbId);
+ VECFILEITEMS selected = selectedItems.GetList();
+ std::sort(selected.begin(), selected.end(), compFileItemsByDbId);
+
+ bool refreshNeeded = false;
+ // update the "added" items
+ VECFILEITEMS addedItems;
+ set_difference(selected.begin(),selected.end(), original.begin(),original.end(), std::back_inserter(addedItems), compFileItemsByDbId);
+ for (VECFILEITEMS::iterator it = addedItems.begin(); it != addedItems.end(); ++it)
+ {
+ if (SetMovieSet(*it, item))
+ refreshNeeded = true;
+ }
+ // update the "deleted" items
+ CFileItemPtr clearItem(new CFileItem());
+ clearItem->GetVideoInfoTag()->m_iDbId = -1; // -1 will be used to clear set
+ VECFILEITEMS deletedItems;
+ set_difference(original.begin(),original.end(), selected.begin(),selected.end(), std::back_inserter(deletedItems), compFileItemsByDbId);
+ for (VECFILEITEMS::iterator it = deletedItems.begin(); it != deletedItems.end(); ++it)
+ {
+ if (SetMovieSet(*it, clearItem))
+ refreshNeeded = true;
+ }
+
+ // we need to clear any cached version of this tag's listing
+ if (refreshNeeded)
+ Refresh();
+ return true;
+ }
case CONTEXT_BUTTON_UPDATE_LIBRARY:
{
OnScan("");
@@ -1761,6 +1820,152 @@ bool CGUIWindowVideoNav::GetItemsForTag(const CStdString &strHeading, const std:
return items.Size() > 0;
}
+bool CGUIWindowVideoNav::GetMoviesForSet(CFileItemPtr &setItem, CFileItemList &originalMovies, CFileItemList &selectedMovies)
+{
+ CVideoDatabase videodb;
+ if (!videodb.Open())
+ return false;
+
+ CStdString strHeading; strHeading.Format(g_localizeStrings.Get(20457));
+ CStdString baseDir;
+ baseDir.Format("videodb://1/7/%d", setItem->GetVideoInfoTag()->m_iDbId);
+
+ if (!CDirectory::GetDirectory(baseDir, originalMovies) || originalMovies.Size() <= 0) // keep a copy of the original members of the set
+ return false;
+
+ CFileItemList listItems;
+ if (!videodb.GetSortedVideos(MediaTypeMovie, "videodb://1", SortDescription(), listItems) || listItems.Size() <= 0)
+ return false;
+
+ CGUIDialogSelect *dialog = (CGUIDialogSelect *)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
+ if (dialog == NULL)
+ return false;
+
+ listItems.Sort(SORT_METHOD_LABEL_IGNORE_THE, SortOrderAscending);
+
+ dialog->Reset();
+ dialog->SetMultiSelection(true);
+ dialog->SetHeading(strHeading);
+ dialog->SetItems(&listItems);
+ vector<int> selectedIndices;
+ for (int i = 0; i < originalMovies.Size(); i++)
+ {
+ for (int listIndex = 0; listIndex < listItems.Size(); listIndex++)
+ {
+ if (listItems.Get(listIndex)->GetVideoInfoTag()->m_iDbId == originalMovies[i]->GetVideoInfoTag()->m_iDbId)
+ {
+ selectedIndices.push_back(listIndex);
+ break;
+ }
+ }
+ }
+ dialog->SetSelected(selectedIndices);
+ dialog->EnableButton(true, 186);
+ dialog->DoModal();
+
+ if (dialog->IsConfirmed())
+ {
+ selectedMovies.Copy(dialog->GetSelectedItems());
+ return (selectedMovies.Size() > 0);
+ }
+ else
+ return false;
+}
+
+bool CGUIWindowVideoNav::GetSetForMovie(CFileItemPtr &movieItem, CFileItemPtr &selectedSet)
+{
+ CVideoDatabase videodb;
+ if (!videodb.Open())
+ return false;
+
+ CFileItemList listItems;
+ CStdString baseDir = "videodb://1/7/";
+ if (!CDirectory::GetDirectory(baseDir, listItems) || listItems.Size() <= 0)
+ return false;
+ listItems.Sort(SORT_METHOD_LABEL_IGNORE_THE, SortOrderAscending);
+
+ int currentSetId = 0;
+ CStdString currentSetLabel;
+
+ if (movieItem->GetVideoInfoTag()->m_iSetId > currentSetId)
+ {
+ currentSetId = movieItem->GetVideoInfoTag()->m_iSetId;
+ currentSetLabel = videodb.GetSetById(currentSetId);
+ }
+
+ if (currentSetId > 0)
+ {
+ // add clear item
+ CStdString strClear; strClear.Format(g_localizeStrings.Get(20467), currentSetLabel);
+ CFileItemPtr clearItem(new CFileItem(strClear));
+ clearItem->GetVideoInfoTag()->m_iDbId = -1; // -1 will be used to clear set
+ listItems.AddFront(clearItem, 0);
+ // add keep current set item
+ CStdString strKeep; strKeep.Format(g_localizeStrings.Get(20469), currentSetLabel);
+ CFileItemPtr keepItem(new CFileItem(strKeep));
+ keepItem->GetVideoInfoTag()->m_iDbId = currentSetId;
+ listItems.AddFront(keepItem, 1);
+ }
+
+ CGUIDialogSelect *dialog = (CGUIDialogSelect *)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
+ if (dialog == NULL)
+ return false;
+
+ CStdString strHeading;
+ strHeading.Format(g_localizeStrings.Get(20466));
+ dialog->Reset();
+ dialog->SetHeading(strHeading);
+ dialog->SetItems(&listItems);
+ if (currentSetId >= 0)
+ {
+ for (int listIndex = 0; listIndex < listItems.Size(); listIndex++)
+ {
+ if (listItems.Get(listIndex)->GetVideoInfoTag()->m_iDbId == currentSetId)
+ {
+ dialog->SetSelected(listIndex);
+ break;
+ }
+ }
+ }
+ dialog->EnableButton(true, 20468); // new set via button
+ dialog->DoModal();
+
+ if (dialog->IsButtonPressed())
+ { // creating new set
+ CStdString newSetTitle;
+ if (!CGUIKeyboardFactory::ShowAndGetInput(newSetTitle, g_localizeStrings.Get(20468), false))
+ return false;
+ int idSet = videodb.AddSet(newSetTitle);
+ map<string, string> movieArt, setArt;
+ if (!videodb.GetArtForItem(idSet, "set", setArt))
+ {
+ videodb.GetArtForItem(movieItem->GetVideoInfoTag()->m_iDbId, "movie", movieArt);
+ videodb.SetArtForItem(idSet, "set", movieArt);
+ }
+ CFileItemPtr newSet(new CFileItem(newSetTitle));
+ newSet->GetVideoInfoTag()->m_iDbId = idSet;
+ selectedSet = newSet;
+ return true;
+ }
+ else if (dialog->IsConfirmed())
+ {
+ selectedSet = dialog->GetSelectedItem();
+ return (selectedSet != NULL);
+ }
+ else
+ return false;
+}
+
+bool CGUIWindowVideoNav::SetMovieSet (CFileItemPtr &movieItem, CFileItemPtr &selectedSet)
+{
+ CVideoDatabase videodb;
+ if (!videodb.Open())
+ return false;
+
+ videodb.SetMovieSet(movieItem->GetVideoInfoTag()->m_iDbId, selectedSet->GetVideoInfoTag()->m_iDbId);
+ return true;
+}
+
CStdString CGUIWindowVideoNav::GetLocalizedType(const std::string &strType)
{
if (strType == "movie" || strType == "movies")
@@ -81,5 +81,9 @@ class CGUIWindowVideoNav : public CGUIWindowVideoBase
bool GetItemsForTag(const CStdString &strHeading, const std::string &type, CFileItemList &items, int idTag = -1, bool showAll = true);
static CStdString GetLocalizedType(const std::string &strType);
+ bool GetSetForMovie(CFileItemPtr &movieItem, CFileItemPtr &selectedSet);
+ bool GetMoviesForSet(CFileItemPtr &setItem, CFileItemList &originalMovies, CFileItemList &selectedMovies);
+ bool SetMovieSet(CFileItemPtr &movieItem, CFileItemPtr &selectedSet);
+
VECSOURCES m_shares;
};