]> cloud.milkyroute.net Git - dolphin.git/blobdiff - src/dolphinviewcontainer.cpp
GIT_SILENT made messages (after extraction)
[dolphin.git] / src / dolphinviewcontainer.cpp
index fbad258ace5fd26067b0e22e71dd28b2d6e7b0b8..f2df638f6cbfb7a68ed09b151bceee41fb867dbc 100644 (file)
@@ -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"
@@ -21,9 +22,6 @@
 #include "statusbar/dolphinstatusbar.h"
 
 #include <KActionCollection>
-#if HAVE_PLASMA_ACTIVITIES
-#include <PlasmaActivities/ResourceInstance>
-#endif
 #include <KApplicationTrader>
 #include <KFileItemActions>
 #include <KFilePlacesModel>
@@ -35,6 +33,9 @@
 #include <KShell>
 #include <kio_version.h>
 
+#ifndef QT_NO_ACCESSIBILITY
+#include <QAccessible>
+#endif
 #include <QApplication>
 #include <QDesktopServices>
 #include <QDropEvent>
@@ -43,6 +44,7 @@
 #include <QRegularExpression>
 #include <QTimer>
 #include <QUrl>
+#include <QUrlQuery>
 
 // An overview of the widgets contained by this ViewContainer
 struct LayoutStructure {
@@ -65,6 +67,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)
@@ -142,13 +145,12 @@ 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);
     connect(m_view, &DolphinView::sortHiddenLastChanged, this, &DolphinViewContainer::slotSortHiddenLastChanged);
     connect(m_view, &DolphinView::currentDirectoryRemoved, this, &DolphinViewContainer::slotCurrentDirectoryRemoved);
-    connect(m_view, &DolphinView::urlChanged, this, &DolphinViewContainer::updateAdminBarVisibility);
 
     // Initialize status bar
     m_statusBar = new DolphinStatusBar(this);
@@ -168,6 +170,9 @@ DolphinViewContainer::DolphinViewContainer(const QUrl &url, QWidget *parent)
     });
     connect(m_statusBar, &DolphinStatusBar::stopPressed, this, &DolphinViewContainer::stopDirectoryLoading);
     connect(m_statusBar, &DolphinStatusBar::zoomLevelChanged, this, &DolphinViewContainer::slotStatusBarZoomLevelChanged);
+    connect(m_statusBar, &DolphinStatusBar::showMessage, this, [this](const QString &message, KMessageWidget::MessageType messageType) {
+        showMessage(message, messageType);
+    });
 
     m_statusBarTimer = new QTimer(this);
     m_statusBarTimer->setSingleShot(true);
@@ -184,7 +189,6 @@ DolphinViewContainer::DolphinViewContainer(const QUrl &url, QWidget *parent)
     m_topLayout->addWidget(m_statusBar, positionFor.statusBar, 0);
 
     setSearchModeEnabled(isSearchUrl(url));
-    updateAdminBarVisibility(url);
 
     // Update view as the ContentDisplaySettings change
     // this happens here and not in DolphinView as DolphinviewContainer and DolphinView are not in the same build target ATM
