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 ()));
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_);
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:" 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);
163 handleFlushCaches ();
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;
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)
218 return GetPath (IconizeBasename (basename));
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 ();
264 return Load (QStringList { pathVariant }, open);
269 return Load (IconizeBasename (basename), open);
274 if (CachePixmaps_.contains (basename))
275 return *CachePixmaps_ [basename];
281 const auto& data = dev->readAll ();
284 result.loadFromData (data);
285 CachePixmaps_.insert (basename,
new QPixmap (result), data.size ());
296 AttrFilters_ = 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)
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 ();
QIODevice_ptr GetIconDevice(const QString &basename, bool open=false) const
Returns the QIODevice for the corresponding icon.
QString GetIconPath(const QString &basename) const
Calls GetPath() with standard variants for the icon extensions.
void watchedDirectoriesChanged()
void SetAttrFilters(QDir::Filters)
Sets the attribute filters for the subelement model.
void AddLocalPrefix(QString prefix=QString())
Registers a local search prefix.
QIODevice_ptr Load(const QStringList &pathVariants, bool open=false) const
Returns the QIODevice for the corresponding resource.
QFileInfoList List(const QString &option, const QStringList &names={}, QDir::Filters filters=QDir::NoFilter) const
Lists the available files for the given option.
void SetNameFilters(const QStringList &)
Sets the name filters for the subelement model.
QAbstractItemModel * GetSubElemModel() const
Returns the subelement model with the contents of registered paths.
void SetCacheParams(int size, int timeout)
Sets the caching parameters of this loader.
void AddGlobalPrefix()
Registers global OS-dependent prefixes.
QString GetPath(const QStringList &pathVariants) const
Returns the first found path for the list of variants.
void FlushCache()
Forcefully flushes the cache.
ResourceLoader(const QString &relPath, QObject *obj=0)
Initializes the loader with the given path.
QPixmap LoadPixmap(const QString &basename) const
Returns the pixmap for the given basename.
std::shared_ptr< QIODevice > QIODevice_ptr