9
9
import java .util .List ;
10
10
import java .util .Optional ;
11
11
import java .util .function .BiPredicate ;
12
+ import java .util .function .Supplier ;
12
13
13
14
import javax .net .ssl .HostnameVerifier ;
14
15
import javax .net .ssl .HttpsURLConnection ;
35
36
import org .jabref .gui .icon .IconTheme ;
36
37
import org .jabref .gui .icon .JabRefIcon ;
37
38
import org .jabref .gui .linkedfile .LinkedFileEditDialogView ;
39
+ import org .jabref .gui .mergeentries .MultiMergeEntriesView ;
38
40
import org .jabref .gui .util .BackgroundTask ;
39
41
import org .jabref .gui .util .ControlHelper ;
40
42
import org .jabref .gui .util .TaskExecutor ;
41
43
import org .jabref .logic .externalfiles .LinkedFileHandler ;
44
+ import org .jabref .logic .importer .Importer ;
45
+ import org .jabref .logic .importer .ParserResult ;
46
+ import org .jabref .logic .importer .fileformat .PdfContentImporter ;
47
+ import org .jabref .logic .importer .fileformat .PdfEmbeddedBibFileImporter ;
48
+ import org .jabref .logic .importer .fileformat .PdfGrobidImporter ;
49
+ import org .jabref .logic .importer .fileformat .PdfVerbatimBibTextImporter ;
50
+ import org .jabref .logic .importer .fileformat .PdfXmpImporter ;
42
51
import org .jabref .logic .l10n .Localization ;
43
52
import org .jabref .logic .net .URLDownload ;
44
53
import org .jabref .logic .util .io .FileNameUniqueness ;
45
54
import org .jabref .logic .util .io .FileUtil ;
46
- import org .jabref .logic .xmp .XmpPreferences ;
47
55
import org .jabref .logic .xmp .XmpUtilWriter ;
48
56
import org .jabref .model .database .BibDatabaseContext ;
49
57
import org .jabref .model .entry .BibEntry ;
50
58
import org .jabref .model .entry .LinkedFile ;
51
59
import org .jabref .model .strings .StringUtil ;
52
60
import org .jabref .model .util .FileHelper ;
53
61
import org .jabref .model .util .OptionalUtil ;
54
- import org .jabref .preferences .FilePreferences ;
62
+ import org .jabref .preferences .PreferencesService ;
55
63
56
64
import de .saxsys .mvvmfx .utils .validation .FunctionBasedValidator ;
57
65
import de .saxsys .mvvmfx .utils .validation .ValidationMessage ;
@@ -69,12 +77,11 @@ public class LinkedFileViewModel extends AbstractViewModel {
69
77
private final DoubleProperty downloadProgress = new SimpleDoubleProperty (-1 );
70
78
private final BooleanProperty downloadOngoing = new SimpleBooleanProperty (false );
71
79
private final BooleanProperty isAutomaticallyFound = new SimpleBooleanProperty (false );
72
- private final BooleanProperty canWriteXMPMetadata = new SimpleBooleanProperty (false );
80
+ private final BooleanProperty isOfflinePdf = new SimpleBooleanProperty (false );
73
81
private final DialogService dialogService ;
74
82
private final BibEntry entry ;
75
83
private final TaskExecutor taskExecutor ;
76
- private final FilePreferences filePreferences ;
77
- private final XmpPreferences xmpPreferences ;
84
+ private final PreferencesService preferences ;
78
85
private final LinkedFileHandler linkedFileHandler ;
79
86
private final ExternalFileTypes externalFileTypes ;
80
87
@@ -85,38 +92,36 @@ public LinkedFileViewModel(LinkedFile linkedFile,
85
92
BibDatabaseContext databaseContext ,
86
93
TaskExecutor taskExecutor ,
87
94
DialogService dialogService ,
88
- XmpPreferences xmpPreferences ,
89
- FilePreferences filePreferences ,
95
+ PreferencesService preferences ,
90
96
ExternalFileTypes externalFileTypes ) {
91
97
92
98
this .linkedFile = linkedFile ;
93
- this .filePreferences = filePreferences ;
94
- this .linkedFileHandler = new LinkedFileHandler (linkedFile , entry , databaseContext , filePreferences );
99
+ this .preferences = preferences ;
100
+ this .linkedFileHandler = new LinkedFileHandler (linkedFile , entry , databaseContext , preferences . getFilePreferences () );
95
101
this .databaseContext = databaseContext ;
96
102
this .entry = entry ;
97
103
this .dialogService = dialogService ;
98
104
this .taskExecutor = taskExecutor ;
99
105
this .externalFileTypes = externalFileTypes ;
100
- this .xmpPreferences = xmpPreferences ;
101
106
102
107
fileExistsValidator = new FunctionBasedValidator <>(
103
108
linkedFile .linkProperty (),
104
109
link -> {
105
110
if (linkedFile .isOnlineLink ()) {
106
111
return true ;
107
112
} else {
108
- Optional <Path > path = FileHelper .find (databaseContext , link , filePreferences );
113
+ Optional <Path > path = FileHelper .find (databaseContext , link , preferences . getFilePreferences () );
109
114
return path .isPresent () && Files .exists (path .get ());
110
115
}
111
116
},
112
117
ValidationMessage .warning (Localization .lang ("Could not find file '%0'." , linkedFile .getLink ())));
113
118
114
119
downloadOngoing .bind (downloadProgress .greaterThanOrEqualTo (0 ).and (downloadProgress .lessThan (1 )));
115
- canWriteXMPMetadata .setValue (!linkedFile .isOnlineLink () && linkedFile .getFileType ().equalsIgnoreCase ("pdf" ));
120
+ isOfflinePdf .setValue (!linkedFile .isOnlineLink () && linkedFile .getFileType ().equalsIgnoreCase ("pdf" ));
116
121
}
117
122
118
- public BooleanProperty canWriteXMPMetadataProperty () {
119
- return canWriteXMPMetadata ;
123
+ public BooleanProperty isOfflinePdfProperty () {
124
+ return isOfflinePdf ;
120
125
}
121
126
122
127
public boolean isAutomaticallyFound () {
@@ -211,7 +216,7 @@ public void openFolder() {
211
216
Optional <Path > resolvedPath = FileHelper .find (
212
217
databaseContext ,
213
218
linkedFile .getLink (),
214
- filePreferences );
219
+ preferences . getFilePreferences () );
215
220
216
221
if (resolvedPath .isPresent ()) {
217
222
JabRefDesktop .openFolderAndSelectFile (resolvedPath .get ());
@@ -246,7 +251,7 @@ public void renameFileToName(String targetFileName) {
246
251
return ;
247
252
}
248
253
249
- Optional <Path > file = linkedFile .findIn (databaseContext , filePreferences );
254
+ Optional <Path > file = linkedFile .findIn (databaseContext , preferences . getFilePreferences () );
250
255
if (file .isPresent ()) {
251
256
performRenameWithConflictCheck (targetFileName );
252
257
} else {
@@ -283,13 +288,13 @@ public void moveToDefaultDirectory() {
283
288
}
284
289
285
290
// Get target folder
286
- Optional <Path > fileDir = databaseContext .getFirstExistingFileDir (filePreferences );
291
+ Optional <Path > fileDir = databaseContext .getFirstExistingFileDir (preferences . getFilePreferences () );
287
292
if (fileDir .isEmpty ()) {
288
293
dialogService .showErrorDialogAndWait (Localization .lang ("Move file" ), Localization .lang ("File directory is not set or does not exist!" ));
289
294
return ;
290
295
}
291
296
292
- Optional <Path > file = linkedFile .findIn (databaseContext , filePreferences );
297
+ Optional <Path > file = linkedFile .findIn (databaseContext , preferences . getFilePreferences () );
293
298
if ((file .isPresent ())) {
294
299
// Found the linked file, so move it
295
300
try {
@@ -325,9 +330,9 @@ public boolean isGeneratedNameSameAsOriginal() {
325
330
* @return true if suggested filepath is same as existing filepath.
326
331
*/
327
332
public boolean isGeneratedPathSameAsOriginal () {
328
- Optional <Path > newDir = databaseContext .getFirstExistingFileDir (filePreferences );
333
+ Optional <Path > newDir = databaseContext .getFirstExistingFileDir (preferences . getFilePreferences () );
329
334
330
- Optional <Path > currentDir = linkedFile .findIn (databaseContext , filePreferences ).map (Path ::getParent );
335
+ Optional <Path > currentDir = linkedFile .findIn (databaseContext , preferences . getFilePreferences () ).map (Path ::getParent );
331
336
332
337
BiPredicate <Path , Path > equality = (fileA , fileB ) -> {
333
338
try {
@@ -351,7 +356,7 @@ public void moveToDefaultDirectoryAndRename() {
351
356
* successfully, does not exist in the first place or the user choose to remove it)
352
357
*/
353
358
public boolean delete () {
354
- Optional <Path > file = linkedFile .findIn (databaseContext , filePreferences );
359
+ Optional <Path > file = linkedFile .findIn (databaseContext , preferences . getFilePreferences () );
355
360
356
361
if (file .isEmpty ()) {
357
362
LOGGER .warn ("Could not find file " + linkedFile .getLink ());
@@ -395,13 +400,13 @@ public void edit() {
395
400
public void writeXMPMetadata () {
396
401
// Localization.lang("Writing XMP metadata...")
397
402
BackgroundTask <Void > writeTask = BackgroundTask .wrap (() -> {
398
- Optional <Path > file = linkedFile .findIn (databaseContext , filePreferences );
403
+ Optional <Path > file = linkedFile .findIn (databaseContext , preferences . getFilePreferences () );
399
404
if (file .isEmpty ()) {
400
405
// TODO: Print error message
401
406
// Localization.lang("PDF does not exist");
402
407
} else {
403
408
try {
404
- XmpUtilWriter .writeXmp (file .get (), entry , databaseContext .getDatabase (), xmpPreferences );
409
+ XmpUtilWriter .writeXmp (file .get (), entry , databaseContext .getDatabase (), preferences . getXmpPreferences () );
405
410
} catch (IOException | TransformerException ex ) {
406
411
// TODO: Print error message
407
412
// Localization.lang("Error while writing") + " '" + file.toString() + "': " + ex;
@@ -421,7 +426,7 @@ public void download() {
421
426
throw new UnsupportedOperationException ("In order to download the file it has to be an online link" );
422
427
}
423
428
try {
424
- Optional <Path > targetDirectory = databaseContext .getFirstExistingFileDir (filePreferences );
429
+ Optional <Path > targetDirectory = databaseContext .getFirstExistingFileDir (preferences . getFilePreferences () );
425
430
if (targetDirectory .isEmpty ()) {
426
431
dialogService .showErrorDialogAndWait (Localization .lang ("Download file" ), Localization .lang ("File directory is not set or does not exist!" ));
427
432
return ;
@@ -443,7 +448,7 @@ public void download() {
443
448
}
444
449
445
450
if (!isDuplicate ) {
446
- LinkedFile newLinkedFile = LinkedFilesEditorViewModel .fromFile (destination , databaseContext .getFileDirectories (filePreferences ), externalFileTypes );
451
+ LinkedFile newLinkedFile = LinkedFilesEditorViewModel .fromFile (destination , databaseContext .getFileDirectories (preferences . getFilePreferences () ), externalFileTypes );
447
452
List <LinkedFile > linkedFiles = entry .getFiles ();
448
453
449
454
entry .addLinkedFile (entry , linkedFile , newLinkedFile , linkedFiles );
@@ -495,7 +500,7 @@ public BackgroundTask<Path> prepareDownloadTask(Path targetDirectory, URLDownloa
495
500
String suggestedTypeName = externalFileType .getName ();
496
501
linkedFile .setFileType (suggestedTypeName );
497
502
String suggestedName = linkedFileHandler .getSuggestedFileName (externalFileType .getExtension ());
498
- String fulltextDir = FileUtil .createDirNameFromPattern (databaseContext .getDatabase (), entry , filePreferences .getFileDirectoryPattern ());
503
+ String fulltextDir = FileUtil .createDirNameFromPattern (databaseContext .getDatabase (), entry , preferences . getFilePreferences () .getFileDirectoryPattern ());
499
504
suggestedName = FileNameUniqueness .getNonOverWritingFileName (targetDirectory .resolve (fulltextDir ), suggestedName );
500
505
return targetDirectory .resolve (fulltextDir ).resolve (suggestedName );
501
506
})
@@ -538,4 +543,34 @@ public LinkedFile getFile() {
538
543
public ValidationStatus fileExistsValidationStatus () {
539
544
return fileExistsValidator .getValidationStatus ();
540
545
}
546
+
547
+ public void parsePdfMetadataAndShowMergeDialog () {
548
+ linkedFile .findIn (databaseContext , preferences .getFilePreferences ()).ifPresent (filePath -> {
549
+ MultiMergeEntriesView dialog = new MultiMergeEntriesView (preferences , taskExecutor );
550
+ dialog .addSource (Localization .lang ("Entry" ), entry );
551
+ dialog .addSource (Localization .lang ("Verbatim" ), wrapImporterToSupplier (new PdfVerbatimBibTextImporter (preferences .getImportFormatPreferences ()), filePath ));
552
+ dialog .addSource (Localization .lang ("Embedded" ), wrapImporterToSupplier (new PdfEmbeddedBibFileImporter (preferences .getImportFormatPreferences ()), filePath ));
553
+ dialog .addSource ("Grobid" , wrapImporterToSupplier (new PdfGrobidImporter (preferences .getImportSettingsPreferences (), preferences .getImportFormatPreferences ()), filePath ));
554
+ dialog .addSource (Localization .lang ("XMP metadata" ), wrapImporterToSupplier (new PdfXmpImporter (preferences .getXmpPreferences ()), filePath ));
555
+ dialog .addSource (Localization .lang ("Content" ), wrapImporterToSupplier (new PdfContentImporter (preferences .getImportFormatPreferences ()), filePath ));
556
+ dialog .showAndWait ().ifPresent (newEntry -> {
557
+ databaseContext .getDatabase ().removeEntry (entry );
558
+ databaseContext .getDatabase ().insertEntry (newEntry );
559
+ });
560
+ });
561
+ }
562
+
563
+ private Supplier <BibEntry > wrapImporterToSupplier (Importer importer , Path filePath ) {
564
+ return () -> {
565
+ try {
566
+ ParserResult parserResult = importer .importDatabase (filePath , preferences .getDefaultEncoding ());
567
+ if (parserResult .isInvalid () || parserResult .isEmpty () || !parserResult .getDatabase ().hasEntries ()) {
568
+ return null ;
569
+ }
570
+ return parserResult .getDatabase ().getEntries ().get (0 );
571
+ } catch (IOException e ) {
572
+ return null ;
573
+ }
574
+ };
575
+ }
541
576
}
0 commit comments