Skip to content

Commit c83ea3f

Browse files
authored
Merge pull request #6152 from JabRef/allowReordering
Allow reordering of custom entry types fields
2 parents 593b235 + d1f4d99 commit c83ea3f

28 files changed

+491
-238
lines changed

src/main/java/org/jabref/gui/DragAndDropDataFormats.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
*/
1212
public class DragAndDropDataFormats {
1313

14+
public static final DataFormat FIELD = new DataFormat("dnd/org.jabref.model.entry.field.Field");
1415
public static final DataFormat GROUP = new DataFormat("dnd/org.jabref.model.groups.GroupTreeNode");
1516
public static final DataFormat LINKED_FILE = new DataFormat("dnd/org.jabref.model.entry.LinkedFile");
1617
public static final DataFormat ENTRIES = new DataFormat("dnd/org.jabref.model.entry.BibEntries");

src/main/java/org/jabref/gui/customentrytypes/CustomEntryTypeDialogViewModel.java

Lines changed: 50 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,12 @@
33
import java.util.ArrayList;
44
import java.util.Collection;
55
import java.util.Collections;
6-
import java.util.HashMap;
76
import java.util.List;
8-
import java.util.Map;
97
import java.util.function.Predicate;
108
import java.util.stream.Collectors;
119

1210
import javafx.beans.Observable;
13-
import javafx.beans.property.ListProperty;
1411
import javafx.beans.property.ObjectProperty;
15-
import javafx.beans.property.SimpleListProperty;
1612
import javafx.beans.property.SimpleObjectProperty;
1713
import javafx.beans.property.SimpleStringProperty;
1814
import javafx.beans.property.StringProperty;
@@ -34,7 +30,6 @@
3430
import org.jabref.model.entry.types.UnknownEntryType;
3531
import org.jabref.preferences.PreferencesService;
3632

37-
import com.tobiasdiez.easybind.EasyBind;
3833
import de.saxsys.mvvmfx.utils.validation.FunctionBasedValidator;
3934
import de.saxsys.mvvmfx.utils.validation.ValidationMessage;
4035
import de.saxsys.mvvmfx.utils.validation.ValidationStatus;
@@ -55,18 +50,14 @@ public Field fromString(String string) {
5550
}
5651
};
5752

58-
private final ListProperty<BibEntryType> entryTypes;
59-
private final ListProperty<Field> fields;
60-
private final ObjectProperty<BibEntryType> selectedEntryTypes = new SimpleObjectProperty<>();
61-
private final ListProperty<FieldViewModel> fieldsForType;
53+
private final ObservableList<Field> fieldsForAdding = FXCollections.observableArrayList(FieldFactory.getStandardFielsdsWithBibTexKey());
54+
private final ObjectProperty<CustomEntryTypeViewModel> selectedEntryType = new SimpleObjectProperty<>();
6255
private final ObjectProperty<Field> selectedFieldToAdd = new SimpleObjectProperty<>();
6356
private final StringProperty entryTypeToAdd = new SimpleStringProperty("");
64-
private final ObservableList<BibEntryType> allEntryTypes;
65-
private final ObservableList<FieldViewModel> allFieldsForType = FXCollections.observableArrayList(extractor -> new Observable[] {extractor.fieldName(), extractor.fieldType()});
6657
private final ObjectProperty<Field> newFieldToAdd = new SimpleObjectProperty<>();
6758
private final BibDatabaseMode mode;
68-
private final Map<BibEntryType, List<FieldViewModel>> typesWithFields = new HashMap<>();
69-
private final List<BibEntryType> typesToRemove = new ArrayList<>();
59+
private final ObservableList<CustomEntryTypeViewModel> entryTypesWithFields = FXCollections.observableArrayList(extractor -> new Observable[] {extractor.entryType(), extractor.fields()});
60+
private final List<BibEntryType> entryTypesToDelete = new ArrayList<>();
7061

