Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Searchable/Filterable preferences #4415

Merged
merged 34 commits into from
Mar 27, 2019

Conversation

WtfJoke
Copy link
Contributor

@WtfJoke WtfJoke commented Oct 27, 2018

Fixes #1019

Up so far I just created the textbox for searching and fixed a deprecation warning.
I added @paulKra as collaborator on my fork.

Last step so far: I was asking myself how I can access the text of the different Preferences-Categories and I was wondering if I need a new Interface (something like PrefTabContents or PrefTabContainer for it or extend existing PrefsTab Interface.


  • Change in CHANGELOG.md described
  • Tests created for changes
  • Manually tested changed features in running JabRef
  • Screenshots added in PR description (for bigger UI changes)
  • Ensured that the git commit message is a good one
  • Check documentation status (Issue created for outdated help page at help.jabref.org?)

@Siedlerchr
Copy link
Member

Siedlerchr commented Oct 27, 2018

First of all, thanks for your contribtion! 👍

If you look at the code fo the old PreferencesFilterDialog, you see that the data comes from the JabRefPreferencesFilter class in org.jabref.preferences.

If you have further questions you can also ask in out gitter chat. https://gitter.im/JabRef/jabref

Edit// Adjusted my comment

@tobiasdiez
Copy link
Member

The easiest solution is probably to transverse the complete control node tree and take the text of all label controls.

@Siedlerchr
Copy link
Member

@WtfJoke @paulKra What is the current status here? The code looks already promising. It would be really nice if you could finish this!

@WtfJoke
Copy link
Contributor Author

WtfJoke commented Nov 11, 2018

@Siedlerchr Its still on my todo list. Havent found the time to investigate further and were stuck on how I display the filtered preferences.

I think @paulKra doesnt work on it, he still didnt accept my invitation link to my forked repo

@Siedlerchr
Copy link
Member

Okay thanks for the udpate! Take your time. If you have any questions just ask here or in gitter and we try to help

@tobiasdiez
Copy link
Member

Maybe the JFXHighlighter from https://github.com/jfoenixadmin/JFoenix/ works to highlight the matches

@WtfJoke WtfJoke force-pushed the searchablePreferences branch 2 times, most recently from 488540f to 3ac59ef Compare November 18, 2018 18:01
@WtfJoke
Copy link
Contributor Author

WtfJoke commented Nov 20, 2018

@tobiasdiez Thanks for the hint, however I tested it locally but I didnt liked it that much (for example it did mark the buttons for importing/exporting/show/reset preferences also).
If I dont find alternatives I think about using it anways.

@tobiasdiez
Copy link
Member

@CaptainDaVinci is this ready for review or do you need to further work on it?
(The first remark you had concerning "Sending emails" is a nice suggestion for further improvement, but not necessary for merging I would say).

@CaptainDaVinci
Copy link
Contributor

@tobiasdiez Yes, this is ready for review.

@tobiasdiez tobiasdiez added the status: ready-for-review Pull Requests that are ready to be reviewed by the maintainers label Mar 14, 2019
@tobiasdiez tobiasdiez changed the title [WIP] Searchable/Filterable preferences Searchable/Filterable preferences Mar 14, 2019

private final Labeled labeled;

LabeledWrapper(Labeled _labeled) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please do not use an underscore. In java it's more common to do:

Suggested change
LabeledWrapper(Labeled _labeled) {
LabeledWrapper(Labeled labeled){
this.labeled= labeled;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And maybe use a better name to indicate what the purpose of the class actually is. LabeledWrapper sounds a bit too generic for me.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initial idea with the inner class was to handle Labeled being treated as a key to mapping from Labeled to PrefsTab. Now that the relation is reversed, I don't think the LabeledWrapper class is required anymore.

Copy link
Member

@Siedlerchr Siedlerchr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the contribution!
In general looks good to me, just some minor code style things.
And also please add a screenshot

}
}

PreferencesSearchHandler(List<PrefsTab> preferenceTabs, StringProperty searchText) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove the StringProperty as constructor argument, instead expose the property through a method:
And initialize the variable with new SimpleStringProperty("")

public StringProperty searchTextProperty()
{
return this.searchText;
 }

Copy link
Contributor

@CaptainDaVinci CaptainDaVinci Mar 17, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I understand, this should then be used to bind to searchBox.textProperty() in PerferencesDialog,
searchHandler.searchTextProperty().bind(searchBox.textProperty()); ?

Also, shouldn't tabsList.itemsProperty().bindBidirectional(searchHandler.filteredPreferenceTabsProperty());
have a unidirectional binding instead?

Copy link
Contributor

@CaptainDaVinci CaptainDaVinci Mar 20, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Siedlerchr I am facing some issues on implementing this.
I have removed the StringProperty from the constructor argument as per your suggestion.
In PreferencesDialog, the searchHandler.searchStringProperty() is bound to searchBox.textProperty(). However, when the searchBox text changes, it doesn't trigger the ChangeListener for searchText. Unless, I add a statement to listen for changes on searchBox as well.

 searchBox.textProperty().addListener((o, p, n) -> {
        // dummy reference to the text property.
        searchHandler.searchTextProperty();
});

I am not able to understand the reason for this, is it necessary to have listeners on both the properties which are bound?

TextField searchBox = new TextField();
searchBox.setPromptText(Localization.lang("Search"));

PreferencesSearchHandler searchHandler = new PreferencesSearchHandler(preferenceTabs, searchBox.textProperty());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bind the searchBox.textProperty the same ways as you do with the itemsProperty below

return prefsTabLabelMap;
}

