#include "qquickfolderlistmodel.h"
#include "fileinfothread_p.h"
#include "fileproperty_p.h"
#include <qqmlcontext.h>
#include <qqmlfile.h>
class QQuickFolderListModelPrivate
{
Q_DECLARE_PUBLIC(QQuickFolderListModel)
public:
QQuickFolderListModelPrivate(QQuickFolderListModel *q)
: q_ptr(q),
sortField(QQuickFolderListModel::Name), sortReversed(false), showDirs(true), showDirsFirst(false), showDots(false), showOnlyReadable(false)
{
nameFilters << QLatin1String("*");
}
QQuickFolderListModel *q_ptr;
QUrl currentDir;
QUrl rootDir;
FileInfoThread fileInfoThread;
QList<FileProperty> data;
QHash<int, QByteArray> roleNames;
QQuickFolderListModel::SortField sortField;
QStringList nameFilters;
bool sortReversed;
bool showDirs;
bool showDirsFirst;
bool showDots;
bool showOnlyReadable;
~QQuickFolderListModelPrivate() {}
void init();
void updateSorting();
void _q_directoryChanged(const QString &directory, const QList<FileProperty> &list);
void _q_directoryUpdated(const QString &directory, const QList<FileProperty> &list, int fromIndex, int toIndex);
void _q_sortFinished(const QList<FileProperty> &list);
};
void QQuickFolderListModelPrivate::init()
{
Q_Q(QQuickFolderListModel);
qRegisterMetaType<QList<FileProperty> >("QList<FileProperty>");
q->connect(&fileInfoThread, SIGNAL(directoryChanged(QString, QList<FileProperty>)),
q, SLOT(_q_directoryChanged(QString, QList<FileProperty>)));
q->connect(&fileInfoThread, SIGNAL(directoryUpdated(QString, QList<FileProperty>, int, int)),
q, SLOT(_q_directoryUpdated(QString, QList<FileProperty>, int, int)));
q->connect(&fileInfoThread, SIGNAL(sortFinished(QList<FileProperty>)),
q, SLOT(_q_sortFinished(QList<FileProperty>)));
}
void QQuickFolderListModelPrivate::updateSorting()
{
Q_Q(QQuickFolderListModel);
QDir::SortFlags flags = 0;
switch (sortField) {
case QQuickFolderListModel::Unsorted:
flags |= QDir::Unsorted;
break;
case QQuickFolderListModel::Name:
flags |= QDir::Name;
break;
case QQuickFolderListModel::Time:
flags |= QDir::Time;
break;
case QQuickFolderListModel::Size:
flags |= QDir::Size;
break;
case QQuickFolderListModel::Type:
flags |= QDir::Type;
break;
default:
break;
}
emit q->layoutAboutToBeChanged();
if (sortReversed)
flags |= QDir::Reversed;
fileInfoThread.setSortFlags(flags);
}
void QQuickFolderListModelPrivate::_q_directoryChanged(const QString &directory, const QList<FileProperty> &list)
{
Q_Q(QQuickFolderListModel);
Q_UNUSED(directory);
data = list;
q->endResetModel();
emit q->rowCountChanged();
emit q->folderChanged();
}
void QQuickFolderListModelPrivate::_q_directoryUpdated(const QString &directory, const QList<FileProperty> &list, int fromIndex, int toIndex)
{
Q_Q(QQuickFolderListModel);
Q_UNUSED(directory);
QModelIndex parent;
if (data.size() > list.size()) {
data = list;
q->beginRemoveRows(parent, fromIndex, toIndex);
q->endRemoveRows();
q->beginInsertRows(parent, fromIndex, list.size()-1);
q->endInsertRows();
emit q->rowCountChanged();
} else if (data.size() < list.size()) {
toIndex = fromIndex + (list.size() - data.size()-1);
q->beginInsertRows(parent, fromIndex, toIndex);
q->endInsertRows();
data = list;
emit q->rowCountChanged();
QModelIndex modelIndexFrom = q->createIndex(fromIndex, 0);
QModelIndex modelIndexTo = q->createIndex(toIndex, 0);
emit q->dataChanged(modelIndexFrom, modelIndexTo);
} else {
QModelIndex modelIndexFrom = q->createIndex(fromIndex, 0);
QModelIndex modelIndexTo = q->createIndex(toIndex, 0);
data = list;
emit q->dataChanged(modelIndexFrom, modelIndexTo);
}
}
void QQuickFolderListModelPrivate::_q_sortFinished(const QList<FileProperty> &list)
{
Q_Q(QQuickFolderListModel);
QModelIndex parent;
q->beginRemoveRows(parent, 0, data.size()-1);
data.clear();
q->endRemoveRows();
q->beginInsertRows(parent, 0, list.size()-1);
data = list;
q->endInsertRows();
}
QQuickFolderListModel::QQuickFolderListModel(QObject *parent)
: QAbstractListModel(parent), d_ptr(new QQuickFolderListModelPrivate(this))
{
Q_D(QQuickFolderListModel);
d->roleNames[FileNameRole] = "fileName";
d->roleNames[FilePathRole] = "filePath";
d->roleNames[FileBaseNameRole] = "fileBaseName";
d->roleNames[FileSuffixRole] = "fileSuffix";
d->roleNames[FileSizeRole] = "fileSize";
d->roleNames[FileLastModifiedRole] = "fileModified";
d->roleNames[FileLastReadRole] = "fileAccessed";
d->roleNames[FileIsDirRole] = "fileIsDir";
d->init();
}
QQuickFolderListModel::~QQuickFolderListModel()
{
}
QVariant QQuickFolderListModel::data(const QModelIndex &index, int role) const
{
Q_D(const QQuickFolderListModel);
QVariant rv;
if (index.row() >= d->data.size())
return rv;
switch (role)
{
case FileNameRole:
rv = d->data.at(index.row()).fileName();
break;
case FilePathRole:
rv = d->data.at(index.row()).filePath();
break;
case FileBaseNameRole:
rv = d->data.at(index.row()).baseName();
break;
case FileSuffixRole:
rv = d->data.at(index.row()).suffix();
break;
case FileSizeRole:
rv = d->data.at(index.row()).size();
break;
case FileLastModifiedRole:
rv = d->data.at(index.row()).lastModified().date().toString(Qt::ISODate) + " " + d->data.at(index.row()).lastModified().time().toString();
break;
case FileLastReadRole:
rv = d->data.at(index.row()).lastRead().date().toString(Qt::ISODate) + " " + d->data.at(index.row()).lastRead().time().toString();
break;
case FileIsDirRole:
rv = d->data.at(index.row()).isDir();
break;
default:
break;
}
return rv;
}
QHash<int, QByteArray> QQuickFolderListModel::roleNames() const
{
Q_D(const QQuickFolderListModel);
return d->roleNames;
}
int QQuickFolderListModel::rowCount(const QModelIndex &parent) const
{
Q_D(const QQuickFolderListModel);
Q_UNUSED(parent);
return d->data.size();
}
QModelIndex QQuickFolderListModel::index(int row, int , const QModelIndex &) const
{
return createIndex(row, 0);
}
QUrl QQuickFolderListModel::folder() const
{
Q_D(const QQuickFolderListModel);
return d->currentDir;
}
void QQuickFolderListModel::setFolder(const QUrl &folder)
{
Q_D(QQuickFolderListModel);
if (folder == d->currentDir)
return;
QString localPath = QQmlFile::urlToLocalFileOrQrc(folder);
QString resolvedPath = QDir::cleanPath(QUrl(localPath).path());
beginResetModel();
if (!d->currentDir.isEmpty())
d->fileInfoThread.removePath(d->currentDir.path());
d->currentDir = folder;
QFileInfo info(resolvedPath);
if (!info.exists() || !info.isDir()) {
d->data.clear();
endResetModel();
emit rowCountChanged();
return;
}
d->fileInfoThread.setPath(resolvedPath);
}
QUrl QQuickFolderListModel::rootFolder() const
{
Q_D(const QQuickFolderListModel);
return d->rootDir;
}
void QQuickFolderListModel::setRootFolder(const QUrl &path)
{
Q_D(QQuickFolderListModel);
if (path.isEmpty())
return;
QString localPath = QQmlFile::urlToLocalFileOrQrc(path);
QString resolvedPath = QDir::cleanPath(QUrl(localPath).path());
QFileInfo info(resolvedPath);
if (!info.exists() || !info.isDir())
return;
d->fileInfoThread.setRootPath(resolvedPath);
d->rootDir = path;
}
QUrl QQuickFolderListModel::parentFolder() const
{
Q_D(const QQuickFolderListModel);
QString localFile = d->currentDir.toLocalFile();
if (!localFile.isEmpty()) {
QDir dir(localFile);
#if defined(Q_OS_WIN)
if (dir.isRoot())
dir.setPath("");
else
#endif
dir.cdUp();
localFile = dir.path();
} else {
int pos = d->currentDir.path().lastIndexOf(QLatin1Char('/'));
if (pos == -1)
return QUrl();
localFile = d->currentDir.path().left(pos);
}
return QUrl::fromLocalFile(localFile);
}
QStringList QQuickFolderListModel::nameFilters() const
{
Q_D(const QQuickFolderListModel);
return d->nameFilters;
}
void QQuickFolderListModel::setNameFilters(const QStringList &filters)
{
Q_D(QQuickFolderListModel);
d->fileInfoThread.setNameFilters(filters);
d->nameFilters = filters;
}
void QQuickFolderListModel::classBegin()
{
}
void QQuickFolderListModel::componentComplete()
{
Q_D(QQuickFolderListModel);
if (!d->currentDir.isValid() || d->currentDir.toLocalFile().isEmpty() || !QDir().exists(d->currentDir.toLocalFile()))
setFolder(QUrl(QLatin1String("file://")+QDir::currentPath()));
}
QQuickFolderListModel::SortField QQuickFolderListModel::sortField() const
{
Q_D(const QQuickFolderListModel);
return d->sortField;
}
void QQuickFolderListModel::setSortField(SortField field)
{
Q_D(QQuickFolderListModel);
if (field != d->sortField) {
d->sortField = field;
d->updateSorting();
}
}
int QQuickFolderListModel::roleFromString(const QString &roleName) const
{
Q_D(const QQuickFolderListModel);
return d->roleNames.key(roleName.toLatin1(), -1);
}
bool QQuickFolderListModel::sortReversed() const
{
Q_D(const QQuickFolderListModel);
return d->sortReversed;
}
void QQuickFolderListModel::setSortReversed(bool rev)
{
Q_D(QQuickFolderListModel);
if (rev != d->sortReversed) {
d->sortReversed = rev;
d->updateSorting();
}
}
bool QQuickFolderListModel::isFolder(int index) const
{
if (index != -1) {
QModelIndex idx = createIndex(index, 0);
if (idx.isValid()) {
QVariant var = data(idx, FileIsDirRole);
if (var.isValid())
return var.toBool();
}
}
return false;
}
bool QQuickFolderListModel::showDirs() const
{
Q_D(const QQuickFolderListModel);
return d->showDirs;
}
void QQuickFolderListModel::setShowDirs(bool on)
{
Q_D(QQuickFolderListModel);
d->fileInfoThread.setShowDirs(on);
d->showDirs = on;
}
bool QQuickFolderListModel::showDirsFirst() const
{
Q_D(const QQuickFolderListModel);
return d->showDirsFirst;
}
void QQuickFolderListModel::setShowDirsFirst(bool on)
{
Q_D(QQuickFolderListModel);
d->fileInfoThread.setShowDirsFirst(on);
d->showDirsFirst = on;
}
bool QQuickFolderListModel::showDotAndDotDot() const
{
Q_D(const QQuickFolderListModel);
return d->showDots;
}
void QQuickFolderListModel::setShowDotAndDotDot(bool on)
{
Q_D(QQuickFolderListModel);
if (on != d->showDots) {
d->fileInfoThread.setShowDotDot(on);
}
}
bool QQuickFolderListModel::showOnlyReadable() const
{
Q_D(const QQuickFolderListModel);
return d->showOnlyReadable;
}
void QQuickFolderListModel::setShowOnlyReadable(bool on)
{
Q_D(QQuickFolderListModel);
if (on != d->showOnlyReadable) {
d->fileInfoThread.setShowOnlyReadable(on);
}
}
QVariant QQuickFolderListModel::get(int idx, const QString &property) const
{
int role = roleFromString(property);
if (role >= 0 && idx >= 0)
return data(index(idx, 0), role);
else
return QVariant();
}
#include "moc_qquickfolderlistmodel.cpp"