Skip to content

Commit

Permalink
Merge pull request #6152 from JabRef/allowReordering
Browse files Browse the repository at this point in the history
Allow reordering of custom entry types fields
  • Loading branch information
Siedlerchr committed Jul 1, 2020
2 parents 593b235 + d1f4d99 commit c83ea3f
Show file tree
Hide file tree
Showing 28 changed files with 491 additions and 238 deletions.
1 change: 1 addition & 0 deletions src/main/java/org/jabref/gui/DragAndDropDataFormats.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
*/
public class DragAndDropDataFormats {

public static final DataFormat FIELD = new DataFormat("dnd/org.jabref.model.entry.field.Field");
public static final DataFormat GROUP = new DataFormat("dnd/org.jabref.model.groups.GroupTreeNode");
public static final DataFormat LINKED_FILE = new DataFormat("dnd/org.jabref.model.entry.LinkedFile");
public static final DataFormat ENTRIES = new DataFormat("dnd/org.jabref.model.entry.BibEntries");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,12 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import javafx.beans.Observable;
import javafx.beans.property.ListProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleListProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
Expand All @@ -34,7 +30,6 @@
import org.jabref.model.entry.types.UnknownEntryType;
import org.jabref.preferences.PreferencesService;

import com.tobiasdiez.easybind.EasyBind;
import de.saxsys.mvvmfx.utils.validation.FunctionBasedValidator;
import de.saxsys.mvvmfx.utils.validation.ValidationMessage;
import de.saxsys.mvvmfx.utils.validation.ValidationStatus;
Expand All @@ -55,18 +50,14 @@ public Field fromString(String string) {
}
};

private final ListProperty<BibEntryType> entryTypes;
private final ListProperty<Field> fields;
private final ObjectProperty<BibEntryType> selectedEntryTypes = new SimpleObjectProperty<>();
private final ListProperty<FieldViewModel> fieldsForType;
private final ObservableList<Field> fieldsForAdding = FXCollections.observableArrayList(FieldFactory.getStandardFielsdsWithBibTexKey());
private final ObjectProperty<CustomEntryTypeViewModel> selectedEntryType = new SimpleObjectProperty<>();
private final ObjectProperty<Field> selectedFieldToAdd = new SimpleObjectProperty<>();
private final StringProperty entryTypeToAdd = new SimpleStringProperty("");
private final ObservableList<BibEntryType> allEntryTypes;
private final ObservableList<FieldViewModel> allFieldsForType = FXCollections.observableArrayList(extractor -> new Observable[] {extractor.fieldName(), extractor.fieldType()});
private final ObjectProperty<Field> newFieldToAdd = new SimpleObjectProperty<>();
private final BibDatabaseMode mode;
private final Map<BibEntryType, List<FieldViewModel>> typesWithFields = new HashMap<>();
private final List<BibEntryType> typesToRemove = new ArrayList<>();
private final ObservableList<CustomEntryTypeViewModel> entryTypesWithFields = FXCollections.observableArrayList(extractor -> new Observable[] {extractor.entryType(), extractor.fields()});
private final List<BibEntryType> entryTypesToDelete = new ArrayList<>();

private final PreferencesService preferencesService;
private final BibEntryTypesManager entryTypesManager;
Expand All @@ -79,40 +70,33 @@ public CustomEntryTypeDialogViewModel(BibDatabaseMode mode, PreferencesService p
this.preferencesService = preferencesService;
this.entryTypesManager = entryTypesManager;

Collection<BibEntryType> allTypes = entryTypesManager.getAllTypes(mode);
allTypes.addAll(entryTypesManager.getAllCustomTypes(mode));
addAllTypes();

allEntryTypes = FXCollections.observableArrayList(allTypes);
entryTypes = new SimpleListProperty<>(allEntryTypes);
Predicate<String> notEmpty = input -> (input != null) && !input.trim().isEmpty();
entryTypeValidator = new FunctionBasedValidator<>(entryTypeToAdd, notEmpty, ValidationMessage.error(Localization.lang("Entry type cannot be empty. Please enter a name.")));
fieldValidator = new FunctionBasedValidator<>(newFieldToAdd,
input -> (input != null) && !input.getDisplayName().isEmpty(),
ValidationMessage.error(Localization.lang("Field cannot be empty. Please enter a name.")));
}