7162
private final PreferencesService preferencesService;
7263
private final BibEntryTypesManager entryTypesManager;
@@ -79,40 +70,33 @@ public CustomEntryTypeDialogViewModel(BibDatabaseMode mode, PreferencesService p
7970
this.preferencesService = preferencesService;
8071
this.entryTypesManager = entryTypesManager;
8172

82-
Collection<BibEntryType> allTypes = entryTypesManager.getAllTypes(mode);
83-
allTypes.addAll(entryTypesManager.getAllCustomTypes(mode));
73+
addAllTypes();
8474

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

88-
fields = new SimpleListProperty<>(FXCollections.observableArrayList(FieldFactory.getCommonFields()));
82+
public void addAllTypes() {
83+
if (this.entryTypesWithFields.size() > 0) {
84+
this.entryTypesWithFields.clear();
85+
}
86+
Collection<BibEntryType> allTypes = entryTypesManager.getAllTypes(mode);
8987

9088
for (BibEntryType entryType : allTypes) {
91-
List<FieldViewModel> fields = entryType.getAllFields().stream().map(bibField -> new FieldViewModel(bibField.getField(), entryType.isRequired(bibField.getField()), bibField.getPriority(), entryType)).collect(Collectors.toList());
92-
typesWithFields.put(entryType, fields);
89+
CustomEntryTypeViewModel viewModel = new CustomEntryTypeViewModel(entryType);
90+
this.entryTypesWithFields.add(viewModel);
9391
}
94-
95-
this.fieldsForType = new SimpleListProperty<>(allFieldsForType);
96-
97-
EasyBind.subscribe(selectedEntryTypes, type -> {
98-
if (type != null) {
99-
allFieldsForType.setAll(typesWithFields.get(type));
100-
}
101-
});
102-
103-
Predicate<String> notEmpty = input -> (input != null) && !input.trim().isEmpty();
104-
entryTypeValidator = new FunctionBasedValidator<>(entryTypeToAdd, notEmpty, ValidationMessage.error(Localization.lang("Entry type cannot be empty. Please enter a name.")));
105-
fieldValidator = new FunctionBasedValidator<>(newFieldToAdd,
106-
input -> input != null && !input.getDisplayName().isEmpty(),
107-
ValidationMessage.error(Localization.lang("Field cannot be empty. Please enter a name.")));
10892
}
10993

110-
public ListProperty<BibEntryType> entryTypes() {
111-
return this.entryTypes;
94+
public ObservableList<CustomEntryTypeViewModel> entryTypes() {
95+
return this.entryTypesWithFields;
11296
}
11397

114-
public ListProperty<Field> fields() {
115-
return this.fields;
98+
public ObservableList<Field> fieldsForAdding() {
99+
return this.fieldsForAdding;
116100
}
117101

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

139123
public void addNewField() {
140124
Field field = newFieldToAdd.getValue();
141-
FieldViewModel model = new FieldViewModel(field, true, FieldPriority.IMPORTANT, selectedEntryTypes.getValue());
142-
typesWithFields.computeIfAbsent(selectedEntryTypes.getValue(), key -> new ArrayList<>()).add(model);
143-
allFieldsForType.add(model);
125+
FieldViewModel model = new FieldViewModel(field, true, FieldPriority.IMPORTANT);
126+
this.selectedEntryType.getValue().addField(model);
144127
newFieldToAddProperty().setValue(null);
145128
}
146129

147-
public void addNewCustomEntryType() {
130+
public CustomEntryTypeViewModel addNewCustomEntryType() {
148131
EntryType newentryType = new UnknownEntryType(entryTypeToAdd.getValue());
149132
BibEntryType type = new BibEntryType(newentryType, new ArrayList<>(), Collections.emptyList());
150-
this.allEntryTypes.add(type);
133+
CustomEntryTypeViewModel viewModel = new CustomEntryTypeViewModel(type);
134+
this.entryTypesWithFields.add(viewModel);
151135
this.entryTypeToAdd.setValue("");
152-
this.typesWithFields.put(type, new ArrayList<>());
153-
}
154136

155-
public ObjectProperty<BibEntryType> selectedEntryTypeProperty() {
156-
return this.selectedEntryTypes;
137+
return viewModel;
157138
}
158139

159-
public ListProperty<FieldViewModel> fieldsforTypesProperty() {
160-
return this.fieldsForType;
140+
public ObjectProperty<CustomEntryTypeViewModel> selectedEntryTypeProperty() {
141+
return this.selectedEntryType;
161142
}
162143

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

183-
public void removeEntryType(BibEntryType focusedItem) {
184-
typesToRemove.add(focusedItem);
185-
typesWithFields.remove(focusedItem);
186-
allEntryTypes.remove(focusedItem);
164+
public void removeEntryType(CustomEntryTypeViewModel focusedItem) {
165+
entryTypesWithFields.remove(focusedItem);
166+
entryTypesToDelete.add(focusedItem.entryType().getValue());
187167
}
188168

189169
public void removeField(FieldViewModel focusedItem) {
190-
typesWithFields.computeIfAbsent(selectedEntryTypes.getValue(), key -> new ArrayList<>()).remove(focusedItem);
191-
allFieldsForType.remove(focusedItem);
170+
selectedEntryType.getValue().removeField(focusedItem);
171+
}
172+
173+
public void resetAllCustomEntryTypes() {
174+
entryTypesManager.clearAllCustomEntryTypes(mode);
175+
preferencesService.clearBibEntryTypes(mode);
176+
entryTypesManager.addCustomOrModifiedTypes(preferencesService.loadBibEntryTypes(BibDatabaseMode.BIBTEX),
177+
preferencesService.loadBibEntryTypes(BibDatabaseMode.BIBLATEX));
192178
}
193179

194180
public void apply() {
195181

196-
for (var typeWithField : typesWithFields.entrySet()) {
197-
BibEntryType type = typeWithField.getKey();
198-
List<FieldViewModel> allFields = typeWithField.getValue();
182+
for (var typeWithField : entryTypesWithFields) {
183+
BibEntryType type = typeWithField.entryType().getValue();
184+
List<FieldViewModel> allFields = typeWithField.fields();
199185

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

207-
for (var type : typesToRemove) {
208-
entryTypesManager.removeCustomOrModifiedEntryType(type, mode);
193+
for (var entryType : entryTypesToDelete) {
194+
entryTypesManager.removeCustomOrModifiedEntryType(entryType, mode);
209195
}
210-
preferencesService.saveCustomEntryTypes();
196+
197+
preferencesService.saveCustomEntryTypes(entryTypesManager);
211198
// Reload types from preferences to make sure any modifications are present when reopening the dialog
212-
entryTypesManager.addCustomOrModifiedTypes(
213-
preferencesService.loadBibEntryTypes(BibDatabaseMode.BIBTEX),
214-
preferencesService.loadBibEntryTypes(BibDatabaseMode.BIBLATEX));
199+
entryTypesManager.addCustomOrModifiedTypes(preferencesService.loadBibEntryTypes(BibDatabaseMode.BIBTEX),
200+
preferencesService.loadBibEntryTypes(BibDatabaseMode.BIBLATEX));
215201
}
216202
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package org.jabref.gui.customentrytypes;
2+
3+
import java.util.List;
4+
import java.util.Objects;
5+
import java.util.stream.Collectors;
6+
7+
import javafx.beans.property.ObjectProperty;
8+
import javafx.beans.property.SimpleObjectProperty;
9+
import javafx.collections.FXCollections;
10+
import javafx.collections.ObservableList;
11+
12+
import org.jabref.model.entry.BibEntryType;
13+
14+
public class CustomEntryTypeViewModel {
15+
16+
private final ObjectProperty<BibEntryType> entryType = new SimpleObjectProperty<>();
17+
private final ObservableList<FieldViewModel> fields;
18+
19+
public CustomEntryTypeViewModel(BibEntryType entryType) {
20+
this.entryType.set(entryType);
21+
22+
List<FieldViewModel> allFieldsForType = entryType.getAllBibFields().stream().map(bibField -> new FieldViewModel(bibField.getField(), entryType.isRequired(bibField.getField()), bibField.getPriority())).collect(Collectors.toList());
23+
fields = FXCollections.observableArrayList((allFieldsForType));
24+
}
25+
26+
@Override
27+
public int hashCode() {
28+
return Objects.hash(entryType, fields);
29+
}
30+
31+
@Override
32+
public boolean equals(Object obj) {
33+
if (this == obj) {
34+
return true;
35+
}
36+
if (!(obj instanceof CustomEntryTypeViewModel)) {
37+
return false;
38+
}
39+
CustomEntryTypeViewModel other = (CustomEntryTypeViewModel) obj;
40+
return Objects.equals(entryType, other.entryType) && Objects.equals(fields, other.fields);
41+
}
42+
43+
public void addField(FieldViewModel field) {
44+
this.fields.add(field);
45+
}
46+
47+
public ObservableList<FieldViewModel> fields() {
48+
return this.fields;
49+
}
50+
51+
public ObjectProperty<BibEntryType> entryType() {
52+
return this.entryType;
53+
}
54+
55+
public void removeField(FieldViewModel focusedItem) {
56+
this.fields.remove(focusedItem);
57+
}
58+
59+
@Override
60+
public String toString() {
61+
return "CustomEntryTypeViewModel [entryType=" + entryType + ", fields=" + fields + "]";
62+
}
63+
64+
}

src/main/java/org/jabref/gui/customentrytypes/CustomizeEntryTypeDialog.fxml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,4 +96,5 @@
9696
<ButtonType fx:id="applyButton" buttonData="OK_DONE"
9797
text="%Apply"/>
9898
<ButtonType fx:constant="CANCEL"/>
99+
<ButtonType fx:id="resetButton" buttonData="LEFT" text="%Reset" />
99100
</DialogPane>

0 commit comments

Comments
 (0)