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

Validates the file path of a TexGroup and fixes Texgroup's "Library has been modified by another program" #6586

Merged
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
23557f9
process GROUPSTREE and GROUPSTREE_LEGACY at the very end
systemoperator Jun 4, 2020
2eac649
changelog
systemoperator Jun 4, 2020
01c36a3
refactoring (part 1)
systemoperator Jun 4, 2020
44b8896
refactoring (part 2)
systemoperator Jun 4, 2020
f36ece6
validator for aux file added, checking for empty field and using the …
systemoperator Jun 4, 2020
f554c95
changelog
systemoperator Jun 4, 2020
53cd9ad
extension
systemoperator Jun 4, 2020
ad11243
formatting file according to JabRef's formatter for Eclipse
systemoperator Jun 5, 2020
d20388f
Revert "formatting file according to JabRef's formatter for Eclipse"
systemoperator Jun 5, 2020
8b7063d
more checks added + checkstyle improved
systemoperator Jun 5, 2020
7b65150
refactoring
systemoperator Jun 5, 2020
5b7d80e
Merge branch 'systemoperator-texgroup' into systemoperator-texgroup-v…
systemoperator Jun 5, 2020
fe895cf
update
systemoperator Jun 5, 2020
db60939
refactoring
systemoperator Jun 5, 2020
f593b13
refactoring
systemoperator Jun 5, 2020
586d55b
l10n
systemoperator Jun 5, 2020
6a82156
update
systemoperator Jun 5, 2020
f092108
refactoring
systemoperator Jun 5, 2020
74f05ea
cleanup (checkstyle)
systemoperator Jun 5, 2020
ba367ad
refactor
systemoperator Jun 5, 2020
c120c45
refactor to sorting mechanism
systemoperator Jun 5, 2020
ec8933e
refactor (without stream)
systemoperator Jun 5, 2020
01cdb44
remove brackets
systemoperator Jun 5, 2020
e7a3c3f
test created
systemoperator Jun 5, 2020
49c3a2b
finalize test
systemoperator Jun 5, 2020
26342ab
formatting
systemoperator Jun 5, 2020
aac9ffc
formatting
systemoperator Jun 5, 2020
f98466a
checkstyle
systemoperator Jun 5, 2020
3f2f46f
refactoring
systemoperator Jun 17, 2020
5a3548a
Merge branch 'master' into systemoperator-texgroup-validation
systemoperator Jun 17, 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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve
- We fixed an issue where "null" appeared in generated BibTeX keys. [#6459](https://github.com/JabRef/jabref/issues/6459)
- We fixed an issue where the authors' names were incorrectly displayed in the authors' column when they were bracketed. [#6465](https://github.com/JabRef/jabref/issues/6465) [#6459](https://github.com/JabRef/jabref/issues/6459)
- We fixed an issue where importing certain unlinked files would result in an exception [#5815](https://github.com/JabRef/jabref/issues/5815)
- We fixed an issue with the creation of a group of cited entries which incorrectly showed the message that the library had been modified externally whenever saving the library. [#6420](https://github.com/JabRef/jabref/issues/6420)
- We fixed an issue with the creation of a group of cited entries. Now the file path to an aux file gets validated. [#6585](https://github.com/JabRef/jabref/issues/6585)

### Removed

Expand Down
1 change: 1 addition & 0 deletions src/main/java/org/jabref/gui/groups/GroupDialogView.java
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ public void initialize() {
validationVisualizer.initVisualization(viewModel.keywordRegexValidationStatus(), keywordGroupSearchTerm);
validationVisualizer.initVisualization(viewModel.keywordSearchTermEmptyValidationStatus(), keywordGroupSearchTerm);
validationVisualizer.initVisualization(viewModel.keywordFieldEmptyValidationStatus(), keywordGroupSearchField);
validationVisualizer.initVisualization(viewModel.texGroupFilePathValidatonStatus(), texGroupFilePath);
nameField.requestFocus();
});

Expand Down
35 changes: 33 additions & 2 deletions src/main/java/org/jabref/gui/groups/GroupDialogViewModel.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.jabref.gui.groups;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
Expand Down Expand Up @@ -98,6 +99,7 @@ public class GroupDialogViewModel {
private Validator keywordSearchTermEmptyValidator;
private Validator searchRegexValidator;
private Validator searchSearchTermEmptyValidator;
private Validator texGroupFilePathValidator;
private final CompositeValidator validator = new CompositeValidator();

private final DialogService dialogService;
Expand Down Expand Up @@ -212,8 +214,25 @@ private void setupValidation() {
input -> !StringUtil.isNullOrEmpty(input),
ValidationMessage.error(String.format("%s > %n %s",
Localization.lang("Free search expression"),
Localization.lang("Search term is empty.")
)));
Localization.lang("Search term is empty."))));

texGroupFilePathValidator = new FunctionBasedValidator<>(
texGroupFilePathProperty,
input -> {
if (StringUtil.isBlank(input)) {
return false;
} else {
Copy link
Member

Choose a reason for hiding this comment

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

@stefan-kolb Would review here: "Fail fast". Not endless nested if/else statements, but just exit early.

Therefore, I proposed:

if (StringUtil.isBlank(input)) {
  return false;
}

Think, I will start another PR with this and the other code style thing and we can have the discussion there --> we need to get this fix in soon.

Path texFilePath = preferencesService.getWorkingDir().resolve(input);
Optional<String> fileExtension = FileUtil.getFileExtension(input);
if (fileExtension.isEmpty() || !fileExtension.get().toLowerCase().equals("aux")) {
return false;
} else if (!Files.isRegularFile(texFilePath)) {
systemoperator marked this conversation as resolved.
Show resolved Hide resolved
return false;
}
return true;
}
},
ValidationMessage.error(Localization.lang("Please provide a valid aux file.")));

validator.addValidators(nameValidator, sameNameValidator);

Expand All @@ -232,6 +251,14 @@ private void setupValidation() {
validator.removeValidators(keywordFieldEmptyValidator, keywordRegexValidator, keywordSearchTermEmptyValidator);
}
});