fields = new SimpleListProperty<>(FXCollections.observableArrayList(FieldFactory.getCommonFields()));
public void addAllTypes() {
if (this.entryTypesWithFields.size() > 0) {
this.entryTypesWithFields.clear();
}
Collection<BibEntryType> allTypes = entryTypesManager.getAllTypes(mode);

for (BibEntryType entryType : allTypes) {
List<FieldViewModel> fields = entryType.getAllFields().stream().map(bibField -> new FieldViewModel(bibField.getField(), entryType.isRequired(bibField.getField()), bibField.getPriority(), entryType)).collect(Collectors.toList());
typesWithFields.put(entryType, fields);
CustomEntryTypeViewModel viewModel = new CustomEntryTypeViewModel(entryType);
this.entryTypesWithFields.add(viewModel);
}

this.fieldsForType = new SimpleListProperty<>(allFieldsForType);

EasyBind.subscribe(selectedEntryTypes, type -> {
if (type != null) {
allFieldsForType.setAll(typesWithFields.get(type));
}
});

Predicate<String> notEmpty = input -> (input != null) && !input.trim().isEmpty();
entryTypeValidator = new FunctionBasedValidator<>(entryTypeToAdd, notEmpty, ValidationMessage.error(Localization.lang("Entry type cannot be empty. Please enter a name.")));
fieldValidator = new FunctionBasedValidator<>(newFieldToAdd,
input -> input != null && !input.getDisplayName().isEmpty(),
ValidationMessage.error(Localization.lang("Field cannot be empty. Please enter a name.")));
}

