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

[WIP] UI consistency polish #5737

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
77 changes: 50 additions & 27 deletions src/main/java/org/jabref/gui/metadata/BibtexStringEditorDialog.fxml
Expand Up @@ -7,31 +7,54 @@
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<DialogPane minHeight="-Infinity" minWidth="-Infinity" prefHeight="340.0" prefWidth="427.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.jabref.gui.metadata.BibtexStringEditorDialogView">
<content>
<VBox>
<children>
<TableView fx:id="tblStrings" prefHeight="250.0">
<columns>
<TableColumn fx:id="colLabel" prefWidth="75.0" text="%Label" />
<TableColumn fx:id="colContent" prefWidth="75.0" text="%Content" />
</columns>
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
</columnResizePolicy>
</TableView>
<HBox minWidth="-Infinity" prefHeight="100.0" prefWidth="300.0">
<children>
<Button fx:id="btnNewString" minWidth="-Infinity" mnemonicParsing="false" onAction="#addString" text="%Add new String" HBox.hgrow="ALWAYS" />
<Button fx:id="btnRemove" mnemonicParsing="false" onAction="#removeString" text="%Remove selected Strings" HBox.hgrow="ALWAYS" />
<Button fx:id="btnHelp" mnemonicParsing="false" onAction="#openHelp" HBox.hgrow="ALWAYS" />
</children>
</HBox>
</children>
</VBox>
</content>
<buttonTypes>
<ButtonType fx:constant="CANCEL" />
<ButtonType fx:id="saveButton" buttonData="OK_DONE" text="%Save" />
</buttonTypes>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.control.Tooltip?>
<?import org.jabref.gui.icon.JabRefIconView?>

<DialogPane minHeight="-Infinity" minWidth="-Infinity" prefHeight="350.0" prefWidth="450.0"
xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="org.jabref.gui.metadata.BibtexStringEditorDialogView">
<content>
<HBox spacing="4.0">
<VBox spacing="4.0" HBox.hgrow="ALWAYS">
<TableView fx:id="stringsList">
<columns>
<TableColumn fx:id="labelColumn" minWidth="75.0" text="%Label"/>
<TableColumn fx:id="contentColumn" minWidth="75.0" text="%Content"/>
<TableColumn fx:id="actionsColumn" maxWidth="30.0" minWidth="30.0" prefWidth="30.0"
editable="false" resizable="false" reorderable="false"/>
</columns>
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY"/>
</columnResizePolicy>
</TableView>
<HBox spacing="4.0">
<TextField fx:id="addStringLabel" promptText="%Label" HBox.hgrow="ALWAYS"/>
<TextField fx:id="addStringContent" promptText="%Content" HBox.hgrow="ALWAYS"/>
</HBox>
</VBox>
<VBox>
<Button styleClass="icon-button,narrow" onAction="#openHelp">
<graphic>
<JabRefIconView glyph="HELP"/>
</graphic>
<tooltip>
<Tooltip text="%Open Help page"/>
</tooltip>
</Button>
<VBox VBox.vgrow="ALWAYS"/>
<Button styleClass="icon-button,narrow" fx:id="addStringButton" minWidth="-Infinity"
onAction="#addString">
<graphic>
<JabRefIconView glyph="ADD_NOBOX"/>
</graphic>
<tooltip>
<Tooltip text="%Add new String"/>
</tooltip>
</Button>
</VBox>
</HBox>
</content>
<ButtonType fx:constant="CANCEL"/>
<ButtonType fx:id="saveButton" buttonData="OK_DONE" text="%Save"/>
</DialogPane>
Expand Up @@ -2,20 +2,23 @@

import javax.inject.Inject;

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellEditEvent;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.util.converter.DefaultStringConverter;

