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

single line text fields #4138

Merged
merged 9 commits into from
Jul 22, 2018
15 changes: 15 additions & 0 deletions src/main/java/org/jabref/gui/fieldeditors/ContextMenuAddable.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.jabref.gui.fieldeditors;

import java.util.List;
import java.util.function.Supplier;

import javafx.scene.control.MenuItem;

public interface ContextMenuAddable {
/**
* Adds the given list of menu items to the context menu. The usage of {@link Supplier} prevents that the menus need
* to be instantiated at this point. They are populated when the user needs them which prevents many unnecessary
* allocations when the main table is just scrolled with the entry editor open.
*/
void addToContextMenu(final Supplier<List<MenuItem>> items);
}
12 changes: 4 additions & 8 deletions src/main/java/org/jabref/gui/fieldeditors/EditorTextArea.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@

import com.sun.javafx.scene.control.skin.TextAreaSkin;

public class EditorTextArea extends javafx.scene.control.TextArea implements Initializable {
public class EditorTextArea extends javafx.scene.control.TextArea implements Initializable, ContextMenuAddable {

public EditorTextArea() {
this("");
}

public EditorTextArea(String text) {
public EditorTextArea(final String text) {
super(text);

setMinHeight(1);
Expand Down Expand Up @@ -49,12 +49,8 @@ public EditorTextArea(String text) {
});
}

/**
* Adds the given list of menu items to the context menu. The usage of {@link Supplier} prevents that the menus need
* to be instantiated at this point. They are populated when the user needs them which prevents many unnecessary
* allocations when the main table is just scrolled with the entry editor open.
*/
public void addToContextMenu(Supplier<List<MenuItem>> items) {
@Override
public void addToContextMenu(final Supplier<List<MenuItem>> items) {
TextAreaSkin customContextSkin = new TextAreaSkin(this) {
@Override
public void populateContextMenu(ContextMenu contextMenu) {
Expand Down
65 changes: 65 additions & 0 deletions src/main/java/org/jabref/gui/fieldeditors/EditorTextField.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package org.jabref.gui.fieldeditors;

import java.net.URL;
import java.util.List;
import java.util.ResourceBundle;
import java.util.function.Supplier;

import javafx.fxml.Initializable;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;

import com.sun.javafx.scene.control.skin.TextFieldSkin;

public class EditorTextField extends javafx.scene.control.TextField implements Initializable, ContextMenuAddable {

public EditorTextField() {
this("");
}

public EditorTextField(final String text) {
super(text);

setMinHeight(1);
setMinWidth(200);

// Should behave as a normal text field with respect to TAB behaviour
addEventFilter(KeyEvent.KEY_PRESSED, event -> {
if (event.getCode() == KeyCode.TAB) {
TextFieldSkin skin = (TextFieldSkin) getSkin();
if (event.isShiftDown()) {
// Shift + Tab > previous text area
skin.getBehavior().traversePrevious();
} else {
if (event.isControlDown()) {
// Ctrl + Tab > insert tab
skin.getBehavior().callAction("InsertTab");
} else {
// Tab > next text area
skin.getBehavior().traverseNext();
}
}
event.consume();
}
});
}

@Override
public void addToContextMenu(final Supplier<List<MenuItem>> items) {
TextFieldSkin customContextSkin = new TextFieldSkin(this) {
@Override
public void populateContextMenu(ContextMenu contextMenu) {
super.populateContextMenu(contextMenu);
contextMenu.getItems().addAll(0, items.get());
}
};
setSkin(customContextSkin);
}

@Override
public void initialize(URL location, ResourceBundle resources) {
// not needed
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.jabref.gui.fieldeditors;

import javafx.scene.control.TextInputControl;

import org.jabref.gui.util.IconValidationDecorator;
import org.jabref.preferences.JabRefPreferences;

Expand All @@ -14,11 +16,11 @@ public EditorValidator(JabRefPreferences preferences) {
this.preferences = preferences;
}

public void configureValidation(ValidationStatus status, EditorTextArea area) {
public void configureValidation(final ValidationStatus status, final TextInputControl textInput) {
if (preferences.getBoolean(JabRefPreferences.VALIDATE_IN_ENTRY_EDITOR)) {
ControlsFxVisualizer validationVisualizer = new ControlsFxVisualizer();
validationVisualizer.setDecoration(new IconValidationDecorator());
validationVisualizer.initVisualization(status, area);
validationVisualizer.initVisualization(status, textInput);
}
}
}
37 changes: 32 additions & 5 deletions src/main/java/org/jabref/gui/fieldeditors/FieldEditors.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package org.jabref.gui.fieldeditors;

import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

Expand All @@ -25,16 +28,40 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static org.jabref.model.entry.FieldName.AUTHOR;
import static org.jabref.model.entry.FieldName.INSTITUTION;
import static org.jabref.model.entry.FieldName.TITLE;
import static org.jabref.model.entry.FieldName.YEAR;

public class FieldEditors {

private static final Logger LOGGER = LoggerFactory.getLogger(FieldEditors.class);

public static FieldEditorFX getForField(String fieldName, TaskExecutor taskExecutor, DialogService dialogService, JournalAbbreviationLoader journalAbbreviationLoader, JournalAbbreviationPreferences journalAbbreviationPreferences, JabRefPreferences preferences, BibDatabaseContext databaseContext, String entryType, SuggestionProviders suggestionProviders, UndoManager undoManager) {
private static final Set<String> SINGLE_LINE_FIELDS = Collections.unmodifiableSet(new HashSet<>(
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 add this list two InternalBibtexFields (this class needs to be refactored at some point, but for now it is good to have anything at one place).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep. Sorry for delay, I will do that on Saturday.

Arrays.asList(TITLE, AUTHOR, YEAR, INSTITUTION)
));

public static FieldEditorFX getForField(final String fieldName,
final TaskExecutor taskExecutor,
final DialogService dialogService,
final JournalAbbreviationLoader journalAbbreviationLoader,
Copy link
Member

Choose a reason for hiding this comment

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

You could extract the loader and the prefs parameter and directly pass the JounralAbbrev Repo stuff which is just passed onto the field checkers later
journalAbbreviationLoader.getRepository(journalAbbreviationPreferences)

Copy link
Contributor Author

@Naitoreivun Naitoreivun Jun 23, 2018

Choose a reason for hiding this comment

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

done; I'm just wonder if it's ok to access repository at the beginning instead of calling for it every time? I mean, is there a way, that the repo could be updated?

Copy link
Member

Choose a reason for hiding this comment

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

In principle, the user might change the journal abbreviations at any time. However, it should be fine to use the repository since the field editors are recreated when switching to the new entry.

final JournalAbbreviationPreferences journalAbbreviationPreferences,
final JabRefPreferences preferences,
final BibDatabaseContext databaseContext,
final String entryType,
final SuggestionProviders suggestionProviders,
final UndoManager undoManager) {
final Set<FieldProperty> fieldExtras = InternalBibtexFields.getFieldProperties(fieldName);

AutoCompleteSuggestionProvider<?> suggestionProvider = getSuggestionProvider(fieldName, suggestionProviders, databaseContext.getMetaData());
final AutoCompleteSuggestionProvider<?> suggestionProvider = getSuggestionProvider(fieldName, suggestionProviders, databaseContext.getMetaData());

final FieldCheckers fieldCheckers = new FieldCheckers(
databaseContext,
preferences.getFileDirectoryPreferences(),
journalAbbreviationLoader.getRepository(journalAbbreviationPreferences),
Copy link
Member

Choose a reason for hiding this comment

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

Here the abbrev repo stuff is passed

preferences.getBoolean(JabRefPreferences.ENFORCE_LEGAL_BIBTEX_KEY));

FieldCheckers fieldCheckers = new FieldCheckers(databaseContext, preferences.getFileDirectoryPreferences(), journalAbbreviationLoader.getRepository(journalAbbreviationPreferences), preferences.getBoolean(JabRefPreferences.ENFORCE_LEGAL_BIBTEX_KEY));
final boolean hasSingleLine = SINGLE_LINE_FIELDS.contains(fieldName.toLowerCase());
Copy link
Member

Choose a reason for hiding this comment

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

I might be mistaken here, but isSingleLine(Field) sounds more natural to me.


if (preferences.getTimestampPreferences().getTimestampField().equals(fieldName) || fieldExtras.contains(FieldProperty.DATE)) {
if (fieldExtras.contains(FieldProperty.ISO_DATE)) {
Expand Down Expand Up @@ -71,7 +98,7 @@ public static FieldEditorFX getForField(String fieldName, TaskExecutor taskExecu
} else if (fieldExtras.contains(FieldProperty.SINGLE_ENTRY_LINK) || fieldExtras.contains(FieldProperty.MULTIPLE_ENTRY_LINK)) {
return new LinkedEntriesEditor(fieldName, databaseContext, suggestionProvider, fieldCheckers);
} else if (fieldExtras.contains(FieldProperty.PERSON_NAMES)) {
return new PersonsEditor(fieldName, suggestionProvider, preferences, fieldCheckers);
return new PersonsEditor(fieldName, suggestionProvider, preferences, fieldCheckers, hasSingleLine);
} else if (FieldName.KEYWORDS.equals(fieldName)) {
return new KeywordsEditor(fieldName, suggestionProvider, fieldCheckers, preferences);
} else if (fieldExtras.contains(FieldProperty.MULTILINE_TEXT)) {
Expand All @@ -81,7 +108,7 @@ public static FieldEditorFX getForField(String fieldName, TaskExecutor taskExecu
}

// default
return new SimpleEditor(fieldName, suggestionProvider, fieldCheckers, preferences);
return new SimpleEditor(fieldName, suggestionProvider, fieldCheckers, preferences, hasSingleLine);
}

@SuppressWarnings("unchecked")
Expand Down
27 changes: 17 additions & 10 deletions src/main/java/org/jabref/gui/fieldeditors/PersonsEditor.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import javafx.fxml.FXML;
import javafx.scene.Parent;
import javafx.scene.control.TextInputControl;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;

Expand All @@ -16,20 +17,26 @@ public class PersonsEditor extends HBox implements FieldEditorFX {

@FXML private final PersonsEditorViewModel viewModel;

private EditorTextArea textArea;
private TextInputControl textInput;

public PersonsEditor(String fieldName, AutoCompleteSuggestionProvider<?> suggestionProvider, JabRefPreferences preferences, FieldCheckers fieldCheckers) {
public PersonsEditor(final String fieldName,
final AutoCompleteSuggestionProvider<?> suggestionProvider,
final JabRefPreferences preferences,
final FieldCheckers fieldCheckers,
final boolean hasSingleLine) {
this.viewModel = new PersonsEditorViewModel(fieldName, suggestionProvider, preferences.getAutoCompletePreferences(), fieldCheckers);

textArea = new EditorTextArea();
HBox.setHgrow(textArea, Priority.ALWAYS);
textArea.textProperty().bindBidirectional(viewModel.textProperty());
textArea.addToContextMenu(EditorMenus.getNameMenu(textArea));
this.getChildren().add(textArea);
textInput = hasSingleLine
? new EditorTextField()
: new EditorTextArea();
HBox.setHgrow(textInput, Priority.ALWAYS);
textInput.textProperty().bindBidirectional(viewModel.textProperty());
((ContextMenuAddable) textInput).addToContextMenu(EditorMenus.getNameMenu(textInput));
this.getChildren().add(textInput);

AutoCompletionTextInputBinding.autoComplete(textArea, viewModel::complete, viewModel.getAutoCompletionConverter(), viewModel.getAutoCompletionStrategy());
AutoCompletionTextInputBinding.autoComplete(textInput, viewModel::complete, viewModel.getAutoCompletionConverter(), viewModel.getAutoCompletionStrategy());

new EditorValidator(preferences).configureValidation(viewModel.getFieldValidator().getValidationStatus(), textArea);
new EditorValidator(preferences).configureValidation(viewModel.getFieldValidator().getValidationStatus(), textInput);
}

@Override
Expand All @@ -44,7 +51,7 @@ public Parent getNode() {

@Override
public void requestFocus() {
textArea.requestFocus();
textInput.requestFocus();
}

}
31 changes: 23 additions & 8 deletions src/main/java/org/jabref/gui/fieldeditors/SimpleEditor.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import javafx.fxml.FXML;
import javafx.scene.Parent;
import javafx.scene.control.TextInputControl;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;

Expand All @@ -17,22 +18,36 @@ public class SimpleEditor extends HBox implements FieldEditorFX {

@FXML private final SimpleEditorViewModel viewModel;

public SimpleEditor(String fieldName, AutoCompleteSuggestionProvider<?> suggestionProvider, FieldCheckers fieldCheckers, JabRefPreferences preferences) {
public SimpleEditor(final String fieldName,
final AutoCompleteSuggestionProvider<?> suggestionProvider,
final FieldCheckers fieldCheckers,
final JabRefPreferences preferences,
final boolean hasSingleLine) {
this.viewModel = new SimpleEditorViewModel(fieldName, suggestionProvider, fieldCheckers);

EditorTextArea textArea = new EditorTextArea();
HBox.setHgrow(textArea, Priority.ALWAYS);
textArea.textProperty().bindBidirectional(viewModel.textProperty());
textArea.addToContextMenu(EditorMenus.getDefaultMenu(textArea));
this.getChildren().add(textArea);
TextInputControl textInput = hasSingleLine
? new EditorTextField()
: new EditorTextArea();
HBox.setHgrow(textInput, Priority.ALWAYS);
textInput.textProperty().bindBidirectional(viewModel.textProperty());
((ContextMenuAddable) textInput).addToContextMenu(EditorMenus.getDefaultMenu(textInput));
this.getChildren().add(textInput);

AutoCompletionTextInputBinding<?> autoCompleter = AutoCompletionTextInputBinding.autoComplete(textArea, viewModel::complete, viewModel.getAutoCompletionStrategy());
AutoCompletionTextInputBinding<?> autoCompleter = AutoCompletionTextInputBinding.autoComplete(textInput, viewModel::complete, viewModel.getAutoCompletionStrategy());
if (suggestionProvider instanceof ContentSelectorSuggestionProvider) {
// If content selector values are present, then we want to show the auto complete suggestions immediately on focus
autoCompleter.setShowOnFocus(true);
}

new EditorValidator(preferences).configureValidation(viewModel.getFieldValidator().getValidationStatus(), textArea);
new EditorValidator(preferences).configureValidation(viewModel.getFieldValidator().getValidationStatus(), textInput);
}


public SimpleEditor(final String fieldName,
final AutoCompleteSuggestionProvider<?> suggestionProvider,
final FieldCheckers fieldCheckers,
final JabRefPreferences preferences) {
this(fieldName, suggestionProvider, fieldCheckers, preferences, false);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package org.jabref.gui.fieldeditors.contextmenu;

import javafx.scene.control.MenuItem;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextInputControl;

import org.jabref.logic.l10n.Localization;

class ClearField extends MenuItem {

public ClearField(TextArea opener) {
public ClearField(TextInputControl opener) {
super(Localization.lang("Clear"));
setOnAction(event -> opener.setText(""));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import javafx.scene.control.MenuItem;
import javafx.scene.control.SeparatorMenuItem;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextInputControl;
import javafx.scene.control.Tooltip;

import org.jabref.gui.actions.CopyDoiUrlAction;
Expand All @@ -29,37 +30,37 @@ public class EditorMenus {
/**
* The default menu that contains functions for changing the case of text and doing several conversions.
*
* @param textArea text-area that this menu will be connected to
* @param textInput text-input-control that this menu will be connected to
* @return default context menu available for most text fields
*/
public static Supplier<List<MenuItem>> getDefaultMenu(TextArea textArea) {
public static Supplier<List<MenuItem>> getDefaultMenu(final TextInputControl textInput) {
return () -> {
List<MenuItem> menuItems = new ArrayList<>(6);
menuItems.add(new CaseChangeMenu(textArea.textProperty()));
menuItems.add(new ConversionMenu(textArea.textProperty()));
menuItems.add(new CaseChangeMenu(textInput.textProperty()));
menuItems.add(new ConversionMenu(textInput.textProperty()));
menuItems.add(new SeparatorMenuItem());
menuItems.add(new ProtectedTermsMenu(textArea));
menuItems.add(new ProtectedTermsMenu(textInput));
menuItems.add(new SeparatorMenuItem());
menuItems.add(new ClearField(textArea));
menuItems.add(new ClearField(textInput));
return menuItems;
};
}

/**
* The default context menu with a specific menu for normalizing person names regarding to BibTex rules.
*
* @param textArea text-area that this menu will be connected to
* @param textInput text-input-control that this menu will be connected to
* @return menu containing items of the default menu and an item for normalizing person names
*/
public static Supplier<List<MenuItem>> getNameMenu(TextArea textArea) {
public static Supplier<List<MenuItem>> getNameMenu(final TextInputControl textInput) {
return () -> {
CustomMenuItem normalizeNames = new CustomMenuItem(new Label(Localization.lang("Normalize to BibTeX name format")));
normalizeNames.setOnAction(event -> textArea.setText(new NormalizeNamesFormatter().format(textArea.getText())));
normalizeNames.setOnAction(event -> textInput.setText(new NormalizeNamesFormatter().format(textInput.getText())));
Tooltip toolTip = new Tooltip(Localization.lang("If possible, normalize this list of names to conform to standard BibTeX name formatting"));
Tooltip.install(normalizeNames.getContent(), toolTip);
List<MenuItem> menuItems = new ArrayList<>(6);
menuItems.add(normalizeNames);
menuItems.addAll(getDefaultMenu(textArea).get());
menuItems.addAll(getDefaultMenu(textInput).get());
return menuItems;
};
}
Expand Down
Loading