aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArne Morten Kvarving <spiff@xbmc.org>2012-11-12 08:14:32 -0800
committerArne Morten Kvarving <spiff@xbmc.org>2012-11-12 08:14:32 -0800
commitfc0d58b64dc753121c50598b8312bd8ca611b71e (patch)
tree6b342746a6f5178f478cb0a0db7af46d8334560d
parent158aac0f9f0e447ce00cada5bd0a0fa51dd5dd5f (diff)
parent8c517ac2360d457bf752e964988ba098697a58b0 (diff)
Merge pull request #1418 from Montellese/grouping
grouping by movie set outside of the database
-rw-r--r--project/VS2010Express/XBMC.vcxproj2
-rw-r--r--project/VS2010Express/XBMC.vcxproj.filters6
-rw-r--r--xbmc/filesystem/SmartPlaylistDirectory.cpp2
-rw-r--r--xbmc/utils/EdenVideoArtUpdater.cpp2
-rw-r--r--xbmc/utils/GroupUtils.cpp131
-rw-r--r--xbmc/utils/GroupUtils.h42
-rw-r--r--xbmc/utils/Makefile1
-rw-r--r--xbmc/video/VideoDatabase.cpp184
-rw-r--r--xbmc/video/VideoDatabase.h4
-rw-r--r--xbmc/video/windows/GUIWindowVideoBase.cpp29
-rw-r--r--xbmc/video/windows/GUIWindowVideoBase.h2
-rw-r--r--xbmc/video/windows/GUIWindowVideoNav.cpp17
-rw-r--r--xbmc/windows/GUIMediaWindow.cpp102
-rw-r--r--xbmc/windows/GUIMediaWindow.h4
14 files changed, 301 insertions, 227 deletions
diff --git a/project/VS2010Express/XBMC.vcxproj b/project/VS2010Express/XBMC.vcxproj
index f0fd8c9f35..0ecd8896dd 100644
--- a/project/VS2010Express/XBMC.vcxproj
+++ b/project/VS2010Express/XBMC.vcxproj
@@ -1249,6 +1249,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug Testsuite|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release (DirectX)|Win32'">true</ExcludedFromBuild>
</ClCompile>
+ <ClCompile Include="..\..\xbmc\utils\GroupUtils.cpp" />
<ClCompile Include="..\..\xbmc\utils\HTMLTable.cpp" />
<ClCompile Include="..\..\xbmc\utils\HTMLUtil.cpp" />
<ClCompile Include="..\..\xbmc\utils\HttpHeader.cpp" />
@@ -2395,6 +2396,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug Testsuite|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release (DirectX)|Win32'">true</ExcludedFromBuild>
</ClInclude>
+ <ClInclude Include="..\..\xbmc\utils\GroupUtils.h" />
<ClInclude Include="..\..\xbmc\utils\HTMLTable.h" />
<ClInclude Include="..\..\xbmc\utils\HTMLUtil.h" />
<ClInclude Include="..\..\xbmc\utils\HttpHeader.h" />
diff --git a/project/VS2010Express/XBMC.vcxproj.filters b/project/VS2010Express/XBMC.vcxproj.filters
index 8923bfe3d7..4ff509fc01 100644
--- a/project/VS2010Express/XBMC.vcxproj.filters
+++ b/project/VS2010Express/XBMC.vcxproj.filters
@@ -2942,6 +2942,9 @@
<ClCompile Include="..\..\xbmc\filesystem\HTTPFile.cpp">
<Filter>filesystem</Filter>
</ClCompile>
+ <ClCompile Include="..\..\xbmc\utils\GroupUtils.cpp">
+ <Filter>utils</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\xbmc\win32\pch.h">
@@ -5749,6 +5752,9 @@
<ClInclude Include="..\..\xbmc\filesystem\HTTPFile.h">
<Filter>filesystem</Filter>
</ClInclude>
+ <ClInclude Include="..\..\xbmc\utils\GroupUtils.h">
+ <Filter>utils</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\xbmc\win32\XBMC_PC.rc">
diff --git a/xbmc/filesystem/SmartPlaylistDirectory.cpp b/xbmc/filesystem/SmartPlaylistDirectory.cpp
index 175159f743..95c7a1cf65 100644
--- a/xbmc/filesystem/SmartPlaylistDirectory.cpp
+++ b/xbmc/filesystem/SmartPlaylistDirectory.cpp
@@ -114,7 +114,7 @@ namespace XFILE
videoUrl.AddOption(option, xsp);
CDatabase::Filter dbfilter;
- success = db.GetSortedVideos(mediaType, videoUrl.ToString(), sorting, items, dbfilter, true);
+ success = db.GetSortedVideos(mediaType, videoUrl.ToString(), sorting, items, dbfilter);
db.Close();
// if we retrieve a list of episodes and we didn't receive
diff --git a/xbmc/utils/EdenVideoArtUpdater.cpp b/xbmc/utils/EdenVideoArtUpdater.cpp
index 390f9a7ad5..7f221aa4bb 100644
--- a/xbmc/utils/EdenVideoArtUpdater.cpp
+++ b/xbmc/utils/EdenVideoArtUpdater.cpp
@@ -76,7 +76,7 @@ void CEdenVideoArtUpdater::Process()
handle->SetTitle(g_localizeStrings.Get(12349));
// movies
- db.GetMoviesByWhere("videodb://1/2/", CDatabase::Filter(), items, false);
+ db.GetMoviesByWhere("videodb://1/2/", CDatabase::Filter(), items);
for (int i = 0; i < items.Size(); i++)
{
CFileItemPtr item = items[i];
diff --git a/xbmc/utils/GroupUtils.cpp b/xbmc/utils/GroupUtils.cpp
new file mode 100644
index 0000000000..a0b31db45e
--- /dev/null
+++ b/xbmc/utils/GroupUtils.cpp
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2012 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <map>
+#include <set>
+
+#include "GroupUtils.h"
+#include "FileItem.h"
+#include "utils/StringUtils.h"
+#include "utils/Variant.h"
+#include "video/VideoInfoTag.h"
+
+using namespace std;
+
+typedef map<int, set<CFileItemPtr> > SetMap;
+
+bool GroupUtils::Group(GroupBy groupBy, const CFileItemList &items, CFileItemList &groupedItems, GroupAttribute groupAttributes /* = GroupAttributeNone */)
+{
+ if (items.Size() <= 0 || groupBy == GroupByNone)
+ return false;
+
+ SetMap setMap;
+ for (int index = 0; index < items.Size(); index++)
+ {
+ bool add = true;
+ const CFileItemPtr item = items.Get(index);
+
+ // group by sets
+ if ((groupBy & GroupBySet) &&
+ item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_iSetId > 0)
+ {
+ add = false;
+ setMap[item->GetVideoInfoTag()->m_iSetId].insert(item);
+ }
+
+ if (add)
+ groupedItems.Add(item);
+ }
+
+ if ((groupBy & GroupBySet) && setMap.size() > 0)
+ {
+ for (SetMap::const_iterator set = setMap.begin(); set != setMap.end(); set++)
+ {
+ // only one item in the set, so just re-add it
+ if (set->second.size() == 1 && (groupAttributes & GroupAttributeIgnoreSingleItems))
+ {
+ groupedItems.Add(*set->second.begin());
+ continue;
+ }
+
+ CFileItemPtr pItem(new CFileItem((*set->second.begin())->GetVideoInfoTag()->m_strSet));
+ pItem->GetVideoInfoTag()->m_iDbId = set->first;
+ pItem->GetVideoInfoTag()->m_type = "set";
+ pItem->SetPath(StringUtils::Format("videodb://1/7/%ld/", set->first));
+ pItem->m_bIsFolder = true;
+
+ CVideoInfoTag* setInfo = pItem->GetVideoInfoTag();
+ setInfo->m_strPath = pItem->GetPath();
+ setInfo->m_strTitle = pItem->GetLabel();
+
+ int ratings = 0;
+ int iWatched = 0; // have all the movies been played at least once?
+ for (std::set<CFileItemPtr>::const_iterator movie = set->second.begin(); movie != set->second.end(); movie++)
+ {
+ CVideoInfoTag* movieInfo = (*movie)->GetVideoInfoTag();
+ // handle rating
+ if (movieInfo->m_fRating > 0.0f)
+ {
+ ratings++;
+ setInfo->m_fRating += movieInfo->m_fRating;
+ }
+
+ // handle year
+ if (movieInfo->m_iYear > setInfo->m_iYear)
+ setInfo->m_iYear = movieInfo->m_iYear;
+
+ // handle lastplayed
+ if (movieInfo->m_lastPlayed.IsValid() && movieInfo->m_lastPlayed > setInfo->m_lastPlayed)
+ setInfo->m_lastPlayed = movieInfo->m_lastPlayed;
+
+ // handle dateadded
+ if (movieInfo->m_dateAdded.IsValid() && movieInfo->m_dateAdded > setInfo->m_dateAdded)
+ setInfo->m_dateAdded = movieInfo->m_dateAdded;
+
+ // handle playcount/watched
+ setInfo->m_playCount += movieInfo->m_playCount;
+ if (movieInfo->m_playCount > 0)
+ iWatched++;
+ }
+
+ if (ratings > 1)
+ pItem->GetVideoInfoTag()->m_fRating /= ratings;
+
+ setInfo->m_playCount = iWatched >= (int)set->second.size() ? (setInfo->m_playCount / set->second.size()) : 0;
+ pItem->SetProperty("total", (int)set->second.size());
+ pItem->SetProperty("watched", iWatched);
+ pItem->SetProperty("unwatched", (int)set->second.size() - iWatched);
+ pItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, setInfo->m_playCount > 0);
+
+ groupedItems.Add(pItem);
+ }
+ }
+
+ return true;
+}
+
+bool GroupUtils::GroupAndSort(GroupBy groupBy, const CFileItemList &items, const SortDescription &sortDescription, CFileItemList &groupedItems, GroupAttribute groupAttributes /* = GroupAttributeNone */)
+{
+ if (!Group(groupBy, items, groupedItems, groupAttributes))
+ return false;
+
+ groupedItems.Sort(sortDescription);
+ return true;
+}
diff --git a/xbmc/utils/GroupUtils.h b/xbmc/utils/GroupUtils.h
new file mode 100644
index 0000000000..0e09450998
--- /dev/null
+++ b/xbmc/utils/GroupUtils.h
@@ -0,0 +1,42 @@
+#pragma once
+/*
+ * Copyright (C) 2012 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "SortUtils.h"
+
+class CFileItemList;
+
+// can be used as a flag
+typedef enum {
+ GroupByNone = 0x0,
+ GroupBySet = 0x1
+} GroupBy;
+
+typedef enum {
+ GroupAttributeNone = 0x0,
+ GroupAttributeIgnoreSingleItems = 0x1
+} GroupAttribute;
+
+class GroupUtils
+{
+public:
+ static bool Group(GroupBy groupBy, const CFileItemList &items, CFileItemList &groupedItems, GroupAttribute groupAttributes = GroupAttributeNone);
+ static bool GroupAndSort(GroupBy groupBy, const CFileItemList &items, const SortDescription &sortDescription, CFileItemList &groupedItems, GroupAttribute groupAttributes = GroupAttributeNone);
+};
diff --git a/xbmc/utils/Makefile b/xbmc/utils/Makefile
index b2a5c5fc3b..d2018846d5 100644
--- a/xbmc/utils/Makefile
+++ b/xbmc/utils/Makefile
@@ -23,6 +23,7 @@ SRCS=AlarmClock.cpp \
fstrcmp.c \
fft.cpp \
GLUtils.cpp \
+ GroupUtils.cpp \
HTMLTable.cpp \
HTMLUtil.cpp \
HttpHeader.cpp \
diff --git a/xbmc/video/VideoDatabase.cpp b/xbmc/video/VideoDatabase.cpp
index a698e801b1..3274f74117 100644
--- a/xbmc/video/VideoDatabase.cpp
+++ b/xbmc/video/VideoDatabase.cpp
@@ -55,6 +55,7 @@
#include "URL.h"
#include "video/VideoDbUrl.h"
#include "playlists/SmartPlayList.h"
+#include "utils/GroupUtils.h"
using namespace std;
using namespace dbiplus;
@@ -4815,111 +4816,21 @@ bool CVideoDatabase::GetSetsByWhere(const CStdString& strBaseDir, const Filter &
if (!videoUrl.FromString(strBaseDir))
return false;
- CStdString strSQL = "SELECT movieview.*, sets.strSet FROM movieview"
- " JOIN sets ON movieview.idSet = sets.idSet ";
- if (!filter.join.empty())
- strSQL += filter.join;
- if (!filter.where.empty())
- strSQL += " WHERE (" + filter.where + ")";
- strSQL += " ORDER BY sets.idSet";
- if (!filter.order.empty())
- strSQL += "," + filter.order;
- if (!filter.limit.empty())
- strSQL += " LIMIT " + filter.limit;
+ Filter setFilter = filter;
+ setFilter.join += " JOIN sets ON movieview.idSet = sets.idSet";
+ if (!setFilter.order.empty())
+ setFilter.order += ",";
+ setFilter.order += "sets.idSet";
- int iRowsFound = RunQuery(strSQL);
- if (iRowsFound <= 0)
- return iRowsFound == 0;
-
- map<int, CSetInfo> mapSets;
- map<int, CSetInfo>::iterator it;
- while (!m_pDS->eof())
- {
- if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE && !g_passwordManager.bMasterUser &&
- !g_passwordManager.IsDatabasePathUnlocked(CStdString(m_pDS->fv("movieview.strPath").get_asString()),g_settings.m_videoSources))
- continue;
-
- // get the setid and check if we already have this set
- int idSet = m_pDS->fv("movieview.idSet").get_asInt();
- if ((it = mapSets.find(idSet)) == mapSets.end())
- {
- // add the set to the list of sets
- CSetInfo set;
- set.name = m_pDS->fv("sets.strSet").get_asString();
-
- pair<map<int, CSetInfo>::iterator, bool> insertIt = mapSets.insert(make_pair(idSet, set));
- it = insertIt.first;
- }
-
- // add the movie's details to the set
- it->second.movies.push_back(GetDetailsForMovie(m_pDS));
-
- m_pDS->next();
- }
- m_pDS->close();
-
- for (it = mapSets.begin(); it != mapSets.end(); it++)
- {
- // we only handle sets with at least 2 movies
- if (it->second.movies.size() <= 0 ||
- (ignoreSingleMovieSets && it->second.movies.size() == 1))
- continue;
-
- CFileItemPtr pItem(new CFileItem(it->second.name));
- pItem->GetVideoInfoTag()->m_iDbId = it->first;
- pItem->GetVideoInfoTag()->m_type = "set";
-
- CVideoDbUrl itemUrl = videoUrl;
- CStdString strDir; strDir.Format("%ld/", it->first);
- itemUrl.AppendPath(strDir);
- pItem->SetPath(itemUrl.ToString());
-
- pItem->m_bIsFolder = true;
- pItem->GetVideoInfoTag()->m_strPath = pItem->GetPath();
- pItem->GetVideoInfoTag()->m_strTitle = pItem->GetLabel();
+ if (!GetMoviesByWhere(strBaseDir, setFilter, items))
+ return false;
- // calculate the remaining metadata from the movies
- int ratings = 0;
- int iWatched = 0; // have all the movies been played at least once?
- for (VECMOVIES::const_iterator movie = it->second.movies.begin(); movie != it->second.movies.end(); movie++)
- {
- // handle rating
- if (movie->m_fRating > 0.0f)
- {
- ratings++;
- pItem->GetVideoInfoTag()->m_fRating += movie->m_fRating;
- }
-
- // handle year
- if (movie->m_iYear > pItem->GetVideoInfoTag()->m_iYear)
- pItem->GetVideoInfoTag()->m_iYear = movie->m_iYear;
-
- // handle lastplayed
- if (movie->m_lastPlayed.IsValid() && movie->m_lastPlayed > pItem->GetVideoInfoTag()->m_lastPlayed)
- pItem->GetVideoInfoTag()->m_lastPlayed = movie->m_lastPlayed;
-
- // handle dateadded
- if (movie->m_dateAdded.IsValid() && movie->m_dateAdded > pItem->GetVideoInfoTag()->m_dateAdded)
- pItem->GetVideoInfoTag()->m_dateAdded = movie->m_dateAdded;
-
- // handle playcount/watched
- pItem->GetVideoInfoTag()->m_playCount += movie->m_playCount;
- if (movie->m_playCount > 0)
- iWatched++;
- }
-
- if (ratings > 1)
- pItem->GetVideoInfoTag()->m_fRating /= ratings;
-
- pItem->GetVideoInfoTag()->m_playCount = iWatched >= (int)it->second.movies.size() ? (pItem->GetVideoInfoTag()->m_playCount / it->second.movies.size()) : 0;
- pItem->SetProperty("total", (int)it->second.movies.size());
- pItem->SetProperty("watched", iWatched);
- pItem->SetProperty("unwatched", (int)it->second.movies.size() - iWatched);
- pItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, pItem->GetVideoInfoTag()->m_playCount > 0);
+ CFileItemList sets;
+ if (!GroupUtils::Group(GroupBySet, items, sets))
+ return false;
- if (!items.Contains(pItem->GetPath()))
- items.Add(pItem);
- }
+ items.ClearItems();
+ items.Append(sets);
return true;
}
@@ -5686,7 +5597,7 @@ bool CVideoDatabase::GetSeasonsNav(const CStdString& strBaseDir, CFileItemList&
return false;
}
-bool CVideoDatabase::GetSortedVideos(MediaType mediaType, const CStdString& strBaseDir, const SortDescription &sortDescription, CFileItemList& items, const Filter &filter /* = Filter() */, bool fetchSets /* = false */)
+bool CVideoDatabase::GetSortedVideos(MediaType mediaType, const CStdString& strBaseDir, const SortDescription &sortDescription, CFileItemList& items, const Filter &filter /* = Filter() */)
{
if (NULL == m_pDB.get() || NULL == m_pDS.get())
return false;
@@ -5710,7 +5621,7 @@ bool CVideoDatabase::GetSortedVideos(MediaType mediaType, const CStdString& strB
switch (mediaType)
{
case MediaTypeMovie:
- success = GetMoviesByWhere(strBaseDir, filter, items, fetchSets, sorting);
+ success = GetMoviesByWhere(strBaseDir, filter, items, sorting);
break;
case MediaTypeTvShow:
@@ -5760,10 +5671,10 @@ bool CVideoDatabase::GetMoviesNav(const CStdString& strBaseDir, CFileItemList& i
videoUrl.AddOption("tagid", idTag);
Filter filter;
- return GetMoviesByWhere(videoUrl.ToString(), filter, items, idSet == -1, sortDescription);
+ return GetMoviesByWhere(videoUrl.ToString(), filter, items, sortDescription);
}
-bool CVideoDatabase::GetMoviesByWhere(const CStdString& strBaseDir, const Filter &filter, CFileItemList& items, bool fetchSets /* = false */, const SortDescription &sortDescription /* = SortDescription() */)
+bool CVideoDatabase::GetMoviesByWhere(const CStdString& strBaseDir, const Filter &filter, CFileItemList& items, const SortDescription &sortDescription /* = SortDescription() */)
{
try
{
@@ -5780,50 +5691,10 @@ bool CVideoDatabase::GetMoviesByWhere(const CStdString& strBaseDir, const Filter
if (!videoUrl.FromString(strBaseDir) || !GetFilter(videoUrl, extFilter, sorting))
return false;
- // if we have a "setid" option we don't want to retrieve sets
- CVariant setId;
- if (fetchSets && videoUrl.GetOption("setid", setId) &&
- setId.isInteger() && setId.asInteger() > 0)
- fetchSets = false;
-
int total = -1;
CStdString strSQL = "select %s from movieview ";
CStdString strSQLExtra;
- CFileItemList setItems;
- if (fetchSets && g_guiSettings.GetBool("videolibrary.groupmoviesets"))
- {
- // user wants sets (and we're not fetching a particular set node), so grab all sets that match this where clause first
- Filter setsFilter;
- if (!extFilter.where.empty() || !extFilter.join.empty())
- {
- setsFilter.where = "movieview.idMovie in (select movieview.idMovie from movieview ";
- if (!extFilter.join.empty())
- setsFilter.where += extFilter.join;
- if (!extFilter.where.empty())
- setsFilter.where += " WHERE " + extFilter.where;
- setsFilter.where += ")";
- }
-
- CVideoDbUrl setUrl;
- if (!setUrl.FromString("videodb://1/7/"))
- return false;
-
- setUrl.AddOptions(videoUrl.GetOptionsString());
- GetSetsByWhere(setUrl.ToString(), setsFilter, setItems, true);
-
- CStdString movieSetsWhere;
- if (setItems.Size() > 0)
- {
- movieSetsWhere = "movieview.idMovie NOT IN (SELECT idMovie FROM movieview WHERE movieview.idSet IN (";
- for (int index = 0; index < setItems.Size(); index++)
- movieSetsWhere.AppendFormat("%s%d", index > 0 ? "," : "", setItems[index]->GetVideoInfoTag()->m_iDbId);
- movieSetsWhere += "))";
-
- extFilter.AppendWhere(movieSetsWhere);
- }
- }
-
if (!CDatabase::BuildSQL(strSQLExtra, extFilter, strSQLExtra))
return false;
@@ -5839,10 +5710,9 @@ bool CVideoDatabase::GetMoviesByWhere(const CStdString& strBaseDir, const Filter
strSQL = PrepareSQL(strSQL, !extFilter.fields.empty() ? extFilter.fields.c_str() : "*") + strSQLExtra;
int iRowsFound = RunQuery(strSQL);
- if (iRowsFound <= 0 && setItems.Size() == 0)
+ if (iRowsFound <= 0)
return iRowsFound == 0;
- iRowsFound += setItems.Size();
// store the total value of items as a property
if (total < iRowsFound)
total = iRowsFound;
@@ -5851,16 +5721,7 @@ bool CVideoDatabase::GetMoviesByWhere(const CStdString& strBaseDir, const Filter
DatabaseResults results;
results.reserve(iRowsFound);
- // Add the previously retrieved sets
- for (int index = 0; index < setItems.Size(); index++)
- {
- DatabaseResult result;
- setItems[index]->ToSortable(result);
- result[FieldRow] = (unsigned int)index;
- results.push_back(result);
- }
-
- if (!SortUtils::SortFromDataset(sorting, MediaTypeMovie, m_pDS, results))
+ if (!SortUtils::SortFromDataset(sortDescription, MediaTypeMovie, m_pDS, results))
return false;
// get data from returned rows
@@ -5869,13 +5730,6 @@ bool CVideoDatabase::GetMoviesByWhere(const CStdString& strBaseDir, const Filter
for (DatabaseResults::const_iterator it = results.begin(); it != results.end(); it++)
{
unsigned int targetRow = (unsigned int)it->at(FieldRow).asInteger();
- if (targetRow < (unsigned int)setItems.Size())
- {
- items.Add(setItems[targetRow]);
- continue;
- }
- targetRow -= setItems.Size();
-
const dbiplus::sql_record* const record = data.at(targetRow);
CVideoInfoTag movie = GetDetailsForMovie(record);
diff --git a/xbmc/video/VideoDatabase.h b/xbmc/video/VideoDatabase.h
index 225dc4964d..13de593dbb 100644
--- a/xbmc/video/VideoDatabase.h
+++ b/xbmc/video/VideoDatabase.h
@@ -640,14 +640,14 @@ public:
bool ImportArtFromXML(const TiXmlNode *node, std::map<std::string, std::string> &artwork);
// smart playlists and main retrieval work in these functions
- bool GetMoviesByWhere(const CStdString& strBaseDir, const Filter &filter, CFileItemList& items, bool fetchSets = false, const SortDescription &sortDescription = SortDescription());
+ bool GetMoviesByWhere(const CStdString& strBaseDir, const Filter &filter, CFileItemList& items, const SortDescription &sortDescription = SortDescription());
bool GetSetsByWhere(const CStdString& strBaseDir, const Filter &filter, CFileItemList& items, bool ignoreSingleMovieSets = false);
bool GetTvShowsByWhere(const CStdString& strBaseDir, const Filter &filter, CFileItemList& items, const SortDescription &sortDescription = SortDescription());
bool GetEpisodesByWhere(const CStdString& strBaseDir, const Filter &filter, CFileItemList& items, bool appendFullShowPath = true, const SortDescription &sortDescription = SortDescription());
bool GetMusicVideosByWhere(const CStdString &baseDir, const Filter &filter, CFileItemList& items, bool checkLocks = true, const SortDescription &sortDescription = SortDescription());
// retrieve sorted and limited items
- bool GetSortedVideos(MediaType mediaType, const CStdString& strBaseDir, const SortDescription &sortDescription, CFileItemList& items, const Filter &filter = Filter(), bool fetchSets = false);
+ bool GetSortedVideos(MediaType mediaType, const CStdString& strBaseDir, const SortDescription &sortDescription, CFileItemList& items, const Filter &filter = Filter());
// partymode
int GetMusicVideoCount(const CStdString& strWhere);
diff --git a/xbmc/video/windows/GUIWindowVideoBase.cpp b/xbmc/video/windows/GUIWindowVideoBase.cpp
index a147bf3252..937f8b7d4c 100644
--- a/xbmc/video/windows/GUIWindowVideoBase.cpp
+++ b/xbmc/video/windows/GUIWindowVideoBase.cpp
@@ -71,6 +71,7 @@
#include "URL.h"
#include "utils/EdenVideoArtUpdater.h"
#include "GUIInfoManager.h"
+#include "utils/GroupUtils.h"
using namespace std;
using namespace XFILE;
@@ -1787,7 +1788,9 @@ bool CGUIWindowVideoBase::Update(const CStdString &strDirectory, bool updateFilt
if (!CGUIMediaWindow::Update(strDirectory, updateFilterPath))
return false;
- m_thumbLoader.Load(*m_unfilteredItems);
+ // might already be running from GetGroupedItems
+ if (!m_thumbLoader.IsLoading())
+ m_thumbLoader.Load(*m_vecItems);
return true;
}
@@ -1839,8 +1842,30 @@ bool CGUIWindowVideoBase::StackingAvailable(const CFileItemList &items) const
url.GetProtocol() == "playlistvideo");
}
-void CGUIWindowVideoBase::OnPrepareFileItems(CFileItemList &items)
+void CGUIWindowVideoBase::GetGroupedItems(CFileItemList &items)
{
+ CGUIMediaWindow::GetGroupedItems(items);
+
+ CQueryParams params;
+ CVideoDatabaseDirectory dir;
+ dir.GetQueryParams(items.GetPath(), params);
+ if (items.GetContent().Equals("movies") && params.GetSetId() <= 0 &&
+ CVideoDatabaseDirectory::GetDirectoryChildType(items.GetPath()) != NODE_TYPE_RECENTLY_ADDED_MOVIES &&
+ g_guiSettings.GetBool("videolibrary.groupmoviesets"))
+ {
+ CFileItemList groupedItems;
+ if (GroupUtils::Group(GroupBySet, items, groupedItems, GroupAttributeIgnoreSingleItems))
+ {
+ items.ClearItems();
+ items.Append(groupedItems);
+ }
+ }
+
+ // reload thumbs after filtering and grouping
+ if (m_thumbLoader.IsLoading())
+ m_thumbLoader.StopThread();
+
+ m_thumbLoader.Load(items);
}
bool CGUIWindowVideoBase::CheckFilterAdvanced(CFileItemList &items) const
diff --git a/xbmc/video/windows/GUIWindowVideoBase.h b/xbmc/video/windows/GUIWindowVideoBase.h
index b4d555db9a..439f6c28d1 100644
--- a/xbmc/video/windows/GUIWindowVideoBase.h
+++ b/xbmc/video/windows/GUIWindowVideoBase.h
@@ -88,7 +88,7 @@ protected:
virtual bool Update(const CStdString &strDirectory, bool updateFilterPath = true);
virtual bool GetDirectory(const CStdString &strDirectory, CFileItemList &items);
virtual void OnItemLoaded(CFileItem* pItem) {};
- virtual void OnPrepareFileItems(CFileItemList &items);
+ virtual void GetGroupedItems(CFileItemList &items);
virtual bool CheckFilterAdvanced(CFileItemList &items) const;
virtual bool CanContainFilter(const CStdString &strDirectory) const;
diff --git a/xbmc/video/windows/GUIWindowVideoNav.cpp b/xbmc/video/windows/GUIWindowVideoNav.cpp
index fab7d9d808..8a268805cc 100644
--- a/xbmc/video/windows/GUIWindowVideoNav.cpp
+++ b/xbmc/video/windows/GUIWindowVideoNav.cpp
@@ -537,24 +537,9 @@ void CGUIWindowVideoNav::UpdateButtons()
bool CGUIWindowVideoNav::GetFilteredItems(const CStdString &filter, CFileItemList &items)
{
- bool listchanged = false;
- bool updateItems = false;
- if (!m_canFilterAdvanced)
- listchanged = CGUIMediaWindow::GetFilteredItems(filter, items);
- else
- listchanged = CGUIMediaWindow::GetAdvanceFilteredItems(items, updateItems);
-
+ bool listchanged = CGUIMediaWindow::GetFilteredItems(filter, items);
listchanged |= ApplyWatchedFilter(items);
- // there are new items so we need to run the thumbloader
- if (updateItems)
- {
- if (m_thumbLoader.IsLoading())
- m_thumbLoader.StopThread();
-
- m_thumbLoader.Load(items);
- }
-
return listchanged;
}
diff --git a/xbmc/windows/GUIMediaWindow.cpp b/xbmc/windows/GUIMediaWindow.cpp
index bf01668354..0f391b61ab 100644
--- a/xbmc/windows/GUIMediaWindow.cpp
+++ b/xbmc/windows/GUIMediaWindow.cpp
@@ -617,10 +617,6 @@ void CGUIMediaWindow::SortItems(CFileItemList &items)
if (!sorted)
items.Sort(sortMethod, guiState->GetDisplaySortOrder());
-
- // Should these items be saved to the hdd
- if (items.CacheToDiscAlways() && !IsFiltered())
- items.Save(GetID());
}
}
@@ -657,8 +653,9 @@ void CGUIMediaWindow::FormatAndSort(CFileItemList &items)
LABEL_MASKS labelMasks;
viewState->GetSortMethodLabelMasks(labelMasks);
FormatItemLabels(items, labelMasks);
+
+ items.Sort(viewState->GetSortMethod(), viewState->GetDisplaySortOrder());
}
- SortItems(items);
}
/*!
@@ -892,7 +889,16 @@ bool CGUIMediaWindow::Update(const CStdString &strDirectory, bool updateFilterPa
m_guiState.reset(CGUIViewState::GetViewState(GetID(), *m_vecItems));
- FormatAndSort(*m_vecItems);
+ // remember the original (untouched) list of items (for filtering etc)
+ m_unfilteredItems->SetPath(m_vecItems->GetPath()); // use the original path - it'll likely be relied on for other things later.
+ m_unfilteredItems->Append(*m_vecItems);
+
+ // Cache the list of items if possible
+ OnCacheFileItems(*m_vecItems);
+
+ // Filter and group the items if necessary
+ CStdString titleFilter = GetProperty("filter").asString();
+ OnFilterItems(titleFilter);
// Ask the devived class if it wants to do custom list operations,
// eg. changing the label
@@ -968,17 +974,22 @@ void CGUIMediaWindow::OnPrepareFileItems(CFileItemList &items)
}
+// \brief This function will be called by Update() before
+// any additional formatting, filtering or sorting is applied.
+// Override this function to define a custom caching behaviour.
+void CGUIMediaWindow::OnCacheFileItems(CFileItemList &items)
+{
+ // Should these items be saved to the hdd
+ if (items.CacheToDiscAlways() && !IsFiltered())
+ items.Save(GetID());
+}
+
// \brief This function will be called by Update() after the
// labels of the fileitems are formatted. Override this function
// to modify the fileitems. Eg. to modify the item label
void CGUIMediaWindow::OnFinalizeFileItems(CFileItemList &items)
{
- m_unfilteredItems->SetPath(items.GetPath()); // use the original path - it'll likely be relied on for other things later.
- m_unfilteredItems->Append(items);
-
- CStdString filter(GetProperty("filter").asString());
- OnFilterItems(filter);
}
// \brief With this function you can react on a users click in the list/thumb panel.
@@ -1695,24 +1706,52 @@ void CGUIMediaWindow::OnFilterItems(const CStdString &filter)
CFileItemList items(m_vecItems->GetPath()); // use the original path - it'll likely be relied on for other things later.
items.Append(*m_unfilteredItems);
- if (GetFilteredItems(filter, items) || m_vecItems->Size() != items.Size())
+ bool filtered = GetFilteredItems(filter, items);
+
+ m_vecItems->ClearItems();
+ // we need to clear the sort state and re-sort the items
+ m_vecItems->ClearSortState();
+ m_vecItems->Append(items);
+
+ // if the filter has changed, get the new filter path
+ if (filtered && m_canFilterAdvanced)
{
- m_vecItems->ClearItems();
- m_vecItems->Append(items);
+ if (items.HasProperty(PROPERTY_PATH_DB))
+ m_strFilterPath = items.GetProperty(PROPERTY_PATH_DB).asString();
+ else
+ m_strFilterPath = items.GetPath();
+ }
+
+ GetGroupedItems(*m_vecItems);
+ FormatAndSort(*m_vecItems);
- // we need to clear the sort state and re-sort the items
- m_vecItems->ClearSortState();
- SortItems(*m_vecItems);
+ // get the "filter" option
+ CStdString filterOption;
+ CURL filterUrl(m_strFilterPath);
+ if (filterUrl.HasOption("filter"))
+ filterOption = filterUrl.GetOption("filter");
+
+ // apply the "filter" option to any folder item so that
+ // the filter can be passed down to the sub-directory
+ for (int index = 0; index < m_vecItems->Size(); index++)
+ {
+ CFileItemPtr pItem = m_vecItems->Get(index);
+ // if the item is a folder we need to copy the path of
+ // the filtered item to be able to keep the applied filters
+ if (pItem->m_bIsFolder)
+ {
+ CURL itemUrl(pItem->GetPath());
+ itemUrl.SetOption("filter", filterOption);
+ pItem->SetPath(itemUrl.Get());
+ }
+ }
+ if (filtered)
+ {
if (!m_canFilterAdvanced)
SetProperty("filter", filter);
else
{
- if (items.HasProperty(PROPERTY_PATH_DB))
- m_strFilterPath = items.GetProperty(PROPERTY_PATH_DB).asString();
- else
- m_strFilterPath = items.GetPath();
-
// to be able to select the same item as before we need to adjust
// the path of the item i.e. add or remove the "filter=" URL option
// but that's only necessary for folder items
@@ -1738,10 +1777,7 @@ void CGUIMediaWindow::OnFilterItems(const CStdString &filter)
bool CGUIMediaWindow::GetFilteredItems(const CStdString &filter, CFileItemList &items)
{
if (m_canFilterAdvanced)
- {
- bool hasNewItems;
- return GetAdvanceFilteredItems(items, hasNewItems);
- }
+ return GetAdvanceFilteredItems(items);
CStdString trimmedFilter(filter);
trimmedFilter.TrimLeft().ToLower();
@@ -1786,10 +1822,8 @@ bool CGUIMediaWindow::GetFilteredItems(const CStdString &filter, CFileItemList &
return items.GetObjectCount() > 0;
}
-bool CGUIMediaWindow::GetAdvanceFilteredItems(CFileItemList &items, bool &hasNewItems)
+bool CGUIMediaWindow::GetAdvanceFilteredItems(CFileItemList &items)
{
- hasNewItems = false;
-
// don't run the advanced filter if the filter is empty
// and there hasn't been a filter applied before which
// would have to be removed
@@ -1831,11 +1865,6 @@ bool CGUIMediaWindow::GetAdvanceFilteredItems(CFileItemList &items, bool &hasNew
map<CStdString, CFileItemPtr>::iterator itItem = lookup.find(path);
if (itItem != lookup.end())
{
- // if the item is a folder we need to copy the path of
- // the filtered item to be able to keep the applied filters
- if (item->m_bIsFolder)
- item->SetPath(itItem->second->GetPath());
-
// add the item to the list of filtered items
filteredItems.Add(item);
@@ -1846,10 +1875,7 @@ bool CGUIMediaWindow::GetAdvanceFilteredItems(CFileItemList &items, bool &hasNew
}
if (resultItems.Size() > 0)
- {
- filteredItems.Append(resultItems);
- hasNewItems = true;
- }
+ CLog::Log(LOGWARNING, "CGUIMediaWindow::GetAdvanceFilteredItems(): %d unknown items", resultItems.Size());
items.ClearItems();
items.Append(filteredItems);
diff --git a/xbmc/windows/GUIMediaWindow.h b/xbmc/windows/GUIMediaWindow.h
index b8230432e5..aa1ae3dbde 100644
--- a/xbmc/windows/GUIMediaWindow.h
+++ b/xbmc/windows/GUIMediaWindow.h
@@ -86,7 +86,9 @@ protected:
virtual bool Refresh(bool clearCache = false);
virtual void FormatAndSort(CFileItemList &items);
virtual void OnPrepareFileItems(CFileItemList &items);
+ virtual void OnCacheFileItems(CFileItemList &items);
virtual void OnFinalizeFileItems(CFileItemList &items);
+ virtual void GetGroupedItems(CFileItemList &items) { }
void ClearFileItems();
virtual void SortItems(CFileItemList &items);
@@ -123,7 +125,7 @@ protected:
which were not present in the original list
\sa GetFilteredItems
*/
- virtual bool GetAdvanceFilteredItems(CFileItemList &items, bool &hasNewItems);
+ virtual bool GetAdvanceFilteredItems(CFileItemList &items);
// check for a disc or connection
virtual bool HaveDiscOrConnection(const CStdString& strPath, int iDriveType);