@@ -299,12 +303,15 @@ void DolphinViewContainer::connectUrlNavigator(DolphinUrlNavigator *urlNavigator
 
     // Url changes are still done via m_urlNavigator.
     connect(urlNavigator, &DolphinUrlNavigator::urlChanged, m_urlNavigator.get(), &DolphinUrlNavigator::setLocationUrl);
-    connect(urlNavigator, &DolphinUrlNavigator::urlsDropped, this, [=](const QUrl &destination, QDropEvent *event) {
+    connect(urlNavigator, &DolphinUrlNavigator::urlsDropped, this, [=, this](const QUrl &destination, QDropEvent *event) {
         m_view->dropUrls(destination, event, urlNavigator->dropWidget());
     });
     // Aside from these, only visual things need to be connected.
     connect(m_view, &DolphinView::urlChanged, urlNavigator, &DolphinUrlNavigator::setLocationUrl);
     connect(urlNavigator, &DolphinUrlNavigator::activated, this, &DolphinViewContainer::activate);
+    connect(urlNavigator, &DolphinUrlNavigator::requestToLoseFocus, m_view, [this]() {
+        m_view->setFocus();
+    });
 
     urlNavigator->setReadOnlyBadgeVisible(rootItem().isLocalFile() && !rootItem().isWritable());
 
@@ -321,6 +328,7 @@ void DolphinViewContainer::disconnectUrlNavigator()
     disconnect(m_urlNavigatorConnected, &DolphinUrlNavigator::urlsDropped, this, nullptr);
     disconnect(m_view, &DolphinView::urlChanged, m_urlNavigatorConnected, &DolphinUrlNavigator::setLocationUrl);
     disconnect(m_urlNavigatorConnected, &DolphinUrlNavigator::activated, this, &DolphinViewContainer::activate);
+    disconnect(m_urlNavigatorConnected, &DolphinUrlNavigator::requestToLoseFocus, m_view, nullptr);
 
     m_urlNavigatorVisualState = m_urlNavigatorConnected->visualState();
     m_urlNavigatorConnected = nullptr;
@@ -406,7 +414,7 @@ void DolphinViewContainer::slotSplitTabDisabled()
     }
 }
 
-void DolphinViewContainer::showMessage(const QString &message, KMessageWidget::MessageType messageType)
+void DolphinViewContainer::showMessage(const QString &message, KMessageWidget::MessageType messageType, std::initializer_list<QAction *> buttonActions)
 {
     if (message.isEmpty()) {
         return;
@@ -419,6 +427,14 @@ void DolphinViewContainer::showMessage(const QString &message, KMessageWidget::M
     m_messageWidget->setWordWrap(true);
     m_messageWidget->setMessageType(messageType);
 
+    const QList<QAction *> previousMessageWidgetActions = m_messageWidget->actions();
+    for (auto action : previousMessageWidgetActions) {
+        m_messageWidget->removeAction(action);
+    }
+    for (QAction *action : buttonActions) {
+        m_messageWidget->addAction(action);
+    }
+
     m_messageWidget->setWordWrap(false);
     const int unwrappedWidth = m_messageWidget->sizeHint().width();
     m_messageWidget->setWordWrap(unwrappedWidth > size().width());
@@ -427,6 +443,14 @@ void DolphinViewContainer::showMessage(const QString &message, KMessageWidget::M
         m_messageWidget->hide();
     }
     m_messageWidget->animatedShow();
+
+#ifndef QT_NO_ACCESSIBILITY
+    if (QAccessible::isActive() && isActive()) {
+        // To announce the new message keyboard focus must be moved to the message label. However, we do not have direct access to the label that is internal
+        // to the KMessageWidget. Instead we setFocus() on the KMessageWidget and trust that it has set correct focus handling.
+        m_messageWidget->setFocus();
+    }
+#endif
 }
 
 void DolphinViewContainer::readSettings()
@@ -473,7 +497,9 @@ void DolphinViewContainer::setSearchModeEnabled(bool enabled)
         if (url.isEmpty() || !url.isValid() || isSearchUrl(url)) {
             url = Dolphin::homeUrl();
         }
-        m_urlNavigatorConnected->setLocationUrl(url);
+        if (m_urlNavigatorConnected) {
+            m_urlNavigatorConnected->setLocationUrl(url);
+        }
     }
 
     m_searchModeEnabled = enabled;
@@ -525,6 +551,15 @@ QString DolphinViewContainer::captionWindowTitle() const
 
 QString DolphinViewContainer::caption() const
 {
+    // see KUrlNavigatorPrivate::firstButtonText().
+    if (url().path().isEmpty() || url().path() == QLatin1Char('/')) {
+        QUrlQuery query(url());
+        const QString title = query.queryItemValue(QStringLiteral("title"));
+        if (!title.isEmpty()) {
+            return title;
+        }
+    }
+
     if (isSearchModeEnabled()) {
         if (currentSearchText().isEmpty()) {
             return i18n("Search");
@@ -534,12 +569,11 @@ QString DolphinViewContainer::caption() const
     }
 
     KFilePlacesModel *placesModel = DolphinPlacesModelSingleton::instance().placesModel();
-    const QString pattern = url().adjusted(QUrl::StripTrailingSlash).toString(QUrl::FullyEncoded).append("/?");
-    const auto &matchedPlaces =
-        placesModel->match(placesModel->index(0, 0), KFilePlacesModel::UrlRole, QRegularExpression::anchoredPattern(pattern), 1, Qt::MatchRegularExpression);
 
-    if (!matchedPlaces.isEmpty()) {
-        return placesModel->text(matchedPlaces.first());
+    QModelIndex url_index = placesModel->closestItem(url());
+
+    if (url_index.isValid() && placesModel->url(url_index).matches(url(), QUrl::StripTrailingSlash)) {
+        return placesModel->text(url_index);
     }
 
     if (!url().isLocalFile()) {
@@ -570,10 +604,6 @@ void DolphinViewContainer::setUrl(const QUrl &newUrl)
     if (newUrl != m_urlNavigator->locationUrl()) {
         m_urlNavigator->setLocationUrl(newUrl);
     }
-
-#if HAVE_PLASMA_ACTIVITIES
-    KActivities::ResourceInstance::notifyAccessed(newUrl);
-#endif
 }
 
 void DolphinViewContainer::setFilterBarVisible(bool visible)
@@ -644,6 +674,17 @@ void DolphinViewContainer::slotDirectoryLoadingCompleted()
     if (m_urlNavigatorConnected) {
         m_urlNavigatorConnected->setReadOnlyBadgeVisible(rootItem().isLocalFile() && !rootItem().isWritable());
     }
+
+    // Update admin bar visibility
+    if (m_view->url().scheme() == QStringLiteral("admin")) {
+        if (!m_adminBar) {
+            m_adminBar = new Admin::Bar(this);
+            m_topLayout->addWidget(m_adminBar, positionFor.adminBar, 0);
+        }
+        m_adminBar->setVisible(true, WithAnimation);
+    } else if (m_adminBar) {
+        m_adminBar->setVisible(false, WithAnimation);
+    }
 }
 
 void DolphinViewContainer::slotDirectoryLoadingCanceled()
@@ -726,6 +767,18 @@ void DolphinViewContainer::slotfileMiddleClickActivated(const KFileItem &item)
         job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this));
         connect(job, &KIO::OpenUrlJob::finished, this, &DolphinViewContainer::slotOpenUrlFinished);
         job->start();
+    } else {
+        // If no 2nd service available, try to open archives in new tabs, regardless of the "Open archives as folder" setting.
+        const QUrl &url = DolphinView::openItemAsFolderUrl(item);
+        const auto modifiers = QGuiApplication::keyboardModifiers();
+        if (!url.isEmpty()) {
+            // keep in sync with KUrlNavigator::slotNavigatorButtonClicked
+            if (modifiers & Qt::ShiftModifier) {
+                Q_EMIT activeTabRequested(url);
+            } else {
+                Q_EMIT tabRequested(url);
+            }
+        }
     }
 }
 
