Skip to content

Commit 5e1117a

Browse files
committed
Merge remote-tracking branch 'upstream/master' into exportPdf
* upstream/master: Initializing EntryEditor Tabs on focus (#3331) Fix #3292: annotations are now automatically refreshed (#3325) # Conflicts: # CHANGELOG.md
2 parents bb1a304 + f71c5a8 commit 5e1117a

38 files changed

+356
-406
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,15 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `#
1717
- Updated French translation
1818
- We improved the handling of abstracts in the "Astrophysics Data System" fetcher. [#2471](https://github.com/JabRef/jabref/issues/2471)
1919
- We added support for pasting entries in different formats [#3143](https://github.com/JabRef/jabref/issues/3143)
20+
- In the annotation tab, PDF files are now monitored for new or changed annotation. A manual reload is no longer necessary. [#3292](https://github.com/JabRef/jabref/issues/3292)
2021
- We increased the relative size of the "abstract" field in the entry editor. [Feature request in the forum](http://discourse.jabref.org/t/entry-preview-in-version-4/827)
2122
- Crossreferenced entries are now used when a BibTex key is generated for an entry with empty fields. [#2811](https://github.com/JabRef/jabref/issues/2811)
2223
- We now set the WM_CLASS of the UI to org-jabref-JabRefMain to allow certain Un*x window managers to properly identify its windows
2324
- We changed the default paths for the OpenOffice/LibreOffice binaries to the default path for LibreOffice
2425
- We no longer create a new entry editor when selecting a new entry to increase performance. [#3187](https://github.com/JabRef/jabref/pull/3187)
2526
- We added the possibility to copy linked files from entries to a single output folder [#2539](https://github.com/JabRef/jabref/pull/2593)
27+
- We increased performance and decreased the memory footprint of the entry editor drastically. [#3331](https://github.com/JabRef/jabref/pull/3331)
28+
2629

2730
### Fixed
2831
- We fixed the translation of \textendash in the entry preview [#3307](https://github.com/JabRef/jabref/issues/3307)

src/main/java/org/jabref/Globals.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
import java.util.Optional;
55
import java.util.UUID;
66

7-
import org.jabref.collab.FileUpdateMonitor;
87
import org.jabref.gui.GlobalFocusListener;
98
import org.jabref.gui.StateManager;
109
import org.jabref.gui.keyboard.KeyBindingRepository;
1110
import org.jabref.gui.util.DefaultTaskExecutor;
11+
import org.jabref.gui.util.FileUpdateMonitor;
1212
import org.jabref.gui.util.TaskExecutor;
1313
import org.jabref.logic.importer.ImportFormatReader;
1414
import org.jabref.logic.journals.JournalAbbreviationLoader;

src/main/java/org/jabref/collab/ChangeDisplayDialog.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ public ChangeDisplayDialog(JFrame owner, final BasePanel panel,
103103
if (anyDisabled) {
104104
panel.markBaseChanged();
105105
}
106-
panel.setUpdatedExternally(false);
106+
panel.markExternalChangesAsResolved();
107107
dispose();
108108
okPressed = true;
109109
});

src/main/java/org/jabref/collab/ChangeScanner.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ public class ChangeScanner implements Runnable {
4949

5050
private static final double MATCH_THRESHOLD = 0.4;
5151
private final File file;
52+
private final Path tempFile;
5253
private final BibDatabase databaseInMemory;
5354
private final MetaData metadataInMemory;
5455

@@ -67,20 +68,20 @@ public class ChangeScanner implements Runnable {
6768

6869
// NamedCompound edit = new NamedCompound("Merged external changes")
6970

70-
public ChangeScanner(JabRefFrame frame, BasePanel bp, File file) {
71+
public ChangeScanner(JabRefFrame frame, BasePanel bp, File file, Path tempFile) {
7172
this.panel = bp;
7273
this.frame = frame;
7374
this.databaseInMemory = bp.getDatabase();
7475
this.metadataInMemory = bp.getBibDatabaseContext().getMetaData();
7576
this.file = file;
77+
this.tempFile = tempFile;
7678
}
7779

7880
@Override
7981
public void run() {
8082
try {
8183

8284
// Parse the temporary file.
83-
Path tempFile = Globals.getFileUpdateMonitor().getTempFile(panel.fileMonitorHandle());
8485
ImportFormatPreferences importFormatPreferences = Globals.prefs.getImportFormatPreferences();
8586
ParserResult result = OpenDatabase.loadDatabase(tempFile.toFile(), importFormatPreferences);
8687
databaseInTemp = result.getDatabase();
@@ -153,7 +154,7 @@ private void storeTempDatabase() {
153154
Defaults defaults = new Defaults(Globals.prefs.getDefaultBibDatabaseMode());
154155
BibDatabaseWriter<SaveSession> databaseWriter = new BibtexDatabaseWriter<>(FileSaveSession::new);
155156
SaveSession ss = databaseWriter.saveDatabase(new BibDatabaseContext(databaseInTemp, metadataInTemp, defaults), prefs);
156-
ss.commit(Globals.getFileUpdateMonitor().getTempFile(panel.fileMonitorHandle()));
157+
ss.commit(tempFile);
157158
} catch (SaveException ex) {
158159
LOGGER.warn("Problem updating tmp file after accepting external changes", ex);
159160
}
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
package org.jabref.collab;
2+
3+
import java.io.IOException;
4+
import java.nio.file.Files;
5+
import java.nio.file.Path;
6+
import java.util.Optional;
7+
8+
import javax.swing.SwingUtilities;
9+
10+
import org.jabref.JabRefExecutorService;
11+
import org.jabref.gui.BasePanel;
12+
import org.jabref.gui.SidePaneManager;
13+
import org.jabref.gui.util.FileUpdateListener;
14+
import org.jabref.gui.util.FileUpdateMonitor;
15+
import org.jabref.logic.util.io.FileBasedLock;
16+
import org.jabref.logic.util.io.FileUtil;
17+
import org.jabref.model.database.BibDatabaseContext;
18+
19+
import org.apache.commons.logging.Log;
20+
import org.apache.commons.logging.LogFactory;
21+
22+
public class DatabaseChangeMonitor implements FileUpdateListener {
23+
private static final Log LOGGER = LogFactory.getLog(DatabaseChangeMonitor.class);
24+
25+
private final BibDatabaseContext database;
26+
private final FileUpdateMonitor fileMonitor;
27+
private final BasePanel panel;
28+
private boolean updatedExternally;
29+
private Path tmpFile;
30+
private long timeStamp;
31+
private long fileSize;
32+
33+
public DatabaseChangeMonitor(BibDatabaseContext database, FileUpdateMonitor fileMonitor, BasePanel panel) {
34+
this.database = database;
35+
this.fileMonitor = fileMonitor;
36+
this.panel = panel;
37+
38+
this.database.getDatabasePath().ifPresent(path -> {
39+
try {
40+
fileMonitor.addListenerForFile(path, this);
41+
timeStamp = Files.getLastModifiedTime(path).toMillis();
42+
fileSize = Files.size(path);
43+
tmpFile = Files.createTempFile("jabref", ".bib");
44+
tmpFile.toFile().deleteOnExit();
45+
copyToTemp(path);
46+
} catch (IOException e) {
47+
LOGGER.error("Error while trying to monitor " + path, e);
48+
}
49+
});
50+
}
51+
52+
@Override
53+
public void fileUpdated() {
54+
if (panel.isSaving()) {
55+
// We are just saving the file, so this message is most likely due to bad timing.
56+
// If not, we'll handle it on the next polling.
57+
return;
58+
}
59+
60+
updatedExternally = true;
61+
62+
final ChangeScanner scanner = new ChangeScanner(panel.frame(), panel, database.getDatabaseFile().orElse(null), tmpFile);
63+
64+
// Test: running scan automatically in background
65+
if (database.getDatabasePath().isPresent() && !FileBasedLock.waitForFileLock(database.getDatabasePath().get())) {
66+
// The file is locked even after the maximum wait. Do nothing.
67+
LOGGER.error("File updated externally, but change scan failed because the file is locked.");
68+
69+
// Wait a bit and then try again
70+
try {
71+
Thread.sleep(1000);
72+
} catch (InterruptedException e) {
73+
// Nothing to do
74+
}
75+
fileUpdated();
76+
return;
77+
}
78+
79+
JabRefExecutorService.INSTANCE.executeInterruptableTaskAndWait(scanner);
80+
81+
// Adding the sidepane component is Swing work, so we must do this in the Swing
82+
// thread:
83+
Runnable t = () -> {
84+
85+
// Check if there is already a notification about external
86+
// changes:
87+
SidePaneManager sidePaneManager = panel.getSidePaneManager();
88+
boolean hasAlready = sidePaneManager.hasComponent(FileUpdatePanel.class);
89+
if (hasAlready) {
90+
sidePaneManager.hideComponent(FileUpdatePanel.class);
91+
sidePaneManager.unregisterComponent(FileUpdatePanel.class);
92+
}
93+
FileUpdatePanel pan = new FileUpdatePanel(panel, sidePaneManager,
94+
database.getDatabaseFile().orElse(null), scanner);
95+
sidePaneManager.register(pan);
96+
sidePaneManager.show(FileUpdatePanel.class);
97+
};
98+
99+
if (scanner.changesFound()) {
100+
SwingUtilities.invokeLater(t);
101+
} else {
102+
updatedExternally = false;
103+
}
104+
}
105+
106+
/**
107+
* Forces a check on the file, and returns the result. Check if time stamp or the file size has changed.
108+
*
109+
* @return boolean true if the file has changed.
110+
*/
111+
private boolean hasBeenModified() {
112+
Optional<Path> file = database.getDatabasePath();
113+
if (file.isPresent()) {
114+
try {
115+
long modified = Files.getLastModifiedTime(file.get()).toMillis();
116+
if (modified == 0L) {
117+
// File deleted
118+
return false;
119+
}
120+
long fileSizeNow = Files.size(file.get());
121+
return (timeStamp != modified) || (fileSize != fileSizeNow);
122+
} catch (IOException ex) {
123+
return false;
124+
}
125+
}
126+
return false;
127+
}
128+
129+
public void unregister() {
130+
database.getDatabasePath().ifPresent(file -> fileMonitor.removeListener(file, this));
131+
}
132+
133+
public boolean hasBeenModifiedExternally() {
134+
return updatedExternally || hasBeenModified();
135+
}
136+
137+
public void markExternalChangesAsResolved() {
138+
updatedExternally = false;
139+
}
140+
141+
public void markAsSaved() {
142+
database.getDatabasePath().ifPresent(file -> {
143+
try {
144+
timeStamp = Files.getLastModifiedTime(file).toMillis();
145+
fileSize = Files.size(file);
146+
147+
copyToTemp(file);
148+
} catch (IOException ex) {
149+
LOGGER.error("Error while getting file information", ex);
150+
}
151+
});
152+
}
153+
154+
private void copyToTemp(Path file) {
155+
FileUtil.copyFile(file, tmpFile, true);
156+
}
157+
158+
public Path getTempFile() {
159+
return tmpFile;
160+
}
161+
}

0 commit comments

Comments
 (0)