From 5759e01a658687be795608c647dc45c535ab1293 Mon Sep 17 00:00:00 2001 From: m-mauersberger Date: Fri, 4 Sep 2020 09:39:43 +0200 Subject: [PATCH 1/5] Filtering collapsed to assigning an attribute of a BibDatabaseContextChangedEvent (filteredOut): true - event may be filtered out, false - event may not be filtered out BibDatabaseContextChangedEvent got a filteredOut attribute to account for general event filtering. Super class constructors are called within inheriting classes. Last FieldChangedEvents that has not been synchronized (due to filteredOut==true) are synchronized at any other event in DBMSSynchronizer or closing the database( DBMSSynchronizer.closeSharedDatabase). --- .../autosaveandbackup/AutosaveManager.java | 6 +++ .../autosaveandbackup/BackupManager.java | 5 +- .../jabref/logic/shared/DBMSSynchronizer.java | 43 +++++++++++++--- .../jabref/logic/util/CoarseChangeFilter.java | 50 ++++++++++--------- .../jabref/logic/util/DelayTaskThrottler.java | 18 +++++-- .../event/BibDatabaseContextChangedEvent.java | 21 +++++++- .../model/entry/event/EntriesEvent.java | 1 + .../model/entry/event/FieldChangedEvent.java | 6 +-- .../metadata/event/MetaDataChangedEvent.java | 1 + 9 files changed, 111 insertions(+), 40 deletions(-) diff --git a/src/main/java/org/jabref/logic/autosaveandbackup/AutosaveManager.java b/src/main/java/org/jabref/logic/autosaveandbackup/AutosaveManager.java index 1ba127033d1..8a14f7fc533 100644 --- a/src/main/java/org/jabref/logic/autosaveandbackup/AutosaveManager.java +++ b/src/main/java/org/jabref/logic/autosaveandbackup/AutosaveManager.java @@ -42,6 +42,12 @@ private AutosaveManager(BibDatabaseContext bibDatabaseContext) { @Subscribe public synchronized void listen(@SuppressWarnings("unused") BibDatabaseContextChangedEvent event) { + if (!event.isFilteredOut()) { + startAutosaveTask(); + } + } + + private void startAutosaveTask() { throttler.schedule(() -> { eventBus.post(new AutosaveEvent()); }); diff --git a/src/main/java/org/jabref/logic/autosaveandbackup/BackupManager.java b/src/main/java/org/jabref/logic/autosaveandbackup/BackupManager.java index 36d1b0a1f53..544df39cdb8 100644 --- a/src/main/java/org/jabref/logic/autosaveandbackup/BackupManager.java +++ b/src/main/java/org/jabref/logic/autosaveandbackup/BackupManager.java @@ -21,6 +21,7 @@ import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.database.event.BibDatabaseContextChangedEvent; import org.jabref.model.entry.BibEntryTypesManager; +import org.jabref.model.entry.event.EntriesEvent; import org.jabref.preferences.JabRefPreferences; import com.google.common.eventbus.Subscribe; @@ -156,7 +157,9 @@ private void logIfCritical(Path backupPath, IOException e) { @Subscribe public synchronized void listen(@SuppressWarnings("unused") BibDatabaseContextChangedEvent event) { - startBackupTask(); + if (!event.isFilteredOut()) { + startBackupTask(); + } } private void startBackupTask() { diff --git a/src/main/java/org/jabref/logic/shared/DBMSSynchronizer.java b/src/main/java/org/jabref/logic/shared/DBMSSynchronizer.java index 9aefa1049bb..4599ddb0387 100644 --- a/src/main/java/org/jabref/logic/shared/DBMSSynchronizer.java +++ b/src/main/java/org/jabref/logic/shared/DBMSSynchronizer.java @@ -54,6 +54,7 @@ public class DBMSSynchronizer implements DatabaseSynchronizer { private final Character keywordSeparator; private final GlobalCitationKeyPattern globalCiteKeyPattern; private final FileUpdateMonitor fileMonitor; + private Optional lastEntryChanged; public DBMSSynchronizer(BibDatabaseContext bibDatabaseContext, Character keywordSeparator, GlobalCitationKeyPattern globalCiteKeyPattern, FileUpdateMonitor fileMonitor) { @@ -64,6 +65,7 @@ public DBMSSynchronizer(BibDatabaseContext bibDatabaseContext, Character keyword this.eventBus = new EventBus(); this.keywordSeparator = keywordSeparator; this.globalCiteKeyPattern = Objects.requireNonNull(globalCiteKeyPattern); + this.lastEntryChanged = Optional.empty(); } /** @@ -76,11 +78,10 @@ public void listen(EntriesAddedEvent event) { // While synchronizing the local database (see synchronizeLocalDatabase() below), some EntriesEvents may be posted. // In this case DBSynchronizer should not try to insert the bibEntry entry again (but it would not harm). if (isEventSourceAccepted(event) && checkCurrentConnection()) { - synchronizeLocalMetaData(); - synchronizeLocalDatabase(); // Pull changes for the case that there were some + pullWithLastEntry(); dbmsProcessor.insertEntries(event.getBibEntries()); - } } + } /** * Listening method. Updates an existing shared {@link BibEntry}. @@ -89,13 +90,17 @@ public void listen(EntriesAddedEvent event) { */ @Subscribe public void listen(FieldChangedEvent event) { + BibEntry bibEntry = event.getBibEntry(); // While synchronizing the local database (see synchronizeLocalDatabase() below), some EntriesEvents may be posted. // In this case DBSynchronizer should not try to update the bibEntry entry again (but it would not harm). - if (isPresentLocalBibEntry(event.getBibEntry()) && isEventSourceAccepted(event) && checkCurrentConnection()) { + if (isPresentLocalBibEntry(bibEntry) && isEventSourceAccepted(event) && checkCurrentConnection() && !event.isFilteredOut()) { synchronizeLocalMetaData(); - BibEntry bibEntry = event.getBibEntry(); synchronizeSharedEntry(bibEntry); synchronizeLocalDatabase(); // Pull changes for the case that there were some + lastEntryChanged = Optional.empty(); + } else { + // Set new BibEntry that has been changed last + lastEntryChanged = Optional.of(bibEntry); } } @@ -112,8 +117,7 @@ public void listen(EntriesRemovedEvent event) { if (isEventSourceAccepted(event) && checkCurrentConnection()) { List entries = event.getBibEntries(); dbmsProcessor.removeEntries(entries); - synchronizeLocalMetaData(); - synchronizeLocalDatabase(); // Pull changes for the case that there where some + pullWithLastEntry(); } } @@ -313,9 +317,30 @@ public void pullChanges() { if (!checkCurrentConnection()) { return; } + pullWithLastEntry(); + } + + // Synchronizes local BibEntries only if last entry changes still remain + public void pullLastEntryChanges() { + if (!lastEntryChanged.isEmpty()) { + if (!checkCurrentConnection()) { + return; + } + pullWithLastEntry(); + // Reset last entry that has been changed + lastEntryChanged = Optional.empty(); + } + } - synchronizeLocalDatabase(); + // Synchronizes local BibEntries and pulls remaining last entry changes + private void pullWithLastEntry() { synchronizeLocalMetaData(); + if (!lastEntryChanged.isEmpty()) { + synchronizeSharedEntry(lastEntryChanged.get()); + // Reset last entry that has been changed + lastEntryChanged = Optional.empty(); + } + synchronizeLocalDatabase(); // Pull changes for the case that there were some } /** @@ -360,6 +385,8 @@ public void openSharedDatabase(DatabaseConnection connection) throws DatabaseNot @Override public void closeSharedDatabase() { + // Submit remaining entry changes + pullLastEntryChanges(); try { dbmsProcessor.stopNotificationListener(); currentConnection.close(); diff --git a/src/main/java/org/jabref/logic/util/CoarseChangeFilter.java b/src/main/java/org/jabref/logic/util/CoarseChangeFilter.java index 9c7a7236a3a..d19cef12e66 100644 --- a/src/main/java/org/jabref/logic/util/CoarseChangeFilter.java +++ b/src/main/java/org/jabref/logic/util/CoarseChangeFilter.java @@ -1,6 +1,7 @@ package org.jabref.logic.util; import java.util.Optional; +import java.util.concurrent.ScheduledFuture; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.database.event.BibDatabaseContextChangedEvent; @@ -9,6 +10,7 @@ import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe; +import com.microsoft.applicationinsights.internal.channel.TelemetrySerializer; /** * Filters change events and only relays major changes. @@ -17,34 +19,23 @@ public class CoarseChangeFilter { private final BibDatabaseContext context; private final EventBus eventBus = new EventBus(); - private final DelayTaskThrottler delayPost; private Optional lastFieldChanged; private int totalDelta; public CoarseChangeFilter(BibDatabaseContext bibDatabaseContext) { // Listen for change events - bibDatabaseContext.getDatabase().registerListener(this); - bibDatabaseContext.getMetaData().registerListener(this); this.context = bibDatabaseContext; - // Delay event post by 5 seconds - this.delayPost = new DelayTaskThrottler(5000); + context.getDatabase().registerListener(this); + context.getMetaData().registerListener(this); this.lastFieldChanged = Optional.empty(); this.totalDelta = 0; } @Subscribe public synchronized void listen(BibDatabaseContextChangedEvent event) { - Runnable eventPost = () -> { - // Reset total change delta - totalDelta = 0; - // Post event - eventBus.post(event); - }; - - if (!(event instanceof FieldChangedEvent)) { - eventPost.run(); - } else { + + if (event instanceof FieldChangedEvent) { // Only relay event if the field changes are more than one character or a new field is edited FieldChangedEvent fieldChange = (FieldChangedEvent) event; // Sum up change delta @@ -53,19 +44,30 @@ public synchronized void listen(BibDatabaseContextChangedEvent event) { // If editing is started boolean isNewEdit = lastFieldChanged.isEmpty(); // If other field is edited - boolean isEditOnOtherField = !isNewEdit && !lastFieldChanged.get().equals(fieldChange.getField()); + boolean isEditChanged = !isNewEdit && !lastFieldChanged.get().equals(fieldChange.getField()); // Only deltas of 1 registered by fieldChange, major change means editing much content - boolean isMajorChange = totalDelta >= 100; - - if ((isEditOnOtherField && !isNewEdit) || isMajorChange) { - // Submit old changes immediately - eventPost.run(); - } else { - delayPost.schedule(eventPost); - } + boolean isMajorChange = totalDelta >= 30; + + // Event is filtered out if neither the edited field has changed nor a major change has occurred + fieldChange.setFilteredOut(!(isEditChanged || isMajorChange)); + // Post every FieldChangedEvent, but some have been marked (filtered) + eventPost(fieldChange); // Set new last field lastFieldChanged = Optional.of(fieldChange.getField()); + } + else { + eventPost(event); + } + } + + private void eventPost(BibDatabaseContextChangedEvent event) { + // Reset total change delta + totalDelta = 0; + // Reset last field that changed + lastFieldChanged = Optional.empty(); + // Post event + eventBus.post(event); } public void registerListener(Object listener) { diff --git a/src/main/java/org/jabref/logic/util/DelayTaskThrottler.java b/src/main/java/org/jabref/logic/util/DelayTaskThrottler.java index 939d9e5250b..6ce6c35094a 100644 --- a/src/main/java/org/jabref/logic/util/DelayTaskThrottler.java +++ b/src/main/java/org/jabref/logic/util/DelayTaskThrottler.java @@ -25,7 +25,8 @@ public class DelayTaskThrottler { private static final Logger LOGGER = LoggerFactory.getLogger(DelayTaskThrottler.class); private final ScheduledThreadPoolExecutor executor; - private final int delay; + + private int delay; private ScheduledFuture scheduledTask; @@ -41,7 +42,7 @@ public DelayTaskThrottler(int delay) { public ScheduledFuture schedule(Runnable command) { if (scheduledTask != null) { - scheduledTask.cancel(false); + cancel(); } try { scheduledTask = executor.schedule(command, delay, TimeUnit.MILLISECONDS); @@ -51,9 +52,20 @@ public ScheduledFuture schedule(Runnable command) { return scheduledTask; } + // Execute scheduled Runnable early + public void execute(Runnable command) { + delay = 0; + schedule(command); + } + + // Cancel scheduled Runnable gracefully + public void cancel() { + scheduledTask.cancel(false); + } + public ScheduledFuture scheduleTask(Callable command) { if (scheduledTask != null) { - scheduledTask.cancel(false); + cancel(); } try { scheduledTask = executor.schedule(command, delay, TimeUnit.MILLISECONDS); diff --git a/src/main/java/org/jabref/model/database/event/BibDatabaseContextChangedEvent.java b/src/main/java/org/jabref/model/database/event/BibDatabaseContextChangedEvent.java index 15acdced130..378c313070e 100644 --- a/src/main/java/org/jabref/model/database/event/BibDatabaseContextChangedEvent.java +++ b/src/main/java/org/jabref/model/database/event/BibDatabaseContextChangedEvent.java @@ -1,5 +1,7 @@ package org.jabref.model.database.event; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.event.EntriesEvent; import org.jabref.model.groups.event.GroupUpdatedEvent; import org.jabref.model.metadata.event.MetaDataChangedEvent; @@ -7,5 +9,22 @@ * This Event is automatically fired at the same time as {@link EntriesEvent}, {@link GroupUpdatedEvent} or {@link MetaDataChangedEvent}. */ public class BibDatabaseContextChangedEvent { - // no data + // If the event has been filtered out + private boolean filteredOut; + + public BibDatabaseContextChangedEvent() { + this(false); + } + + public BibDatabaseContextChangedEvent(boolean filteredOut) { + this.filteredOut = filteredOut; + } + + public boolean isFilteredOut() { + return filteredOut; + } + + public void setFilteredOut(boolean filtered) { + this.filteredOut = filtered; + } } diff --git a/src/main/java/org/jabref/model/entry/event/EntriesEvent.java b/src/main/java/org/jabref/model/entry/event/EntriesEvent.java index aa0511b1950..e44aa89ca9f 100644 --- a/src/main/java/org/jabref/model/entry/event/EntriesEvent.java +++ b/src/main/java/org/jabref/model/entry/event/EntriesEvent.java @@ -26,6 +26,7 @@ public EntriesEvent(List bibEntries) { * @param location Location affected by this event */ public EntriesEvent(List bibEntries, EntriesEventSource location) { + super(); this.bibEntries = Objects.requireNonNull(bibEntries); this.location = Objects.requireNonNull(location); } diff --git a/src/main/java/org/jabref/model/entry/event/FieldChangedEvent.java b/src/main/java/org/jabref/model/entry/event/FieldChangedEvent.java index 71cff406894..45d9ae2ec1d 100644 --- a/src/main/java/org/jabref/model/entry/event/FieldChangedEvent.java +++ b/src/main/java/org/jabref/model/entry/event/FieldChangedEvent.java @@ -27,7 +27,7 @@ public FieldChangedEvent(BibEntry bibEntry, Field field, String newValue, String this.field = field; this.newValue = newValue; this.oldValue = oldValue; - delta = computeDelta(oldValue, newValue); + this.delta = computeDelta(oldValue, newValue); } /** @@ -40,7 +40,7 @@ public FieldChangedEvent(BibEntry bibEntry, Field field, String newValue, String this.field = field; this.newValue = newValue; this.oldValue = oldValue; - delta = computeDelta(oldValue, newValue); + this.delta = computeDelta(oldValue, newValue); } /** @@ -51,7 +51,7 @@ public FieldChangedEvent(FieldChange fieldChange, EntriesEventSource location) { this.field = fieldChange.getField(); this.newValue = fieldChange.getNewValue(); this.oldValue = fieldChange.getOldValue(); - delta = computeDelta(oldValue, newValue); + this.delta = computeDelta(oldValue, newValue); } public FieldChangedEvent(FieldChange fieldChange) { diff --git a/src/main/java/org/jabref/model/metadata/event/MetaDataChangedEvent.java b/src/main/java/org/jabref/model/metadata/event/MetaDataChangedEvent.java index db3997cb15e..f910e50a47c 100644 --- a/src/main/java/org/jabref/model/metadata/event/MetaDataChangedEvent.java +++ b/src/main/java/org/jabref/model/metadata/event/MetaDataChangedEvent.java @@ -14,6 +14,7 @@ public class MetaDataChangedEvent extends BibDatabaseContextChangedEvent { * @param metaData Affected instance */ public MetaDataChangedEvent(MetaData metaData) { + super(); this.metaData = metaData; } From 8ae59d7a66c9001fb880477ed73a28a441ec9841 Mon Sep 17 00:00:00 2001 From: m-mauersberger Date: Fri, 4 Sep 2020 10:28:12 +0200 Subject: [PATCH 2/5] Remove unused imports --- src/main/java/org/jabref/logic/util/CoarseChangeFilter.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/org/jabref/logic/util/CoarseChangeFilter.java b/src/main/java/org/jabref/logic/util/CoarseChangeFilter.java index d19cef12e66..1b4c8c4b7ac 100644 --- a/src/main/java/org/jabref/logic/util/CoarseChangeFilter.java +++ b/src/main/java/org/jabref/logic/util/CoarseChangeFilter.java @@ -1,7 +1,6 @@ package org.jabref.logic.util; import java.util.Optional; -import java.util.concurrent.ScheduledFuture; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.database.event.BibDatabaseContextChangedEvent; @@ -10,7 +9,6 @@ import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe; -import com.microsoft.applicationinsights.internal.channel.TelemetrySerializer; /** * Filters change events and only relays major changes. From 2e6c967750cbf7da464f9548cfc2ee01bf19beff Mon Sep 17 00:00:00 2001 From: Michael Mauersberger <67641254+m-mauersberger@users.noreply.github.com> Date: Fri, 25 Sep 2020 10:16:14 +0200 Subject: [PATCH 3/5] Update src/main/java/org/jabref/logic/util/CoarseChangeFilter.java Wording Co-authored-by: Oliver Kopp --- src/main/java/org/jabref/logic/util/CoarseChangeFilter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/logic/util/CoarseChangeFilter.java b/src/main/java/org/jabref/logic/util/CoarseChangeFilter.java index 1b4c8c4b7ac..317271784bb 100644 --- a/src/main/java/org/jabref/logic/util/CoarseChangeFilter.java +++ b/src/main/java/org/jabref/logic/util/CoarseChangeFilter.java @@ -48,7 +48,7 @@ public synchronized void listen(BibDatabaseContextChangedEvent event) { // Event is filtered out if neither the edited field has changed nor a major change has occurred fieldChange.setFilteredOut(!(isEditChanged || isMajorChange)); - // Post every FieldChangedEvent, but some have been marked (filtered) + // Post each FieldChangedEvent - even the ones being marked as "filtered" eventPost(fieldChange); // Set new last field lastFieldChanged = Optional.of(fieldChange.getField()); From 7382ba60b2101e807d46b63c257100339c96c8ac Mon Sep 17 00:00:00 2001 From: m-mauersberger Date: Fri, 25 Sep 2020 15:37:42 +0200 Subject: [PATCH 4/5] Remove unused imports. CoarseChangeFilter: Remove totalDelta due to restriction to pasting and deleting more than one character. Handle changed field. DBMSSynchronizer: Pull remaining changes at every entry-related event. --- docs/advanced-reading/remote-storage.md | 20 ++++++++++ .../autosaveandbackup/BackupManager.java | 1 - .../jabref/logic/shared/DBMSSynchronizer.java | 25 +++++++----- .../jabref/logic/util/CoarseChangeFilter.java | 40 ++++++++----------- .../event/BibDatabaseContextChangedEvent.java | 1 - 5 files changed, 51 insertions(+), 36 deletions(-) create mode 100644 docs/advanced-reading/remote-storage.md diff --git a/docs/advanced-reading/remote-storage.md b/docs/advanced-reading/remote-storage.md new file mode 100644 index 00000000000..9fe71744a10 --- /dev/null +++ b/docs/advanced-reading/remote-storage.md @@ -0,0 +1,20 @@ +# Remote Storage + +## Using a shared PostgreSQL database + +... + +## Handling large shared databases + +Synchronization times may get long when working with a large database containing several thousand entries. Therefore, synchronization only happens if several conditions are fulfilled: + +* Edit to another field. +* Major changes have been made (pasting or deleting more than one character). + +Class `org.jabref.logic.util.CoarseChangeFilter.java` checks both conditions. + +Remaining changes that has not been synchronized yet are saved at closing the database rendering additional closing time. Saving is realized in `org.jabref.logic.shared.DBMSSynchronizer.java`. Following methods account for synchronization modes: + +* `pullChanges` synchronizes the database unconditionally. +* `pullLastEntryChanges` synchronizes only if there are remaining entry changes. It is invoked when closing the shared database (`closeSharedDatabase`). + diff --git a/src/main/java/org/jabref/logic/autosaveandbackup/BackupManager.java b/src/main/java/org/jabref/logic/autosaveandbackup/BackupManager.java index 544df39cdb8..60cccdd855a 100644 --- a/src/main/java/org/jabref/logic/autosaveandbackup/BackupManager.java +++ b/src/main/java/org/jabref/logic/autosaveandbackup/BackupManager.java @@ -21,7 +21,6 @@ import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.database.event.BibDatabaseContextChangedEvent; import org.jabref.model.entry.BibEntryTypesManager; -import org.jabref.model.entry.event.EntriesEvent; import org.jabref.preferences.JabRefPreferences; import com.google.common.eventbus.Subscribe; diff --git a/src/main/java/org/jabref/logic/shared/DBMSSynchronizer.java b/src/main/java/org/jabref/logic/shared/DBMSSynchronizer.java index 4599ddb0387..e4b7e0294c3 100644 --- a/src/main/java/org/jabref/logic/shared/DBMSSynchronizer.java +++ b/src/main/java/org/jabref/logic/shared/DBMSSynchronizer.java @@ -78,8 +78,12 @@ public void listen(EntriesAddedEvent event) { // While synchronizing the local database (see synchronizeLocalDatabase() below), some EntriesEvents may be posted. // In this case DBSynchronizer should not try to insert the bibEntry entry again (but it would not harm). if (isEventSourceAccepted(event) && checkCurrentConnection()) { + synchronizeLocalMetaData(); pullWithLastEntry(); + synchronizeLocalDatabase(); dbmsProcessor.insertEntries(event.getBibEntries()); + // Reset last changed entry because it just has already been synchronized -> Why necessary? + lastEntryChanged = Optional.empty(); } } @@ -95,9 +99,9 @@ public void listen(FieldChangedEvent event) { // In this case DBSynchronizer should not try to update the bibEntry entry again (but it would not harm). if (isPresentLocalBibEntry(bibEntry) && isEventSourceAccepted(event) && checkCurrentConnection() && !event.isFilteredOut()) { synchronizeLocalMetaData(); + pullWithLastEntry(); synchronizeSharedEntry(bibEntry); synchronizeLocalDatabase(); // Pull changes for the case that there were some - lastEntryChanged = Optional.empty(); } else { // Set new BibEntry that has been changed last lastEntryChanged = Optional.of(bibEntry); @@ -115,9 +119,10 @@ public void listen(EntriesRemovedEvent event) { // While synchronizing the local database (see synchronizeLocalDatabase() below), some EntriesEvents may be posted. // In this case DBSynchronizer should not try to delete the bibEntry entry again (but it would not harm). if (isEventSourceAccepted(event) && checkCurrentConnection()) { - List entries = event.getBibEntries(); - dbmsProcessor.removeEntries(entries); + synchronizeLocalMetaData(); pullWithLastEntry(); + dbmsProcessor.removeEntries(event.getBibEntries()); + synchronizeLocalDatabase(); } } @@ -317,7 +322,10 @@ public void pullChanges() { if (!checkCurrentConnection()) { return; } + // First synchronize entry, then synchronize database pullWithLastEntry(); + synchronizeLocalDatabase(); + synchronizeLocalMetaData(); } // Synchronizes local BibEntries only if last entry changes still remain @@ -326,21 +334,18 @@ public void pullLastEntryChanges() { if (!checkCurrentConnection()) { return; } + synchronizeLocalMetaData(); pullWithLastEntry(); - // Reset last entry that has been changed - lastEntryChanged = Optional.empty(); + synchronizeLocalDatabase(); // Pull changes for the case that there were some } } // Synchronizes local BibEntries and pulls remaining last entry changes private void pullWithLastEntry() { - synchronizeLocalMetaData(); - if (!lastEntryChanged.isEmpty()) { + if (!lastEntryChanged.isEmpty() && isPresentLocalBibEntry(lastEntryChanged.get())) { synchronizeSharedEntry(lastEntryChanged.get()); - // Reset last entry that has been changed - lastEntryChanged = Optional.empty(); } - synchronizeLocalDatabase(); // Pull changes for the case that there were some + lastEntryChanged = Optional.empty(); } /** diff --git a/src/main/java/org/jabref/logic/util/CoarseChangeFilter.java b/src/main/java/org/jabref/logic/util/CoarseChangeFilter.java index 1b4c8c4b7ac..e7ed6b75d16 100644 --- a/src/main/java/org/jabref/logic/util/CoarseChangeFilter.java +++ b/src/main/java/org/jabref/logic/util/CoarseChangeFilter.java @@ -4,6 +4,7 @@ import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.database.event.BibDatabaseContextChangedEvent; +import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.event.FieldChangedEvent; import org.jabref.model.entry.field.Field; @@ -19,6 +20,7 @@ public class CoarseChangeFilter { private final EventBus eventBus = new EventBus(); private Optional lastFieldChanged; + private Optional lastEntryChanged; private int totalDelta; public CoarseChangeFilter(BibDatabaseContext bibDatabaseContext) { @@ -27,7 +29,7 @@ public CoarseChangeFilter(BibDatabaseContext bibDatabaseContext) { context.getDatabase().registerListener(this); context.getMetaData().registerListener(this); this.lastFieldChanged = Optional.empty(); - this.totalDelta = 0; + this.lastEntryChanged = Optional.empty(); } @Subscribe @@ -36,38 +38,28 @@ public synchronized void listen(BibDatabaseContextChangedEvent event) { if (event instanceof FieldChangedEvent) { // Only relay event if the field changes are more than one character or a new field is edited FieldChangedEvent fieldChange = (FieldChangedEvent) event; - // Sum up change delta - totalDelta += fieldChange.getDelta(); // If editing is started - boolean isNewEdit = lastFieldChanged.isEmpty(); - // If other field is edited - boolean isEditChanged = !isNewEdit && !lastFieldChanged.get().equals(fieldChange.getField()); - // Only deltas of 1 registered by fieldChange, major change means editing much content - boolean isMajorChange = totalDelta >= 30; + boolean isNewEdit = lastFieldChanged.isEmpty() || lastEntryChanged.isEmpty(); + // If other field or entry is edited + boolean isChangedField = lastFieldChanged.filter(f -> !f.equals(fieldChange.getField())).isPresent(); + boolean isChangedEntry = lastEntryChanged.filter(e -> !e.equals(fieldChange.getBibEntry())).isPresent(); + boolean isEditChanged = !isNewEdit && (isChangedField || isChangedEntry); + // Only deltas of 1 when typing in manually, major change means pasting something (more than one character) + boolean isMajorChange = fieldChange.getDelta() > 1; // Event is filtered out if neither the edited field has changed nor a major change has occurred fieldChange.setFilteredOut(!(isEditChanged || isMajorChange)); - // Post every FieldChangedEvent, but some have been marked (filtered) - eventPost(fieldChange); - // Set new last field + // Post each FieldChangedEvent - even the ones being marked as "filtered" + eventBus.post(fieldChange); + // Set new last field and entry lastFieldChanged = Optional.of(fieldChange.getField()); - - } - else { - eventPost(event); + lastEntryChanged = Optional.of(fieldChange.getBibEntry()); + } else { + eventBus.post(event); } } - private void eventPost(BibDatabaseContextChangedEvent event) { - // Reset total change delta - totalDelta = 0; - // Reset last field that changed - lastFieldChanged = Optional.empty(); - // Post event - eventBus.post(event); - } - public void registerListener(Object listener) { eventBus.register(listener); } diff --git a/src/main/java/org/jabref/model/database/event/BibDatabaseContextChangedEvent.java b/src/main/java/org/jabref/model/database/event/BibDatabaseContextChangedEvent.java index 378c313070e..197097691e3 100644 --- a/src/main/java/org/jabref/model/database/event/BibDatabaseContextChangedEvent.java +++ b/src/main/java/org/jabref/model/database/event/BibDatabaseContextChangedEvent.java @@ -1,6 +1,5 @@ package org.jabref.model.database.event; -import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.event.EntriesEvent; import org.jabref.model.groups.event.GroupUpdatedEvent; import org.jabref.model.metadata.event.MetaDataChangedEvent; From 4015ab89b3fe6f62ed8170ed4ef4b884b45250df Mon Sep 17 00:00:00 2001 From: m-mauersberger Date: Fri, 25 Sep 2020 15:41:56 +0200 Subject: [PATCH 5/5] Remove unused imports. CoarseChangeFilter: Remove totalDelta due to restriction to pasting and deleting more than one character. Handle changed field. DBMSSynchronizer: Pull remaining changes at every entry-related event. --- .../java/org/jabref/logic/util/CoarseChangeFilter.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/jabref/logic/util/CoarseChangeFilter.java b/src/main/java/org/jabref/logic/util/CoarseChangeFilter.java index e7ed6b75d16..ead72efe4d5 100644 --- a/src/main/java/org/jabref/logic/util/CoarseChangeFilter.java +++ b/src/main/java/org/jabref/logic/util/CoarseChangeFilter.java @@ -39,20 +39,19 @@ public synchronized void listen(BibDatabaseContextChangedEvent event) { // Only relay event if the field changes are more than one character or a new field is edited FieldChangedEvent fieldChange = (FieldChangedEvent) event; - // If editing is started + // If editing has started boolean isNewEdit = lastFieldChanged.isEmpty() || lastEntryChanged.isEmpty(); - // If other field or entry is edited + boolean isChangedField = lastFieldChanged.filter(f -> !f.equals(fieldChange.getField())).isPresent(); boolean isChangedEntry = lastEntryChanged.filter(e -> !e.equals(fieldChange.getBibEntry())).isPresent(); boolean isEditChanged = !isNewEdit && (isChangedField || isChangedEntry); // Only deltas of 1 when typing in manually, major change means pasting something (more than one character) boolean isMajorChange = fieldChange.getDelta() > 1; - // Event is filtered out if neither the edited field has changed nor a major change has occurred fieldChange.setFilteredOut(!(isEditChanged || isMajorChange)); // Post each FieldChangedEvent - even the ones being marked as "filtered" eventBus.post(fieldChange); - // Set new last field and entry + lastFieldChanged = Optional.of(fieldChange.getField()); lastEntryChanged = Optional.of(fieldChange.getBibEntry()); } else {