Integrated file selection dialogue with the main code. Improved the
[openvpnui.git] / src / filebrowse / filemodel.cpp
diff --git a/src/filebrowse/filemodel.cpp b/src/filebrowse/filemodel.cpp
new file mode 100644 (file)
index 0000000..562f29e
--- /dev/null
@@ -0,0 +1,337 @@
+#include "filemodel.h"
+#include <QDateTime>
+#include <QSettings>
+#include <QGuiApplication>
+#include "engine.h"
+#include "globals.h"
+
+enum {
+    FilenameRole = Qt::UserRole + 1,
+    FileKindRole = Qt::UserRole + 2,
+    FileIconRole = Qt::UserRole + 3,
+    PermissionsRole = Qt::UserRole + 4,
+    SizeRole = Qt::UserRole + 5,
+    LastModifiedRole = Qt::UserRole + 6,
+    CreatedRole = Qt::UserRole + 7,
+    IsDirRole = Qt::UserRole + 8,
+    IsLinkRole = Qt::UserRole + 9,
+    SymLinkTargetRole = Qt::UserRole + 10
+};
+
+FileModel::FileModel(QObject *parent) :
+    QAbstractListModel(parent),
+    m_active(false),
+    m_dirty(false)
+{
+    m_dir = "";
+    m_watcher = new QFileSystemWatcher(this);
+    connect(m_watcher, SIGNAL(directoryChanged(const QString&)), this, SLOT(refresh()));
+    connect(m_watcher, SIGNAL(fileChanged(const QString&)), this, SLOT(refresh()));
+
+    QSettings settings;
+    m_showAll = settings.value("showAll", false).toBool();
+
+    // refresh model every time settings are changed
+    Engine *engine = qApp->property("engine").value<Engine *>();
+    connect(engine, SIGNAL(settingsChanged()), this, SLOT(refreshFull()));
+}
+
+FileModel::~FileModel()
+{
+}
+
+int FileModel::rowCount(const QModelIndex &parent) const
+{
+    Q_UNUSED(parent);
+    return m_files.count();
+}
+
+QVariant FileModel::data(const QModelIndex &index, int role) const
+{
+    if (!index.isValid() || index.row() > m_files.size()-1)
+        return QVariant();
+
+    QFileInfo info = m_files.at(index.row()).info;
+    switch (role) {
+
+    case Qt::DisplayRole:
+    case FilenameRole:
+        return info.fileName();
+
+    case FileKindRole:
+        if (info.isSymLink()) return "l";
+        if (info.isDir()) return "d";
+        if (info.isFile()) return "-";
+        return "?";
+
+    case FileIconRole:
+        if (info.isSymLink() && info.isDir()) return "folder-link";
+        if (info.isDir()) return "folder";
+        if (info.isSymLink()) return "link";
+        if (info.isFile()) {
+            QString suffix = info.suffix().toLower();
+            return suffixToIconName(suffix);
+        }
+        return "file";
+
+    case PermissionsRole:
+        return permissionsToString(info.permissions());
+
+    case SizeRole:
+        if (info.isSymLink() && info.isDir()) return "dir-link";
+        if (info.isDir()) return "dir";
+        return filesizeToString(info.size());
+
+    case LastModifiedRole:
+        return datetimeToString(info.lastModified());
+
+    case CreatedRole:
+        return datetimeToString(info.created());
+
+    case IsDirRole:
+        return info.isDir();
+
+    case IsLinkRole:
+        return info.isSymLink();
+
+    case SymLinkTargetRole:
+        return info.symLinkTarget();
+
+    default:
+        return QVariant();
+    }
+}
+
+QHash<int, QByteArray> FileModel::roleNames() const
+{
+    QHash<int, QByteArray> roles = QAbstractListModel::roleNames();
+    roles.insert(FilenameRole, QByteArray("filename"));
+    roles.insert(FileKindRole, QByteArray("filekind"));
+    roles.insert(FileIconRole, QByteArray("fileIcon"));
+    roles.insert(PermissionsRole, QByteArray("permissions"));
+    roles.insert(SizeRole, QByteArray("size"));
+    roles.insert(LastModifiedRole, QByteArray("modified"));
+    roles.insert(CreatedRole, QByteArray("created"));
+    roles.insert(IsDirRole, QByteArray("isDir"));
+    roles.insert(IsLinkRole, QByteArray("isLink"));
+    roles.insert(SymLinkTargetRole, QByteArray("symLinkTarget"));
+    return roles;
+}
+
+int FileModel::fileCount() const
+{
+    return m_files.count();
+}
+
+QString FileModel::errorMessage() const
+{
+    return m_errorMessage;
+}
+
+void FileModel::setDir(QString dir)
+{
+    if (m_dir == dir)
+        return;
+
+    // update watcher to watch the new directory
+    if (!m_dir.isEmpty())
+        m_watcher->removePath(m_dir);
+    if (!dir.isEmpty())
+        m_watcher->addPath(dir);
+
+    m_dir = dir;
+
+    readDirectory();
+    m_dirty = false;
+
+    emit dirChanged();
+}
+
+QString FileModel::appendPath(QString dirName)
+{
+    return QDir::cleanPath(QDir(m_dir).absoluteFilePath(dirName));
+}
+
+void FileModel::setActive(bool active)
+{
+    if (m_active == active)
+        return;
+
+    m_active = active;
+    emit activeChanged();
+
+    if (m_dirty)
+        readDirectory();
+
+    m_dirty = false;
+}
+
+QString FileModel::parentPath()
+{
+    return QDir::cleanPath(QDir(m_dir).absoluteFilePath(".."));
+}
+
+QString FileModel::fileNameAt(int fileIndex)
+{
+    if (fileIndex < 0 || fileIndex >= m_files.count())
+        return QString();
+
+    return m_files.at(fileIndex).info.absoluteFilePath();
+}
+
+void FileModel::refresh()
+{
+    if (!m_active) {
+        m_dirty = true;
+        return;
+    }
+
+    refreshEntries();
+    m_dirty = false;
+}
+
+void FileModel::refreshFull()
+{
+    if (!m_active) {
+        m_dirty = true;
+        return;
+    }
+
+    readDirectory();
+    m_dirty = false;
+}
+
+void FileModel::readDirectory()
+{
+    // wrapped in reset model methods to get views notified
+    beginResetModel();
+
+    m_files.clear();
+    m_errorMessage = "";
+
+    if (!m_dir.isEmpty())
+        readEntries();
+
+    endResetModel();
+    emit fileCountChanged();
+    emit errorMessageChanged();
+}
+
+void FileModel::readEntries()
+{
+    QDir dir(m_dir);
+    if (!dir.exists()) {
+        m_errorMessage = tr("Folder does not exist");
+        return;
+    }
+    if (access(m_dir, R_OK) == -1) {
+        m_errorMessage = tr("No permission to read the folder");
+        return;
+    }
+
+    QSettings settings;
+    bool hiddenSetting = settings.value("show-hidden-files", false).toBool();
+    QDir::Filter hidden = hiddenSetting ? QDir::Hidden : (QDir::Filter)0;
+    dir.setFilter(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot | hidden);
+
+    if (settings.value("show-dirs-first", false).toBool())
+        dir.setSorting(QDir::Name | QDir::DirsFirst);
+
+    Engine *engine = qApp->property("engine").value<Engine *>();
+
+    QFileInfoList infoList = dir.entryInfoList();
+    foreach (QFileInfo info, infoList) {
+        if (m_showAll || (info.isDir()) || (info.suffix() == engine->extensionFilter())) {
+            FileData data;
+            data.info = info;
+            m_files.append(data);
+        }
+    }
+}
+
+void FileModel::refreshEntries()
+{
+    m_errorMessage = "";
+
+    // empty dir name
+    if (m_dir.isEmpty()) {
+        beginResetModel();
+        m_files.clear();
+        endResetModel();
+        emit fileCountChanged();
+        emit errorMessageChanged();
+        return;
+    }
+
+    QDir dir(m_dir);
+    if (!dir.exists()) {
+        m_errorMessage = tr("Folder does not exist");
+        emit errorMessageChanged();
+        return;
+    }
+    if (access(m_dir, R_OK) == -1) {
+        m_errorMessage = tr("No permission to read the folder");
+        emit errorMessageChanged();
+        return;
+    }
+
+    QSettings settings;
+    bool hiddenSetting = settings.value("show-hidden-files", false).toBool();
+    QDir::Filter hidden = hiddenSetting ? QDir::Hidden : (QDir::Filter)0;
+    dir.setFilter(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot | hidden);
+
+    if (settings.value("show-dirs-first", false).toBool())
+        dir.setSorting(QDir::Name | QDir::DirsFirst);
+
+    Engine *engine = qApp->property("engine").value<Engine *>();
+
+    // read all files
+    QList<FileData> newFiles;
+    QFileInfoList infoList = dir.entryInfoList();
+    foreach (QFileInfo info, infoList) {
+        if ((m_showAll) || (info.isDir()) || (info.suffix() == engine->extensionFilter())) {
+            FileData data;
+            data.info = info;
+            newFiles.append(data);
+        }
+    }
+
+    int oldFileCount = m_files.count();
+
+    // compare old and new files and do removes if needed
+    for (int i = m_files.count()-1; i >= 0; --i) {
+        FileData data = m_files.at(i);
+        if (!newFiles.contains(data)) {
+            beginRemoveRows(QModelIndex(), i, i);
+            m_files.removeAt(i);
+            endRemoveRows();
+        }
+    }
+    // compare old and new files and do inserts if needed
+    for (int i = 0; i < newFiles.count(); ++i) {
+        FileData data = newFiles.at(i);
+        if (!m_files.contains(data)) {
+            beginInsertRows(QModelIndex(), i, i);
+            m_files.insert(i, data);
+            endInsertRows();
+        }
+    }
+
+    if (m_files.count() != oldFileCount)
+        emit fileCountChanged();
+
+    emit errorMessageChanged();
+}
+
+void FileModel::setShowAll(bool showAll)
+{
+    if (m_showAll != showAll) {
+        m_showAll = showAll;
+
+        QSettings settings;
+        settings.setValue("showAll", m_showAll);
+
+        emit showAllChanged();
+        refresh();
+    }
+}