Skip to content

Commit

Permalink
Merge pull request #14 from subhramit/olly-improvements
Browse files Browse the repository at this point in the history
Refactor out class ReferenceMark
  • Loading branch information
subhramit authored Aug 5, 2024
2 parents 09e4218 + 48d2f4d commit 2e2d408
Show file tree
Hide file tree
Showing 6 changed files with 178 additions and 78 deletions.
4 changes: 4 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,12 @@ dependencies {

implementation 'commons-cli:commons-cli:1.8.0'

// region: LibreOffice
implementation 'org.libreoffice:unoloader:24.2.3'
implementation 'org.libreoffice:libreoffice:24.2.3'
// Required for ID generation
implementation 'io.github.thibaultmeyer:cuid:2.0.3'
// endregion

implementation 'io.github.java-diff-utils:java-diff-utils:4.12'
implementation 'info.debatty:java-string-similarity:2.0.0'
Expand Down
1 change: 1 addition & 0 deletions src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@
requires transitive org.jspecify;

// region: other libraries (alphabetically)
requires cuid;
requires dd.plist;
requires mslinks;
requires org.antlr.antlr4.runtime;
Expand Down
90 changes: 90 additions & 0 deletions src/main/java/org/jabref/logic/openoffice/ReferenceMark.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package org.jabref.logic.openoffice;

import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.jabref.logic.openoffice.oocsltext.CSLCitationOOAdapter;

import io.github.thibaultmeyer.cuid.CUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* See {@link CSLCitationOOAdapter#PREFIXES} for the prefix(es) used to identify reference marks.
*/
public class ReferenceMark {
private static final Logger LOGGER = LoggerFactory.getLogger(ReferenceMark.class);

private static final Pattern REFERENCE_MARK_FORMAT = Pattern.compile("^JABREF_(\\w+) CID_(\\w+) (\\w+)$");
private final String name;

private String citationKey;
private Integer citationNumber;
private String uniqueId;

/**
* @param name Format: <code>JABREF_{citationKey} CID_{citationNumber} {uniqueId}</code>
*/
public ReferenceMark(String name) {
this.name = name;

Matcher matcher = getMatcher(name);
if (!matcher.matches()) {
LOGGER.warn("CSLReferenceMark: name={} does not match pattern. Assuming random values", name);
this.citationKey = CUID.randomCUID2(8).toString();
this.citationNumber = 0;
this.uniqueId = this.citationKey;
return;
}

this.citationKey = matcher.group(1);
this.citationNumber = Integer.parseInt(matcher.group(2));
this.uniqueId = matcher.group(3);

LOGGER.debug("CSLReferenceMark: citationKey={} citationNumber={} uniqueId={}", getCitationKey(), getCitationNumber(), getUniqueId());
}

public ReferenceMark(String name, String citationKey, Integer citationNumber, String uniqueId) {
this.name = name;
this.citationKey = citationKey;
this.citationNumber = citationNumber;
this.uniqueId = uniqueId;
}

private ReferenceMark(String name, String citationKey, String citationNumber, String uniqueId) {
this(name, citationKey, Integer.parseInt(citationNumber), uniqueId);
}

private static Matcher getMatcher(String name) {
return REFERENCE_MARK_FORMAT.matcher(name);
}

public String getName() {
return name;
}

/**
* The BibTeX citation key
*/
public String getCitationKey() {
return citationKey;
}

public Integer getCitationNumber() {
return citationNumber;
}

public String getUniqueId() {
return uniqueId;
}

public static Optional<ReferenceMark> of(String name) {
Matcher matcher = getMatcher(name);
if (!matcher.matches()) {
return Optional.empty();
}

return Optional.of(new ReferenceMark(name, matcher.group(1), matcher.group(2), matcher.group(3)));
}
}
Original file line number Diff line number Diff line change
@@ -1,40 +1,51 @@
package org.jabref.logic.openoffice.oocsltext;

import org.jabref.logic.openoffice.ReferenceMark;
import org.jabref.model.openoffice.ootext.OOText;
import org.jabref.model.openoffice.ootext.OOTextIntoOO;
import org.jabref.model.openoffice.uno.CreationException;

import com.sun.star.container.XNamed;
import com.sun.star.lang.XMultiServiceFactory;
import com.sun.star.text.XTextContent;
import com.sun.star.text.XTextCursor;
import com.sun.star.text.XTextDocument;
import com.sun.star.text.XTextRange;
import com.sun.star.uno.Exception;
import com.sun.star.uno.UnoRuntime;
import io.github.thibaultmeyer.cuid.CUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Class to handle a reference mark. See {@link CSLReferenceMarkManager} for the management of all reference marks.
*/
public class CSLReferenceMark {
private final String name;

private static final Logger LOGGER = LoggerFactory.getLogger(CSLReferenceMark.class);

private final ReferenceMark referenceMark;
private final XTextContent textContent;
private String citationKey;
private String citationNumber;
private String uniqueId;

public CSLReferenceMark(XNamed named, String name) {
this.name = name;
this.textContent = UnoRuntime.queryInterface(XTextContent.class, named);
public CSLReferenceMark(XNamed named, ReferenceMark referenceMark) {
this.referenceMark = referenceMark;
textContent = UnoRuntime.queryInterface(XTextContent.class, named);
}

// Format: JABREF_{citationKey} CID_{citationNumber} {uniqueId}
String[] parts = name.split(" ");
public CSLReferenceMark(XNamed named, String name, String citationKey, Integer citationNumber, String uniqueId) {
referenceMark = new ReferenceMark(name, citationKey, citationNumber, uniqueId);
this.textContent = UnoRuntime.queryInterface(XTextContent.class, named);
}

if (parts.length >= 3 && parts[0].startsWith("JABREF_") && parts[1].startsWith("CID_")) {
this.citationKey = parts[0].substring(7);
this.citationNumber = parts[1].substring(4);
this.uniqueId = parts[2];
System.out.println(citationKey);
System.out.println(citationNumber);
System.out.println(uniqueId);
}
public static CSLReferenceMark of(String citationKey, Integer citationNumber, XMultiServiceFactory factory) throws Exception {
String uniqueId = CUID.randomCUID2(8).toString();
String name = "JABREF_" + citationKey + " CID_" + citationNumber + " " + uniqueId;
XNamed named = UnoRuntime.queryInterface(XNamed.class, factory.createInstance("com.sun.star.text.ReferenceMark"));
named.setName(name);
return new CSLReferenceMark(named, name, citationKey, citationNumber, uniqueId);
}

public void insertReferenceIntoOO(XTextDocument doc, XTextCursor cursor, OOText ooText) throws Exception {
public void insertReferenceIntoOO(XTextDocument doc, XTextCursor cursor, OOText ooText) throws Exception, CreationException {
XTextRange startRange = cursor.getStart();
OOTextIntoOO.write(doc, cursor, ooText);
XTextRange endRange = cursor.getEnd();
Expand All @@ -44,23 +55,11 @@ public void insertReferenceIntoOO(XTextDocument doc, XTextCursor cursor, OOText
cursor.gotoRange(endRange, false);
}

public String getName() {
return name;
}

public XTextContent getTextContent() {
return textContent;
}

public String getCitationKey() {
return citationKey;
}

public String getCitationNumber() {
return citationNumber;
}

public String getUniqueId() {
return uniqueId;
public String getName() {
return referenceMark.getName();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.Optional;

import org.jabref.logic.openoffice.ReferenceMark;
import org.jabref.model.entry.BibEntry;

import com.sun.star.container.XNameAccess;
Expand All @@ -16,8 +15,13 @@
import com.sun.star.text.XReferenceMarksSupplier;
import com.sun.star.text.XTextDocument;
import com.sun.star.uno.UnoRuntime;
import io.github.thibaultmeyer.cuid.CUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class CSLReferenceMarkManager {
private static final Logger LOGGER = LoggerFactory.getLogger(CSLReferenceMarkManager.class);

private final HashMap<String, CSLReferenceMark> marksByName;
private final ArrayList<CSLReferenceMark> marksByID;
private final IdentityHashMap<CSLReferenceMark, Integer> idsByMark;
Expand All @@ -44,43 +48,24 @@ public void readExistingMarks() throws Exception {
int citationCounter = 0;

for (String name : marks.getElementNames()) {
String citationKey = extractCitationKey(name);
if (!citationKey.isEmpty()) {
citationOrder.putIfAbsent(citationKey, ++citationCounter);

Optional<ReferenceMark> referenceMark = ReferenceMark.of(name);
if (!referenceMark.isEmpty()) {
citationOrder.putIfAbsent(referenceMark.map(ReferenceMark::getCitationKey).get(), ++citationCounter);
XNamed named = UnoRuntime.queryInterface(XNamed.class, marks.getByName(name));
CSLReferenceMark mark = new CSLReferenceMark(named, name);
CSLReferenceMark mark = new CSLReferenceMark(named, referenceMark.get());
addMark(mark);
}
}
}

private String extractCitationKey(String name) {
for (String prefix : CSLCitationOOAdapter.PREFIXES) {
if (name.startsWith(prefix)) {
String withoutPrefix = name.substring(prefix.length());
String[] parts = withoutPrefix.split("\\s+");
if (parts.length > 0) {
String key = parts[0];
key = key.replaceAll("^[^a-zA-Z0-9]+|[^a-zA-Z0-9]+$", "");
if (!key.isEmpty()) {
return key;
}
}
break;
}
}
return "";
}

private void updateCitationInfo(String name) {
Pattern pattern = Pattern.compile("JABREF_(.+) CID_(\\d+) (.+)"); // Updated pattern
Matcher matcher = pattern.matcher(name);
if (matcher.find()) {
String citationKey = matcher.group(1);
int citationNumber = Integer.parseInt(matcher.group(2));
citationKeyToNumber.put(citationKey, citationNumber);
Optional<ReferenceMark> referenceMark = ReferenceMark.of(name);
if (referenceMark.isPresent()) {
int citationNumber = referenceMark.get().getCitationNumber();
citationKeyToNumber.put(referenceMark.get().getCitationKey(), citationNumber);
highestCitationNumber = Math.max(highestCitationNumber, citationNumber);
} else {
LOGGER.warn("Could not parse ReferenceMark name: {}", name);
}
}

Expand All @@ -92,25 +77,14 @@ public void addMark(CSLReferenceMark mark) {
}

public int getCitationNumber(String citationKey) {
return citationKeyToNumber.computeIfAbsent(citationKey, k -> {
highestCitationNumber++;
return highestCitationNumber;
});
return citationKeyToNumber.computeIfAbsent(citationKey, k -> ++highestCitationNumber);
}

public CSLReferenceMark createReferenceMark(BibEntry entry) throws Exception {
String citationKey = entry.getCitationKey().orElse("");
String citationKey = entry.getCitationKey().orElse(CUID.randomCUID2(8).toString());
int citationNumber = getCitationNumber(citationKey);
String uniqueId = UUID.randomUUID().toString().substring(0, 8); // Generate a unique ID

String name = CSLCitationOOAdapter.PREFIXES[0] + citationKey + " CID_" + citationNumber + " " + uniqueId;
Object mark = factory.createInstance("com.sun.star.text.ReferenceMark");
XNamed named = UnoRuntime.queryInterface(XNamed.class, mark);
named.setName(name);

CSLReferenceMark referenceMark = new CSLReferenceMark(named, name);
CSLReferenceMark referenceMark = CSLReferenceMark.of(citationKey, citationNumber, factory);
addMark(referenceMark);

return referenceMark;
}

Expand Down
32 changes: 32 additions & 0 deletions src/test/java/org/jabref/logic/openoffice/ReferenceMarkTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.jabref.logic.openoffice;

import java.util.stream.Stream;

import org.junit.jupiter.api.DisplayName;
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;

class ReferenceMarkTest {

@ParameterizedTest
@MethodSource
@DisplayName("Test parsing of valid reference marks")
void validParsing(String name, String expectedCitationKey, String expectedCitationNumber, String expectedUniqueId) {
ReferenceMark referenceMark = new ReferenceMark(name);

assertEquals(expectedCitationKey, referenceMark.getCitationKey());
assertEquals(expectedCitationNumber, referenceMark.getCitationNumber());
assertEquals(expectedUniqueId, referenceMark.getUniqueId());
}

private static Stream<Arguments> validParsing() {
return Stream.of(
Arguments.of("JABREF_key1 CID_12345 uniqueId1", "key1", "12345", "uniqueId1"),
Arguments.of("JABREF_key2 CID_67890 uniqueId2", "key2", "67890", "uniqueId2"),
Arguments.of("JABREF_key3 CID_54321 uniqueId3", "key3", "54321", "uniqueId3")
);
}
}

0 comments on commit 2e2d408

Please sign in to comment.