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

Convert SharedDatabaseConnect Dialog to Javafx #4040

Merged
merged 36 commits into from
Aug 31, 2018
Merged

Conversation

Siedlerchr
Copy link
Member

@Siedlerchr Siedlerchr commented May 20, 2018

Connection works so far. No more freezes regarding addTabs. in basePanel
Somehow the dialog looks odd, @tobiasdiez Any idea what is missing? The checkboxes are not visible correct. I just see that it looks really odd in he maintable-beta branch, too. e..g. int he Event Log

Edit// The conection and the synchronization seems to be working.

Fixes: #3419 PostgresSQL database connection now supports SSL

TODO for documentaition:
Create and configure Server certs
https://www.postgresql.org/docs/current/static/ssl-tcp.html

Convert to keystore format
https://jdbc.postgresql.org/documentation/head/ssl-client.html

grafik

Currently I only tested it with PostgresSQL, but I see that mySQL should also work
https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-using-ssl.html


TODO:

  • check conflict merge dialog

  • 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 Siedlerchr added shared-database status: ready-for-review Pull Requests that are ready to be reviewed by the maintainers labels May 20, 2018
@tobiasdiez
Copy link
Member

The display problem probably results from us playing around with different styles and changing defaults. Since there is no checkbox in the main view, it was not noticed that some of the input controls look strange. I'll have a look at it later...

