Skip to content

Commit

Permalink
single line text fields (#4138)
Browse files Browse the repository at this point in the history
* force author, title and year text areas to be single line text field using text formatter

* consider 'institution' as a field, that should contain only one line

* create EditorTextField and use that control for author, institution, year and title

* pass JournalAbbrevRepo instead of Loader and Prefs

* code review fixes
- move SINGLE_LINE_FIELDS list to InternalBibtexFields class
- rename hasSingleLine var to isSingleLine
  • Loading branch information
Dominik Traczyk authored and tobiasdiez committed Jul 22, 2018
1 parent 9ae2b40 commit f9799d4
Show file tree
Hide file tree
Showing 14 changed files with 183 additions and 67 deletions.
5 changes: 2 additions & 3 deletions src/main/java/org/jabref/gui/entryeditor/FieldsEditorTab.java
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,8 @@ private Region setupPanel(BibEntry entry, boolean compressed, SuggestionProvider
boolean isFirstField = true;
for (String fieldName : fields) {
FieldEditorFX fieldEditor = FieldEditors.getForField(fieldName, Globals.TASK_EXECUTOR, dialogService,
Globals.journalAbbreviationLoader, Globals.prefs.getJournalAbbreviationPreferences(), Globals.prefs,
databaseContext, entry.getType(),
suggestionProviders, undoManager);
Globals.journalAbbreviationLoader.getRepository(Globals.prefs.getJournalAbbreviationPreferences()),
Globals.prefs, databaseContext, entry.getType(), suggestionProviders, undoManager);
fieldEditor.bindToEntry(entry);

editors.put(fieldName, fieldEditor);
Expand Down
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);
}
}
}
29 changes: 21 additions & 8 deletions src/main/java/org/jabref/gui/fieldeditors/FieldEditors.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@
import org.jabref.gui.autocompleter.SuggestionProviders;
import org.jabref.gui.util.TaskExecutor;
import org.jabref.logic.integrity.FieldCheckers;
import org.jabref.logic.journals.JournalAbbreviationLoader;
import org.jabref.logic.journals.JournalAbbreviationPreferences;
import org.jabref.logic.journals.JournalAbbreviationRepository;
import org.jabref.model.database.BibDatabaseContext;
import org.jabref.model.entry.FieldName;
import org.jabref.model.entry.FieldProperty;
Expand All @@ -29,12 +28,26 @@ 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) {
public static FieldEditorFX getForField(final String fieldName,
final TaskExecutor taskExecutor,
final DialogService dialogService,
final JournalAbbreviationRepository journalAbbreviationRepository,
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());

FieldCheckers fieldCheckers = new FieldCheckers(databaseContext, preferences.getFileDirectoryPreferences(), journalAbbreviationLoader.getRepository(journalAbbreviationPreferences), preferences.getBoolean(JabRefPreferences.ENFORCE_LEGAL_BIBTEX_KEY));
final FieldCheckers fieldCheckers = new FieldCheckers(
databaseContext,
preferences.getFileDirectoryPreferences(),
journalAbbreviationRepository,
preferences.getBoolean(JabRefPreferences.ENFORCE_LEGAL_BIBTEX_KEY));

final boolean isSingleLine = InternalBibtexFields.isSingleLineField(fieldName);

if (preferences.getTimestampPreferences().getTimestampField().equals(fieldName) || fieldExtras.contains(FieldProperty.DATE)) {
if (fieldExtras.contains(FieldProperty.ISO_DATE)) {
Expand All @@ -45,7 +58,7 @@ public static FieldEditorFX getForField(String fieldName, TaskExecutor taskExecu
} else if (fieldExtras.contains(FieldProperty.EXTERNAL)) {
return new UrlEditor(fieldName, dialogService, suggestionProvider, fieldCheckers, preferences);
} else if (fieldExtras.contains(FieldProperty.JOURNAL_NAME)) {
return new JournalEditor(fieldName, journalAbbreviationLoader, preferences, suggestionProvider, fieldCheckers);
return new JournalEditor(fieldName, journalAbbreviationRepository, preferences, suggestionProvider, fieldCheckers);
} else if (fieldExtras.contains(FieldProperty.DOI) || fieldExtras.contains(FieldProperty.EPRINT) || fieldExtras.contains(FieldProperty.ISBN)) {
return new IdentifierEditor(fieldName, taskExecutor, dialogService, suggestionProvider, fieldCheckers, preferences);
} else if (fieldExtras.contains(FieldProperty.OWNER)) {
Expand All @@ -71,7 +84,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, isSingleLine);
} else if (FieldName.KEYWORDS.equals(fieldName)) {
return new KeywordsEditor(fieldName, suggestionProvider, fieldCheckers, preferences);
} else if (fieldExtras.contains(FieldProperty.MULTILINE_TEXT)) {
Expand All @@ -81,7 +94,7 @@ public static FieldEditorFX getForField(String fieldName, TaskExecutor taskExecu
}

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

@SuppressWarnings("unchecked")
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/org/jabref/gui/fieldeditors/JournalEditor.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import org.jabref.gui.autocompleter.AutoCompletionTextInputBinding;
import org.jabref.gui.fieldeditors.contextmenu.EditorMenus;
import org.jabref.logic.integrity.FieldCheckers;
import org.jabref.logic.journals.JournalAbbreviationLoader;
import org.jabref.logic.journals.JournalAbbreviationRepository;
import org.jabref.model.entry.BibEntry;
import org.jabref.preferences.JabRefPreferences;

Expand All @@ -19,8 +19,8 @@ public class JournalEditor extends HBox implements FieldEditorFX {
@FXML private JournalEditorViewModel viewModel;
@FXML private EditorTextArea textArea;

public JournalEditor(String fieldName, JournalAbbreviationLoader journalAbbreviationLoader, JabRefPreferences preferences, AutoCompleteSuggestionProvider<?> suggestionProvider, FieldCheckers fieldCheckers) {
this.viewModel = new JournalEditorViewModel(fieldName, suggestionProvider, journalAbbreviationLoader, preferences.getJournalAbbreviationPreferences(), fieldCheckers);
public JournalEditor(String fieldName, JournalAbbreviationRepository journalAbbreviationRepository, JabRefPreferences preferences, AutoCompleteSuggestionProvider<?> suggestionProvider, FieldCheckers fieldCheckers) {
this.viewModel = new JournalEditorViewModel(fieldName, suggestionProvider, journalAbbreviationRepository, fieldCheckers);

ViewLoader.view(this)
.root(this)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,25 @@

import org.jabref.gui.autocompleter.AutoCompleteSuggestionProvider;
import org.jabref.logic.integrity.FieldCheckers;
import org.jabref.logic.journals.JournalAbbreviationLoader;
import org.jabref.logic.journals.JournalAbbreviationPreferences;
import org.jabref.logic.journals.JournalAbbreviationRepository;
import org.jabref.model.strings.StringUtil;

public class JournalEditorViewModel extends AbstractEditorViewModel {
private final JournalAbbreviationLoader journalAbbreviationLoader;
private final JournalAbbreviationPreferences journalAbbreviationPreferences;
private final JournalAbbreviationRepository journalAbbreviationRepository;

public JournalEditorViewModel(String fieldName, AutoCompleteSuggestionProvider<?> suggestionProvider, JournalAbbreviationLoader journalAbbreviationLoader, JournalAbbreviationPreferences journalAbbreviationPreferences, FieldCheckers fieldCheckers) {
public JournalEditorViewModel(String fieldName, AutoCompleteSuggestionProvider<?> suggestionProvider, JournalAbbreviationRepository journalAbbreviationRepository, FieldCheckers fieldCheckers) {
super(fieldName, suggestionProvider, fieldCheckers);

this.journalAbbreviationLoader = journalAbbreviationLoader;
this.journalAbbreviationPreferences = journalAbbreviationPreferences;
this.journalAbbreviationRepository = journalAbbreviationRepository;
}

public void toggleAbbreviation() {
if (StringUtil.isBlank(text.get())) {
return;
}

JournalAbbreviationRepository abbreviationRepository = journalAbbreviationLoader.getRepository(journalAbbreviationPreferences);
if (abbreviationRepository.isKnownName(text.get())) {
Optional<String> nextAbbreviation = abbreviationRepository.getNextAbbreviation(text.get());
if (journalAbbreviationRepository.isKnownName(text.get())) {
Optional<String> nextAbbreviation = journalAbbreviationRepository.getNextAbbreviation(text.get());

if (nextAbbreviation.isPresent()) {
text.set(nextAbbreviation.get());
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 isSingleLine) {
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 = isSingleLine
? 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 isSingleLine) {
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 = isSingleLine
? 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
Loading

0 comments on commit f9799d4

Please sign in to comment.