2 * Copyright (C) 2005-2012 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 "Directory.h"
22 #include "DirectoryFactory.h"
23 #include "FileDirectoryFactory.h"
24 #include "commons/Exception.h"
26 #include "DirectoryCache.h"
27 #include "settings/GUISettings.h"
28 #include "utils/log.h"
29 #include "utils/Job.h"
30 #include "utils/JobManager.h"
31 #include "Application.h"
32 #include "guilib/GUIWindowManager.h"
33 #include "dialogs/GUIDialogBusy.h"
34 #include "threads/SingleLock.h"
35 #include "utils/URIUtils.h"
38 using namespace XFILE;
40 #define TIME_TO_BUSY_DIALOG 500
48 CResult(const CStdString& dir) : m_event(true), m_dir(dir), m_result(false) {}
58 CGetJob(boost::shared_ptr<IDirectory>& imp
59 , boost::shared_ptr<CResult>& result)
66 m_result->m_list.SetPath(m_result->m_dir);
67 m_result->m_result = m_imp->GetDirectory(m_result->m_dir, m_result->m_list);
68 m_result->m_event.Set();
69 return m_result->m_result;
72 boost::shared_ptr<CResult> m_result;
73 boost::shared_ptr<IDirectory> m_imp;
78 CGetDirectory(boost::shared_ptr<IDirectory>& imp, const CStdString& dir)
79 : m_result(new CResult(dir))
81 m_id = CJobManager::GetInstance().AddJob(new CGetJob(imp, m_result)
83 , CJob::PRIORITY_HIGH);
87 CJobManager::GetInstance().CancelJob(m_id);
90 bool Wait(unsigned int timeout)
92 return m_result->m_event.WaitMSec(timeout);
95 bool GetDirectory(CFileItemList& list)
97 /* if it was not finished or failed, return failure */
98 if(!m_result->m_event.WaitMSec(0) || !m_result->m_result)
104 list.Copy(m_result->m_list);
107 boost::shared_ptr<CResult> m_result;
112 CDirectory::CDirectory()
115 CDirectory::~CDirectory()
118 bool CDirectory::GetDirectory(const CStdString& strPath, CFileItemList &items, const CStdString &strMask /*=""*/, int flags /*=DIR_FLAG_DEFAULTS*/, bool allowThreads /* = false */)
122 hints.mask = strMask;
123 return GetDirectory(strPath, items, hints, allowThreads);
126 bool CDirectory::GetDirectory(const CStdString& strPath, CFileItemList &items, const CHints &hints, bool allowThreads)
130 CStdString realPath = URIUtils::SubstitutePath(strPath);
131 boost::shared_ptr<IDirectory> pDirectory(CDirectoryFactory::Create(realPath));
132 if (!pDirectory.get())
135 // check our cache for this path
136 if (g_directoryCache.GetDirectory(strPath, items, (hints.flags & DIR_FLAG_READ_CACHE) == DIR_FLAG_READ_CACHE))
137 items.SetPath(strPath);
140 // need to clear the cache (in case the directory fetch fails)
141 // and (re)fetch the folder
142 if (!(hints.flags & DIR_FLAG_BYPASS_CACHE))
143 g_directoryCache.ClearDirectory(strPath);
145 pDirectory->SetFlags(hints.flags);
147 bool result = false, cancel = false;
148 while (!result && !cancel)
150 if (g_application.IsCurrentThread() && allowThreads && !URIUtils::IsSpecial(strPath))
152 CSingleExit ex(g_graphicsContext);
154 CGetDirectory get(pDirectory, realPath);
155 if(!get.Wait(TIME_TO_BUSY_DIALOG))
157 CGUIDialogBusy* dialog = (CGUIDialogBusy*)g_windowManager.GetWindow(WINDOW_DIALOG_BUSY);
162 CSingleLock lock(g_graphicsContext);
165 float progress = pDirectory->GetProgress();
167 dialog->SetProgress(progress);
169 if(dialog->IsCanceled())
172 pDirectory->CancelDirectory();
176 lock.Leave(); // prevent an occasional deadlock on exit
177 g_windowManager.ProcessRenderLoop(false);
182 result = get.GetDirectory(items);
186 items.SetPath(strPath);
187 result = pDirectory->GetDirectory(realPath, items);
192 if (!cancel && g_application.IsCurrentThread() && pDirectory->ProcessRequirements())
194 CLog::Log(LOGERROR, "%s - Error getting %s", __FUNCTION__, strPath.c_str());
199 // cache the directory, if necessary
200 if (!(hints.flags & DIR_FLAG_BYPASS_CACHE))
201 g_directoryCache.SetDirectory(strPath, items, pDirectory->GetCacheType(strPath));
204 // now filter for allowed files
205 pDirectory->SetMask(hints.mask);
206 for (int i = 0; i < items.Size(); ++i)
208 CFileItemPtr item = items[i];
209 // TODO: we shouldn't be checking the gui setting here;
210 // callers should use getHidden instead
211 if ((!item->m_bIsFolder && !pDirectory->IsAllowed(item->GetPath())) ||
212 (item->GetProperty("file:hidden").asBoolean() && !(hints.flags & DIR_FLAG_GET_HIDDEN) && !g_guiSettings.GetBool("filelists.showhidden")))
215 i--; // don't confuse loop
219 // Should any of the files we read be treated as a directory?
220 // Disable for database folders, as they already contain the extracted items
221 if (!(hints.flags & DIR_FLAG_NO_FILE_DIRS) && !items.IsMusicDb() && !items.IsVideoDb() && !items.IsSmartPlayList())
222 FilterFileDirectories(items, hints.mask);
226 XBMCCOMMONS_HANDLE_UNCHECKED
229 CLog::Log(LOGERROR, "%s - Unhandled exception", __FUNCTION__);
231 CLog::Log(LOGERROR, "%s - Error getting %s", __FUNCTION__, strPath.c_str());
235 bool CDirectory::Create(const CStdString& strPath)
239 CStdString realPath = URIUtils::SubstitutePath(strPath);
240 auto_ptr<IDirectory> pDirectory(CDirectoryFactory::Create(realPath));
241 if (pDirectory.get())
242 if(pDirectory->Create(realPath.c_str()))
245 XBMCCOMMONS_HANDLE_UNCHECKED
248 CLog::Log(LOGERROR, "%s - Unhandled exception", __FUNCTION__);
250 CLog::Log(LOGERROR, "%s - Error creating %s", __FUNCTION__, strPath.c_str());
254 bool CDirectory::Exists(const CStdString& strPath)
258 CStdString realPath = URIUtils::SubstitutePath(strPath);
259 auto_ptr<IDirectory> pDirectory(CDirectoryFactory::Create(realPath));
260 if (pDirectory.get())
261 return pDirectory->Exists(realPath.c_str());
263 XBMCCOMMONS_HANDLE_UNCHECKED
266 CLog::Log(LOGERROR, "%s - Unhandled exception", __FUNCTION__);
268 CLog::Log(LOGERROR, "%s - Error checking for %s", __FUNCTION__, strPath.c_str());
272 bool CDirectory::Remove(const CStdString& strPath)
276 CStdString realPath = URIUtils::SubstitutePath(strPath);
277 auto_ptr<IDirectory> pDirectory(CDirectoryFactory::Create(realPath));
278 if (pDirectory.get())
279 if(pDirectory->Remove(realPath.c_str()))
282 XBMCCOMMONS_HANDLE_UNCHECKED
285 CLog::Log(LOGERROR, "%s - Unhandled exception", __FUNCTION__);
287 CLog::Log(LOGERROR, "%s - Error removing %s", __FUNCTION__, strPath.c_str());
291 void CDirectory::FilterFileDirectories(CFileItemList &items, const CStdString &mask)
293 for (int i=0; i< items.Size(); ++i)
295 CFileItemPtr pItem=items[i];
296 if ((!pItem->m_bIsFolder) && (!pItem->IsInternetStream()))
298 auto_ptr<IFileDirectory> pDirectory(CFileDirectoryFactory::Create(pItem->GetPath(),pItem.get(),mask));
299 if (pDirectory.get())
300 pItem->m_bIsFolder = true;
302 if (pItem->m_bIsFolder)
305 i--; // don't confuse loop