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

Allow reordering of custom entry types fields #6152

Merged
merged 51 commits into from
Jul 1, 2020
Merged
Show file tree
Hide file tree
Changes from 40 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
4a2737f
[WIP] allow Reordering of custom entry types fields
Siedlerchr Mar 21, 2020
18800b9
Merge remote-tracking branch 'upstream/master' into allowReordering
Siedlerchr Mar 23, 2020
daeec26
Merge remote-tracking branch 'upstream/master' into allowReordering
Siedlerchr Mar 23, 2020
d06d545
change to linkedHashSet
Siedlerchr Mar 23, 2020
5353a85
Further changes
Siedlerchr Mar 23, 2020
2a48588
Merge remote-tracking branch 'upstream/master' into allowReordering
Siedlerchr May 2, 2020
13b2923
iteratre prefs with chidlren recursively to show custom entry types
Siedlerchr May 2, 2020
1cbed25
try around with some more stuff
Siedlerchr May 2, 2020
dcbe938
Merge remote-tracking branch 'upstream/master' into allowReordering
Siedlerchr May 3, 2020
c937601
show prefs path
Siedlerchr May 3, 2020
f49a839
Fix action helper when no library is open
Siedlerchr May 3, 2020
791f458
Merge remote-tracking branch 'upstream/master' into allowReordering
Siedlerchr May 22, 2020
0a010bf
fix checkstyle
Siedlerchr May 22, 2020
1d7832a
fix checkstyle
Siedlerchr May 22, 2020
dc51afd
try with Observable
Siedlerchr May 22, 2020
28aaa0c
Create a new EntryTypeViewModel with observable types and fields
Siedlerchr May 24, 2020
815050f
Merge remote-tracking branch 'upstream/master' into allowReordering
Siedlerchr Jun 6, 2020
ca23628
simplify code
Siedlerchr Jun 6, 2020
5eb5bfc
add/remove handling
Siedlerchr Jun 6, 2020
2777455
check style
Siedlerchr Jun 6, 2020
c275419
simplify code and use observable list where possible
Siedlerchr Jun 7, 2020
eaf7099
fix checkstyle
Siedlerchr Jun 7, 2020
c04b2fc
fix unit tests due to LinkedHashSet
Siedlerchr Jun 7, 2020
15ba840
add extractor
Siedlerchr Jun 7, 2020
614470e
change to observablelist
Siedlerchr Jun 8, 2020
e16cbda
fix issue that items get cleared
Siedlerchr Jun 8, 2020
7ddb6fa
Merge remote-tracking branch 'upstream/master' into allowReordering
Siedlerchr Jun 9, 2020
42606fe
Merge remote-tracking branch 'upstream/master' into allowReordering
Siedlerchr Jun 11, 2020
70853bd
Add option to remove custom entr types
Siedlerchr Jun 11, 2020
e38742b
fix checkstyle
Siedlerchr Jun 11, 2020
230d8dd
Fix bug with empty ghost fields on empty field collection when parsing
Siedlerchr Jun 12, 2020
831eb50
checkstyle
Siedlerchr Jun 12, 2020
73bd208
add reset and fix tests
Siedlerchr Jun 12, 2020
ada2a87
fix fcking checkstyle again
Siedlerchr Jun 12, 2020
e2e6fbd
fix tests
Siedlerchr Jun 12, 2020
c093a05
reenable filter
Siedlerchr Jun 12, 2020
ffa35d4
fix comma error
Siedlerchr Jun 12, 2020
46f0192
add l10n
Siedlerchr Jun 12, 2020
66995a3
l10n
Siedlerchr Jun 12, 2020
fbc3d4d
Merge remote-tracking branch 'upstream/master' into allowReordering
Siedlerchr Jun 13, 2020
716a78d
Merge remote-tracking branch 'upstream/master' into allowReordering
Siedlerchr Jun 19, 2020
e5dd9c6
revert booktitle order
Siedlerchr Jun 20, 2020
fe01050
Merge remote-tracking branch 'upstream/master' into allowReordering
Siedlerchr Jun 22, 2020
5a6fc22
try to add test for use case
Siedlerchr Jun 23, 2020
6846297
pass entry types manager as parameter
Siedlerchr Jun 23, 2020
df03c38
Merge remote-tracking branch 'upstream/master' into allowReordering
Siedlerchr Jun 27, 2020
298a832
Fix issue with wrong order after using BibEntryType Builder
Siedlerchr Jun 27, 2020
16b5366
checkstyle
Siedlerchr Jun 27, 2020
0e8803a
implement reset
Siedlerchr Jun 28, 2020
07d5983
make dialogmessage more specific
Siedlerchr Jun 28, 2020
d1f4d99
checkstyle
Siedlerchr Jun 28, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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");
Siedlerchr marked this conversation as resolved.
Show resolved Hide resolved
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 @@ -82,37 +73,24 @@ public CustomEntryTypeDialogViewModel(BibDatabaseMode mode, PreferencesService p
Collection<BibEntryType> allTypes = entryTypesManager.getAllTypes(mode);
allTypes.addAll(entryTypesManager.getAllCustomTypes(mode));

allEntryTypes = FXCollections.observableArrayList(allTypes);
entryTypes = new SimpleListProperty<>(allEntryTypes);

fields = new SimpleListProperty<>(FXCollections.observableArrayList(FieldFactory.getCommonFields()));

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.")));
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 +116,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 +155,26 @@ 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);
this.entryTypesToDelete.add(focusedItem.entryType().getValue());
}

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

public void resetAllCustomEntryTypes() {
this.preferencesService.clearAllBibEntryTypes();
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 +183,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();
// 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.getAllFields().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