]> cloud.milkyroute.net Git - dolphin.git/blobdiff - src/dolphinviewcontainer.cpp
KFileItemListWidget: wrong selection when renamed file ends with a dot
[dolphin.git] / src / dolphinviewcontainer.cpp
index e55519d04300b270967fcf744b026907d5f76e21..dcf159cda1fc4e9d01406bf9a7ead203d0c1ce2e 100644 (file)
@@ -17,6 +17,7 @@
 #include "dolphinplacesmodelsingleton.h"
 #include "filterbar/filterbar.h"
 #include "global.h"
+#include "kitemviews/kitemlistcontainer.h"
 #include "search/dolphinsearchbox.h"
 #include "selectionmode/topbar.h"
 #include "statusbar/dolphinstatusbar.h"
 #include <KShell>
 #include <kio_version.h>
 
+#ifndef QT_NO_ACCESSIBILITY
+#include <QAccessible>
+#endif
 #include <QApplication>
 #include <QDesktopServices>
 #include <QDropEvent>
 #include <QGridLayout>
 #include <QGuiApplication>
 #include <QRegularExpression>
+#include <QScrollBar>
+#include <QStyle>
 #include <QTimer>
 #include <QUrl>
 #include <QUrlQuery>
@@ -170,6 +176,9 @@ DolphinViewContainer::DolphinViewContainer(const QUrl &url, QWidget *parent)
     connect(m_statusBar, &DolphinStatusBar::showMessage, this, [this](const QString &message, KMessageWidget::MessageType messageType) {
         showMessage(message, messageType);
     });
+    connect(m_statusBar, &DolphinStatusBar::widthUpdated, this, &DolphinViewContainer::updateStatusBarGeometry);
+    connect(m_statusBar, &DolphinStatusBar::urlChanged, this, &DolphinViewContainer::updateStatusBar);
+    connect(this, &DolphinViewContainer::showFilterBarChanged, this, &DolphinViewContainer::updateStatusBar);
 
     m_statusBarTimer = new QTimer(this);
     m_statusBarTimer->setSingleShot(true);
@@ -183,7 +192,24 @@ DolphinViewContainer::DolphinViewContainer(const QUrl &url, QWidget *parent)
     m_topLayout->addWidget(m_messageWidget, positionFor.messageWidget, 0);
     m_topLayout->addWidget(m_view, positionFor.view, 0);
     m_topLayout->addWidget(m_filterBar, positionFor.filterBar, 0);
-    m_topLayout->addWidget(m_statusBar, positionFor.statusBar, 0);
+    if (GeneralSettings::showStatusBar() == GeneralSettings::EnumShowStatusBar::FullWidth) {
+        m_topLayout->addWidget(m_statusBar, positionFor.statusBar, 0);
+    }
+    connect(m_statusBar, &DolphinStatusBar::modeUpdated, this, [this]() {
+        const bool statusBarInLayout = m_topLayout->itemAtPosition(positionFor.statusBar, 0);
+        if (GeneralSettings::showStatusBar() == GeneralSettings::EnumShowStatusBar::FullWidth) {
+            if (!statusBarInLayout) {
+                m_topLayout->addWidget(m_statusBar, positionFor.statusBar, 0);
+                m_statusBar->setUrl(m_view->url());
+            }
+        } else {
+            if (statusBarInLayout) {
+                m_topLayout->removeWidget(m_statusBar);
+            }
+        }
+        updateStatusBarGeometry();
+    });
+    m_statusBar->setHidden(false);
 
     setSearchModeEnabled(isSearchUrl(url));
 
@@ -197,6 +223,8 @@ DolphinViewContainer::DolphinViewContainer(const QUrl &url, QWidget *parent)
     connect(placesModel, &KFilePlacesModel::rowsRemoved, this, &DolphinViewContainer::slotPlacesModelChanged);
 
     connect(this, &DolphinViewContainer::searchModeEnabledChanged, this, &DolphinViewContainer::captionChanged);
