From 2a4dd2aa43aeff54187955ed66e8462751bfed1c Mon Sep 17 00:00:00 2001 From: Marco Savelli Date: Mon, 18 Sep 2023 22:53:49 +0200 Subject: selection: select-on-rubberband-on-row as new default Sets a rectangular, non-full-width rubberband as the new default. User selection is made wherever the rubberband intersects with the row. --- src/kitemviews/kitemlistcontroller.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/kitemviews/kitemlistcontroller.cpp b/src/kitemviews/kitemlistcontroller.cpp index 0f3c5bc8c..d70028d23 100644 --- a/src/kitemviews/kitemlistcontroller.cpp +++ b/src/kitemviews/kitemlistcontroller.cpp @@ -1302,9 +1302,9 @@ void KItemListController::slotRubberBandChanged() const QRectF widgetRect = m_view->itemRect(index); if (widgetRect.intersects(rubberBandRect)) { - const QRectF iconRect = widget->iconRect().translated(widgetRect.topLeft()); - const QRectF textRect = widget->textRect().translated(widgetRect.topLeft()); - if (iconRect.intersects(rubberBandRect) || textRect.intersects(rubberBandRect)) { + // Select the full row intersecting with the rubberband rectangle + const QRectF selectionRect = widget->selectionRect().translated(widgetRect.topLeft()); + if (selectionRect.intersects(rubberBandRect)) { selectedItems.insert(index); } } -- cgit v1.3 From d9a18b04ea0b1b4e427f45083fdc0cdec87cbbfd Mon Sep 17 00:00:00 2001 From: Marco Savelli Date: Mon, 18 Sep 2023 23:20:39 +0200 Subject: selection: fix rubberband vertices --- src/kitemviews/kitemlistcontroller.cpp | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'src') diff --git a/src/kitemviews/kitemlistcontroller.cpp b/src/kitemviews/kitemlistcontroller.cpp index d70028d23..be7a63e09 100644 --- a/src/kitemviews/kitemlistcontroller.cpp +++ b/src/kitemviews/kitemlistcontroller.cpp @@ -654,11 +654,6 @@ bool KItemListController::mouseMoveEvent(QGraphicsSceneMouseEvent *event, const if (m_view->scrollOrientation() == Qt::Vertical) { endPos.ry() += m_view->scrollOffset(); - if (m_view->itemSize().width() < 0) { - // Use a special rubberband for views that have only one column and - // expand the rubberband to use the whole width of the view. - endPos.setX(m_view->size().width()); - } } else { endPos.rx() += m_view->scrollOffset(); } @@ -1809,11 +1804,6 @@ void KItemListController::startRubberBand() QPoint startPos = m_view->transform().map(m_view->scene()->views().first()->mapFromGlobal(m_pressedMouseGlobalPos.toPoint())); if (m_view->scrollOrientation() == Qt::Vertical) { startPos.ry() += m_view->scrollOffset(); - if (m_view->itemSize().width() < 0) { - // Use a special rubberband for views that have only one column and - // expand the rubberband to use the whole width of the view. - startPos.setX(0); - } } else { startPos.rx() += m_view->scrollOffset(); } -- cgit v1.3 From cff402356e269d562a3acf2292cfdac233b1032c Mon Sep 17 00:00:00 2001 From: Méven Car Date: Fri, 29 Sep 2023 09:29:16 +0200 Subject: DolphinPlacesModel: remove usage of alternativeApplicationName This is now not needed anymore since `PlacesItemModel::cleanupBookmarks` (now removed) from https://phabricator.kde.org/D9333 has run for on users systems. --- src/dolphinplacesmodelsingleton.cpp | 11 +++-------- src/dolphinplacesmodelsingleton.h | 5 +---- 2 files changed, 4 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/dolphinplacesmodelsingleton.cpp b/src/dolphinplacesmodelsingleton.cpp index 3044dc8f5..301150394 100644 --- a/src/dolphinplacesmodelsingleton.cpp +++ b/src/dolphinplacesmodelsingleton.cpp @@ -13,8 +13,8 @@ #include #include -DolphinPlacesModel::DolphinPlacesModel(const QString &alternativeApplicationName, QObject *parent) - : KFilePlacesModel(alternativeApplicationName, parent) +DolphinPlacesModel::DolphinPlacesModel(QObject *parent) + : KFilePlacesModel(parent) { connect(&Trash::instance(), &Trash::emptinessChanged, this, &DolphinPlacesModel::slotTrashEmptinessChanged); } @@ -118,7 +118,7 @@ bool DolphinPlacesModel::isTrash(const QModelIndex &index) const } DolphinPlacesModelSingleton::DolphinPlacesModelSingleton() - : m_placesModel(new DolphinPlacesModel(KAboutData::applicationData().componentName() + applicationNameSuffix())) + : m_placesModel(new DolphinPlacesModel()) { } @@ -133,9 +133,4 @@ DolphinPlacesModel *DolphinPlacesModelSingleton::placesModel() const return m_placesModel.data(); } -QString DolphinPlacesModelSingleton::applicationNameSuffix() -{ - return QStringLiteral("-places-panel"); -} - #include "moc_dolphinplacesmodelsingleton.cpp" diff --git a/src/dolphinplacesmodelsingleton.h b/src/dolphinplacesmodelsingleton.h index a0524068f..161a19cbc 100644 --- a/src/dolphinplacesmodelsingleton.h +++ b/src/dolphinplacesmodelsingleton.h @@ -23,7 +23,7 @@ class DolphinPlacesModel : public KFilePlacesModel Q_OBJECT public: - explicit DolphinPlacesModel(const QString &alternativeApplicationName, QObject *parent = nullptr); + explicit DolphinPlacesModel(QObject *parent = nullptr); ~DolphinPlacesModel() override; bool panelsLocked() const; @@ -54,9 +54,6 @@ public: static DolphinPlacesModelSingleton &instance(); DolphinPlacesModel *placesModel() const; - /** A suffix to the application-name of the stored bookmarks is - added, which is only read by PlacesItemModel. */ - static QString applicationNameSuffix(); DolphinPlacesModelSingleton(const DolphinPlacesModelSingleton &) = delete; DolphinPlacesModelSingleton &operator=(const DolphinPlacesModelSingleton &) = delete; -- cgit v1.3 From e1de6c3492c67073fdaa0e454a9c748ba0337ba6 Mon Sep 17 00:00:00 2001 From: Amol Godbole Date: Tue, 3 Oct 2023 00:44:55 -0500 Subject: DolphinRecentTabsMenu: Fix blank text for closed search tab The recently closed menu adds a blank item when a search tab is closed. Add the search term and path to the item text. BUG: 474999 --- src/dolphinrecenttabsmenu.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/dolphinrecenttabsmenu.cpp b/src/dolphinrecenttabsmenu.cpp index 6a647c177..74aaf232e 100644 --- a/src/dolphinrecenttabsmenu.cpp +++ b/src/dolphinrecenttabsmenu.cpp @@ -5,12 +5,14 @@ */ #include "dolphinrecenttabsmenu.h" +#include "search/dolphinquery.h" #include #include #include #include +#include DolphinRecentTabsMenu::DolphinRecentTabsMenu(QObject *parent) : KActionMenu(QIcon::fromTheme(QStringLiteral("edit-undo")), i18n("Recently Closed Tabs"), parent) @@ -30,7 +32,15 @@ DolphinRecentTabsMenu::DolphinRecentTabsMenu(QObject *parent) void DolphinRecentTabsMenu::rememberClosedTab(const QUrl &url, const QByteArray &state) { QAction *action = new QAction(menu()); - action->setText(url.path()); + if (DolphinQuery::supportsScheme(url.scheme())) { + const DolphinQuery query = DolphinQuery::fromSearchUrl(url); + action->setText(i18n("Search for %1 in %2", query.text(), query.includeFolder())); + } else if (url.scheme() == QLatin1String("filenamesearch")) { + const QUrlQuery query(url); + action->setText(i18n("Search for %1 in %2", query.queryItemValue(QStringLiteral("search")), query.queryItemValue(QStringLiteral("url")))); + } else { + action->setText(url.path()); + } action->setData(state); const QString iconName = KIO::iconNameForUrl(url); action->setIcon(QIcon::fromTheme(iconName)); -- cgit v1.3 From 4d018e1c3cd5211c82cfe42a250956adfb47747b Mon Sep 17 00:00:00 2001 From: Amol Godbole Date: Tue, 3 Oct 2023 21:38:47 -0500 Subject: DolphinViewContainer: Keep search box open when URL is changed The search box was being automatically closed whenever the URL is changed. Keep the search box open if no search text had been entered when the URL was changed. BUG: 474951 --- src/dolphinviewcontainer.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/dolphinviewcontainer.cpp b/src/dolphinviewcontainer.cpp index 66a9a116a..5b2a318d6 100644 --- a/src/dolphinviewcontainer.cpp +++ b/src/dolphinviewcontainer.cpp @@ -818,11 +818,13 @@ void DolphinViewContainer::slotUrlNavigatorLocationChanged(const QUrl &url) } if (KProtocolManager::supportsListing(url)) { - setSearchModeEnabled(isSearchUrl(url)); + const bool searchBoxInitialized = isSearchModeEnabled() && m_searchBox->text().isEmpty(); + setSearchModeEnabled(isSearchUrl(url) || searchBoxInitialized); + m_view->setUrl(url); tryRestoreViewState(); - if (m_autoGrabFocus && isActive() && !isSearchUrl(url)) { + if (m_autoGrabFocus && isActive() && !isSearchModeEnabled()) { // When an URL has been entered, the view should get the focus. // The focus must be requested asynchronously, as changing the URL might create // a new view widget. -- cgit v1.3 From 7a6cba7f51068a367c2dcd1908d1f3f329e8d50f Mon Sep 17 00:00:00 2001 From: Méven Car Date: Wed, 6 Sep 2023 10:40:22 +0200 Subject: KItemListWidget: make unfocused alternate background slightly lighter --- src/kitemviews/kitemlistwidget.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/kitemviews/kitemlistwidget.cpp b/src/kitemviews/kitemlistwidget.cpp index cfaf89175..fb985ba23 100644 --- a/src/kitemviews/kitemlistwidget.cpp +++ b/src/kitemviews/kitemlistwidget.cpp @@ -105,7 +105,17 @@ void KItemListWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *o Q_UNUSED(option) if (m_alternateBackground) { - const QColor backgroundColor = m_styleOption.palette.color(QPalette::AlternateBase); + QColor backgroundColor = m_styleOption.palette.color(QPalette::AlternateBase); + if (!widget->hasFocus()) { + QColor baseColor = m_styleOption.palette.color(QPalette::Base); + if (baseColor.lightnessF() > 0.5) { + // theme seems light + backgroundColor = backgroundColor.lighter(101); + } else { + // theme seems dark + backgroundColor = backgroundColor.darker(101); + } + } const QRectF backgroundRect(0, 0, size().width(), size().height()); painter->fillRect(backgroundRect, backgroundColor); } -- cgit v1.3 From 549fad2daeeccac53b88b4777dcc9effbc2110e5 Mon Sep 17 00:00:00 2001 From: Felix Ernst Date: Mon, 17 Jul 2023 17:13:51 +0300 Subject: Fix accessibility ancestor tree Before this commit, KItemListViewAccessible would always return nullptr as its parent. This meant that accessibility software would have to guess to which window/hierarchy the KItemListView belongs to. Guessing shouldn't be necessary here. This commit makes sure that the KItemListView always returns a sensible parent in the accessible hierarchy. It does so by explicitly setting the accessible parent for every KItemListView after construction in the DolphinView contructor. Since KItemListView now always knows about its accessible parent, the accessibleInterfaceFactory can always ask the KItemListView for that information when constructing the QAccessibleInterfaces. Fixes https://invent.kde.org/system/dolphin/-/issues/47. --- src/kitemviews/kitemlistview.cpp | 20 +++++++++++++++++++- src/kitemviews/kitemlistview.h | 18 ++++++++++++++++++ src/kitemviews/kitemlistviewaccessible.cpp | 7 ++++--- src/kitemviews/kitemlistviewaccessible.h | 5 ++++- src/tests/kitemlistcontrollerexpandtest.cpp | 3 +++ src/tests/kitemlistcontrollertest.cpp | 3 +++ src/views/dolphinview.cpp | 3 +++ 7 files changed, 54 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/kitemviews/kitemlistview.cpp b/src/kitemviews/kitemlistview.cpp index 38d21ff5e..457c02ec5 100644 --- a/src/kitemviews/kitemlistview.cpp +++ b/src/kitemviews/kitemlistview.cpp @@ -50,9 +50,14 @@ QAccessibleInterface *accessibleInterfaceFactory(const QString &key, QObject *ob Q_UNUSED(key) if (KItemListContainer *container = qobject_cast(object)) { + if (auto controller = container->controller(); controller) { + if (KItemListView *view = controller->view(); view && view->accessibleParent()) { + return view->accessibleParent(); + } + } return new KItemListContainerAccessible(container); } else if (KItemListView *view = qobject_cast(object)) { - return new KItemListViewAccessible(view); + return new KItemListViewAccessible(view, view->accessibleParent()); } return nullptr; @@ -337,6 +342,19 @@ KItemListGroupHeaderCreatorBase *KItemListView::groupHeaderCreator() const return m_groupHeaderCreator; } +#ifndef QT_NO_ACCESSIBILITY +void KItemListView::setAccessibleParentsObject(KItemListContainer *accessibleParentsObject) +{ + Q_ASSERT(!m_accessibleParent); + m_accessibleParent = new KItemListContainerAccessible(accessibleParentsObject); +} +KItemListContainerAccessible *KItemListView::accessibleParent() +{ + Q_CHECK_PTR(m_accessibleParent); // We always want the accessibility tree/hierarchy to be complete. + return m_accessibleParent; +} +#endif + QSizeF KItemListView::itemSize() const { return m_itemSize; diff --git a/src/kitemviews/kitemlistview.h b/src/kitemviews/kitemlistview.h index ff51af922..7bcaec704 100644 --- a/src/kitemviews/kitemlistview.h +++ b/src/kitemviews/kitemlistview.h @@ -21,6 +21,8 @@ #include #include +class KItemListContainer; +class KItemListContainerAccessible; class KItemListController; class KItemListGroupHeaderCreatorBase; class KItemListHeader; @@ -142,6 +144,18 @@ public: void setGroupHeaderCreator(KItemListGroupHeaderCreatorBase *groupHeaderCreator); KItemListGroupHeaderCreatorBase *groupHeaderCreator() const; +#ifndef QT_NO_ACCESSIBILITY + /** + * Uses \a parent to create an accessible object for \a parent. That accessible object will + * then be used as the accessible parent of the accessible object for this KItemListView. + * Make sure \a parent is the container which contains this specific KItemListView. + * This method must be called once before the accessible interface is queried for this class. + */ + void setAccessibleParentsObject(KItemListContainer *accessibleParentsObject); + /** The parent of the QAccessibilityInterface of this class. */ + KItemListContainerAccessible *accessibleParent(); +#endif + /** * @return The basic size of all items. The size of an item may be larger than * the basic size (see KItemListView::itemRect()). @@ -711,6 +725,10 @@ private: QList m_visibleRoles; mutable KItemListWidgetCreatorBase *m_widgetCreator; mutable KItemListGroupHeaderCreatorBase *m_groupHeaderCreator; +#ifndef QT_NO_ACCESSIBILITY + /** The object that will be the parent of this classes QAccessibleInterface. */ + KItemListContainerAccessible *m_accessibleParent = nullptr; +#endif KItemListStyleOption m_styleOption; QHash m_visibleItems; diff --git a/src/kitemviews/kitemlistviewaccessible.cpp b/src/kitemviews/kitemlistviewaccessible.cpp index a75df8b76..38c883efe 100644 --- a/src/kitemviews/kitemlistviewaccessible.cpp +++ b/src/kitemviews/kitemlistviewaccessible.cpp @@ -21,10 +21,12 @@ KItemListView *KItemListViewAccessible::view() const return qobject_cast(object()); } -KItemListViewAccessible::KItemListViewAccessible(KItemListView *view_) +KItemListViewAccessible::KItemListViewAccessible(KItemListView *view_, KItemListContainerAccessible *parent) : QAccessibleObject(view_) + , m_parent(parent) { Q_ASSERT(view()); + Q_CHECK_PTR(parent); m_cells.resize(childCount()); } @@ -208,8 +210,7 @@ QAccessibleInterface *KItemListViewAccessible::childAt(int x, int y) const QAccessibleInterface *KItemListViewAccessible::parent() const { - // FIXME: return KItemListContainerAccessible here - return nullptr; + return m_parent; } int KItemListViewAccessible::childCount() const diff --git a/src/kitemviews/kitemlistviewaccessible.h b/src/kitemviews/kitemlistviewaccessible.h index 628c32fc2..41aacf367 100644 --- a/src/kitemviews/kitemlistviewaccessible.h +++ b/src/kitemviews/kitemlistviewaccessible.h @@ -18,11 +18,12 @@ class KItemListView; class KItemListContainer; +class KItemListContainerAccessible; class DOLPHIN_EXPORT KItemListViewAccessible : public QAccessibleObject, public QAccessibleTableInterface { public: - explicit KItemListViewAccessible(KItemListView *view); + explicit KItemListViewAccessible(KItemListView *view, KItemListContainerAccessible *parent); ~KItemListViewAccessible() override; void *interface_cast(QAccessible::InterfaceType type) override; @@ -81,6 +82,8 @@ private: QAccessible::Id id; }; mutable QVector m_cells; + + KItemListContainerAccessible *m_parent; }; class DOLPHIN_EXPORT KItemListAccessibleCell : public QAccessibleInterface, public QAccessibleTableCellInterface diff --git a/src/tests/kitemlistcontrollerexpandtest.cpp b/src/tests/kitemlistcontrollerexpandtest.cpp index 368ec67ce..05708f4d2 100644 --- a/src/tests/kitemlistcontrollerexpandtest.cpp +++ b/src/tests/kitemlistcontrollerexpandtest.cpp @@ -48,6 +48,9 @@ void KItemListControllerExpandTest::initTestCase() m_view = new KFileItemListView(); m_controller = new KItemListController(m_model, m_view, this); m_container = new KItemListContainer(m_controller); +#ifndef QT_NO_ACCESSIBILITY + m_view->setAccessibleParentsObject(m_container); +#endif m_controller = m_container->controller(); m_controller->setSelectionBehavior(KItemListController::MultiSelection); m_selectionManager = m_controller->selectionManager(); diff --git a/src/tests/kitemlistcontrollertest.cpp b/src/tests/kitemlistcontrollertest.cpp index d1a9cfc7c..9d345fdd9 100644 --- a/src/tests/kitemlistcontrollertest.cpp +++ b/src/tests/kitemlistcontrollertest.cpp @@ -109,6 +109,9 @@ void KItemListControllerTest::initTestCase() m_view = new KFileItemListView(); m_controller = new KItemListController(m_model, m_view, this); m_container = new KItemListContainer(m_controller); +#ifndef QT_NO_ACCESSIBILITY + m_view->setAccessibleParentsObject(m_container); +#endif m_controller = m_container->controller(); m_controller->setSelectionBehavior(KItemListController::MultiSelection); m_selectionManager = m_controller->selectionManager(); diff --git a/src/views/dolphinview.cpp b/src/views/dolphinview.cpp index 21e23d5ac..d8eab142d 100644 --- a/src/views/dolphinview.cpp +++ b/src/views/dolphinview.cpp @@ -129,6 +129,9 @@ DolphinView::DolphinView(const QUrl &url, QWidget *parent) m_container = new KItemListContainer(controller, this); m_container->installEventFilter(this); +#ifndef QT_NO_ACCESSIBILITY + m_view->setAccessibleParentsObject(m_container); +#endif setFocusProxy(m_container); connect(m_container->horizontalScrollBar(), &QScrollBar::valueChanged, this, [=] { hideToolTip(); -- cgit v1.3 From b58fead9beaf3165146d3e536b6b14ae1cc9514d Mon Sep 17 00:00:00 2001 From: Felix Ernst Date: Fri, 8 Sep 2023 17:10:29 +0200 Subject: Add test for accessibility ancestor tree This is to make sure that all items that can be tabbed to and their accessible children have the main window somewhere in their ancestry/ancestor tree. --- src/tests/dolphinmainwindowtest.cpp | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'src') diff --git a/src/tests/dolphinmainwindowtest.cpp b/src/tests/dolphinmainwindowtest.cpp index 009008002..e6c355a87 100644 --- a/src/tests/dolphinmainwindowtest.cpp +++ b/src/tests/dolphinmainwindowtest.cpp @@ -14,11 +14,14 @@ #include +#include #include #include #include #include +#include + class DolphinMainWindowTest : public QObject { Q_OBJECT @@ -39,6 +42,7 @@ private Q_SLOTS: void testPlacesPanelWidthResistance(); void testGoActions(); void testOpenFiles(); + void testAccessibilityAncestorTree(); void cleanupTestCase(); private: @@ -524,6 +528,39 @@ void DolphinMainWindowTest::testOpenFiles() QTRY_COMPARE(m_mainWindow->m_activeViewContainer->view()->selectedItems().count(), 1); } +void DolphinMainWindowTest::testAccessibilityAncestorTree() +{ + m_mainWindow->openDirectories({QUrl::fromLocalFile(QDir::homePath())}, false); + m_mainWindow->show(); + QVERIFY(QTest::qWaitForWindowExposed(m_mainWindow.data())); + QVERIFY(m_mainWindow->isVisible()); + + std::set testedObjects; // Makes sure we stop testing if we arrive at an item that was already tested. + QAccessibleInterface *accessibleInterfaceOfMainWindow = QAccessible::queryAccessibleInterface(m_mainWindow.get()); + Q_CHECK_PTR(accessibleInterfaceOfMainWindow); + + // We will do accessibility checks for every object that gets focus. Focus will be changed using the Tab key. + while (qApp->focusObject() && !testedObjects.count(qApp->focusObject())) { + const auto currentlyFocusedObject = qApp->focusObject(); + QAccessibleInterface *accessibleInterface = QAccessible::queryAccessibleInterface(currentlyFocusedObject); + + // The accessibleInterfaces of focused objects might themselves have children. + // We go down that hierarchy as far as possible and then test the ancestor tree from there. + while (accessibleInterface->childCount() > 0) { + accessibleInterface = accessibleInterface->child(0); + } + while (accessibleInterface != accessibleInterfaceOfMainWindow) { + QVERIFY2(accessibleInterface, + qPrintable(QString("%1's accessibleInterface or one of its accessible children doesn't have the main window as an ancestor.") + .arg(currentlyFocusedObject->metaObject()->className()))); + accessibleInterface = accessibleInterface->parent(); + } + + testedObjects.insert(currentlyFocusedObject); // Add it to testedObjects so we won't test it again later. + QTest::keyClick(m_mainWindow.get(), Qt::Key::Key_Tab, Qt::ShiftModifier); // ShiftModifier because the Tab cycle is currently broken going forward. + } +} + void DolphinMainWindowTest::cleanupTestCase() { m_mainWindow->showNormal(); -- cgit v1.3