KDirModel: implement showing a root node for the requested URL
ClosedPublic

Authored by dfaure on Nov 15 2019, 3:52 AM.

Details

Summary

To trigger this, cal KDirModel::openUrl(rootUrl, KDirModel::ShowRoot)

KDirModel has always been lacking a openUrl method anyway, it's always
been weird to create a KDirModel but then call
dirModel->dirLister()->openUrl().

This feature has been requested by Raphael Rosch who is reimplementing
the konqueror sidebar tree on top of KDirModel. Having a visible item
for "/" is necessary in order to be able to click on it and have it
listed in the main file view.

Test Plan

kdirmodeltest_gui and 2 new methods in kdirmodeltest (unittest)

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.
dfaure created this revision.Nov 15 2019, 3:52 AM
Restricted Application added a project: Frameworks. · View Herald TranscriptNov 15 2019, 3:52 AM
Restricted Application added a subscriber: kde-frameworks-devel. · View Herald Transcript
dfaure requested review of this revision.Nov 15 2019, 3:52 AM
meven added inline comments.Nov 22 2019, 6:57 PM
src/widgets/kdirmodel.h
78

Would it make sense to instead of interpreting QUrl(), OpenUrlFlag would include a ShowRoot flag ?
I really like enums are they are explicit from the callee perspective.
Then it could call expandAllParentsUntil directly, this would allow in a single call to openUrl with a shown root node.

dfaure updated this revision to Diff 70183.Nov 22 2019, 7:44 PM

Add ShowRoot flag, excellent idea!

rrosch added a subscriber: rrosch.Feb 28 2020, 12:22 PM

Tested on patched KF5 5.64, on Fedora 30 (32bit)... root node shows up! I had to change the call in my code that was originally:

model->dirLister()->openUrl(QUrl::fromLocalFile("/"), KDirLister::Keep);

to

model->openUrl(QUrl::fromLocalFile("/"), KDirModel::ShowRoot);

and don't really know the implications of the change at this point. (Will it "Keep"? Does it matter that I now call the model's openURL vs the dirLister's?)

I couldn't however get the following to work:

QModelIndex index = getIndexFromUrl("/home/myuser");
if (index.isValid()) {
    treeView->setRootIndex(index.parent());
}