+
+    QApplication::instance()->installEventFilter(this);
 }
 
 DolphinViewContainer::~DolphinViewContainer()
@@ -300,12 +328,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());
 
@@ -322,6 +353,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;
@@ -436,6 +468,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()
@@ -482,7 +522,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;
@@ -597,6 +639,7 @@ void DolphinViewContainer::setFilterBarVisible(bool visible)
         m_filterBar->setVisible(true, WithAnimation);
         m_filterBar->setFocus();
         m_filterBar->selectAll();
+        Q_EMIT showFilterBarChanged(true);
     } else {
         closeFilterBar();
     }
@@ -621,6 +664,7 @@ void DolphinViewContainer::updateStatusBar()
 {
     m_statusBarTimestamp.start();
     m_view->requestStatusBarText();
+    updateStatusBarGeometry();
 }
 
 void DolphinViewContainer::slotDirectoryLoadingStarted()
@@ -879,6 +923,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);
@@ -895,7 +942,12 @@ void DolphinViewContainer::startSearching()
     const QUrl url = m_searchBox->urlForSearching();
     if (url.isValid() && !url.isEmpty()) {
         m_view->setViewPropertiesContext(QStringLiteral("search"));
-        m_urlNavigatorConnected->setLocationUrl(url);
+        // If we open a new tab that has a search assigned to it, we can't
+        // update the urlNavigator, since there is none connected to that tab.
+        // See BUG:500101
+        if (m_urlNavigatorConnected) {
+            m_urlNavigatorConnected->setLocationUrl(url);
+        }
     }
 }
 
@@ -975,10 +1027,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)
@@ -1020,4 +1075,53 @@ QString DolphinViewContainer::getNearestExistingAncestorOfPath(const QString &pa
     return dir.exists() ? dir.path() : QString{};
 }
 
+void DolphinViewContainer::updateStatusBarGeometry()
+{
+    if (!m_statusBar) {
+        return;
+    }
+    if (GeneralSettings::showStatusBar() == GeneralSettings::EnumShowStatusBar::Small) {
+        QRect statusBarRect(preferredSmallStatusBarGeometry());
+        if (view()->layoutDirection() == Qt::RightToLeft) {
+            const int splitterWidth = m_statusBar->clippingAmount();
+            statusBarRect.setLeft(rect().width() - m_statusBar->width() + splitterWidth); // Add clipping amount.
+        }
+        // Move statusbar to bottomLeft, or bottomRight with right-to-left-layout.
+        m_statusBar->setGeometry(statusBarRect);
+        // Add 1 due to how qrect coordinates work.
+        m_view->setStatusBarOffset(m_statusBar->geometry().height() - m_statusBar->clippingAmount() + 1);
+    } else {
+        m_view->setStatusBarOffset(0);
+    }
+}
+
+bool DolphinViewContainer::eventFilter(QObject *object, QEvent *event)
+{
+    if (GeneralSettings::showStatusBar() == GeneralSettings::EnumShowStatusBar::Small && object == m_view) {
+        switch (event->type()) {
+        case QEvent::Resize: {
+            m_statusBar->updateWidthToContent();
+            break;
+        }
+        case QEvent::LayoutRequest: {
+            m_statusBar->updateWidthToContent();
+            break;
+        }
+        default:
+            break;
+        }
+    }
+    return false;
+}
+
+QRect DolphinViewContainer::preferredSmallStatusBarGeometry()
+{
+    // Adjust to clipping, we need to add 1 due to how QRects coordinates work.
+    int clipAdjustment = m_statusBar->clippingAmount() + 1;
+    // Add offset depending if horizontal scrollbar or filterbar is visible.
+    const int yPos = m_view->geometry().bottom() - m_view->horizontalScrollBarHeight() - m_statusBar->minimumHeight() + clipAdjustment;
+    QRect statusBarRect = rect().adjusted(-clipAdjustment, yPos, 0, 0);
+    return statusBarRect;
+}
+
 #include "moc_dolphinviewcontainer.cpp"