Skip to content

Commit

Permalink
Fix issue #9306: Move "Open only one instance of JabRef" preference o…
Browse files Browse the repository at this point in the history
…ption to somewhere else (#10602)

* Fix issue #9306: Move "Open only one instance of JabRef" preference option to somewhere else

* edit issue#9306

* edit

* edit

* edit

* edit

* edit

* edit

* edit

* fix trustStoreManager NullPointerException

* use one action factory

---------

Co-authored-by: Siedlerchr <siedlerkiller@gmail.com>
  • Loading branch information
DiamondMyK and Siedlerchr committed Oct 30, 2023
1 parent df1f6e4 commit 1945a5a
Show file tree
Hide file tree
Showing 9 changed files with 136 additions and 109 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv

### Changed

- We move the location of the 'Open only one instance of JabRef' preference option from "Network" to "General" .[#9306](https://github.com/JabRef/jabref/issues/9306)
- The two previews in the change resolver dialog now have their scrollbars synchronized [#9576](https://github.com/JabRef/jabref/issues/9576).
- We changed the setting of the keyword separator to accept a single character only. [#177](https://github.com/koppor/jabref/issues/177)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.Hyperlink?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Spinner?>
<?import javafx.scene.control.TextField?>
Expand All @@ -13,7 +14,6 @@
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import org.jabref.gui.icon.JabRefIconView?>
<?import javafx.scene.control.Hyperlink?>
<fx:root spacing="10.0" type="VBox"
xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml"
fx:controller="org.jabref.gui.preferences.general.GeneralTab">
Expand Down Expand Up @@ -70,6 +70,13 @@
<CheckBox fx:id="confirmDelete" text="%Show confirmation dialog when deleting entries"/>
<CheckBox fx:id="collectTelemetry" text="%Collect and share telemetry data to help improve JabRef"/>

<Label styleClass="sectionHeader" text="%Single instance" />
<HBox alignment="CENTER_LEFT" spacing="10.0">
<CheckBox fx:id="remoteServer" text="%Enforce single JabRef instance (and allow remote operations) using port" />
<TextField fx:id="remotePort" maxWidth="100.0" HBox.hgrow="ALWAYS" />
<Button fx:id="remoteHelp" prefWidth="20.0" />
</HBox>

<Label styleClass="sectionHeader" text="%Libraries"/>
<GridPane hgap="10.0" vgap="4.0">
<columnConstraints>
Expand Down
16 changes: 15 additions & 1 deletion src/main/java/org/jabref/gui/preferences/general/GeneralTab.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,13 @@
import org.jabref.logic.l10n.Language;
import org.jabref.logic.l10n.Localization;
import org.jabref.model.database.BibDatabaseMode;
import org.jabref.model.entry.BibEntryTypesManager;
import org.jabref.model.util.FileUpdateMonitor;

import com.airhacks.afterburner.views.ViewLoader;
import com.tobiasdiez.easybind.EasyBind;
import de.saxsys.mvvmfx.utils.validation.visualization.ControlsFxVisualizer;
import jakarta.inject.Inject;

public class GeneralTab extends AbstractPreferenceTabView<GeneralTabViewModel> implements PreferencesTab {

Expand All @@ -49,6 +52,11 @@ public class GeneralTab extends AbstractPreferenceTabView<GeneralTabViewModel> i
@FXML private Button autosaveLocalLibrariesHelp;
@FXML private CheckBox createBackup;
@FXML private TextField backupDirectory;
@FXML private CheckBox remoteServer;
@FXML private TextField remotePort;
@FXML private Button remoteHelp;
@Inject private FileUpdateMonitor fileUpdateMonitor;
@Inject private BibEntryTypesManager entryTypesManager;

private final ControlsFxVisualizer validationVisualizer = new ControlsFxVisualizer();

Expand All @@ -74,7 +82,7 @@ public String getTabName() {
}

public void initialize() {
this.viewModel = new GeneralTabViewModel(dialogService, preferencesService);
this.viewModel = new GeneralTabViewModel(dialogService, preferencesService, fileUpdateMonitor, entryTypesManager);

new ViewModelListCellFactory<Language>()
.withText(Language::getDisplayName)
Expand Down Expand Up @@ -122,15 +130,21 @@ public void initialize() {
autosaveLocalLibraries.selectedProperty().bindBidirectional(viewModel.autosaveLocalLibrariesProperty());
ActionFactory actionFactory = new ActionFactory(preferencesService.getKeyBindingRepository());
actionFactory.configureIconButton(StandardActions.HELP, new HelpAction(HelpFile.AUTOSAVE, dialogService, preferencesService.getFilePreferences()), autosaveLocalLibrariesHelp);
actionFactory.configureIconButton(StandardActions.HELP, new HelpAction(HelpFile.REMOTE, dialogService, preferencesService.getFilePreferences()), remoteHelp);

createBackup.selectedProperty().bindBidirectional(viewModel.createBackupProperty());
backupDirectory.textProperty().bindBidirectional(viewModel.backupDirectoryProperty());
backupDirectory.disableProperty().bind(viewModel.createBackupProperty().not());

Platform.runLater(() -> {
validationVisualizer.initVisualization(viewModel.remotePortValidationStatus(), remotePort);
validationVisualizer.initVisualization(viewModel.fontSizeValidationStatus(), fontSize);
validationVisualizer.initVisualization(viewModel.customPathToThemeValidationStatus(), customThemePath);
});

remoteServer.selectedProperty().bindBidirectional(viewModel.remoteServerProperty());
remotePort.textProperty().bindBidirectional(viewModel.remotePortProperty());
remotePort.disableProperty().bind(remoteServer.selectedProperty().not());
}

@FXML
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ListProperty;
Expand All @@ -19,18 +20,26 @@
import javafx.scene.control.SpinnerValueFactory;

import org.jabref.gui.DialogService;
import org.jabref.gui.Globals;
import org.jabref.gui.desktop.JabRefDesktop;
import org.jabref.gui.preferences.PreferenceTabViewModel;
import org.jabref.gui.remote.CLIMessageHandler;
import org.jabref.gui.theme.Theme;
import org.jabref.gui.theme.ThemeTypes;
import org.jabref.gui.util.DirectoryDialogConfiguration;
import org.jabref.gui.util.FileDialogConfiguration;
import org.jabref.logic.l10n.Language;
import org.jabref.logic.l10n.Localization;
import org.jabref.logic.net.ssl.TrustStoreManager;
import org.jabref.logic.remote.RemotePreferences;
import org.jabref.logic.remote.RemoteUtil;
import org.jabref.logic.util.StandardFileType;
import org.jabref.model.database.BibDatabaseMode;
import org.jabref.model.entry.BibEntryTypesManager;
import org.jabref.model.strings.StringUtil;
import org.jabref.model.util.FileUpdateMonitor;
import org.jabref.preferences.FilePreferences;
import org.jabref.preferences.InternalPreferences;
import org.jabref.preferences.LibraryPreferences;
import org.jabref.preferences.PreferencesService;
import org.jabref.preferences.TelemetryPreferences;
Expand Down Expand Up @@ -81,19 +90,33 @@ public class GeneralTabViewModel implements PreferenceTabViewModel {
private final TelemetryPreferences telemetryPreferences;
private final LibraryPreferences libraryPreferences;
private final FilePreferences filePreferences;
private final RemotePreferences remotePreferences;

private final Validator fontSizeValidator;
private final Validator customPathToThemeValidator;

private final List<String> restartWarning = new ArrayList<>();

public GeneralTabViewModel(DialogService dialogService, PreferencesService preferences) {
private final BooleanProperty remoteServerProperty = new SimpleBooleanProperty();
private final StringProperty remotePortProperty = new SimpleStringProperty("");
private final Validator remotePortValidator;
private final InternalPreferences internalPreferences;
private final BooleanProperty versionCheckProperty = new SimpleBooleanProperty();
private final FileUpdateMonitor fileUpdateMonitor;
private final BibEntryTypesManager entryTypesManager;
private TrustStoreManager trustStoreManager;

public GeneralTabViewModel(DialogService dialogService, PreferencesService preferences, FileUpdateMonitor fileUpdateMonitor, BibEntryTypesManager entryTypesManager) {
this.dialogService = dialogService;
this.preferences = preferences;
this.workspacePreferences = preferences.getWorkspacePreferences();
this.telemetryPreferences = preferences.getTelemetryPreferences();
this.libraryPreferences = preferences.getLibraryPreferences();
this.filePreferences = preferences.getFilePreferences();
this.remotePreferences = preferences.getRemotePreferences();
this.internalPreferences = preferences.getInternalPreferences();
this.fileUpdateMonitor = fileUpdateMonitor;
this.entryTypesManager = entryTypesManager;
this.trustStoreManager = trustStoreManager;

fontSizeValidator = new FunctionBasedValidator<>(
fontSizeProperty,
Expand All @@ -116,6 +139,27 @@ public GeneralTabViewModel(DialogService dialogService, PreferencesService prefe
Localization.lang("General"),
Localization.lang("Visual theme"),
Localization.lang("Please specify a css theme file."))));

remotePortValidator = new FunctionBasedValidator<>(
remotePortProperty,
input -> {
try {
int portNumber = Integer.parseInt(remotePortProperty().getValue());
return RemoteUtil.isUserPort(portNumber);
} catch (NumberFormatException ex) {
return false;
}
},
ValidationMessage.error(String.format("%s > %s %n %n %s",
Localization.lang("Network"),
Localization.lang("Remote operation"),
Localization.lang("You must enter an integer value in the interval 1025-65535"))));

this.trustStoreManager = new TrustStoreManager(Path.of(preferences.getSSLPreferences().getTruststorePath()));
}

public ValidationStatus remotePortValidationStatus() {
return remotePortValidator.getValidationStatus();
}

@Override
Expand All @@ -125,8 +169,10 @@ public void setValues() {
// The light theme is in fact the absence of any theme modifying 'base.css'. Another embedded theme like
// 'dark.css', stored in the classpath, can be introduced in {@link org.jabref.gui.theme.Theme}.
switch (workspacePreferences.getTheme().getType()) {
case DEFAULT -> selectedThemeProperty.setValue(ThemeTypes.LIGHT);
case EMBEDDED -> selectedThemeProperty.setValue(ThemeTypes.DARK);
case DEFAULT ->
selectedThemeProperty.setValue(ThemeTypes.LIGHT);
case EMBEDDED ->
selectedThemeProperty.setValue(ThemeTypes.DARK);
case CUSTOM -> {
selectedThemeProperty.setValue(ThemeTypes.CUSTOM);
customPathToThemeProperty.setValue(workspacePreferences.getTheme().getName());
Expand All @@ -151,6 +197,9 @@ public void setValues() {

createBackupProperty.setValue(filePreferences.shouldCreateBackup());
backupDirectoryProperty.setValue(filePreferences.getBackupDirectory().toString());

remoteServerProperty.setValue(remotePreferences.useRemoteServer());
remotePortProperty.setValue(String.valueOf(remotePreferences.getPort()));
}

@Override
Expand Down Expand Up @@ -185,6 +234,38 @@ public void storeSettings() {

filePreferences.createBackupProperty().setValue(createBackupProperty.getValue());
filePreferences.backupDirectoryProperty().setValue(Path.of(backupDirectoryProperty.getValue()));

getPortAsInt(remotePortProperty.getValue()).ifPresent(newPort -> {
if (remotePreferences.isDifferentPort(newPort)) {
remotePreferences.setPort(newPort);
}
});

internalPreferences.setVersionCheckEnabled(versionCheckProperty.getValue());

getPortAsInt(remotePortProperty.getValue()).ifPresent(newPort -> {
if (remotePreferences.isDifferentPort(newPort)) {
remotePreferences.setPort(newPort);
}
});

if (remoteServerProperty.getValue()) {
remotePreferences.setUseRemoteServer(true);
Globals.REMOTE_LISTENER.openAndStart(new CLIMessageHandler(preferences, fileUpdateMonitor, entryTypesManager), remotePreferences.getPort());
} else {
remotePreferences.setUseRemoteServer(false);
Globals.REMOTE_LISTENER.stop();
}
trustStoreManager.flush();

if (remoteServerProperty.getValue()) {
remotePreferences.setUseRemoteServer(true);
Globals.REMOTE_LISTENER.openAndStart(new CLIMessageHandler(preferences, fileUpdateMonitor, entryTypesManager), remotePreferences.getPort());
} else {
remotePreferences.setUseRemoteServer(false);
Globals.REMOTE_LISTENER.stop();
}
trustStoreManager.flush();
}

public ValidationStatus fontSizeValidationStatus() {
Expand All @@ -199,6 +280,10 @@ public ValidationStatus customPathToThemeValidationStatus() {
public boolean validateSettings() {
CompositeValidator validator = new CompositeValidator();

if (remoteServerProperty.getValue()) {
validator.addValidators(remotePortValidator);
}

if (fontOverrideProperty.getValue()) {
validator.addValidators(fontSizeValidator);
}
Expand Down Expand Up @@ -310,6 +395,14 @@ public void backupFileDirBrowse() {
.ifPresent(dir -> backupDirectoryProperty.setValue(dir.toString()));
}

public BooleanProperty remoteServerProperty() {
return remoteServerProperty;
}

public StringProperty remotePortProperty() {
return remotePortProperty;
}

public void openBrowser() {
String url = "https://themes.jabref.org";
try {
Expand All @@ -318,4 +411,12 @@ public void openBrowser() {
dialogService.showErrorDialogAndWait(Localization.lang("Could not open website."), e);
}
}

private Optional<Integer> getPortAsInt(String value) {
try {
return Optional.of(Integer.parseInt(value));
} catch (NumberFormatException ex) {
return Optional.empty();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<?import org.jabref.gui.icon.JabRefIconView?>
Expand All @@ -19,13 +18,6 @@
<Label styleClass="titleHeader" text="%Network" />
<CheckBox fx:id="versionCheck" text="%Check for latest version online"/>
<Label text="%If you encounter an issue or a bug, please check the latest version, whether the issue is still present." wrapText="true"/>
<Label styleClass="sectionHeader" text="%Remote operation" />
<Label fx:id="remoteLabel" text="%This feature lets new files be opened or imported into an already running instance of JabRef instead of opening a new instance. For instance, this is useful when you open a file in JabRef from your web browser. Note that this will prevent you from running more than one instance of JabRef at a time." textOverrun="CLIP" wrapText="true" />
<HBox alignment="CENTER_LEFT" spacing="10.0">
<CheckBox fx:id="remoteServer" text="%Listen for remote operation on port" />
<TextField fx:id="remotePort" maxWidth="100.0" HBox.hgrow="ALWAYS" />
<Button fx:id="remoteHelp" prefWidth="20.0" />
</HBox>

<Label styleClass="sectionHeader" text="%Proxy configuration" />
<GridPane hgap="10.0" vgap="10.0">
Expand Down
27 changes: 1 addition & 26 deletions src/main/java/org/jabref/gui/preferences/network/NetworkTab.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,33 +17,20 @@
import javafx.scene.control.Tooltip;
import javafx.scene.input.MouseEvent;

import org.jabref.gui.Globals;
import org.jabref.gui.actions.ActionFactory;
import org.jabref.gui.actions.StandardActions;
import org.jabref.gui.help.HelpAction;
import org.jabref.gui.icon.IconTheme;
import org.jabref.gui.preferences.AbstractPreferenceTabView;
import org.jabref.gui.preferences.PreferencesTab;
import org.jabref.gui.util.IconValidationDecorator;
import org.jabref.gui.util.ValueTableCellFactory;
import org.jabref.logic.help.HelpFile;
import org.jabref.logic.l10n.Localization;
import org.jabref.model.entry.BibEntryTypesManager;
import org.jabref.model.util.FileUpdateMonitor;

import com.airhacks.afterburner.views.ViewLoader;
import com.tobiasdiez.easybind.EasyBind;
import de.saxsys.mvvmfx.utils.validation.visualization.ControlsFxVisualizer;
import jakarta.inject.Inject;
import org.controlsfx.control.textfield.CustomPasswordField;

public class NetworkTab extends AbstractPreferenceTabView<NetworkTabViewModel> implements PreferencesTab {
@FXML private Label remoteLabel;
@FXML private CheckBox versionCheck;
@FXML private CheckBox remoteServer;
@FXML private TextField remotePort;
@FXML private Button remoteHelp;

@FXML private CheckBox proxyUse;
@FXML private Label proxyHostnameLabel;
@FXML private TextField proxyHostname;
Expand All @@ -67,9 +54,6 @@ public class NetworkTab extends AbstractPreferenceTabView<NetworkTabViewModel> i
@FXML private TableColumn<CustomCertificateViewModel, String> certVersion;
@FXML private TableColumn<CustomCertificateViewModel, String> actionsColumn;

@Inject private FileUpdateMonitor fileUpdateMonitor;
@Inject private BibEntryTypesManager entryTypesManager;

private String proxyPasswordText = "";
private int proxyPasswordCaretPosition = 0;

Expand All @@ -87,15 +71,10 @@ public String getTabName() {
}

public void initialize() {
this.viewModel = new NetworkTabViewModel(dialogService, preferencesService, fileUpdateMonitor, entryTypesManager);
this.viewModel = new NetworkTabViewModel(dialogService, preferencesService);

versionCheck.selectedProperty().bindBidirectional(viewModel.versionCheckProperty());

remoteLabel.setVisible(preferencesService.getWorkspacePreferences().shouldShowAdvancedHints());
remoteServer.selectedProperty().bindBidirectional(viewModel.remoteServerProperty());
remotePort.textProperty().bindBidirectional(viewModel.remotePortProperty());
remotePort.disableProperty().bind(remoteServer.selectedProperty().not());

proxyUse.selectedProperty().bindBidirectional(viewModel.proxyUseProperty());
proxyHostnameLabel.disableProperty().bind(proxyUse.selectedProperty().not());
proxyHostname.textProperty().bindBidirectional(viewModel.proxyHostnameProperty());
Expand Down Expand Up @@ -129,12 +108,8 @@ public void initialize() {
proxyPassword.getRight().addEventFilter(MouseEvent.MOUSE_RELEASED, this::proxyPasswordMask);
proxyPassword.getRight().addEventFilter(MouseEvent.MOUSE_EXITED, this::proxyPasswordMask);

ActionFactory actionFactory = new ActionFactory(Globals.getKeyPrefs());
actionFactory.configureIconButton(StandardActions.HELP, new HelpAction(HelpFile.REMOTE, dialogService, preferencesService.getFilePreferences()), remoteHelp);

validationVisualizer.setDecoration(new IconValidationDecorator());
Platform.runLater(() -> {
validationVisualizer.initVisualization(viewModel.remotePortValidationStatus(), remotePort);
validationVisualizer.initVisualization(viewModel.proxyHostnameValidationStatus(), proxyHostname);
validationVisualizer.initVisualization(viewModel.proxyPortValidationStatus(), proxyPort);
validationVisualizer.initVisualization(viewModel.proxyUsernameValidationStatus(), proxyUsername);
Expand Down
Loading

0 comments on commit 1945a5a

Please sign in to comment.