Which should show the node for "/home" as the root, but is instead giving me a flat listing of all the child nodes without "/home" as the root. Am I doing something wrong here? That part is called on a slot for the signal &KDirModel::expand. (Also, it would be great to have a setRootPath() that works in conjunction to expandToUrl or openUrl, to save processing cycles wasted on loading the parts of the model that won't be shown in the new rootIndex, like https://doc.qt.io/qt-5/qfilesystemmodel.html#setRootPath )

As it is relevant, I also tested the patch at http://www.davidfaure.fr/2019/kdirmodel_haschildren.diff for hasChildren(), which works as expected! Thank you!


For the curious, I just downloaded the source rpm for kf5-kio, installed it as unprivileged user, edited the .spec file to include the raw diff here as a the second patch, and the raw diff for D25249 as the first patch (and copying them to ~/rpmbuild/SOURCES/ of course). I also had to change the Release: line to something greater than the one already there so it installs without conflicts (I changed mine from "1" to "2patched"). Then just

rpmbuild -bb ~/rpmbuild/SPECS/kf5-kio.spec

and install the relevant rpms. No need to rebuild all of KF5 from git (which I started to attempt and bailed pretty quickly after thinking this might be the easier/faster/less space-using way. Knowing this process will be useful for newcomers to help test features on their system without the daunting (and probably impossible due to limited space) task of compiling all of KF5. This could be added to the dev documentation somewhere.

In any case, thanks again for implementing the feature! (Next step is to try to follow the same procedure to test the "crash on close of view" fix you submitted for Qt5, thanks also for that!)

Ok, I found one of the "implications". With model->dirLister()->openUrl(m_initURL, KDirLister::Keep); I can list KIO urls like remote:, font:, and applications:, but with model->openUrl(m_initURL, KDirModel::ShowRoot); I cannot, and only seems to display the the local filesystem (specifically it lists "/"). I can probably work around it, but just wanted to pass that info along. I think it would be great if the "root" could be shown for these as well.

dfaure planned changes to this revision.Feb 28 2020, 9:05 PM

Tested on patched KF5 5.64, on Fedora 30 (32bit)... root node shows up! I had to change the call in my code that was originally:

model->dirLister()->openUrl(QUrl::fromLocalFile("/"), KDirLister::Keep);

[to] model->openUrl(QUrl::fromLocalFile("/"), KDirModel::ShowRoot);
and don't really know the implications of the change at this point. (Will it "Keep"? Does it matter that I now call the model's openURL vs the dirLister's?)

It's part of the documentation for this change, that you're actually supposed to call model->openUrl(). So yes it matters :-)

Keep only matters for further calls to openUrl, not the first one. It's about whether to *add* or *replace* the currently open URL.
KDirModel takes care of that.

I couldn't however get the following to work:

QModelIndex index = getIndexFromUrl("/home/myuser");

Invalid URL, that's a path, not a URL. You need QUrl::fromLocalFile().

if (index.isValid()) {
    treeView->setRootIndex(index.parent());
}

Which should show the node for "/home" as the root, but is instead giving me a flat listing of all the child nodes without "/home" as the root.

Oh, hmm, that's not how setRootIndex works (that's a *view* feature, we can't change that).
I changed the model to have one more node for "/", while I see now that what you want is that it *always* shows a root node even when the root is another directory.

(Also, it would be great to have a setRootPath() that works in conjunction to expandToUrl or openUrl, to save processing cycles wasted on loading the parts of the model that won't be shown in the new rootIndex, like https://doc.qt.io/qt-5/qfilesystemmodel.html#setRootPath )

Yes it sounds like that's exactly what's needed in KDirModel. Damn, I need to rework all this then.

As it is relevant, I also tested the patch at http://www.davidfaure.fr/2019/kdirmodel_haschildren.diff for hasChildren(), which works as expected! Thank you!

Thanks, posted as D27731

Keep only matters for further calls to openUrl, not the first one. It's about whether to *add* or *replace* the currently open URL.
KDirModel takes care of that.

Ah ok, so it's going to do that without me needing to explicitly specify "Keep"?

I couldn't however get the following to work:

QModelIndex index = getIndexFromUrl("/home/myuser");

Invalid URL, that's a path, not a URL. You need QUrl::fromLocalFile().

Sorry that was me using shorthand to illustrate the problem, the url in the code is an absolute url stored in a variable with the schema and all the necessary things.

Which should show the node for "/home" as the root, but is instead giving me a flat listing of all the child nodes without "/home" as the root.

Oh, hmm, that's not how setRootIndex works (that's a *view* feature, we can't change that).
I changed the model to have one more node for "/", while I see now that what you want is that it *always* shows a root node even when the root is another directory.

Yeah that was my intent with the above. How come it doesn't work in the view for file:///home/myuser but it works for file:///?

In any case, the code here you provided works great for at least file:/// and that gets us quite far. How much of a rework would getting it to work with subdirectories (like file:///home/myuser) take?

Keep only matters for further calls to openUrl, not the first one. It's about whether to *add* or *replace* the currently open URL.
KDirModel takes care of that.

Ah ok, so it's going to do that without me needing to explicitly specify "Keep"?

Yes. Basically KDirModel is one layer above KDirLister, it encapsulates it. If you use KDirModel, you shouldn't have to use KDirLister API directly.

Which should show the node for "/home" as the root, but is instead giving me a flat listing of all the child nodes without "/home" as the root.

Oh, hmm, that's not how setRootIndex works (that's a *view* feature, we can't change that).
I changed the model to have one more node for "/", while I see now that what you want is that it *always* shows a root node even when the root is another directory.

Yeah that was my intent with the above. How come it doesn't work in the view for file:///home/myuser but it works for file:///?

I thought the plan was to always show a tree that starts at the root, like iirc the old "Root" tab in konqueror-kde4, or the Root tree view in dolphin.
This is why KDirModel::openUrl("file:///home/myuser", ShowRoot) shows

"/"
| - home
    | - myuser

In any case, the code here you provided works great for at least file:/// and that gets us quite far. How much of a rework would getting it to work with subdirectories (like file:///home/myuser) take?

No idea. I'll work on it and let you know how much work it was :)

dfaure updated this revision to Diff 76701.Feb 29 2020, 7:30 PM
dfaure retitled this revision from KDirModel: implement showing "/" as a root node, optionally to KDirModel: implement showing a root node for the requested URL.
dfaure edited the summary of this revision. (Show Details)
dfaure removed a subscriber: rrosch.

Rework the patch so that any node can be shown as a visible root.

This is actually much cleaner, no more empty-URL hacks.

Crash:

kf5.kio.kdirmodel: Items emitted in directory QUrl("file:///home/myuser/") but that directory isn't in KDirModel! Root directory: QUrl("file:///home/myuser/")
KCrash: Application 'konqueror' crashing...

This happens right after pressing F9 to bring up the sidebar.

Well, I don't have your code. Which calls are you making into KDirModel? (openUrl(args=?), expandToUrl(args=?))

OK, reproduced by adding a test for a URL with a trailing slash. Fix coming up.

dfaure updated this revision to Diff 77155.Mar 7 2020, 10:19 AM

Strip trailing slashes, add test

ahmadsamir added inline comments.
src/widgets/kdirmodel.cpp
222

Braces around if.

src/widgets/kdirmodel.h
79

I suggest:
s/its children/the first child/ OR
s/at its children/directly at the first child/

ahmadsamir added inline comments.Mar 7 2020, 1:17 PM
tests/kdirmodeltest_gui.cpp
92

I think a test with "file:///usr/share/fonts" would work better, i.e. the url arg is the top/focus of the model.

dfaure marked an inline comment as done.Mar 8 2020, 4:39 PM
dfaure added inline comments.
src/widgets/kdirmodel.h
79

That sounds more confusing to me, depending on how one thinks about all this.

There's nothing special about the first child compared to other direct children, one misinterpretation of your suggested sentence would be that the first child will be shown but not its siblings.

If ShowRoot is not set, then the given URL isn't shown, its children are. All of them :)

tests/kdirmodeltest_gui.cpp
92

Making file:/// work was actually more trouble so it's worth having an easy way to test this. This is an interactive test anyway, you can pass /usr/share/fonts as argument if you want to test that path :-)

dfaure updated this revision to Diff 77224.Mar 8 2020, 4:39 PM

Add missing braces around one-line if()

ahmadsamir added inline comments.Mar 8 2020, 4:52 PM
src/widgets/kdirmodel.h
79

Fair point.

tests/kdirmodeltest_gui.cpp
92

I did test the /usr/share/fonts path :); it's just that starting at "/" looked "normal", whereas starting at a specific dir conveyed the goal of this change better, to me anyway.

dfaure added inline comments.Mar 11 2020, 10:27 PM
tests/kdirmodeltest_gui.cpp
92

It doesn't look "normal" : without the ShowRoot feature, you wouldn't see the "/" root node.
So I would say the test program is valid, no matter what the starting directory is.

(I was wrong about passing a path as argument, this goes into the code path that does NOT set ShowRoot)

ahmadsamir added inline comments.Mar 12 2020, 4:26 AM
tests/kdirmodeltest_gui.cpp
92

I wasn't re-arguing for changing the path in the test app, just explaining my POV (and "normal" as in I expected, mentally, to see "/" as the parent, since, well, it is).

When I tested with /usr/share/fonts, I modified the source code directly. :)

dfaure added a subscriber: rrosch.Mar 21 2020, 10:01 AM

@rrosch Does this now behave as expected?

Hi, sorry for the lack of responses, for some reason I did not receive any of the notifications except this last one. I will test and comment as soon as I can. Wishing everyone safety and health too.

Tested, no crashes, it works as intended, and it is beautiful! Thank you!

This revision was not accepted when it landed; it landed in state Needs Review.Mar 28 2020, 9:04 AM
This revision was automatically updated to reflect the committed changes.