import org.jabref.gui.DialogService;
import org.jabref.gui.icon.IconTheme.JabRefIcons;
import org.jabref.gui.icon.IconTheme;
import org.jabref.gui.util.BaseDialog;
import org.jabref.gui.util.IconValidationDecorator;
import org.jabref.gui.util.ValueTableCellFactory;
import org.jabref.gui.util.ViewModelTextFieldTableCellVisualizationFactory;
import org.jabref.logic.l10n.Localization;
import org.jabref.model.database.BibDatabase;
Expand All @@ -25,26 +28,26 @@

public class BibtexStringEditorDialogView extends BaseDialog<Void> {

@FXML private Button btnNewString;
@FXML private Button btnRemove;
@FXML private Button btnHelp;
@FXML private TableView<BibtexStringEditorItemModel> stringsList;
@FXML private TableColumn<BibtexStringEditorItemModel, String> labelColumn;
@FXML private TableColumn<BibtexStringEditorItemModel, String> contentColumn;
@FXML private TableColumn<BibtexStringEditorItemModel, String> actionsColumn;
@FXML private TextField addStringLabel;
@FXML private TextField addStringContent;
@FXML private Button addStringButton;
@FXML private ButtonType saveButton;

@FXML private TableView<BibtexStringViewModel> tblStrings;
@FXML private TableColumn<BibtexStringViewModel, String> colLabel;
@FXML private TableColumn<BibtexStringViewModel, String> colContent;

private final ControlsFxVisualizer visualizer = new ControlsFxVisualizer();
private final BibtexStringEditorDialogViewModel viewModel;

@Inject private DialogService dialogService;

public BibtexStringEditorDialogView(BibDatabase database) {
viewModel = new BibtexStringEditorDialogViewModel(database);
this.viewModel = new BibtexStringEditorDialogViewModel(database);

ViewLoader.view(this)
.load()
.setAsDialogPane(this);
.load()
.setAsDialogPane(this);

Button btnSave = (Button) this.getDialogPane().lookupButton(saveButton);

Expand All @@ -64,51 +67,72 @@ public BibtexStringEditorDialogView(BibDatabase database) {
private void initialize() {
visualizer.setDecoration(new IconValidationDecorator());

btnHelp.setGraphic(JabRefIcons.HELP.getGraphicNode());
btnHelp.setTooltip(new Tooltip(Localization.lang("Open Help page")));

btnNewString.setTooltip(new Tooltip(Localization.lang("New string")));
btnRemove.setTooltip(new Tooltip(Localization.lang("Remove selected strings")));

colLabel.setCellValueFactory(cellData -> cellData.getValue().labelProperty());
new ViewModelTextFieldTableCellVisualizationFactory<BibtexStringViewModel, String>().withValidation(BibtexStringViewModel::labelValidation, visualizer).install(colLabel, new DefaultStringConverter());

colContent.setCellValueFactory(cellData -> cellData.getValue().contentProperty());
new ViewModelTextFieldTableCellVisualizationFactory<BibtexStringViewModel, String>().withValidation(BibtexStringViewModel::contentValidation, visualizer).install(colContent, new DefaultStringConverter());

colLabel.setOnEditCommit((CellEditEvent<BibtexStringViewModel, String> cell) -> {
addStringButton.setTooltip(new Tooltip(Localization.lang("New string")));

labelColumn.setSortable(true);
labelColumn.setReorderable(false);
labelColumn.setCellValueFactory(cellData -> cellData.getValue().labelProperty());
new ViewModelTextFieldTableCellVisualizationFactory<BibtexStringEditorItemModel, String>()
.withValidation(BibtexStringEditorItemModel::labelValidation, visualizer)
.install(labelColumn, new DefaultStringConverter());
labelColumn.setOnEditCommit((CellEditEvent<BibtexStringEditorItemModel, String> cell) -> {
String newLabelValue = cell.getNewValue();
if (cell.getTableView().getItems().stream().anyMatch(strs -> strs.labelProperty().get().equals(newLabelValue))) {

if (viewModel.labelAlreadyExists(newLabelValue)) {
dialogService.showErrorDialogAndWait(Localization.lang("A string with the label '%0' already exists.", newLabelValue));
cell.getRowValue().setLabel("");
cell.getRowValue().setLabel(cell.getOldValue());
} else {
cell.getRowValue().setLabel(cell.getNewValue());
cell.getRowValue().setLabel(newLabelValue);
}
});
colContent.setOnEditCommit((CellEditEvent<BibtexStringViewModel, String> cell) -> {
cell.getRowValue().setContent(cell.getNewValue());

contentColumn.setSortable(true);
contentColumn.setReorderable(false);
contentColumn.setCellValueFactory(cellData -> cellData.getValue().contentProperty());
new ViewModelTextFieldTableCellVisualizationFactory<BibtexStringEditorItemModel, String>()
.withValidation(BibtexStringEditorItemModel::contentValidation, visualizer)
.install(contentColumn, new DefaultStringConverter());
contentColumn.setOnEditCommit((CellEditEvent<BibtexStringEditorItemModel, String> cell) ->
cell.getRowValue().setContent(cell.getNewValue()));

actionsColumn.setSortable(false);
actionsColumn.setReorderable(false);
actionsColumn.setCellValueFactory(cellData -> cellData.getValue().labelProperty());
new ValueTableCellFactory<BibtexStringEditorItemModel, String>()
.withGraphic(label -> IconTheme.JabRefIcons.DELETE_ENTRY.getGraphicNode())
.withTooltip(label -> Localization.lang("Remove string %0", label))
.withOnMouseClickedEvent(item -> evt ->
viewModel.removeString(stringsList.getFocusModel().getFocusedItem()))
.install(actionsColumn);

addStringLabel.textProperty().bindBidirectional(viewModel.addLabelProperty());
addStringLabel.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
if (event.getCode() == KeyCode.ENTER) {
addStringContent.requestFocus();
addStringContent.selectAll();
event.consume();
}
});

tblStrings.itemsProperty().bindBidirectional(viewModel.allStringsProperty());
tblStrings.setEditable(true);
addStringContent.textProperty().bindBidirectional(viewModel.addContentProperty());
addStringContent.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
if (event.getCode() == KeyCode.ENTER) {
viewModel.addNewString();
addStringLabel.requestFocus();
event.consume();
}
});

viewModel.seletedItemProperty().bind(tblStrings.getSelectionModel().selectedItemProperty());
stringsList.itemsProperty().bindBidirectional(viewModel.stringsListProperty());
stringsList.setEditable(true);
}

@FXML
private void addString(ActionEvent event) {
private void addString() {
viewModel.addNewString();
}

@FXML
private void openHelp(ActionEvent event) {
private void openHelp() {
viewModel.openHelpPage();
}

@FXML
private void removeString(ActionEvent event) {
viewModel.removeString();
}
}
Expand Up @@ -6,10 +6,10 @@

import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ListProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleListProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
Expand All @@ -20,71 +20,87 @@
import org.jabref.logic.help.HelpFile;
import org.jabref.model.database.BibDatabase;
import org.jabref.model.entry.BibtexString;
import org.jabref.model.strings.StringUtil;

import org.fxmisc.easybind.EasyBind;

public class BibtexStringEditorDialogViewModel extends AbstractViewModel {

private final ListProperty<BibtexStringViewModel> allStrings = new SimpleListProperty<>(FXCollections.observableArrayList());
private final ObjectProperty<BibtexStringViewModel> selectedItemProperty = new SimpleObjectProperty<>();
private final ListProperty<BibtexStringEditorItemModel> stringsListProperty = new SimpleListProperty<>(FXCollections.observableArrayList());
private final StringProperty addLabelProperty = new SimpleStringProperty();
private final StringProperty addContentProperty = new SimpleStringProperty();

private final BibDatabase bibDatabase;
private final BooleanProperty validProperty = new SimpleBooleanProperty();

public BibtexStringEditorDialogViewModel(BibDatabase bibDatabase) {
this.bibDatabase = bibDatabase;
addAllStringsFromDB();

ObservableList<ObservableValue<Boolean>> allValidProperty = EasyBind.map(allStringsProperty(), BibtexStringViewModel::combinedValidationValidProperty);
ObservableList<ObservableValue<Boolean>> allValidProperty = EasyBind.map(stringsListProperty(), BibtexStringEditorItemModel::combinedValidationValidProperty);
validProperty.bind(EasyBind.combine(allValidProperty, stream -> stream.allMatch(valid -> valid)));
}

private void addAllStringsFromDB() {

Set<BibtexStringViewModel> strings = bibDatabase.getStringValues()
.stream()
.sorted(new BibtexStringComparator(false))
.map(this::convertFromBibTexString)
.collect(Collectors.toSet());
allStrings.addAll(strings);
Set<BibtexStringEditorItemModel> strings = bibDatabase.getStringValues().stream()
.sorted(new BibtexStringComparator(false))
.map(this::convertFromBibTexString)
.collect(Collectors.toSet());
stringsListProperty.addAll(strings);
}

public ListProperty<BibtexStringViewModel> allStringsProperty() {
return this.allStrings;
public boolean addNewString() {
if (!StringUtil.isNullOrEmpty(addLabelProperty.getValue())
&& !labelAlreadyExists(addLabelProperty.getValue())) {
stringsListProperty.add(new BibtexStringEditorItemModel(addLabelProperty.getValue(), addContentProperty.getValue()));
addLabelProperty.setValue("");
addContentProperty.setValue("");
return true;
} else {
return false;
}
}

public void addNewString() {
allStrings.add(new BibtexStringViewModel("", ""));
public void removeString(BibtexStringEditorItemModel item) {
stringsListProperty.remove(item);
}

public void removeString() {
BibtexStringViewModel toBeRemoved = selectedItemProperty.getValue();
allStrings.remove(toBeRemoved);
}

private BibtexStringViewModel convertFromBibTexString(BibtexString bibtexString) {
return new BibtexStringViewModel(bibtexString.getName(), bibtexString.getContent());
}

public ObjectProperty<BibtexStringViewModel> seletedItemProperty() {
return this.selectedItemProperty;
private BibtexStringEditorItemModel convertFromBibTexString(BibtexString bibtexString) {
return new BibtexStringEditorItemModel(bibtexString.getName(), bibtexString.getContent());
}

public void save() {
List<BibtexString> stringsToAdd = allStrings.stream().map(this::fromBibtexStringViewModel).collect(Collectors.toList());
List<BibtexString> stringsToAdd = stringsListProperty.stream().map(this::fromBibtexStringViewModel).collect(Collectors.toList());
bibDatabase.setStrings(stringsToAdd);
}

private BibtexString fromBibtexStringViewModel(BibtexStringViewModel viewModel) {
private BibtexString fromBibtexStringViewModel(BibtexStringEditorItemModel viewModel) {
String label = viewModel.labelProperty().getValue();
String content = viewModel.contentProperty().getValue();
return new BibtexString(label, content);
}

public BooleanProperty validProperty() {
return validProperty;
public boolean labelAlreadyExists(String label) {
return stringsListProperty.stream().anyMatch(item -> item.labelProperty().getValue().equals(label));
}

public void openHelpPage() {
HelpAction.openHelpPage(HelpFile.STRING_EDITOR);
}

public ListProperty<BibtexStringEditorItemModel> stringsListProperty() {
return stringsListProperty;
}

public BooleanProperty validProperty() {
return validProperty;
}

public StringProperty addLabelProperty() {
return addLabelProperty;
}

public StringProperty addContentProperty() {
return addContentProperty;
}
}