protected ListProperty<PrefsTab> getFilteredPreferenceTabsProperty() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just the wording, remove the "get" from the name., e.g. just FilteredPreviewPreferencesTabsProperty() to conform to the javafx code naming conventions


private final Labeled labeled;

LabeledWrapper(Labeled _labeled) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And maybe use a better name to indicate what the purpose of the class actually is. LabeledWrapper sounds a bit too generic for me.

Copy link
Member

@tobiasdiez tobiasdiez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've only two small suggestions in addition to the ones of @Siedlerchr.

@@ -12,3 +12,7 @@
.preferencePaneContainer {
-fx-padding: 0em 1em 0em 3em;
}

*:search-highlight {
-fx-background-color: #ed7474;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please reuse one of the colors defined in base.css. In case you find no suitable color there, then please define a new one there.

}
}

if (tabContainsLabel) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As you suggested yourself, I think it is a good idea to move the logic of filterByTabName here (if (tabContainsLabel || tabNameIsMatchedBySearchQuery) instead of having two separate methods.

@CaptainDaVinci
Copy link
Contributor

Thank you for the suggestions @tobiasdiez and @Siedlerchr! I have refactored the code for the most part to account for the changes and will push the code once I have implemented all changes.

Screenshot showing the preferences window when searching:
preferences

@Siedlerchr
Copy link
Member

Siedlerchr commented Mar 20, 2019

@CaptainDaVinci Look at my patch: (Import via git am < file.patch)
I added the bidiretional binding and a listener in the Handler. This worked for me

0001-add-bidiretional-binding-to-searchProperty.patch.txt

@CaptainDaVinci
Copy link
Contributor

@Siedlerchr Thank you for sharing the patch, however, this did not work for me. The change listener for searchText is never called. I had a similar implementation except for not using EasyBind to register the callback.

The only way I could make this work was to add a listener to searchBox as well and refer to the searchText property in that.

searchBox.textProperty().addListener((o, p, n) -> {
    searchHandler.searchTextProperty();     // required, so that changed are reflected.
});

@Siedlerchr
Copy link
Member

Siedlerchr commented Mar 20, 2019

Hm this is odd. It worked fine for me with this line:
searchHandler.searchTextProperty().bindBidirectional(searchBox.textProperty());
Whenever I changed the text in the GUI field, e.g. key to asdfasd the view was updated and the new findings were highlighted.
Maybe I understand you wrong, but I think this is enough?

Under the hood the bidirectional is nothing else than a wrapper around the changeLIstener stuff.

@CaptainDaVinci
Copy link
Contributor

CaptainDaVinci commented Mar 20, 2019

Also, note that its necessary to have a reference to searchText property accessed under the ChangeListener for searchBox. Could this be related to some sort of premature garbage collection?

Edit: For me changing the text in the GUI field did not update the view or highlight the labels.

@Siedlerchr
Copy link
Member

Bindings are created using WeakListener, so they might get garbage collected. But I still don't understand why it works for me with the patch. I would propose you test again with my patch or at least commit the changes and let others test as well.
Unfortunately I am the next days busy at work and probably can't help much.

@CaptainDaVinci
Copy link
Contributor

CaptainDaVinci commented Mar 20, 2019

Okay, I have pushed changes, in the mean time I will try testing it again.

P.S: Since the PreferencesSearchHandler does not use the searchText property but only the query text, can we instead bind the searchBox to the filterTabs, i.e, not have to deal with binding the text property and string property?

searchBox.setPromptText(Localization.lang("Search"));

PreferencesSearchHandler searchHandler = new PreferencesSearchHandler(preferenceTabs);
tabsList.itemsProperty().bindBidirectional(searchHandler.filteredPreferenceTabsProperty());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if this is the reason for the problem, but it should suffice to replace the filteredPreferenceTabsProperty by an observable list (instead of an list property) and then use the bindContentsBidirectional method to bind tabsList.getItems() to this observable list.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, this did not work either. The problem is that searchHandler.searchText does not reflect the changes from the searchBox, unless an explicit listener is added to searchBox and searchHandler.searchText is simply accessed there.

searchBox.textProperty().addListener((o, p, n) -> {
    searchHandler.searchTextProperty();     // required, so that changed are reflected.
});


PreferencesSearchHandler searchHandler = new PreferencesSearchHandler(preferenceTabs);
tabsList.itemsProperty().bindBidirectional(searchHandler.filteredPreferenceTabsProperty());
searchHandler.searchTextProperty().bindBidirectional(searchBox.textProperty());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another try would be to pass the searchBox.textProperty() as the constructor argument and then add the listener directly (I think you had something similar before). I think both approaches are valid although it's strange that the current code does not work for you.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, that was the previous approach.
How about another approach where we add a listener on searchBox, which makes call to searchHandler.filterTabs directly, without the need of having StringProperty in between?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that sounds like the easiest solution. Please go ahead and make the corresponding changes. Thanks!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tobiasdiez I have implemented the required changes in the recent commit.

@tobiasdiez tobiasdiez merged commit ef5710c into JabRef:master Mar 27, 2019
@tobiasdiez
Copy link
Member

Thanks to both @WtfJoke and @CaptainDaVinci for joining forces!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: ready-for-review Pull Requests that are ready to be reviewed by the maintainers
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Make Show Preferences Window searchable
4 participants