Skip to content

Commit

Permalink
Change copy-paste function to handle string constants (follow up PR) (#…
Browse files Browse the repository at this point in the history
…11037)

* [Copy] Include string constants in copy (#11)

Signed-off-by: Anders Blomqvist <anders@minaemail.se>

* [Copy] New method for serializing string constants (#12)

Signed-off-by: Anders Blomqvist <anders@minaemail.se>

* Add a sanity check for null for clipboard content

Currenlty, the clipboard content can be null since the database
does not seem to be updating. This is a sanity check to prevent
the program from adding null to the clipboard.

Link to DD2480-Group1#13

* [Fix] Add parsed serilization when save settings

When loading from existing files or libraries, the parser will set
the serilization of the string constant to the correct value. However,
when editing via the GUI, the serilization was not set and a new
string constant list will be created without the serilization.
This result in the serilization being null and when copying with
the clipboard.

Link to DD2480-Group1#13

* feat: import string constants when pasting #9

Add functionality to import string constants in the paste function

Should add functionality to handle colliding string constants.
Should also check that the constants are valid using the
ConstantsItemModel class.

* feat: Add string constant validity checker and dialog messages #9

Check that a pasted string constant is valid using the
ConstantsItemModel class.

Add diagnostic messages notifying users when adding a string constant
fails while pasting.

* [Copy] Copy referenced constant strings to clipboard  (#16)

* feat: Add parsed serialized string when cloning
* feat: Add sanity check for null in ClipBoardManager
* closes #15

* feat: new unit tests

Add 4 new unit tests, testing the new features added for issue-10872. Specifically the tests are for the `storeSettings` method in the ConstantsPropertiesViewModel.java, and `setContent` in the ClipBaordManager.java.

Closes #6

* Update CHANGELOG with copy and paste function

* Fix Checkstyle failing by reformat the code

* Fix OpenRewrite failing by running rewriteRun

* Refactor by extract methods in setContent

* collet failures

* changelog and use os.newline

* checkstyle

* use real bibentrytypes manager

* Fix CHANGELOG.md

* Swap if branches

* Code cleanup

* Use List for getUsedStringValues

* Fix submodule

* Collection is better

* Fix csl-styles

* Remove empty line

* Group BibTeX string l10n together

---------

Signed-off-by: Anders Blomqvist <anders@minaemail.se>
Co-authored-by: Anders Blomqvist <anders@minaemail.se>
Co-authored-by: ZOU Hetai <33616271+JXNCTED@users.noreply.github.com>
Co-authored-by: Hannes Stig <hannes.a.stig@gmail.com>
Co-authored-by: Elliot <elliot.darth@gmail.com>
Co-authored-by: Oliver Kopp <kopp.dev@gmail.com>
  • Loading branch information
6 people authored Mar 18, 2024
1 parent fb65bed commit d792923
Show file tree
Hide file tree
Showing 13 changed files with 299 additions and 66 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv
- We added the ability to zoom in and out in the document viewer using <kbd>Ctrl</kbd> + <kbd>Scroll</kbd>. [#10964](https://github.com/JabRef/jabref/pull/10964)
- We added a Cleanup for removing non-existent files and grouped the related options [#10929](https://github.com/JabRef/jabref/issues/10929)
- We added the functionality to parse the bibliography of PDFs using the GROBID online service. [#10200](https://github.com/JabRef/jabref/issues/10200)
- We added support for BibTeX String constants during copy & paste between libraries [#10872](https://github.com/JabRef/jabref/issues/10872)

### Changed

Expand Down
22 changes: 16 additions & 6 deletions src/main/java/org/jabref/gui/ClipBoardManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.jabref.model.database.BibDatabaseMode;
import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.BibEntryTypesManager;
import org.jabref.model.entry.BibtexString;
import org.jabref.preferences.PreferencesService;

import org.slf4j.Logger;
Expand Down Expand Up @@ -155,14 +156,23 @@ public void setContent(String string) {
}

public void setContent(List<BibEntry> entries, BibEntryTypesManager entryTypesManager) throws IOException {
final ClipboardContent content = new ClipboardContent();
BibEntryWriter writer = new BibEntryWriter(new FieldWriter(preferencesService.getFieldPreferences()), entryTypesManager);
String serializedEntries = writer.serializeAll(entries, BibDatabaseMode.BIBTEX);
String serializedEntries = serializeEntries(entries, entryTypesManager);
setContent(serializedEntries);
}

public void setContent(List<BibEntry> entries, BibEntryTypesManager entryTypesManager, List<BibtexString> stringConstants) throws IOException {
StringBuilder builder = new StringBuilder();
stringConstants.forEach(strConst -> builder.append(strConst.getParsedSerialization() == null ? "" : strConst.getParsedSerialization()));
String serializedEntries = serializeEntries(entries, entryTypesManager);
builder.append(serializedEntries);
setContent(builder.toString());
}

private String serializeEntries(List<BibEntry> entries, BibEntryTypesManager entryTypesManager) throws IOException {
// BibEntry is not Java serializable. Thus, we need to do the serialization manually
// At reading of the clipboard in JabRef, we parse the plain string in all cases, so we don't need to flag we put BibEntries here
// Furthermore, storing a string also enables other applications to work with the data
content.putString(serializedEntries);
clipboard.setContent(content);
setPrimaryClipboardContent(content);
BibEntryWriter writer = new BibEntryWriter(new FieldWriter(preferencesService.getFieldPreferences()), entryTypesManager);
return writer.serializeAll(entries, BibDatabaseMode.BIBTEX);
}
}
1 change: 0 additions & 1 deletion src/main/java/org/jabref/gui/edit/ReplaceStringAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ public class ReplaceStringAction extends SimpleCommand {
public ReplaceStringAction(Supplier<LibraryTab> tabSupplier, StateManager stateManager, DialogService dialogService) {
this.tabSupplier = tabSupplier;
this.dialogService = dialogService;

this.executable.bind(ActionHelper.needsDatabase(stateManager));
}

Expand Down
30 changes: 28 additions & 2 deletions src/main/java/org/jabref/gui/externalfiles/ImportHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.jabref.gui.StateManager;
import org.jabref.gui.duplicationFinder.DuplicateResolverDialog;
import org.jabref.gui.fieldeditors.LinkedFileViewModel;
import org.jabref.gui.libraryproperties.constants.ConstantsItemModel;
import org.jabref.gui.undo.UndoableInsertEntries;
import org.jabref.gui.util.BackgroundTask;
import org.jabref.gui.util.DefaultTaskExecutor;
Expand All @@ -40,7 +41,9 @@
import org.jabref.logic.util.io.FileUtil;
import org.jabref.model.FieldChange;
import org.jabref.model.database.BibDatabaseContext;
import org.jabref.model.database.KeyCollisionException;
import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.BibtexString;
import org.jabref.model.entry.LinkedFile;
import org.jabref.model.entry.field.StandardField;
import org.jabref.model.entry.identifier.ArXivIdentifier;
Expand Down Expand Up @@ -311,13 +314,36 @@ private void generateKeys(List<BibEntry> entries) {
public List<BibEntry> handleBibTeXData(String entries) {
BibtexParser parser = new BibtexParser(preferencesService.getImportFormatPreferences(), fileUpdateMonitor);
try {
return parser.parseEntries(new ByteArrayInputStream(entries.getBytes(StandardCharsets.UTF_8)));
List<BibEntry> result = parser.parseEntries(new ByteArrayInputStream(entries.getBytes(StandardCharsets.UTF_8)));
Collection<BibtexString> stringConstants = parser.getStringValues();
importStringConstantsWithDuplicateCheck(stringConstants);
return result;
} catch (ParseException ex) {
LOGGER.error("Could not paste", ex);
return Collections.emptyList();
}
}

public void importStringConstantsWithDuplicateCheck(Collection<BibtexString> stringConstants) {
List<String> failures = new ArrayList<>();

for (BibtexString stringConstantToAdd : stringConstants) {
try {
ConstantsItemModel checker = new ConstantsItemModel(stringConstantToAdd.getName(), stringConstantToAdd.getContent());
if (checker.combinedValidationValidProperty().get()) {
bibDatabaseContext.getDatabase().addString(stringConstantToAdd);
} else {
failures.add(Localization.lang("String constant \"%0\" was not imported because it is not a valid string constant", stringConstantToAdd.getName()));
}
} catch (KeyCollisionException ex) {
failures.add(Localization.lang("String constant %0 was not imported because it already exists in this library", stringConstantToAdd.getName()));
}
}
if (!failures.isEmpty()) {
dialogService.showWarningDialogAndWait(Localization.lang("Importing String constants"), Localization.lang("Could not import the following string constants:\n %0", String.join("\n", failures)));
}
}

public List<BibEntry> handleStringData(String data) throws FetcherException {
if ((data == null) || data.isEmpty()) {
return Collections.emptyList();
Expand Down Expand Up @@ -356,7 +382,7 @@ private List<BibEntry> tryImportFormats(String data) {
}

private List<BibEntry> fetchByDOI(DOI doi) throws FetcherException {
LOGGER.info("Found DOI identifer in clipboard");
LOGGER.info("Found DOI identifier in clipboard");
Optional<BibEntry> entry = new DoiFetcher(preferencesService.getImportFormatPreferences()).performSearchById(doi.getDOI());
return OptionalUtil.toList(entry);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package org.jabref.gui.libraryproperties.constants;

import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.stream.Collectors;

import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ListProperty;
Expand All @@ -18,6 +18,7 @@
import org.jabref.gui.libraryproperties.PropertiesTabViewModel;
import org.jabref.logic.bibtex.comparator.BibtexStringComparator;
import org.jabref.logic.help.HelpFile;
import org.jabref.logic.util.OS;
import org.jabref.model.database.BibDatabaseContext;
import org.jabref.model.entry.BibtexString;
import org.jabref.preferences.FilePreferences;
Expand Down Expand Up @@ -86,9 +87,12 @@ private ConstantsItemModel convertFromBibTexString(BibtexString bibtexString) {

@Override
public void storeSettings() {
databaseContext.getDatabase().setStrings(stringsListProperty.stream()
.map(this::fromBibtexStringViewModel)
.collect(Collectors.toList()));
List<BibtexString> strings = stringsListProperty.stream()
.map(this::fromBibtexStringViewModel)
.toList();
strings.forEach(string -> string.setParsedSerialization("@String{" +
string.getName() + " = " + string.getContent() + "}" + OS.NEWLINE));
databaseContext.getDatabase().setStrings(strings);
}

private BibtexString fromBibtexStringViewModel(ConstantsItemModel viewModel) {
Expand Down
12 changes: 11 additions & 1 deletion src/main/java/org/jabref/gui/maintable/MainTable.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import org.jabref.model.database.event.EntriesAddedEvent;
import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.BibEntryTypesManager;
import org.jabref.model.entry.BibtexString;
import org.jabref.model.util.FileUpdateMonitor;
import org.jabref.preferences.PreferencesService;

Expand Down Expand Up @@ -257,8 +258,13 @@ public void copy() {
List<BibEntry> selectedEntries = getSelectedEntries();

if (!selectedEntries.isEmpty()) {
List<BibtexString> stringConstants = getUsedStringValues(selectedEntries);
try {
clipBoardManager.setContent(selectedEntries, entryTypesManager);
if (stringConstants.isEmpty()) {
clipBoardManager.setContent(selectedEntries, entryTypesManager);
} else {
clipBoardManager.setContent(selectedEntries, entryTypesManager, stringConstants);
}
dialogService.notify(Localization.lang("Copied %0 entry(ies)", selectedEntries.size()));
} catch (IOException e) {
LOGGER.error("Error while copying selected entries to clipboard.", e);
Expand Down Expand Up @@ -489,4 +495,8 @@ private Optional<BibEntryTableViewModel> findEntry(BibEntry entry) {
.filter(viewModel -> viewModel.getEntry().equals(entry))
.findFirst();
}

private List<BibtexString> getUsedStringValues(List<BibEntry> entries) {
return database.getDatabase().getUsedStrings(entries);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,10 @@ public List<BibEntry> parseEntries(InputStream inputStream) throws ParseExceptio
}
}

public Collection<BibtexString> getStringValues() {
return database.getStringValues();
}

public Optional<BibEntry> parseSingleEntry(String bibtexString) throws ParseException {
return parseEntries(bibtexString).stream().findFirst();
}
Expand Down
21 changes: 8 additions & 13 deletions src/main/java/org/jabref/model/database/BibDatabase.java
Original file line number Diff line number Diff line change
Expand Up @@ -370,27 +370,22 @@ public String resolveForStrings(String content) {
/**
* Get all strings used in the entries.
*/
public Collection<BibtexString> getUsedStrings(Collection<BibEntry> entries) {
List<BibtexString> result = new ArrayList<>();
public List<BibtexString> getUsedStrings(Collection<BibEntry> entries) {
Set<String> allUsedIds = new HashSet<>();

// All entries
for (BibEntry entry : entries) {
for (String fieldContent : entry.getFieldValues()) {
resolveContent(fieldContent, new HashSet<>(), allUsedIds);
}
}

// Preamble
if (preamble != null) {
resolveContent(preamble, new HashSet<>(), allUsedIds);
}

for (String stringId : allUsedIds) {
result.add((BibtexString) bibtexStrings.get(stringId).clone());
// All entries
for (BibEntry entry : entries) {
for (String fieldContent : entry.getFieldValues()) {
resolveContent(fieldContent, new HashSet<>(), allUsedIds);
}
}

return result;
return allUsedIds.stream().map(bibtexStrings::get).toList();
}

/**
Expand Down Expand Up @@ -459,7 +454,7 @@ private String resolveString(String label, Set<String> usedIds, Set<String> allU
// circular reference, and have to stop to avoid
// infinite recursion.
if (usedIds.contains(string.getId())) {
LOGGER.info("Stopped due to circular reference in strings: " + label);
LOGGER.info("Stopped due to circular reference in strings: {}", label);
return label;
}
// If not, log this string's ID now.
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/org/jabref/model/entry/BibtexString.java
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,9 @@ public String getUserComments() {
public Object clone() {
BibtexString clone = new BibtexString(name, content);
clone.setId(id);
if (parsedSerialization != null) {
clone.setParsedSerialization(parsedSerialization);
}

return clone;
}
Expand Down
Loading

0 comments on commit d792923

Please sign in to comment.