getAnyTaskRunning() {
diff --git a/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java b/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java
index e2621d4cec0..759c46fc0ad 100644
--- a/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java
+++ b/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java
@@ -55,6 +55,7 @@
import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.BibEntryTypesManager;
import org.jabref.model.entry.field.Field;
+import org.jabref.model.util.DirectoryMonitorManager;
import org.jabref.model.util.FileUpdateMonitor;
import org.jabref.preferences.PreferencesService;
@@ -73,6 +74,8 @@
*
* EntryEditor also registers itself to the event bus, receiving events whenever a field of the entry changes, enabling
* the text fields to update themselves if the change is made from somewhere else.
+ *
+ * The editors for fields are created via {@link org.jabref.gui.fieldeditors.FieldEditors}.
*/
public class EntryEditor extends BorderPane {
@@ -82,6 +85,7 @@ public class EntryEditor extends BorderPane {
private final BibDatabaseContext databaseContext;
private final EntryEditorPreferences entryEditorPreferences;
private final ExternalFilesEntryLinker fileLinker;
+ private final DirectoryMonitorManager directoryMonitorManager;
private Subscription typeSubscription;
@@ -121,6 +125,7 @@ public class EntryEditor extends BorderPane {
public EntryEditor(LibraryTab libraryTab) {
this.libraryTab = libraryTab;
this.databaseContext = libraryTab.getBibDatabaseContext();
+ this.directoryMonitorManager = libraryTab.getDirectoryMonitorManager();
ViewLoader.view(this)
.root(this)
@@ -307,7 +312,7 @@ private List createTabs() {
bibEntryTypesManager,
keyBindingRepository);
entryEditorTabs.add(sourceTab);
- entryEditorTabs.add(new LatexCitationsTab(databaseContext, preferencesService, taskExecutor, dialogService));
+ entryEditorTabs.add(new LatexCitationsTab(databaseContext, preferencesService, dialogService, directoryMonitorManager));
entryEditorTabs.add(new FulltextSearchResultsTab(stateManager, preferencesService, dialogService, taskExecutor));
return entryEditorTabs;
diff --git a/src/main/java/org/jabref/gui/entryeditor/EntryEditorPreferences.java b/src/main/java/org/jabref/gui/entryeditor/EntryEditorPreferences.java
index ae0fda0194c..fcca2b100ad 100644
--- a/src/main/java/org/jabref/gui/entryeditor/EntryEditorPreferences.java
+++ b/src/main/java/org/jabref/gui/entryeditor/EntryEditorPreferences.java
@@ -49,6 +49,7 @@ public static JournalPopupEnabled fromString(String status) {
private final ObjectProperty enablementStatus;
private final BooleanProperty shouldShowSciteTab;
private final BooleanProperty showUserCommentsFields;
+ private final DoubleProperty previewWidthDividerPosition;
public EntryEditorPreferences(Map> entryEditorTabList,
Map> defaultEntryEditorTabList,
@@ -62,7 +63,8 @@ public EntryEditorPreferences(Map> entryEditorTabList,
boolean autolinkFilesEnabled,
JournalPopupEnabled journalPopupEnabled,
boolean showSciteTab,
- boolean showUserCommentsFields) {
+ boolean showUserCommentsFields,
+ double previewWidthDividerPosition) {
this.entryEditorTabList = new SimpleMapProperty<>(FXCollections.observableMap(entryEditorTabList));
this.defaultEntryEditorTabList = new SimpleMapProperty<>(FXCollections.observableMap(defaultEntryEditorTabList));
@@ -77,6 +79,7 @@ public EntryEditorPreferences(Map> entryEditorTabList,
this.enablementStatus = new SimpleObjectProperty<>(journalPopupEnabled);
this.shouldShowSciteTab = new SimpleBooleanProperty(showSciteTab);
this.showUserCommentsFields = new SimpleBooleanProperty(showUserCommentsFields);
+ this.previewWidthDividerPosition = new SimpleDoubleProperty(previewWidthDividerPosition);
}
public ObservableMap> getEntryEditorTabs() {
@@ -226,4 +229,19 @@ public BooleanProperty showUserCommentsFieldsProperty() {
public void setShowUserCommentsFields(boolean showUserCommentsFields) {
this.showUserCommentsFields.set(showUserCommentsFields);
}
+
+ public void setPreviewWidthDividerPosition(double previewWidthDividerPosition) {
+ this.previewWidthDividerPosition.set(previewWidthDividerPosition);
+ }
+
+ /**
+ * Holds the horizontal divider position when the Preview is shown in the entry editor
+ */
+ public DoubleProperty previewWidthDividerPositionProperty() {
+ return previewWidthDividerPosition;
+ }
+
+ public Double getPreviewWidthDividerPosition() {
+ return previewWidthDividerPosition.get();
+ }
}
diff --git a/src/main/java/org/jabref/gui/entryeditor/FieldsEditorTab.java b/src/main/java/org/jabref/gui/entryeditor/FieldsEditorTab.java
index 20e54396bfe..97348f5838a 100644
--- a/src/main/java/org/jabref/gui/entryeditor/FieldsEditorTab.java
+++ b/src/main/java/org/jabref/gui/entryeditor/FieldsEditorTab.java
@@ -41,6 +41,7 @@
import org.jabref.preferences.PreferencesService;
import com.tobiasdiez.easybind.EasyBind;
+import com.tobiasdiez.easybind.Subscription;
/**
* A single tab displayed in the EntryEditor holding several FieldEditors.
@@ -61,6 +62,7 @@ abstract class FieldsEditorTab extends EntryEditorTab {
private PreviewPanel previewPanel;
private final UndoManager undoManager;
private Collection fields = new ArrayList<>();
+ private Subscription dividerPositionSubscription;
public FieldsEditorTab(boolean compressed,
BibDatabaseContext databaseContext,
@@ -258,9 +260,22 @@ private void initPanel() {
container.getItems().remove(previewPanel);
} else {
container.getItems().add(1, previewPanel);
+ container.setDividerPositions(preferences.getEntryEditorPreferences().getPreviewWidthDividerPosition());
}
});
+
+ // save position
+ dividerPositionSubscription = EasyBind.valueAt(container.getDividers(), 0)
+ .mapObservable(SplitPane.Divider::positionProperty)
+ .subscribeToValues(this::savePreviewWidthDividerPosition);
setContent(container);
}
}
+
+ private void savePreviewWidthDividerPosition(Number position) {
+ if (!preferences.getPreviewPreferences().shouldShowPreviewAsExtraTab()) {
+ preferences.getEntryEditorPreferences().setPreviewWidthDividerPosition(position.doubleValue());
+ }
+ }
}
+
diff --git a/src/main/java/org/jabref/gui/entryeditor/LatexCitationsTab.java b/src/main/java/org/jabref/gui/entryeditor/LatexCitationsTab.java
index 2272316bb8f..0be86194c87 100644
--- a/src/main/java/org/jabref/gui/entryeditor/LatexCitationsTab.java
+++ b/src/main/java/org/jabref/gui/entryeditor/LatexCitationsTab.java
@@ -17,10 +17,10 @@
import org.jabref.gui.DialogService;
import org.jabref.gui.icon.IconTheme;
import org.jabref.gui.texparser.CitationsDisplay;
-import org.jabref.gui.util.TaskExecutor;
import org.jabref.logic.l10n.Localization;
import org.jabref.model.database.BibDatabaseContext;
import org.jabref.model.entry.BibEntry;
+import org.jabref.model.util.DirectoryMonitorManager;
import org.jabref.preferences.PreferencesService;
import com.tobiasdiez.easybind.EasyBind;
@@ -33,9 +33,17 @@ public class LatexCitationsTab extends EntryEditorTab {
private final ProgressIndicator progressIndicator;
private final CitationsDisplay citationsDisplay;
- public LatexCitationsTab(BibDatabaseContext databaseContext, PreferencesService preferencesService,
- TaskExecutor taskExecutor, DialogService dialogService) {
- this.viewModel = new LatexCitationsTabViewModel(databaseContext, preferencesService, taskExecutor, dialogService);
+ public LatexCitationsTab(BibDatabaseContext databaseContext,
+ PreferencesService preferencesService,
+ DialogService dialogService,
+ DirectoryMonitorManager directoryMonitorManager) {
+
+ this.viewModel = new LatexCitationsTabViewModel(
+ databaseContext,
+ preferencesService,
+ dialogService,
+ directoryMonitorManager);
+
this.searchPane = new GridPane();
this.progressIndicator = new ProgressIndicator();
this.citationsDisplay = new CitationsDisplay();
@@ -66,6 +74,11 @@ private void setSearchPane() {
searchPane.setId("citationsPane");
setContent(searchPane);
+ HBox latexDirectoryBox = getLatexDirectoryBox();
+ VBox citationsPane = getCitationsPane();
+ VBox notFoundPane = getNotFoundPane();
+ VBox errorPane = getErrorPane();
+
EasyBind.subscribe(viewModel.statusProperty(), status -> {
searchPane.getChildren().clear();
switch (status) {
@@ -73,36 +86,35 @@ private void setSearchPane() {
searchPane.add(progressIndicator, 0, 0);
break;
case CITATIONS_FOUND:
- searchPane.add(getCitationsPane(), 0, 0);
+ searchPane.add(citationsPane, 0, 0);
break;
case NO_RESULTS:
- searchPane.add(getNotFoundPane(), 0, 0);
+ searchPane.add(notFoundPane, 0, 0);
break;
case ERROR:
- searchPane.add(getErrorPane(), 0, 0);
+ searchPane.add(errorPane, 0, 0);
break;
}
- searchPane.add(getLatexDirectoryBox(), 0, 1);
+ searchPane.add(latexDirectoryBox, 0, 1);
});
}
private HBox getLatexDirectoryBox() {
Text latexDirectoryText = new Text(Localization.lang("Current search directory:"));
- Text latexDirectoryPath = new Text(viewModel.directoryProperty().get().toString());
+ Text latexDirectoryPath = new Text();
+ latexDirectoryPath.textProperty().bind(viewModel.directoryProperty().asString());
latexDirectoryPath.setStyle("-fx-font-family:monospace;-fx-font-weight: bold;");
Button latexDirectoryButton = new Button(Localization.lang("Set LaTeX file directory"));
latexDirectoryButton.setGraphic(IconTheme.JabRefIcons.LATEX_FILE_DIRECTORY.getGraphicNode());
latexDirectoryButton.setOnAction(event -> viewModel.setLatexDirectory());
- Button latexDirectoryRefreshButton = new Button(Localization.lang("Refresh"));
- latexDirectoryRefreshButton.setGraphic(IconTheme.JabRefIcons.REFRESH.getGraphicNode());
- latexDirectoryRefreshButton.setOnAction(event -> viewModel.refreshLatexDirectory());
- HBox latexDirectoryBox = new HBox(10, latexDirectoryText, latexDirectoryPath, latexDirectoryButton, latexDirectoryRefreshButton);
+ HBox latexDirectoryBox = new HBox(10, latexDirectoryText, latexDirectoryPath, latexDirectoryButton);
latexDirectoryBox.setAlignment(Pos.CENTER);
return latexDirectoryBox;
}
private VBox getCitationsPane() {
VBox citationsBox = new VBox(30, citationsDisplay);
+ VBox.setVgrow(citationsDisplay, Priority.ALWAYS);
citationsBox.setStyle("-fx-padding: 0;");
return citationsBox;
}
@@ -122,7 +134,8 @@ private VBox getNotFoundPane() {
private VBox getErrorPane() {
Label titleLabel = new Label(Localization.lang("Error"));
titleLabel.setStyle("-fx-font-size: 1.5em;-fx-font-weight: bold;-fx-text-fill: -fx-accent;");
- Text errorMessageText = new Text(viewModel.searchErrorProperty().get());
+ Text errorMessageText = new Text();
+ errorMessageText.textProperty().bind(viewModel.searchErrorProperty());
VBox errorMessageBox = new VBox(30, titleLabel, errorMessageText);
errorMessageBox.setStyle("-fx-padding: 30 0 0 30;");
return errorMessageBox;
@@ -130,7 +143,7 @@ private VBox getErrorPane() {
@Override
protected void bindToEntry(BibEntry entry) {
- viewModel.init(entry);
+ viewModel.bindToEntry(entry);
}
@Override
diff --git a/src/main/java/org/jabref/gui/entryeditor/LatexCitationsTabViewModel.java b/src/main/java/org/jabref/gui/entryeditor/LatexCitationsTabViewModel.java
index 833ce40ef63..7f6d74cc94f 100644
--- a/src/main/java/org/jabref/gui/entryeditor/LatexCitationsTabViewModel.java
+++ b/src/main/java/org/jabref/gui/entryeditor/LatexCitationsTabViewModel.java
@@ -1,11 +1,15 @@
package org.jabref.gui.entryeditor;
+import java.io.File;
+import java.nio.file.Files;
import java.nio.file.Path;
+import java.util.Collection;
import java.util.Optional;
-import java.util.concurrent.Future;
+import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyListWrapper;
+import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
@@ -14,23 +18,29 @@
import org.jabref.gui.AbstractViewModel;
import org.jabref.gui.DialogService;
-import org.jabref.gui.util.BackgroundTask;
+import org.jabref.gui.util.DefaultTaskExecutor;
import org.jabref.gui.util.DirectoryDialogConfiguration;
-import org.jabref.gui.util.TaskExecutor;
import org.jabref.logic.l10n.Localization;
-import org.jabref.logic.texparser.CitationFinder;
+import org.jabref.logic.texparser.DefaultLatexParser;
import org.jabref.logic.util.io.FileUtil;
import org.jabref.model.database.BibDatabaseContext;
import org.jabref.model.entry.BibEntry;
import org.jabref.model.texparser.Citation;
+import org.jabref.model.texparser.LatexParserResult;
+import org.jabref.model.texparser.LatexParserResults;
+import org.jabref.model.util.DirectoryMonitorManager;
import org.jabref.preferences.PreferencesService;
+import org.apache.commons.io.filefilter.FileFilterUtils;
+import org.apache.commons.io.filefilter.IOFileFilter;
+import org.apache.commons.io.monitor.FileAlterationListener;
+import org.apache.commons.io.monitor.FileAlterationObserver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LatexCitationsTabViewModel extends AbstractViewModel {
- enum Status {
+ public enum Status {
IN_PROGRESS,
CITATIONS_FOUND,
NO_RESULTS,
@@ -39,114 +49,187 @@ enum Status {
private static final Logger LOGGER = LoggerFactory.getLogger(LatexCitationsTabViewModel.class);
private static final String TEX_EXT = ".tex";
+ private static final IOFileFilter FILE_FILTER = FileFilterUtils.or(FileFilterUtils.suffixFileFilter(TEX_EXT), FileFilterUtils.directoryFileFilter());
private final BibDatabaseContext databaseContext;
private final PreferencesService preferencesService;
- private final TaskExecutor taskExecutor;
private final DialogService dialogService;
private final ObjectProperty directory;
- private CitationFinder citationFinder;
private final ObservableList citationList;
private final ObjectProperty status;
private final StringProperty searchError;
- private Future> searchTask;
+ private final BooleanProperty updateStatusOnCreate;
+ private final DefaultLatexParser latexParser;
+ private final LatexParserResults latexFiles;
+ private final DirectoryMonitorManager directoryMonitorManager;
+ private final FileAlterationListener listener;
+ private FileAlterationObserver observer;
private BibEntry currentEntry;
public LatexCitationsTabViewModel(BibDatabaseContext databaseContext,
PreferencesService preferencesService,
- TaskExecutor taskExecutor,
- DialogService dialogService) {
+ DialogService dialogService,
+ DirectoryMonitorManager directoryMonitorManager) {
+
this.databaseContext = databaseContext;
this.preferencesService = preferencesService;
- this.taskExecutor = taskExecutor;
this.dialogService = dialogService;
this.directory = new SimpleObjectProperty<>(databaseContext.getMetaData().getLatexFileDirectory(preferencesService.getFilePreferences().getUserAndHost())
.orElse(FileUtil.getInitialDirectory(databaseContext, preferencesService.getFilePreferences().getWorkingDirectory())));
- this.citationFinder = new CitationFinder(directory.get());
this.citationList = FXCollections.observableArrayList();
this.status = new SimpleObjectProperty<>(Status.IN_PROGRESS);
this.searchError = new SimpleStringProperty("");
+ this.directoryMonitorManager = directoryMonitorManager;
+ this.updateStatusOnCreate = new SimpleBooleanProperty(false);
+ this.listener = getListener();
+
+ this.latexParser = new DefaultLatexParser();
+ this.latexFiles = new LatexParserResults();
}
- public void init(BibEntry entry) {
- cancelSearch();
+ private FileAlterationListener getListener() {
+ return new FileAlterationListener() {
+ @Override
+ public void onStart(FileAlterationObserver observer) {
+ if (!updateStatusOnCreate.get()) {
+ DefaultTaskExecutor.runInJavaFXThread(() -> status.set(Status.IN_PROGRESS));
+ }
+ }
+
+ @Override
+ public void onStop(FileAlterationObserver observer) {
+ if (!updateStatusOnCreate.get()) {
+ updateStatusOnCreate.set(true);
+ updateStatus();
+ }
+ }
+
+ @Override
+ public void onFileCreate(File file) {
+ Path path = file.toPath();
+ LatexParserResult result = latexParser.parse(path).get();
+ latexFiles.add(path, result);
+
+ Optional citationKey = currentEntry.getCitationKey();
+ if (citationKey.isPresent()) {
+ Collection citations = result.getCitationsByKey(citationKey.get());
+ DefaultTaskExecutor.runInJavaFXThread(() -> citationList.addAll(citations));
+ }
+
+ if (updateStatusOnCreate.get()) {
+ updateStatus();
+ }
+ }
+
+ @Override
+ public void onFileDelete(File file) {
+ LatexParserResult result = latexFiles.remove(file.toPath());
+
+ Optional citationKey = currentEntry.getCitationKey();
+ if (citationKey.isPresent()) {
+ Collection citations = result.getCitationsByKey(citationKey.get());
+ DefaultTaskExecutor.runInJavaFXThread(() -> citationList.removeAll(citations));
+ updateStatus();
+ }
+ }
+
+ @Override
+ public void onFileChange(File file) {
+ onFileDelete(file);
+ onFileCreate(file);
+ updateStatus();
+ }
+
+ @Override
+ public void onDirectoryChange(File directory) {
+ }
+
+ @Override
+ public void onDirectoryCreate(File directory) {
+ }
+
+ @Override
+ public void onDirectoryDelete(File directory) {
+ }
+ };
+ }
+
+ public void bindToEntry(BibEntry entry) {
+ checkAndUpdateDirectory();
currentEntry = entry;
- Optional citeKey = entry.getCitationKey();
+ Optional citationKey = entry.getCitationKey();
+
+ if (observer == null) {
+ observer = new FileAlterationObserver(directory.get().toFile(), FILE_FILTER);
+ directoryMonitorManager.addObserver(observer, listener);
+ }
- if (citeKey.isPresent()) {
- startSearch(citeKey.get());
+ if (citationKey.isPresent()) {
+ citationList.setAll(latexFiles.getCitationsByKey(citationKey.get()));
+ if (!status.get().equals(Status.IN_PROGRESS)) {
+ updateStatus();
+ }
} else {
searchError.set(Localization.lang("Selected entry does not have an associated citation key."));
status.set(Status.ERROR);
}
}
- public ObjectProperty directoryProperty() {
- return directory;
- }
-
- public ObservableList getCitationList() {
- return new ReadOnlyListWrapper<>(citationList);
- }
-
- public ObjectProperty statusProperty() {
- return status;
- }
+ public void setLatexDirectory() {
+ DirectoryDialogConfiguration directoryDialogConfiguration = new DirectoryDialogConfiguration.Builder()
+ .withInitialDirectory(directory.get()).build();
- public StringProperty searchErrorProperty() {
- return searchError;
- }
+ dialogService.showDirectorySelectionDialog(directoryDialogConfiguration).ifPresent(selectedDirectory ->
+ databaseContext.getMetaData().setLatexFileDirectory(preferencesService.getFilePreferences().getUserAndHost(), selectedDirectory.toAbsolutePath()));
- private void startSearch(String citeKey) {
- // we need to check whether the user meanwhile set the LaTeX file directory or the database changed locations
checkAndUpdateDirectory();
-
- searchTask = BackgroundTask.wrap(() -> citationFinder.searchAndParse(citeKey))
- .onRunning(() -> status.set(Status.IN_PROGRESS))
- .onSuccess(result -> {
- citationList.setAll(result);
- status.set(citationList.isEmpty() ? Status.NO_RESULTS : Status.CITATIONS_FOUND);
- })
- .onFailure(error -> {
- searchError.set(error.getMessage());
- status.set(Status.ERROR);
- })
- .executeWith(taskExecutor);
- }
-
- private void cancelSearch() {
- if (searchTask == null || searchTask.isCancelled() || searchTask.isDone()) {
- return;
- }
-
- status.set(Status.IN_PROGRESS);
- searchTask.cancel(true);
}
- public void checkAndUpdateDirectory() {
+ private void checkAndUpdateDirectory() {
Path newDirectory = databaseContext.getMetaData().getLatexFileDirectory(preferencesService.getFilePreferences().getUserAndHost())
.orElse(FileUtil.getInitialDirectory(databaseContext, preferencesService.getFilePreferences().getWorkingDirectory()));
if (!newDirectory.equals(directory.get())) {
+ status.set(Status.IN_PROGRESS);
+ updateStatusOnCreate.set(false);
+ citationList.clear();
+ latexFiles.clear();
+
+ directoryMonitorManager.removeObserver(observer);
directory.set(newDirectory);
- citationFinder = new CitationFinder(newDirectory);
+ observer = new FileAlterationObserver(directory.get().toFile(), FILE_FILTER);
+ directoryMonitorManager.addObserver(observer, listener);
}
}
- public void setLatexDirectory() {
- DirectoryDialogConfiguration directoryDialogConfiguration = new DirectoryDialogConfiguration.Builder()
- .withInitialDirectory(directory.get()).build();
+ private void updateStatus() {
+ DefaultTaskExecutor.runInJavaFXThread(() -> {
+ if (!Files.exists(directory.get())) {
+ searchError.set(Localization.lang("Current search directory does not exist: %0", directory.get()));
+ status.set(Status.ERROR);
+ } else if (citationList.isEmpty()) {
+ status.set(Status.NO_RESULTS);
+ } else {
+ status.set(Status.CITATIONS_FOUND);
+ }
+ });
+ }
- dialogService.showDirectorySelectionDialog(directoryDialogConfiguration).ifPresent(selectedDirectory ->
- databaseContext.getMetaData().setLatexFileDirectory(preferencesService.getFilePreferences().getUserAndHost(), selectedDirectory.toAbsolutePath()));
+ public ObjectProperty directoryProperty() {
+ return directory;
+ }
+
+ public ObservableList getCitationList() {
+ return new ReadOnlyListWrapper<>(citationList);
+ }
- init(currentEntry);
+ public ObjectProperty statusProperty() {
+ return status;
}
- public void refreshLatexDirectory() {
- citationFinder = new CitationFinder(directory.get());
- init(currentEntry);
+ public StringProperty searchErrorProperty() {
+ return searchError;
}
public boolean shouldShow() {
diff --git a/src/main/java/org/jabref/gui/externalfiles/DownloadFullTextAction.java b/src/main/java/org/jabref/gui/externalfiles/DownloadFullTextAction.java
index 321f31bc31f..7197f9c2422 100644
--- a/src/main/java/org/jabref/gui/externalfiles/DownloadFullTextAction.java
+++ b/src/main/java/org/jabref/gui/externalfiles/DownloadFullTextAction.java
@@ -141,8 +141,7 @@ private void addLinkedFileFromURL(BibDatabaseContext databaseContext, URL url, B
taskExecutor,
dialogService,
preferences);
-
- onlineFile.download();
+ onlineFile.download(true);
} else {
dialogService.notify(Localization.lang("Full text document for entry %0 already linked.",
entry.getCitationKey().orElse(Localization.lang("undefined"))));
diff --git a/src/main/java/org/jabref/gui/externalfiles/ImportHandler.java b/src/main/java/org/jabref/gui/externalfiles/ImportHandler.java
index de4ac03f686..96ad7e46e4d 100644
--- a/src/main/java/org/jabref/gui/externalfiles/ImportHandler.java
+++ b/src/main/java/org/jabref/gui/externalfiles/ImportHandler.java
@@ -194,7 +194,7 @@ public void importCleanedEntries(List entries) {
bibDatabaseContext.getDatabase().insertEntries(entries);
generateKeys(entries);
setAutomaticFields(entries);
- addToGroups(entries, stateManager.getSelectedGroup(bibDatabaseContext));
+ addToGroups(entries, stateManager.getSelectedGroups(bibDatabaseContext));
}
public void importEntryWithDuplicateCheck(BibDatabaseContext bibDatabaseContext, BibEntry entry) {
@@ -276,7 +276,7 @@ public void downloadLinkedFiles(BibEntry entry) {
taskExecutor,
dialogService,
preferencesService
- ).download()
+ ).download(false)
);
}
}
@@ -405,13 +405,13 @@ public void importEntriesWithDuplicateCheck(BibDatabaseContext database, List linkedFile.edit();
case OPEN_FILE -> linkedFile.open();
case OPEN_FOLDER -> linkedFile.openFolder();
- case DOWNLOAD_FILE -> linkedFile.download();
+ case DOWNLOAD_FILE -> linkedFile.download(true);
case REDOWNLOAD_FILE -> linkedFile.redownload();
case RENAME_FILE_TO_PATTERN -> linkedFile.renameToSuggestion();
case RENAME_FILE_TO_NAME -> linkedFile.askForNameAndRename();
diff --git a/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditorViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditorViewModel.java
index 91d0dbf6690..005ef6e75ff 100644
--- a/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditorViewModel.java
+++ b/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditorViewModel.java
@@ -279,7 +279,7 @@ private void addFromURLAndDownload(URL url) {
dialogService,
preferences);
files.add(onlineFile);
- onlineFile.download();
+ onlineFile.download(true);
}
public void deleteFile(LinkedFileViewModel file) {
diff --git a/src/main/java/org/jabref/gui/frame/FrameDndHandler.java b/src/main/java/org/jabref/gui/frame/FrameDndHandler.java
index 75fd0aebb77..424b3512488 100644
--- a/src/main/java/org/jabref/gui/frame/FrameDndHandler.java
+++ b/src/main/java/org/jabref/gui/frame/FrameDndHandler.java
@@ -26,8 +26,12 @@
import org.jabref.model.groups.GroupTreeNode;
import com.tobiasdiez.easybind.EasyBind;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class FrameDndHandler {
+ private static final Logger LOGGER = LoggerFactory.getLogger(FrameDndHandler.class);
+
private final TabPane tabPane;
private final Supplier scene;
private final Supplier openDatabaseAction;
@@ -81,45 +85,65 @@ private void onTabDragDropped(Node destinationTabNode, DragEvent tabDragEvent, T
tabDragEvent.setDropCompleted(true);
tabDragEvent.consume();
} else {
- if (stateManager.getActiveDatabase().isEmpty()
- || stateManager.getActiveDatabase().get().getMetaData().getGroups().isEmpty()) {
+ if (stateManager.getActiveDatabase().isEmpty()) {
+ LOGGER.warn("Active library is empty when dropping entries");
return;
}
+ LibraryTab destinationLibraryTab = null;
for (Tab libraryTab : tabPane.getTabs()) {
if (libraryTab.getId().equals(destinationTabNode.getId()) &&
!tabPane.getSelectionModel().getSelectedItem().equals(libraryTab)) {
- LibraryTab destinationLibraryTab = (LibraryTab) libraryTab;
- if (hasGroups(dragboard)) {
- List groupPathToSources = getGroups(dragboard);
-
- copyRootNode(destinationLibraryTab);
-
- GroupTreeNode destinationLibraryGroupRoot = destinationLibraryTab
- .getBibDatabaseContext()
- .getMetaData()
- .getGroups().get();
-
- GroupTreeNode groupsTreeNode = stateManager.getActiveDatabase().get()
- .getMetaData()
- .getGroups()
- .get();
-
- for (String pathToSource : groupPathToSources) {
- GroupTreeNode groupTreeNodeToCopy = groupsTreeNode
- .getChildByPath(pathToSource)
- .get();
- copyGroupTreeNode((LibraryTab) libraryTab, destinationLibraryGroupRoot, groupTreeNodeToCopy);
- }
- return;
- }
- destinationLibraryTab.dropEntry(stateManager.getLocalDragboard().getBibEntries());
+ destinationLibraryTab = (LibraryTab) libraryTab;
+ break;
}
}
+
+ if (destinationLibraryTab == null) {
+ LOGGER.warn("Failed to find library tab to drop into");
+ return;
+ }
+
+ if (hasEntries(dragboard)) {
+ List entryCopies = stateManager.getLocalDragboard().getBibEntries()
+ .stream().map(entry -> (BibEntry) entry.clone())
+ .toList();
+ destinationLibraryTab.dropEntry(entryCopies);
+ } else if (hasGroups(dragboard)) {
+ dropGroups(dragboard, destinationLibraryTab);
+ }
+
tabDragEvent.consume();
}
}
+ private void dropGroups(Dragboard dragboard, LibraryTab destinationLibraryTab) {
+ List groupPathToSources = getGroups(dragboard);
+
+ copyRootNode(destinationLibraryTab);
+
+ GroupTreeNode destinationLibraryGroupRoot = destinationLibraryTab
+ .getBibDatabaseContext()
+ .getMetaData()
+ .getGroups().get();
+
+ GroupTreeNode groupsTreeNode = stateManager.getActiveDatabase().get()
+ .getMetaData()
+ .getGroups()
+ .get();
+
+ for (String pathToSource : groupPathToSources) {
+ GroupTreeNode groupTreeNodeToCopy = groupsTreeNode
+ .getChildByPath(pathToSource)
+ .get();
+ copyGroupTreeNode(destinationLibraryTab, destinationLibraryGroupRoot, groupTreeNodeToCopy);
+ }
+ }
+
+ private boolean hasEntries(Dragboard dragboard) {
+ return dragboard.hasContent(DragAndDropDataFormats.ENTRIES);
+ }
+
private void onTabDragOver(DragEvent event, DragEvent tabDragEvent, Tab dndIndicator) {
if (hasBibFiles(tabDragEvent.getDragboard()) || hasGroups(tabDragEvent.getDragboard())) {
tabDragEvent.acceptTransferModes(TransferMode.ANY);
diff --git a/src/main/java/org/jabref/gui/frame/JabRefFrame.java b/src/main/java/org/jabref/gui/frame/JabRefFrame.java
index 84a34f53966..e154ae6f7e6 100644
--- a/src/main/java/org/jabref/gui/frame/JabRefFrame.java
+++ b/src/main/java/org/jabref/gui/frame/JabRefFrame.java
@@ -9,6 +9,7 @@
import java.util.function.Supplier;
import javafx.application.Platform;
+import javafx.beans.InvalidationListener;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.StringBinding;
import javafx.collections.transformation.FilteredList;
@@ -212,7 +213,9 @@ private void initLayout() {
splitPane.getItems().addAll(tabbedPane);
SplitPane.setResizableWithParent(sidePane, false);
- EasyBind.subscribe(sidePane.widthProperty(), c -> updateSidePane());
+ sidePane.widthProperty().addListener(c -> updateSidePane());
+ sidePane.getChildren().addListener((InvalidationListener) c -> updateSidePane());
+ updateSidePane();
setCenter(splitPane);
}
diff --git a/src/main/java/org/jabref/gui/groups/GroupNodeViewModel.java b/src/main/java/org/jabref/gui/groups/GroupNodeViewModel.java
index bd113bf249e..dccd1fef498 100644
--- a/src/main/java/org/jabref/gui/groups/GroupNodeViewModel.java
+++ b/src/main/java/org/jabref/gui/groups/GroupNodeViewModel.java
@@ -262,7 +262,7 @@ private void refreshGroup() {
DefaultTaskExecutor.runInJavaFXThread(() -> {
updateMatchedEntries(); // Update the entries matched by the group
// "Re-add" to the selected groups if it were selected, this refreshes the entries the user views
- ObservableList selectedGroups = this.stateManager.getSelectedGroup(this.databaseContext);
+ ObservableList selectedGroups = this.stateManager.getSelectedGroups(this.databaseContext);
if (selectedGroups.remove(this.groupNode)) {
selectedGroups.add(this.groupNode);
}
diff --git a/src/main/java/org/jabref/gui/groups/GroupTreeViewModel.java b/src/main/java/org/jabref/gui/groups/GroupTreeViewModel.java
index 4efab42033b..de0c579699b 100644
--- a/src/main/java/org/jabref/gui/groups/GroupTreeViewModel.java
+++ b/src/main/java/org/jabref/gui/groups/GroupTreeViewModel.java
@@ -153,11 +153,11 @@ private void onActiveDatabaseChanged(Optional newDatabase) {
.orElse(GroupNodeViewModel.getAllEntriesGroup(newDatabase.get(), stateManager, taskExecutor, localDragboard, preferences));
rootGroup.setValue(newRoot);
- if (stateManager.getSelectedGroup(newDatabase.get()).isEmpty()) {
+ if (stateManager.getSelectedGroups(newDatabase.get()).isEmpty()) {
stateManager.setSelectedGroups(newDatabase.get(), Collections.singletonList(newRoot.getGroupNode()));
}
selectedGroups.setAll(
- stateManager.getSelectedGroup(newDatabase.get()).stream()
+ stateManager.getSelectedGroups(newDatabase.get()).stream()
.map(selectedGroup -> new GroupNodeViewModel(newDatabase.get(), stateManager, taskExecutor, selectedGroup, localDragboard, preferences))
.collect(Collectors.toList()));
} else {
diff --git a/src/main/java/org/jabref/gui/linkedfile/AttachFileFromURLAction.java b/src/main/java/org/jabref/gui/linkedfile/AttachFileFromURLAction.java
index 08c9240b0a2..e95af5e25a6 100644
--- a/src/main/java/org/jabref/gui/linkedfile/AttachFileFromURLAction.java
+++ b/src/main/java/org/jabref/gui/linkedfile/AttachFileFromURLAction.java
@@ -68,7 +68,7 @@ public void execute() {
taskExecutor,
dialogService,
preferencesService);
- onlineFile.download();
+ onlineFile.download(true);
} catch (MalformedURLException exception) {
dialogService.showErrorDialogAndWait(Localization.lang("Invalid URL"), exception);
}
diff --git a/src/main/java/org/jabref/gui/linkedfile/DownloadLinkedFileAction.java b/src/main/java/org/jabref/gui/linkedfile/DownloadLinkedFileAction.java
index 53684fe43f7..6df76576628 100644
--- a/src/main/java/org/jabref/gui/linkedfile/DownloadLinkedFileAction.java
+++ b/src/main/java/org/jabref/gui/linkedfile/DownloadLinkedFileAction.java
@@ -6,6 +6,8 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Optional;
import javax.net.ssl.HostnameVerifier;
@@ -55,6 +57,7 @@ public class DownloadLinkedFileAction extends SimpleCommand {
private final String downloadUrl;
private final FilePreferences filePreferences;
private final TaskExecutor taskExecutor;
+ private final boolean keepHtmlLink;
private final BibDatabaseContext databaseContext;
@@ -68,7 +71,8 @@ public DownloadLinkedFileAction(BibDatabaseContext databaseContext,
DialogService dialogService,
FilePreferences filePreferences,
TaskExecutor taskExecutor,
- String suggestedName) {
+ String suggestedName,
+ boolean keepHtmlLink) {
this.databaseContext = databaseContext;
this.entry = entry;
this.linkedFile = linkedFile;
@@ -77,10 +81,14 @@ public DownloadLinkedFileAction(BibDatabaseContext databaseContext,
this.dialogService = dialogService;
this.filePreferences = filePreferences;
this.taskExecutor = taskExecutor;
+ this.keepHtmlLink = keepHtmlLink;
this.linkedFileHandler = new LinkedFileHandler(linkedFile, entry, databaseContext, filePreferences);
}
+ /**
+ * Downloads the given linked file to the first existing file directory. It keeps HTML files as URLs.
+ */
public DownloadLinkedFileAction(BibDatabaseContext databaseContext,
BibEntry entry,
LinkedFile linkedFile,
@@ -88,12 +96,12 @@ public DownloadLinkedFileAction(BibDatabaseContext databaseContext,
DialogService dialogService,
FilePreferences filePreferences,
TaskExecutor taskExecutor) {
- this(databaseContext, entry, linkedFile, downloadUrl, dialogService, filePreferences, taskExecutor, "");
+ this(databaseContext, entry, linkedFile, downloadUrl, dialogService, filePreferences, taskExecutor, "", true);
}
@Override
public void execute() {
- LOGGER.info("Downloading file from " + downloadUrl);
+ LOGGER.info("Downloading file from {}", downloadUrl);
if (downloadUrl.isEmpty() || !LinkedFile.isOnlineLink(downloadUrl)) {
throw new UnsupportedOperationException("In order to download the file, the url has to be an online link");
}
@@ -132,51 +140,64 @@ private void doDownload(Path targetDirectory, URLDownload urlDownload) {
taskExecutor.execute(downloadTask);
}
- private void onSuccess(Path targetDirectory, Path destination) {
+ /**
+ * @param targetDirectory The directory to store the file into. Is an absolute path.
+ */
+ private void onSuccess(Path targetDirectory, Path downloadedFile) {
+ assert targetDirectory.isAbsolute();
+
boolean isDuplicate;
boolean isHtml;
try {
- isDuplicate = FileNameUniqueness.isDuplicatedFile(targetDirectory, destination.getFileName(), dialogService);
+ isDuplicate = FileNameUniqueness.isDuplicatedFile(targetDirectory, downloadedFile.getFileName(), dialogService);
} catch (IOException e) {
LOGGER.error("FileNameUniqueness.isDuplicatedFile failed", e);
return;
}
if (isDuplicate) {
- destination = targetDirectory.resolve(
- FileNameUniqueness.eraseDuplicateMarks(destination.getFileName()));
-
- linkedFile.setLink(FileUtil.relativize(destination,
- databaseContext.getFileDirectories(filePreferences)).toString());
+ // We do not add duplicate files.
+ // The downloaded file was deleted in {@link org.jabref.logic.util.io.FileNameUniqueness.isDuplicatedFile]}
+ LOGGER.info("File {} already exists in target directory {}.", downloadedFile.getFileName(), targetDirectory);
+ return;
+ }
- isHtml = linkedFile.getFileType().equals(StandardExternalFileType.URL.getName());
+ // we need to call LinkedFileViewModel#fromFile, because we need to make the path relative to the configured directories
+ LinkedFile newLinkedFile = LinkedFilesEditorViewModel.fromFile(
+ downloadedFile,
+ databaseContext.getFileDirectories(filePreferences),
+ filePreferences);
+ if (newLinkedFile.getDescription().isEmpty() && !linkedFile.getDescription().isEmpty()) {
+ newLinkedFile.setDescription((linkedFile.getDescription()));
+ }
+ if (linkedFile.getSourceUrl().isEmpty() && LinkedFile.isOnlineLink(linkedFile.getLink())) {
+ newLinkedFile.setSourceURL(linkedFile.getLink());
} else {
- // we need to call LinkedFileViewModel#fromFile, because we need to make the path relative to the configured directories
- LinkedFile newLinkedFile = LinkedFilesEditorViewModel.fromFile(
- destination,
- databaseContext.getFileDirectories(filePreferences),
- filePreferences);
- if (newLinkedFile.getDescription().isEmpty() && !linkedFile.getDescription().isEmpty()) {
- newLinkedFile.setDescription((linkedFile.getDescription()));
- }
- if (linkedFile.getSourceUrl().isEmpty() && LinkedFile.isOnlineLink(linkedFile.getLink())) {
- newLinkedFile.setSourceURL(linkedFile.getLink());
- } else {
- newLinkedFile.setSourceURL(linkedFile.getSourceUrl());
- }
- entry.replaceDownloadedFile(linkedFile.getLink(), newLinkedFile);
- isHtml = newLinkedFile.getFileType().equals(StandardExternalFileType.URL.getName());
+ newLinkedFile.setSourceURL(linkedFile.getSourceUrl());
}
- // Notify in bar when the file type is HTML.
+ isHtml = newLinkedFile.getFileType().equals(StandardExternalFileType.URL.getName());
if (isHtml) {
- dialogService.notify(Localization.lang("Downloaded website as an HTML file."));
- LOGGER.debug("Downloaded website {} as an HTML file at {}", linkedFile.getLink(), destination);
+ if (this.keepHtmlLink) {
+ dialogService.notify(Localization.lang("Download '%0' was a HTML file. Keeping URL.", downloadUrl));
+ } else {
+ dialogService.notify(Localization.lang("Download '%0' was a HTML file. Removed.", downloadUrl));
+ List newFiles = new ArrayList<>(entry.getFiles());
+ newFiles.remove(linkedFile);
+ entry.setFiles(newFiles);
+ try {
+ Files.delete(downloadedFile);
+ } catch (IOException e) {
+ LOGGER.error("Could not delete downloaded file {}.", downloadedFile, e);
+ }
+ }
+ } else {
+ entry.replaceDownloadedFile(linkedFile.getLink(), newLinkedFile);
}
}
private void onFailure(URLDownload urlDownload, Exception ex) {
- LOGGER.error("Error downloading from URL: " + urlDownload, ex);
+ LOGGER.error("Error downloading from URL: {}", urlDownload, ex);
String fetcherExceptionMessage = ex.getMessage();
String failedTitle = Localization.lang("Failed to download from URL");
int statusCode;
@@ -261,7 +282,7 @@ private Optional inferFileTypeFromMimeType(URLDownload urlDown
String mimeType = urlDownload.getMimeType();
if (mimeType != null) {
- LOGGER.debug("MIME Type suggested: " + mimeType);
+ LOGGER.debug("MIME Type suggested: {}", mimeType);
return ExternalFileTypes.getExternalFileTypeByMimeType(mimeType, filePreferences);
} else {
return Optional.empty();
diff --git a/src/main/java/org/jabref/gui/linkedfile/RedownloadMissingFilesAction.java b/src/main/java/org/jabref/gui/linkedfile/RedownloadMissingFilesAction.java
index f08933976cb..3a69061b10f 100644
--- a/src/main/java/org/jabref/gui/linkedfile/RedownloadMissingFilesAction.java
+++ b/src/main/java/org/jabref/gui/linkedfile/RedownloadMissingFilesAction.java
@@ -56,6 +56,9 @@ public void execute() {
}
}
+ /**
+ * @implNote Similar method {@link org.jabref.gui.fieldeditors.LinkedFileViewModel#redownload}
+ */
private void redownloadMissing(BibDatabaseContext databaseContext) {
LOGGER.info("Redownloading missing files");
databaseContext.getEntries().forEach(entry -> {
@@ -71,7 +74,7 @@ private void redownloadMissing(BibDatabaseContext databaseContext) {
String fileName = Path.of(linkedFile.getLink()).getFileName().toString();
DownloadLinkedFileAction downloadAction = new DownloadLinkedFileAction(this.databaseContext, entry,
- linkedFile, linkedFile.getSourceUrl(), dialogService, filePreferences, taskExecutor, fileName);
+ linkedFile, linkedFile.getSourceUrl(), dialogService, filePreferences, taskExecutor, fileName, true);
downloadAction.execute();
});
});
diff --git a/src/main/java/org/jabref/gui/search/GlobalSearchBar.java b/src/main/java/org/jabref/gui/search/GlobalSearchBar.java
index de9319c93a3..5c18e02243a 100644
--- a/src/main/java/org/jabref/gui/search/GlobalSearchBar.java
+++ b/src/main/java/org/jabref/gui/search/GlobalSearchBar.java
@@ -238,7 +238,7 @@ public GlobalSearchBar(LibraryTabContainer tabContainer,
query -> setSearchTerm(query.map(SearchQuery::getQuery).orElse("")));
this.searchQueryProperty.addListener((obs, oldValue, newValue) -> newValue.ifPresent(this::updateSearchResultsForQuery));
- this.searchQueryProperty.addListener((obs, oldValue, newValue) -> searchQueryProperty.get().ifPresent(this::updateSearchResultsForQuery));
+ this.stateManager.activeDatabaseProperty().addListener(obs -> searchQueryProperty.get().ifPresent(this::updateSearchResultsForQuery));
/*
* The listener tracks a change on the focus property value.
* This happens, from active (user types a query) to inactive / focus
diff --git a/src/main/java/org/jabref/gui/util/DefaultDirectoryMonitor.java b/src/main/java/org/jabref/gui/util/DefaultDirectoryMonitor.java
new file mode 100644
index 00000000000..522a63632b0
--- /dev/null
+++ b/src/main/java/org/jabref/gui/util/DefaultDirectoryMonitor.java
@@ -0,0 +1,54 @@
+package org.jabref.gui.util;
+
+import org.jabref.model.util.DirectoryMonitor;
+
+import org.apache.commons.io.monitor.FileAlterationListener;
+import org.apache.commons.io.monitor.FileAlterationMonitor;
+import org.apache.commons.io.monitor.FileAlterationObserver;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DefaultDirectoryMonitor implements DirectoryMonitor {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(DefaultDirectoryMonitor.class);
+ private static final int POLL_INTERVAL = 1000;
+
+ private final FileAlterationMonitor monitor;
+
+ public DefaultDirectoryMonitor() {
+ monitor = new FileAlterationMonitor(POLL_INTERVAL);
+ start();
+ }
+
+ @Override
+ public void addObserver(FileAlterationObserver observer, FileAlterationListener listener) {
+ if (observer != null) {
+ observer.addListener(listener);
+ monitor.addObserver(observer);
+ }
+ }
+
+ @Override
+ public void removeObserver(FileAlterationObserver observer) {
+ if (observer != null) {
+ monitor.removeObserver(observer);
+ }
+ }
+
+ public void start() {
+ try {
+ monitor.start();
+ } catch (Exception e) {
+ LOGGER.error("Error starting directory monitor", e);
+ }
+ }
+
+ @Override
+ public void shutdown() {
+ try {
+ monitor.stop();
+ } catch (Exception e) {
+ LOGGER.error("Error stopping directory monitor", e);
+ }
+ }
+}
diff --git a/src/main/java/org/jabref/logic/formatter/Formatters.java b/src/main/java/org/jabref/logic/formatter/Formatters.java
index bcc7c202295..fb827f9ab8e 100644
--- a/src/main/java/org/jabref/logic/formatter/Formatters.java
+++ b/src/main/java/org/jabref/logic/formatter/Formatters.java
@@ -25,7 +25,8 @@
import org.jabref.logic.formatter.bibtexfields.NormalizeUnicodeFormatter;
import org.jabref.logic.formatter.bibtexfields.OrdinalsToSuperscriptFormatter;
import org.jabref.logic.formatter.bibtexfields.RegexFormatter;
-import org.jabref.logic.formatter.bibtexfields.RemoveBracesFormatter;
+import org.jabref.logic.formatter.bibtexfields.RemoveEnclosingBracesFormatter;
+import org.jabref.logic.formatter.bibtexfields.RemoveWordEnclosingAndOuterEnclosingBracesFormatter;
import org.jabref.logic.formatter.bibtexfields.ShortenDOIFormatter;
import org.jabref.logic.formatter.bibtexfields.UnicodeToLatexFormatter;
import org.jabref.logic.formatter.bibtexfields.UnitsToLatexFormatter;
@@ -82,7 +83,8 @@ public static List getOthers() {
new NormalizeNamesFormatter(),
new NormalizePagesFormatter(),
new OrdinalsToSuperscriptFormatter(),
- new RemoveBracesFormatter(),
+ new RemoveEnclosingBracesFormatter(),
+ new RemoveWordEnclosingAndOuterEnclosingBracesFormatter(),
new UnitsToLatexFormatter(),
new EscapeUnderscoresFormatter(),
new EscapeAmpersandsFormatter(),
diff --git a/src/main/java/org/jabref/logic/formatter/bibtexfields/RemoveBracesFormatter.java b/src/main/java/org/jabref/logic/formatter/bibtexfields/RemoveEnclosingBracesFormatter.java
similarity index 97%
rename from src/main/java/org/jabref/logic/formatter/bibtexfields/RemoveBracesFormatter.java
rename to src/main/java/org/jabref/logic/formatter/bibtexfields/RemoveEnclosingBracesFormatter.java
index c29b081cc48..31b071aac12 100644
--- a/src/main/java/org/jabref/logic/formatter/bibtexfields/RemoveBracesFormatter.java
+++ b/src/main/java/org/jabref/logic/formatter/bibtexfields/RemoveEnclosingBracesFormatter.java
@@ -6,7 +6,7 @@
import org.jspecify.annotations.NullMarked;
@NullMarked
-public class RemoveBracesFormatter extends Formatter {
+public class RemoveEnclosingBracesFormatter extends Formatter {
@Override
public String getName() {
@@ -18,6 +18,16 @@ public String getKey() {
return "remove_braces";
}
+ @Override
+ public String getDescription() {
+ return Localization.lang("Removes braces encapsulating the complete field content.");
+ }
+
+ @Override
+ public String getExampleInput() {
+ return "{In CDMA}";
+ }
+
@Override
public String format(String value) {
String formatted = value;
@@ -37,16 +47,6 @@ public String format(String value) {
return formatted;
}
- @Override
- public String getDescription() {
- return Localization.lang("Removes braces encapsulating the complete field content.");
- }
-
- @Override
- public String getExampleInput() {
- return "{In CDMA}";
- }
-
/**
* Check if a string at any point has had more ending } braces than opening { ones.
* Will e.g. return true for the string "DNA} text {EPA"
diff --git a/src/main/java/org/jabref/logic/formatter/bibtexfields/RemoveWordEnclosingAndOuterEnclosingBracesFormatter.java b/src/main/java/org/jabref/logic/formatter/bibtexfields/RemoveWordEnclosingAndOuterEnclosingBracesFormatter.java
new file mode 100644
index 00000000000..c70c7315ebe
--- /dev/null
+++ b/src/main/java/org/jabref/logic/formatter/bibtexfields/RemoveWordEnclosingAndOuterEnclosingBracesFormatter.java
@@ -0,0 +1,110 @@
+package org.jabref.logic.formatter.bibtexfields;
+
+import java.util.Objects;
+import java.util.StringJoiner;
+
+import org.jabref.logic.cleanup.Formatter;
+import org.jabref.logic.l10n.Localization;
+import org.jabref.model.strings.StringUtil;
+
+import org.jspecify.annotations.NullMarked;
+
+/**
+ * Removes start and end brace both at the complete string and at beginning/end of a word
+ *
+ * E.g.,
+ *
+ * - {Vall{\'e}e Poussin} -> Vall{\'e}e Poussin
+ * - {Vall{\'e}e} {Poussin} -> Vall{\'e}e Poussin
+ * - Vall{\'e}e Poussin -> Vall{\'e}e Poussin
+ *
+ */
+@NullMarked
+public class RemoveWordEnclosingAndOuterEnclosingBracesFormatter extends Formatter {
+
+ private static final RemoveEnclosingBracesFormatter REMOVE_ENCLOSING_BRACES_FORMATTER = new RemoveEnclosingBracesFormatter();
+
+ @Override
+ public String getName() {
+ return Localization.lang("Remove word enclosing braces");
+ }
+
+ @Override
+ public String getKey() {
+ return "remove_enclosing_and_outer_enclosing_braces";
+ }
+
+ @Override
+ public String getDescription() {
+ return Localization.lang("Removes braces encapsulating a complete word and the complete field content.");
+ }
+
+ @Override
+ public String getExampleInput() {
+ return "{In {CDMA}}";
+ }
+
+ @Override
+ public String format(String input) {
+ Objects.requireNonNull(input);
+ if (StringUtil.isBlank(input)) {
+ return input;
+ }
+
+ if (!input.contains("{")) {
+ return input;
+ }
+
+ // We need to first remove the outer braces to have double braces at the last word working (e.g., {In {CDMA}})
+ input = REMOVE_ENCLOSING_BRACES_FORMATTER.format(input);
+
+ String[] split = input.split(" ");
+ StringJoiner result = new StringJoiner(" ");
+ for (String s : split) {
+ if ((s.length() > 2) && s.startsWith("{") && s.endsWith("}")) {
+ // quick solution (which we don't do): just remove first "{" and last "}"
+ // however, it might be that s is like {A}bbb{c}, where braces may not be removed
+
+ String inner = s.substring(1, s.length() - 1);
+
+ if (inner.contains("}")) {
+ if (properBrackets(inner)) {
+ s = inner;
+ }
+ } else {
+ // no inner curly brackets found, no check needed, inner can just be used as s
+ s = inner;
+ }
+ }
+ result.add(s);
+ }
+ return result.toString();
+ }
+
+ /**
+ * @return true iff the brackets in s are properly paired
+ */
+ private boolean properBrackets(String s) {
+ // nested construct is there, check for "proper" nesting
+ int i = 0;
+ int level = 0;
+ while (i < s.length()) {
+ char c = s.charAt(i);
+ switch (c) {
+ case '{':
+ level++;
+ break;
+ case '}':
+ level--;
+ if (level == -1) { // improper nesting
+ return false;
+ }
+ break;
+ default:
+ break;
+ }
+ i++;
+ }
+ return level == 0;
+ }
+}
diff --git a/src/main/java/org/jabref/logic/importer/fetcher/AstrophysicsDataSystem.java b/src/main/java/org/jabref/logic/importer/fetcher/AstrophysicsDataSystem.java
index 7b85d1534cd..23e5c077d8b 100644
--- a/src/main/java/org/jabref/logic/importer/fetcher/AstrophysicsDataSystem.java
+++ b/src/main/java/org/jabref/logic/importer/fetcher/AstrophysicsDataSystem.java
@@ -17,7 +17,7 @@
import org.jabref.logic.formatter.bibtexfields.ClearFormatter;
import org.jabref.logic.formatter.bibtexfields.NormalizeMonthFormatter;
import org.jabref.logic.formatter.bibtexfields.NormalizeNamesFormatter;
-import org.jabref.logic.formatter.bibtexfields.RemoveBracesFormatter;
+import org.jabref.logic.formatter.bibtexfields.RemoveEnclosingBracesFormatter;
import org.jabref.logic.formatter.bibtexfields.RemoveNewlinesFormatter;
import org.jabref.logic.help.HelpFile;
import org.jabref.logic.importer.EntryBasedParserFetcher;
@@ -149,9 +149,9 @@ public Parser getParser() {
@Override
public void doPostCleanup(BibEntry entry) {
- new FieldFormatterCleanup(StandardField.ABSTRACT, new RemoveBracesFormatter()).cleanup(entry);
+ new FieldFormatterCleanup(StandardField.ABSTRACT, new RemoveEnclosingBracesFormatter()).cleanup(entry);
new FieldFormatterCleanup(StandardField.ABSTRACT, new RemoveNewlinesFormatter()).cleanup(entry);
- new FieldFormatterCleanup(StandardField.TITLE, new RemoveBracesFormatter()).cleanup(entry);
+ new FieldFormatterCleanup(StandardField.TITLE, new RemoveEnclosingBracesFormatter()).cleanup(entry);
new FieldFormatterCleanup(StandardField.AUTHOR, new NormalizeNamesFormatter()).cleanup(entry);
new FieldFormatterCleanup(StandardField.MONTH, new NormalizeMonthFormatter()).cleanup(entry);
diff --git a/src/main/java/org/jabref/logic/importer/fetcher/CrossRef.java b/src/main/java/org/jabref/logic/importer/fetcher/CrossRef.java
index 4826239e3e6..c34277add1e 100644
--- a/src/main/java/org/jabref/logic/importer/fetcher/CrossRef.java
+++ b/src/main/java/org/jabref/logic/importer/fetcher/CrossRef.java
@@ -11,7 +11,7 @@
import org.jabref.logic.cleanup.FieldFormatterCleanup;
import org.jabref.logic.formatter.bibtexfields.ClearFormatter;
-import org.jabref.logic.formatter.bibtexfields.RemoveBracesFormatter;
+import org.jabref.logic.formatter.bibtexfields.RemoveEnclosingBracesFormatter;
import org.jabref.logic.importer.EntryBasedParserFetcher;
import org.jabref.logic.importer.FetcherException;
import org.jabref.logic.importer.IdBasedParserFetcher;
@@ -46,7 +46,7 @@ public class CrossRef implements IdParserFetcher, EntryBasedParserFetcher,
private static final String API_URL = "https://api.crossref.org/works";
- private static final RemoveBracesFormatter REMOVE_BRACES_FORMATTER = new RemoveBracesFormatter();
+ private static final RemoveEnclosingBracesFormatter REMOVE_BRACES_FORMATTER = new RemoveEnclosingBracesFormatter();
@Override
public String getName() {
diff --git a/src/main/java/org/jabref/logic/importer/fetcher/INSPIREFetcher.java b/src/main/java/org/jabref/logic/importer/fetcher/INSPIREFetcher.java
index 67f9e84afc0..86d27594a84 100644
--- a/src/main/java/org/jabref/logic/importer/fetcher/INSPIREFetcher.java
+++ b/src/main/java/org/jabref/logic/importer/fetcher/INSPIREFetcher.java
@@ -11,7 +11,7 @@
import org.jabref.logic.cleanup.FieldFormatterCleanup;
import org.jabref.logic.formatter.bibtexfields.ClearFormatter;
-import org.jabref.logic.formatter.bibtexfields.RemoveBracesFormatter;
+import org.jabref.logic.formatter.bibtexfields.RemoveEnclosingBracesFormatter;
import org.jabref.logic.help.HelpFile;
import org.jabref.logic.importer.EntryBasedFetcher;
import org.jabref.logic.importer.FetcherException;
@@ -76,7 +76,7 @@ public void doPostCleanup(BibEntry entry) {
new FieldFormatterCleanup(new UnknownField("SLACcitation"), new ClearFormatter()).cleanup(entry);
// Remove braces around content of "title" field
- new FieldFormatterCleanup(StandardField.TITLE, new RemoveBracesFormatter()).cleanup(entry);
+ new FieldFormatterCleanup(StandardField.TITLE, new RemoveEnclosingBracesFormatter()).cleanup(entry);
new FieldFormatterCleanup(StandardField.TITLE, new LatexToUnicodeFormatter()).cleanup(entry);
}
diff --git a/src/main/java/org/jabref/logic/importer/fetcher/ZbMATH.java b/src/main/java/org/jabref/logic/importer/fetcher/ZbMATH.java
index 70afa7847c1..c8398a1e8f3 100644
--- a/src/main/java/org/jabref/logic/importer/fetcher/ZbMATH.java
+++ b/src/main/java/org/jabref/logic/importer/fetcher/ZbMATH.java
@@ -9,7 +9,7 @@
import org.jabref.logic.cleanup.FieldFormatterCleanup;
import org.jabref.logic.cleanup.MoveFieldCleanup;
-import org.jabref.logic.formatter.bibtexfields.RemoveBracesFormatter;
+import org.jabref.logic.formatter.bibtexfields.RemoveEnclosingBracesFormatter;
import org.jabref.logic.importer.EntryBasedParserFetcher;
import org.jabref.logic.importer.FetcherException;
import org.jabref.logic.importer.IdBasedParserFetcher;
@@ -131,7 +131,7 @@ public Parser getParser() {
public void doPostCleanup(BibEntry entry) {
new MoveFieldCleanup(new UnknownField("msc2010"), StandardField.KEYWORDS).cleanup(entry);
new MoveFieldCleanup(AMSField.FJOURNAL, StandardField.JOURNAL).cleanup(entry);
- new FieldFormatterCleanup(StandardField.JOURNAL, new RemoveBracesFormatter()).cleanup(entry);
- new FieldFormatterCleanup(StandardField.TITLE, new RemoveBracesFormatter()).cleanup(entry);
+ new FieldFormatterCleanup(StandardField.JOURNAL, new RemoveEnclosingBracesFormatter()).cleanup(entry);
+ new FieldFormatterCleanup(StandardField.TITLE, new RemoveEnclosingBracesFormatter()).cleanup(entry);
}
}
diff --git a/src/main/java/org/jabref/logic/layout/format/HTMLChars.java b/src/main/java/org/jabref/logic/layout/format/HTMLChars.java
index 5bfe60c7bd1..9776f49a504 100644
--- a/src/main/java/org/jabref/logic/layout/format/HTMLChars.java
+++ b/src/main/java/org/jabref/logic/layout/format/HTMLChars.java
@@ -4,14 +4,14 @@
import java.util.Objects;
import java.util.regex.Pattern;
-import org.jabref.logic.layout.LayoutFormatter;
+import org.jabref.logic.layout.ParamLayoutFormatter;
import org.jabref.logic.util.strings.HTMLUnicodeConversionMaps;
import org.jabref.model.strings.StringUtil;
/**
- * This formatter escapes characters so they are suitable for HTML.
+ * This formatter escapes characters so that they are suitable for HTML.
*/
-public class HTMLChars implements LayoutFormatter {
+public class HTMLChars implements ParamLayoutFormatter {
private static final Map HTML_CHARS = HTMLUnicodeConversionMaps.LATEX_HTML_CONVERSION_MAP;
/**
@@ -23,6 +23,15 @@ public class HTMLChars implements LayoutFormatter {
* */
private static final Pattern HTML_ENTITY_PATTERN = Pattern.compile("&(?!(?:[a-z0-9]+|#[0-9]{1,6}|#x[0-9a-fA-F]{1,6});)");
+ private boolean keepCurlyBraces = false;
+
+ @Override
+ public void setArgument(String arg) {
+ if ("keepCurlyBraces".equalsIgnoreCase(arg)) {
+ this.keepCurlyBraces = true;
+ }
+ }
+
@Override
public String format(String inField) {
String field = normalizedField(inField);
@@ -49,7 +58,7 @@ public String format(String inField) {
escaped = true;
incommand = true;
currentCommand = new StringBuilder();
- } else if (!incommand && ((c == '{') || (c == '}'))) {
+ } else if (!this.keepCurlyBraces && !incommand && ((c == '{') || (c == '}'))) {
// Swallow the brace.
} else if (Character.isLetter(c) || StringUtil.SPECIAL_COMMAND_CHARS.contains(String.valueOf(c))) {
escaped = false;
@@ -73,7 +82,7 @@ public String format(String inField) {
String commandBody;
if (c == '{') {
String part = StringUtil.getPart(field, i, false);
- i += part.length();
+ i += this.keepCurlyBraces ? part.length() + 1 : part.length();
commandBody = part;
} else {
commandBody = field.substring(i, i + 1);
@@ -83,7 +92,6 @@ public String format(String inField) {
sb.append(Objects.requireNonNullElse(result, commandBody));
incommand = false;
- escaped = false;
} else {
// Are we already at the end of the string?
if ((i + 1) == field.length()) {
@@ -109,11 +117,14 @@ public String format(String inField) {
String tag = getHTMLTag(command);
if (!tag.isEmpty()) {
String part = StringUtil.getPart(field, i, true);
+ if (this.keepCurlyBraces && (c == '{' || (c == '}'))) {
+ i++;
+ }
i += part.length();
sb.append('<').append(tag).append('>').append(part).append("").append(tag).append('>');
} else if (c == '{') {
String argument = StringUtil.getPart(field, i, true);
- i += argument.length();
+ i += this.keepCurlyBraces ? argument.length() + 1 : argument.length();
// handle common case of general latex command
String result = HTML_CHARS.get(command + argument);
// If found, then use translated version. If not, then keep
@@ -133,10 +144,14 @@ public String format(String inField) {
} else if (c == '}') {
// This end brace terminates a command. This can be the case in
// constructs like {\aa}. The correct behaviour should be to
- // substitute the evaluated command and swallow the brace:
+ // substitute the evaluated command.
String result = HTML_CHARS.get(command);
// If the command is unknown, just print it:
sb.append(Objects.requireNonNullElse(result, command));
+ // We only keep the brace if we are in 'KEEP' mode.
+ if (this.keepCurlyBraces) {
+ sb.append(c);
+ }
} else {
String result = HTML_CHARS.get(command);
sb.append(Objects.requireNonNullElse(result, command));
@@ -170,7 +185,7 @@ private String normalizedField(String inField) {
.replaceAll("[\\n]{2,}", "") // Replace double line breaks with
.replace("\n", "
") // Replace single line breaks with
.replace("\\$", "$") // Replace \$ with $
- .replaceAll("\\$([^$]*)\\$", "\\{$1\\}");
+ .replaceAll("\\$([^$]*)\\$", this.keepCurlyBraces ? "\\\\{$1\\\\}" : "$1}");
}
private String getHTMLTag(String latexCommand) {
diff --git a/src/main/java/org/jabref/logic/msbib/MSBibConverter.java b/src/main/java/org/jabref/logic/msbib/MSBibConverter.java
index d565195e6fc..1870254e933 100644
--- a/src/main/java/org/jabref/logic/msbib/MSBibConverter.java
+++ b/src/main/java/org/jabref/logic/msbib/MSBibConverter.java
@@ -4,7 +4,7 @@
import java.util.List;
import java.util.Optional;
-import org.jabref.logic.formatter.bibtexfields.RemoveBracesFormatter;
+import org.jabref.logic.formatter.bibtexfields.RemoveEnclosingBracesFormatter;
import org.jabref.model.entry.AuthorList;
import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.Month;
@@ -18,7 +18,7 @@ public class MSBibConverter {
private static final String MSBIB_PREFIX = "msbib-";
private static final String BIBTEX_PREFIX = "BIBTEX_";
- private static final RemoveBracesFormatter REMOVE_BRACES_FORMATTER = new RemoveBracesFormatter();
+ private static final RemoveEnclosingBracesFormatter REMOVE_BRACES_FORMATTER = new RemoveEnclosingBracesFormatter();
private MSBibConverter() {
}
diff --git a/src/main/java/org/jabref/logic/msbib/MsBibAuthor.java b/src/main/java/org/jabref/logic/msbib/MsBibAuthor.java
index bcceef9657f..9285a4d9d05 100644
--- a/src/main/java/org/jabref/logic/msbib/MsBibAuthor.java
+++ b/src/main/java/org/jabref/logic/msbib/MsBibAuthor.java
@@ -1,11 +1,11 @@
package org.jabref.logic.msbib;
-import org.jabref.logic.formatter.bibtexfields.RemoveBracesFormatter;
+import org.jabref.logic.formatter.bibtexfields.RemoveEnclosingBracesFormatter;
import org.jabref.model.entry.Author;
public class MsBibAuthor {
- private static final RemoveBracesFormatter REMOVE_BRACES_FORMATTER = new RemoveBracesFormatter();
+ private static final RemoveEnclosingBracesFormatter REMOVE_BRACES_FORMATTER = new RemoveEnclosingBracesFormatter();
private String firstName;
private String middleName;
diff --git a/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java b/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java
index 851b084b866..6683a67637a 100644
--- a/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java
+++ b/src/main/java/org/jabref/logic/openoffice/backend/NamedRangeReferenceMark.java
@@ -2,6 +2,7 @@
import java.util.Optional;
+import org.jabref.model.openoffice.DocumentAnnotation;
import org.jabref.model.openoffice.backend.NamedRange;
import org.jabref.model.openoffice.uno.CreationException;
import org.jabref.model.openoffice.uno.NoDocumentException;
@@ -101,8 +102,8 @@ private static void createReprInDocument(XTextDocument doc,
: left + right;
cursor.getText().insertString(cursor, bracketedContent, true);
-
- UnoReferenceMark.create(doc, refMarkName, cursor, true /* absorb */);
+ DocumentAnnotation documentAnnotation = new DocumentAnnotation(doc, refMarkName, cursor, true /* absorb */);
+ UnoReferenceMark.create(documentAnnotation);
// eat the first inserted space
cursorBefore.goRight((short) 1, true);
diff --git a/src/main/java/org/jabref/logic/openoffice/frontend/UpdateBibliography.java b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateBibliography.java
index 99e71e13725..47e63414c78 100644
--- a/src/main/java/org/jabref/logic/openoffice/frontend/UpdateBibliography.java
+++ b/src/main/java/org/jabref/logic/openoffice/frontend/UpdateBibliography.java
@@ -4,6 +4,7 @@
import org.jabref.logic.openoffice.style.OOBibStyle;
import org.jabref.logic.openoffice.style.OOFormatBibliography;
+import org.jabref.model.openoffice.DocumentAnnotation;
import org.jabref.model.openoffice.ootext.OOText;
import org.jabref.model.openoffice.ootext.OOTextIntoOO;
import org.jabref.model.openoffice.style.CitedKeys;
@@ -67,7 +68,8 @@ private static void createBibTextSection2(XTextDocument doc)
// Alternatively, we could receive a cursor.
XTextCursor textCursor = doc.getText().createTextCursor();
textCursor.gotoEnd(false);
- UnoTextSection.create(doc, BIB_SECTION_NAME, textCursor, false);
+ DocumentAnnotation annotation = new DocumentAnnotation(doc, BIB_SECTION_NAME, textCursor, false);
+ UnoTextSection.create(annotation);
}
/**
@@ -129,7 +131,8 @@ private static void populateBibTextSection(XTextDocument doc,
initialParagraph.setString("");
UnoBookmark.removeIfExists(doc, BIB_SECTION_END_NAME);
- UnoBookmark.create(doc, BIB_SECTION_END_NAME, cursor, true);
+ DocumentAnnotation documentAnnotation = new DocumentAnnotation(doc, BIB_SECTION_END_NAME, cursor, true);
+ UnoBookmark.create(documentAnnotation);
cursor.collapseToEnd();
}
diff --git a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetCitationMarker.java b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetCitationMarker.java
index c38e3d37ed0..aff4c1ce84c 100644
--- a/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetCitationMarker.java
+++ b/src/main/java/org/jabref/logic/openoffice/style/OOBibStyleGetCitationMarker.java
@@ -5,7 +5,7 @@
import java.util.List;
import java.util.Optional;
-import org.jabref.logic.formatter.bibtexfields.RemoveBracesFormatter;
+import org.jabref.logic.formatter.bibtexfields.RemoveEnclosingBracesFormatter;
import org.jabref.model.database.BibDatabase;
import org.jabref.model.entry.Author;
import org.jabref.model.entry.AuthorList;
@@ -24,7 +24,7 @@
class OOBibStyleGetCitationMarker {
- private static final RemoveBracesFormatter REMOVE_BRACES_FORMATTER = new RemoveBracesFormatter();
+ private static final RemoveEnclosingBracesFormatter REMOVE_BRACES_FORMATTER = new RemoveEnclosingBracesFormatter();
private OOBibStyleGetCitationMarker() {
}
diff --git a/src/main/java/org/jabref/logic/pdf/search/PdfIndexer.java b/src/main/java/org/jabref/logic/pdf/search/PdfIndexer.java
index 7b66b1c62ca..45750ac5b84 100644
--- a/src/main/java/org/jabref/logic/pdf/search/PdfIndexer.java
+++ b/src/main/java/org/jabref/logic/pdf/search/PdfIndexer.java
@@ -16,11 +16,11 @@
import org.jabref.model.database.BibDatabaseContext;
import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.LinkedFile;
-import org.jabref.model.pdf.search.EnglishStemAnalyzer;
import org.jabref.model.pdf.search.SearchFieldConstants;
import org.jabref.preferences.FilePreferences;
import com.google.common.annotations.VisibleForTesting;
+import org.apache.lucene.analysis.en.EnglishAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexNotFoundException;
@@ -130,7 +130,7 @@ private void initializeIndexWriterAndReader(IndexWriterConfig.OpenMode mode) {
indexWriter = new IndexWriter(
indexDirectory,
new IndexWriterConfig(
- new EnglishStemAnalyzer()).setOpenMode(mode));
+ new EnglishAnalyzer()).setOpenMode(mode));
} catch (IOException e) {
LOGGER.error("Could not initialize the IndexWriter", e);
// FIXME: This can also happen if another instance of JabRef is launched in parallel.
@@ -205,7 +205,7 @@ public void addToIndex(BibEntry entry, Collection linkedFiles, boole
private void doCommit() {
try {
- getIndexWriter().ifPresent(Unchecked.consumer(writer -> writer.commit()));
+ getIndexWriter().ifPresent(Unchecked.consumer(IndexWriter::commit));
} catch (UncheckedIOException e) {
LOGGER.warn("Could not commit changes to the index.", e);
}
@@ -274,7 +274,6 @@ private void addToIndex(BibEntry entry, LinkedFile linkedFile, boolean shouldCom
LOGGER.debug("Could not find {}", linkedFile.getLink());
return;
}
- LOGGER.debug("Adding {} to index", linkedFile.getLink());
try {
// Check if a document with this path is already in the index
try {
@@ -283,17 +282,21 @@ private void addToIndex(BibEntry entry, LinkedFile linkedFile, boolean shouldCom
TopDocs topDocs = searcher.search(query, 1);
// If a document was found, check if is less current than the one in the FS
if (topDocs.scoreDocs.length > 0) {
- Document doc = reader.document(topDocs.scoreDocs[0].doc);
+ Document doc = reader.storedFields().document(topDocs.scoreDocs[0].doc);
long indexModificationTime = Long.parseLong(doc.getField(SearchFieldConstants.MODIFIED).stringValue());
BasicFileAttributes attributes = Files.readAttributes(resolvedPath.get(), BasicFileAttributes.class);
if (indexModificationTime >= attributes.lastModifiedTime().to(TimeUnit.SECONDS)) {
- LOGGER.debug("File {} is already indexed", linkedFile.getLink());
+ LOGGER.debug("File {} is already indexed and up-to-date.", linkedFile.getLink());
return;
+ } else {
+ LOGGER.debug("File {} is already indexed but outdated. Removing from index.", linkedFile.getLink());
+ removeFromIndex(linkedFile.getLink());
}
}
} catch (IndexNotFoundException e) {
LOGGER.debug("Index not found. Continuing.", e);
}
+ LOGGER.debug("Adding {} to index", linkedFile.getLink());
// If no document was found, add the new one
Optional> pages = new DocumentReader(entry, filePreferences).readLinkedPdf(this.databaseContext, linkedFile);
if (pages.isPresent()) {
@@ -328,7 +331,7 @@ public Set getListOfFilePaths() {
MatchAllDocsQuery query = new MatchAllDocsQuery();
TopDocs allDocs = searcher.search(query, Integer.MAX_VALUE);
for (ScoreDoc scoreDoc : allDocs.scoreDocs) {
- Document doc = reader.document(scoreDoc.doc);
+ Document doc = reader.storedFields().document(scoreDoc.doc);
paths.add(doc.getField(SearchFieldConstants.PATH).stringValue());
}
} catch (IOException e) {
diff --git a/src/main/java/org/jabref/logic/pdf/search/PdfSearcher.java b/src/main/java/org/jabref/logic/pdf/search/PdfSearcher.java
index 40acc97f8af..fb6afccc29b 100644
--- a/src/main/java/org/jabref/logic/pdf/search/PdfSearcher.java
+++ b/src/main/java/org/jabref/logic/pdf/search/PdfSearcher.java
@@ -7,11 +7,12 @@
import java.util.Optional;
import org.jabref.gui.LibraryTab;
-import org.jabref.model.pdf.search.EnglishStemAnalyzer;
import org.jabref.model.pdf.search.PdfSearchResults;
import org.jabref.model.pdf.search.SearchResult;
import org.jabref.model.strings.StringUtil;
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.analysis.en.EnglishAnalyzer;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
@@ -31,7 +32,7 @@ public final class PdfSearcher {
private static final Logger LOGGER = LoggerFactory.getLogger(LibraryTab.class);
private final PdfIndexer indexer;
- private EnglishStemAnalyzer englishStemAnalyzer = new EnglishStemAnalyzer();
+ private final Analyzer englishAnalyzer = new EnglishAnalyzer();
private PdfSearcher(PdfIndexer indexer) {
this.indexer = indexer;
@@ -65,7 +66,7 @@ public PdfSearchResults search(final String searchString, final int maxHits) thr
return new PdfSearchResults();
}
try (IndexReader reader = DirectoryReader.open(optionalIndexWriter.get())) {
- Query query = new MultiFieldQueryParser(PDF_FIELDS, englishStemAnalyzer).parse(searchString);
+ Query query = new MultiFieldQueryParser(PDF_FIELDS, englishAnalyzer).parse(searchString);
IndexSearcher searcher = new IndexSearcher(reader);
TopDocs results = searcher.search(query, maxHits);
for (ScoreDoc scoreDoc : results.scoreDocs) {
diff --git a/src/main/java/org/jabref/logic/texparser/CitationFinder.java b/src/main/java/org/jabref/logic/texparser/CitationFinder.java
deleted file mode 100644
index fac31569876..00000000000
--- a/src/main/java/org/jabref/logic/texparser/CitationFinder.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package org.jabref.logic.texparser;
-
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.Collection;
-import java.util.List;
-import java.util.stream.Stream;
-
-import org.jabref.model.texparser.Citation;
-import org.jabref.model.texparser.LatexParserResults;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class CitationFinder {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(CitationFinder.class);
- private static final String TEX_EXT = ".tex";
- private final Path directory;
-
- private LatexParserResults latexParserResults;
-
- public CitationFinder(Path directory) {
- this.directory = directory;
- }
-
- public Collection searchAndParse(String citeKey) throws IOException {
- if (latexParserResults == null) {
- if (!Files.exists(directory)) {
- throw new IOException("Current search directory does not exist: %s".formatted(directory));
- }
-
- List texFiles = searchDirectory(directory);
- LOGGER.debug("Found tex files: {}", texFiles);
- latexParserResults = new DefaultLatexParser().parse(texFiles);
- }
-
- return latexParserResults.getCitationsByKey(citeKey);
- }
-
- /**
- * @param directory the directory to search for. It is recursively searched.
- */
- private List searchDirectory(Path directory) {
- LOGGER.debug("Searching directory {}", directory);
- try (Stream paths = Files.walk(directory)) {
- return paths.filter(Files::isRegularFile)
- .filter(path -> path.toString().endsWith(TEX_EXT))
- .toList();
- } catch (IOException e) {
- LOGGER.error("Error while searching files", e);
- return List.of();
- }
- }
-}
diff --git a/src/main/java/org/jabref/logic/texparser/DefaultLatexParser.java b/src/main/java/org/jabref/logic/texparser/DefaultLatexParser.java
index 385c3b8b94e..1e24671c21e 100644
--- a/src/main/java/org/jabref/logic/texparser/DefaultLatexParser.java
+++ b/src/main/java/org/jabref/logic/texparser/DefaultLatexParser.java
@@ -12,7 +12,6 @@
import java.nio.file.Path;
import java.util.List;
import java.util.Optional;
-import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -50,12 +49,6 @@ public class DefaultLatexParser implements LatexParser {
private static final Pattern INCLUDE_PATTERN = Pattern.compile(
"\\\\(?:include|input)\\{(?<%s>[^\\}]*)\\}".formatted(INCLUDE_GROUP));
- private final LatexParserResults latexParserResults;
-
- public DefaultLatexParser() {
- this.latexParserResults = new LatexParserResults();
- }
-
@Override
public LatexParserResult parse(String citeString) {
Path path = Path.of("");
@@ -70,6 +63,7 @@ public Optional parse(Path latexFile) {
LOGGER.error("File does not exist: {}", latexFile);
return Optional.empty();
}
+
LatexParserResult latexParserResult = new LatexParserResult(latexFile);
try (InputStream inputStream = Files.newInputStream(latexFile);
@@ -99,20 +93,9 @@ public Optional parse(Path latexFile) {
@Override
public LatexParserResults parse(List latexFiles) {
- for (Path latexFile : latexFiles) {
- if (!latexParserResults.isParsed(latexFile)) {
- parse(latexFile).ifPresent(parsedTex -> latexParserResults.add(latexFile, parsedTex));
- }
- }
-
- Set nonParsedNestedFiles = latexParserResults.getNonParsedNestedFiles();
- // Parse all "non-parsed" files referenced by TEX files, recursively.
- if (!nonParsedNestedFiles.isEmpty()) {
- // modifies class variable latexParserResults
- parse(nonParsedNestedFiles.stream().toList());
- }
-
- return latexParserResults;
+ LatexParserResults results = new LatexParserResults();
+ latexFiles.forEach(file -> parse(file).ifPresent(result -> results.add(file, result)));
+ return results;
}
/**
diff --git a/src/main/java/org/jabref/logic/util/io/FileNameUniqueness.java b/src/main/java/org/jabref/logic/util/io/FileNameUniqueness.java
index 2c1456d13cd..44a73e0ae71 100644
--- a/src/main/java/org/jabref/logic/util/io/FileNameUniqueness.java
+++ b/src/main/java/org/jabref/logic/util/io/FileNameUniqueness.java
@@ -11,7 +11,12 @@
import org.jabref.gui.DialogService;
import org.jabref.logic.l10n.Localization;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
public class FileNameUniqueness {
+ private static final Logger LOGGER = LoggerFactory.getLogger(FileNameUniqueness.class);
+
private static final Pattern DUPLICATE_MARK_PATTERN = Pattern.compile("(.*) \\(\\d+\\)");
/**
@@ -61,7 +66,6 @@ public static String getNonOverWritingFileName(Path targetDirectory, String file
* @throws IOException Fail when the file is not exist or something wrong when reading the file
*/
public static boolean isDuplicatedFile(Path directory, Path fileName, DialogService dialogService) throws IOException {
-
Objects.requireNonNull(directory);
Objects.requireNonNull(fileName);
Objects.requireNonNull(dialogService);
@@ -83,10 +87,11 @@ public static boolean isDuplicatedFile(Path directory, Path fileName, DialogServ
while (Files.exists(originalFile)) {
if (com.google.common.io.Files.equal(originalFile.toFile(), duplicateFile.toFile())) {
- if (duplicateFile.toFile().delete()) {
+ try {
+ Files.delete(duplicateFile);
dialogService.notify(Localization.lang("File '%1' is a duplicate of '%0'. Keeping '%0'", originalFileName, fileName));
- } else {
- dialogService.notify(Localization.lang("File '%1' is a duplicate of '%0'. Keeping both due to deletion error", originalFileName, fileName));
+ } catch (IOException e) {
+ LOGGER.error("File '{}' is a duplicate of '{}'. Could not delete '{}'.", fileName, originalFileName, fileName);
}
return true;
}
diff --git a/src/main/java/org/jabref/migrations/PreferencesMigrations.java b/src/main/java/org/jabref/migrations/PreferencesMigrations.java
index 92d60f49632..5a364ad06c5 100644
--- a/src/main/java/org/jabref/migrations/PreferencesMigrations.java
+++ b/src/main/java/org/jabref/migrations/PreferencesMigrations.java
@@ -331,6 +331,7 @@ protected static void upgradePreviewStyle(JabRefPreferences prefs) {
String currentPreviewStyle = prefs.get(JabRefPreferences.PREVIEW_STYLE);
String migratedStyle = currentPreviewStyle.replace("\\begin{review}
Review: \\format[HTMLChars]{\\review} \\end{review}", "\\begin{comment}
Comment: \\format[Markdown,HTMLChars]{\\comment} \\end{comment}")
.replace("\\format[HTMLChars]{\\comment}", "\\format[Markdown,HTMLChars]{\\comment}")
+ .replace("\\format[Markdown,HTMLChars]{\\comment}", "\\format[Markdown,HTMLChars(keepCurlyBraces)]{\\comment}")
.replace("\\bibtextype\\begin{bibtexkey} (\\bibtexkey)", "\\bibtextype\\begin{citationkey} (\\citationkey)")
.replace("\\end{bibtexkey}
__NEWLINE__", "\\end{citationkey}
__NEWLINE__");
prefs.put(JabRefPreferences.PREVIEW_STYLE, migratedStyle);
diff --git a/src/main/java/org/jabref/model/database/BibDatabaseContext.java b/src/main/java/org/jabref/model/database/BibDatabaseContext.java
index b43f7069a24..f8d4c3dfdcf 100644
--- a/src/main/java/org/jabref/model/database/BibDatabaseContext.java
+++ b/src/main/java/org/jabref/model/database/BibDatabaseContext.java
@@ -6,6 +6,7 @@
import java.util.List;
import java.util.Objects;
import java.util.Optional;
+import java.util.UUID;
import java.util.stream.Collectors;
import org.jabref.architecture.AllowedToUseLogic;
@@ -33,7 +34,7 @@
* and the options relevant for this file in Defaults.
*
*
- * To get an instance for a .bib file, use {@link org.jabref.logic.importer.fileformat.BibtexParser}.
+ * To get an instance for a .bib file, use {@link org.jabref.logic.importer.fileformat.BibtexParser}.
*
*/
@AllowedToUseLogic("because it needs access to shared database features")
@@ -44,6 +45,12 @@ public class BibDatabaseContext {
private final BibDatabase database;
private MetaData metaData;
+ /**
+ * Generate a random UID for unique of the concrete context
+ * In contrast to hashCode this stays unique
+ */
+ private final String uid = "bibdatabasecontext_" + UUID.randomUUID();
+
/**
* The path where this database was last saved to.
*/
@@ -127,9 +134,9 @@ public boolean isBiblatexMode() {
*/
public boolean isStudy() {
return this.getDatabasePath()
- .map(path -> path.getFileName().toString().equals(Crawler.FILENAME_STUDY_RESULT_BIB) &&
- Files.exists(path.resolveSibling(StudyRepository.STUDY_DEFINITION_FILE_NAME)))
- .orElse(false);
+ .map(path -> path.getFileName().toString().equals(Crawler.FILENAME_STUDY_RESULT_BIB) &&
+ Files.exists(path.resolveSibling(StudyRepository.STUDY_DEFINITION_FILE_NAME)))
+ .orElse(false);
}
/**
@@ -286,4 +293,13 @@ public boolean equals(Object o) {
public int hashCode() {
return Objects.hash(database, metaData, path, location);
}
+
+ /**
+ * Get the generated UID for the current context. Can be used to distinguish contexts with changing metadata etc
+ *
+ * @return The generated UID in UUIDv4 format with the prefix bibdatabasecontext_
+ */
+ public String getUid() {
+ return uid;
+ }
}
diff --git a/src/main/java/org/jabref/model/entry/Author.java b/src/main/java/org/jabref/model/entry/Author.java
index e4511e7ef07..5892ca0b457 100644
--- a/src/main/java/org/jabref/model/entry/Author.java
+++ b/src/main/java/org/jabref/model/entry/Author.java
@@ -3,6 +3,8 @@
import java.util.Objects;
import java.util.Optional;
+import org.jabref.architecture.AllowedToUseLogic;
+import org.jabref.logic.formatter.bibtexfields.RemoveWordEnclosingAndOuterEnclosingBracesFormatter;
import org.jabref.model.strings.LatexToUnicodeAdapter;
import org.jabref.model.strings.StringUtil;
@@ -11,6 +13,7 @@
*
* Current usage: only methods getLastOnly
, getFirstLast
, and getLastFirst
are used; all other methods are provided for completeness.
*/
+@AllowedToUseLogic("because it needs to use formatter")
public class Author {
/**
@@ -20,6 +23,8 @@ public class Author {
*/
public static final Author OTHERS = new Author("", "", null, "others", null);
+ public static final RemoveWordEnclosingAndOuterEnclosingBracesFormatter FORMATTER = new RemoveWordEnclosingAndOuterEnclosingBracesFormatter();
+
private final String givenName;
private final String givenNameAbbreviated;
private final String namePrefix;
@@ -41,17 +46,37 @@ public class Author {
public Author(String givenName, String givenNameAbbreviated, String namePrefix, String familyName, String nameSuffix) {
boolean keepBracesAtLastPart = StringUtil.isBlank(givenName) && StringUtil.isBlank(givenNameAbbreviated) && StringUtil.isBlank(namePrefix) && !StringUtil.isBlank(familyName) && StringUtil.isBlank(nameSuffix);
- this.givenName = addDotIfAbbreviation(removeStartAndEndBraces(givenName));
- this.givenNameAbbreviated = removeStartAndEndBraces(givenNameAbbreviated);
- this.namePrefix = removeStartAndEndBraces(namePrefix);
+ if (!StringUtil.isBlank(givenName)) {
+ this.givenName = addDotIfAbbreviation(FORMATTER.format(givenName));
+ } else {
+ this.givenName = null;
+ }
+ if (!StringUtil.isBlank(givenNameAbbreviated)) {
+ this.givenNameAbbreviated = FORMATTER.format(givenNameAbbreviated);
+ } else {
+ this.givenNameAbbreviated = null;
+ }
+ if (!StringUtil.isBlank(namePrefix)) {
+ this.namePrefix = FORMATTER.format(namePrefix);
+ } else {
+ this.namePrefix = null;
+ }
if (keepBracesAtLastPart) {
// We do not remove braces here to keep institutions protected
// https://github.com/JabRef/jabref/issues/10031
this.familyName = familyName;
} else {
- this.familyName = removeStartAndEndBraces(familyName);
+ if (!StringUtil.isBlank(familyName)) {
+ this.familyName = FORMATTER.format(familyName);
+ } else {
+ this.familyName = null;
+ }
+ }
+ if (!StringUtil.isBlank(nameSuffix)) {
+ this.nameSuffix = FORMATTER.format(nameSuffix);
+ } else {
+ this.nameSuffix = null;
}
- this.nameSuffix = removeStartAndEndBraces(nameSuffix);
}
public static String addDotIfAbbreviation(String name) {
@@ -165,94 +190,6 @@ public boolean equals(Object other) {
return false;
}
- /**
- * @return true iff the brackets in s are properly paired
- */
- private boolean properBrackets(String s) {
- // nested construct is there, check for "proper" nesting
- int i = 0;
- int level = 0;
- while (i < s.length()) {
- char c = s.charAt(i);
- switch (c) {
- case '{':
- level++;
- break;
- case '}':
- level--;
- if (level == -1) { // improper nesting
- return false;
- }
- break;
- default:
- break;
- }
- i++;
- }
- return level == 0;
- }
-
- /**
- * Removes start and end brace both at the complete string and at beginning/end of a word
- *
- * E.g.,
- *
- * - {Vall{\'e}e Poussin} -> Vall{\'e}e Poussin
- * - {Vall{\'e}e} {Poussin} -> Vall{\'e}e Poussin
- * - Vall{\'e}e Poussin -> Vall{\'e}e Poussin
- *
- */
- private String removeStartAndEndBraces(String name) {
- if (StringUtil.isBlank(name)) {
- return null;
- }
-
- if (!name.contains("{")) {
- return name;
- }
-
- String[] split = name.split(" ");
- StringBuilder b = new StringBuilder();
- for (String s : split) {
- if ((s.length() > 2) && s.startsWith("{") && s.endsWith("}")) {
- // quick solution (which we don't do: just remove first "{" and last "}"
- // however, it might be that s is like {A}bbb{c}, where braces may not be removed
-
- // inner
- String inner = s.substring(1, s.length() - 1);
-
- if (inner.contains("}")) {
- if (properBrackets(inner)) {
- s = inner;
- }
- } else {
- // no inner curly brackets found, no check needed, inner can just be used as s
- s = inner;
- }
- }
- b.append(s).append(' ');
- }
- // delete last
- b.deleteCharAt(b.length() - 1);
-
- // now, all inner words are cleared
- // case {word word word} remains
- // as above, we have to be aware of {w}ord word wor{d} and {{w}ord word word}
-
- String newName = b.toString();
-
- if (newName.startsWith("{") && newName.endsWith("}")) {
- String inner = newName.substring(1, newName.length() - 1);
- if (properBrackets(inner)) {
- return inner;
- } else {
- return newName;
- }
- } else {
- return newName;
- }
- }
-
/**
* Returns the first name of the author stored in this object ("First").
*
@@ -304,7 +241,7 @@ public Optional getNameSuffix() {
* @return 'von Last'
*/
public String getNamePrefixAndFamilyName() {
- if (namePrefix == null) {
+ if (namePrefix == null || "".equals(namePrefix)) {
return getFamilyName().orElse("");
} else {
return familyName == null ? namePrefix : namePrefix + ' ' + familyName;
diff --git a/src/main/java/org/jabref/model/entry/BibEntry.java b/src/main/java/org/jabref/model/entry/BibEntry.java
index 19b33f257fb..b52b827579f 100644
--- a/src/main/java/org/jabref/model/entry/BibEntry.java
+++ b/src/main/java/org/jabref/model/entry/BibEntry.java
@@ -45,6 +45,7 @@
import org.jabref.model.strings.StringUtil;
import org.jabref.model.util.MultiKeyMap;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.eventbus.EventBus;
import com.tobiasdiez.easybind.EasyBind;
import com.tobiasdiez.easybind.optional.OptionalBinding;
@@ -353,19 +354,22 @@ private Optional genericGetResolvedFieldOrAlias(Field field, BibDatabase
}
/**
- * Returns this entry's ID.
+ * Returns this entry's ID. It is used internally to distinguish different BibTeX entries.
+ *
+ * It is not the citation key (which is stored in the {@link InternalField#KEY_FIELD} and also known as BibTeX key).
*/
public String getId() {
return id;
}
/**
- * Sets this entry's identifier (ID). It is used internally to distinguish different BibTeX entries. It is not the citation key. The BibTexKey is the {@link InternalField#KEY_FIELD}.
+ * Sets this entry's identifier (ID).
*
* The entry is also updated in the shared database - provided the database containing it doesn't veto the change.
*
* @param id The ID to be used
*/
+ @VisibleForTesting
public void setId(String id) {
Objects.requireNonNull(id, "Every BibEntry must have an ID");
@@ -613,11 +617,11 @@ public Optional setField(Field field, String value, EntriesEventSou
}
String oldValue = getField(field).orElse(null);
- boolean isNewField = oldValue == null;
if (value.equals(oldValue)) {
return Optional.empty();
}
+ boolean isNewField = oldValue == null;
changed = true;
invalidateFieldCache(field);
@@ -1062,15 +1066,15 @@ public BibEntry withFiles(List files) {
* Gets a list of linked files.
*
* @return the list of linked files, is never null but can be empty.
- * Changes to the underlying list will have no effect on the entry itself. Use {@link #addFile(LinkedFile)}
+ * Changes to the underlying list will have no effect on the entry itself. Use {@link #addFile(LinkedFile)}.
*/
public List getFiles() {
- // Extract the path
Optional oldValue = getField(StandardField.FILE);
if (oldValue.isEmpty()) {
return new ArrayList<>(); // Return new ArrayList because emptyList is immutable
}
+ // Extract the path
return FileFieldParser.parse(oldValue.get());
}
diff --git a/src/main/java/org/jabref/model/openoffice/DocumentAnnotation.java b/src/main/java/org/jabref/model/openoffice/DocumentAnnotation.java
new file mode 100644
index 00000000000..2d7037f7199
--- /dev/null
+++ b/src/main/java/org/jabref/model/openoffice/DocumentAnnotation.java
@@ -0,0 +1,15 @@
+package org.jabref.model.openoffice;
+
+import com.sun.star.text.XTextDocument;
+import com.sun.star.text.XTextRange;
+
+/**
+ * Represents a document annotation.
+ *
+ * @param doc The document
+ * @param name For the ReferenceMark, Bookmark, TextSection. If the name is already in use, LibreOffice may change the name.
+ * @param range Cursor marking the location or range for the thing to be inserted.
+ * @param absorb ReferenceMark, Bookmark and TextSection can incorporate a text range. If absorb is true, the text in the range becomes part of the thing. If absorb is false, the thing is inserted at the end of the range.
+ */
+public record DocumentAnnotation(XTextDocument doc, String name, XTextRange range, boolean absorb) {
+}
diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoBookmark.java b/src/main/java/org/jabref/model/openoffice/uno/UnoBookmark.java
index 5f4f5ea40d7..0f87ddcd21b 100644
--- a/src/main/java/org/jabref/model/openoffice/uno/UnoBookmark.java
+++ b/src/main/java/org/jabref/model/openoffice/uno/UnoBookmark.java
@@ -2,6 +2,8 @@
import java.util.Optional;
+import org.jabref.model.openoffice.DocumentAnnotation;
+
import com.sun.star.container.NoSuchElementException;
import com.sun.star.container.XNameAccess;
import com.sun.star.container.XNamed;
@@ -52,16 +54,13 @@ public static Optional getAnchor(XTextDocument doc, String name)
*
* In LibreOffice the another name is in "{name}{number}" format.
*
- * @param name For the bookmark.
- * @param range Cursor marking the location or range for the bookmark.
- * @param absorb Shall we incorporate range?
* @return The XNamed interface of the bookmark.
* result.getName() should be checked by the caller, because its name may differ from the one requested.
*/
- public static XNamed create(XTextDocument doc, String name, XTextRange range, boolean absorb)
+ public static XNamed create(DocumentAnnotation documentAnnotation)
throws
CreationException {
- return UnoNamed.insertNamedTextContent(doc, "com.sun.star.text.Bookmark", name, range, absorb);
+ return UnoNamed.insertNamedTextContent("com.sun.star.text.Bookmark", documentAnnotation);
}
/**
diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoNamed.java b/src/main/java/org/jabref/model/openoffice/uno/UnoNamed.java
index d3bf46668d1..3352150ba85 100644
--- a/src/main/java/org/jabref/model/openoffice/uno/UnoNamed.java
+++ b/src/main/java/org/jabref/model/openoffice/uno/UnoNamed.java
@@ -1,10 +1,10 @@
package org.jabref.model.openoffice.uno;
+import org.jabref.model.openoffice.DocumentAnnotation;
+
import com.sun.star.container.XNamed;
import com.sun.star.lang.XMultiServiceFactory;
import com.sun.star.text.XTextContent;
-import com.sun.star.text.XTextDocument;
-import com.sun.star.text.XTextRange;
public class UnoNamed {
@@ -17,20 +17,13 @@ private UnoNamed() {
* @param service For example "com.sun.star.text.ReferenceMark", "com.sun.star.text.Bookmark" or "com.sun.star.text.TextSection".
*
* Passed to this.asXMultiServiceFactory().createInstance(service) The result is expected to support the XNamed and XTextContent interfaces.
- * @param name For the ReferenceMark, Bookmark, TextSection. If the name is already in use, LibreOffice may change the name.
- * @param range Marks the location or range for the thing to be inserted.
- * @param absorb ReferenceMark, Bookmark and TextSection can incorporate a text range. If absorb is true, the text in the range becomes part of the thing. If absorb is false, the thing is inserted at the end of the range.
* @return The XNamed interface, in case we need to check the actual name.
*/
- static XNamed insertNamedTextContent(XTextDocument doc,
- String service,
- String name,
- XTextRange range,
- boolean absorb)
+ static XNamed insertNamedTextContent(String service, DocumentAnnotation documentAnnotation)
throws
CreationException {
- XMultiServiceFactory msf = UnoCast.cast(XMultiServiceFactory.class, doc).get();
+ XMultiServiceFactory msf = UnoCast.cast(XMultiServiceFactory.class, documentAnnotation.doc()).get();
Object xObject;
try {
@@ -41,12 +34,12 @@ static XNamed insertNamedTextContent(XTextDocument doc,
XNamed xNamed = UnoCast.cast(XNamed.class, xObject)
.orElseThrow(() -> new IllegalArgumentException("Service is not an XNamed"));
- xNamed.setName(name);
+ xNamed.setName(documentAnnotation.name());
// get XTextContent interface
XTextContent xTextContent = UnoCast.cast(XTextContent.class, xObject)
.orElseThrow(() -> new IllegalArgumentException("Service is not an XTextContent"));
- range.getText().insertTextContent(range, xTextContent, absorb);
+ documentAnnotation.range().getText().insertTextContent(documentAnnotation.range(), xTextContent, documentAnnotation.absorb());
return xNamed;
}
}
diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoReferenceMark.java b/src/main/java/org/jabref/model/openoffice/uno/UnoReferenceMark.java
index 12e36fae46a..0b9f2adc6c0 100644
--- a/src/main/java/org/jabref/model/openoffice/uno/UnoReferenceMark.java
+++ b/src/main/java/org/jabref/model/openoffice/uno/UnoReferenceMark.java
@@ -5,6 +5,8 @@
import java.util.List;
import java.util.Optional;
+import org.jabref.model.openoffice.DocumentAnnotation;
+
import com.sun.star.container.NoSuchElementException;
import com.sun.star.container.XNameAccess;
import com.sun.star.container.XNamed;
@@ -105,16 +107,14 @@ public static Optional getAnchor(XTextDocument doc, String name)
/**
* Insert a new reference mark at the provided cursor position.
*
- * If {@code absorb} is true, the text in the cursor range will become the text with gray background.
+ * If {@code documentAnnotation.getAbsorb} is true, the text in the cursor range will become the text with gray background.
*
* Note: LibreOffice 6.4.6.2 will create multiple reference marks with the same name without error or renaming. Its GUI does not allow this, but we can create them programmatically. In the GUI, clicking on any of those identical names will move the cursor to the same mark.
*
- * @param name For the reference mark.
- * @param range Cursor marking the location or range for the reference mark.
*/
- public static XNamed create(XTextDocument doc, String name, XTextRange range, boolean absorb)
+ public static XNamed create(DocumentAnnotation documentAnnotation)
throws
CreationException {
- return UnoNamed.insertNamedTextContent(doc, "com.sun.star.text.ReferenceMark", name, range, absorb);
+ return UnoNamed.insertNamedTextContent("com.sun.star.text.ReferenceMark", documentAnnotation);
}
}
diff --git a/src/main/java/org/jabref/model/openoffice/uno/UnoTextSection.java b/src/main/java/org/jabref/model/openoffice/uno/UnoTextSection.java
index 1717795cfa7..9e0c3fddf2d 100644
--- a/src/main/java/org/jabref/model/openoffice/uno/UnoTextSection.java
+++ b/src/main/java/org/jabref/model/openoffice/uno/UnoTextSection.java
@@ -2,6 +2,8 @@
import java.util.Optional;
+import org.jabref.model.openoffice.DocumentAnnotation;
+
import com.sun.star.container.NoSuchElementException;
import com.sun.star.container.XNameAccess;
import com.sun.star.container.XNamed;
@@ -63,17 +65,13 @@ public static Optional getAnchor(XTextDocument doc, String name)
/**
* Create a text section with the provided name and insert it at the provided cursor.
- *
- * @param name The desired name for the section.
- * @param range The location to insert at.
- *
- * If an XTextSection by that name already exists, LibreOffice (6.4.6.2) creates a section with a name different from what we requested, in "Section {number}" format.
+ * If an XTextSection by that name already exists, LibreOffice (6.4.6.2) creates a section with a name different from what we requested, in "Section {number}" format
*/
- public static XNamed create(XTextDocument doc, String name, XTextRange range, boolean absorb)
+ public static XNamed create(DocumentAnnotation documentAnnotation)
throws
CreationException {
- return UnoNamed.insertNamedTextContent(doc, "com.sun.star.text.TextSection", name, range, absorb);
+ return UnoNamed.insertNamedTextContent("com.sun.star.text.TextSection", documentAnnotation);
}
}
diff --git a/src/main/java/org/jabref/model/pdf/search/EnglishStemAnalyzer.java b/src/main/java/org/jabref/model/pdf/search/EnglishStemAnalyzer.java
deleted file mode 100644
index 1dcccbb6583..00000000000
--- a/src/main/java/org/jabref/model/pdf/search/EnglishStemAnalyzer.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package org.jabref.model.pdf.search;
-
-import org.apache.lucene.analysis.Analyzer;
-import org.apache.lucene.analysis.LowerCaseFilter;
-import org.apache.lucene.analysis.StopFilter;
-import org.apache.lucene.analysis.TokenStream;
-import org.apache.lucene.analysis.Tokenizer;
-import org.apache.lucene.analysis.core.DecimalDigitFilter;
-import org.apache.lucene.analysis.en.EnglishAnalyzer;
-import org.apache.lucene.analysis.en.PorterStemFilter;
-import org.apache.lucene.analysis.standard.StandardTokenizer;
-
-public class EnglishStemAnalyzer extends Analyzer {
-
- @Override
- protected TokenStreamComponents createComponents(String fieldName) {
- Tokenizer source = new StandardTokenizer();
- TokenStream filter = new LowerCaseFilter(source);
- filter = new StopFilter(filter, EnglishAnalyzer.ENGLISH_STOP_WORDS_SET);
- filter = new DecimalDigitFilter(filter);
- filter = new PorterStemFilter(filter);
- return new TokenStreamComponents(source, filter);
- }
-}
-
diff --git a/src/main/java/org/jabref/model/pdf/search/SearchResult.java b/src/main/java/org/jabref/model/pdf/search/SearchResult.java
index 7a79191e94c..aeb70ff6779 100644
--- a/src/main/java/org/jabref/model/pdf/search/SearchResult.java
+++ b/src/main/java/org/jabref/model/pdf/search/SearchResult.java
@@ -7,7 +7,9 @@
import org.jabref.model.entry.BibEntry;
+import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
+import org.apache.lucene.analysis.en.EnglishAnalyzer;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
@@ -46,14 +48,16 @@ public SearchResult(IndexSearcher searcher, Query query, ScoreDoc scoreDoc) thro
Highlighter highlighter = new Highlighter(new SimpleHTMLFormatter("", ""), new QueryScorer(query));
- try (TokenStream contentStream = new EnglishStemAnalyzer().tokenStream(CONTENT, content)) {
+ try (Analyzer analyzer = new EnglishAnalyzer();
+ TokenStream contentStream = analyzer.tokenStream(CONTENT, content)) {
TextFragment[] frags = highlighter.getBestTextFragments(contentStream, content, true, 10);
this.contentResultStringsHtml = Arrays.stream(frags).map(TextFragment::toString).collect(Collectors.toList());
} catch (InvalidTokenOffsetsException e) {
this.contentResultStringsHtml = List.of();
}
- try (TokenStream annotationStream = new EnglishStemAnalyzer().tokenStream(ANNOTATIONS, annotations)) {
+ try (Analyzer analyzer = new EnglishAnalyzer();
+ TokenStream annotationStream = analyzer.tokenStream(ANNOTATIONS, annotations)) {
TextFragment[] frags = highlighter.getBestTextFragments(annotationStream, annotations, true, 10);
this.annotationsResultStringsHtml = Arrays.stream(frags).map(TextFragment::toString).collect(Collectors.toList());
} catch (InvalidTokenOffsetsException e) {
@@ -62,7 +66,7 @@ public SearchResult(IndexSearcher searcher, Query query, ScoreDoc scoreDoc) thro
}
private String getFieldContents(IndexSearcher searcher, ScoreDoc scoreDoc, String field) throws IOException {
- IndexableField indexableField = searcher.doc(scoreDoc.doc).getField(field);
+ IndexableField indexableField = searcher.storedFields().document(scoreDoc.doc).getField(field);
if (indexableField == null) {
return "";
}
diff --git a/src/main/java/org/jabref/model/texparser/LatexParserResults.java b/src/main/java/org/jabref/model/texparser/LatexParserResults.java
index 63245fea4ea..d09df07408a 100644
--- a/src/main/java/org/jabref/model/texparser/LatexParserResults.java
+++ b/src/main/java/org/jabref/model/texparser/LatexParserResults.java
@@ -28,31 +28,20 @@ public LatexParserResults(LatexParserResult... parsedFiles) {
}
}
- public boolean isParsed(Path texFile) {
- return parsedTexFiles.containsKey(texFile);
- }
-
public void add(Path texFile, LatexParserResult parsedFile) {
parsedTexFiles.put(texFile, parsedFile);
}
+ public LatexParserResult remove(Path texFile) {
+ return parsedTexFiles.remove(texFile);
+ }
+
public Set getBibFiles() {
Set bibFiles = new HashSet<>();
parsedTexFiles.values().forEach(result -> bibFiles.addAll(result.getBibFiles()));
return bibFiles;
}
- public Set getNonParsedNestedFiles() {
- Set nonParsedNestedFiles = new HashSet<>();
- for (LatexParserResult result : parsedTexFiles.values()) {
- nonParsedNestedFiles.addAll(result.getNestedFiles()
- .stream()
- .filter(nestedFile -> !parsedTexFiles.containsKey(nestedFile))
- .toList());
- }
- return nonParsedNestedFiles;
- }
-
public Multimap getCitations() {
Multimap citations = HashMultimap.create();
parsedTexFiles.forEach((path, result) -> citations.putAll(result.getCitations()));
@@ -65,6 +54,10 @@ public Collection getCitationsByKey(String key) {
return citations;
}
+ public void clear() {
+ parsedTexFiles.clear();
+ }
+
@Override
public boolean equals(Object obj) {
if (this == obj) {
diff --git a/src/main/java/org/jabref/model/util/DirectoryMonitor.java b/src/main/java/org/jabref/model/util/DirectoryMonitor.java
new file mode 100644
index 00000000000..0678704c8a1
--- /dev/null
+++ b/src/main/java/org/jabref/model/util/DirectoryMonitor.java
@@ -0,0 +1,25 @@
+package org.jabref.model.util;
+
+import org.apache.commons.io.monitor.FileAlterationListener;
+import org.apache.commons.io.monitor.FileAlterationObserver;
+
+public interface DirectoryMonitor {
+ /**
+ * Add an observer to the monitor.
+ *
+ * @param observer The directory to observe.
+ * @param listener The listener to invoke when the directory changes.
+ */
+ void addObserver(FileAlterationObserver observer, FileAlterationListener listener);
+
+ /**
+ * Remove an observer from the monitor.
+ *
+ * @param observer The directory to stop monitoring.
+ */
+ void removeObserver(FileAlterationObserver observer);
+
+ void start();
+
+ void shutdown();
+}
diff --git a/src/main/java/org/jabref/model/util/DirectoryMonitorManager.java b/src/main/java/org/jabref/model/util/DirectoryMonitorManager.java
new file mode 100644
index 00000000000..ba3c6546a8f
--- /dev/null
+++ b/src/main/java/org/jabref/model/util/DirectoryMonitorManager.java
@@ -0,0 +1,36 @@
+package org.jabref.model.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.io.monitor.FileAlterationListener;
+import org.apache.commons.io.monitor.FileAlterationObserver;
+
+public class DirectoryMonitorManager {
+
+ private final DirectoryMonitor directoryMonitor;
+ private final List observers = new ArrayList<>();
+
+ public DirectoryMonitorManager(DirectoryMonitor directoryMonitor) {
+ this.directoryMonitor = directoryMonitor;
+ }
+
+ public void addObserver(FileAlterationObserver observer, FileAlterationListener listener) {
+ directoryMonitor.addObserver(observer, listener);
+ observers.add(observer);
+ }
+
+ public void removeObserver(FileAlterationObserver observer) {
+ directoryMonitor.removeObserver(observer);
+ observers.remove(observer);
+ }
+
+ /**
+ * Unregister all observers associated with this manager from the directory monitor.
+ * This method should be called when the library is closed to stop watching observers.
+ */
+ public void unregister() {
+ observers.forEach(directoryMonitor::removeObserver);
+ observers.clear();
+ }
+}
diff --git a/src/main/java/org/jabref/preferences/JabRefPreferences.java b/src/main/java/org/jabref/preferences/JabRefPreferences.java
index 55de7b43b54..59b01569a34 100644
--- a/src/main/java/org/jabref/preferences/JabRefPreferences.java
+++ b/src/main/java/org/jabref/preferences/JabRefPreferences.java
@@ -173,6 +173,10 @@ public class JabRefPreferences implements PreferencesService {
public static final String BIBLATEX_DEFAULT_MODE = "biblatexMode";
public static final String NAMES_AS_IS = "namesAsIs";
public static final String ENTRY_EDITOR_HEIGHT = "entryEditorHeightFX";
+ /**
+ * Holds the horizontal divider position of the preview view when it is shown inside the entry editor
+ */
+ public static final String ENTRY_EDITOR_PREVIEW_DIVIDER_POS = "entryEditorPreviewDividerPos";
public static final String AUTO_RESIZE_MODE = "autoResizeMode";
public static final String WINDOW_MAXIMISED = "windowMaximised";
public static final String WINDOW_FULLSCREEN = "windowFullscreen";
@@ -602,6 +606,7 @@ private JabRefPreferences() {
defaults.put(WINDOW_FULLSCREEN, Boolean.FALSE);
defaults.put(AUTO_RESIZE_MODE, Boolean.FALSE); // By default disable "Fit table horizontally on the screen"
defaults.put(ENTRY_EDITOR_HEIGHT, 0.65);
+ defaults.put(ENTRY_EDITOR_PREVIEW_DIVIDER_POS, 0.5);
defaults.put(NAMES_AS_IS, Boolean.FALSE); // "Show names unchanged"
defaults.put(NAMES_FIRST_LAST, Boolean.FALSE); // "Show 'Firstname Lastname'"
defaults.put(NAMES_NATBIB, Boolean.TRUE); // "Natbib style"
@@ -821,7 +826,7 @@ private JabRefPreferences() {
"\\begin{pages}
p. \\format[FormatPagesForHTML]{\\pages}\\end{pages}__NEWLINE__" +
"\\begin{abstract}
Abstract: \\format[HTMLChars]{\\abstract} \\end{abstract}__NEWLINE__" +
"\\begin{owncitation}
Own citation: \\format[HTMLChars]{\\owncitation} \\end{owncitation}__NEWLINE__" +
- "\\begin{comment}
Comment: \\format[Markdown,HTMLChars]{\\comment}\\end{comment}__NEWLINE__" +
+ "\\begin{comment}
Comment: \\format[Markdown,HTMLChars(keepCurlyBraces)]{\\comment}\\end{comment}__NEWLINE__" +
"__NEWLINE__");
// set default theme
@@ -1488,7 +1493,8 @@ public EntryEditorPreferences getEntryEditorPreferences() {
getBoolean(AUTOLINK_FILES_ENABLED),
EntryEditorPreferences.JournalPopupEnabled.fromString(get(JOURNAL_POPUP)),
getBoolean(SHOW_SCITE_TAB),
- getBoolean(SHOW_USER_COMMENTS_FIELDS));
+ getBoolean(SHOW_USER_COMMENTS_FIELDS),
+ getDouble(ENTRY_EDITOR_PREVIEW_DIVIDER_POS));
EasyBind.listen(entryEditorPreferences.entryEditorTabs(), (obs, oldValue, newValue) -> storeEntryEditorTabs(newValue));
// defaultEntryEditorTabs are read-only
@@ -1503,7 +1509,7 @@ public EntryEditorPreferences getEntryEditorPreferences() {
EasyBind.listen(entryEditorPreferences.enableJournalPopupProperty(), (obs, oldValue, newValue) -> put(JOURNAL_POPUP, newValue.toString()));
EasyBind.listen(entryEditorPreferences.shouldShowLSciteTabProperty(), (obs, oldValue, newValue) -> putBoolean(SHOW_SCITE_TAB, newValue));
EasyBind.listen(entryEditorPreferences.showUserCommentsFieldsProperty(), (obs, oldValue, newValue) -> putBoolean(SHOW_USER_COMMENTS_FIELDS, newValue));
-
+ EasyBind.listen(entryEditorPreferences.previewWidthDividerPositionProperty(), (obs, oldValue, newValue) -> putDouble(ENTRY_EDITOR_PREVIEW_DIVIDER_POS, newValue.doubleValue()));
return entryEditorPreferences;
}
diff --git a/src/main/resources/csl-styles b/src/main/resources/csl-styles
index d9ca25977a1..434df0ad75d 160000
--- a/src/main/resources/csl-styles
+++ b/src/main/resources/csl-styles
@@ -1 +1 @@
-Subproject commit d9ca25977a10d6717d0fc219c1b982863a23a0e7
+Subproject commit 434df0ad75d7416bb651ad1f08826a5152c77a27
diff --git a/src/main/resources/l10n/JabRef_de.properties b/src/main/resources/l10n/JabRef_de.properties
index 9d6ee1620c2..770d0680f26 100644
--- a/src/main/resources/l10n/JabRef_de.properties
+++ b/src/main/resources/l10n/JabRef_de.properties
@@ -61,7 +61,7 @@ Added\ group\ "%0".=Gruppe "%0" hinzugefügt.
Added\ string\:\ '%0'=Zeichenkette hinzugefügt\: '%0'
Added\ string=String hinzugefügt
Edit\ strings=Strings bearbeiten
-Duplicate\ string\ name\:\ '%0'=Doppelter String-Name\: '%0'l
+Duplicate\ string\ name\:\ '%0'=Doppelter String-Name\: '%0'
Modified\ string=Veränderter String
Modified\ string\:\ '%0' =String geändert\: '%0'
New\ string=Neuer String
@@ -276,7 +276,6 @@ Donate\ to\ JabRef=An JabRef spenden
Download\ file=Datei herunterladen
-Downloaded\ website\ as\ an\ HTML\ file.=Webseite als HTML-Datei herunterladen.
duplicate\ removal=Duplikate entfernen
@@ -370,7 +369,6 @@ Manage\ field\ names\ &\ content=Feldnamen & Inhalt verwalten
Field\ to\ group\ by=Sortierfeld
Filter=Filter
-Filter\ groups=Gruppen filtern
Success\!\ Finished\ writing\ metadata.=Erfolgreich\! Das Schreiben der Metadaten ist abgeschlossen.
Error\ while\ writing\ metadata.\ See\ the\ error\ log\ for\ details.=Fehler beim Schreiben von Metadaten. Details finden Sie im Fehlerprotokoll.
@@ -1878,7 +1876,6 @@ Could\ not\ copy\ file=Datei konnte nicht kopiert werden
Copied\ %0\ files\ of\ %1\ successfully\ to\ %2=Kopierte %0 Dateien von %1 erfolgreich nach %2
Rename\ failed=Umbenennen fehlgeschlagen
JabRef\ cannot\ access\ the\ file\ because\ it\ is\ being\ used\ by\ another\ process.=JabRef kann nicht auf die Datei zugreifen, da sie von einem anderen Prozess verwendet wird.
-Show\ console\ output\ (only\ when\ the\ launcher\ is\ used)=Konsolenausgabe anzeigen (nur wenn der Launcher verwendet wird)
Remove\ line\ breaks=Entfernen der Zeilenumbrüche
Removes\ all\ line\ breaks\ in\ the\ field\ content.=Entfernen aller Zeilenumbrüche im Inhalt des Feldes.
@@ -2045,7 +2042,6 @@ No\ LaTeX\ files\ containing\ this\ entry\ were\ found.=Es wurden keine LaTeX-Da
Selected\ entry\ does\ not\ have\ an\ associated\ citation\ key.=Der ausgewählte Eintrag hat keinen zugehörigen Zitationsschlüssel.
Current\ search\ directory\:=Aktuelles Suchverzeichnis\:
Set\ LaTeX\ file\ directory=LaTeX-Dateiverzeichnis festlegen
-Refresh=Aktualisieren
Import\ entries\ from\ LaTeX\ files=Einträge aus LaTeX-Dateien importieren
Import\ new\ entries=Neue Einträge importieren
Group\ color=Gruppenfarbe
@@ -2157,7 +2153,7 @@ Text\ editor=Text Editor
Search\ ShortScience=Durchsuche ShortScience
Unable\ to\ open\ ShortScience.=Kann keine Verbindung zu ShortScience herstellen.
-Shared\ database=Geteilte SQL-Datenbank
+Shared\ database=Geteilte Bibliothek (SQL)
Lookup=Nachschlagen
Access\ date\ of\ the\ address\ specified\ in\ the\ url\ field.=Zugriffsdatum der im URL-Feld angegebenen Adresse.
@@ -2401,7 +2397,6 @@ Convert\ timestamp\ field\ to\ field\ 'modificationdate'=timestamp in Feld 'modi
New\ entry\ by\ type=Neuer Eintrag nach Typ
File\ '%1'\ is\ a\ duplicate\ of\ '%0'.\ Keeping\ '%0'=Datei '%1' ist ein Duplikat von '%0'. Behalte '%0'
-File\ '%1'\ is\ a\ duplicate\ of\ '%0'.\ Keeping\ both\ due\ to\ deletion\ error=Datei '%1' ist ein Duplikat von '%0'. Beide werden aufgrund eines Löschfehlers beibehalten
Enable\ field\ formatters=Feldformatierer aktivieren
Entry\ Type=Eintragstyp
diff --git a/src/main/resources/l10n/JabRef_el.properties b/src/main/resources/l10n/JabRef_el.properties
index 344fc48add5..3a142fc59fb 100644
--- a/src/main/resources/l10n/JabRef_el.properties
+++ b/src/main/resources/l10n/JabRef_el.properties
@@ -261,7 +261,6 @@ Donate\ to\ JabRef=Δωρεά στο JabRef
Download\ file=Κατέβασμα αρχείου
-Downloaded\ website\ as\ an\ HTML\ file.=Ολοκληρώθηκε η λήψη της ιστοσελίδας υπό τη μορφή HTML αρχείου.
duplicate\ removal=διαγραφή διπλότυπων
@@ -333,7 +332,6 @@ Field\ names\ are\ not\ allowed\ to\ contain\ white\ spaces\ or\ certain\ charac
Field\ to\ group\ by=Ομαδοποίηση με το πεδίο
Filter=Φίλτρο
-Filter\ groups=Φιλτράρισμα ομάδων
Success\!\ Finished\ writing\ metadata.=Επιτυχία\! Η εγγραφή των μεταδεδομένων ολοκληρώθηκε.
Error\ while\ writing\ metadata.\ See\ the\ error\ log\ for\ details.=Σφάλμα κατά την καταγραφή μεταδεδομένων. Ανατρέξτε στο ιστορικό σφαλμάτων για λεπτομέρειες.
diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties
index 21233b43e2f..21c49a26efb 100644
--- a/src/main/resources/l10n/JabRef_en.properties
+++ b/src/main/resources/l10n/JabRef_en.properties
@@ -276,7 +276,8 @@ Donate\ to\ JabRef=Donate to JabRef
Download\ file=Download file
-Downloaded\ website\ as\ an\ HTML\ file.=Downloaded website as an HTML file.
+Download\ '%0'\ was\ a\ HTML\ file.\ Removed.=Download '%0' was a HTML file. Removed.
+Download\ '%0'\ was\ a\ HTML\ file.\ Keeping\ URL.=Download '%0' was a HTML file. Keeping URL.
duplicate\ removal=duplicate removal
@@ -1479,6 +1480,8 @@ Protect\ terms=Protect terms
Add\ enclosing\ braces=Add enclosing braces
Add\ braces\ encapsulating\ the\ complete\ field\ content.=Add braces encapsulating the complete field content.
Remove\ enclosing\ braces=Remove enclosing braces
+Remove\ word\ enclosing\ braces=Remove word enclosing braces
+Removes\ braces\ encapsulating\ a\ complete\ word\ and\ the\ complete\ field\ content.=Removes braces encapsulating a complete word and the complete field content.
Removes\ braces\ encapsulating\ the\ complete\ field\ content.=Removes braces encapsulating the complete field content.
Removes\ all\ balanced\ {}\ braces\ around\ words.=Removes all balanced {} braces around words.
Shorten\ DOI=Shorten DOI
@@ -1879,7 +1882,6 @@ Could\ not\ copy\ file=Could not copy file
Copied\ %0\ files\ of\ %1\ successfully\ to\ %2=Copied %0 files of %1 successfully to %2
Rename\ failed=Rename failed
JabRef\ cannot\ access\ the\ file\ because\ it\ is\ being\ used\ by\ another\ process.=JabRef cannot access the file because it is being used by another process.
-Show\ console\ output\ (only\ when\ the\ launcher\ is\ used)=Show console output (only when the launcher is used)
Remove\ line\ breaks=Remove line breaks
Removes\ all\ line\ breaks\ in\ the\ field\ content.=Removes all line breaks in the field content.
@@ -2043,10 +2045,10 @@ LaTeX\ Citations=LaTeX Citations
Search\ citations\ for\ this\ entry\ in\ LaTeX\ files=Search citations for this entry in LaTeX files
No\ citations\ found=No citations found
No\ LaTeX\ files\ containing\ this\ entry\ were\ found.=No LaTeX files containing this entry were found.
+Current\ search\ directory\ does\ not\ exist\:\ %0= Current search directory does not exist: %0
Selected\ entry\ does\ not\ have\ an\ associated\ citation\ key.=Selected entry does not have an associated citation key.
Current\ search\ directory\:=Current search directory:
Set\ LaTeX\ file\ directory=Set LaTeX file directory
-Refresh=Refresh
Import\ entries\ from\ LaTeX\ files=Import entries from LaTeX files
Import\ new\ entries=Import new entries
Group\ color=Group color
@@ -2402,7 +2404,6 @@ Convert\ timestamp\ field\ to\ field\ 'modificationdate'=Convert timestamp field
New\ entry\ by\ type=New entry by type
File\ '%1'\ is\ a\ duplicate\ of\ '%0'.\ Keeping\ '%0'=File '%1' is a duplicate of '%0'. Keeping '%0'
-File\ '%1'\ is\ a\ duplicate\ of\ '%0'.\ Keeping\ both\ due\ to\ deletion\ error=File '%1' is a duplicate of '%0'. Keeping both due to deletion error
Enable\ field\ formatters=Enable field formatters
Entry\ Type=Entry Type
diff --git a/src/main/resources/l10n/JabRef_es.properties b/src/main/resources/l10n/JabRef_es.properties
index e6caaddff68..1b7b209e39b 100644
--- a/src/main/resources/l10n/JabRef_es.properties
+++ b/src/main/resources/l10n/JabRef_es.properties
@@ -273,7 +273,6 @@ Donate\ to\ JabRef=Donar a JabRef
Download\ file=Descargar archivo
-Downloaded\ website\ as\ an\ HTML\ file.=Se descargó el sitio web como un archivo HTML.
duplicate\ removal=eliminación de duplicados
@@ -361,7 +360,6 @@ Manage\ field\ names\ &\ content=Gestionar nombres y contenido de los campos
Field\ to\ group\ by=Agrupar a partir de campo
Filter=Filtro
-Filter\ groups=Filtros
Success\!\ Finished\ writing\ metadata.=¡Éxito\! Se ha terminado de escribir metadatos.
Error\ while\ writing\ metadata.\ See\ the\ error\ log\ for\ details.=Error al escribir los metadatos. Vea el registro de errores para más detalles.
@@ -1832,7 +1830,6 @@ Finished\ copying=Copia finalizada
Could\ not\ copy\ file=No se puede copiar el archivo
Rename\ failed=Error al renombrar
JabRef\ cannot\ access\ the\ file\ because\ it\ is\ being\ used\ by\ another\ process.=JabRef no puede acceder al archivo porque está siendo utilizado por otro proceso.
-Show\ console\ output\ (only\ when\ the\ launcher\ is\ used)=Mostrar la salida de la consola (sólo cuando se utiliza el lanzador)
Remove\ line\ breaks=Eliminar saltos de línea
Removes\ all\ line\ breaks\ in\ the\ field\ content.=Eliminar todos los saltos de línea en el contenido del campo.
@@ -1996,7 +1993,6 @@ No\ LaTeX\ files\ containing\ this\ entry\ were\ found.=No se han encontrado arc
Selected\ entry\ does\ not\ have\ an\ associated\ citation\ key.=La entrada seleccionada no tiene asociada una clave de cita.
Current\ search\ directory\:=Directorio de búsqueda actual\:
Set\ LaTeX\ file\ directory=Establecer directorio de archivos LaTeX
-Refresh=Actualizar
Import\ entries\ from\ LaTeX\ files=Importar entradas desde archivos LaTeX
Import\ new\ entries=Importar nuevas entradas
Group\ color=Color del grupo
@@ -2333,7 +2329,6 @@ Download\ operation\ canceled.=Operación de descarga cancelada.
New\ entry\ by\ type=Entrada nueva por tipo
File\ '%1'\ is\ a\ duplicate\ of\ '%0'.\ Keeping\ '%0'=El archivo «%1» es un duplicado de «%0». Se conserva «%0»
-File\ '%1'\ is\ a\ duplicate\ of\ '%0'.\ Keeping\ both\ due\ to\ deletion\ error=El archivo «%1» es un duplicado de «%0». Se conservan ambos a causa de un error de eliminación
Enable\ field\ formatters=Habilitar formateadores de campos
Entry\ Type=Tipo de entrada
diff --git a/src/main/resources/l10n/JabRef_fr.properties b/src/main/resources/l10n/JabRef_fr.properties
index 6ad66b016ff..f08192f2c43 100644
--- a/src/main/resources/l10n/JabRef_fr.properties
+++ b/src/main/resources/l10n/JabRef_fr.properties
@@ -219,6 +219,7 @@ Custom\ entry\ types\ found\ in\ file=Types d'entrées personnalisées trouvées
Customize\ entry\ types=Personnaliser les types d'entrées
+Customize\ keyboard\ shortcuts=Personnaliser les raccourcis clavier
Cut=Couper
@@ -275,7 +276,6 @@ Donate\ to\ JabRef=Faire un don à JabRef
Download\ file=Télécharger le fichier
-Downloaded\ website\ as\ an\ HTML\ file.=Site web téléchargé en tant que fichier HTML.
duplicate\ removal=Suppression des doublons
@@ -328,6 +328,10 @@ Export\ preferences\ to\ file=Exporter les préférences vers un fichier
Export\ to\ clipboard=Exporter vers le presse-papiers
Export\ to\ text\ file.=Exporter vers un fichier texte.
+Extract\ references\ from\ file\ (online)=Extraire les références du fichier (en ligne)
+Extract\ references\ from\ file\ (offline)=Extraire les références du fichier (hors ligne)
+Extract\ References\ (online)=Extraire les références (en ligne)
+Extract\ References\ (offline)=Extraire les références (hors ligne)
Processing\ PDF(s)=Traitement des PDF(s) en cours
Processing\ a\ large\ number\ of\ files=Traitement d'un grand nombre de fichiers
You\ are\ about\ to\ process\ %0\ files.\ Continue?=Vous êtes sur le point de traiter %0 fichiers. Continuer ?
@@ -365,7 +369,6 @@ Manage\ field\ names\ &\ content=Gérer les noms de champs et leur contenu
Field\ to\ group\ by=Champ à grouper par
Filter=Choix des filtres
-Filter\ groups=Filtrer les groupes
Success\!\ Finished\ writing\ metadata.=Succès \! Écriture des métadonnées terminée.
Error\ while\ writing\ metadata.\ See\ the\ error\ log\ for\ details.=Erreur lors de l'écriture des métadonnées. Consultez le journal des erreurs pour plus de détails.
@@ -506,7 +509,9 @@ Keep\ subgroups=Conserver les sous-groupes
Key\ pattern=Paramétrage des clefs
+Keyboard\ shortcuts=Raccourcis clavier
+Keyboard\ shortcuts\ changed=Raccourcis clavier modifiés
keys\ in\ library=clefs dans le fichier
@@ -1240,11 +1245,13 @@ You\ have\ to\ choose\ exactly\ two\ entries\ to\ merge.=Vous devez choisir exac
Add\ timestamp\ to\ modified\ entries\ (field\ "modificationdate")=Ajouter un horodatage aux entrées modifiées (champ "modificationdate")
Add\ timestamp\ to\ new\ entries\ (field\ "creationdate")=Ajouter un horodatage aux nouvelles entrées (champ "creationdate")
+All\ keyboard\ shortcuts\ will\ be\ reset\ to\ their\ defaults.=Tous les raccourcis clavier seront réinitialisés à leurs valeurs par défaut.
Automatically\ set\ file\ links=Configurer automatiquement les liens de fichier
Finished\ automatically\ setting\ external\ links.=La définition automatique des liens externes est terminée.
Changed\ %0\ entries.=%0 entrées modifiées.
+Resetting\ all\ keyboard\ shortcuts=Réinitialisation de tous les raccourcis clavier
Open\ folder=Ouvrir le répertoire
Export\ sort\ order=Exporter l'ordre de tri
@@ -1869,7 +1876,6 @@ Could\ not\ copy\ file=Le fichier n'a pas pu être copié
Copied\ %0\ files\ of\ %1\ successfully\ to\ %2=%0 fichiers sur %1 ont été copiés avec succès vers %2
Rename\ failed=Échec du renommage
JabRef\ cannot\ access\ the\ file\ because\ it\ is\ being\ used\ by\ another\ process.=JabRef ne peut pas accéder au fichier parce qu'il est utilisé par un autre processus.
-Show\ console\ output\ (only\ when\ the\ launcher\ is\ used)=Afficher la sortie de la console (uniquement nécessaire quand l'application est utilisée)
Remove\ line\ breaks=Supprimer les sauts de ligne
Removes\ all\ line\ breaks\ in\ the\ field\ content.=Supprime tous les sauts de ligne du contenu d'un champ.
@@ -2036,7 +2042,6 @@ No\ LaTeX\ files\ containing\ this\ entry\ were\ found.=Aucun fichier LaTeX cont
Selected\ entry\ does\ not\ have\ an\ associated\ citation\ key.=L'entrée sélectionnée n'a pas de clef de citation associée.
Current\ search\ directory\:=Répertoire de recherche actuel \:
Set\ LaTeX\ file\ directory=Configurer le répertoire des fichiers LaTeX
-Refresh=Rafraîchir
Import\ entries\ from\ LaTeX\ files=Importer des entrées à partir des fichiers LaTeX
Import\ new\ entries=Importer de nouvelles entrées
Group\ color=Couleur du groupe
@@ -2392,7 +2397,6 @@ Convert\ timestamp\ field\ to\ field\ 'modificationdate'=Convertir le champ 'tim
New\ entry\ by\ type=Nouvelle entrée par type
File\ '%1'\ is\ a\ duplicate\ of\ '%0'.\ Keeping\ '%0'=Le fichier '%1' est un doublon de '%0'. Conservation de '%0'
-File\ '%1'\ is\ a\ duplicate\ of\ '%0'.\ Keeping\ both\ due\ to\ deletion\ error=Le fichier '%1' est un doublon de '%0'. Conservation des deux en raison d'une erreur de suppression
Enable\ field\ formatters=Activer les formateurs de champs
Entry\ Type=Type d’entrée
@@ -2585,6 +2589,8 @@ Writing\ metadata\ to\ %0=Écriture des métadonnées sur %0
Get\ more\ themes...=Obtenir plus de thèmes...
+Miscellaneous=Divers
+File-related=Lié au fichier
Add\ selected\ entries\ to\ database=Ajouter les entrées sélectionnées au fichier
The\ selected\ entry\ doesn't\ have\ a\ DOI\ linked\ to\ it.\ Lookup\ a\ DOI\ and\ try\ again.=L'entrée sélectionnée ne contient pas de DOI. Recherchez un DOI et réessayez.
diff --git a/src/main/resources/l10n/JabRef_it.properties b/src/main/resources/l10n/JabRef_it.properties
index 3a01e3b6340..5ad4fb78896 100644
--- a/src/main/resources/l10n/JabRef_it.properties
+++ b/src/main/resources/l10n/JabRef_it.properties
@@ -219,6 +219,7 @@ Custom\ entry\ types\ found\ in\ file=Tipi di voce personalizzati trovati nel fi
Customize\ entry\ types=Personalizza tipi di voce
+Customize\ keyboard\ shortcuts=Personalizza le scorciatoie da tastiera
Cut=Taglia
@@ -275,7 +276,6 @@ Donate\ to\ JabRef=Fai una donazione a JabRef
Download\ file=Scarica il file
-Downloaded\ website\ as\ an\ HTML\ file.=Sito web scaricato come file HTML.
duplicate\ removal=rimozione di doppioni
@@ -328,6 +328,10 @@ Export\ preferences\ to\ file=Esporta preferenze in un file
Export\ to\ clipboard=Esporta negli appunti
Export\ to\ text\ file.=Esporta su file di testo.
+Extract\ references\ from\ file\ (online)=Estrai i riferimenti dal file (online)
+Extract\ references\ from\ file\ (offline)=Estrai i riferimenti dal file (offline)
+Extract\ References\ (online)=Estrai Riferimenti (online)
+Extract\ References\ (offline)=Estrai i riferimenti dal file (offline)
Processing\ PDF(s)=Elaborazione PDF
Processing\ a\ large\ number\ of\ files=Elaborazione di un gran numero di file
You\ are\ about\ to\ process\ %0\ files.\ Continue?=Stai per elaborare %0 file. Continuare?
@@ -365,7 +369,6 @@ Manage\ field\ names\ &\ content=Gestione nomi di campi e contenuto
Field\ to\ group\ by=Campo di raggruppamento
Filter=Filtro
-Filter\ groups=Filtra gruppi
Success\!\ Finished\ writing\ metadata.=Completato con successo\! Scrivere i metadati.
Error\ while\ writing\ metadata.\ See\ the\ error\ log\ for\ details.=Errore durante la scrittura dei metadati. Vedere il registro degli errori per i dettagli.
@@ -506,7 +509,9 @@ Keep\ subgroups=Mantieni sottogruppi
Key\ pattern=Modello delle chiavi
+Keyboard\ shortcuts=Scorciatoie da tastiera
+Keyboard\ shortcuts\ changed=Scorciatoie da tastiera cambiate
keys\ in\ library=Chiavi nella libreria
@@ -1240,11 +1245,13 @@ You\ have\ to\ choose\ exactly\ two\ entries\ to\ merge.=È necessario seleziona
Add\ timestamp\ to\ modified\ entries\ (field\ "modificationdate")=Aggiungi timestamp alle voci modificate (campo "modificationdate")
Add\ timestamp\ to\ new\ entries\ (field\ "creationdate")=Aggiungi timestamp alle nuove voci (campo "creationdate")
+All\ keyboard\ shortcuts\ will\ be\ reset\ to\ their\ defaults.=Tutte le scorciatoie da tastiera verranno reimpostate ai valori predefiniti.
Automatically\ set\ file\ links=Impostazione automatica dei collegamenti ai file
Finished\ automatically\ setting\ external\ links.=Impostazione automatica dei collegamenti esterni terminata.
Changed\ %0\ entries.=Modificate %0 voci.
+Resetting\ all\ keyboard\ shortcuts=Ripristino di tutte le scorciatoie da tastiera
Open\ folder=Apri cartella
Export\ sort\ order=Esporta il modo di ordinamento
@@ -1869,7 +1876,6 @@ Could\ not\ copy\ file=Impossibile copiare il file
Copied\ %0\ files\ of\ %1\ successfully\ to\ %2=%0 file su %1 sono stati copiati correttamente in %2
Rename\ failed=Rinomina non riuscita
JabRef\ cannot\ access\ the\ file\ because\ it\ is\ being\ used\ by\ another\ process.=JabRef non può accedere al file perché questo è utilizzato da un altro processo.
-Show\ console\ output\ (only\ when\ the\ launcher\ is\ used)=Mostra l'output della console (solo quando viene utilizzato il launcher)
Remove\ line\ breaks=Rimuovi interruzioni di riga
Removes\ all\ line\ breaks\ in\ the\ field\ content.=Rimuove tutte le interruzioni di riga nel contenuto del campo.
@@ -2036,7 +2042,6 @@ No\ LaTeX\ files\ containing\ this\ entry\ were\ found.=Nessun file LaTeX conten
Selected\ entry\ does\ not\ have\ an\ associated\ citation\ key.=La voce selezionata non ha una chiave BibTeX associata.
Current\ search\ directory\:=Cartella di ricerca corrente\:
Set\ LaTeX\ file\ directory=Imposta la cartella dei file LaTeX
-Refresh=Aggiorna
Import\ entries\ from\ LaTeX\ files=Importa le voci da file LaTeX
Import\ new\ entries=Importa nuove voci
Group\ color=Colore del gruppo
@@ -2392,7 +2397,6 @@ Convert\ timestamp\ field\ to\ field\ 'modificationdate'=Converti il campo times
New\ entry\ by\ type=Nuova voce per tipo
File\ '%1'\ is\ a\ duplicate\ of\ '%0'.\ Keeping\ '%0'=Il file '%1' è un duplicato di '%0'. Mantenere '%0'
-File\ '%1'\ is\ a\ duplicate\ of\ '%0'.\ Keeping\ both\ due\ to\ deletion\ error=Il file '%1' è un duplicato di '%0'. Mantenere entrambi a causa di errore di cancellazione
Enable\ field\ formatters=Abilita formatori di campo
Entry\ Type=Tipo di voce
@@ -2585,6 +2589,8 @@ Writing\ metadata\ to\ %0=Scrittura dei metadati su %0
Get\ more\ themes...=Ottieni altri temi...
+Miscellaneous=Varie
+File-related=Correlato al file
Add\ selected\ entries\ to\ database=Aggiungi le voci selezionate al database
The\ selected\ entry\ doesn't\ have\ a\ DOI\ linked\ to\ it.\ Lookup\ a\ DOI\ and\ try\ again.=La voce selezionata non ha un DOI collegato ad essa. Cerca un DOI e riprova.
diff --git a/src/main/resources/l10n/JabRef_ja.properties b/src/main/resources/l10n/JabRef_ja.properties
index 8c590e3d08a..745f29b2877 100644
--- a/src/main/resources/l10n/JabRef_ja.properties
+++ b/src/main/resources/l10n/JabRef_ja.properties
@@ -263,7 +263,6 @@ Donate\ to\ JabRef=JabRefに寄付
Download\ file=ファイルをダウンロード
-Downloaded\ website\ as\ an\ HTML\ file.=ウェブサイトを HTML ファイルとしてダウンロードしました.
duplicate\ removal=重複を削除
@@ -342,7 +341,6 @@ Manage\ field\ names\ &\ content=フィールド名・フィールド値の管
Field\ to\ group\ by=グループ化するフィールド
Filter=フィルタ
-Filter\ groups=グループ絞り込み
Success\!\ Finished\ writing\ metadata.=成功しました!メタデータの書き込みを終了しました.
Error\ while\ writing\ metadata.\ See\ the\ error\ log\ for\ details.=メタデータ書き込み中にエラー.詳細についてはエラーログを参照してください.
@@ -1761,7 +1759,6 @@ Finished\ copying=コピーを終了しました
Could\ not\ copy\ file=ファイルをコピーできませんでした
Rename\ failed=改名に失敗しました
JabRef\ cannot\ access\ the\ file\ because\ it\ is\ being\ used\ by\ another\ process.=ファイルが他のプロセスによって使用されているため,JabRefがアクセスすることができません.
-Show\ console\ output\ (only\ when\ the\ launcher\ is\ used)=コンソール出力を表示(ロンチャーを使用する場合のみ)
Remove\ line\ breaks=改行を取り除く
Removes\ all\ line\ breaks\ in\ the\ field\ content.=フィールドの内容から改行を全て取り除きます.
@@ -2261,7 +2258,6 @@ Convert\ timestamp\ field\ to\ field\ 'modificationdate'=timestampフィール
New\ entry\ by\ type=型別の新規項目
File\ '%1'\ is\ a\ duplicate\ of\ '%0'.\ Keeping\ '%0'=ファイル「%1」は「%0」と重複しています.「%0」を保持します
-File\ '%1'\ is\ a\ duplicate\ of\ '%0'.\ Keeping\ both\ due\ to\ deletion\ error=ファイル「%1」は「%0」と重複しています.削除エラーが起こりましたので両方保持します
Enable\ field\ formatters=フィールド整形の定義を有効にする
Entry\ Type=項目型
diff --git a/src/main/resources/l10n/JabRef_ko.properties b/src/main/resources/l10n/JabRef_ko.properties
index a82bd22c4c7..de01984d61c 100644
--- a/src/main/resources/l10n/JabRef_ko.properties
+++ b/src/main/resources/l10n/JabRef_ko.properties
@@ -250,7 +250,6 @@ Donate\ to\ JabRef=JabRef에 기부하기
Download\ file=파일 다운로드
-Downloaded\ website\ as\ an\ HTML\ file.=웹사이트를 HTML 파일로 다운로드했습니다.
duplicate\ removal=중복 제거
@@ -327,7 +326,6 @@ Manage\ field\ names\ &\ content=필드 이름 및 콘텐츠 관리
Field\ to\ group\ by=필드를 그룹화 하다
Filter=필터
-Filter\ groups=그룹 필터링
Generate=생성
@@ -1670,7 +1668,6 @@ Finished\ copying=복사 완료
Could\ not\ copy\ file=파일을 복사할 수 없습니다
Rename\ failed=이름 변경 실패
JabRef\ cannot\ access\ the\ file\ because\ it\ is\ being\ used\ by\ another\ process.=JabRef는 다른 프로세스에서 사용 중인 파일에 접근할 수 없습니다
-Show\ console\ output\ (only\ when\ the\ launcher\ is\ used)=콘솔 출력 표시(런처를 사용하는 경우에만)
Remove\ line\ breaks=줄바꿈 제거
Removes\ all\ line\ breaks\ in\ the\ field\ content.=필드 내용에서 모든 줄 바꿈을 제거합니다.
@@ -2149,7 +2146,6 @@ Convert\ timestamp\ field\ to\ field\ 'modificationdate'=타임스탬프 필드
New\ entry\ by\ type=유형별 새 항목
File\ '%1'\ is\ a\ duplicate\ of\ '%0'.\ Keeping\ '%0'=%1 파일은 %0과 동일합니다. %0을 유지합니다.
-File\ '%1'\ is\ a\ duplicate\ of\ '%0'.\ Keeping\ both\ due\ to\ deletion\ error=%1 파일은 %0과 동일합니다. \n삭제 오류로 인해 두 파일을 유지합니다.
Enable\ field\ formatters=필드 포맷터 활성화
Entry\ Type=목록 유형
diff --git a/src/main/resources/l10n/JabRef_nl.properties b/src/main/resources/l10n/JabRef_nl.properties
index 5e56cbf18e2..c9c575a3c56 100644
--- a/src/main/resources/l10n/JabRef_nl.properties
+++ b/src/main/resources/l10n/JabRef_nl.properties
@@ -267,7 +267,6 @@ Donate\ to\ JabRef=Doneer aan JabRef
Download\ file=Download bestand
-Downloaded\ website\ as\ an\ HTML\ file.=Gedownloade website als een HTML-bestand.
duplicate\ removal=duplicaten verwijderen
@@ -348,7 +347,6 @@ Manage\ field\ names\ &\ content=Beheer veldnamen & inhoud
Field\ to\ group\ by=Veld te groeperen op
Filter=Filteren
-Filter\ groups=Filter groepen
Success\!\ Finished\ writing\ metadata.=Gelukt\! Metagegevens schrijven voltooid.
Error\ while\ writing\ metadata.\ See\ the\ error\ log\ for\ details.=Fout tijdens het schrijven van metadata. Bekijk het foutenlogboek voor meer informatie.
@@ -1824,7 +1822,6 @@ Could\ not\ copy\ file=Kan het bestand niet kopiëren
Copied\ %0\ files\ of\ %1\ successfully\ to\ %2=%0 bestanden van %1 succesvol gekopieerd naar %2
Rename\ failed=Hernoemen mislukt
JabRef\ cannot\ access\ the\ file\ because\ it\ is\ being\ used\ by\ another\ process.=JabRef kan geen toegang krijgen tot dit bestand omdat het door een ander proces wordt gebruikt.
-Show\ console\ output\ (only\ when\ the\ launcher\ is\ used)=Toon console-uitvoer (alleen wanneer de launcher wordt gebruikt)
Remove\ line\ breaks=Verwijder regeleinden
Removes\ all\ line\ breaks\ in\ the\ field\ content.=Verwijder alle regeleinden in de veldinhoud.
@@ -2332,7 +2329,6 @@ Convert\ timestamp\ field\ to\ field\ 'modificationdate'=Converteer tijdsstempel
New\ entry\ by\ type=Nieuwe invoer per type
File\ '%1'\ is\ a\ duplicate\ of\ '%0'.\ Keeping\ '%0'=Bestand '%1' is een duplicaat van '%0'. Behoud '%0'
-File\ '%1'\ is\ a\ duplicate\ of\ '%0'.\ Keeping\ both\ due\ to\ deletion\ error=Bestand '%1' is een duplicaat van '%0'. Beide behouden omdat de fout bij het verwijderen is
Enable\ field\ formatters=Veld formatteerder inschakelen
Entry\ Type=Invoer Type
diff --git a/src/main/resources/l10n/JabRef_pl.properties b/src/main/resources/l10n/JabRef_pl.properties
index a83d5f1fcc3..90ccfa12663 100644
--- a/src/main/resources/l10n/JabRef_pl.properties
+++ b/src/main/resources/l10n/JabRef_pl.properties
@@ -69,6 +69,7 @@ Resolve\ BibTeX\ strings=Rozwiąż ciągi znaków BibTeX
The\ label\ of\ the\ string\ cannot\ be\ a\ number.=Etykieta ciągu znaków nie może być liczbą.
The\ label\ of\ the\ string\ cannot\ contain\ spaces.=Etykieta ciągu znaków nie może zawierać spacji.
The\ label\ of\ the\ string\ cannot\ contain\ the\ '\#'\ character.=Etykieta ciągu znaków nie może zawierać znaku '\#'.
+A\ string\ with\ the\ label\ '%0'\ already\ exists.=Ciąg znaków z etykietą '%0' już istnieje.
All\ entries=Wszystkie wpisy
@@ -202,6 +203,7 @@ Custom\ entry\ types\ found\ in\ file=Znaleziono niestandardowe typy wpisów w p
Customize\ entry\ types=Dostosuj typy wpisów
+Customize\ keyboard\ shortcuts=Dostosuj skróty klawiaturowe
Cut=Wytnij
@@ -258,7 +260,6 @@ Donate\ to\ JabRef=Wspomóż JabRef
Download\ file=Pobierz plik
-Downloaded\ website\ as\ an\ HTML\ file.=Pobrano stronę internetową jako plik HTML.
duplicate\ removal=usuwanie duplikatów
@@ -311,6 +312,10 @@ Export\ preferences\ to\ file=Eksportuj ustawienia do pliku
Export\ to\ clipboard=Eksportuj do schowka
Export\ to\ text\ file.=Eksportuj do pliku tekstowego.
+Extract\ references\ from\ file\ (online)=Wyodrębnij referencje z pliku (online)
+Extract\ references\ from\ file\ (offline)=Wyodrębnij referencje z pliku (offline)
+Extract\ References\ (online)=Wyodrębnij referencje (online)
+Extract\ References\ (offline)=Wyodrębnij referencje (offline)
Processing\ PDF(s)=Przetwarzanie PDF(ów)
Processing\ a\ large\ number\ of\ files=Przetwarzanie dużej liczby plików
You\ are\ about\ to\ process\ %0\ files.\ Continue?=Zamierzasz przetworzyć %0 plików. Czy chcesz kontynuować?
@@ -348,7 +353,6 @@ Manage\ field\ names\ &\ content=Zarządzaj nazwami pól i ich zawartością
Field\ to\ group\ by=Pole do grupowania według
Filter=Filtruj
-Filter\ groups=Filtruj grupy
Success\!\ Finished\ writing\ metadata.=Sukces\! Zakończono zapisywanie metadanych.
Error\ while\ writing\ metadata.\ See\ the\ error\ log\ for\ details.=Błąd podczas zapisywania metadanych. Aby uzyskać szczegółowe informacje, zobacz dziennik błędów.
@@ -366,6 +370,7 @@ Generated\ citation\ key\ for=Wygenerowano klucz cytowania dla
Generating\ citation\ key\ for=Generowanie klucza cytowania dla
Invalid\ citation\ key=Nieprawidłowy klucz cytowania
+Jump\ to\ entry\ in\ library=Przejdź do wpisu w bibliotece
Autolink\ files\ with\ names\ starting\ with\ the\ citation\ key=Automatycznie podpinaj pliki z nazwami zaczynającymi się od klucza cytowania
Autolink\ only\ files\ that\ match\ the\ citation\ key=Automatycznie podpinaj tylko pliki, które pasują do klucza cytowania
@@ -435,6 +440,7 @@ Online\ help=Pomoc online
JabRef\ Language\ (Provides\ for\ better\ recommendations\ by\ giving\ an\ indication\ of\ user's\ preferred\ language.)=Język JabRef (zapewnia lepsze rekomendacje poprzez wskazanie preferowanego języka użytkownika).
JabRef\ preferences=Preferencje JabRef
+JabRef\ Version\ (Required\ to\ ensure\ backwards\ compatibility\ with\ Mr.\ DLib's\ Web\ Service)=Wersja JabRef (wymagana do zapewnienia kompatybilności wstecznej z Mr. DLib's Web Service)
Journal\ abbreviations=Skróty czasopism
Journal\ lists\:=Listy czasopism\:
@@ -468,7 +474,9 @@ Keep\ subgroups=Zachowaj podgrupy
Key\ pattern=Układ klawiszy
+Keyboard\ shortcuts=Skróty klawiaturowe
+Keyboard\ shortcuts\ changed=Zmieniono skróty klawiaturowe
keys\ in\ library=klucze w bibliotece
@@ -768,7 +776,10 @@ Empty\ search\ ID=Pusty identyfikator wyszukiwania
The\ given\ search\ ID\ was\ empty.=Podany identyfikator wyszukiwania był pusty.
Clear\ search=Wyczyść wyszukiwanie
Search\ document\ identifier\ online=Szukaj identyfikatora dokumentu online
+Search\ for\ unlinked\ local\ files=Wyszukaj niepowiązane pliki lokalne
+Search\ full\ text\ documents\ online=Wyszukaj pełne teksty dokumentów online
Search\ term\ is\ empty.=Szukane wyrażenie jest puste.
+Invalid\ regular\ expression.=Nieprawidłowe wyrażenie regularne.
Searching\ for\ a\ keyword=Wyszukiwanie słowa kluczowego
Search\ across\ libraries\ in\ a\ new\ window=Szukaj w bibliotekach, wynik pokaż w nowym oknie
@@ -797,6 +808,7 @@ Show\ BibTeX\ source\ by\ default=Domyślnie pokaż źródło BibTeX
Attached\ files=Załączone pliki
Show\ confirmation\ dialog\ when\ deleting\ entries=Pokaż okno dialogowe potwierdzenia podczas usuwania wpisów
+Show\ confirmation\ dialog\ when\ deleting\ attached\ files=Pokaż okno dialogowe potwierdzenia podczas usuwania plików
Persist\ password\ between\ sessions=Zachowaj hasło między sesjami
@@ -1130,9 +1142,11 @@ Parse=Parsuj
Result=Rezultat
You\ have\ to\ choose\ exactly\ two\ entries\ to\ merge.=Musisz wybrać dokładnie dwa wpisy do scalenia.
+All\ keyboard\ shortcuts\ will\ be\ reset\ to\ their\ defaults.=Wszystkie skróty klawiaturowe zostaną zresetowane do wartości domyślnych.
Changed\ %0\ entries.=Zmieniono %0 wpisów.
+Resetting\ all\ keyboard\ shortcuts=Resetowanie wszystkich skrótów klawiaturowych
Open\ folder=Otwórz folder
Export\ sort\ order=Eksportuj kolejność sortowania
@@ -1578,7 +1592,6 @@ files=pliki
No\ citations\ found=Nie znaleziono cytatów
Current\ search\ directory\:=Aktualny katalog wyszukiwania\:
-Refresh=Odśwież
Import\ entries\ from\ LaTeX\ files=Importuj wpisy z plików LaTeX
Import\ new\ entries=Importuj nowe wpisy
@@ -1744,6 +1757,8 @@ Finished\ writing\ metadata\ for\ library\ %0\ (%1\ succeeded,\ %2\ skipped,\ %3
Processing...=Przetwarzanie...
+Miscellaneous=Pozostałe
+File-related=Związane z plikami
Cancel\ search=Anuluj wyszukiwanie
Select\ entry=Wybierz wpis
diff --git a/src/main/resources/l10n/JabRef_pt.properties b/src/main/resources/l10n/JabRef_pt.properties
index 03189da0ac7..6a496f87516 100644
--- a/src/main/resources/l10n/JabRef_pt.properties
+++ b/src/main/resources/l10n/JabRef_pt.properties
@@ -261,7 +261,6 @@ Donate\ to\ JabRef=Doar para JabRef
Download\ file=Download do arquivo
-Downloaded\ website\ as\ an\ HTML\ file.=Site baixado como arquivo HTML.
duplicate\ removal=remoção de duplicatas
@@ -338,7 +337,6 @@ Manage\ field\ names\ &\ content=Gerenciar nomes e conteúdo dos campos
Field\ to\ group\ by=Campos como critério de agrupamento
Filter=Filtro
-Filter\ groups=Filtrar grupos
Success\!\ Finished\ writing\ metadata.=Sucesso\! Escrita de metadados finalizada.
Error\ while\ writing\ metadata.\ See\ the\ error\ log\ for\ details.=Erro ao escrever metadados. Consulte o log de erros para obter detalhes.
diff --git a/src/main/resources/l10n/JabRef_pt_BR.properties b/src/main/resources/l10n/JabRef_pt_BR.properties
index 94fed9e733e..7f7fdc2cfaf 100644
--- a/src/main/resources/l10n/JabRef_pt_BR.properties
+++ b/src/main/resources/l10n/JabRef_pt_BR.properties
@@ -271,7 +271,6 @@ Donate\ to\ JabRef=Doar para JabRef
Download\ file=Download do arquivo
-Downloaded\ website\ as\ an\ HTML\ file.=Site baixado como arquivo HTML.
duplicate\ removal=remoção de duplicatas
@@ -361,7 +360,6 @@ Manage\ field\ names\ &\ content=Gerenciar nomes e conteúdo dos campos
Field\ to\ group\ by=Campos como critério de agrupamento
Filter=Filtro
-Filter\ groups=Filtrar grupos
Success\!\ Finished\ writing\ metadata.=Sucesso\! Terminou a escrita de metadados.
Error\ while\ writing\ metadata.\ See\ the\ error\ log\ for\ details.=Erro ao escrever metadados. Consulte o log de erros para obter detalhes.
@@ -1864,7 +1862,6 @@ Could\ not\ copy\ file=Não foi possível copiar o arquivo
Copied\ %0\ files\ of\ %1\ successfully\ to\ %2=%0 arquivos de %1 copiados com sucesso para %2
Rename\ failed=Falha ao renomear
JabRef\ cannot\ access\ the\ file\ because\ it\ is\ being\ used\ by\ another\ process.=JabRef não pode acessar o arquivo porque ele está sendo usado por outro processo.
-Show\ console\ output\ (only\ when\ the\ launcher\ is\ used)=Mostrar saída do console (somente quando o launcher é usado)
Remove\ line\ breaks=Remover quebras de linha
Removes\ all\ line\ breaks\ in\ the\ field\ content.=Remove todas as quebras de linha do conteúdo do campo.
@@ -2031,7 +2028,6 @@ No\ LaTeX\ files\ containing\ this\ entry\ were\ found.=Nenhum arquivo LaTeX con
Selected\ entry\ does\ not\ have\ an\ associated\ citation\ key.=O item selecionado não tem uma chave de citação associada.
Current\ search\ directory\:=Diretório de pesquisa atual\:
Set\ LaTeX\ file\ directory=Definir diretório de arquivos LaTeX
-Refresh=Atualizar
Import\ entries\ from\ LaTeX\ files=Importar referências a partir dos arquivos LaTeX
Import\ new\ entries=Importar novas referências
Group\ color=Cor do grupo
@@ -2387,7 +2383,6 @@ Convert\ timestamp\ field\ to\ field\ 'modificationdate'=Converter campo timesta
New\ entry\ by\ type=Nova entrada por tipo
File\ '%1'\ is\ a\ duplicate\ of\ '%0'.\ Keeping\ '%0'=Arquivo '%1' é uma duplicata de '%0'. Mantendo '%0'
-File\ '%1'\ is\ a\ duplicate\ of\ '%0'.\ Keeping\ both\ due\ to\ deletion\ error=Arquivo '%1' é uma duplicata de '%0'. Mantendo ambos devido a um erro de exclusão
Enable\ field\ formatters=Ativar formatadores de campo
Entry\ Type=Tipo de referência
diff --git a/src/main/resources/l10n/JabRef_ru.properties b/src/main/resources/l10n/JabRef_ru.properties
index 1b92c78994a..bfbf49c6868 100644
--- a/src/main/resources/l10n/JabRef_ru.properties
+++ b/src/main/resources/l10n/JabRef_ru.properties
@@ -255,7 +255,6 @@ Donate\ to\ JabRef=Поддержать JabRef
Download\ file=Загрузить файл
-Downloaded\ website\ as\ an\ HTML\ file.=Загружен сайт в формате HTML.
duplicate\ removal=удаление дубликатов
@@ -334,7 +333,6 @@ Manage\ field\ names\ &\ content=Управлять названиями пол
Field\ to\ group\ by=Поле для группировки
Filter=Фильтр
-Filter\ groups=Фильтровать группы
Success\!\ Finished\ writing\ metadata.=Успех\! Запись метаданных завершена.
Error\ while\ writing\ metadata.\ See\ the\ error\ log\ for\ details.=Ошибка при записи метаданных. Смотрите журнал ошибок для подробностей.
@@ -442,6 +440,10 @@ Journal\ abbreviations=Сокращения для журналов
Journal\ lists\:=Список журналов\:
Remove\ journal\ '%0'=Удалить журнал '%0'
+Year=Год
+Categories=Категории
+ISSN=ISSN
+Publisher=Издатель
Keep\ both=Оставить оба
@@ -1729,7 +1731,6 @@ Finished\ copying=Копирование завершено
Could\ not\ copy\ file=Невозможно скопировать файл
Rename\ failed=Не удалось переименовать
JabRef\ cannot\ access\ the\ file\ because\ it\ is\ being\ used\ by\ another\ process.=JabRef не может получить доступ к файлу, так как он используется другим процессом.
-Show\ console\ output\ (only\ when\ the\ launcher\ is\ used)=Показывать вывод консоли (только при использовании лаунчера)
Remove\ line\ breaks=Удалить разрывы строк
Removes\ all\ line\ breaks\ in\ the\ field\ content.=Удаляет все разрывы строк в содержимом поля.
@@ -2226,7 +2227,6 @@ Convert\ timestamp\ field\ to\ field\ 'modificationdate'=Преобразова
New\ entry\ by\ type=Новая запись по типу
File\ '%1'\ is\ a\ duplicate\ of\ '%0'.\ Keeping\ '%0'=Файл '%1' является дубликатом '%0'. Оставлен '%0'
-File\ '%1'\ is\ a\ duplicate\ of\ '%0'.\ Keeping\ both\ due\ to\ deletion\ error=Файл '%1' является дубликатом '%0'. Оставлены оба из-за ошибки удаления
Enable\ field\ formatters=Включить форматирование полей
Entry\ Type=Тип записи
diff --git a/src/main/resources/l10n/JabRef_sv.properties b/src/main/resources/l10n/JabRef_sv.properties
index 569743a1f1c..e4ba746185c 100644
--- a/src/main/resources/l10n/JabRef_sv.properties
+++ b/src/main/resources/l10n/JabRef_sv.properties
@@ -249,7 +249,6 @@ Donate\ to\ JabRef=Donera till JabRef
Download\ file=Ladda ned fil
-Downloaded\ website\ as\ an\ HTML\ file.=Webbsida nedladdad som html-fil.
duplicate\ removal=ta bort dubbletter
@@ -328,7 +327,6 @@ Manage\ field\ names\ &\ content=Hantera fältnamn & innehåll
Field\ to\ group\ by=Fält att använda för gruppering
Filter=Filtrera
-Filter\ groups=Filtrera grupper
Generate=Generera
diff --git a/src/main/resources/l10n/JabRef_tr.properties b/src/main/resources/l10n/JabRef_tr.properties
index abb65c2f6ae..bfac7f74ea2 100644
--- a/src/main/resources/l10n/JabRef_tr.properties
+++ b/src/main/resources/l10n/JabRef_tr.properties
@@ -269,7 +269,6 @@ Donate\ to\ JabRef=JabRef'e bağış yap
Download\ file=Dosya indir
-Downloaded\ website\ as\ an\ HTML\ file.=Web sitesi bir HTML dosyası olarak indirildi.
duplicate\ removal=çift nüsha silme
@@ -356,7 +355,6 @@ Manage\ field\ names\ &\ content=Alan ad ve içeriklerini yönet
Field\ to\ group\ by=Gruplanacak alan
Filter=Süzgeç
-Filter\ groups=Grupları filtrele
Success\!\ Finished\ writing\ metadata.=Başarılı\! Metaverisi yazma bitirildi.
Error\ while\ writing\ metadata.\ See\ the\ error\ log\ for\ details.=Metaverisi yazılırken hata. Ayrıntılar için hata kayıtlarına bakın.
@@ -1843,7 +1841,6 @@ Could\ not\ copy\ file=Dosya kopyalanamadı
Copied\ %0\ files\ of\ %1\ successfully\ to\ %2=%1 dosyanın %0'i başarıyla %2'e kopyalandı
Rename\ failed=Yeniden adlandırma başarısız oldu
JabRef\ cannot\ access\ the\ file\ because\ it\ is\ being\ used\ by\ another\ process.=JabRef dosyaya erişemiyor çünkü dosya başka bir süreç tarafından kullanılıyor.
-Show\ console\ output\ (only\ when\ the\ launcher\ is\ used)=Konsol çıktısını göster (yalnızca başlatıcı kullanıldığında)
Remove\ line\ breaks=Satır sonlarını kaldır
Removes\ all\ line\ breaks\ in\ the\ field\ content.=Alan içeriğindeki tüm satır sonlarını kaldırır.
@@ -2363,7 +2360,6 @@ Convert\ timestamp\ field\ to\ field\ 'modificationdate'=Tarih bilgisi alanını
New\ entry\ by\ type=Türle yeni girdi
File\ '%1'\ is\ a\ duplicate\ of\ '%0'.\ Keeping\ '%0'='%1' dosyası '%0'ın tıpkısı. '%0' tutuluyor
-File\ '%1'\ is\ a\ duplicate\ of\ '%0'.\ Keeping\ both\ due\ to\ deletion\ error='%1' dosyası '%0'ın tıpkısı. Silme hatası nedeniyle ikisi de tutuluyor
Enable\ field\ formatters=Alan biçimlendiricilerini etkinleştir
Entry\ Type=Girdi Türü
diff --git a/src/main/resources/l10n/JabRef_uk.properties b/src/main/resources/l10n/JabRef_uk.properties
index 5ccd342ef5d..b39e7976f6b 100644
--- a/src/main/resources/l10n/JabRef_uk.properties
+++ b/src/main/resources/l10n/JabRef_uk.properties
@@ -60,6 +60,7 @@ Added\ group\ "%0".=Додана група
Added\ string\:\ '%0'=Додано рядок
Added\ string=Додано рядок
+Must\ not\ be\ empty\!=Не може бути порожнім\!
All\ entries=Всі записи
@@ -90,12 +91,20 @@ Application\ to\ push\ entries\ to=Заявка на push матеріалів
+Cancel=Скасувати
+Cannot\ create\ group=Не вдається створити групу
+Cannot\ create\ group.\ Please\ create\ a\ library\ first.=Не вдається створити групу. Будь ласка, спочатку створіть бібліотеку.
+Cannot\ open\ folder\ as\ the\ file\ is\ an\ online\ link.=Не вдається відкрити папку, оскільки файл є посиланням.
+case\ insensitive=без урахування регістру
+case\ sensitive=з урахуванням регістру
+Case\ sensitive=З урахуванням регістру
+change\ assignment\ of\ entries=змінити призначення записів
@@ -107,24 +116,51 @@ Application\ to\ push\ entries\ to=Заявка на push матеріалів
+Open\ /\ close\ entry\ editor=Відкрити / закрити редактор записів
+Close\ dialog=Закрити діалог
+Close\ the\ current\ library=Закрити поточну бібліотеку
+Close\ window=Закрити вікно
+Comments=Коментарі
+Contained\ in=Міститься в
+Content=Зміст
+Copy=Копіювати
+Copy\ title=Копіювати заголовок
+Copy\ citation\ (html)=Копіювати цитування (html)
+Copy\ citation\ (text)=Копіювати цитування (текст)
+Copy\ citation\ key=Копіювати ключ цитування
+Copy\ citation\ key\ and\ link=Копіювати ключ цитування та посилання
+Copy\ citation\ key\ and\ title=Копіювати ключ цитування та заголовок
+Copy\ citation\ key\ with\ configured\ cite\ command=Копіювати ключ цитування з налаштованою командою цитування
+Copy\ to\ clipboard=Копіювати в буфер обміну
+Could\ not\ call\ executable=Не вдалося викликати виконавчий файл
+Could\ not\ export\ preferences=Не вдалося експортувати налаштування
+Could\ not\ find\ a\ suitable\ import\ format.=Не вдалося знайти відповідний формат імпорту.
+Could\ not\ import\ preferences=Не вдалося імпортувати налаштування
+Could\ not\ instantiate\ %0=Не вдалося створити %0
+Could\ not\ instantiate\ %0\ %1=Не вдалося створити %0 %1
+Could\ not\ instantiate\ %0.\ Have\ you\ chosen\ the\ correct\ package\ path?=Не вдалося створити %0. Ви обрали правильний шлях до пакету?
+Could\ not\ print\ preview=Не вдалося надрукувати попередній перегляд
+Create\ custom\ fields\ for\ each\ BibTeX\ entry=Створити власні поля для кожного запису BibTeX
+Current\ content\:\ %0=Поточний вміст\: %0
+Current\ value\:\ %0=Поточне значення\: %0
diff --git a/src/main/resources/l10n/JabRef_vi.properties b/src/main/resources/l10n/JabRef_vi.properties
index 49979058375..7187fdcf00f 100644
--- a/src/main/resources/l10n/JabRef_vi.properties
+++ b/src/main/resources/l10n/JabRef_vi.properties
@@ -284,7 +284,6 @@ Field\ name=Tên dữ liệu
Field\ to\ group\ by=Dữ liệu gộp nhóm theo
Filter=Lọc
-Filter\ groups=Nhóm bộ lọc
Generate=Tạo
diff --git a/src/main/resources/l10n/JabRef_zh_CN.properties b/src/main/resources/l10n/JabRef_zh_CN.properties
index 6bd3ae6c20f..f2276cf4d21 100644
--- a/src/main/resources/l10n/JabRef_zh_CN.properties
+++ b/src/main/resources/l10n/JabRef_zh_CN.properties
@@ -267,7 +267,6 @@ Donate\ to\ JabRef=Donate
Download\ file=下载文件
-Downloaded\ website\ as\ an\ HTML\ file.=将网站下载为HTML文件。
duplicate\ removal=移除重复
@@ -348,7 +347,6 @@ Manage\ field\ names\ &\ content=管理字段名称和内容
Field\ to\ group\ by=用来分组的字段
Filter=筛选
-Filter\ groups=筛选组
Success\!\ Finished\ writing\ metadata.=Success\! Finished writing metadata.
Error\ while\ writing\ metadata.\ See\ the\ error\ log\ for\ details.=写入元数据时出错。详细信息请参阅错误日志。
@@ -1812,7 +1810,6 @@ Could\ not\ copy\ file=无法复制文件
Copied\ %0\ files\ of\ %1\ successfully\ to\ %2=Copied %0 files of %1 successfully to %2
Rename\ failed=重命名失败
JabRef\ cannot\ access\ the\ file\ because\ it\ is\ being\ used\ by\ another\ process.=JabRef 无法访问该文件, 因为另一个进程正在使用它。
-Show\ console\ output\ (only\ when\ the\ launcher\ is\ used)=Show console output (only when the launcher is used)
Remove\ line\ breaks=移除换行符
Removes\ all\ line\ breaks\ in\ the\ field\ content.=移除字段内容中的所有换行符。
@@ -2320,7 +2317,6 @@ Convert\ timestamp\ field\ to\ field\ 'modificationdate'=将 timestamp 字段转
New\ entry\ by\ type=按类型创建新条目
File\ '%1'\ is\ a\ duplicate\ of\ '%0'.\ Keeping\ '%0'=文件%1是%0的重复。保留%0
-File\ '%1'\ is\ a\ duplicate\ of\ '%0'.\ Keeping\ both\ due\ to\ deletion\ error=文件%1是%0的重复。由于删除错误同时保留两者。
Enable\ field\ formatters=启用字段格式化器
Entry\ Type=条目类型
diff --git a/src/main/resources/l10n/JabRef_zh_TW.properties b/src/main/resources/l10n/JabRef_zh_TW.properties
index e75a7a1d852..050baf57ba6 100644
--- a/src/main/resources/l10n/JabRef_zh_TW.properties
+++ b/src/main/resources/l10n/JabRef_zh_TW.properties
@@ -280,7 +280,6 @@ Field\ names\ are\ not\ allowed\ to\ contain\ white\ spaces\ or\ certain\ charac
Filter=篩選
-Filter\ groups=篩選群組
Generate=生成
diff --git a/src/test/java/org/jabref/cli/JabRefCLITest.java b/src/test/java/org/jabref/cli/JabRefCLITest.java
index dfcd8478cd7..8fcbbd01013 100644
--- a/src/test/java/org/jabref/cli/JabRefCLITest.java
+++ b/src/test/java/org/jabref/cli/JabRefCLITest.java
@@ -133,19 +133,6 @@ void successfulParsingOfBibtexImportLong() throws Exception {
assertEquals(bibtex, cli.getBibtexImport());
}
- @Test
- void wrapStringList() {
- List given = List.of("html", "simplehtml", "docbook5", "docbook4", "din1505", "bibordf", "tablerefs", "listrefs",
- "tablerefsabsbib", "harvard", "iso690rtf", "iso690txt", "endnote", "oocsv", "ris", "misq", "yaml", "bibtexml", "oocalc", "ods",
- "MSBib", "mods", "xmp", "pdf", "bib");
- String expected = """
- Available export formats: html, simplehtml, docbook5, docbook4, din1505, bibordf, tablerefs,
- listrefs, tablerefsabsbib, harvard, iso690rtf, iso690txt, endnote, oocsv, ris, misq, yaml, bibtexml,
- oocalc, ods, MSBib, mods, xmp, pdf, bib""";
-
- assertEquals(expected, "Available export formats: " + JabRefCLI.wrapStringList(given, 26));
- }
-
@Test
void alignStringTable() {
List> given = List.of(
diff --git a/src/test/java/org/jabref/gui/fieldeditors/LinkedFileViewModelTest.java b/src/test/java/org/jabref/gui/fieldeditors/LinkedFileViewModelTest.java
index 78b765ec3f6..18efb37fd94 100644
--- a/src/test/java/org/jabref/gui/fieldeditors/LinkedFileViewModelTest.java
+++ b/src/test/java/org/jabref/gui/fieldeditors/LinkedFileViewModelTest.java
@@ -29,7 +29,6 @@
import org.jabref.model.entry.LinkedFile;
import org.jabref.preferences.FilePreferences;
import org.jabref.preferences.PreferencesService;
-import org.jabref.testutils.category.FetcherTest;
import org.jabref.testutils.category.GUITest;
import org.junit.jupiter.api.AfterEach;
@@ -37,6 +36,9 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.io.TempDir;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+import org.junit.jupiter.params.provider.ValueSource;
import org.testfx.framework.junit5.ApplicationExtension;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -181,8 +183,12 @@ void deleteWhenDialogCancelledReturnsFalseAndDoesNotRemoveFile() {
assertTrue(Files.exists(tempFile));
}
- @Test
- void downloadHtmlFileCausesWarningDisplay() throws MalformedURLException {
+ @ParameterizedTest
+ @CsvSource({
+ "true, Download 'https://www.google.com/' was a HTML file. Keeping URL.",
+ "false, Download 'https://www.google.com/' was a HTML file. Removed."
+ })
+ void downloadHtmlFileCausesWarningDisplay(Boolean keepHtmlLink, String warningText) throws MalformedURLException {
when(filePreferences.shouldStoreFilesRelativeToBibFile()).thenReturn(true);
when(filePreferences.getFileNamePattern()).thenReturn("[citationkey]");
when(filePreferences.getFileDirectoryPattern()).thenReturn("[entrytype]");
@@ -194,39 +200,9 @@ void downloadHtmlFileCausesWarningDisplay() throws MalformedURLException {
LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, new CurrentThreadTaskExecutor(), dialogService, preferences);
- viewModel.download();
+ viewModel.download(keepHtmlLink);
- verify(dialogService, atLeastOnce()).notify("Downloaded website as an HTML file.");
- }
-
- @FetcherTest
- @Test
- void downloadHtmlWhenLinkedFilePointsToHtml() throws MalformedURLException {
- // use google as test url, wiley is protected by CloudFlare
- String url = "https://google.com";
- String fileType = StandardExternalFileType.URL.getName();
- linkedFile = new LinkedFile(new URL(url), fileType);
-
- when(filePreferences.shouldStoreFilesRelativeToBibFile()).thenReturn(true);
- when(filePreferences.getFileNamePattern()).thenReturn("[citationkey]");
- when(filePreferences.getFileDirectoryPattern()).thenReturn("[entrytype]");
-
- databaseContext.setDatabasePath(tempFile);
-
- LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, new CurrentThreadTaskExecutor(), dialogService, preferences);
-
- viewModel.download();
-
- List linkedFiles = entry.getFiles();
-
- for (LinkedFile file: linkedFiles) {
- if ("Misc/asdf.html".equalsIgnoreCase(file.getLink())) {
- assertEquals("URL", file.getFileType());
- return;
- }
- }
- // If the file was not found among the linked files to the entry
- fail();
+ verify(dialogService, atLeastOnce()).notify(warningText);
}
@Test
@@ -290,9 +266,11 @@ void mimeTypeStringWithParameterIsReturnedAsWithoutParameter() {
assertEquals("URL", actual);
}
- @Test
- @FetcherTest
- void downloadPdfFileWhenLinkedFilePointsToPdfUrl() throws MalformedURLException {
+ // We cannot use "@FetcherTest" annotation, because a @FetcherTest does not fire up a GUI environment (which is needed for this test)
+ // @FetcherTest
+ @ParameterizedTest
+ @ValueSource(booleans = {true, false})
+ void downloadPdfFileWhenLinkedFilePointsToPdfUrl(boolean keepHtml) throws MalformedURLException {
linkedFile = new LinkedFile(new URL("http://arxiv.org/pdf/1207.0408v1"), "pdf");
// Needed Mockito stubbing methods to run test
when(filePreferences.shouldStoreFilesRelativeToBibFile()).thenReturn(true);
@@ -302,7 +280,9 @@ void downloadPdfFileWhenLinkedFilePointsToPdfUrl() throws MalformedURLException
databaseContext.setDatabasePath(tempFile);
LinkedFileViewModel viewModel = new LinkedFileViewModel(linkedFile, entry, databaseContext, new CurrentThreadTaskExecutor(), dialogService, preferences);
- viewModel.download();
+
+ // TODO: Rewrite using WireMock
+ viewModel.download(keepHtml);
// Loop through downloaded files to check for filetype='pdf'
List linkedFiles = entry.getFiles();
diff --git a/src/test/java/org/jabref/gui/groups/GroupTreeViewModelTest.java b/src/test/java/org/jabref/gui/groups/GroupTreeViewModelTest.java
index 5f7f2369134..bdb27ee2fc1 100644
--- a/src/test/java/org/jabref/gui/groups/GroupTreeViewModelTest.java
+++ b/src/test/java/org/jabref/gui/groups/GroupTreeViewModelTest.java
@@ -61,7 +61,7 @@ void rootGroupIsAllEntriesByDefault() {
@Test
void rootGroupIsSelectedByDefault() {
- assertEquals(groupTree.rootGroupProperty().get().getGroupNode(), stateManager.getSelectedGroup(databaseContext).getFirst());
+ assertEquals(groupTree.rootGroupProperty().get().getGroupNode(), stateManager.getSelectedGroups(databaseContext).getFirst());
}
@Test
diff --git a/src/test/java/org/jabref/gui/linkedfile/DownloadLinkedFileActionTest.java b/src/test/java/org/jabref/gui/linkedfile/DownloadLinkedFileActionTest.java
index 80791f86bba..067b21f0cc2 100644
--- a/src/test/java/org/jabref/gui/linkedfile/DownloadLinkedFileActionTest.java
+++ b/src/test/java/org/jabref/gui/linkedfile/DownloadLinkedFileActionTest.java
@@ -26,6 +26,8 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
@@ -33,6 +35,11 @@
import static org.mockito.Mockito.when;
class DownloadLinkedFileActionTest {
+
+ // Required for keepsHtmlEntry
+ @TempDir
+ Path tempFolder;
+
private BibEntry entry;
private final BibDatabaseContext databaseContext = mock(BibDatabaseContext.class);
@@ -84,8 +91,9 @@ void replacesLinkedFiles(@TempDir Path tempFolder) throws Exception {
assertEquals(List.of(new LinkedFile("", tempFolder.resolve("asdf.pdf"), "PDF", url)), entry.getFiles());
}
- @Test
- void doesntReplaceSourceURL(@TempDir Path tempFolder) throws Exception {
+ @ParameterizedTest
+ @ValueSource(booleans = {true, false})
+ void doesntReplaceSourceURL(boolean keepHtml) throws Exception {
String url = "http://arxiv.org/pdf/1207.0408v1";
LinkedFile linkedFile = new LinkedFile(new URL(url), "");
@@ -120,9 +128,62 @@ void doesntReplaceSourceURL(@TempDir Path tempFolder) throws Exception {
dialogService,
preferences.getFilePreferences(),
new CurrentThreadTaskExecutor(),
- Path.of(linkedFile.getLink()).getFileName().toString());
+ Path.of(linkedFile.getLink()).getFileName().toString(),
+ keepHtml);
downloadLinkedFileAction2.execute();
assertEquals(List.of(new LinkedFile("", tempFolder.resolve("asdf.pdf"), "PDF", url)), entry.getFiles());
}
+
+ @Test
+ void keepsHtmlEntry(@TempDir Path tempFolder) throws Exception {
+ String url = "https://blog.fefe.de/?ts=98e04151";
+
+ LinkedFile linkedFile = new LinkedFile(new URL(url), "");
+ when(databaseContext.getFirstExistingFileDir(any())).thenReturn(Optional.of(tempFolder));
+ when(filePreferences.getFileNamePattern()).thenReturn("[citationkey]");
+ when(filePreferences.getFileDirectoryPattern()).thenReturn("");
+
+ entry.setFiles(List.of(linkedFile));
+
+ BibEntry expected = (BibEntry) entry.clone();
+
+ DownloadLinkedFileAction downloadLinkedFileAction = new DownloadLinkedFileAction(
+ databaseContext,
+ entry,
+ linkedFile,
+ linkedFile.getLink(),
+ dialogService,
+ preferences.getFilePreferences(),
+ new CurrentThreadTaskExecutor());
+ downloadLinkedFileAction.execute();
+
+ assertEquals(expected, entry);
+ }
+
+ @Test
+ void removesHtmlEntry(@TempDir Path tempFolder) throws Exception {
+ String url = "https://blog.fefe.de/?ts=98e04151";
+
+ LinkedFile linkedFile = new LinkedFile(new URL(url), "");
+ when(databaseContext.getFirstExistingFileDir(any())).thenReturn(Optional.of(tempFolder));
+ when(filePreferences.getFileNamePattern()).thenReturn("[citationkey]");
+ when(filePreferences.getFileDirectoryPattern()).thenReturn("");
+
+ entry.setFiles(List.of(linkedFile));
+
+ DownloadLinkedFileAction downloadLinkedFileAction = new DownloadLinkedFileAction(
+ databaseContext,
+ entry,
+ linkedFile,
+ linkedFile.getLink(),
+ dialogService,
+ preferences.getFilePreferences(),
+ new CurrentThreadTaskExecutor(),
+ "",
+ false);
+ downloadLinkedFileAction.execute();
+
+ assertEquals(new BibEntry().withCitationKey("asdf"), entry);
+ }
}
diff --git a/src/test/java/org/jabref/logic/formatter/bibtexfields/RemoveBracesFormatterTest.java b/src/test/java/org/jabref/logic/formatter/bibtexfields/RemoveEnclosingBracesFormatterTest.java
similarity index 90%
rename from src/test/java/org/jabref/logic/formatter/bibtexfields/RemoveBracesFormatterTest.java
rename to src/test/java/org/jabref/logic/formatter/bibtexfields/RemoveEnclosingBracesFormatterTest.java
index 37eff160e67..45f6e87373d 100644
--- a/src/test/java/org/jabref/logic/formatter/bibtexfields/RemoveBracesFormatterTest.java
+++ b/src/test/java/org/jabref/logic/formatter/bibtexfields/RemoveEnclosingBracesFormatterTest.java
@@ -9,9 +9,9 @@
/**
* Tests in addition to the general tests from {@link org.jabref.logic.formatter.FormatterTest}
*/
-public class RemoveBracesFormatterTest {
+public class RemoveEnclosingBracesFormatterTest {
- private final RemoveBracesFormatter formatter = new RemoveBracesFormatter();
+ private final RemoveEnclosingBracesFormatter formatter = new RemoveEnclosingBracesFormatter();
@ParameterizedTest
@CsvSource({
diff --git a/src/test/java/org/jabref/logic/formatter/bibtexfields/RemoveWordEnclosingAndOuterEnclosingBracesFormatterTest.java b/src/test/java/org/jabref/logic/formatter/bibtexfields/RemoveWordEnclosingAndOuterEnclosingBracesFormatterTest.java
new file mode 100644
index 00000000000..036268c7929
--- /dev/null
+++ b/src/test/java/org/jabref/logic/formatter/bibtexfields/RemoveWordEnclosingAndOuterEnclosingBracesFormatterTest.java
@@ -0,0 +1,31 @@
+package org.jabref.logic.formatter.bibtexfields;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class RemoveWordEnclosingAndOuterEnclosingBracesFormatterTest {
+ private final RemoveWordEnclosingAndOuterEnclosingBracesFormatter formatter = new RemoveWordEnclosingAndOuterEnclosingBracesFormatter();
+
+ @ParameterizedTest
+ @CsvSource({
+ "A test B, {A} test {B}",
+ "A and B, {{A} and {B}}",
+ "{w}ord word wor{d}, {w}ord word wor{d}",
+ "{w}ord word word, {{w}ord word word}",
+ "{w}ord word wor{d}, {w}ord word {wor{d}}",
+ "Vall{\\'e}e Poussin, {Vall{\\'e}e} {Poussin}",
+ "Vall{\\'e}e Poussin, {Vall{\\'e}e Poussin}",
+ "Vall{\\'e}e Poussin, Vall{\\'e}e Poussin"
+ })
+ public void format(String expected, String input) {
+ assertEquals(expected, formatter.format(input));
+ }
+
+ @Test
+ public void formatExample() {
+ assertEquals("In CDMA", formatter.format(formatter.getExampleInput()));
+ }
+}
diff --git a/src/test/java/org/jabref/logic/importer/fetcher/BiodiversityLibraryTest.java b/src/test/java/org/jabref/logic/importer/fetcher/BiodiversityLibraryTest.java
index b5d4fb4f584..b4cf58532f9 100644
--- a/src/test/java/org/jabref/logic/importer/fetcher/BiodiversityLibraryTest.java
+++ b/src/test/java/org/jabref/logic/importer/fetcher/BiodiversityLibraryTest.java
@@ -100,7 +100,7 @@ public void performSearch() throws FetcherException {
.withField(StandardField.URL, "https://www.biodiversitylibrary.org/part/356490")
.withField(StandardField.DATE, "2023")
.withField(StandardField.VOLUME, "227")
- .withField(StandardField.PAGES, "89-97")
+ .withField(StandardField.PAGES, "89--97")
.withField(StandardField.DOI, "10.3897/phytokeys.227.104703");
assertEquals(expected, fetcher.performSearch("Amanoa condorensis (Phyllanthaceae)").getFirst());
diff --git a/src/test/java/org/jabref/logic/importer/fetcher/CiteSeerTest.java b/src/test/java/org/jabref/logic/importer/fetcher/CiteSeerTest.java
index 647c18d789d..8b5b4f125cd 100644
--- a/src/test/java/org/jabref/logic/importer/fetcher/CiteSeerTest.java
+++ b/src/test/java/org/jabref/logic/importer/fetcher/CiteSeerTest.java
@@ -13,18 +13,25 @@
import org.jabref.model.entry.types.StandardEntryType;
import org.jabref.testutils.category.FetcherTest;
+import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assumptions.assumeFalse;
@FetcherTest
class CiteSeerTest {
private CiteSeer fetcher = new CiteSeer();
+ @BeforeAll
+ static void ensureCiteSeerIsAvailable() throws Exception {
+ assumeFalse(List.of().equals(new CiteSeer().performSearch("title:\"Rigorous Derivation from Landau-de Gennes Theory to Ericksen-leslie Theory\" AND pageSize:1")));
+ }
+
@Test
void searchByQueryFindsEntryRigorousDerivation() throws Exception {
String title = "RIGOROUS DERIVATION FROM LANDAU-DE GENNES THEORY TO ERICKSEN-LESLIE THEORY";
diff --git a/src/test/java/org/jabref/logic/importer/fetcher/CrossRefTest.java b/src/test/java/org/jabref/logic/importer/fetcher/CrossRefTest.java
index 287b65e857d..d67744df55d 100644
--- a/src/test/java/org/jabref/logic/importer/fetcher/CrossRefTest.java
+++ b/src/test/java/org/jabref/logic/importer/fetcher/CrossRefTest.java
@@ -132,7 +132,6 @@ public void performSearchByIdFindsPaperWithoutTitle() throws Exception {
entry.setField(StandardField.JOURNAL, "Indo-Iranian Journal");
entry.setField(StandardField.NUMBER, "2");
entry.setField(StandardField.PUBLISHER, "Brill");
- entry.setField(StandardField.KEYWORDS, "Political Science and International Relations, Linguistics and Language, Philosophy");
assertEquals(Optional.of(entry), fetcher.performSearchById("10.1023/a:1003473214310"));
}
diff --git a/src/test/java/org/jabref/logic/importer/fetcher/IEEETest.java b/src/test/java/org/jabref/logic/importer/fetcher/IEEETest.java
index 965fde89a1a..eeffcf5aa98 100644
--- a/src/test/java/org/jabref/logic/importer/fetcher/IEEETest.java
+++ b/src/test/java/org/jabref/logic/importer/fetcher/IEEETest.java
@@ -16,18 +16,25 @@
import org.jabref.model.entry.types.StandardEntryType;
import org.jabref.testutils.category.FetcherTest;
+import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.mockito.Answers;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assumptions.assumeFalse;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@FetcherTest
class IEEETest implements SearchBasedFetcherCapabilityTest, PagedSearchFetcherTest {
- private final BibEntry IGOR_NEWCOMERS = new BibEntry(StandardEntryType.InProceedings)
+ private static ImportFormatPreferences importFormatPreferences;
+
+ private static ImporterPreferences importerPreferences;
+
+ private static final BibEntry IGOR_NEWCOMERS = new BibEntry(StandardEntryType.InProceedings)
.withField(StandardField.AUTHOR, "Igor Steinmacher and Tayana Uchoa Conte and Christoph Treude and Marco Aurélio Gerosa")
.withField(StandardField.DATE, "14-22 May 2016")
.withField(StandardField.YEAR, "2016")
@@ -45,65 +52,76 @@ class IEEETest implements SearchBasedFetcherCapabilityTest, PagedSearchFetcherTe
.withField(StandardField.FILE, ":https\\://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=7886910:PDF");
private IEEE fetcher;
- private BibEntry entry;
- @BeforeEach
- void setUp() {
- ImportFormatPreferences importFormatPreferences = mock(ImportFormatPreferences.class, Answers.RETURNS_DEEP_STUBS);
+ @BeforeAll
+ static void ensureIeeeIsAvailable() throws Exception {
+ importFormatPreferences = mock(ImportFormatPreferences.class, Answers.RETURNS_DEEP_STUBS);
when(importFormatPreferences.bibEntryPreferences().getKeywordSeparator()).thenReturn(',');
- ImporterPreferences importerPreferences = mock(ImporterPreferences.class);
+ importerPreferences = mock(ImporterPreferences.class);
when(importerPreferences.getApiKeys()).thenReturn(FXCollections.emptyObservableSet());
+ IEEE ieee = new IEEE(importFormatPreferences, importerPreferences);
+
+ assumeFalse(List.of().equals(ieee.performSearch("article_number:8801912")));
+ }
+
+ @BeforeEach
+ void setUp() {
fetcher = new IEEE(importFormatPreferences, importerPreferences);
- entry = new BibEntry();
}
@Test
+ @Disabled("IEEE seems to block us")
void findByDOI() throws Exception {
- entry.setField(StandardField.DOI, "10.1109/ACCESS.2016.2535486");
+ BibEntry entry = new BibEntry().withField(StandardField.DOI, "10.1109/ACCESS.2016.2535486");
assertEquals(Optional.of(new URL("https://ieeexplore.ieee.org/ielx7/6287639/7419931/07421926.pdf?tp=&arnumber=7421926&isnumber=7419931&ref=")),
fetcher.findFullText(entry));
}
@Test
+ @Disabled("IEEE seems to block us")
void findByDocumentUrl() throws Exception {
- entry.setField(StandardField.URL, "https://ieeexplore.ieee.org/document/7421926/");
+ BibEntry entry = new BibEntry().withField(StandardField.URL, "https://ieeexplore.ieee.org/document/7421926/");
assertEquals(Optional.of(new URL("https://ieeexplore.ieee.org/ielx7/6287639/7419931/07421926.pdf?tp=&arnumber=7421926&isnumber=7419931&ref=")),
fetcher.findFullText(entry));
}
@Test
+ @Disabled("IEEE seems to block us")
void findByURL() throws Exception {
- entry.setField(StandardField.URL, "https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=7421926&ref=");
+ BibEntry entry = new BibEntry().withField(StandardField.URL, "https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=7421926&ref=");
assertEquals(Optional.of(new URL("https://ieeexplore.ieee.org/ielx7/6287639/7419931/07421926.pdf?tp=&arnumber=7421926&isnumber=7419931&ref=")),
fetcher.findFullText(entry));
}
@Test
+ @Disabled("IEEE blocks us - works in browser")
void findByOldURL() throws Exception {
- entry.setField(StandardField.URL, "https://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=7421926");
+ BibEntry entry = new BibEntry().withField(StandardField.URL, "https://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=7421926");
assertEquals(Optional.of(new URL("https://ieeexplore.ieee.org/ielx7/6287639/7419931/07421926.pdf?tp=&arnumber=7421926&isnumber=7419931&ref=")),
fetcher.findFullText(entry));
}
@Test
+ @Disabled("IEEE seems to block us")
void findByDOIButNotURL() throws Exception {
- entry.setField(StandardField.DOI, "10.1109/ACCESS.2016.2535486");
- entry.setField(StandardField.URL, "http://dx.doi.org/10.1109/ACCESS.2016.2535486");
+ BibEntry entry = new BibEntry()
+ .withField(StandardField.DOI, "10.1109/ACCESS.2016.2535486")
+ .withField(StandardField.URL, "http://dx.doi.org/10.1109/ACCESS.2016.2535486");
assertEquals(Optional.of(new URL("https://ieeexplore.ieee.org/ielx7/6287639/7419931/07421926.pdf?tp=&arnumber=7421926&isnumber=7419931&ref=")),
fetcher.findFullText(entry));
}
@Test
void notFoundByURL() throws Exception {
- entry.setField(StandardField.URL, "http://dx.doi.org/10.1109/ACCESS.2016.2535486");
+ BibEntry entry = new BibEntry().withField(StandardField.URL, "http://dx.doi.org/10.1109/ACCESS.2016.2535486");
assertEquals(Optional.empty(), fetcher.findFullText(entry));
}
@Test
void notFoundByDOI() throws Exception {
- entry.setField(StandardField.DOI, "10.1021/bk-2006-WWW.ch014");
+ BibEntry entry = new BibEntry().withField(StandardField.DOI, "10.1021/bk-2006-WWW.ch014");
assertEquals(Optional.empty(), fetcher.findFullText(entry));
}
@@ -124,8 +142,9 @@ void searchResultHasNoKeywordTerms() throws Exception {
.withField(StandardField.VOLUME, "16")
.withField(StandardField.KEYWORDS, "Batteries, Generators, Economics, Power quality, State of charge, Harmonic analysis, Control systems, Battery, diesel generator (DG), distributed generation, power quality, photovoltaic (PV), voltage source converter (VSC)");
- List fetchedEntries = fetcher.performSearch("article_number:8801912"); // article number
- fetchedEntries.forEach(entry -> entry.clearField(StandardField.ABSTRACT)); // Remove abstract due to copyright);
+ List fetchedEntries = fetcher.performSearch("article_number:8801912");
+ // Abstract should not be included in JabRef tests (copyrighted)
+ fetchedEntries.forEach(entry -> entry.clearField(StandardField.ABSTRACT));
assertEquals(Collections.singletonList(expected), fetchedEntries);
}
diff --git a/src/test/java/org/jabref/logic/importer/fetcher/ISIDOREFetcherTest.java b/src/test/java/org/jabref/logic/importer/fetcher/ISIDOREFetcherTest.java
index 1b24ea179c9..6fd5239ce0c 100644
--- a/src/test/java/org/jabref/logic/importer/fetcher/ISIDOREFetcherTest.java
+++ b/src/test/java/org/jabref/logic/importer/fetcher/ISIDOREFetcherTest.java
@@ -67,8 +67,8 @@ public void checkThesis() throws FetcherException {
List actual = fetcher.performSearch("Mapping English L2 errors: an integrated system and textual approach");
- // Fetcher returns the same entry twice.
- assertEquals(List.of(expected, expected), actual);
+ // Fetcher returns the same entry twice. Since 2024, it also returns an additional entry. We just ignore this for now.
+ assertEquals(expected, actual.getFirst());
}
@Test
diff --git a/src/test/java/org/jabref/logic/importer/fetcher/ScholarArchiveFetcherTest.java b/src/test/java/org/jabref/logic/importer/fetcher/ScholarArchiveFetcherTest.java
index 0af2c4f0eb4..3ebe337344c 100644
--- a/src/test/java/org/jabref/logic/importer/fetcher/ScholarArchiveFetcherTest.java
+++ b/src/test/java/org/jabref/logic/importer/fetcher/ScholarArchiveFetcherTest.java
@@ -9,6 +9,7 @@
import org.jabref.testutils.category.FetcherTest;
import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -22,16 +23,10 @@ public class ScholarArchiveFetcherTest {
@BeforeEach
public void setUp() {
fetcher = new ScholarArchiveFetcher();
- bibEntry = new BibEntry(StandardEntryType.InCollection)
- .withField(StandardField.TITLE, "Query expansion using associated queries")
- .withField(StandardField.AUTHOR, "Billerbeck, Bodo and Scholer, Falk and Williams, Hugh E. and Zobel, Justin")
- .withField(StandardField.VOLUME, "0")
- .withField(StandardField.DOI, "10.1145/956863.956866")
- .withField(StandardField.JOURNAL, "Proceedings of the twelfth international conference on Information and knowledge management - CIKM '03")
- .withField(StandardField.PUBLISHER, "ACM Press")
- .withField(StandardField.TYPE, "paper-conference")
- .withField(StandardField.YEAR, "2003")
- .withField(StandardField.URL, "https://web.archive.org/web/20170810164449/http://goanna.cs.rmit.edu.au/~jz/fulltext/cikm03.pdf");
+ bibEntry = new BibEntry(StandardEntryType.InProceedings)
+ .withField(StandardField.TITLE, "BPELscript: A Simplified Script Syntax for WS-BPEL 2.0")
+ .withField(StandardField.AUTHOR, "Marc Bischof and Oliver Kopp and Tammo van Lessen and Frank Leymann ")
+ .withField(StandardField.YEAR, "2009");
}
@Test
@@ -40,8 +35,9 @@ public void getNameReturnsCorrectName() {
}
@Test
+ @Disabled("We seem to be blocked")
public void performSearchReturnsExpectedResults() throws FetcherException {
- List fetchedEntries = fetcher.performSearch("query");
+ List fetchedEntries = fetcher.performSearch("bpelscript");
fetchedEntries.forEach(entry -> entry.clearField(StandardField.ABSTRACT));
assertTrue(fetchedEntries.contains(bibEntry), "Found the following entries " + fetchedEntries);
}
diff --git a/src/test/java/org/jabref/logic/importer/fetcher/SemanticScholarTest.java b/src/test/java/org/jabref/logic/importer/fetcher/SemanticScholarTest.java
index 32045374354..04f53818564 100644
--- a/src/test/java/org/jabref/logic/importer/fetcher/SemanticScholarTest.java
+++ b/src/test/java/org/jabref/logic/importer/fetcher/SemanticScholarTest.java
@@ -44,12 +44,10 @@ public class SemanticScholarTest implements PagedSearchFetcherTest {
.withField(StandardField.VENUE, "International Conference on Software Engineering");
private SemanticScholar fetcher;
- private BibEntry entry;
@BeforeEach
void setUp() {
fetcher = new SemanticScholar(importerPreferences);
- entry = new BibEntry();
}
@Test
@@ -64,7 +62,7 @@ void getDocument() throws IOException, FetcherException {
@Disabled("Returns a DOI instead of the required link")
@DisabledOnCIServer("CI server is unreliable")
void fullTextFindByDOI() throws Exception {
- entry.setField(StandardField.DOI, "10.1038/nrn3241");
+ BibEntry entry = new BibEntry().withField(StandardField.DOI, "10.1038/nrn3241");
assertEquals(
Optional.of(new URI("https://europepmc.org/articles/pmc4907333?pdf=render").toURL()),
fetcher.findFullText(entry)
@@ -73,6 +71,7 @@ void fullTextFindByDOI() throws Exception {
@Test
@DisabledOnCIServer("CI server is unreliable")
+ @Disabled("Sometimes, does not find any thing")
void fullTextFindByDOIAlternate() throws Exception {
assertEquals(
Optional.of(new URI("https://pdfs.semanticscholar.org/7f6e/61c254bc2df38a784c1228f56c13317caded.pdf").toURL()),
@@ -89,8 +88,8 @@ void fullTextSearchOnEmptyEntry() throws IOException, FetcherException {
@Test
@DisabledOnCIServer("CI server is unreliable")
void fullTextNotFoundByDOI() throws IOException, FetcherException {
- entry = new BibEntry().withField(StandardField.DOI, DOI);
- entry.setField(StandardField.DOI, "10.1021/bk-2006-WWW.ch014");
+ BibEntry entry = new BibEntry().withField(StandardField.DOI, DOI)
+ .withField(StandardField.DOI, "10.1021/bk-2006-WWW.ch014");
assertEquals(Optional.empty(), fetcher.findFullText(entry));
}
@@ -98,7 +97,7 @@ void fullTextNotFoundByDOI() throws IOException, FetcherException {
@Test
@DisabledOnCIServer("CI server is unreliable")
void fullTextFindByArXiv() throws Exception {
- entry = new BibEntry().withField(StandardField.EPRINT, "1407.3561")
+ BibEntry entry = new BibEntry().withField(StandardField.EPRINT, "1407.3561")
.withField(StandardField.ARCHIVEPREFIX, "arXiv");
assertEquals(
Optional.of(new URI("https://arxiv.org/pdf/1407.3561.pdf").toURL()),
@@ -130,6 +129,7 @@ void getURLForQueryWithLucene() throws QueryNodeParseException, MalformedURLExce
}
@Test
+ @Disabled("We seem to be blocked")
void searchByQueryFindsEntry() throws Exception {
BibEntry master = new BibEntry(StandardEntryType.Article)
.withField(StandardField.AUTHOR, "Tobias Diez")
@@ -145,6 +145,7 @@ void searchByQueryFindsEntry() throws Exception {
}
@Test
+ @Disabled("We seem to be blocked")
void searchByPlainQueryFindsEntry() throws Exception {
List fetchedEntries = fetcher.performSearch("Overcoming Open Source Project Entry Barriers with a Portal for Newcomers");
// Abstract should not be included in JabRef tests
@@ -153,6 +154,7 @@ void searchByPlainQueryFindsEntry() throws Exception {
}
@Test
+ @Disabled("We seem to be blocked")
void searchByQuotedQueryFindsEntry() throws Exception {
List fetchedEntries = fetcher.performSearch("\"Overcoming Open Source Project Entry Barriers with a Portal for Newcomers\"");
// Abstract should not be included in JabRef tests
@@ -166,6 +168,7 @@ public void performSearchByEmptyQuery() throws Exception {
}
@Test
+ @Disabled("We seem to be blocked")
public void findByEntry() throws Exception {
BibEntry barrosEntry = new BibEntry(StandardEntryType.Article)
.withField(StandardField.TITLE, "Formalising BPMN Service Interaction Patterns")
@@ -175,7 +178,7 @@ public void findByEntry() throws Exception {
.withField(StandardField.URL, "https://www.semanticscholar.org/paper/3bb026fd67db7d8e0e25de3189d6b7031b12783e")
.withField(StandardField.VENUE, "The Practice of Enterprise Modeling");
- entry.withField(StandardField.TITLE, "Formalising BPMN Service Interaction Patterns");
+ BibEntry entry = new BibEntry().withField(StandardField.TITLE, "Formalising BPMN Service Interaction Patterns");
BibEntry actual = fetcher.performSearch(entry).getFirst();
// Abstract should not be included in JabRef tests
actual.clearField(StandardField.ABSTRACT);
diff --git a/src/test/java/org/jabref/logic/importer/fileformat/PdfGrobidImporterTest.java b/src/test/java/org/jabref/logic/importer/fileformat/PdfGrobidImporterTest.java
index 33977668ee3..5f9153434fa 100644
--- a/src/test/java/org/jabref/logic/importer/fileformat/PdfGrobidImporterTest.java
+++ b/src/test/java/org/jabref/logic/importer/fileformat/PdfGrobidImporterTest.java
@@ -14,6 +14,7 @@
import org.jabref.testutils.category.FetcherTest;
import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.mockito.Answers;
@@ -47,10 +48,12 @@ public void getExtensions() {
}
@Test
+ @Disabled("Currently does not return anything")
public void importEntries() throws URISyntaxException {
Path file = Path.of(PdfGrobidImporterTest.class.getResource("LNCS-minimal.pdf").toURI());
List bibEntries = importer.importDatabase(file).getDatabase().getEntries();
+ // TODO: Rewrite using our logic of full BibEntries
assertEquals(1, bibEntries.size());
BibEntry be0 = bibEntries.getFirst();
diff --git a/src/test/java/org/jabref/logic/layout/format/HTMLCharsTest.java b/src/test/java/org/jabref/logic/layout/format/HTMLCharsTest.java
index a31c04c7205..045ab4b5adf 100644
--- a/src/test/java/org/jabref/logic/layout/format/HTMLCharsTest.java
+++ b/src/test/java/org/jabref/logic/layout/format/HTMLCharsTest.java
@@ -3,6 +3,7 @@
import java.util.stream.Stream;
import org.jabref.logic.layout.LayoutFormatter;
+import org.jabref.logic.layout.ParamLayoutFormatter;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -15,10 +16,13 @@
public class HTMLCharsTest {
private LayoutFormatter layout;
+ private ParamLayoutFormatter layoutKeep;
@BeforeEach
public void setUp() {
layout = new HTMLChars();
+ layoutKeep = new HTMLChars();
+ layoutKeep.setArgument("keepCurlyBraces");
}
private static Stream provideBasicFormattingData() {
@@ -37,6 +41,7 @@ private static Stream provideBasicFormattingData() {
Arguments.of("ä", "{\\\"a}"),
Arguments.of("ä", "\\\"a"),
Arguments.of("Ç", "{\\c{C}}"),
+ Arguments.of("Ç", "\\c{C}"),
Arguments.of("&Oogon;ı", "\\k{O}\\i"),
Arguments.of("ñ ñ í ı ı", "\\~{n} \\~n \\'i \\i \\i")
);
@@ -144,4 +149,23 @@ private static Stream provideHTMLEntityFormattingData() {
void hTMLEntityFormatting(String expected, String input) {
assertEquals(expected, layout.format(input));
}
+
+ private static Stream provideBracesKeepFormattingData() {
+ return Stream.of(
+ Arguments.of("{ä}", "{\\\"{a}}"),
+ Arguments.of("{ä}", "{\\\"a}"),
+ Arguments.of("{Ç}", "{\\c{C}}"),
+ Arguments.of("{hallo}", "{\\emph hallo}"),
+ Arguments.of("{hallo}", "{\\textbf hallo}"),
+ Arguments.of("{hallo}", "{\\bf hallo}"),
+ Arguments.of("{'}", "{\\textquotesingle}"),
+ Arguments.of("{{ test }}", "{{ test }}")
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource("provideBracesKeepFormattingData")
+ void bracesKeepFormatting(String expected, String input) {
+ assertEquals(expected, layoutKeep.format(input));
+ }
}
diff --git a/src/test/java/org/jabref/logic/layout/format/MarkdownFormatterTest.java b/src/test/java/org/jabref/logic/layout/format/MarkdownFormatterTest.java
index e5e1f9281e6..2bfb5ef4caa 100644
--- a/src/test/java/org/jabref/logic/layout/format/MarkdownFormatterTest.java
+++ b/src/test/java/org/jabref/logic/layout/format/MarkdownFormatterTest.java
@@ -1,10 +1,14 @@
package org.jabref.logic.layout.format;
+import java.util.stream.Stream;
+
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
class MarkdownFormatterTest {
@@ -17,23 +21,74 @@ void setUp() {
}
@Test
- void formatWhenFormattingPlainTextThenReturnsTextWrappedInParagraph() {
- assertEquals("Hello World
", markdownFormatter.format("Hello World"));
- }
-
- @Test
- void formatWhenFormattingComplexMarkupThenReturnsOnlyOneLine() {
- assertFalse(markdownFormatter.format("Markup\n\n* list item one\n* list item 2\n\n rest").contains("\n"));
+ void formatWhenFormattingNullThenThrowsException() {
+ Exception exception = assertThrows(NullPointerException.class, () -> markdownFormatter.format(null));
+ assertEquals("Field Text should not be null, when handed to formatter", exception.getMessage());
}
- @Test
- void formatWhenFormattingEmptyStringThenReturnsEmptyString() {
- assertEquals("", markdownFormatter.format(""));
+ private static Stream provideMarkdownAndHtml() {
+ return Stream.of(
+ Arguments.of("Hello World", "Hello World
"),
+ Arguments.of("""
+ Markup
+
+ * list item one
+ * list item two
+
+ rest
+ """,
+ "Markup
- list item one
- list item two
rest
"
+ ),
+ Arguments.of("""
+ ```
+ Hello World
+ ```
+ """,
+ "Hello World
"
+ ),
+ Arguments.of("""
+ First line
+
+ Second line
+
+ ```java
+ String test;
+ ```
+ """,
+ "First line
Second line
String test;
"
+ ),
+ Arguments.of("""
+ Some text.
+ ```javascript
+ let test = "Hello World";
+ ```
+
+ ```java
+ String test = "Hello World";
+ ```
+ Some more text.
+ """,
+ "Some text.
let test = "Hello World"; " +
+ "
String test = "Hello World"; " +
+ "
Some more text.
"
+ ),
+ Arguments.of("""
+ Some text.
+
+ ```java
+ int foo = 0;
+ foo = 1;
+
+ ```
+ """,
+ "Some text.
int foo = 0; foo = 1;
"
+ )
+ );
}
- @Test
- void formatWhenFormattingNullThenThrowsException() {
- Exception exception = assertThrows(NullPointerException.class, () -> markdownFormatter.format(null));
- assertEquals("Field Text should not be null, when handed to formatter", exception.getMessage());
+ @ParameterizedTest
+ @MethodSource("provideMarkdownAndHtml")
+ void formatWhenFormattingCodeBlockThenReturnsCodeBlockInHtml(String markdown, String expectedHtml) {
+ assertEquals(expectedHtml, markdownFormatter.format(markdown));
}
}
diff --git a/src/test/java/org/jabref/migrations/PreferencesMigrationsTest.java b/src/test/java/org/jabref/migrations/PreferencesMigrationsTest.java
index 0a89c471788..9b3f8f0c145 100644
--- a/src/test/java/org/jabref/migrations/PreferencesMigrationsTest.java
+++ b/src/test/java/org/jabref/migrations/PreferencesMigrationsTest.java
@@ -84,8 +84,8 @@ void previewStyleReviewToComment() {
String newPreviewStyle = "__NEWLINE__"
+ "Customized preview style using reviews and comments:__NEWLINE__"
- + "\\begin{comment}
Comment: \\format[Markdown,HTMLChars]{\\comment} \\end{comment}__NEWLINE__"
- + "\\begin{comment} Something: \\format[Markdown,HTMLChars]{\\comment} special \\end{comment}__NEWLINE__"
+ + "\\begin{comment}
Comment: \\format[Markdown,HTMLChars(keepCurlyBraces)]{\\comment} \\end{comment}__NEWLINE__"
+ + "\\begin{comment} Something: \\format[Markdown,HTMLChars(keepCurlyBraces)]{\\comment} special \\end{comment}__NEWLINE__"
+ "__NEWLINE__";
when(prefs.get(JabRefPreferences.PREVIEW_STYLE)).thenReturn(oldPreviewStyle);