diff --git a/src/plugins/coreplugin/coreplugin.pro b/src/plugins/coreplugin/coreplugin.pro index bd5a4dba70d..93c52d3ddac 100644 --- a/src/plugins/coreplugin/coreplugin.pro +++ b/src/plugins/coreplugin/coreplugin.pro @@ -88,6 +88,7 @@ SOURCES += corejsextensions.cpp \ sidebarwidget.cpp \ externaltool.cpp \ dialogs/externaltoolconfig.cpp \ + dialogs/filepropertiesdialog.cpp \ toolsettings.cpp \ variablechooser.cpp \ mimetypemagicdialog.cpp \ @@ -199,6 +200,7 @@ HEADERS += corejsextensions.h \ sidebarwidget.h \ externaltool.h \ dialogs/externaltoolconfig.h \ + dialogs/filepropertiesdialog.h \ toolsettings.h \ variablechooser.h \ mimetypemagicdialog.h \ @@ -230,6 +232,7 @@ FORMS += dialogs/newdialog.ui \ dialogs/openwithdialog.ui \ generalsettings.ui \ dialogs/externaltoolconfig.ui \ + dialogs/filepropertiesdialog.ui \ mimetypesettingspage.ui \ mimetypemagicdialog.ui \ dialogs/addtovcsdialog.ui \ diff --git a/src/plugins/coreplugin/coreplugin.qbs b/src/plugins/coreplugin/coreplugin.qbs index 7c32b523b49..bab2b062593 100644 --- a/src/plugins/coreplugin/coreplugin.qbs +++ b/src/plugins/coreplugin/coreplugin.qbs @@ -207,6 +207,7 @@ Project { files: [ "addtovcsdialog.cpp", "addtovcsdialog.h", "addtovcsdialog.ui", "externaltoolconfig.cpp", "externaltoolconfig.h", "externaltoolconfig.ui", + "filepropertiesdialog.cpp", "filepropertiesdialog.h", "filepropertiesdialog.ui", "ioptionspage.cpp", "ioptionspage.h", "newdialog.cpp", "newdialog.h", "newdialog.ui", "openwithdialog.cpp", "openwithdialog.h", "openwithdialog.ui", diff --git a/src/plugins/coreplugin/dialogs/filepropertiesdialog.cpp b/src/plugins/coreplugin/dialogs/filepropertiesdialog.cpp new file mode 100644 index 00000000000..409206d455a --- /dev/null +++ b/src/plugins/coreplugin/dialogs/filepropertiesdialog.cpp @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2018 Andre Hartmann +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "filepropertiesdialog.h" +#include "ui_filepropertiesdialog.h" + +#include + +#include +#include +#include +#include + +FilePropertiesDialog::FilePropertiesDialog(const Utils::FileName &fileName, QWidget *parent) : + QDialog(parent), + m_ui(new Ui::FilePropertiesDialog), + m_fileName(fileName.toString()) +{ + m_ui->setupUi(this); + + connect(m_ui->readable, &QCheckBox::clicked, [this](bool checked) { + setPermission(QFile::ReadUser | QFile::ReadOwner, checked); + }); + connect(m_ui->writable, &QCheckBox::clicked, [this](bool checked) { + setPermission(QFile::WriteUser | QFile::WriteOwner, checked); + }); + connect(m_ui->executable, &QCheckBox::clicked, [this](bool checked) { + setPermission(QFile::ExeUser | QFile::ExeOwner, checked); + }); + + refresh(); +} + +FilePropertiesDialog::~FilePropertiesDialog() +{ + delete m_ui; +} + +void FilePropertiesDialog::refresh() +{ + Utils::withNTFSPermissions([this] { + const QFileInfo fileInfo(m_fileName); + QLocale locale; + + m_ui->name->setText(fileInfo.fileName()); + m_ui->path->setText(fileInfo.canonicalPath()); + m_ui->owner->setText(fileInfo.owner()); + m_ui->group->setText(fileInfo.group()); +#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) + m_ui->size->setText(locale.formattedDataSize(fileInfo.size())); +#else + m_ui->size->setText(tr("%1 Bytes").arg(locale.toString(fileInfo.size()))); +#endif + m_ui->readable->setChecked(fileInfo.isReadable()); + m_ui->writable->setChecked(fileInfo.isWritable()); + m_ui->executable->setChecked(fileInfo.isExecutable()); + m_ui->symLink->setChecked(fileInfo.isSymLink()); + m_ui->lastRead->setText(fileInfo.lastRead().toString(locale.dateTimeFormat())); + m_ui->lastModified->setText(fileInfo.lastModified().toString(locale.dateTimeFormat())); + }); +} + +void FilePropertiesDialog::setPermission(QFile::Permissions newPermissions, bool set) +{ + Utils::withNTFSPermissions([this, newPermissions, set] { + QFile::Permissions permissions = QFile::permissions(m_fileName); + if (set) + permissions |= newPermissions; + else + permissions &= ~newPermissions; + + if (!QFile::setPermissions(m_fileName, permissions)) + qWarning() << "Cannot change permissions for file" << m_fileName; + }); + + refresh(); +} diff --git a/src/plugins/coreplugin/dialogs/filepropertiesdialog.h b/src/plugins/coreplugin/dialogs/filepropertiesdialog.h new file mode 100644 index 00000000000..3459b61e433 --- /dev/null +++ b/src/plugins/coreplugin/dialogs/filepropertiesdialog.h @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2018 Andre Hartmann +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include + +#include +#include + +namespace Ui { +class FilePropertiesDialog; +} + +class FilePropertiesDialog : public QDialog +{ + Q_OBJECT + +public: + explicit FilePropertiesDialog(const Utils::FileName &fileName, QWidget *parent = nullptr); + ~FilePropertiesDialog(); + +private: + void refresh(); + void setPermission(QFile::Permissions newPermissions, bool set); + +private: + Ui::FilePropertiesDialog *m_ui = nullptr; + const QString m_fileName; +}; diff --git a/src/plugins/coreplugin/dialogs/filepropertiesdialog.ui b/src/plugins/coreplugin/dialogs/filepropertiesdialog.ui new file mode 100644 index 00000000000..7a1b1e668bb --- /dev/null +++ b/src/plugins/coreplugin/dialogs/filepropertiesdialog.ui @@ -0,0 +1,267 @@ + + + FilePropertiesDialog + + + + 0 + 0 + 400 + 395 + + + + File Properties + + + + + + + + Owner: + + + + + + + + + + Qt::TextSelectableByMouse + + + + + + + Group: + + + + + + + + + + Qt::TextSelectableByMouse + + + + + + + Size: + + + + + + + + + + Qt::TextSelectableByMouse + + + + + + + true + + + + + + true + + + + + + + true + + + + + + true + + + + + + + true + + + + + + true + + + + + + + false + + + + + + true + + + + + + + + + + Qt::TextSelectableByMouse + + + + + + + + + + Qt::TextSelectableByMouse + + + + + + + + + + Qt::TextSelectableByMouse + + + + + + + + + + Qt::TextSelectableByMouse + + + + + + + Name: + + + + + + + Path: + + + + + + + Last read: + + + + + + + Last modified: + + + + + + + Readable: + + + + + + + Writable: + + + + + + + Executable: + + + + + + + Symbolic link: + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Close + + + + + + + + + buttonBox + accepted() + FilePropertiesDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + FilePropertiesDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/plugins/coreplugin/documentmanager.cpp b/src/plugins/coreplugin/documentmanager.cpp index 0edf3a39669..28542f7e5ec 100644 --- a/src/plugins/coreplugin/documentmanager.cpp +++ b/src/plugins/coreplugin/documentmanager.cpp @@ -31,6 +31,7 @@ #include "coreconstants.h" #include +#include #include #include #include @@ -948,6 +949,12 @@ bool DocumentManager::saveModifiedDocument(IDocument *document, const QString &m alwaysSaveMessage, alwaysSave, failedToClose); } +void DocumentManager::showFilePropertiesDialog(const FileName &filePath) +{ + FilePropertiesDialog properties(filePath); + properties.exec(); +} + /*! Asks the user for a set of file names to be opened. The \a filters and \a selectedFilter arguments are interpreted like in diff --git a/src/plugins/coreplugin/documentmanager.h b/src/plugins/coreplugin/documentmanager.h index 5e3eda755fb..d42077f32a8 100644 --- a/src/plugins/coreplugin/documentmanager.h +++ b/src/plugins/coreplugin/documentmanager.h @@ -123,6 +123,7 @@ public: const QString &alwaysSaveMessage = QString(), bool *alwaysSave = nullptr, QList *failedToClose = nullptr); + static void showFilePropertiesDialog(const Utils::FileName &filePath); static QString fileDialogLastVisitedDirectory(); static void setFileDialogLastVisitedDirectory(const QString &); diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp index 5378f9358ab..a44f9fa4b51 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.cpp +++ b/src/plugins/coreplugin/editormanager/editormanager.cpp @@ -211,7 +211,8 @@ EditorManagerPrivate::EditorManagerPrivate(QObject *parent) : m_closeAllEditorsExceptVisibleContextAction(new QAction(EditorManager::tr("Close All Except Visible"), this)), m_openGraphicalShellAction(new QAction(FileUtils::msgGraphicalShellAction(), this)), m_openTerminalAction(new QAction(FileUtils::msgTerminalAction(), this)), - m_findInDirectoryAction(new QAction(FileUtils::msgFindInDirectory(), this)) + m_findInDirectoryAction(new QAction(FileUtils::msgFindInDirectory(), this)), + m_filePropertiesAction(new QAction(tr("Properties..."), this)) { d = this; } @@ -344,6 +345,11 @@ void EditorManagerPrivate::init() connect(m_openTerminalAction, &QAction::triggered, this, &EditorManagerPrivate::openTerminal); connect(m_findInDirectoryAction, &QAction::triggered, this, &EditorManagerPrivate::findInDirectory); + connect(m_filePropertiesAction, &QAction::triggered, []() { + if (!d->m_contextMenuEntry || d->m_contextMenuEntry->fileName().isEmpty()) + return; + DocumentManager::showFilePropertiesDialog(d->m_contextMenuEntry->fileName()); + }); // Goto Previous In History Action cmd = ActionManager::registerAction(m_gotoPreviousDocHistoryAction, Constants::GOTOPREVINHISTORY, editDesignContext); @@ -2425,9 +2431,11 @@ void EditorManager::addNativeDirAndOpenWithActions(QMenu *contextMenu, DocumentM d->m_openGraphicalShellAction->setEnabled(enabled); d->m_openTerminalAction->setEnabled(enabled); d->m_findInDirectoryAction->setEnabled(enabled); + d->m_filePropertiesAction->setEnabled(enabled); contextMenu->addAction(d->m_openGraphicalShellAction); contextMenu->addAction(d->m_openTerminalAction); contextMenu->addAction(d->m_findInDirectoryAction); + contextMenu->addAction(d->m_filePropertiesAction); QMenu *openWith = contextMenu->addMenu(tr("Open With")); openWith->setEnabled(enabled); if (enabled) diff --git a/src/plugins/coreplugin/editormanager/editormanager.h b/src/plugins/coreplugin/editormanager/editormanager.h index 7b467ac1ac0..50528b29a3c 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.h +++ b/src/plugins/coreplugin/editormanager/editormanager.h @@ -181,6 +181,7 @@ signals: void editorAboutToClose(Core::IEditor *editor); void editorsClosed(QList editors); void findOnFileSystemRequest(const QString &path); + void openFileProperties(const Utils::FileName &path); void aboutToSave(IDocument *document); void autoSaved(); void currentEditorAboutToChange(Core::IEditor *editor); diff --git a/src/plugins/coreplugin/editormanager/editormanager_p.h b/src/plugins/coreplugin/editormanager/editormanager_p.h index 589027c3c72..79f35ea3553 100644 --- a/src/plugins/coreplugin/editormanager/editormanager_p.h +++ b/src/plugins/coreplugin/editormanager/editormanager_p.h @@ -245,6 +245,7 @@ private: QAction *m_openGraphicalShellAction; QAction *m_openTerminalAction; QAction *m_findInDirectoryAction; + QAction *m_filePropertiesAction = nullptr; DocumentModel::Entry *m_contextMenuEntry = nullptr; IEditor *m_contextMenuEditor = nullptr; diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 43843ebdf5f..8dea33de332 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -382,6 +382,7 @@ public: QAction *m_removeProjectAction; QAction *m_deleteFileAction; QAction *m_renameFileAction; + QAction *m_filePropertiesAction = nullptr; QAction *m_diffFileAction; QAction *m_openFileAction; QAction *m_projectTreeCollapseAllAction; @@ -1073,6 +1074,12 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er cmd->setDescription(dd->m_unloadActionContextMenu->text()); mprojectContextMenu->addAction(cmd, Constants::G_PROJECT_LAST); + // file properties action + dd->m_filePropertiesAction = new QAction(tr("Properties..."), this); + cmd = ActionManager::registerAction(dd->m_filePropertiesAction, Constants::FILEPROPERTIES, + projecTreeContext); + mfileContextMenu->addAction(cmd, Constants::G_FILE_OTHER); + // remove file action dd->m_removeFileAction = new QAction(tr("Remove File..."), this); cmd = ActionManager::registerAction(dd->m_removeFileAction, Constants::REMOVEFILE, @@ -1343,6 +1350,11 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er dd, &ProjectExplorerPluginPrivate::showInGraphicalShell); connect(dd->m_openTerminalHere, &QAction::triggered, dd, &ProjectExplorerPluginPrivate::openTerminalHere); + connect(dd->m_filePropertiesAction, &QAction::triggered, this, []() { + const Node *currentNode = ProjectTree::findCurrentNode(); + QTC_ASSERT(currentNode && currentNode->nodeType() == NodeType::File, return); + DocumentManager::showFilePropertiesDialog(currentNode->filePath()); + }); connect(dd->m_removeFileAction, &QAction::triggered, dd, &ProjectExplorerPluginPrivate::removeFile); connect(dd->m_duplicateFileAction, &QAction::triggered, diff --git a/src/plugins/projectexplorer/projectexplorerconstants.h b/src/plugins/projectexplorer/projectexplorerconstants.h index af3f76737f9..6e557739c1f 100644 --- a/src/plugins/projectexplorer/projectexplorerconstants.h +++ b/src/plugins/projectexplorer/projectexplorerconstants.h @@ -37,6 +37,7 @@ const char MODE_SESSION[] = "Project"; const char BUILD[] = "ProjectExplorer.Build"; const char STOP[] = "ProjectExplorer.Stop"; const char ADDNEWFILE[] = "ProjectExplorer.AddNewFile"; +const char FILEPROPERTIES[] = "ProjectExplorer.FileProperties"; const char RENAMEFILE[] = "ProjectExplorer.RenameFile"; const char REMOVEFILE[] = "ProjectExplorer.RemoveFile";