public ListProperty<BibEntryType> entryTypes() {
return this.entryTypes;
public ObservableList<CustomEntryTypeViewModel> entryTypes() {
return this.entryTypesWithFields;
}

public ListProperty<Field> fields() {
return this.fields;
public ObservableList<Field> fieldsForAdding() {
return this.fieldsForAdding;
}

public enum FieldType {
Expand All @@ -138,26 +122,23 @@ public String toString() {

public void addNewField() {
Field field = newFieldToAdd.getValue();
FieldViewModel model = new FieldViewModel(field, true, FieldPriority.IMPORTANT, selectedEntryTypes.getValue());
typesWithFields.computeIfAbsent(selectedEntryTypes.getValue(), key -> new ArrayList<>()).add(model);
allFieldsForType.add(model);
FieldViewModel model = new FieldViewModel(field, true, FieldPriority.IMPORTANT);
this.selectedEntryType.getValue().addField(model);
newFieldToAddProperty().setValue(null);
}

public void addNewCustomEntryType() {
public CustomEntryTypeViewModel addNewCustomEntryType() {
EntryType newentryType = new UnknownEntryType(entryTypeToAdd.getValue());
BibEntryType type = new BibEntryType(newentryType, new ArrayList<>(), Collections.emptyList());
this.allEntryTypes.add(type);
CustomEntryTypeViewModel viewModel = new CustomEntryTypeViewModel(type);
this.entryTypesWithFields.add(viewModel);
this.entryTypeToAdd.setValue("");
this.typesWithFields.put(type, new ArrayList<>());
}

public ObjectProperty<BibEntryType> selectedEntryTypeProperty() {
return this.selectedEntryTypes;
return viewModel;
}

public ListProperty<FieldViewModel> fieldsforTypesProperty() {
return this.fieldsForType;
public ObjectProperty<CustomEntryTypeViewModel> selectedEntryTypeProperty() {
return this.selectedEntryType;
}

public ObjectProperty<Field> selectedFieldToAddProperty() {
Expand All @@ -180,22 +161,27 @@ public ValidationStatus fieldValidationStatus() {
return fieldValidator.getValidationStatus();
}

public void removeEntryType(BibEntryType focusedItem) {
typesToRemove.add(focusedItem);
typesWithFields.remove(focusedItem);
allEntryTypes.remove(focusedItem);
public void removeEntryType(CustomEntryTypeViewModel focusedItem) {
entryTypesWithFields.remove(focusedItem);
entryTypesToDelete.add(focusedItem.entryType().getValue());
}

public void removeField(FieldViewModel focusedItem) {
typesWithFields.computeIfAbsent(selectedEntryTypes.getValue(), key -> new ArrayList<>()).remove(focusedItem);
allFieldsForType.remove(focusedItem);
selectedEntryType.getValue().removeField(focusedItem);
}

public void resetAllCustomEntryTypes() {
entryTypesManager.clearAllCustomEntryTypes(mode);
preferencesService.clearBibEntryTypes(mode);
entryTypesManager.addCustomOrModifiedTypes(preferencesService.loadBibEntryTypes(BibDatabaseMode.BIBTEX),
preferencesService.loadBibEntryTypes(BibDatabaseMode.BIBLATEX));
}

public void apply() {

for (var typeWithField : typesWithFields.entrySet()) {
BibEntryType type = typeWithField.getKey();
List<FieldViewModel> allFields = typeWithField.getValue();
for (var typeWithField : entryTypesWithFields) {
BibEntryType type = typeWithField.entryType().getValue();
List<FieldViewModel> allFields = typeWithField.fields();

List<OrFields> requiredFields = allFields.stream().filter(field -> field.getFieldType() == FieldType.REQUIRED).map(FieldViewModel::getField).map(OrFields::new).collect(Collectors.toList());
List<BibField> otherFields = allFields.stream().filter(field -> field.getFieldType() == FieldType.OPTIONAL).map(bibField -> new BibField(bibField.getField(), bibField.getFieldPriority())).collect(Collectors.toList());
Expand All @@ -204,13 +190,13 @@ public void apply() {
entryTypesManager.addCustomOrModifiedType(newType, mode);
}

for (var type : typesToRemove) {
entryTypesManager.removeCustomOrModifiedEntryType(type, mode);
for (var entryType : entryTypesToDelete) {
entryTypesManager.removeCustomOrModifiedEntryType(entryType, mode);
}
preferencesService.saveCustomEntryTypes();

preferencesService.saveCustomEntryTypes(entryTypesManager);
// Reload types from preferences to make sure any modifications are present when reopening the dialog
entryTypesManager.addCustomOrModifiedTypes(
preferencesService.loadBibEntryTypes(BibDatabaseMode.BIBTEX),
preferencesService.loadBibEntryTypes(BibDatabaseMode.BIBLATEX));
entryTypesManager.addCustomOrModifiedTypes(preferencesService.loadBibEntryTypes(BibDatabaseMode.BIBTEX),
preferencesService.loadBibEntryTypes(BibDatabaseMode.BIBLATEX));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package org.jabref.gui.customentrytypes;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

import org.jabref.model.entry.BibEntryType;

public class CustomEntryTypeViewModel {

private final ObjectProperty<BibEntryType> entryType = new SimpleObjectProperty<>();
private final ObservableList<FieldViewModel> fields;

public CustomEntryTypeViewModel(BibEntryType entryType) {
this.entryType.set(entryType);

List<FieldViewModel> allFieldsForType = entryType.getAllBibFields().stream().map(bibField -> new FieldViewModel(bibField.getField(), entryType.isRequired(bibField.getField()), bibField.getPriority())).collect(Collectors.toList());
fields = FXCollections.observableArrayList((allFieldsForType));
}

@Override
public int hashCode() {
return Objects.hash(entryType, fields);
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof CustomEntryTypeViewModel)) {
return false;
}
CustomEntryTypeViewModel other = (CustomEntryTypeViewModel) obj;
return Objects.equals(entryType, other.entryType) && Objects.equals(fields, other.fields);
}

public void addField(FieldViewModel field) {
this.fields.add(field);
}

public ObservableList<FieldViewModel> fields() {
return this.fields;
}

public ObjectProperty<BibEntryType> entryType() {
return this.entryType;
}

public void removeField(FieldViewModel focusedItem) {
this.fields.remove(focusedItem);
}

@Override
public String toString() {
return "CustomEntryTypeViewModel [entryType=" + entryType + ", fields=" + fields + "]";
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,5 @@
<ButtonType fx:id="applyButton" buttonData="OK_DONE"
text="%Apply"/>
<ButtonType fx:constant="CANCEL"/>
<ButtonType fx:id="resetButton" buttonData="LEFT" text="%Reset" />
</DialogPane>
Loading

0 comments on commit c83ea3f

Please sign in to comment.