Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open "near-by" .bib file #12172

Merged
merged 12 commits into from
Nov 13, 2024
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv
- We added an importer for SSRN URLs. [#12021](https://github.com/JabRef/jabref/pull/12021)
- We added a compare button to the duplicates in the citation relations tab to open the "Possible duplicate entries" window. [#11192](https://github.com/JabRef/jabref/issues/11192)
- We added automatic browser extension install on Windows for Chrome and Edge. [#6076](https://github.com/JabRef/jabref/issues/6076)
- We added support to automatically open a `.bib` file in the current/parent folder if no other library is opened. [koppor#377](https://github.com/koppor/jabref/issues/377)
- We added a search bar for filtering keyboard shortcuts. [#11686](https://github.com/JabRef/jabref/issues/11686)
- By double clicking on a local citation in the Citation Relations Tab you can now jump the linked entry. [#11955](https://github.com/JabRef/jabref/pull/11955)
- We use the menu icon for background tasks as a progress indicator to visualise an import's progress when dragging and dropping several PDF files into the main table. [#12072](https://github.com/JabRef/jabref/pull/12072)
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/jabref/cli/ArgumentProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ public ArgumentProcessor(String[] args,
}

/**
* Will open a file (like {@link #importFile(String)}, but will also request JabRef to focus on this database.
* Will open a file (like {@link #importFile(String)}, but will also request JabRef to focus on this library.
*
* @return ParserResult with setToOpenTab(true)
*/
Expand Down
89 changes: 89 additions & 0 deletions src/main/java/org/jabref/gui/frame/JabRefFrameViewModel.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package org.jabref.gui.frame;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.sql.SQLException;
import java.util.ArrayList;
Expand Down Expand Up @@ -30,18 +33,22 @@
import org.jabref.logic.UiCommand;
import org.jabref.logic.ai.AiService;
import org.jabref.logic.importer.ImportCleanup;
import org.jabref.logic.importer.OpenDatabase;
import org.jabref.logic.importer.ParserResult;
import org.jabref.logic.l10n.Localization;
import org.jabref.logic.os.OS;
import org.jabref.logic.shared.DatabaseNotSupportedException;
import org.jabref.logic.shared.exception.InvalidDBMSConnectionPropertiesException;
import org.jabref.logic.shared.exception.NotASharedDatabaseException;
import org.jabref.logic.util.BackgroundTask;
import org.jabref.logic.util.TaskExecutor;
import org.jabref.logic.util.io.FileUtil;
import org.jabref.model.database.BibDatabaseContext;
import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.BibEntryTypesManager;
import org.jabref.model.util.FileUpdateMonitor;

import org.jooq.lambda.Unchecked;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -146,9 +153,12 @@ public boolean close() {
public void handleUiCommands(List<UiCommand> uiCommands) {
LOGGER.debug("Handling UI commands {}", uiCommands);
if (uiCommands.isEmpty()) {
checkForBibInUpperDir();
return;
}

assert !uiCommands.isEmpty();

// Handle blank workspace
boolean blank = uiCommands.stream().anyMatch(UiCommand.BlankWorkspace.class::isInstance);

Expand Down Expand Up @@ -180,6 +190,85 @@ public void handleUiCommands(List<UiCommand> uiCommands) {
});
}

private void checkForBibInUpperDir() {
// "Open last edited databases" happened before this call
// Moreover, there is not any CLI command (especially, not opening any new tab)
// Thus, we check if there are any tabs open.
if (tabContainer.getLibraryTabs().isEmpty()) {
Optional<Path> firstBibFile = firstBibFile();
if (firstBibFile.isPresent()) {
ParserResult parserResult;
try {
parserResult = OpenDatabase.loadDatabase(
firstBibFile.get(),
preferences.getImportFormatPreferences(),
fileUpdateMonitor);
} catch (IOException e) {
LOGGER.error("Could not open bib file {}", firstBibFile.get(), e);
return;
}
List<ParserResult> librariesToOpen = new ArrayList<>(1);
librariesToOpen.add(parserResult);
openDatabases(librariesToOpen);
}
}
}

/// Use case: User starts `JabRef.bat` or `JabRef.exe`. JabRef should open a "close by" bib file.
/// By "close by" a `.bib` file in the current folder or one level up of `JabRef.exe`is meant.
///
/// Paths:
/// - `...\{example-dir}\JabRef\JabRef.exe` (Windows)
/// - `.../{example-dir}/JabRef/bin/JabRef` (Linux)
/// - `...\{example-dir}\JabRef\runtime\bin\JabRef.bat` (Windows)
///
/// In the example, `...\{example-dir}\example.bib` should be found.
///
/// We do NOT go up another level (i.e., everything in `...` is not found)
private Optional<Path> firstBibFile() {
Path absolutePath = Path.of(".").toAbsolutePath();
if (OS.LINUX && absolutePath.startsWith("/usr")) {
return Optional.empty();
}
if (OS.OS_X && absolutePath.startsWith("/Applications")) {
return Optional.empty();
}
if (OS.WINDOWS && absolutePath.startsWith("C:\\Program Files")) {
return Optional.empty();
}

boolean isJabRefExe = Files.exists(Path.of("JabRef.exe"));
boolean isJabRefBat = Files.exists(Path.of("JabRef.bat"));
boolean isJabRef = Files.exists(Path.of("JabRef"));

ArrayList<Path> dirsToCheck = new ArrayList<>(2);
dirsToCheck.add(Path.of(""));
if (isJabRefExe) {
dirsToCheck.add(Path.of("../")); // directory above `JabRef.exe` directory
} else if (isJabRefBat) {
dirsToCheck.add(Path.of("../../../")); // directory above `runtime\bin\JabRef.bat`
} else if (isJabRef) {
dirsToCheck.add(Path.of("../..(/")); // directory above `bin/JabRef` directory
}

// We want to check dirsToCheck only, not all subdirs (due to unnecessary disk i/o)
try {
return dirsToCheck.stream()
.map(Path::toAbsolutePath)
.flatMap(Unchecked.function(dir -> Files.list(dir)))
.filter(path -> FileUtil.getFileExtension(path).equals(Optional.of("bib")))
.findFirst();
} catch (UncheckedIOException ex) {
// Could be access denied exception - when this is started from the application directory
// Therefore log level "debug"
LOGGER.debug("Could not check for existing bib file {}", dirsToCheck, ex);
return Optional.empty();
}
}

/// Opens the libraries given in `parserResults`. This list needs to be modifiable, because invalidDatabases are removed.
///
/// @param parserResults A modifiable list of parser results
private void openDatabases(List<ParserResult> parserResults) {
final List<ParserResult> toOpenTab = new ArrayList<>();

Expand Down
Loading