-
-
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
Fix Part of Issue#3861: Edit->Replace String #4227
Conversation
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.
Thanks again for your contribution!
Generally it goes in the right direction, but some minor improvements and it's good from my point of view.
private BasePanel basePanel; | ||
|
||
public ReplaceStringAction(BasePanel bPanel) { | ||
this.basePanel = bPanel; |
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.
Typically you name the parameter also basePanel as the field and use this to distinguish the field from the parameter.
e.g. this.baesPanel = basePanel
|
||
<DialogPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="339.0" prefWidth="476.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="org.jabref.gui.ReplaceStringView" fx:id="pane"> | ||
<content> | ||
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="376.0" prefWidth="552.0"> |
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.
You better should use a GridPane here for positioning the label and the text fields, that allows them to be properly aligned. Can be easily done using the Scence Builder.
You can also take a look at the FXML here from my other PR #4040 for the db login dialog:
https://github.com/JabRef/jabref/pull/4040/files#diff-200f60f39aab2550ae174ea88d604981
@FXML | ||
public void initialize() { | ||
visualizer.setDecoration(new IconValidationDecorator()); | ||
LimitFieldInput.setEditable(true); |
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.
They should already be editable by default.
counter += replaceField(be, s, ce); | ||
} | ||
} else { | ||
for (String fld : fieldStrings) { |
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.
String field : fieldStrings
public int replaceItem(BibEntry be, NamedCompound ce) { | ||
int counter = 0; | ||
if (this.AllFieldReplace) { | ||
for (String s : be.getFieldNames()) { |
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.
Named Compound ce -> NamedCompound compound
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.
And String string : be.getFieldNames...
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.
even better: String fieldName : ...
int ind; | ||
int piv = 0; | ||
int counter = 0; | ||
int len1 = this.findString.length(); |
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.
maybe better findStringLength to directly make clear what the variable represent
I am sorry for the bad naming fields, and Thank you for your advice, I will fix them later. |
@marisuki you don't have to be sorry or take it personally ;) We really much appreciate your contribution |
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.
Thanks for your contribution. In general, the code looks good but I've some (more or less) minor remarks.
Please also remove the old swing dialog (and make sure it is no longer used).
@@ -598,6 +598,7 @@ private Node createToolbar() { | |||
factory.createIconButton(StandardActions.CUT, new OldDatabaseCommandWrapper(Actions.CUT, this, Globals.stateManager)), | |||
factory.createIconButton(StandardActions.COPY, new OldDatabaseCommandWrapper(Actions.COPY, this, Globals.stateManager)), | |||
factory.createIconButton(StandardActions.PASTE, new OldDatabaseCommandWrapper(Actions.PASTE, this, Globals.stateManager)), | |||
factory.createIconButton(StandardActions.REPLACE_ALL, new ReplaceStringAction(this.getCurrentBasePanel())), |
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 adds the action to the toolbar. I don't think that "replace all" is important enough to appear there. Please remove it again.
@Override | ||
public void execute() { | ||
BibDatabase database = basePanel.getDatabase(); | ||
ReplaceStringView rsc = new ReplaceStringView(database, basePanel); |
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.
Please don't use abbreviations in names etc. dialog
is better.
public void execute() { | ||
BibDatabase database = basePanel.getDatabase(); | ||
ReplaceStringView rsc = new ReplaceStringView(database, basePanel); | ||
rsc.showAndWait().filter(response -> rsc.isExit()); |
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 there is no need for the filter
command.
public class ReplaceStringView extends BaseDialog<Void> | ||
{ | ||
|
||
@FXML public ToggleGroup RadioGroup; |
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.
we usual follow camel casing, i.e it should be radioGroup
. Please also try to give these fields a more descriptive name (like you did below). Also please make these fields private.
.setAsDialogPane(this); | ||
|
||
st = (Stage) this.pane.getScene().getWindow(); | ||
st.setOnCloseRequest(event -> st.close()); |
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.
Normally there is no need for handling the close request in a special way. The problem is that you didn't defined a Cancel/Accept button in the dialog. Have a look at the keybindings dialog on how to handle this correctly:
jabref/src/main/java/org/jabref/gui/keyboard/KeyBindingsDialog.fxml
Lines 24 to 26 in d5d67d7
<ButtonType fx:id="resetButton" text="%Reset Bindings" buttonData="LEFT"/> | |
<ButtonType fx:id="saveButton" text="%Save" buttonData="OK_DONE"/> | |
<ButtonType fx:constant="CANCEL"/> |
ControlHelper.setAction(resetButton, getDialogPane(), event -> setDefaultBindings()); | |
ControlHelper.setAction(saveButton, getDialogPane(), event -> saveKeyBindingsAndCloseDialog()); |
} | ||
|
||
/** | ||
* FXML Message handler |
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 need to state the obvious in a comment (the method already has a @FXML
decoration).
* FXML Message handler | ||
*/ | ||
@FXML | ||
public void buttonReplace() { |
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.
In the Model-View-ViewModel spirit, the view should never contain any logic. The complete logic should be contained in the ViewModel
. The rationale behind this is, that you can test logic in the view model using ordinary (junit) tests without the need to instantiate the ui. Thus, please introduce a new ReplaceStringViewModel
and bind its values against the textfields. See, for example,
@FXML | |
private void saveKeyBindingsAndCloseDialog() { | |
viewModel.saveKeyBindings(); | |
closeDialog(); | |
} |
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 applies also to all other methods below that contain logic.
return this.exitSignal; | ||
} | ||
|
||
/** |
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.
The comments were helpful for the review. Thanks! But they should be removed in the final version.
public int replaceItem(BibEntry be, NamedCompound ce) { | ||
int counter = 0; | ||
if (this.AllFieldReplace) { | ||
for (String s : be.getFieldNames()) { |
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.
even better: String fieldName : ...
Thank you for all the advice above :), and I changed the dialog based on GridPane also the "ViewModel", and modified the miss using of field names, finally deleted the ReplaceStringDialog.java, which is about the old style logic: Swing. I hope it would be better. :) |
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.
Thanks for the quick follow-up. It clearly moves in the right direction. It would be nice if you could also change the structure to follow the usual MVVM pattern (see below for details).
stage.close(); | ||
return; | ||
} | ||
ReplaceStringViewModel viewModel = new ReplaceStringViewModel(panel, fieldStrings, findString, replaceString, selOnly, allFieldReplace); |
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 works because the dialog is very simple, but goes against the usual strategy of JavaFX / MVVM. You should add properties in the ViewModel class and bind these properties to the corresponding properties of the controls. Please have a look at the other JavaFX dialogs to see how this is done.
Since this approach is a bit different from what you are used to in the Swing world, let me quickly explain the big overall picture and its advantages. You are probably used to program against the UI controls (as you do here right now): for example, if you want to know the input from the user, you use textbox.getText()
to get it. Similarly, for other input controls. This works all nicely until the user reports a bug and you have to write a test for it. The problem you then face is the following: how do I automate the user interaction in my test? There are different approaches to this issue but the general answer is: there is no good solution ;-) UI automation is usually ugly and breaks as soon as you change the design. The idea behind the MVVM approach is that you completely separate the UI from the logic that performs the action. So you create a class (the ViewModel) that holds the state of the UI (i.e. you have string
field that corresponds to the user input, but at this point you don't care how or where this string is manipulated). This state in the ViewModel is then bound to the actual userinterface in the View
class using JavaFX bindings. In this way, you can test the ViewModel, i.e. the complete logic, without ever knowing how the user interface looks like.
} | ||
ReplaceStringViewModel viewModel = new ReplaceStringViewModel(panel, fieldStrings, findString, replaceString, selOnly, allFieldReplace); | ||
viewModel.replace(); | ||
stage.close(); |
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.
As BaseDialog
derives from Dialog
you can simply use close()
(without the reference to the stage).
Thank you for your comment ! :) @tobiasdiez , this time I changed the initial part of "view" and add the property bindings to make it a little more MVVM pattern alike ;-). I hope it would be better. |
return selectOnlyProperty; | ||
} | ||
|
||
public StringProperty getFieldStringProperty() { |
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.
Properties in javafx don't have the traditional get/set prefix. So just rename them as the ones abvove,
e.g. fieldStringProperty and findStringProperty etc
|
||
final NamedCompound compound = new NamedCompound(Localization.lang("Replace string")); | ||
int counter = 0; | ||
if (this.panel == null) |
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.
Is this check necessary? You always pass the basePanel as constructor argument.
I would suggest you add an Objects.requireNonNull(basePanel) in the constructor to ensure that the argument is never null. If it is null, it will directly throw and exception which makes it easier to see the real reason,
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.
Yes, you are right :), I forgot to check my logic after converting to a viewModel ;-). Thank You!
From my point of view this looks good. Just some minor code improvements. Let's see what @tobiasdiez thinks about it |
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.
Looks good to me! Thanks again for the quick follow-ups.
I removed the changelog entries since we will probably only add one big statement announcing that the ui and many dialogs where redesigned. Please resolve the conflicts and then we will merge.
I don't know why, but apparently you still have a conflict in the ReplaceStringDialog |
Yeah, I tried every means to avoid the conflict ;-), but it does not work (caused by delete a file) . Does this conflict be inevitable ;-)? Or, do you have any idea to solve it? Thank you. |
Okay, I tried around and found a solution: |
Something like the following should work: git pull upstream master (replace "upstream" by whatever you named the JabRef rep)
> git warns about merge conflict
git mergetool
> accept deletion of file
git commit
git push |
Thank you, I will give it a try! :) |
I think it works! :) this time I use "git pull git@github.com:jabref/jabref.git master" to merge and then remove and push again, there becomes no conflicts :). Thank you! But there shows a failure on build process, need I do something? (Since I did not change the related files.) |
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.
In general lgtm, you just need to fix the l10n and it should be fine
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES"/> | ||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES"/> | ||
</rowConstraints> | ||
<Label text="Find and Replace"/> |
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.
You need to add a % sign in front of the label text, so that it will be recognized as translatable string.
That is probably one of the reasons why the l10n test fails
The Travis CI failed, because of the localiation test. If you click on the Traivs Details and then expand the railed build jpb, you will see the reason. In this case you need to add the missing/remove the obsolete ones from the file. But first you have to add a % sign in front of every translatable label text |
Finally! I updated the properties in resources and make the "text" value linked with the file: Jabref_en.properties, also, I deleted the unused key-values (may generated from the previous replace string dialog) to make no obsolete item in the file. And thank you again for your help! :) @Siedlerchr @tobiasdiez |
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES"/> | ||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES"/> | ||
</rowConstraints> | ||
<Label text="Find and Replace"/> |
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 you missed this one ;) But all others look good
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.
Yeah ;-) I miss it. Thank you for mention! :)
Thank you very much for your contribution! I think you just forgot one little string, if you add this again, then we can finally merge! |
As the faling test on Travis CI is not related to your changes I am going to merge it now. |
Thank you! :-) |
We have to thank for your contribution! 👍 That's a good start. I hope you are interested in contributing some more ;) |
Hi, we fixed part of the Issue#3861, change the Swing Dialog to the JavaFx Dialog: the Edit -> Replace String Dialog, we add 3 files and modified the general control to link the Replace String controller of JavaFX Dialog, and we did not delete the old dialog logic (ReplaceStringDialog.java). The outlook of Dialog hasn't change a lot, and the previous logic is inherited.
The Screenshot is pasted below, just like the design before.