Skip to content

Commit

Permalink
Fix cursor jumping (#11282)
Browse files Browse the repository at this point in the history
* Modernize tests in BibEntryWriterTest

* Add tests for current behavior

* Improve comments and code

* Re-order tests

* Extract method

* Fix handling of ##

* Fix detection of multiline fields

* Fix space removal

* Fix trimming of content

* Codestyle: Tests

* Remove standard cleanups

* Add CHANGELOG.md entry

* Right trim multiline fields

* Add links to CHANGELOG.md

* Test case cleanup

* Fix whitespace formatting

* Reformat comment (and add TODO marker)

* More whitespace tweaking

* Use our builder if possible

* Fix whitespace at import

* Try to get gradle executing all tests on GitHub CI

* Tweak parallel tests

* Optimize build

* Trim whole field content

* Fix variable name

* Use `toList()`

* More modern BibEntry generating

* Better linebreaks

* Fix logic

* Fix an (unlreated) test

* Update CHANGELOG.md

* Update build.gradle

* Use TrimWhitespaceFormatter() instead of internal "trim()"

* Fix typo

* Simplify code

* Try to make code more readable

* Add diffing for correct caret repositioning

* Fix CHANGELOG

* Improve code

* Refine text

* Fix binding issue

* Fix BackupManager to modify the UI

Co-authored-by: Christoph <[email protected]>
Co-authored-by: Carl Christian Snethlage <[email protected]>

* Works for simple case

Co-authored-by: Christoph <[email protected]>
Co-authored-by: Carl Christian Snethlage <[email protected]>

* FieldFormatter not used at reading any more

Co-authored-by: Christoph <[email protected]>

* Convert FieldContentFormatter to NormalizeWhitespaceFormatter

Co-authored-by: Christoph <[email protected]>

* Make use of new change-aware bindings in other text-based editors, too

Co-authored-by: Christoph <[email protected]>

* Fix tinylog

* Fix when end is trimmed

Co-authored-by: Christoph <[email protected]>

* Fix CHANGELOG.md

Co-authored-by: Christoph <[email protected]>

* Adapt tests to new behavior

Co-authored-by: Christoph <[email protected]>

* Fix imports

* Fix paranthethes

* Fix WTF

* fix test

* fix autosave thread

* Remove dead code

* Improve code

- fix method names
- Optional `get()` to `orElseThrow()`
- List -> Collection
- Remove obsoelte "COMMENT" and "CUSTOM_FIELD" property

* Fix semantics of "VERBATIM" and remove 1:1 relation of property and field

* Fix casing (and variable)

* More FieldProperty cleanup

* Enhanced KeyField support (required for customized entry types)

* Fix fixing of double white spaces

* Prepare: Fix cleanup of imported entries

- introduce ParserFetcher interface
- make ImportCleanup an abstract class
- improve MathSicNet test code

* Add TODOs

* Add normalizing of white spaces to import

- Consistent naming if "preferences" (not prefs, not preferenceService)

* Really cleanup the entry

* Adapt MathSciNetTest to new normalizing approach

* Fix DBLP tests

* Use "List.of()" instead of "Collections.singletonList"

* Add @nonnull annotation

* Remove obsolete JavaDoc comment

* Fix NPE at tests

* Incease heap space (again)

* Fix missing dependency injection

* Fix NPE

* Fix checkstyle

* Refine comment

* Add more comments

---------

Co-authored-by: Christoph <[email protected]>
Co-authored-by: Carl Christian Snethlage <[email protected]>
  • Loading branch information
3 people authored Jun 17, 2024
1 parent 7ef4976 commit d51b52b
Show file tree
Hide file tree
Showing 79 changed files with 1,021 additions and 734 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,15 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv
- We fixed an issue where drag and dropping entries from one library to another was not always working. [#11254](https://github.com/JabRef/jabref/issues/11254)
- We fixed an issue where drag and dropping entries created a shallow copy. [#11160](https://github.com/JabRef/jabref/issues/11160)
- We fixed an issue where imports to a custom group would only work for the first entry [#11085](https://github.com/JabRef/jabref/issues/11085), [#11269](https://github.com/JabRef/jabref/issues/11269)
- We fixed an issue when cursor jumped to the beginning of the line. [#5904](https://github.com/JabRef/jabref/issues/5904)
- We fixed an issue where a new entry was not added to the selected group [#8933](https://github.com/JabRef/jabref/issues/8933)
- We fixed an issue where the horizontal position of the Entry Preview inside the entry editor was not remembered across restarts [#11281](https://github.com/JabRef/jabref/issues/11281)
- We fixed an issue where the search index was not updated after linking PDF files. [#11317](https://github.com/JabRef/jabref/pull/11317)
- We fixed rendering of (first) author with a single letter surname. [forum#4330](https://discourse.jabref.org/t/correct-rendering-of-first-author-with-a-single-letter-surname/4330)
- We fixed that the import of the related articles tab sometimes used the wrong library mode. [#11282](https://github.com/JabRef/jabref/pull/11282)
- We fixed an issue where the entry editor context menu was not shown correctly when JabRef is opened on a second, extended screen [#11323](https://github.com/JabRef/jabref/issues/11323), [#11174](https://github.com/JabRef/jabref/issues/11174)
- We fixe an issue where the value of "Override default font settings" was not applied on startup [#11344](https://github.com/JabRef/jabref/issues/11344)
- We fixed an issue where the value of "Override default font settings" was not applied on startup [#11344](https://github.com/JabRef/jabref/issues/11344)
- We fixed an issue when "Library changed on disk" appeared after a save by JabRef. [#4877](https://github.com/JabRef/jabref/issues/4877)

### Removed

Expand Down
8 changes: 5 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -530,9 +530,11 @@ testlogger {

tasks.withType(Test) {
reports.html.outputLocation.set(file("${reporting.baseDir}/${name}"))
// Enable parallel tests. See https://docs.gradle.org/8.1/userguide/performance.html#execute_tests_in_parallel for details.
maxParallelForks = Runtime.runtime.availableProcessors() - 1
ignoreFailures = true
// Enable parallel tests (on desktop).
// See https://docs.gradle.org/8.1/userguide/performance.html#execute_tests_in_parallel for details.
if (!providers.environmentVariable("CI").isPresent()) {
maxParallelForks = Math.max(Runtime.runtime.availableProcessors() - 1, 1)
}
}

tasks.register('databaseTest', Test) {
Expand Down
5 changes: 3 additions & 2 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
org.gradle.vs.watch=true

# hint by https://docs.gradle.org/current/userguide/performance.html#increase_the_heap_size
org.gradle.jvmargs=-Xmx4096M
# Hint by https://docs.gradle.org/current/userguide/performance.html#increase_the_heap_size
# Otherwise, one gets "Java heap space" errors.
org.gradle.jvmargs=-Xmx6096M

# hint by https://docs.gradle.org/current/userguide/performance.html#enable_configuration_cache
# Does not work:
Expand Down
18 changes: 15 additions & 3 deletions src/main/java/org/jabref/gui/autosaveandbackup/BackupManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@
import org.jabref.logic.util.BackupFileType;
import org.jabref.logic.util.CoarseChangeFilter;
import org.jabref.logic.util.io.BackupFileUtil;
import org.jabref.model.database.BibDatabase;
import org.jabref.model.database.BibDatabaseContext;
import org.jabref.model.database.event.BibDatabaseContextChangedEvent;
import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.BibEntryTypesManager;
import org.jabref.model.metadata.SaveOrder;
import org.jabref.model.metadata.SelfContainedSaveOrder;
Expand Down Expand Up @@ -67,7 +69,7 @@ public class BackupManager {
private final LibraryTab libraryTab;

// Contains a list of all backup paths
// During a write, the less recent backup file is deleted
// During writing, the less recent backup file is deleted
private final Queue<Path> backupFilesQueue = new LinkedBlockingQueue<>();
private boolean needsBackup = false;

Expand Down Expand Up @@ -259,10 +261,19 @@ void performBackup(Path backupPath) {
.withSaveOrder(saveOrder)
.withReformatOnSave(preferences.getLibraryPreferences().shouldAlwaysReformatOnSave());

// "Clone" the database context
// We "know" that "only" the BibEntries might be changed during writing (see [org.jabref.logic.exporter.BibDatabaseWriter.savePartOfDatabase])
List<BibEntry> list = bibDatabaseContext.getDatabase().getEntries().stream()
.map(BibEntry::clone)
.map(BibEntry.class::cast)
.toList();
BibDatabase bibDatabaseClone = new BibDatabase(list);
BibDatabaseContext bibDatabaseContextClone = new BibDatabaseContext(bibDatabaseClone, bibDatabaseContext.getMetaData());

Charset encoding = bibDatabaseContext.getMetaData().getEncoding().orElse(StandardCharsets.UTF_8);
// We want to have successful backups only
// Thus, we do not use a plain "FileWriter", but the "AtomicFileWriter"
// Example: What happens if one hard powers off the machine (or kills the jabref process) during the write of the backup?
// Example: What happens if one hard powers off the machine (or kills the jabref process) during writing of the backup?
// This MUST NOT create a broken backup file that then jabref wants to "restore" from?
try (Writer writer = new AtomicFileWriter(backupPath, encoding, false)) {
BibWriter bibWriter = new BibWriter(writer, bibDatabaseContext.getDatabase().getNewLineSeparator());
Expand All @@ -272,7 +283,8 @@ void performBackup(Path backupPath) {
preferences.getFieldPreferences(),
preferences.getCitationKeyPatternPreferences(),
entryTypesManager)
.saveDatabase(bibDatabaseContext);
// we save the clone to prevent the original database (and thus the UI) from being changed
.saveDatabase(bibDatabaseContextClone);
backupFilesQueue.add(backupPath);

// We wrote the file successfully
Expand Down
5 changes: 1 addition & 4 deletions src/main/java/org/jabref/gui/entryeditor/EntryEditor.java
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ private List<EntryEditorTab> createTabs() {
tabs.add(new SciteTab(preferencesService, taskExecutor, dialogService));
tabs.add(new CitationRelationsTab(dialogService, databaseContext,
undoManager, stateManager, fileMonitor, preferencesService, libraryTab, taskExecutor));
tabs.add(new RelatedArticlesTab(entryEditorPreferences, preferencesService, dialogService, taskExecutor));
tabs.add(new RelatedArticlesTab(databaseContext, entryEditorPreferences, preferencesService, dialogService, taskExecutor));
sourceTab = new SourceTab(
databaseContext,
undoManager,
Expand Down Expand Up @@ -361,9 +361,6 @@ private void adaptVisibleTabs() {
}
}

/**
* @return the currently edited entry
*/
public BibEntry getCurrentlyEditedEntry() {
return currentlyEditedEntry;
}
Expand Down
12 changes: 8 additions & 4 deletions src/main/java/org/jabref/gui/entryeditor/RelatedArticlesTab.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@
import org.jabref.logic.importer.ImportCleanup;
import org.jabref.logic.importer.fetcher.MrDLibFetcher;
import org.jabref.logic.l10n.Localization;
import org.jabref.model.database.BibDatabase;
import org.jabref.model.database.BibDatabaseModeDetection;
import org.jabref.model.database.BibDatabaseContext;
import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.field.StandardField;
import org.jabref.preferences.MrDlibPreferences;
Expand All @@ -47,13 +46,18 @@ public class RelatedArticlesTab extends EntryEditorTab {
private final DialogService dialogService;
private final TaskExecutor taskExecutor;

private final BibDatabaseContext databaseContext;

private final PreferencesService preferencesService;
private final EntryEditorPreferences entryEditorPreferences;

public RelatedArticlesTab(EntryEditorPreferences entryEditorPreferences,
public RelatedArticlesTab(BibDatabaseContext databaseContext,
EntryEditorPreferences entryEditorPreferences,
PreferencesService preferencesService,
DialogService dialogService,
TaskExecutor taskExecutor) {
this.databaseContext = databaseContext;

this.dialogService = dialogService;
this.taskExecutor = taskExecutor;

Expand Down Expand Up @@ -82,7 +86,7 @@ private StackPane getRelatedArticlesPane(BibEntry entry) {
.wrap(() -> fetcher.performSearch(entry))
.onRunning(() -> progress.setVisible(true))
.onSuccess(relatedArticles -> {
ImportCleanup cleanup = ImportCleanup.targeting(BibDatabaseModeDetection.inferMode(new BibDatabase(List.of(entry))));
ImportCleanup cleanup = ImportCleanup.targeting(databaseContext.getMode(), preferencesService.getFieldPreferences());
cleanup.doPostCleanup(relatedArticles);
progress.setVisible(false);
root.getChildren().add(getRelatedArticleInfo(relatedArticles, fetcher));
Expand Down
54 changes: 27 additions & 27 deletions src/main/java/org/jabref/gui/externalfiles/ImportHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public class ImportHandler {

private static final Logger LOGGER = LoggerFactory.getLogger(ImportHandler.class);
private final BibDatabaseContext bibDatabaseContext;
private final PreferencesService preferencesService;
private final PreferencesService preferences;
private final FileUpdateMonitor fileUpdateMonitor;
private final ExternalFilesEntryLinker linker;
private final ExternalFilesContentImporter contentImporter;
Expand All @@ -75,22 +75,22 @@ public class ImportHandler {
private final TaskExecutor taskExecutor;

public ImportHandler(BibDatabaseContext database,
PreferencesService preferencesService,
PreferencesService preferences,
FileUpdateMonitor fileupdateMonitor,
UndoManager undoManager,
StateManager stateManager,
DialogService dialogService,
TaskExecutor taskExecutor) {

this.bibDatabaseContext = database;
this.preferencesService = preferencesService;
this.preferences = preferences;
this.fileUpdateMonitor = fileupdateMonitor;
this.stateManager = stateManager;
this.dialogService = dialogService;
this.taskExecutor = taskExecutor;

this.linker = new ExternalFilesEntryLinker(preferencesService.getFilePreferences(), database, dialogService);
this.contentImporter = new ExternalFilesContentImporter(preferencesService.getImportFormatPreferences());
this.linker = new ExternalFilesEntryLinker(preferences.getFilePreferences(), database, dialogService);
this.contentImporter = new ExternalFilesContentImporter(preferences.getImportFormatPreferences());
this.undoManager = undoManager;
}

Expand Down Expand Up @@ -185,7 +185,7 @@ private BibEntry createEmptyEntryWithLink(Path file) {
* There is no automatic download done.
*/
public void importEntries(List<BibEntry> entries) {
ImportCleanup cleanup = ImportCleanup.targeting(bibDatabaseContext.getMode());
ImportCleanup cleanup = ImportCleanup.targeting(bibDatabaseContext.getMode(), preferences.getFieldPreferences());
cleanup.doPostCleanup(entries);
importCleanedEntries(entries);
}
Expand Down Expand Up @@ -217,7 +217,7 @@ private void importEntryWithDuplicateCheck(BibDatabaseContext bibDatabaseContext

@VisibleForTesting
BibEntry cleanUpEntry(BibDatabaseContext bibDatabaseContext, BibEntry entry) {
ImportCleanup cleanup = ImportCleanup.targeting(bibDatabaseContext.getMode());
ImportCleanup cleanup = ImportCleanup.targeting(bibDatabaseContext.getMode(), preferences.getFieldPreferences());
return cleanup.doPostCleanup(entry);
}

Expand Down Expand Up @@ -246,26 +246,26 @@ public Optional<BibEntry> handleDuplicates(BibDatabaseContext bibDatabaseContext
}

public DuplicateDecisionResult getDuplicateDecision(BibEntry originalEntry, BibEntry duplicateEntry, BibDatabaseContext bibDatabaseContext, DuplicateResolverDialog.DuplicateResolverResult decision) {
DuplicateResolverDialog dialog = new DuplicateResolverDialog(duplicateEntry, originalEntry, DuplicateResolverDialog.DuplicateResolverType.IMPORT_CHECK, bibDatabaseContext, stateManager, dialogService, preferencesService);
DuplicateResolverDialog dialog = new DuplicateResolverDialog(duplicateEntry, originalEntry, DuplicateResolverDialog.DuplicateResolverType.IMPORT_CHECK, bibDatabaseContext, stateManager, dialogService, preferences);
if (decision == BREAK) {
decision = dialogService.showCustomDialogAndWait(dialog).orElse(BREAK);
}
if (preferencesService.getMergeDialogPreferences().shouldMergeApplyToAllEntries()) {
preferencesService.getMergeDialogPreferences().setAllEntriesDuplicateResolverDecision(decision);
if (preferences.getMergeDialogPreferences().shouldMergeApplyToAllEntries()) {
preferences.getMergeDialogPreferences().setAllEntriesDuplicateResolverDecision(decision);
}
return new DuplicateDecisionResult(decision, dialog.getMergedEntry());
}

public void setAutomaticFields(List<BibEntry> entries) {
UpdateField.setAutomaticFields(
entries,
preferencesService.getOwnerPreferences(),
preferencesService.getTimestampPreferences()
preferences.getOwnerPreferences(),
preferences.getTimestampPreferences()
);
}

public void downloadLinkedFiles(BibEntry entry) {
if (preferencesService.getFilePreferences().shouldDownloadLinkedFiles()) {
if (preferences.getFilePreferences().shouldDownloadLinkedFiles()) {
entry.getFiles().stream()
.filter(LinkedFile::isOnlineLink)
.forEach(linkedFile ->
Expand All @@ -275,7 +275,7 @@ public void downloadLinkedFiles(BibEntry entry) {
bibDatabaseContext,
taskExecutor,
dialogService,
preferencesService
preferences
).download(false)
);
}
Expand All @@ -300,19 +300,19 @@ private void addToGroups(List<BibEntry> entries, Collection<GroupTreeNode> group
* @param entries entries to generate keys for
*/
private void generateKeys(List<BibEntry> entries) {
if (!preferencesService.getImporterPreferences().isGenerateNewKeyOnImport()) {
if (!preferences.getImporterPreferences().isGenerateNewKeyOnImport()) {
return;
}
CitationKeyGenerator keyGenerator = new CitationKeyGenerator(
bibDatabaseContext.getMetaData().getCiteKeyPatterns(preferencesService.getCitationKeyPatternPreferences()
.getKeyPatterns()),
bibDatabaseContext.getMetaData().getCiteKeyPatterns(preferences.getCitationKeyPatternPreferences()
.getKeyPatterns()),
bibDatabaseContext.getDatabase(),
preferencesService.getCitationKeyPatternPreferences());
preferences.getCitationKeyPatternPreferences());
entries.forEach(keyGenerator::generateAndSetKey);
}

public List<BibEntry> handleBibTeXData(String entries) {
BibtexParser parser = new BibtexParser(preferencesService.getImportFormatPreferences(), fileUpdateMonitor);
BibtexParser parser = new BibtexParser(preferences.getImportFormatPreferences(), fileUpdateMonitor);
try {
List<BibEntry> result = parser.parseEntries(new ByteArrayInputStream(entries.getBytes(StandardCharsets.UTF_8)));
Collection<BibtexString> stringConstants = parser.getStringValues();
Expand Down Expand Up @@ -370,9 +370,9 @@ public List<BibEntry> handleStringData(String data) throws FetcherException {
private List<BibEntry> tryImportFormats(String data) {
try {
ImportFormatReader importFormatReader = new ImportFormatReader(
preferencesService.getImporterPreferences(),
preferencesService.getImportFormatPreferences(),
preferencesService.getCitationKeyPatternPreferences(),
preferences.getImporterPreferences(),
preferences.getImportFormatPreferences(),
preferences.getCitationKeyPatternPreferences(),
fileUpdateMonitor
);
UnknownFormatImport unknownFormatImport = importFormatReader.importUnknownFormat(data);
Expand All @@ -385,19 +385,19 @@ private List<BibEntry> tryImportFormats(String data) {

private List<BibEntry> fetchByDOI(DOI doi) throws FetcherException {
LOGGER.info("Found DOI identifier in clipboard");
Optional<BibEntry> entry = new DoiFetcher(preferencesService.getImportFormatPreferences()).performSearchById(doi.getDOI());
Optional<BibEntry> entry = new DoiFetcher(preferences.getImportFormatPreferences()).performSearchById(doi.getDOI());
return OptionalUtil.toList(entry);
}

private List<BibEntry> fetchByArXiv(ArXivIdentifier arXivIdentifier) throws FetcherException {
LOGGER.info("Found arxiv identifier in clipboard");
Optional<BibEntry> entry = new ArXivFetcher(preferencesService.getImportFormatPreferences()).performSearchById(arXivIdentifier.getNormalizedWithoutVersion());
Optional<BibEntry> entry = new ArXivFetcher(preferences.getImportFormatPreferences()).performSearchById(arXivIdentifier.getNormalizedWithoutVersion());
return OptionalUtil.toList(entry);
}

private List<BibEntry> fetchByISBN(ISBN isbn) throws FetcherException {
LOGGER.info("Found ISBN identifier in clipboard");
Optional<BibEntry> entry = new IsbnFetcher(preferencesService.getImportFormatPreferences()).performSearchById(isbn.getNormalized());
Optional<BibEntry> entry = new IsbnFetcher(preferences.getImportFormatPreferences()).performSearchById(isbn.getNormalized());
return OptionalUtil.toList(entry);
}

Expand All @@ -410,8 +410,8 @@ public void importEntriesWithDuplicateCheck(BibDatabaseContext database, List<Bi
firstEntry = false;
continue;
}
if (preferencesService.getMergeDialogPreferences().shouldMergeApplyToAllEntries()) {
DuplicateResolverDialog.DuplicateResolverResult decision = preferencesService.getMergeDialogPreferences().getAllEntriesDuplicateResolverDecision();
if (preferences.getMergeDialogPreferences().shouldMergeApplyToAllEntries()) {
DuplicateResolverDialog.DuplicateResolverResult decision = preferences.getMergeDialogPreferences().getAllEntriesDuplicateResolverDecision();
LOGGER.debug("Not first entry, pref flag is true, we use {}", decision);
importEntryWithDuplicateCheck(database, entry, decision);
} else {
Expand Down
Loading

0 comments on commit d51b52b

Please sign in to comment.