@@ -746,20 +799,6 @@ void DolphinViewContainer::showItemInfo(const KFileItem &item)
     }
 }
 
-void DolphinViewContainer::updateAdminBarVisibility(const QUrl &url)
-{
-    if (url.scheme() == QStringLiteral("admin")) {
-        if (!m_adminBar) {
-            m_adminBar = new Admin::Bar(this);
-            m_topLayout->addWidget(m_adminBar, positionFor.adminBar, 0);
-            connect(m_adminBar, &Admin::Bar::activated, this, &DolphinViewContainer::activate);
-        }
-        m_adminBar->setVisible(true, WithAnimation);
-    } else if (m_adminBar) {
-        m_adminBar->setVisible(false, WithAnimation);
-    }
-}
-
 void DolphinViewContainer::closeFilterBar()
 {
     m_filterBar->closeFilterBar();
@@ -857,6 +896,9 @@ void DolphinViewContainer::redirect(const QUrl &oldUrl, const QUrl &newUrl)
     // URL history.
     m_urlNavigator->saveLocationState(QByteArray());
     m_urlNavigator->setLocationUrl(newUrl);
+    if (m_searchBox->isActive()) {
+        m_searchBox->setSearchPath(newUrl);
+    }
     setSearchModeEnabled(isSearchUrl(newUrl));
 
     m_urlNavigator->blockSignals(block);
@@ -898,6 +940,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);
@@ -931,10 +995,13 @@ void DolphinViewContainer::slotCurrentDirectoryRemoved()
         const QString dirPath = url().toLocalFile();
         const QString newPath = getNearestExistingAncestorOfPath(dirPath);
         const QUrl newUrl = QUrl::fromLocalFile(newPath);
-        setUrl(newUrl);
-    }
-
-    showMessage(xi18n("Current location changed, <filename>%1</filename> is no longer accessible.", location), KMessageWidget::Warning);
+        // #473377: Delay changing the url to avoid modifying KCoreDirLister before KCoreDirListerCache::deleteDir() returns.
+        QTimer::singleShot(0, this, [&, newUrl, location] {
+            setUrl(newUrl);
+            showMessage(xi18n("Current location changed, <filename>%1</filename> is no longer accessible.", location), KMessageWidget::Warning);
+        });
+    } else
+        showMessage(xi18n("Current location changed, <filename>%1</filename> is no longer accessible.", location), KMessageWidget::Warning);
 }
 
 void DolphinViewContainer::slotOpenUrlFinished(KJob *job)