2 * Copyright (C) 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 "DirectoryProvider.h"
22 #include "filesystem/Directory.h"
23 #include "filesystem/FavouritesDirectory.h"
24 #include "guilib/GUIWindowManager.h"
25 #include "utils/JobManager.h"
26 #include "utils/StringUtils.h"
27 #include "utils/TimeUtils.h"
28 #include "utils/XMLUtils.h"
29 #include "utils/StringUtils.h"
30 #include "utils/URIUtils.h"
31 #include "utils/log.h"
32 #include "threads/SingleLock.h"
33 #include "ApplicationMessenger.h"
35 #include "video/VideoThumbLoader.h"
36 #include "music/MusicThumbLoader.h"
37 #include "pictures/PictureThumbLoader.h"
38 #include "boost/make_shared.hpp"
39 #include "interfaces/AnnouncementManager.h"
42 using namespace XFILE;
43 using namespace ANNOUNCEMENT;
45 class CDirectoryJob : public CJob
48 CDirectoryJob(const std::string &url, int parentID) : m_url(url), m_parentID(parentID) { };
49 virtual ~CDirectoryJob() {};
51 virtual const char* GetType() const { return "directory"; };
52 virtual bool operator==(const CJob *job) const
54 if (strcmp(job->GetType(),GetType()) == 0)
56 const CDirectoryJob* dirJob = dynamic_cast<const CDirectoryJob*>(job);
57 if (dirJob && dirJob->m_url == m_url)
66 if (CDirectory::GetDirectory(m_url, items, ""))
68 // convert to CGUIStaticItem's and set visibility and targets
69 m_items.reserve(items.Size());
70 for (int i = 0; i < items.Size(); i++)
72 CGUIStaticItemPtr item(new CGUIStaticItem(*items[i]));
73 if (item->HasProperty("node.visible"))
74 item->SetVisibleCondition(item->GetProperty("node.visible").asString(), m_parentID);
76 getThumbLoader(item)->LoadItem(item.get());
78 m_items.push_back(item);
80 m_target = items.GetProperty("node.target").asString();
85 boost::shared_ptr<CThumbLoader> getThumbLoader(CGUIStaticItemPtr &item)
89 initThumbLoader<CVideoThumbLoader>(VIDEO);
90 return m_thumbloaders[VIDEO];
94 initThumbLoader<CMusicThumbLoader>(AUDIO);
95 return m_thumbloaders[AUDIO];
97 if (item->IsPicture())
99 initThumbLoader<CPictureThumbLoader>(PICTURE);
100 return m_thumbloaders[PICTURE];
102 initThumbLoader<CProgramThumbLoader>(PROGRAM);
103 return m_thumbloaders[PROGRAM];
106 template<class CThumbLoaderClass>
107 void initThumbLoader(InfoTagType type)
109 if (!m_thumbloaders.count(type))
111 boost::shared_ptr<CThumbLoader> thumbLoader = boost::make_shared<CThumbLoaderClass>();
112 thumbLoader->OnLoaderStart();
113 m_thumbloaders.insert(make_pair(type, thumbLoader));
117 const std::vector<CGUIStaticItemPtr> &GetItems() const { return m_items; }
118 const std::string &GetTarget() const { return m_target; }
119 std::vector<InfoTagType> GetItemTypes(std::vector<InfoTagType> &itemTypes) const
122 for (std::map<InfoTagType, boost::shared_ptr<CThumbLoader> >::const_iterator
123 i = m_thumbloaders.begin(); i != m_thumbloaders.end(); ++i)
124 itemTypes.push_back(i->first);
129 std::string m_target;
131 std::vector<CGUIStaticItemPtr> m_items;
132 std::map<InfoTagType, boost::shared_ptr<CThumbLoader> > m_thumbloaders;
135 CDirectoryProvider::CDirectoryProvider(const TiXmlElement *element, int parentID)
136 : IListProvider(parentID),
139 m_isDbUpdating(false),
140 m_isAnnounced(false),
144 if (!element->NoChildren())
146 const char *target = element->Attribute("target");
148 m_target.SetLabel(target, "", parentID);
149 m_url.SetLabel(element->FirstChild()->ValueStr(), "", parentID);
153 CDirectoryProvider::~CDirectoryProvider()
158 bool CDirectoryProvider::Update(bool forceRefresh)
160 // we never need to force refresh here
161 bool changed = false;
162 bool fireJob = false;
164 CSingleLock lock(m_section);
165 if (m_updateState == DONE)
167 else if (m_updateState == PENDING)
172 // update the URL and fire off a new job if needed
173 if (fireJob || UpdateURL())
176 for (vector<CGUIStaticItemPtr>::iterator i = m_items.begin(); i != m_items.end(); ++i)
177 changed |= (*i)->UpdateVisibility(m_parentID);
178 return changed; // TODO: Also returned changed if properties are changed (if so, need to update scroll to letter).
181 void CDirectoryProvider::Announce(AnnouncementFlag flag, const char *sender, const char *message, const CVariant &data)
183 // we are only interested in library changes
184 if ((flag & (VideoLibrary | AudioLibrary)) == 0)
188 CSingleLock lock(m_section);
189 // we don't need to refresh anything if there are no fitting
190 // items in this list provider for the announcement flag
191 if (((flag & VideoLibrary) &&
192 (std::find(m_itemTypes.begin(), m_itemTypes.end(), VIDEO) == m_itemTypes.end())) ||
193 ((flag & AudioLibrary) &&
194 (std::find(m_itemTypes.begin(), m_itemTypes.end(), AUDIO) == m_itemTypes.end())))
197 // don't update while scanning / cleaning
198 if (strcmp(message, "OnScanStarted") == 0 ||
199 strcmp(message, "OnCleanStarted") == 0)
201 m_isDbUpdating = true;
205 // if there was a database update, we set the update state
206 // to PENDING to fire off a new job in the next update
207 if (strcmp(message, "OnScanFinished") == 0 ||
208 strcmp(message, "OnCleanFinished") == 0 ||
209 ((strcmp(message, "OnUpdate") == 0 ||
210 strcmp(message, "OnRemove") == 0) && !m_isDbUpdating))
212 m_isDbUpdating = false;
213 m_updateState = PENDING;
218 void CDirectoryProvider::Fetch(vector<CGUIListItemPtr> &items) const
220 CSingleLock lock(m_section);
222 for (vector<CGUIStaticItemPtr>::const_iterator i = m_items.begin(); i != m_items.end(); ++i)
224 if ((*i)->IsVisible())
229 void CDirectoryProvider::Reset(bool immediately /* = false */)
231 // cancel any pending jobs
232 CSingleLock lock(m_section);
234 CJobManager::GetInstance().CancelJob(m_jobID);
236 // reset only if this is going to be destructed
240 m_currentTarget.clear();
241 m_currentUrl.clear();
244 RegisterListProvider(false);
248 void CDirectoryProvider::OnJobComplete(unsigned int jobID, bool success, CJob *job)
250 CSingleLock lock(m_section);
253 m_items = ((CDirectoryJob*)job)->GetItems();
254 m_currentTarget = ((CDirectoryJob*)job)->GetTarget();
255 ((CDirectoryJob*)job)->GetItemTypes(m_itemTypes);
256 m_updateState = DONE;
261 bool CDirectoryProvider::OnClick(const CGUIListItemPtr &item)
263 CFileItem fileItem(*boost::static_pointer_cast<CFileItem>(item));
264 string target = fileItem.GetProperty("node.target").asString();
266 target = m_currentTarget;
268 target = m_target.GetLabel(m_parentID, false);
269 if (fileItem.HasProperty("node.target_url"))
270 fileItem.SetPath(fileItem.GetProperty("node.target_url").asString());
271 // grab the execute string
272 string execute = CFavouritesDirectory::GetExecutePath(fileItem, target);
273 if (!execute.empty())
275 CGUIMessage message(GUI_MSG_EXECUTE, 0, 0);
276 message.SetStringParam(execute);
277 g_windowManager.SendMessage(message);
283 bool CDirectoryProvider::IsUpdating() const
285 CSingleLock lock(m_section);
286 return m_jobID || (m_updateState == DONE);
289 void CDirectoryProvider::FireJob()
291 CSingleLock lock(m_section);
293 CJobManager::GetInstance().CancelJob(m_jobID);
294 m_jobID = CJobManager::GetInstance().AddJob(new CDirectoryJob(m_currentUrl, m_parentID), this);
297 void CDirectoryProvider::RegisterListProvider(bool hasLibraryContent)
299 if (hasLibraryContent && !m_isAnnounced)
301 m_isAnnounced = true;
302 CAnnouncementManager::AddAnnouncer(this);
304 else if (!hasLibraryContent && m_isAnnounced)
306 m_isAnnounced = false;
307 m_isDbUpdating = false;
308 CAnnouncementManager::RemoveAnnouncer(this);
312 bool CDirectoryProvider::UpdateURL()
314 CStdString value(m_url.GetLabel(m_parentID, false));
315 if (value == m_currentUrl)
318 m_currentUrl = value;
320 // Register this provider only if we have library content
321 RegisterListProvider(URIUtils::IsLibraryContent(m_currentUrl));