31 #include <QApplication>
34 #include <QStandardItemModel>
35 #include <QSortFilterProxyModel>
36 #include <QFileSystemWatcher>
47 , RelativePath_ (relPath)
48 , SubElemModel_ (new QStandardItemModel (this))
49 , AttrFilters_ (QDir::Dirs | QDir::NoDotAndDotDot | QDir::Readable)
50 , SortModel_ (new QSortFilterProxyModel (this))
51 , Watcher_ (new QFileSystemWatcher (this))
52 , CacheFlushTimer_ (new QTimer (this))
53 , CachePathContents_ (0)
56 if (RelativePath_.startsWith (
'/'))
57 RelativePath_ = RelativePath_.mid (1);
58 if (!RelativePath_.endsWith (
'/'))
59 RelativePath_.append (
'/');
61 SortModel_->setDynamicSortFilter (
true);
62 SortModel_->setSourceModel (SubElemModel_);
66 SIGNAL (directoryChanged (
const QString&)),
68 SLOT (handleDirectoryChanged (
const QString&)));
70 connect (CacheFlushTimer_,
73 SLOT (handleFlushCaches ()));
76 void ResourceLoader::AddLocalPrefix (QString prefix)
78 if (!prefix.isEmpty () &&
79 !prefix.endsWith (
'/'))
81 QString result = QDir::homePath () +
"/.leechcraft/data/" + prefix;
82 LocalPrefixesChain_ << result;
84 QDir testDir = QDir::home ();
85 if (!testDir.exists (
".leechcraft/data/" + prefix + RelativePath_))
87 qDebug () << Q_FUNC_INFO
88 <<
".leechcraft/data/" + prefix + RelativePath_
89 <<
"doesn't exist, trying to create it...";
91 if (!testDir.mkpath (
".leechcraft/data/" + prefix + RelativePath_))
93 qWarning () << Q_FUNC_INFO
95 <<
".leechcraft/data/" + prefix + RelativePath_;
99 ScanPath (result + RelativePath_);
101 Watcher_->addPath (result + RelativePath_);
104 void ResourceLoader::AddGlobalPrefix ()
106 #if defined (Q_OS_MAC) && !defined (USE_UNIX_LAYOUT)
107 const QStringList prefixes { QApplication::applicationDirPath () +
"/../Resources/share/" };
108 #elif defined (Q_OS_WIN32)
109 const QStringList prefixes { QApplication::applicationDirPath () +
"/share/" };
110 #elif defined (INSTALL_PREFIX)
111 const QStringList prefixes { INSTALL_PREFIX
"/share/leechcraft/" };
113 const QStringList prefixes
115 "/usr/local/share/leechcraft/",
116 "/usr/share/leechcraft/"
119 bool hasBeenAdded =
false;
120 for (
const auto& prefix : prefixes)
122 GlobalPrefixesChain_ << prefix;
123 ScanPath (prefix + RelativePath_);
125 if (QFile::exists (prefix + RelativePath_))
127 Watcher_->addPath (prefix + RelativePath_);
133 qWarning () << Q_FUNC_INFO
134 <<
"no prefixes have been added:"
140 void ResourceLoader::SetCacheParams (
int size,
int timeout)
142 if (qApp->property (
"no-resource-caching").toBool ())
147 CacheFlushTimer_->stop ();
149 handleFlushCaches ();
154 CacheFlushTimer_->start (timeout);
156 CachePathContents_.setMaxCost (size * 1024);
157 CachePixmaps_.setMaxCost (size * 1024);
161 void ResourceLoader::FlushCache ()
163 handleFlushCaches ();
166 QFileInfoList ResourceLoader::List (
const QString& option,
167 const QStringList& nameFilters, QDir::Filters filters)
const
169 QSet<QString> alreadyListed;
170 QFileInfoList result;
171 for (
const auto& prefix : LocalPrefixesChain_ + GlobalPrefixesChain_)
173 const QDir dir { prefix + RelativePath_ + option };
174 const auto& list = dir.entryInfoList (nameFilters, filters);
175 for (
const auto& info : list)
177 const auto& fname = info.fileName ();
178 if (alreadyListed.contains (fname))
181 alreadyListed << fname;
189 QString ResourceLoader::GetPath (
const QStringList& pathVariants)
const
191 for (
const auto& prefix : LocalPrefixesChain_ + GlobalPrefixesChain_)
192 for (
const auto& path : pathVariants)
194 const QString& can = QFileInfo (prefix + RelativePath_ + path).absoluteFilePath ();
195 if (QFile::exists (can))
204 QStringList IconizeBasename (
const QString& basename)
216 QString ResourceLoader::GetIconPath (
const QString& basename)
const
218 return GetPath (IconizeBasename (basename));
221 QIODevice_ptr ResourceLoader::Load (
const QStringList& pathVariants,
bool open)
const
223 const auto& path = GetPath (pathVariants);
227 if (CachePathContents_.contains (path))
229 auto result = std::make_shared<QBuffer> ();
230 result->setData (*CachePathContents_ [path]);
232 result->open (QIODevice::ReadOnly);
236 auto result = std::make_shared<QFile> (path);
238 if (!result->isSequential () &&
239 result->size () < CachePathContents_.maxCost () / 2)
241 if (result->open (QIODevice::ReadOnly))
243 const auto& data = result->readAll ();
244 CachePathContents_.insert (path,
new QByteArray { data }, data.size ());
252 if (open && !result->isOpen ())
253 if (!result->open (QIODevice::ReadOnly))
254 qWarning () << Q_FUNC_INFO
255 <<
"unable to open file"
257 << result->errorString ();
262 QIODevice_ptr ResourceLoader::Load (
const QString& pathVariant,
bool open)
const
264 return Load (QStringList { pathVariant }, open);
267 QIODevice_ptr ResourceLoader::GetIconDevice (
const QString& basename,
bool open)
const
269 return Load (IconizeBasename (basename), open);
272 QPixmap ResourceLoader::LoadPixmap (
const QString& basename)
const
274 if (CachePixmaps_.contains (basename))
275 return *CachePixmaps_ [basename];
277 auto dev = GetIconDevice (basename,
true);
281 const auto& data = dev->readAll ();
284 result.loadFromData (data);
285 CachePixmaps_.insert (basename,
new QPixmap (result), data.size ());
289 QAbstractItemModel* ResourceLoader::GetSubElemModel ()
const
294 void ResourceLoader::SetAttrFilters (QDir::Filters filters)
296 AttrFilters_ = filters;
299 void ResourceLoader::SetNameFilters (
const QStringList& filters)
301 NameFilters_ = filters;
304 void ResourceLoader::ScanPath (
const QString& path)
306 for (
const auto& entry : QDir (path).entryList (NameFilters_, AttrFilters_))
308 Entry2Paths_ [entry] << path;
309 if (SubElemModel_->findItems (entry).size ())
312 SubElemModel_->appendRow (
new QStandardItem (entry));
316 void ResourceLoader::handleDirectoryChanged (
const QString& path)
318 emit watchedDirectoriesChanged ();
320 for (
auto i = Entry2Paths_.begin (), end = Entry2Paths_.end (); i != end; ++i)
329 QStringList toRemove;
330 for (
auto i = Entry2Paths_.begin (), end = Entry2Paths_.end (); i != end; ++i)
332 toRemove << i.key ();
334 for (
const auto& entry : toRemove)
336 Entry2Paths_.remove (entry);
338 auto items = SubElemModel_->findItems (entry);
339 for (
auto item : SubElemModel_->findItems (entry))
340 SubElemModel_->removeRow (item->row ());
344 void ResourceLoader::handleFlushCaches ()
346 CachePathContents_.clear ();
347 CachePixmaps_.clear ();