typeTexProperty.addListener((obs, oldValue, isSelected) -> {
if (isSelected) {
validator.addValidators(texGroupFilePathValidator);
} else {
validator.removeValidators(texGroupFilePathValidator);
}
});
}

public void validationHandler(Event event) {
Expand Down Expand Up @@ -439,6 +466,10 @@ public ValidationStatus keywordSearchTermEmptyValidationStatus() {
return keywordSearchTermEmptyValidator.getValidationStatus();
}

public ValidationStatus texGroupFilePathValidatonStatus() {
return texGroupFilePathValidator.getValidationStatus();
}

public StringProperty nameProperty() {
return nameProperty;
}
Expand Down
71 changes: 34 additions & 37 deletions src/main/java/org/jabref/logic/importer/util/MetaDataParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.jabref.logic.cleanup.Cleanups;
import org.jabref.logic.importer.ParseException;
Expand Down Expand Up @@ -49,68 +52,62 @@ public MetaData parse(MetaData metaData, Map<String, String> data, Character key
List<String> defaultCiteKeyPattern = new ArrayList<>();
Map<EntryType, List<String>> nonDefaultCiteKeyPatterns = new HashMap<>();

for (Map.Entry<String, String> entry : data.entrySet()) {
// process groups (GROUPSTREE and GROUPSTREE_LEGACY) at the very end (otherwise it can happen that not all dependent data are set)
Stream<Map.Entry<String, String>> entrySetStream = data.entrySet().stream().sorted(groupsLast());
systemoperator marked this conversation as resolved.
Show resolved Hide resolved

for (Map.Entry<String, String> entry : entrySetStream.collect(Collectors.toList())) {
List<String> value = getAsList(entry.getValue());

if (entry.getKey().startsWith(MetaData.PREFIX_KEYPATTERN)) {
EntryType entryType = EntryTypeFactory.parse(entry.getKey().substring(MetaData.PREFIX_KEYPATTERN.length()));
nonDefaultCiteKeyPatterns.put(entryType, Collections.singletonList(getSingleItem(value)));
continue;
} else if (entry.getKey().startsWith(MetaData.FILE_DIRECTORY + '-')) {
// The user name comes directly after "FILE_DIRECTORY-"
String user = entry.getKey().substring(MetaData.FILE_DIRECTORY.length() + 1);
metaData.setUserFileDirectory(user, getSingleItem(value));
continue;
} else if (entry.getKey().startsWith(MetaData.SELECTOR_META_PREFIX)) {
metaData.addContentSelector(ContentSelectors.parse(FieldFactory.parseField(entry.getKey().substring(MetaData.SELECTOR_META_PREFIX.length())), StringUtil.unquote(entry.getValue(), MetaData.ESCAPE_CHARACTER)));
continue;
} else if (entry.getKey().startsWith(MetaData.FILE_DIRECTORY + "Latex-")) {
// The user name comes directly after "FILE_DIRECTORYLatex-"
String user = entry.getKey().substring(MetaData.FILE_DIRECTORY.length() + 6);
Path path = Path.of(getSingleItem(value)).normalize();
metaData.setLatexFileDirectory(user, path);
continue;
}

switch (entry.getKey()) {
case MetaData.GROUPSTREE:
case MetaData.GROUPSTREE_LEGACY:
metaData.setGroups(GroupsParser.importGroups(value, keywordSeparator, fileMonitor, metaData));
break;
case MetaData.SAVE_ACTIONS:
metaData.setSaveActions(Cleanups.parse(value));
break;
case MetaData.DATABASE_TYPE:
metaData.setMode(BibDatabaseMode.parse(getSingleItem(value)));
break;
case MetaData.KEYPATTERNDEFAULT:
defaultCiteKeyPattern = Collections.singletonList(getSingleItem(value));
break;
case MetaData.PROTECTED_FLAG_META:
if (Boolean.parseBoolean(getSingleItem(value))) {
metaData.markAsProtected();
} else {
metaData.markAsNotProtected();
}
break;
case MetaData.FILE_DIRECTORY:
metaData.setDefaultFileDirectory(getSingleItem(value));
break;
case MetaData.SAVE_ORDER_CONFIG:
metaData.setSaveOrderConfig(SaveOrderConfig.parse(value));
break;
default:
// Keep meta data items that we do not know in the file
metaData.putUnknownMetaDataItem(entry.getKey(), value);
} else if (entry.getKey().equals(MetaData.SAVE_ACTIONS)) {
Copy link
Member

Choose a reason for hiding this comment

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

Can we keep the switch (entry.getKey) somehow? Maybe nested in an else branch?

You can use the new Java14 switch: https://openjdk.java.net/jeps/361

(File needs to be added to

<property name="fileNamePattern" value="AuthorAndsReplacer.java|Ordinal.java|EntryTypeView.java" />
then)

Copy link
Member

Choose a reason for hiding this comment

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

This is still a huge p.i.t.a.
Checkstyle really needs to keep up, people start getting tired of these workarounds.
Some background information, if you are interested: checkstyle/checkstyle#6615

Copy link
Member

Choose a reason for hiding this comment

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

The key problem is here that switch cases are not executed in order. That's the reason for the if else

Copy link
Member

Choose a reason for hiding this comment

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

In the concrete case here, it is always checked for entry.getKey(). Please check the diff:

grafik

The wrong order was at that diff - completely unrelated to my proposal!

grafik

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, the switch statement could be reintroduced (and simplified). Before this fix, the code was structured really confusing and looked error-prone. So I decided to create this consistent and simplified version, which I find quite acceptable.

Copy link
Member

Choose a reason for hiding this comment

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

I meant only for the lower part; not with the xxxx continue statements. Just for the endless chain of else if (entry.getKey().equeals(MetaData.X)) chains, where only X is different from the checks.

There is ALWAYS entry.getKey() compared from line 75 to line 92 (or did I see something wrong?).

This is just a matter of taste. Maybe, I'll just do it and open another PR to have the discussions there. Should not be a show stopper for us now.

metaData.setSaveActions(Cleanups.parse(value));
} else if (entry.getKey().equals(MetaData.DATABASE_TYPE)) {
metaData.setMode(BibDatabaseMode.parse(getSingleItem(value)));
} else if (entry.getKey().equals(MetaData.KEYPATTERNDEFAULT)) {
defaultCiteKeyPattern = Collections.singletonList(getSingleItem(value));
} else if (entry.getKey().equals(MetaData.PROTECTED_FLAG_META)) {
if (Boolean.parseBoolean(getSingleItem(value))) {
metaData.markAsProtected();
} else {
metaData.markAsNotProtected();
}
} else if (entry.getKey().equals(MetaData.FILE_DIRECTORY)) {
metaData.setDefaultFileDirectory(getSingleItem(value));
} else if (entry.getKey().equals(MetaData.SAVE_ORDER_CONFIG)) {
metaData.setSaveOrderConfig(SaveOrderConfig.parse(value));
} else if (entry.getKey().equals(MetaData.GROUPSTREE) || entry.getKey().equals(MetaData.GROUPSTREE_LEGACY)) {
metaData.setGroups(GroupsParser.importGroups(value, keywordSeparator, fileMonitor, metaData));
} else {
// Keep meta data items that we do not know in the file
metaData.putUnknownMetaDataItem(entry.getKey(), value);
}
}

if (!defaultCiteKeyPattern.isEmpty() || !nonDefaultCiteKeyPatterns.isEmpty()) {
metaData.setCiteKeyPattern(defaultCiteKeyPattern, nonDefaultCiteKeyPatterns);
}

return metaData;
}

private static Comparator<? super Map.Entry<String, String>> groupsLast() {
return (s1, s2) -> MetaData.GROUPSTREE.equals(s1.getKey()) || MetaData.GROUPSTREE_LEGACY.equals(s1.getKey()) ? 1 :
MetaData.GROUPSTREE.equals(s2.getKey()) || MetaData.GROUPSTREE_LEGACY.equals(s2.getKey()) ? -1 : 0;
}

/**
* Returns the first item in the list.
* If the specified list does not contain exactly one item, then a {@link ParseException} will be thrown.
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/l10n/JabRef_en.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2065,6 +2065,7 @@ Specified\ keywords=Specified keywords
Cited\ entries=Cited entries
Search\ term\ is\ empty.=Search term is empty.
Invalid\ regular\ expression.=Invalid regular expression.
Please\ provide\ a\ valid\ aux\ file.=Please provide a valid aux file.
Keyword\ delimiter=Keyword delimiter
Hierarchical\ keyword\ delimiter=Hierarchical keyword delimiter
Escape\ ampersands=Escape ampersands
Expand Down