Merge branch 'container_foldername'
[vuplus_xbmc] / xbmc / filesystem / VideoDatabaseDirectory / DirectoryNode.cpp
1 /*
2  *      Copyright (C) 2005-2008 Team XBMC
3  *      http://www.xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, write to
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21
22 #include "DirectoryNode.h"
23 #include "utils/URIUtils.h"
24 #include "QueryParams.h"
25 #include "DirectoryNodeRoot.h"
26 #include "DirectoryNodeOverview.h"
27 #include "DirectoryNodeGenre.h"
28 #include "DirectoryNodeCountry.h"
29 #include "DirectoryNodeSets.h"
30 #include "DirectoryNodeTitleMovies.h"
31 #include "DirectoryNodeTitleTvShows.h"
32 #include "DirectoryNodeYear.h"
33 #include "DirectoryNodeActor.h"
34 #include "DirectoryNodeDirector.h"
35 #include "DirectoryNodeMoviesOverview.h"
36 #include "DirectoryNodeTvShowsOverview.h"
37 #include "DirectoryNodeSeasons.h"
38 #include "DirectoryNodeEpisodes.h"
39 #include "DirectoryNodeRecentlyAddedMovies.h"
40 #include "DirectoryNodeRecentlyAddedEpisodes.h"
41 #include "DirectoryNodeStudio.h"
42 #include "DirectoryNodeMusicVideosOverview.h"
43 #include "DirectoryNodeRecentlyAddedMusicVideos.h"
44 #include "DirectoryNodeTitleMusicVideos.h"
45 #include "DirectoryNodeMusicVideoAlbum.h"
46 #include "video/VideoInfoTag.h"
47 #include "URL.h"
48 #include "settings/AdvancedSettings.h"
49 #include "FileItem.h"
50 #include "filesystem/File.h"
51 #include "utils/StringUtils.h"
52 #include "guilib/LocalizeStrings.h"
53
54 using namespace std;
55 using namespace XFILE::VIDEODATABASEDIRECTORY;
56
57 //  Constructor is protected use ParseURL()
58 CDirectoryNode::CDirectoryNode(NODE_TYPE Type, const CStdString& strName, CDirectoryNode* pParent)
59 {
60   m_Type=Type;
61   m_strName=strName;
62   m_pParent=pParent;
63 }
64
65 CDirectoryNode::~CDirectoryNode()
66 {
67   delete m_pParent;
68 }
69
70 //  Parses a given path and returns the current node of the path
71 CDirectoryNode* CDirectoryNode::ParseURL(const CStdString& strPath)
72 {
73   CURL url(strPath);
74
75   CStdString strDirectory=url.GetFileName();
76   URIUtils::RemoveSlashAtEnd(strDirectory);
77
78   CStdStringArray Path;
79   StringUtils::SplitString(strDirectory, "/", Path);
80   if (!strDirectory.IsEmpty())
81     Path.insert(Path.begin(), "");
82
83   CDirectoryNode* pNode=NULL;
84   CDirectoryNode* pParent=NULL;
85   NODE_TYPE NodeType=NODE_TYPE_ROOT;
86
87   for (int i=0; i<(int)Path.size(); ++i)
88   {
89     pNode=CDirectoryNode::CreateNode(NodeType, Path[i], pParent);
90     NodeType= pNode ? pNode->GetChildType() : NODE_TYPE_NONE;
91     pParent=pNode;
92   }
93
94   return pNode;
95 }
96
97 //  returns the database ids of the path,
98 void CDirectoryNode::GetDatabaseInfo(const CStdString& strPath, CQueryParams& params)
99 {
100   auto_ptr<CDirectoryNode> pNode(CDirectoryNode::ParseURL(strPath));
101
102   if (!pNode.get())
103     return;
104
105   pNode->CollectQueryParams(params);
106 }
107
108 //  Create a node object
109 CDirectoryNode* CDirectoryNode::CreateNode(NODE_TYPE Type, const CStdString& strName, CDirectoryNode* pParent)
110 {
111   switch (Type)
112   {
113   case NODE_TYPE_ROOT:
114     return new CDirectoryNodeRoot(strName, pParent);
115   case NODE_TYPE_OVERVIEW:
116     return new CDirectoryNodeOverview(strName, pParent);
117   case NODE_TYPE_GENRE:
118     return new CDirectoryNodeGenre(strName, pParent);
119   case NODE_TYPE_COUNTRY:
120     return new CDirectoryNodeCountry(strName, pParent);
121   case NODE_TYPE_SETS:
122     return new CDirectoryNodeSets(strName, pParent);
123   case NODE_TYPE_YEAR:
124     return new CDirectoryNodeYear(strName, pParent);
125   case NODE_TYPE_ACTOR:
126     return new CDirectoryNodeActor(strName, pParent);
127   case NODE_TYPE_DIRECTOR:
128     return new CDirectoryNodeDirector(strName, pParent);
129   case NODE_TYPE_TITLE_MOVIES:
130     return new CDirectoryNodeTitleMovies(strName, pParent);
131   case NODE_TYPE_TITLE_TVSHOWS:
132     return new CDirectoryNodeTitleTvShows(strName, pParent);
133   case NODE_TYPE_MOVIES_OVERVIEW:
134     return new CDirectoryNodeMoviesOverview(strName, pParent);
135   case NODE_TYPE_TVSHOWS_OVERVIEW:
136     return new CDirectoryNodeTvShowsOverview(strName, pParent);
137   case NODE_TYPE_SEASONS:
138     return new CDirectoryNodeSeasons(strName, pParent);
139   case NODE_TYPE_EPISODES:
140     return new CDirectoryNodeEpisodes(strName, pParent);
141   case NODE_TYPE_RECENTLY_ADDED_MOVIES:
142     return new CDirectoryNodeRecentlyAddedMovies(strName,pParent);
143   case NODE_TYPE_RECENTLY_ADDED_EPISODES:
144     return new CDirectoryNodeRecentlyAddedEpisodes(strName,pParent);
145   case NODE_TYPE_STUDIO:
146     return new CDirectoryNodeStudio(strName,pParent);
147   case NODE_TYPE_MUSICVIDEOS_OVERVIEW:
148     return new CDirectoryNodeMusicVideosOverview(strName,pParent);
149   case NODE_TYPE_RECENTLY_ADDED_MUSICVIDEOS:
150     return new CDirectoryNodeRecentlyAddedMusicVideos(strName,pParent);
151   case NODE_TYPE_TITLE_MUSICVIDEOS:
152     return new CDirectoryNodeTitleMusicVideos(strName,pParent);
153   case NODE_TYPE_MUSICVIDEOS_ALBUM:
154     return new CDirectoryNodeMusicVideoAlbum(strName,pParent);
155   default:
156     break;
157   }
158
159   return NULL;
160 }
161
162 //  Current node name
163 const CStdString& CDirectoryNode::GetName() const
164 {
165   return m_strName;
166 }
167
168 int CDirectoryNode::GetID() const
169 {
170   return atoi(m_strName.c_str());
171 }
172
173 CStdString CDirectoryNode::GetLocalizedName() const
174 {
175   return "";
176 }
177
178 //  Current node type
179 NODE_TYPE CDirectoryNode::GetType() const
180 {
181   return m_Type;
182 }
183
184 //  Return the parent directory node or NULL, if there is no
185 CDirectoryNode* CDirectoryNode::GetParent() const
186 {
187   return m_pParent;
188 }
189
190 void CDirectoryNode::RemoveParent()
191 {
192   m_pParent=NULL;
193 }
194
195 //  should be overloaded by a derived class
196 //  to get the content of a node. Will be called
197 //  by GetChilds() of a parent node
198 bool CDirectoryNode::GetContent(CFileItemList& items) const
199 {
200   return false;
201 }
202
203 //  Creates a videodb url
204 CStdString CDirectoryNode::BuildPath() const
205 {
206   CStdStringArray array;
207
208   if (!m_strName.IsEmpty())
209     array.insert(array.begin(), m_strName);
210
211   CDirectoryNode* pParent=m_pParent;
212   while (pParent!=NULL)
213   {
214     const CStdString& strNodeName=pParent->GetName();
215     if (!strNodeName.IsEmpty())
216       array.insert(array.begin(), strNodeName);
217
218     pParent=pParent->GetParent();
219   }
220
221   CStdString strPath="videodb://";
222   for (int i=0; i<(int)array.size(); ++i)
223     strPath+=array[i]+"/";
224
225   return strPath;
226 }
227
228 //  Collects Query params from this and all parent nodes. If a NODE_TYPE can
229 //  be used as a database parameter, it will be added to the
230 //  params object.
231 void CDirectoryNode::CollectQueryParams(CQueryParams& params) const
232 {
233   params.SetQueryParam(m_Type, m_strName);
234
235   CDirectoryNode* pParent=m_pParent;
236   while (pParent!=NULL)
237   {
238     params.SetQueryParam(pParent->GetType(), pParent->GetName());
239     pParent=pParent->GetParent();
240   }
241 }
242
243 //  Should be overloaded by a derived class.
244 //  Returns the NODE_TYPE of the child nodes.
245 NODE_TYPE CDirectoryNode::GetChildType() const
246 {
247   return NODE_TYPE_NONE;
248 }
249
250 //  Get the child fileitems of this node
251 bool CDirectoryNode::GetChilds(CFileItemList& items)
252 {
253   if (CanCache() && items.Load())
254     return true;
255
256   auto_ptr<CDirectoryNode> pNode(CDirectoryNode::CreateNode(GetChildType(), "", this));
257
258   bool bSuccess=false;
259   if (pNode.get())
260   {
261     bSuccess=pNode->GetContent(items);
262     if (bSuccess)
263     {
264       AddQueuingFolder(items);
265       if (CanCache())
266         items.SetCacheToDisc(CFileItemList::CACHE_ALWAYS);
267     }
268     else
269       items.Clear();
270
271     pNode->RemoveParent();
272   }
273
274   return bSuccess;
275 }
276
277 //  Add an "* All ..." folder to the CFileItemList
278 //  depending on the child node
279 void CDirectoryNode::AddQueuingFolder(CFileItemList& items) const
280 {
281   CFileItemPtr pItem;
282
283   // always hide "all" items
284   if (g_advancedSettings.m_bVideoLibraryHideAllItems)
285     return;
286
287   // no need for "all" item when only one item
288   if (items.GetObjectCount() <= 1)
289     return;
290
291   // hack - as the season node might return episodes
292   auto_ptr<CDirectoryNode> pNode(ParseURL(items.m_strPath));
293
294   switch (pNode->GetChildType())
295   {
296     case NODE_TYPE_SEASONS:
297       {
298         CStdString strLabel = g_localizeStrings.Get(20366);
299         pItem.reset(new CFileItem(strLabel));  // "All Seasons"
300         pItem->m_strPath = BuildPath() + "-1/";
301         // set the number of watched and unwatched items accordingly
302         int watched = 0;
303         int unwatched = 0;
304         for (int i = 0; i < items.Size(); i++)
305         {
306           CFileItemPtr item = items[i];
307           watched += item->GetPropertyInt("watchedepisodes");
308           unwatched += item->GetPropertyInt("unwatchedepisodes");
309         }
310         pItem->SetProperty("totalepisodes", watched + unwatched);
311         pItem->SetProperty("numepisodes", watched + unwatched); // will be changed later to reflect watchmode setting
312         pItem->SetProperty("watchedepisodes", watched);
313         pItem->SetProperty("unwatchedepisodes", unwatched);
314         if (items.Size() && items[0]->GetVideoInfoTag())
315         {
316           *pItem->GetVideoInfoTag() = *items[0]->GetVideoInfoTag();
317           pItem->GetVideoInfoTag()->m_iSeason = -1;
318         }
319         pItem->GetVideoInfoTag()->m_strTitle = strLabel;
320         pItem->GetVideoInfoTag()->m_iEpisode = watched + unwatched;
321         pItem->GetVideoInfoTag()->m_playCount = (unwatched == 0) ? 1 : 0;
322         if (XFILE::CFile::Exists(pItem->GetCachedSeasonThumb()))
323           pItem->SetThumbnailImage(pItem->GetCachedSeasonThumb());
324       }
325       break;
326     default:
327       break;
328   }
329
330   if (pItem)
331   {
332     pItem->m_bIsFolder = true;
333     pItem->SetSpecialSort(g_advancedSettings.m_bVideoLibraryAllItemsOnBottom ? SORT_ON_BOTTOM : SORT_ON_TOP);
334     pItem->SetCanQueue(false);
335     items.Add(pItem);
336   }
337 }
338
339 bool CDirectoryNode::CanCache() const
340 {
341   //  Only cache the directorys in the root
342   //NODE_TYPE childnode=GetChildType();
343   //NODE_TYPE node=GetType();
344
345   // something should probably be cached
346   return true;//(childnode==NODE_TYPE_TITLE_MOVIES || childnode==NODE_TYPE_EPISODES || childnode == NODE_TYPE_SEASONS || childnode == NODE_TYPE_TITLE_TVSHOWS);
347 }