* upstream/maintable-beta:
  update gradle to 4.7 (#4049)
  Add missing translation for "HTML to Unicode" (#4046)
  New Crowdin translations (#4042)
  Use all-text-fields magic also in BibTeX cleanup. (#4039)
  Shortittle bibtexkeypattern now also discards small words (#4030)
@Siedlerchr Siedlerchr changed the title [WIP] Convert SharedDatabaseConnect Dialog to Javafx Convert SharedDatabaseConnect Dialog to Javafx May 25, 2018
add migration help message
remove old dialogs
@Siedlerchr Siedlerchr changed the base branch from master to maintable-beta May 25, 2018 08:29
@Siedlerchr
Copy link
Member Author

Siedlerchr commented May 25, 2018

The database connection works so far. Tested with PostgresSQL. I reworked the dialog and fixed an error in the listener which led to freezes.
The MergeEntryDialog is not yet converted, this will be done in a future PR.

The only thing open is the GUI styling. The dialog looks a bit odd. But that's due to some missing CSS stuff I think.

@Siedlerchr Siedlerchr requested review from koppor and removed request for lenhard May 25, 2018 08:36
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.

In general the rework looks good. Thanks for the work!

It would be nice if you could move all the logic to the view model so that we have a nice separation of concerns. The other remarks are mostly minor.

<Label text="%Database Type:" />
<ComboBox fx:id="cmbDbType" prefHeight="25.0" prefWidth="606.0" GridPane.columnIndex="1" GridPane.columnSpan="2" />
<Label text="%Host/Port:" GridPane.rowIndex="1" />
<TextField fx:id="tbHost" GridPane.columnIndex="1" GridPane.rowIndex="1" />
Copy link
Member

Choose a reason for hiding this comment

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

I don't have a strong opinion on this, but this Hungarian notation is against the usual naming convention. Probably, host or hostTextField is preferable. @koppor what's your opinion about this?

this.frame = frame;
this.setTitle(Localization.lang("Connect to shared database"));

this.getDialogPane().getButtonTypes().addAll(connect, ButtonType.CANCEL);
Copy link
Member

Choose a reason for hiding this comment

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

It is preferable to set the buttons in the fxml

<ButtonType fx:id="copyVersionButton" text="%Copy Version" />
<ButtonType fx:constant="CLOSE" />

and then add the action in the code-behind
ControlHelper.setAction(copyVersionButton, getDialogPane(), event -> copyVersionToClipboard());

Copy link
Member Author

@Siedlerchr Siedlerchr May 25, 2018

Choose a reason for hiding this comment

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

Unfortunately this results in an NPE here for the connect butotn which I don't understand. The lookUpButton returns null.

Copy link
Member

Choose a reason for hiding this comment

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

Did you also tried it without the surrounding buttontypes tag?


}

private void openDatabase(ActionEvent e) {
Copy link
Member

Choose a reason for hiding this comment

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

This method and essentially everything below should be moved to the ViewModel. The view should contain no logic whatsoever and just binds the fxml file to the properties in the view model.

cmbDbType.getSelectionModel().select(0);
viewModel.selectedDbmstypeProperty().bind(cmbDbType.getSelectionModel().selectedItemProperty());

viewModel.selectedDbmstypeProperty().addListener((observable, oldValue, newValue) -> {
Copy link
Member

Choose a reason for hiding this comment

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

EasyBind.subscribe is usually easier to read. Moreover, this logic should also be moved to the view model.

FileDialogConfiguration fileDialogConfiguration = new FileDialogConfiguration.Builder()
.addExtensionFilter(FileType.BIBTEX_DB)
.withDefaultExtension(FileType.BIBTEX_DB)
.withInitialDirectory(Globals.prefs.get(JabRefPreferences.WORKING_DIRECTORY))
Copy link
Member

Choose a reason for hiding this comment

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

Please extract the Globals.prefs dependency. The new JavaFX stuff should no longer depend on Globals.

}

private void setLoadingConnectButtonText(boolean isLoading) {
btnConnect.setDisable(isLoading);
Copy link
Member

Choose a reason for hiding this comment

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

The viewModel should have a boolean property connectionInProgress so that the functionality of this method can be realized by binding.

private DBMSConnectionProperties connectionProperties;
private SharedDatabaseLoginDialogViewModel viewModel;

public SharedDatabaseLoginDialogView(JabRefFrame frame) {
Copy link
Member

Choose a reason for hiding this comment

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

I really don't like that we need a frame here. Can you please investigate if it can be replaced by the StateManager (maybe after extending the latter).

}

private void checkFields() throws JabRefException {
if (isEmptyField(tbHost)) {
Copy link
Member

Choose a reason for hiding this comment

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

Validation should be done using the validation framework so that the user get immediate feedback (have a look at the usage of ControlsFxVisualizer).

jabRefFrame.closeCurrentTab();
new SharedDatabaseLoginDialogView(jabRefFrame).showAndWait();

}
Copy link
Member

Choose a reason for hiding this comment

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

else if (and remove empty line above)


SwingUtilities.invokeLater(() -> panel.closeBottomPane());
dialogService.showInformationDialogAndWait(Localization.lang("Shared entry is no longer present"),
Localization.lang("The BibEntry you currently work on has been deleted on the shared side.")
Copy link
Member

Choose a reason for hiding this comment

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

BibEntry is for our internal usage and entry should be used for dialogs.

</header>
<buttonTypes>
<ButtonType fx:constant="CLOSE" />
<ButtonType fx:id="connectButton" text="Connect" />
Copy link
Member Author

Choose a reason for hiding this comment

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

Here I add the button

@FXML private TextField tbFolder;
@FXML private Button btnBrowse;
@FXML private CheckBox chkAutosave;
@FXML private ButtonType connectButton;
Copy link
Member Author

Choose a reason for hiding this comment

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

The buttonType is initalized here

.load()
.setAsContent(this.getDialogPane());

ControlHelper.setAction(connectButton, this.getDialogPane(), event -> openDatabase());
Copy link
Member Author

Choose a reason for hiding this comment

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

In this method the lookup method from the dialogPane returns null. I don't understand why.

Copy link
Member Author

Choose a reason for hiding this comment

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

Somehow the buttons are in the content property of the dialog pane. Does not make any sense to me

@Siedlerchr
Copy link
Member Author

Siedlerchr commented May 25, 2018 via email


ViewLoader.view(this)
.load()
.setAsContent(this.getDialogPane());
Copy link
Member

Choose a reason for hiding this comment

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

Should be .setAsDialogPane(this);

* upstream/master: (89 commits)
  Fix that sometimes an empty side pane is shown (#4105)
  Update gradle from 4.7 to 4.8 (#4102)
  Add gradle task downloadDependencies and use it at CircleCI (#4091)
  Set minimum java to 171 (#4095)
  Also use https in the CHANGELOG itself
  Add missing CHANGELOG entry
  Fix localiazation test
  Use official TempFolder extension for JUnit 5 tests
  Remove menu* from crowdin.yml (#4094)
  Merge recent changes to exporter/importer
  Add missing CHANGELOG entry
  New translations JabRef_en.properties (Vietnamese)
  New translations JabRef_en.properties (Dutch)
  New translations JabRef_en.properties (French)
  New translations JabRef_en.properties (German)
  New translations JabRef_en.properties (Greek)
  New translations JabRef_en.properties (Indonesian)
  New translations JabRef_en.properties (Italian)
  New translations JabRef_en.properties (Japanese)
  New translations JabRef_en.properties (Danish)
  ...

# Conflicts:
#	src/main/java/org/jabref/gui/shared/ConnectToSharedDatabaseDialog.java
renamings and other refactorings
* upstream/master: (129 commits)
  Fix Export to clipbaord action (#4286)
  Add minimal height for entry editor (#4283)
  Fix exceptions when trying to change settings (#4284)
  Added a comment for the purpose of the class (#4282)
  Fix NPE when importing from CLI (#4281)
  Fix display of key patterns
  convert bibtexkeypatterndlg to javafx as well (#4277)
  Style preference sections using css
  Fix a few style issues
  Changed the behavior of the field formatting dialog (#4275)
  Fix checkbox display
  Remove small font size
  Style side pane in preferences
  Wrap preference tabs in scrollpane
  Fix NPE with bibdatabasecontext in preview style dialog
  update xmlunit and log4j jul and checkstyle
  Update mysql driver to 8.0.12
  Rework preference dialog main class
  Move preferences stuff to gui.preferences
  Implement drag and drop for maintable (#3765)
  ...

# Conflicts:
#	src/main/java/org/jabref/gui/shared/ConnectToSharedDatabaseDialog.java
* upstream/master:
  Fix error prone warnings (#4290)
  Fix freeze on import into current library (#4299)
  Upgrade gradle to 4.10 update xmlunit and postgres
  update xmlunit-matchers from 2.6.0 -> 2.6.1
  update gradle build-scan from 1.15.2 -> 1.16
  checkstyle
  execute changes only if disk db present
  fix npe in Merge entries dialog
fix layoout
enable ssl stuff only when postgres is enabeld
shutdown listener stops the listener thread safely
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.

Since this already looks pretty good, I took the opportunity and reviewed the code again. Feel free to merge directly after fixing my comments.

});
});

viewModel.applyPreferences();
Copy link
Member

Choose a reason for hiding this comment

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

call this in the constructor of the view model

databaseType.valueProperty().bindBidirectional(viewModel.selectedDbmstypeProperty());

folder.textProperty().bindBidirectional(viewModel.folderProperty());
browseButton.disableProperty().bind(autosave.selectedProperty().not());
Copy link
Member

Choose a reason for hiding this comment

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

Bind to viewModel.autosaveProperty() (the view model controls the view).


fileKeystore.textProperty().bindBidirectional(viewModel.keyStoreProperty());

browseKeystore.disableProperty().bind(useSSL.selectedProperty().not());
Copy link
Member

Choose a reason for hiding this comment

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

here too

hostValidator = new FunctionBasedValidator<>(host, predicate, ValidationMessage.error(Localization.lang("Required field \"%0\" is empty.", Localization.lang("Port"))));
portValidator = new FunctionBasedValidator<>(port, predicate, ValidationMessage.error(Localization.lang("Required field \"%0\" is empty.", Localization.lang("Host"))));
userValidator = new FunctionBasedValidator<>(user, predicate, ValidationMessage.error(Localization.lang("Required field \"%0\" is empty.", Localization.lang("User"))));
folderValidator = new FunctionBasedValidator<>(folder, predicate, ValidationMessage.error(Localization.lang("Please enter a valid file path.")));
Copy link
Member

Choose a reason for hiding this comment

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

Really test that the files exists.

ButtonType.OK, openHelp);

result.filter(btn -> btn.equals(openHelp)).ifPresent(btn -> HelpAction.openHelpPage(HelpFile.SQL_DATABASE_MIGRATION));
result.filter(btn -> btn == ButtonType.OK).ifPresent(btn -> openSharedDatabase());
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 but equals might be necessary here.

this.connection = DriverManager.getConnection(
properties.getType().getUrl(properties.getHost(), properties.getPort(), properties.getDatabase()),
properties.getUser(), properties.getPassword());
Properties props = new Properties();
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 move these additions to the DBMSConnectionProperties class as two methods Properties asJavaProperties() and String getUrl.

&& this.host.equalsIgnoreCase(properties.getHost())
&& (this.port == properties.getPort())
&& this.database.equals(properties.getDatabase())
&& this.user.equals(properties.getUser());
Copy link
Member

Choose a reason for hiding this comment

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

add useSSL in equals and hash

@@ -89,7 +89,8 @@ public void startNotificationListener(DBMSSynchronizer dbmsSynchronizer) {
// Otherwise the listener is going to be deleted by GC.
PGConnection pgConnection = connection.unwrap(PGConnection.class);
listener = new PostgresSQLNotificationListener(dbmsSynchronizer, pgConnection);
listener.start();
new Thread(listener, "PostgresSQLNotificationListener").start();
Copy link
Member

Choose a reason for hiding this comment

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

Better reuse our threading infrastructure so that we are sure that the thread is shutdown on exit etc.


public PostgresSQLNotificationListener(DBMSSynchronizer dbmsSynchronizer, PGConnection pgConnection) {
this.dbmsSynchronizer = dbmsSynchronizer;
this.pgConnection = pgConnection;
}

public void start() {
stop = false;
new Thread(this).start();
Copy link
Member

Choose a reason for hiding this comment

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

same

@@ -71,6 +72,11 @@ public boolean getRememberPassword() {
return internalPrefs.getBoolean(SHARED_DATABASE_REMEMBER_PASSWORD, false);
}

public boolean isUseSSL()
{
Copy link
Member

Choose a reason for hiding this comment

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

code style

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants