[KFileWidget] Avoid calling slotOk right after the url changed
ClosedPublic

Authored by meven on Nov 20 2019, 12:08 PM.

Details

Summary

When _k_slotViewKeyEnterReturnPressed is called, KDirOperator::_k_slotActivated is called first potentially opening another directory.
And since the directory changed, the kdiroperator selection is empty, causing then kiowidgets-kdirmodeltest to call slotOk and if a filename was present in the filename field, it will cause the dialog to accept() prematurely.

This patch prevents KDirOperator::keyEnterReturnPressed to be emitted when QAbstractItemView::activated would be, preventing the issue in the first place.

BUG: 412737
FIXED-IN: 5.65

Relates to D19824

Test Plan
  1. Save a file using KFileWidget
  2. Go to a folder with files and directories
  3. Select a file
  4. Select a directory
  5. Hit Enter

Before:
The directory is opened briefly and the dialog returns.

After:
The selected directory is opened.

Diff Detail

Repository
R241 KIO
Lint
Automatic diff as part of commit; lint not applicable.
Unit
Automatic diff as part of commit; unit tests not applicable.
meven created this revision.Nov 20 2019, 12:08 PM
Restricted Application added a project: Frameworks. · View Herald TranscriptNov 20 2019, 12:08 PM
Restricted Application added a subscriber: kde-frameworks-devel. · View Herald Transcript
meven requested review of this revision.Nov 20 2019, 12:08 PM
meven added a comment.Dec 2 2019, 3:38 PM

ping anyone ?

This comment was removed by ngraham.
ngraham accepted this revision.Dec 2 2019, 5:10 PM

Seems to fix the issue and I did not detect any regressions in keyboard navigation in open or save dialogs. May be a good idea to wait to commit this until after Frameworks 5.65 is tagged though so it has a month of testing in production before release rather than just a few days.

This revision is now accepted and ready to land.Dec 2 2019, 5:10 PM
ahmadsamir added a subscriber: ahmadsamir.

IMHO, it's such a user-visible bug with several reports and it affects all apps that use KIO; it should be included if it can catch the 5.65 train.

I can confirm it fixes the issue in my local build (and the code LGTM).

Urgh. bool members as used here to share state between methods, with the assumption that they're always called together and in a certain order, are very brittle.

If KDirOperator is a child widget, and it receives and processes a key event, it can choose to NOT let the event propagate to the parent widget
[by calling accept() on the QKeyEvent, or returning false from event(), or true from eventFilter(), depending on how the event is processed -- isn't Qt easy? ;-)]

IMHO, it's such a user-visible bug with several reports and it affects all apps that use KIO; it should be included if it can catch the 5.65 train.

I can confirm it fixes the issue in my local build (and the code LGTM).

No objections if folks smarter than me think the code is acceptable. :)

dfaure added a comment.Dec 3 2019, 8:42 AM

I'm not smarter than you, but I consider this code hacky :-)

dfaure requested changes to this revision.Dec 3 2019, 8:42 AM
This revision now requires changes to proceed.Dec 3 2019, 8:42 AM
meven added a comment.Dec 3 2019, 1:06 PM

If KDirOperator is a child widget, and it receives and processes a key event, it can choose to NOT let the event propagate to the parent widget
[by calling accept() on the QKeyEvent, or returning false from event(), or true from eventFilter(), depending on how the event is processed -- isn't Qt easy? ;-)]

The issue is that QAbstractItemView::activated does not have a QEvent as parameter and it is emitted from different places.
Meaning I can't use the Qt Event system to stop propagation of events triggering QAbstractItemView::activated, it is a Qt limitation IMO.
So I might just move this boolean in KDirOperator or try to detect the condition when activated will be emitted, unless there is something more elegant I am missing.
Moving the hack to KDirOperator is already somewhat cleaner.

meven edited the summary of this revision. (Show Details)Dec 3 2019, 1:33 PM
meven updated this revision to Diff 70826.Dec 3 2019, 1:33 PM

Move activated event detection to KDirOperator

dfaure added a comment.Dec 3 2019, 1:52 PM

So after a double-click, activated() is emitted, the boolean is set, and much later some Key_Enter event that should have been emitted, gets eaten?

Wouldn't an event filter on the QAbstractItemView solve your problem? Then you can catch the Return key before QAbstractItemView sees it, and call _k_slotActivated yourself, and decide whether to emit returnPressed as well?

I hope this makes sense, if not I can dig further later, I'm in a bit of a rush right now.

I'm actually wondering *when* we want KDirOperator to emit returnPressed at all. When the current index isn't a directory, I assume?

So after a double-click, activated() is emitted, the boolean is set, and much later some Key_Enter event that should have been emitted, gets eaten?

Wouldn't an event filter on the QAbstractItemView solve your problem? Then you can catch the Return key before QAbstractItemView sees it, and call _k_slotActivated yourself, and decide whether to emit returnPressed as well?

I hope this makes sense, if not I can dig further later, I'm in a bit of a rush right now.

I'm actually wondering *when* we want KDirOperator to emit returnPressed at all. When the current index isn't a directory, I assume?

Digging around in git history I found this:
https://cgit.kde.org/kdelibs.git/commit/?id=81e69464329ddad59600dde5a1a27f58a0b91188
with a detailed/great commit message.

I think there should be a set of rules for kfilewidget in the API docs, so that future behaviour changes in this, rather tricky, area are aware of the various "requirements" involved.

And, of course, more unit tests like the one in D19824... :D

meven added a comment.Dec 3 2019, 6:54 PM

So after a double-click, activated() is emitted, the boolean is set, and much later some Key_Enter event that should have been emitted, gets eaten?

Wouldn't an event filter on the QAbstractItemView solve your problem? Then you can catch the Return key before QAbstractItemView sees it, and call _k_slotActivated yourself, and decide whether to emit returnPressed as well?

I hope this makes sense, if not I can dig further later, I'm in a bit of a rush right now.

I'm actually wondering *when* we want KDirOperator to emit returnPressed at all. When the current index isn't a directory, I assume?

When the view has nothing selected, in fact.

And, of course, more unit tests like the one in D19824... :D

This was not an automated test.

meven edited the summary of this revision. (Show Details)Dec 3 2019, 7:03 PM
meven updated this revision to Diff 70847.Dec 3 2019, 7:04 PM

Consumes KeyPressEvent when activated would not needed, clean up

meven updated this revision to Diff 70848.Dec 3 2019, 7:05 PM

Clean up

And, of course, more unit tests like the one in D19824... :D

This was not an automated test.

OK, thanks for clarifying that.

dfaure accepted this revision.Dec 4 2019, 12:06 AM

No reconstructing-call-history-via-a-boolean-member, I like this! :-)

Thanks for your tests with this solution.

src/filewidgets/kdiroperator.cpp
1446

I expected a "return true" after this line.

Otherwise the event, while marked as accepted, is still sent to the target widget, the view(). Well, I guess it doesn't do anything when there's no current index, but still, we handled the event, no point in sending it to the view, right?

accept() only stops propagation to parent widgets.
We need "return true" to stop the current "send event to the view" operation.

But yeah, I suppose it works either way, so I'm approving as is.

This revision is now accepted and ready to land.Dec 4 2019, 12:06 AM
meven updated this revision to Diff 70883.Dec 4 2019, 10:19 AM

Add return after accepting

meven marked an inline comment as done.Dec 4 2019, 10:21 AM
This revision was automatically updated to reflect the committed changes.

FWIW, this still doesn't work:

  • Open a pdf in okular
  • Invoke save as, navigate via the keyboard, highlight/select a dir, Enter, the file is saved inside that dir and the dialog closes
dfaure added inline comments.Dec 13 2019, 8:48 AM
src/filewidgets/kdiroperator.h
688

For the record, removing a virtual method is BIC, I have added it again now (as a dummy forwarder). Oops, I failed to think about that earlier.