-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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
Used late initialization for context menus #3340
Used late initialization for context menus #3340
Conversation
…upplier Updated checkstyle in gradle to 8.3 to be able to use {@link ..} in doc comments that refer to classes that would otherwise be "unused".
Nice work @halirutan Anytime your PRs are ready for review please add a 'ready-for-review' label. |
@stefan-kolb At the moment, I'm not sure I'm allowed to do this. |
@halirutan Oops, ok I thought you already have access 😄 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perfect!
@FXML private EditorTextArea textArea; | ||
@FXML private Button fetchInformationByIdentifierButton; | ||
@FXML private Button lookupIdentifierButton; | ||
@FXML |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Our convention is that these @FXML
tags should be kept on the same line (I think this is also configured in the intellj style)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's what IntelliJ did, therefore I thought it might be overlooked in the first place. I can change this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a fetish of @tobiasdiez :P For the sake of being consistent to what we have done before, please keep the @FXML
in the same line a the instance variable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* @return default context menu available for most text fields | ||
*/ | ||
public static Supplier<List<MenuItem>> getDefaultMenu(TextArea textArea) { | ||
return () -> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure what is more readable: Hiding the supplier interface here like you did or instead writing something like addToContextMenu(() -> getDefaultMenu(textArea))
. @JabRef/developers any opinions on this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I am in favor of the second solution, i.e. putting the supplier into EditorTextArea.addToContextMenu()
. Reasoning: With the current solution, the lazy initialization is dispersed over two classes. Changes are required in EditorTextArea
and EditorMenus
. If I understand everything correctly, we could build the supplier inside addToContextMenu()
only. That would be a very localized change that hides the lazy initialization as far as possible.
My perception might be wrong, though. Please correct me if this is the case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@FXML private EditorTextArea textArea; | ||
@FXML private Button fetchInformationByIdentifierButton; | ||
@FXML private Button lookupIdentifierButton; | ||
@FXML |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a fetish of @tobiasdiez :P For the sake of being consistent to what we have done before, please keep the @FXML
in the same line a the instance variable.
* @return default context menu available for most text fields | ||
*/ | ||
public static Supplier<List<MenuItem>> getDefaultMenu(TextArea textArea) { | ||
return () -> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I am in favor of the second solution, i.e. putting the supplier into EditorTextArea.addToContextMenu()
. Reasoning: With the current solution, the lazy initialization is dispersed over two classes. Changes are required in EditorTextArea
and EditorMenus
. If I understand everything correctly, we could build the supplier inside addToContextMenu()
only. That would be a very localized change that hides the lazy initialization as far as possible.
My perception might be wrong, though. Please correct me if this is the case.
TextAreaSkin customContextSkin = new TextAreaSkin(this) { | ||
@Override | ||
public void populateContextMenu(ContextMenu contextMenu) { | ||
super.populateContextMenu(contextMenu); | ||
contextMenu.getItems().addAll(0, items); | ||
contextMenu.getItems().addAll(0, items.get()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I understand everything correctly, we could build the supplier right here and still accept a List<MenuItem>
as method parameter. That would keep the changes very localized.
More discussion see below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, then I misunderstood the whole thing. Every text-field editor needs to attach its own context menu. Als long as I have wrapped it in a supplier, the code is not instantiated. So how is for instance IdentifierEditor
supposed to attach a non-instantiated context menu?
textArea.addToContextMenu(EditorMenus.getDefaultMenu(textArea));
Assume we don't do the wrapping inside EditorMenus
, then the menu would be instantiated exactly there. Except when I put the Supplier
wrapper at this place. But then we have the suppliers scattered over even more classes. What do I miss?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, Jörg, the supplier has to be built outside of this method since otherwise the context menu items are already created. With the help of a supplier, we are able to delay the creation until the user opens the context menu (since only then the get
method is called).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, then I was wrong. Thanks for clarifying! In that case, please disregard my comment and keep the solution.
@lenhard I wanted to comment on this
The keydown behavior is a good general indicator, but there are some drawbacks. The main issue with it is that it can be heavily misleading. Assume for a moment that we ignore everything else and look only at the impact of showing the entry editor. When we have fixed an issue like the one in this PR that does not only affect memory but performance as well, then the speed of creating the entry editor will improve. That directly impacts how many entries you can visit on holding the key down. Now assuming that we could speed up things by 50% but couldn't reduce the memory impact, then your memory monitor will make the impression if things had gone worse because it will fill the memory faster. That was the main reason why I reported both the memory and the performance separately under controlled circumstances (visiting exactly 50 entries). What we would need (maybe we already have this) are what we call model level functional tests in IDEA plugin development. So, for instance, a test that visits n entries and simulates a click or starts JabRef and performs a search. Those tests shouldn't be run by travis but they should be available for profiling to clearly pinpoint if we have a regression or a speedup. |
@halirutan You are right of course. We have some GUI tests in We also have a few performance tests in It would be good to have the tests you describe and, as usual, it depends on someone being willing to put the effort into. Most people (including myself) are a little shy when it comes to UI testing in JabRef, because the user interface has been heavily changed in the last year, meaning you have to re-write the tests all the time. If you are interested in doing something here, I would suggest you have a look at the current GUI tests, but if you want to use a better framework for building such tests, be my guest! A new minor release of JabRef is imminent. Since I definitely want to have this in, I'll merge it right now. It is complete as far as I can see (the other refactoring I proposed does not work, as we have discussed). Thank you for your contribution. |
@halirutan - Did you sign up for https://hacktoberfest.digitalocean.com/? |
@koppor I've seen it but I thought it was a JabRef internal thing. After all, many of the contributors are located in Germany and I thought it was a fun way of dedicating a month to pushing things forward. |
* upstream/master: (31 commits) Source tab entry duplication (#3360) Use CITE_COMMENT not only for external latex editors but also for cop… (#3351) Updating with new translations (#3348) Upgrade error-prone (#3350) Jabref_pt_BR partially updated (#3349) Used late initialization for context menus (#3340) Fix NPE when calling with bib file as cmd argument (#3343) update mockito-core from 2.10.0 -> 2.11.0 (#3338) Remove underscore in Localized messages (#3336) Localisation: French: new entries translated (#3337) Refactoring: Lazy init of all editor tabs (#3333) Initializing EntryEditor Tabs on focus (#3331) Fix #3292: annotations are now automatically refreshed (#3325) Change integrity message for names depending on database mode (#3330) Fix location bundle with fast access (#3327) Small code cleanup Fix "path not found" exception Small fix in drag and drop handler of linked files (#3328) Fix NPE in MainTable (#3318) Increase relative size of abstract field in editor (#3320) ...
* upstream/master: Rework AutoSetFileLinks (#3368) revert wrongly commited changes Refactorings (#3370) Fix freezing when running cleanup file operations like rename (#3315) This additional style setting for IDEA (#3355) Fix checkstyle Add proper equals to content selector Source tab entry duplication (#3360) Use CITE_COMMENT not only for external latex editors but also for cop… (#3351) Updating with new translations (#3348) Upgrade error-prone (#3350) Jabref_pt_BR partially updated (#3349) Delete unused code Extract difference finder from gui to logic Used late initialization for context menus (#3340) Remove unnecessary EntrySorter Move existing code to gui and rename change classes to view model Small code improvements
* upstream/master: (79 commits) Update richtext and flowless (#3386) Source tab: hide notification pane when code is correct again (#3387) Titles are optional at crossref (#3378) Update entry for every change in the source panel (#3366) Rework AutoSetFileLinks (#3368) revert wrongly commited changes Refactorings (#3370) Fix freezing when running cleanup file operations like rename (#3315) This additional style setting for IDEA (#3355) Fix checkstyle Add proper equals to content selector Source tab entry duplication (#3360) Use CITE_COMMENT not only for external latex editors but also for cop… (#3351) Updating with new translations (#3348) Upgrade error-prone (#3350) Jabref_pt_BR partially updated (#3349) Delete unused code Extract difference finder from gui to logic Used late initialization for context menus (#3340) Fix NPE when calling with bib file as cmd argument (#3343) ...
I believe I could bring down the performance impact of the context menus to a bare minimum. I reported this in #3335 and @tobiasdiez provided me with the hint how this could work. Against his suggestion to not overshoot, I decided to prove my point that even those small context menus have a significant impact because things will sum up in the end and those menus are newly instantiated for every visible field in the editor.
The starting point was the current master-branch and profiling it by going through only 50 bib-entries. This means that the context menus are instantiated for the visible text fields. This has an impact on performance and memory and, unfortunately, it is not only a tiny fraction.
Memory
Notable are the columns "Objects", which are all objects that are created by this method and underlying sub calls and the overall "Size".
With almost 40% of the overall memory size, it's definitely something to look into.
Performance
The performance is with 8% not so large but still noticeable.
Fixing it
By using the
Supplier
interface, we can move the instantiation to the point where the user actually right-clicks into the field. I debugged this, and it seems to work nice. The outcome was as expected. Since no one actually triggers the context menu by just browsing through the list, it vanished altogether. Here is the used memory with this PR created by exactly scrolling through the 50 entries. First the memory footprintand here the performance impact
In conclusion, this means as long as the user doesn't need a context menu, we have no memory or performance impact at all.
Note
I updated the
checkstyle
version in the Gradle built. I like to write comments, and now it doesn't prevent me any longer from using{@link ...}
in doc-comments to classes that are otherwise not used.gradle localizationUpdate
?