From a85eb017a372b43372a17213848ce492187391d9 Mon Sep 17 00:00:00 2001 From: baldurk Date: Mon, 21 Nov 2016 16:46:19 +0100 Subject: [PATCH] Add custom browsing for executable files that checks permissions --- qrenderdoc/Code/QRDUtils.cpp | 66 ++++++++++++++++++++ qrenderdoc/Code/QRDUtils.h | 20 ++++++ qrenderdoc/Windows/Dialogs/CaptureDialog.cpp | 3 +- 3 files changed, 87 insertions(+), 2 deletions(-) diff --git a/qrenderdoc/Code/QRDUtils.cpp b/qrenderdoc/Code/QRDUtils.cpp index 186146a19..4617cb1ce 100644 --- a/qrenderdoc/Code/QRDUtils.cpp +++ b/qrenderdoc/Code/QRDUtils.cpp @@ -23,6 +23,7 @@ ******************************************************************************/ #include "QRDUtils.h" +#include #include #include #include @@ -339,6 +340,7 @@ QString RDDialog::getOpenFileName(QWidget *parent, const QString &caption, const QFileDialog::Options options) { QFileDialog fd(parent, caption, dir, filter); + fd.setFileMode(QFileDialog::ExistingFile); fd.setAcceptMode(QFileDialog::AcceptOpen); fd.setOptions(options); show(&fd); @@ -356,6 +358,35 @@ QString RDDialog::getOpenFileName(QWidget *parent, const QString &caption, const return QString(); } +QString RDDialog::getExecutableFileName(QWidget *parent, const QString &caption, const QString &dir, + QFileDialog::Options options) +{ + QString filter; + +#if defined(Q_OS_WIN32) + // can't filter by executable bit on windows, but we have extensions + filter = "Executables (*.exe);;All Files (*.*)"; +#endif + + QFileDialog fd(parent, caption, dir, filter); + fd.setOptions(options); + fd.setAcceptMode(QFileDialog::AcceptOpen); + fd.setFileMode(QFileDialog::ExistingFile); + QFileFilterModel *proxy = new QFileFilterModel(parent); + proxy->setRequirePermissions(QDir::Executable); + fd.setProxyModel(proxy); + show(&fd); + + if(fd.result() == QFileDialog::Accepted) + { + QStringList files = fd.selectedFiles(); + if(!files.isEmpty()) + return files[0]; + } + + return QString(); +} + QString RDDialog::getSaveFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options) @@ -377,3 +408,38 @@ QString RDDialog::getSaveFileName(QWidget *parent, const QString &caption, const return QString(); } + +bool QFileFilterModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const +{ + QModelIndex idx = sourceModel()->index(source_row, 0, source_parent); + + QFileSystemModel *fs = qobject_cast(sourceModel()); + + if(!fs) + { + qCritical() << "Expected a QFileSystemModel as the source model!"; + return true; + } + + if(fs->isDir(idx)) + return true; + + QFile::Permissions permissions = + (QFile::Permissions)sourceModel()->data(idx, QFileSystemModel::FilePermissions).toInt(); + + if((m_requireMask & QDir::Readable) && !(permissions & QFile::ReadUser)) + return false; + if((m_requireMask & QDir::Writable) && !(permissions & QFile::WriteUser)) + return false; + if((m_requireMask & QDir::Executable) && !(permissions & QFile::ExeUser)) + return false; + + if((m_excludeMask & QDir::Readable) && (permissions & QFile::ReadUser)) + return false; + if((m_excludeMask & QDir::Writable) && (permissions & QFile::WriteUser)) + return false; + if((m_excludeMask & QDir::Executable) && (permissions & QFile::ExeUser)) + return false; + + return true; +} diff --git a/qrenderdoc/Code/QRDUtils.h b/qrenderdoc/Code/QRDUtils.h index 9ddb98d77..0d7512f27 100644 --- a/qrenderdoc/Code/QRDUtils.h +++ b/qrenderdoc/Code/QRDUtils.h @@ -28,6 +28,7 @@ #include #include #include +#include #include "renderdoc_replay.h" // total hack, expose the same basic interface as on renderdoc side. @@ -248,6 +249,21 @@ public: } }; +class QFileFilterModel : public QSortFilterProxyModel +{ + Q_OBJECT + +public: + explicit QFileFilterModel(QObject *parent = Q_NULLPTR) : QSortFilterProxyModel(parent) {} + void setRequirePermissions(QDir::Filters mask) { m_requireMask = mask; } + void setExcludePermissions(QDir::Filters mask) { m_excludeMask = mask; } +protected: + virtual bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override; + +private: + QDir::Filters m_requireMask, m_excludeMask; +}; + class QMenu; // helper for doing a manual blocking invoke of a dialog @@ -304,6 +320,10 @@ struct RDDialog QString *selectedFilter = NULL, QFileDialog::Options options = QFileDialog::Options()); + static QString getExecutableFileName(QWidget *parent = NULL, const QString &caption = QString(), + const QString &dir = QString(), + QFileDialog::Options options = QFileDialog::Options()); + static QString getSaveFileName(QWidget *parent = NULL, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = NULL, diff --git a/qrenderdoc/Windows/Dialogs/CaptureDialog.cpp b/qrenderdoc/Windows/Dialogs/CaptureDialog.cpp index f1e6ff995..8e40d1e1e 100644 --- a/qrenderdoc/Windows/Dialogs/CaptureDialog.cpp +++ b/qrenderdoc/Windows/Dialogs/CaptureDialog.cpp @@ -283,8 +283,7 @@ void CaptureDialog::on_exePathBrowse_clicked() // if(m_Core.Renderer.Remote == null) { - QString filename = RDDialog::getOpenFileName(this, tr("Choose executable"), initDir, - "Executable files (*.exe);;All files (*.*)"); + QString filename = RDDialog::getExecutableFileName(this, tr("Choose executable"), initDir); if(filename != "") setExecutableFilename(filename);