┌   ┐
54
└   ┘

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Ernst <[email protected]>2024-07-22 10:51:33 +0000
committerFelix Ernst <[email protected]>2024-07-22 10:51:33 +0000
commit6e6fcf8da80b5b6821837054ae51eaa19edc24b8 (patch)
tree6a627a61e8bcba056784b796cb5cecb419c08af4
parentf5687396c4f84d4045d652d7f8a5d783be54f7ea (diff)
Notify users if authorization is required to proceed
Previous to this commit entering a folder without read access would show the non-descriptive error message "Could not enter folder". If the user actually is not allowed to view the contents of the folder, this is indeed true and this commit will preserve this message as is. However, if an admin protocol is installed, users can actually view the contents of most folders after authorizing themselves as administrators. So this commit changes the error message in those specific circumstances to instead read "Authorization required to enter this folder." and provide a button to authorize themselves. This button is the "Act as Administrator" action. If no admin protocol is installed, this commit has no effect. The idea for this change came from Harald Sitter. I receive funding for changes like this by the Next Generation Internet Initiative, which (as I understand it) will no longer provide funds for future projects like this if the current EU draft budget goes through as it is.
-rw-r--r--src/admin/bar.cpp6
-rw-r--r--src/admin/workerintegration.cpp10
-rw-r--r--src/admin/workerintegration.h20
-rw-r--r--src/dolphinviewcontainer.cpp26
-rw-r--r--src/dolphinviewcontainer.h7
-rw-r--r--src/kitemviews/kfileitemmodel.cpp5
-rw-r--r--src/kitemviews/kfileitemmodel.h2
-rw-r--r--src/views/dolphinview.cpp14
-rw-r--r--src/views/dolphinview.h2
9 files changed, 68 insertions, 24 deletions
diff --git a/src/admin/bar.cpp b/src/admin/bar.cpp
index 52bbc3772..e01ef81a5 100644
--- a/src/admin/bar.cpp
+++ b/src/admin/bar.cpp
@@ -58,7 +58,7 @@ Bar::Bar(DolphinViewContainer *parentViewContainer)
m_closeButton->setFlat(true);
connect(m_closeButton, &QAbstractButton::clicked, m_parentViewContainer, [this]() {
m_parentViewContainer->setActive(true); // Make sure the view connected to this bar is active before exiting admin mode.
- QAction *actAsAdminAction = WorkerIntegration::actAsAdminAction();
+ QAction *actAsAdminAction = WorkerIntegration::FriendAccess::actAsAdminAction();
if (actAsAdminAction->isChecked()) {
actAsAdminAction->trigger();
}
@@ -134,8 +134,8 @@ void Bar::hideTheNextTimeAuthorizationExpires()
m_parentViewContainer->setUrl(viewContainerUrl);
// Explain to users that their admin authorization expired.
- if (!m_reenableActAsAdminAction) {
- auto actAsAdminAction = WorkerIntegration::actAsAdminAction();
+ if (!m_reenableActAsAdminAction) { // This code is similar to parts of DolphinViewContainer::slotViewErrorMessage().
+ auto actAsAdminAction = WorkerIntegration::FriendAccess::actAsAdminAction();
m_reenableActAsAdminAction =
new QAction{actAsAdminAction->icon(), i18nc("@action:button shown after acting as admin ended", "Act as Administrator Again"), this};
m_reenableActAsAdminAction->setToolTip(actAsAdminAction->toolTip());
diff --git a/src/admin/workerintegration.cpp b/src/admin/workerintegration.cpp
index 0b95ec782..80d8fda1b 100644
--- a/src/admin/workerintegration.cpp
+++ b/src/admin/workerintegration.cpp
@@ -134,6 +134,11 @@ void WorkerIntegration::createActAsAdminAction(KActionCollection *actionCollecti
}
}
+QAction *WorkerIntegration::FriendAccess::actAsAdminAction()
+{
+ return instance->m_actAsAdminAction;
+}
+
void WorkerIntegration::toggleActAsAdmin()
{
auto dolphinMainWindow = static_cast<DolphinMainWindow *>(parent());
@@ -187,8 +192,3 @@ void WorkerIntegration::updateActAsAdminAction()
}
}
}
-
-QAction *WorkerIntegration::actAsAdminAction()
-{
- return instance->m_actAsAdminAction;
-}
diff --git a/src/admin/workerintegration.h b/src/admin/workerintegration.h
index 19cc5c172..1e32c33d3 100644
--- a/src/admin/workerintegration.h
+++ b/src/admin/workerintegration.h
@@ -11,6 +11,7 @@
#include <QObject>
class DolphinMainWindow;
+class DolphinViewContainer;
class KActionCollection;
class QAction;
class QUrl;
@@ -57,6 +58,20 @@ public:
*/
static void createActAsAdminAction(KActionCollection *actionCollection, DolphinMainWindow *dolphinMainWindow);
+ /**
+ * An interface that only allows friend classes to show the WorkerIntegration::m_actAsAdminAction to users.
+ * Aside from these friend classes the action is only accessible through the actionCollection of DolphinMainWindow.
+ */
+ class FriendAccess
+ {
+ /** @returns WorkerIntegration::m_actAsAdminAction or crashes if WorkerIntegration::createActAsAdminAction() has not been called previously. */
+ static QAction *actAsAdminAction();
+
+ friend class Bar; /// Allows the bar to access the actAsAdminAction, so users can use the bar to change who they are acting as.
+ friend DolphinViewContainer; // Allows the view container to access the actAsAdminAction, so the action can be shown to users when they are trying to
+ // view a folder for which they are lacking read permissions.
+ };
+
private:
WorkerIntegration(DolphinMainWindow *parent, QAction *actAsAdminAction);
@@ -69,14 +84,9 @@ private:
/** Updates the toggled/checked state of the action depending on the state of the currently active view. */
static void updateActAsAdminAction();
- /** Used by the friend class Bar to show the m_actAsAdminAction to users. */
- static QAction *actAsAdminAction();
-
private:
/** @see createActAsAdminAction() */
QAction *const m_actAsAdminAction = nullptr;
-
- friend class Bar; // Allows the bar to access the actAsAdminAction, so users can use the bar to change who they are acting as.
};
}
diff --git a/src/dolphinviewcontainer.cpp b/src/dolphinviewcontainer.cpp
index 27f845fa7..3fedef6fc 100644
--- a/src/dolphinviewcontainer.cpp
+++ b/src/dolphinviewcontainer.cpp
@@ -7,6 +7,7 @@
#include "dolphinviewcontainer.h"
#include "admin/bar.h"
+#include "admin/workerintegration.h"
#include "dolphin_compactmodesettings.h"
#include "dolphin_contentdisplaysettings.h"
#include "dolphin_detailsmodesettings.h"
@@ -62,6 +63,7 @@ DolphinViewContainer::DolphinViewContainer(const QUrl &url, QWidget *parent)
, m_searchBox(nullptr)
, m_searchModeEnabled(false)
, m_adminBar{nullptr}
+ , m_authorizeToEnterFolderAction{nullptr}
, m_messageWidget(nullptr)
, m_selectionModeTopBar{nullptr}
, m_view(nullptr)
@@ -139,7 +141,7 @@ DolphinViewContainer::DolphinViewContainer(const QUrl &url, QWidget *parent)
connect(m_view, &DolphinView::directoryLoadingCanceled, this, &DolphinViewContainer::slotDirectoryLoadingCanceled);
connect(m_view, &DolphinView::itemCountChanged, this, &DolphinViewContainer::delayedStatusBarUpdate);
connect(m_view, &DolphinView::selectionChanged, this, &DolphinViewContainer::delayedStatusBarUpdate);
- connect(m_view, &DolphinView::errorMessage, this, &DolphinViewContainer::showErrorMessage);
+ connect(m_view, &DolphinView::errorMessage, this, &DolphinViewContainer::slotErrorMessageFromView);
connect(m_view, &DolphinView::urlIsFileError, this, &DolphinViewContainer::slotUrlIsFileError);
connect(m_view, &DolphinView::activated, this, &DolphinViewContainer::activate);
connect(m_view, &DolphinView::hiddenFilesShownChanged, this, &DolphinViewContainer::slotHiddenFilesShownChanged);
@@ -897,6 +899,28 @@ void DolphinViewContainer::slotStatusBarZoomLevelChanged(int zoomLevel)
m_view->setZoomLevel(zoomLevel);
}
+void DolphinViewContainer::slotErrorMessageFromView(const QString &message, const int kioErrorCode)
+{
+ if (kioErrorCode == KIO::ERR_CANNOT_ENTER_DIRECTORY && m_view->url().scheme() == QStringLiteral("file")
+ && KProtocolInfo::isKnownProtocol(QStringLiteral("admin")) && !rootItem().isReadable()) {
+ // Explain to users that they need authentication to see the folder contents.
+ if (!m_authorizeToEnterFolderAction) { // This code is similar to parts of Admin::Bar::hideTheNextTimeAuthorizationExpires().
+ // We should not simply use the actAsAdminAction() itself here because that one always refers to the active view instead of this->m_view.
+ auto actAsAdminAction = Admin::WorkerIntegration::FriendAccess::actAsAdminAction();
+ m_authorizeToEnterFolderAction = new QAction{actAsAdminAction->icon(), actAsAdminAction->text(), this};
+ m_authorizeToEnterFolderAction->setToolTip(actAsAdminAction->toolTip());
+ m_authorizeToEnterFolderAction->setWhatsThis(actAsAdminAction->whatsThis());
+ connect(m_authorizeToEnterFolderAction, &QAction::triggered, this, [this, actAsAdminAction]() {
+ setActive(true);
+ actAsAdminAction->trigger();
+ });
+ }
+ showMessage(i18nc("@info", "Authorization required to enter this folder."), KMessageWidget::Error, {m_authorizeToEnterFolderAction});
+ return;
+ }
+ Q_EMIT showErrorMessage(message);
+}
+
void DolphinViewContainer::showErrorMessage(const QString &message)
{
showMessage(message, KMessageWidget::Error);
diff --git a/src/dolphinviewcontainer.h b/src/dolphinviewcontainer.h
index c5da6b48b..be28ecdeb 100644
--- a/src/dolphinviewcontainer.h
+++ b/src/dolphinviewcontainer.h
@@ -388,6 +388,11 @@ private Q_SLOTS:
void slotStatusBarZoomLevelChanged(int zoomLevel);
/**
+ * Creates and shows an error message based on \p message and \p kioErrorCode.
+ */
+ void slotErrorMessageFromView(const QString &message, const int kioErrorCode);
+
+ /**
* Slot that calls showMessage(message, KMessageWidget::Error).
*/
void showErrorMessage(const QString &message);
@@ -449,6 +454,8 @@ private:
/// A bar shown at the top of the view to signify that the view is currently viewed and acted on with elevated privileges.
Admin::Bar *m_adminBar;
+ /// An action to switch to the admin protocol. This variable will always be nullptr unless kio-admin was installed. @see Admin::WorkerIntegration.
+ QAction *m_authorizeToEnterFolderAction;
KMessageWidget *m_messageWidget;
diff --git a/src/kitemviews/kfileitemmodel.cpp b/src/kitemviews/kfileitemmodel.cpp
index c694da9f2..d18754ec7 100644
--- a/src/kitemviews/kfileitemmodel.cpp
+++ b/src/kitemviews/kfileitemmodel.cpp
@@ -2856,13 +2856,14 @@ bool KFileItemModel::isConsistent() const
void KFileItemModel::slotListerError(KIO::Job *job)
{
- if (job->error() == KIO::ERR_IS_FILE) {
+ const int jobError = job->error();
+ if (jobError == KIO::ERR_IS_FILE) {
if (auto *listJob = qobject_cast<KIO::ListJob *>(job)) {
Q_EMIT urlIsFileError(listJob->url());
}
} else {
const QString errorString = job->errorString();
- Q_EMIT errorMessage(!errorString.isEmpty() ? errorString : i18nc("@info:status", "Unknown error."));
+ Q_EMIT errorMessage(!errorString.isEmpty() ? errorString : i18nc("@info:status", "Unknown error."), jobError);
}
}
diff --git a/src/kitemviews/kfileitemmodel.h b/src/kitemviews/kfileitemmodel.h
index ce58f89ac..5662d4fa8 100644
--- a/src/kitemviews/kfileitemmodel.h
+++ b/src/kitemviews/kfileitemmodel.h
@@ -258,7 +258,7 @@ Q_SIGNALS:
* Is emitted if an error message (e.g. "Unknown location")
* should be shown.
*/
- void errorMessage(const QString &message);
+ void errorMessage(const QString &message, const int kioErrorCode);
/**
* Is emitted if a redirection from the current URL \a oldUrl
diff --git a/src/views/dolphinview.cpp b/src/views/dolphinview.cpp
index d42d9cfcd..85e652ecf 100644
--- a/src/views/dolphinview.cpp
+++ b/src/views/dolphinview.cpp
@@ -231,7 +231,9 @@ DolphinView::DolphinView(const QUrl &url, QWidget *parent)
m_versionControlObserver->setView(this);
m_versionControlObserver->setModel(m_model);
connect(m_versionControlObserver, &VersionControlObserver::infoMessage, this, &DolphinView::infoMessage);
- connect(m_versionControlObserver, &VersionControlObserver::errorMessage, this, &DolphinView::errorMessage);
+ connect(m_versionControlObserver, &VersionControlObserver::errorMessage, this, [this](const QString &message) {
+ Q_EMIT errorMessage(message, KIO::ERR_UNKNOWN);
+ });
connect(m_versionControlObserver, &VersionControlObserver::operationCompletedMessage, this, &DolphinView::operationCompletedMessage);
m_twoClicksRenamingTimer = new QTimer(this);
@@ -1453,7 +1455,7 @@ void DolphinView::onDirectoryLoadingCompletedAfterJob()
void DolphinView::slotJobResult(KJob *job)
{
if (job->error() && job->error() != KIO::ERR_USER_CANCELED) {
- Q_EMIT errorMessage(job->errorString());
+ Q_EMIT errorMessage(job->errorString(), job->error());
}
if (!m_selectJobCreatedItems) {
m_selectedUrls.clear();
@@ -1826,7 +1828,7 @@ void DolphinView::slotTrashFileFinished(KJob *job)
selectNextItem(); // Fixes BUG: 419914 via selecting next item
Q_EMIT operationCompletedMessage(i18nc("@info:status", "Trash operation completed."));
} else if (job->error() != KIO::ERR_USER_CANCELED) {
- Q_EMIT errorMessage(job->errorString());
+ Q_EMIT errorMessage(job->errorString(), job->error());
}
}
@@ -1836,7 +1838,7 @@ void DolphinView::slotDeleteFileFinished(KJob *job)
selectNextItem(); // Fixes BUG: 419914 via selecting next item
Q_EMIT operationCompletedMessage(i18nc("@info:status", "Delete operation completed."));
} else if (job->error() != KIO::ERR_USER_CANCELED) {
- Q_EMIT errorMessage(job->errorString());
+ Q_EMIT errorMessage(job->errorString(), job->error());
}
}
@@ -2048,9 +2050,9 @@ void DolphinView::loadDirectory(const QUrl &url, bool reload)
if (!url.isValid()) {
const QString location(url.toDisplayString(QUrl::PreferLocalFile));
if (location.isEmpty()) {
- Q_EMIT errorMessage(i18nc("@info:status", "The location is empty."));
+ Q_EMIT errorMessage(i18nc("@info:status", "The location is empty."), KIO::ERR_UNKNOWN);
} else {
- Q_EMIT errorMessage(i18nc("@info:status", "The location '%1' is invalid.", location));
+ Q_EMIT errorMessage(i18nc("@info:status", "The location '%1' is invalid.", location), KIO::ERR_UNKNOWN);
}
return;
}
diff --git a/src/views/dolphinview.h b/src/views/dolphinview.h
index b55e2ee9b..c985f4eb9 100644
--- a/src/views/dolphinview.h
+++ b/src/views/dolphinview.h
@@ -567,7 +567,7 @@ Q_SIGNALS:
* Is emitted if an error message with the content \a msg
* should be shown.
*/
- void errorMessage(const QString &msg);
+ void errorMessage(const QString &message, const int kioErrorCode);
/**
* Is emitted if an "operation completed" message with the content \a msg